aboutsummaryrefslogtreecommitdiff
path: root/src/api
diff options
context:
space:
mode:
authorGravatar Jarred SUmner <jarred@jarredsumner.com> 2022-01-01 01:53:50 -0800
committerGravatar Jarred SUmner <jarred@jarredsumner.com> 2022-01-01 01:53:50 -0800
commita17088363f16fc72562994ed01555841c7c1b1ac (patch)
tree27cb1685eb1ce676476797f7076dd46e2bac5d9c /src/api
parent83004f0a0a51658a50499256a874558f26e09a24 (diff)
downloadbun-a17088363f16fc72562994ed01555841c7c1b1ac.tar.gz
bun-a17088363f16fc72562994ed01555841c7c1b1ac.tar.zst
bun-a17088363f16fc72562994ed01555841c7c1b1ac.zip
[bun dev] Improve filesystem watcher & HMR reliability (Linux + a little macOS)
Text editors like Replit save through atomic file updates. In an inotify filesystem watcher (Linux), that appears to be a delete followed by moving the file to the directory. Now when known files are moved into a directory, the watcher sends the file change notification to the browser(s). From there, the browser looks at it's files to determine whether or not Additionally, if an existing HMR connection does not know about a file ID passed to it, it asks the browser to reply with the file path and then starts watching that file. This improves HMR reliabiality if Bun had been restarted but the page hadn't been restarted.
Diffstat (limited to 'src/api')
-rw-r--r--src/api/schema.d.ts78
-rw-r--r--src/api/schema.js196
-rw-r--r--src/api/schema.peechy38
-rw-r--r--src/api/schema.zig133
4 files changed, 69 insertions, 376 deletions
diff --git a/src/api/schema.d.ts b/src/api/schema.d.ts
index d00dcfa6e..273f8d9d3 100644
--- a/src/api/schema.d.ts
+++ b/src/api/schema.d.ts
@@ -231,6 +231,8 @@ export enum WebsocketMessageKind {
build_fail = 4,
manifest_success = 5,
manifest_fail = 6,
+ resolve_file = 7,
+ file_change_notification_with_hint = 8,
}
export const WebsocketMessageKindKeys = {
1: "welcome",
@@ -245,16 +247,23 @@ export const WebsocketMessageKindKeys = {
manifest_success: "manifest_success",
6: "manifest_fail",
manifest_fail: "manifest_fail",
+ 7: "resolve_file",
+ resolve_file: "resolve_file",
+ 8: "file_change_notification_with_hint",
+ file_change_notification_with_hint: "file_change_notification_with_hint",
};
export enum WebsocketCommandKind {
build = 1,
manifest = 2,
+ build_with_file_path = 3,
}
export const WebsocketCommandKindKeys = {
1: "build",
build: "build",
2: "manifest",
manifest: "manifest",
+ 3: "build_with_file_path",
+ build_with_file_path: "build_with_file_path",
};
export interface StackFrame {
function_name: string;
@@ -575,37 +584,13 @@ export interface WebsocketMessageBuildFailure {
log: Log;
}
-export interface DependencyManifest {
- ids: Uint32Array;
-}
-
-export interface FileList {
- ptrs: StringPointer[];
- files: string;
-}
-
-export interface WebsocketMessageResolveIDs {
- id: Uint32Array;
- list: FileList;
-}
-
-export interface WebsocketCommandResolveIDs {
- ptrs: StringPointer[];
- files: string;
-}
-
-export interface WebsocketMessageManifestSuccess {
+export interface WebsocketCommandBuildWithFilePath {
id: uint32;
- module_path: string;
- loader: Loader;
- manifest: DependencyManifest;
+ file_path: string;
}
-export interface WebsocketMessageManifestFailure {
+export interface WebsocketMessageResolveID {
id: uint32;
- from_timestamp: uint32;
- loader: Loader;
- log: Log;
}
export declare function encodeStackFrame(
@@ -860,40 +845,17 @@ export declare function encodeWebsocketMessageBuildFailure(
export declare function decodeWebsocketMessageBuildFailure(
buffer: ByteBuffer
): WebsocketMessageBuildFailure;
-export declare function encodeDependencyManifest(
- message: DependencyManifest,
- bb: ByteBuffer
-): void;
-export declare function decodeDependencyManifest(
- buffer: ByteBuffer
-): DependencyManifest;
-export declare function encodeFileList(message: FileList, bb: ByteBuffer): void;
-export declare function decodeFileList(buffer: ByteBuffer): FileList;
-export declare function encodeWebsocketMessageResolveIDs(
- message: WebsocketMessageResolveIDs,
- bb: ByteBuffer
-): void;
-export declare function decodeWebsocketMessageResolveIDs(
- buffer: ByteBuffer
-): WebsocketMessageResolveIDs;
-export declare function encodeWebsocketCommandResolveIDs(
- message: WebsocketCommandResolveIDs,
- bb: ByteBuffer
-): void;
-export declare function decodeWebsocketCommandResolveIDs(
- buffer: ByteBuffer
-): WebsocketCommandResolveIDs;
-export declare function encodeWebsocketMessageManifestSuccess(
- message: WebsocketMessageManifestSuccess,
+export declare function encodeWebsocketCommandBuildWithFilePath(
+ message: WebsocketCommandBuildWithFilePath,
bb: ByteBuffer
): void;
-export declare function decodeWebsocketMessageManifestSuccess(
+export declare function decodeWebsocketCommandBuildWithFilePath(
buffer: ByteBuffer
-): WebsocketMessageManifestSuccess;
-export declare function encodeWebsocketMessageManifestFailure(
- message: WebsocketMessageManifestFailure,
+): WebsocketCommandBuildWithFilePath;
+export declare function encodeWebsocketMessageResolveID(
+ message: WebsocketMessageResolveID,
bb: ByteBuffer
): void;
-export declare function decodeWebsocketMessageManifestFailure(
+export declare function decodeWebsocketMessageResolveID(
buffer: ByteBuffer
-): WebsocketMessageManifestFailure;
+): WebsocketMessageResolveID;
diff --git a/src/api/schema.js b/src/api/schema.js
index dc89e2b11..8b2043e9c 100644
--- a/src/api/schema.js
+++ b/src/api/schema.js
@@ -2369,12 +2369,16 @@ const WebsocketMessageKind = {
4: 4,
5: 5,
6: 6,
+ 7: 7,
+ 8: 8,
welcome: 1,
file_change_notification: 2,
build_success: 3,
build_fail: 4,
manifest_success: 5,
manifest_fail: 6,
+ resolve_file: 7,
+ file_change_notification_with_hint: 8,
};
const WebsocketMessageKindKeys = {
1: "welcome",
@@ -2383,24 +2387,32 @@ const WebsocketMessageKindKeys = {
4: "build_fail",
5: "manifest_success",
6: "manifest_fail",
+ 7: "resolve_file",
+ 8: "file_change_notification_with_hint",
welcome: "welcome",
file_change_notification: "file_change_notification",
build_success: "build_success",
build_fail: "build_fail",
manifest_success: "manifest_success",
manifest_fail: "manifest_fail",
+ resolve_file: "resolve_file",
+ file_change_notification_with_hint: "file_change_notification_with_hint",
};
const WebsocketCommandKind = {
1: 1,
2: 2,
+ 3: 3,
build: 1,
manifest: 2,
+ build_with_file_path: 3,
};
const WebsocketCommandKindKeys = {
1: "build",
2: "manifest",
+ 3: "build_with_file_path",
build: "build",
manifest: "manifest",
+ build_with_file_path: "build_with_file_path",
};
function decodeWebsocketMessage(bb) {
@@ -2669,121 +2681,15 @@ function encodeWebsocketMessageBuildFailure(message, bb) {
}
}
-function decodeDependencyManifest(bb) {
- var result = {};
-
- result["ids"] = bb.readUint32ByteArray();
- return result;
-}
-
-function encodeDependencyManifest(message, bb) {
- var value = message["ids"];
- if (value != null) {
- bb.writeUint32ByteArray(value);
- } else {
- throw new Error('Missing required field "ids"');
- }
-}
-
-function decodeFileList(bb) {
- var result = {};
-
- var length = bb.readVarUint();
- var values = (result["ptrs"] = Array(length));
- for (var i = 0; i < length; i++) values[i] = decodeStringPointer(bb);
- result["files"] = bb.readString();
- return result;
-}
-
-function encodeFileList(message, bb) {
- var value = message["ptrs"];
- if (value != null) {
- var values = value,
- n = values.length;
- bb.writeVarUint(n);
- for (var i = 0; i < n; i++) {
- value = values[i];
- encodeStringPointer(value, bb);
- }
- } else {
- throw new Error('Missing required field "ptrs"');
- }
-
- var value = message["files"];
- if (value != null) {
- bb.writeString(value);
- } else {
- throw new Error('Missing required field "files"');
- }
-}
-
-function decodeWebsocketMessageResolveIDs(bb) {
- var result = {};
-
- result["id"] = bb.readUint32ByteArray();
- result["list"] = decodeFileList(bb);
- return result;
-}
-
-function encodeWebsocketMessageResolveIDs(message, bb) {
- var value = message["id"];
- if (value != null) {
- bb.writeUint32ByteArray(value);
- } else {
- throw new Error('Missing required field "id"');
- }
-
- var value = message["list"];
- if (value != null) {
- encodeFileList(value, bb);
- } else {
- throw new Error('Missing required field "list"');
- }
-}
-
-function decodeWebsocketCommandResolveIDs(bb) {
- var result = {};
-
- var length = bb.readVarUint();
- var values = (result["ptrs"] = Array(length));
- for (var i = 0; i < length; i++) values[i] = decodeStringPointer(bb);
- result["files"] = bb.readString();
- return result;
-}
-
-function encodeWebsocketCommandResolveIDs(message, bb) {
- var value = message["ptrs"];
- if (value != null) {
- var values = value,
- n = values.length;
- bb.writeVarUint(n);
- for (var i = 0; i < n; i++) {
- value = values[i];
- encodeStringPointer(value, bb);
- }
- } else {
- throw new Error('Missing required field "ptrs"');
- }
-
- var value = message["files"];
- if (value != null) {
- bb.writeString(value);
- } else {
- throw new Error('Missing required field "files"');
- }
-}
-
-function decodeWebsocketMessageManifestSuccess(bb) {
+function decodeWebsocketCommandBuildWithFilePath(bb) {
var result = {};
result["id"] = bb.readUint32();
- result["module_path"] = bb.readString();
- result["loader"] = Loader[bb.readByte()];
- result["manifest"] = decodeDependencyManifest(bb);
+ result["file_path"] = bb.readString();
return result;
}
-function encodeWebsocketMessageManifestSuccess(message, bb) {
+function encodeWebsocketCommandBuildWithFilePath(message, bb) {
var value = message["id"];
if (value != null) {
bb.writeUint32(value);
@@ -2791,76 +2697,28 @@ function encodeWebsocketMessageManifestSuccess(message, bb) {
throw new Error('Missing required field "id"');
}
- var value = message["module_path"];
+ var value = message["file_path"];
if (value != null) {
bb.writeString(value);
} else {
- throw new Error('Missing required field "module_path"');
- }
-
- var value = message["loader"];
- if (value != null) {
- var encoded = Loader[value];
- if (encoded === void 0)
- throw new Error(
- "Invalid value " + JSON.stringify(value) + ' for enum "Loader"'
- );
- bb.writeByte(encoded);
- } else {
- throw new Error('Missing required field "loader"');
- }
-
- var value = message["manifest"];
- if (value != null) {
- encodeDependencyManifest(value, bb);
- } else {
- throw new Error('Missing required field "manifest"');
+ throw new Error('Missing required field "file_path"');
}
}
-function decodeWebsocketMessageManifestFailure(bb) {
+function decodeWebsocketMessageResolveID(bb) {
var result = {};
result["id"] = bb.readUint32();
- result["from_timestamp"] = bb.readUint32();
- result["loader"] = Loader[bb.readByte()];
- result["log"] = decodeLog(bb);
return result;
}
-function encodeWebsocketMessageManifestFailure(message, bb) {
+function encodeWebsocketMessageResolveID(message, bb) {
var value = message["id"];
if (value != null) {
bb.writeUint32(value);
} else {
throw new Error('Missing required field "id"');
}
-
- var value = message["from_timestamp"];
- if (value != null) {
- bb.writeUint32(value);
- } else {
- throw new Error('Missing required field "from_timestamp"');
- }
-
- var value = message["loader"];
- if (value != null) {
- var encoded = Loader[value];
- if (encoded === void 0)
- throw new Error(
- "Invalid value " + JSON.stringify(value) + ' for enum "Loader"'
- );
- bb.writeByte(encoded);
- } else {
- throw new Error('Missing required field "loader"');
- }
-
- var value = message["log"];
- if (value != null) {
- encodeLog(value, bb);
- } else {
- throw new Error('Missing required field "log"');
- }
}
export { Loader };
@@ -2985,15 +2843,7 @@ export { decodeWebsocketMessageBuildSuccess };
export { encodeWebsocketMessageBuildSuccess };
export { decodeWebsocketMessageBuildFailure };
export { encodeWebsocketMessageBuildFailure };
-export { decodeDependencyManifest };
-export { encodeDependencyManifest };
-export { decodeFileList };
-export { encodeFileList };
-export { decodeWebsocketMessageResolveIDs };
-export { encodeWebsocketMessageResolveIDs };
-export { decodeWebsocketCommandResolveIDs };
-export { encodeWebsocketCommandResolveIDs };
-export { decodeWebsocketMessageManifestSuccess };
-export { encodeWebsocketMessageManifestSuccess };
-export { decodeWebsocketMessageManifestFailure };
-export { encodeWebsocketMessageManifestFailure };
+export { decodeWebsocketCommandBuildWithFilePath };
+export { encodeWebsocketCommandBuildWithFilePath };
+export { decodeWebsocketMessageResolveID };
+export { encodeWebsocketMessageResolveID };
diff --git a/src/api/schema.peechy b/src/api/schema.peechy
index 8afb0f30a..7c5b482a2 100644
--- a/src/api/schema.peechy
+++ b/src/api/schema.peechy
@@ -440,11 +440,14 @@ smol WebsocketMessageKind {
build_fail = 4;
manifest_success = 5;
manifest_fail = 6;
+ resolve_file = 7;
+ file_change_notification_with_hint = 8;
}
smol WebsocketCommandKind {
build = 1;
manifest = 2;
+ build_with_file_path = 3;
}
// Each websocket message has two messages in it!
@@ -492,7 +495,6 @@ struct WebsocketMessageBuildSuccess {
uint32 blob_length;
}
-
struct WebsocketMessageBuildFailure {
uint32 id;
uint32 from_timestamp;
@@ -502,37 +504,11 @@ struct WebsocketMessageBuildFailure {
Log log;
}
-// CSS @import only for now!
-struct DependencyManifest {
- uint32[] ids;
-}
-
-struct FileList {
- StringPointer[] ptrs;
- string files;
-}
-
-struct WebsocketMessageResolveIDs {
- uint32[] id;
- FileList list;
-}
-
-struct WebsocketCommandResolveIDs {
- StringPointer[] ptrs;
- string files;
-}
-
-struct WebsocketMessageManifestSuccess {
+struct WebsocketCommandBuildWithFilePath {
uint32 id;
- string module_path;
- Loader loader;
-
- DependencyManifest manifest;
+ string file_path;
}
-struct WebsocketMessageManifestFailure {
+struct WebsocketMessageResolveID {
uint32 id;
- uint32 from_timestamp;
- Loader loader;
- Log log;
-}
+} \ No newline at end of file
diff --git a/src/api/schema.zig b/src/api/schema.zig
index 2238ea3f0..8a850c8f1 100644
--- a/src/api/schema.zig
+++ b/src/api/schema.zig
@@ -2338,6 +2338,12 @@ pub const Api = struct {
/// manifest_fail
manifest_fail,
+ /// resolve_file
+ resolve_file,
+
+ /// file_change_notification_with_hint
+ file_change_notification_with_hint,
+
_,
pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void {
@@ -2353,6 +2359,9 @@ pub const Api = struct {
/// manifest
manifest,
+ /// build_with_file_path
+ build_with_file_path,
+
_,
pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void {
@@ -2553,144 +2562,40 @@ pub const Api = struct {
}
};
- pub const DependencyManifest = struct {
- /// ids
- ids: []const u32,
-
- pub fn decode(reader: anytype) anyerror!DependencyManifest {
- var this = std.mem.zeroes(DependencyManifest);
-
- this.ids = try reader.readArray(u32);
- return this;
- }
-
- pub fn encode(this: *const @This(), writer: anytype) anyerror!void {
- try writer.writeArray(u32, this.ids);
- }
- };
-
- pub const FileList = struct {
- /// ptrs
- ptrs: []const StringPointer,
-
- /// files
- files: []const u8,
-
- pub fn decode(reader: anytype) anyerror!FileList {
- var this = std.mem.zeroes(FileList);
-
- this.ptrs = try reader.readArray(StringPointer);
- this.files = try reader.readValue([]const u8);
- return this;
- }
-
- pub fn encode(this: *const @This(), writer: anytype) anyerror!void {
- try writer.writeArray(StringPointer, this.ptrs);
- try writer.writeValue(@TypeOf(this.files), this.files);
- }
- };
-
- pub const WebsocketMessageResolveIDs = struct {
- /// id
- id: []const u32,
-
- /// list
- list: FileList,
-
- pub fn decode(reader: anytype) anyerror!WebsocketMessageResolveIDs {
- var this = std.mem.zeroes(WebsocketMessageResolveIDs);
-
- this.id = try reader.readArray(u32);
- this.list = try reader.readValue(FileList);
- return this;
- }
-
- pub fn encode(this: *const @This(), writer: anytype) anyerror!void {
- try writer.writeArray(u32, this.id);
- try writer.writeValue(@TypeOf(this.list), this.list);
- }
- };
-
- pub const WebsocketCommandResolveIDs = struct {
- /// ptrs
- ptrs: []const StringPointer,
-
- /// files
- files: []const u8,
-
- pub fn decode(reader: anytype) anyerror!WebsocketCommandResolveIDs {
- var this = std.mem.zeroes(WebsocketCommandResolveIDs);
-
- this.ptrs = try reader.readArray(StringPointer);
- this.files = try reader.readValue([]const u8);
- return this;
- }
-
- pub fn encode(this: *const @This(), writer: anytype) anyerror!void {
- try writer.writeArray(StringPointer, this.ptrs);
- try writer.writeValue(@TypeOf(this.files), this.files);
- }
- };
-
- pub const WebsocketMessageManifestSuccess = struct {
+ pub const WebsocketCommandBuildWithFilePath = struct {
/// id
id: u32 = 0,
- /// module_path
- module_path: []const u8,
+ /// file_path
+ file_path: []const u8,
- /// loader
- loader: Loader,
-
- /// manifest
- manifest: DependencyManifest,
-
- pub fn decode(reader: anytype) anyerror!WebsocketMessageManifestSuccess {
- var this = std.mem.zeroes(WebsocketMessageManifestSuccess);
+ pub fn decode(reader: anytype) anyerror!WebsocketCommandBuildWithFilePath {
+ var this = std.mem.zeroes(WebsocketCommandBuildWithFilePath);
this.id = try reader.readValue(u32);
- this.module_path = try reader.readValue([]const u8);
- this.loader = try reader.readValue(Loader);
- this.manifest = try reader.readValue(DependencyManifest);
+ this.file_path = try reader.readValue([]const u8);
return this;
}
pub fn encode(this: *const @This(), writer: anytype) anyerror!void {
try writer.writeInt(this.id);
- try writer.writeValue(@TypeOf(this.module_path), this.module_path);
- try writer.writeEnum(this.loader);
- try writer.writeValue(@TypeOf(this.manifest), this.manifest);
+ try writer.writeValue(@TypeOf(this.file_path), this.file_path);
}
};
- pub const WebsocketMessageManifestFailure = struct {
+ pub const WebsocketMessageResolveId = packed struct {
/// id
id: u32 = 0,
- /// from_timestamp
- from_timestamp: u32 = 0,
-
- /// loader
- loader: Loader,
-
- /// log
- log: Log,
-
- pub fn decode(reader: anytype) anyerror!WebsocketMessageManifestFailure {
- var this = std.mem.zeroes(WebsocketMessageManifestFailure);
+ pub fn decode(reader: anytype) anyerror!WebsocketMessageResolveId {
+ var this = std.mem.zeroes(WebsocketMessageResolveId);
this.id = try reader.readValue(u32);
- this.from_timestamp = try reader.readValue(u32);
- this.loader = try reader.readValue(Loader);
- this.log = try reader.readValue(Log);
return this;
}
pub fn encode(this: *const @This(), writer: anytype) anyerror!void {
try writer.writeInt(this.id);
- try writer.writeInt(this.from_timestamp);
- try writer.writeEnum(this.loader);
- try writer.writeValue(@TypeOf(this.log), this.log);
}
};
};