const std = @import("std"); pub const Reader = struct { const Self = @This(); pub const ReadError = error{EOF}; buf: []u8, remain: []u8, allocator: std.mem.Allocator, pub fn init(buf: []u8, allocator: std.mem.Allocator) Reader { return Reader{ .buf = buf, .remain = buf, .allocator = allocator, }; } pub fn read(this: *Self, count: usize) ![]u8 { const read_count = @min(count, this.remain.len); if (read_count < count) { return error.EOF; } var slice = this.remain[0..read_count]; this.remain = this.remain[read_count..]; return slice; } pub inline fn readAs(this: *Self, comptime T: type) !T { if (!std.meta.trait.hasUniqueRepresentation(T)) { @compileError(@typeName(T) ++ " must have unique representation."); } return std.mem.bytesAsValue(T, try this.read(@sizeOf(T))); } pub inline fn readByte(this: *Self) !u8 { return (try this.read(1))[0]; } pub fn readEnum(this: *Self, comptime Enum: type) !Enum { const E = error{ /// An integer was read, but it did not match any of the tags in the supplied enum. InvalidValue, }; const type_info = @typeInfo(Enum).Enum; const tag = try this.readInt(type_info.tag_type); inline for (std.meta.fields(Enum)) |field| { if (tag == field.value) { return @field(Enum, field.name); } } return E.InvalidValue; } pub fn readArray(this: *Self, comptime T: type) ![]const T { const length = try this.readInt(u32); if (length == 0) { return &([_]T{}); } switch (comptime T) { u8 => { return try this.read(length); }, u16, u32, i8, i16, i32 => { return std.mem.readIntSliceNative(T, this.read(length * @sizeOf(T))); }, [:0]const u8, []const u8 => { var i: u32 = 0; var array = try this.allocator.alloc(T, length); while (i < length) : (i += 1) { array[i] = try this.readArray(u8); } return array; }, else => { switch (comptime @typeInfo(T)) { .Struct => |Struct| { switch (Struct.layout) { .Packed => { const sizeof = @sizeOf(T); var slice = try this.read(sizeof * length); return std.mem.bytesAsSlice(T, slice); }, else => {}, } }, .Enum => |type_info| { const enum_values = try this.read(length * @sizeOf(type_info.tag_type)); return @as([*]T, @ptrCast(enum_values.ptr))[0..length]; }, else => {}, } var i: u32 = 0; var array = try this.allocator.alloc(T, length); while (i < length) : (i += 1) { array[i] = try this.readValue(T); } return array; }, } } pub inline fn readByteArray(this: *Self) ![]u8 { const length = try this.readInt(u32); if (length == 0) { return &([_]u8{}); } return try this.read(@as(usize, length)); } pub inline fn readInt(this: *Self, comptime T: type) !T { var slice = try this.read(@sizeOf(T)); return std.mem.readIntSliceNative(T, slice); } pub inline fn readBool(this: *Self) !bool { return (try this.readByte()) > 0; } pub inline fn readValue(this: *Self, comptime T: type) !T { switch (comptime T) { bool => { return try this.readBool(); }, u8 => { return try this.readByte(); }, [*:0]const u8, [:0]const u8, []const u8 => { return try this.readArray(u8); }, []const [:0]const u8, []const [*:0]const u8, []const []const u8 => { return try this.readArray([]const u8); }, []u8, [:0]u8, [*:0]u8 => { return try this.readArray([]u8); }, u16, u32, i8, i16, i32 => { return std.mem.readIntSliceNative(T, try this.read(@sizeOf(T))); }, else => { switch (comptime @typeInfo(T)) { .Struct => |Struct| { switch (Struct.layout) { .Packed => { const sizeof = @sizeOf(T); var slice = try this.read(sizeof); return @as(*align(1) T, @ptrCast(slice[0..sizeof])).*; }, else => {}, } }, .Enum => { return try this.readEnum(T); }, else => {}, } return try T.decode(this); }, } @compileError("Invalid type passed to readValue"); } }; pub fn Writer(comptime WritableStream: type) type { return struct { const Self = @This(); writable: WritableStream, pub fn init(writable: WritableStream) Self { return Self{ .writable = writable }; } pub inline fn write(this: *Self, bytes: anytype) !void { _ = try this.writable.write(bytes); } pub inline fn writeByte(this: *Self, byte: u8) !void { _ = try this.writable.write(&[1]u8{byte}); } pub inline fn writeInt(this: *Self, int: anytype) !void { try this.write(std.mem.asBytes(&int)); } pub inline fn writeFieldID(this: *Self, comptime id: comptime_int) !void { try this.writeByte(id); } pub inline fn writeEnum(this: *Self, val: anytype) !void { try this.writeInt(@intFromEnum(val)); } pub fn writeValue(this: *Self, comptime SliceType: type, slice: SliceType) !void { switch (SliceType) { []u16, []u32, []i16, []i32, []i8, []const u16, []const u32, []const i16, []const i32, []const i8, [:0]u16, [:0]u32, [:0]i16, [:0]i32, [:0]i8, [:0]const u16, [:0]const u32, [:0]const i16, [:0]const i32, [:0]const i8, [*:0]u16, [*:0]u32, [*:0]i16, [*:0]i32, [*:0]i8, [*:0]const u16, [*:0]const u32, [*:0]const i16, [*:0]const i32, [*:0]const i8, => { try this.writeArray(SliceType, slice); }, []u8, []const u8, [:0]u8, [:0]const u8, [*:0]u8, [*:0]const u8, => { try this.writeArray(u8, slice); }, u8 => { try this.write(slice); }, u16, u32, i16, i32, i8 => { try this.write(std.mem.asBytes(slice)); }, else => { try slice.encode(this); }, } } pub fn writeArray(this: *Self, comptime T: type, slice: anytype) !void { try this.writeInt(@as(u32, @truncate(slice.len))); switch (T) { u8 => { try this.write(slice); }, u16, u32, i16, i32, i8 => { try this.write(std.mem.asBytes(slice)); }, [:0]u8, []u8, []u16, []u32, []i16, []i32, []i8, []const u8, [:0]const u8, []const u16, []const u32, []const i16, []const i32, []const i8, [:0]u16, [:0]u32, [:0]i16, [:0]i32, [:0]i8, [:0]const u16, [:0]const u32, [:0]const i16, [:0]const i32, [:0]const i8, [*:0]u16, [*:0]u32, [*:0]i16, [*:0]i32, [*:0]i8, [*:0]const u16, [*:0]const u32, [*:0]const i16, [*:0]const i32, [*:0]const i8, => { for (slice) |num_slice| { try this.writeArray(std.meta.Child(@TypeOf(num_slice)), num_slice); } }, else => { for (slice) |val| { try val.encode(this); } }, } } pub inline fn endMessage(this: *Self) !void { try this.writeByte(0); } }; } pub const ByteWriter = Writer(*std.io.FixedBufferStream([]u8)); pub const FileWriter = Writer(std.fs.File); pub const analytics = struct { pub const OperatingSystem = enum(u8) { _none, /// linux linux, /// macos macos, /// windows windows, /// wsl wsl, _, pub fn jsonStringify(self: @This(), writer: anytype) !void { return try writer.write(@tagName(self)); } }; pub const Architecture = enum(u8) { _none, /// x64 x64, /// arm arm, _, pub fn jsonStringify(self: @This(), writer: anytype) !void { return try writer.write(@tagName(self)); } }; pub const Platform = struct { /// os os: OperatingSystem, /// arch arch: Architecture, /// version version: []const u8, pub fn decode(reader: anytype) anyerror!Platform { var this = std.mem.zeroes(Platform); this.os = try reader.readValue(OperatingSystem); this.arch = try reader.readValue(Architecture); this.version = try reader.readArray(u8); return this; } pub fn encode(this: *const @This(), writer: anytype) anyerror!void { try writer.writeEnum(this.os); try writer.writeEnum(this.arch); try writer.writeArray(u8, this.version); } }; pub const EventKind = enum(u32) { _none, /// bundle_success bundle_success, /// bundle_fail bundle_fail, /// http_start http_start, /// http_build http_build, /// bundle_start bundle_start, _, pub fn jsonStringify(self: @This(), writer: anytype) !void { return try writer.write(@tagName(self)); } }; pub const Uint64 = packed struct { /// first first: u32 = 0, /// second second: u32 = 0, pub fn decode(reader: anytype) anyerror!Uint64 { var this = std.mem.zeroes(Uint64); this.first = try reader.readValue(u32); this.second = try reader.readValue(u32); return this; } pub fn encode(this: *const @This(), writer: anytype) anyerror!void { try writer.writeInt(this.first); try writer.writeInt(this.second); } }; pub const EventListHeader = struct { /// machine_id machine_id: Uint64, /// session_id session_id: u32 = 0, /// platform platform: Platform, /// build_id build_id: u32 = 0, /// project_id project_id: Uint64, /// session_length session_length: u32 = 0, /// feature_usage feature_usage: u32 = 0, pub fn decode(reader: anytype) anyerror!EventListHeader { var this = std.mem.zeroes(EventListHeader); this.machine_id = try reader.readValue(Uint64); this.session_id = try reader.readValue(u32); this.platform = try reader.readValue(Platform); this.build_id = try reader.readValue(u32); this.project_id = try reader.readValue(Uint64); this.session_length = try reader.readValue(u32); this.feature_usage = try reader.readValue(u32); return this; } pub fn encode(this: *const @This(), writer: anytype) anyerror!void { try writer.writeValue(@TypeOf(this.machine_id), this.machine_id); try writer.writeInt(this.session_id); try writer.writeValue(@TypeOf(this.platform), this.platform); try writer.writeInt(this.build_id); try writer.writeValue(@TypeOf(this.project_id), this.project_id); try writer.writeInt(this.session_length); try writer.writeInt(this.feature_usage); } }; pub const EventHeader = struct { /// timestamp timestamp: Uint64, /// kind kind: EventKind, pub fn decode(reader: anytype) anyerror!EventHeader { var this = std.mem.zeroes(EventHeader); this.timestamp = try reader.readValue(Uint64); this.kind = try reader.readValue(EventKind); return this; } pub fn encode(this: *const @This(), writer: anytype) anyerror!void { try writer.writeValue(@TypeOf(this.timestamp), this.timestamp); try writer.writeEnum(this.kind); } }; pub const EventList = struct { /// header header: EventListHeader, /// event_count event_count: u32 = 0, pub fn decode(reader: anytype) anyerror!EventList { var this = std.mem.zeroes(EventList); this.header = try reader.readValue(EventListHeader); this.event_count = try reader.readValue(u32); return this; } pub fn encode(this: *const @This(), writer: anytype) anyerror!void { try writer.writeValue(@TypeOf(this.header), this.header); try writer.writeInt(this.event_count); } }; }; ject'>Fix ffi type (#4265)Gravatar Code Hz 2-49/+272 * add readonly so it works with as const * split ffi type infer to args and returns * add JSCallback to FFITypeToArgsType * add read functions * simplify FFITypeOrString * fix cstring type * fix pointer type test * fix readonly * add unknown handling * trigger action * use Parameters * add read type test * add other read function to tests 2023-08-23Bunch of streams fixes (#4251)Gravatar Jarred Sumner 31-548/+866 * Update WebKit * Don't do async hooks things when async hooks are not enabled * Smarter scheduling of event loop tasks with the http server * less exciting approach * Bump WebKit * Another approach * Fix body-stream tests * Fixes #1886 * Fix UAF in fetch body streaming * Missing from commit * Fix leak * Fix the other leak * Fix test * Fix crash * missing duperef * Make this code clearer * Ignore empty chunks * Fixes #3969 * Delete flaky test * Update bun-linux-build.yml * Fix memory issue * fix result body, and .done status before the last callback, dont touch headers after sent once * refactor HTTPClientResult * less flasky corrupted test * oops * fix mutex invalid state * fix onProgressUpdate deinit/unlock * fix onProgressUpdate deinit/unlock * oops * remove verbose * fix posible null use * avoid http null * metadata can still be used onReject after toResponse * dont leak task.http * fix flask tests * less flask close tests --------- Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> Co-authored-by: cirospaciari <ciro.spaciari@gmail.com> 2023-08-23docs: remove broken DNS link which is also not present in the official docs ↵Gravatar Quentin 1-1/+0 (#4268) 2023-08-23Fix more types. (#4273)Gravatar xxxhussein 8-16/+22 2023-08-23ask for bun --revision instead bun -v (#4256)Gravatar Jozef Steinhübl 1-1/+1 2023-08-22fix yield (#4264)Gravatar dave caruso 2-1/+17 2023-08-22Fix Bun.inspect typesGravatar Colin McDonnell 1-1/+1 2023-08-21fix fsevents and stub for qwikcity (#4247)Gravatar dave caruso 9-64/+24 * fix test * ok * cm * EE * remove the hack we didnt need 2023-08-21fix stdin stream unref and resuming (#4250)Gravatar Dylan Conway 4-19/+26 * fix stream unref and resuming stream * fix `child-process-stdio` test 2023-08-21Docs and types for v0.8.0 (#4199)Gravatar Colin McDonnell 10-37/+487 * Improve test documentation * Update nodejs compat docs with tty * Add debugger guide * Document Bun.inspect.custom, improve bun test nav * Address reviews * Update Bun.file types * Add Nuxt guide * Add tty types 2023-08-21Bun v0.8Gravatar Jarred Sumner 5-5/+5 2023-08-21Make the code generator less duplicativeGravatar Jarred Sumner 2-84/+39 2023-08-21import errors have `code` set to `ERR_MODULE_NOT_FOUND` and `require` errors ↵Gravatar Jarred Sumner 11-19/+122 have `code` set to `MODULE_NOT_FOUND` (#4244) * ResolveMessage * Fix it --------- Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2023-08-21fetch(stream) add stream support for compressed and uncompressed data (#4127)Gravatar Ciro Spaciari 19-156/+1876 * streams non compressed data in 64kb chunks (at least) * fmt * wip remove pause * fix default streaming and buffering * fix atomic lags * fix size * make chunked encoding work again (WIP streaming chunked) * WIP: chunked encoding streaming * fix end of streamings * working streaming + compression * add fixes + tests * fmt + fix proxy * fix oopsies * codegen after merge * fmt + fixes * more fixes * more fixes and logs * avoid double free * check empty before pop * check empty on pop * fix copy to real when complete * remove unnecessary logs * better has_schedule_callback swap, body locked size helper, remove isEmpty from unbounded_queue pop * fix response ref, fix body_size * add deflate support, fix error throw, add more tests * codegen after merge * remove logs, add connection close test * fix macOS build * fix redirect error option * make body_size more clear * support new Reponse(response) * toString DOMWrapper objects properly instead of supporting response in Response constructor * ignore headers with no name, add more tests * oops * handle transform with fetch * add gz image stream test * remove duplicate test * fix missing chunk on macOS under pressure * oops include all OS * some fixes * compare buffers instead of sizes * refactor err.err and protect it 2023-08-21Fix inquirer (#4245)Gravatar dave caruso 2-3/+6 2023-08-21Update module_loader.zigGravatar Jarred Sumner 1-1/+1 2023-08-21Fix(bundler): allow generating exe file in nested path. (#4226)Gravatar Ai Hoshino 3-7/+49 * Fix(bundler): allow generating binary file in nested path. Close: #4195 * Add read flag for fd. * refactor 2023-08-21Fix typoGravatar Colin McDonnell 1-1/+1 2023-08-21Fix crypto.EC constructor (#4242)Gravatar dave caruso 2-3/+4 * Fix EC constructor * make js 2023-08-21Implement `napi_ref_threadsafe_function` (#4156)Gravatar dave caruso 10-7/+65 * Implement napi_ref_threadsafe_function * work on this * i hate event loops * little better * clean 2023-08-21feat: Implement Bun.inspect.custom (#4243)Gravatar dave caruso 6-8/+26 * add Bun.inspect.custom * test * Add Types 2023-08-21Fixes #4089 (#4105)Gravatar Jarred Sumner 3-36/+136 * Fixes #4089 * Update bindings.cpp * address PR feedback --------- Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2023-08-2140x faster .toString('hex') (#4237)Gravatar Jarred Sumner 3-17/+105 Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2023-08-21Fix memory leak in `buffer.toString("hex")` (#4235)Gravatar Jarred Sumner 2-1/+6 Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2023-08-21Update README.md (#4232)Gravatar xxxhussein 1-1/+1 Fix typo in README.md 2023-08-21Add missing header changeGravatar Jarred Sumner 1-1/+1 2023-08-21Add LazyPropertyGravatar Jarred Sumner 1-0/+3 2023-08-21Fix BigIntStats generated classGravatar Jarred Sumner 1-1/+1 cc @paperdave, code generator script misses a constructor decl when this isn't true 2023-08-21RegenerateGravatar Jarred Sumner 1-8/+15 2023-08-21Implement FileGravatar Jarred Sumner 12-12/+387 2023-08-20Fixes #1675 (#4230)Gravatar Jarred Sumner 8-70/+297 * Fixes https://github.com/oven-sh/bun/issues/1675 * Add fallback for Bun.write * Update blob.zig * Fix test --------- Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2023-08-20Implement `--inspect-brk` (#4222)Gravatar Jarred Sumner 17-41/+101 * Implement `--inspect-brk` * Bump WebKit --------- Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2023-08-20Fix test failures from 3a9a6c63a (#4231)Gravatar Jarred Sumner 4-32/+34 cc @Hanaasagi Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2023-08-20Fix(bundler): use different alias mappings based on the target. (#4163)Gravatar Ai Hoshino 8-18/+90 * Fix(bundler): use different alias mappings based on the target. Close: #3844 * chore: reduce duplicated code. * chore: split to two separate ComptimeStringMap. 2023-08-19Update BunDebugger.cppGravatar Jarred Sumner 1-1/+3 2023-08-19Introduce `bun --inspect-wait`Gravatar Jarred Sumner 3-19/+47 This waits for the inspector to connect before beginning execution 2023-08-19misc non-posix fixesGravatar Jarred Sumner 2-3/+3 2023-08-19Update lockfile.mdGravatar Jarred Sumner 1-1/+8 2023-08-19Update lockfile.mdGravatar Jarred Sumner 1-4/+4 2023-08-19Update lockfile.mdGravatar Jarred Sumner 1-1/+29 2023-08-19Update Dockerfile-distroless (#4210)Gravatar Omar 1-0/+1 2023-08-19Fix symbol visibilityGravatar Jarred Sumner 1-0/+1 2023-08-19[napi] Implement `node_api_create_syntax_error`, `node_api_symbol_for`, ↵Gravatar Jarred Sumner 5-1/+70 `node_api_throw_syntax_error` These were marked as experimental 2023-08-19Fix crash impacting sharp & resvg (#4221)Gravatar Jarred Sumner 5-73/+73 Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2023-08-19Fixes #172 (#4220)Gravatar Jarred Sumner 7-9/+87 Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2023-08-19Add inline sourcemaps when `--inspect` is enabled (#4213)Gravatar Jarred Sumner 3-3/+64 * Add inline sourcemaps when --inspect is enabled * Add some assertions * Update javascript.zig --------- Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2023-08-19tty `ReadStream`, `WriteStream`, and readline rawmode (#4179)Gravatar Dylan Conway 23-722/+821 * tty `WriteStream`, `ReadStream`, and rawmode * tests * refactor prototypes * fix failing test * fix test and library usage * more merge * fix child_process test * create pseudo terminal for tty tests * match node logic * handle invalid tty * close descriptors * move tests to another process * fix test again * fix test on linux 2023-08-18Fix make headers (again)Gravatar Jarred Sumner 1-0/+2