@swifttui/web 0.0.14 → 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -10
- package/dist/index.d.ts +9 -0
- package/dist/index.js +9 -0
- package/dist/manifest.d.ts +2 -0
- package/dist/manifest.js +2 -0
- package/dist/src/AccessibilityTree.js +156 -0
- package/dist/src/AccessibilityTree.js.map +1 -0
- package/dist/src/BoxDrawingRenderer.js +1106 -0
- package/dist/src/BoxDrawingRenderer.js.map +1 -0
- package/dist/src/WebHostApp.d.ts +41 -0
- package/dist/src/WebHostApp.js +135 -0
- package/dist/src/WebHostApp.js.map +1 -0
- package/dist/src/WebHostSceneManifest.d.ts +18 -0
- package/dist/src/WebHostSceneManifest.js +70 -0
- package/dist/src/WebHostSceneManifest.js.map +1 -0
- package/dist/src/WebHostSceneRuntime.d.ts +112 -0
- package/dist/src/WebHostSceneRuntime.js +651 -0
- package/dist/src/WebHostSceneRuntime.js.map +1 -0
- package/dist/src/WebHostSurfaceTransport.d.ts +166 -0
- package/dist/src/WebHostSurfaceTransport.js +252 -0
- package/dist/src/WebHostSurfaceTransport.js.map +1 -0
- package/dist/src/WebHostTerminalStyle.d.ts +92 -0
- package/dist/src/WebHostTerminalStyle.js +277 -0
- package/dist/src/WebHostTerminalStyle.js.map +1 -0
- package/dist/src/WebHostTestFixtures.d.ts +5 -0
- package/dist/src/WebHostTestFixtures.js +9 -0
- package/dist/src/WebHostTestFixtures.js.map +1 -0
- package/dist/src/WebSocketSceneBridge.d.ts +53 -0
- package/dist/src/WebSocketSceneBridge.js +124 -0
- package/dist/src/WebSocketSceneBridge.js.map +1 -0
- package/dist/src/wasi/BrowserWASIBridge.d.ts +33 -0
- package/dist/src/wasi/BrowserWASIBridge.js +97 -0
- package/dist/src/wasi/BrowserWASIBridge.js.map +1 -0
- package/dist/src/wasi/SharedInputQueue.d.ts +31 -0
- package/dist/src/wasi/SharedInputQueue.js +102 -0
- package/dist/src/wasi/SharedInputQueue.js.map +1 -0
- package/dist/src/wasi/StdIOPipe.d.ts +15 -0
- package/dist/src/wasi/StdIOPipe.js +56 -0
- package/dist/src/wasi/StdIOPipe.js.map +1 -0
- package/dist/src/wasi/WasiPollScheduler.js +114 -0
- package/dist/src/wasi/WasiPollScheduler.js.map +1 -0
- package/dist/src/wasi/WasmSceneRuntime.d.ts +23 -0
- package/dist/src/wasi/WasmSceneRuntime.js +119 -0
- package/dist/src/wasi/WasmSceneRuntime.js.map +1 -0
- package/dist/src/wasi/WasmSceneWorker.d.ts +27 -0
- package/dist/src/wasi/WasmSceneWorker.js +109 -0
- package/dist/src/wasi/WasmSceneWorker.js.map +1 -0
- package/dist/testing.d.ts +2 -0
- package/dist/testing.js +2 -0
- package/dist/wasi-worker.d.ts +2 -0
- package/dist/wasi-worker.js +2 -0
- package/dist/wasi.d.ts +6 -0
- package/dist/wasi.js +6 -0
- package/dist/websocket.d.ts +2 -0
- package/dist/websocket.js +2 -0
- package/package.json +49 -18
- package/AGENTS.md +0 -52
- package/cli.ts +0 -168
- package/index.html +0 -50
- package/index.ts +0 -8
- package/manifest.ts +0 -1
- package/src/AccessibilityTree.ts +0 -262
- package/src/BoxDrawingRenderer.ts +0 -585
- package/src/PublicEntrypointBoundary.test.ts +0 -20
- package/src/WebHostApp.test.ts +0 -222
- package/src/WebHostApp.ts +0 -269
- package/src/WebHostSceneManifest.test.ts +0 -38
- package/src/WebHostSceneManifest.ts +0 -156
- package/src/WebHostSceneRuntime.test.ts +0 -1982
- package/src/WebHostSceneRuntime.ts +0 -1142
- package/src/WebHostSurfaceTransport.test.ts +0 -362
- package/src/WebHostSurfaceTransport.ts +0 -691
- package/src/WebHostTerminalStyle.test.ts +0 -123
- package/src/WebHostTerminalStyle.ts +0 -471
- package/src/WebHostTestFixtures.ts +0 -10
- package/src/WebSocketSceneBridge.test.ts +0 -198
- package/src/WebSocketSceneBridge.ts +0 -233
- package/src/browser.ts +0 -59
- package/src/wasi/BrowserWASIBridge.test.ts +0 -168
- package/src/wasi/BrowserWASIBridge.ts +0 -167
- package/src/wasi/SharedInputQueue.test.ts +0 -146
- package/src/wasi/SharedInputQueue.ts +0 -199
- package/src/wasi/StdIOPipe.ts +0 -72
- package/src/wasi/WasiPollScheduler.test.ts +0 -176
- package/src/wasi/WasiPollScheduler.ts +0 -305
- package/src/wasi/WasmSceneRuntime.ts +0 -205
- package/src/wasi/WasmSceneWorker.ts +0 -182
- package/testing.ts +0 -1
- package/tsconfig.json +0 -29
- package/wasi-worker.ts +0 -1
- package/wasi.ts +0 -4
- package/websocket.ts +0 -1
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { WebHostTerminalStyle } from "../WebHostTerminalStyle.js";
|
|
2
|
+
import { WebHostOutputSink, encodeRenderStyleControlMessage, encodeResizeControlMessage } from "../WebHostSurfaceTransport.js";
|
|
3
|
+
import { StdIOPipe } from "./StdIOPipe.js";
|
|
4
|
+
|
|
5
|
+
//#region src/wasi/BrowserWASIBridge.d.ts
|
|
6
|
+
interface BrowserWASIBridgeOptions {
|
|
7
|
+
sceneId: string;
|
|
8
|
+
columns: number;
|
|
9
|
+
rows: number;
|
|
10
|
+
environment?: Record<string, string>;
|
|
11
|
+
renderStyle?: WebHostTerminalStyle;
|
|
12
|
+
}
|
|
13
|
+
type BrowserWASIOutputSink = WebHostOutputSink;
|
|
14
|
+
declare class BrowserWASIBridge {
|
|
15
|
+
readonly stdin: StdIOPipe;
|
|
16
|
+
readonly stdout: StdIOPipe;
|
|
17
|
+
readonly stderr: StdIOPipe;
|
|
18
|
+
readonly environment: Record<string, string>;
|
|
19
|
+
private detachStdout?;
|
|
20
|
+
private detachStderr?;
|
|
21
|
+
private readonly resizeListeners;
|
|
22
|
+
private latestResize;
|
|
23
|
+
constructor(options: BrowserWASIBridgeOptions);
|
|
24
|
+
bindOutput(sink: BrowserWASIOutputSink): void;
|
|
25
|
+
resize(columns: number, rows: number, cellWidth?: number, cellHeight?: number): void;
|
|
26
|
+
updateRenderStyle(style: WebHostTerminalStyle): void;
|
|
27
|
+
sendInput(chunk: Uint8Array): void;
|
|
28
|
+
subscribeResize(listener: (columns: number, rows: number, cellWidth?: number, cellHeight?: number) => void): () => void;
|
|
29
|
+
dispose(): void;
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
export { BrowserWASIBridge, BrowserWASIBridgeOptions, BrowserWASIOutputSink };
|
|
33
|
+
//# sourceMappingURL=BrowserWASIBridge.d.ts.map
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { StdIOPipe } from "./StdIOPipe.js";
|
|
2
|
+
import { encodeWebHostTerminalRenderStyleBase64 } from "../WebHostTerminalStyle.js";
|
|
3
|
+
import { WebHostOutputDecoder, encodeRenderStyleControlMessage, encodeResizeControlMessage } from "../WebHostSurfaceTransport.js";
|
|
4
|
+
//#region src/wasi/BrowserWASIBridge.ts
|
|
5
|
+
var BrowserWASIBridge = class {
|
|
6
|
+
stdin = new StdIOPipe();
|
|
7
|
+
stdout = new StdIOPipe();
|
|
8
|
+
stderr = new StdIOPipe();
|
|
9
|
+
environment;
|
|
10
|
+
detachStdout;
|
|
11
|
+
detachStderr;
|
|
12
|
+
resizeListeners = /* @__PURE__ */ new Set();
|
|
13
|
+
latestResize;
|
|
14
|
+
constructor(options) {
|
|
15
|
+
this.environment = {
|
|
16
|
+
TUIGUI_MODE: "browser",
|
|
17
|
+
TUIGUI_TRANSPORT: "surface",
|
|
18
|
+
TUIGUI_SURFACE_DELTA: "1",
|
|
19
|
+
TUIGUI_SCENE: options.sceneId,
|
|
20
|
+
TUIGUI_COLUMNS: String(Math.max(1, options.columns)),
|
|
21
|
+
TUIGUI_ROWS: String(Math.max(1, options.rows)),
|
|
22
|
+
...options.environment,
|
|
23
|
+
...options.renderStyle ? { TUIGUI_RENDER_STYLE: encodeWebHostTerminalRenderStyleBase64(options.renderStyle) } : {}
|
|
24
|
+
};
|
|
25
|
+
this.latestResize = {
|
|
26
|
+
columns: Math.max(1, options.columns),
|
|
27
|
+
rows: Math.max(1, options.rows)
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
bindOutput(sink) {
|
|
31
|
+
this.detachStdout?.();
|
|
32
|
+
this.detachStderr?.();
|
|
33
|
+
const decoder = new WebHostOutputDecoder();
|
|
34
|
+
this.detachStdout = this.stdout.subscribe((chunk) => {
|
|
35
|
+
for (const record of decoder.feed(chunk)) switch (record.type) {
|
|
36
|
+
case "surface":
|
|
37
|
+
sink.presentSurface(record.frame);
|
|
38
|
+
break;
|
|
39
|
+
case "clipboard":
|
|
40
|
+
sink.writeClipboard?.(record.text);
|
|
41
|
+
break;
|
|
42
|
+
case "runtimeIssue":
|
|
43
|
+
sink.notifyRuntimeIssue?.(record.issue);
|
|
44
|
+
break;
|
|
45
|
+
case "frameDiagnostic":
|
|
46
|
+
sink.recordFrameDiagnostic?.(record.diagnostic);
|
|
47
|
+
break;
|
|
48
|
+
case "text":
|
|
49
|
+
sink.writeOutput?.(record.text);
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
this.detachStderr = this.stderr.subscribe((chunk) => {
|
|
54
|
+
sink.writeError?.(new TextDecoder().decode(chunk));
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
resize(columns, rows, cellWidth, cellHeight) {
|
|
58
|
+
const normalizedColumns = Math.max(1, columns);
|
|
59
|
+
const normalizedRows = Math.max(1, rows);
|
|
60
|
+
this.environment.TUIGUI_COLUMNS = String(normalizedColumns);
|
|
61
|
+
this.environment.TUIGUI_ROWS = String(normalizedRows);
|
|
62
|
+
this.latestResize = {
|
|
63
|
+
columns: normalizedColumns,
|
|
64
|
+
rows: normalizedRows,
|
|
65
|
+
cellWidth,
|
|
66
|
+
cellHeight
|
|
67
|
+
};
|
|
68
|
+
this.stdin.write(encodeResizeControlMessage(columns, rows, cellWidth, cellHeight));
|
|
69
|
+
for (const listener of this.resizeListeners) listener(normalizedColumns, normalizedRows, cellWidth, cellHeight);
|
|
70
|
+
}
|
|
71
|
+
updateRenderStyle(style) {
|
|
72
|
+
this.environment.TUIGUI_RENDER_STYLE = encodeWebHostTerminalRenderStyleBase64(style);
|
|
73
|
+
this.stdin.write(encodeRenderStyleControlMessage(style));
|
|
74
|
+
}
|
|
75
|
+
sendInput(chunk) {
|
|
76
|
+
this.stdin.write(chunk);
|
|
77
|
+
}
|
|
78
|
+
subscribeResize(listener) {
|
|
79
|
+
this.resizeListeners.add(listener);
|
|
80
|
+
listener(this.latestResize.columns, this.latestResize.rows, this.latestResize.cellWidth, this.latestResize.cellHeight);
|
|
81
|
+
return () => {
|
|
82
|
+
this.resizeListeners.delete(listener);
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
dispose() {
|
|
86
|
+
this.detachStdout?.();
|
|
87
|
+
this.detachStderr?.();
|
|
88
|
+
this.resizeListeners.clear();
|
|
89
|
+
this.stdin.close();
|
|
90
|
+
this.stdout.close();
|
|
91
|
+
this.stderr.close();
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
//#endregion
|
|
95
|
+
export { BrowserWASIBridge };
|
|
96
|
+
|
|
97
|
+
//# sourceMappingURL=BrowserWASIBridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BrowserWASIBridge.js","names":[],"sources":["../../../src/wasi/BrowserWASIBridge.ts"],"sourcesContent":["import { StdIOPipe } from \"./StdIOPipe.ts\";\nimport {\n encodeWebHostTerminalRenderStyleBase64,\n type WebHostTerminalStyle,\n} from \"../WebHostTerminalStyle.ts\";\nimport {\n WebHostOutputDecoder,\n encodeRenderStyleControlMessage,\n encodeResizeControlMessage,\n type WebHostOutputSink,\n} from \"../WebHostSurfaceTransport.ts\";\n\nexport interface BrowserWASIBridgeOptions {\n sceneId: string;\n columns: number;\n rows: number;\n environment?: Record<string, string>;\n renderStyle?: WebHostTerminalStyle;\n}\n\nexport type BrowserWASIOutputSink = WebHostOutputSink;\n\nexport class BrowserWASIBridge {\n readonly stdin = new StdIOPipe();\n readonly stdout = new StdIOPipe();\n readonly stderr = new StdIOPipe();\n readonly environment: Record<string, string>;\n\n private detachStdout?: () => void;\n private detachStderr?: () => void;\n private readonly resizeListeners = new Set<(\n columns: number,\n rows: number,\n cellWidth?: number,\n cellHeight?: number\n ) => void>();\n private latestResize: {\n columns: number;\n rows: number;\n cellWidth?: number;\n cellHeight?: number;\n };\n\n constructor(options: BrowserWASIBridgeOptions) {\n this.environment = {\n TUIGUI_MODE: \"browser\",\n TUIGUI_TRANSPORT: \"surface\",\n TUIGUI_SURFACE_DELTA: \"1\",\n TUIGUI_SCENE: options.sceneId,\n TUIGUI_COLUMNS: String(Math.max(1, options.columns)),\n TUIGUI_ROWS: String(Math.max(1, options.rows)),\n ...options.environment,\n ...(options.renderStyle\n ? {\n TUIGUI_RENDER_STYLE: encodeWebHostTerminalRenderStyleBase64(\n options.renderStyle\n ),\n }\n : {}),\n };\n this.latestResize = {\n columns: Math.max(1, options.columns),\n rows: Math.max(1, options.rows),\n };\n }\n\n bindOutput(\n sink: BrowserWASIOutputSink\n ): void {\n this.detachStdout?.();\n this.detachStderr?.();\n const decoder = new WebHostOutputDecoder();\n this.detachStdout = this.stdout.subscribe((chunk) => {\n for (const record of decoder.feed(chunk)) {\n switch (record.type) {\n case \"surface\":\n sink.presentSurface(record.frame);\n break;\n case \"clipboard\":\n void sink.writeClipboard?.(record.text);\n break;\n case \"runtimeIssue\":\n sink.notifyRuntimeIssue?.(record.issue);\n break;\n case \"frameDiagnostic\":\n sink.recordFrameDiagnostic?.(record.diagnostic);\n break;\n case \"text\":\n sink.writeOutput?.(record.text);\n break;\n }\n }\n });\n this.detachStderr = this.stderr.subscribe((chunk) => {\n sink.writeError?.(new TextDecoder().decode(chunk));\n });\n }\n\n resize(\n columns: number,\n rows: number,\n cellWidth?: number,\n cellHeight?: number\n ): void {\n const normalizedColumns = Math.max(1, columns);\n const normalizedRows = Math.max(1, rows);\n this.environment.TUIGUI_COLUMNS = String(normalizedColumns);\n this.environment.TUIGUI_ROWS = String(normalizedRows);\n this.latestResize = {\n columns: normalizedColumns,\n rows: normalizedRows,\n cellWidth,\n cellHeight,\n };\n this.stdin.write(encodeResizeControlMessage(columns, rows, cellWidth, cellHeight));\n for (const listener of this.resizeListeners) {\n listener(normalizedColumns, normalizedRows, cellWidth, cellHeight);\n }\n }\n\n updateRenderStyle(\n style: WebHostTerminalStyle\n ): void {\n this.environment.TUIGUI_RENDER_STYLE = encodeWebHostTerminalRenderStyleBase64(style);\n this.stdin.write(encodeRenderStyleControlMessage(style));\n }\n\n sendInput(\n chunk: Uint8Array\n ): void {\n this.stdin.write(chunk);\n }\n\n subscribeResize(\n listener: (\n columns: number,\n rows: number,\n cellWidth?: number,\n cellHeight?: number\n ) => void\n ): () => void {\n this.resizeListeners.add(listener);\n listener(\n this.latestResize.columns,\n this.latestResize.rows,\n this.latestResize.cellWidth,\n this.latestResize.cellHeight\n );\n return () => {\n this.resizeListeners.delete(listener);\n };\n }\n\n dispose(): void {\n this.detachStdout?.();\n this.detachStderr?.();\n this.resizeListeners.clear();\n this.stdin.close();\n this.stdout.close();\n this.stderr.close();\n }\n}\n\nexport {\n encodeRenderStyleControlMessage,\n encodeResizeControlMessage,\n};\n"],"mappings":";;;;AAsBA,IAAa,oBAAb,MAA+B;CAC7B,QAAiB,IAAI,UAAU;CAC/B,SAAkB,IAAI,UAAU;CAChC,SAAkB,IAAI,UAAU;CAChC;CAEA;CACA;CACA,kCAAmC,IAAI,IAK5B;CACX;CAOA,YAAY,SAAmC;EAC7C,KAAK,cAAc;GACjB,aAAa;GACb,kBAAkB;GAClB,sBAAsB;GACtB,cAAc,QAAQ;GACtB,gBAAgB,OAAO,KAAK,IAAI,GAAG,QAAQ,OAAO,CAAC;GACnD,aAAa,OAAO,KAAK,IAAI,GAAG,QAAQ,IAAI,CAAC;GAC7C,GAAG,QAAQ;GACX,GAAI,QAAQ,cACR,EACE,qBAAqB,uCACnB,QAAQ,WACV,EACF,IACA,CAAC;EACP;EACA,KAAK,eAAe;GAClB,SAAS,KAAK,IAAI,GAAG,QAAQ,OAAO;GACpC,MAAM,KAAK,IAAI,GAAG,QAAQ,IAAI;EAChC;CACF;CAEA,WACE,MACM;EACN,KAAK,eAAe;EACpB,KAAK,eAAe;EACpB,MAAM,UAAU,IAAI,qBAAqB;EACzC,KAAK,eAAe,KAAK,OAAO,WAAW,UAAU;GACnD,KAAK,MAAM,UAAU,QAAQ,KAAK,KAAK,GACrC,QAAQ,OAAO,MAAf;IACA,KAAK;KACH,KAAK,eAAe,OAAO,KAAK;KAChC;IACF,KAAK;KACH,KAAU,iBAAiB,OAAO,IAAI;KACtC;IACF,KAAK;KACH,KAAK,qBAAqB,OAAO,KAAK;KACtC;IACF,KAAK;KACH,KAAK,wBAAwB,OAAO,UAAU;KAC9C;IACF,KAAK;KACH,KAAK,cAAc,OAAO,IAAI;KAC9B;GACF;EAEJ,CAAC;EACD,KAAK,eAAe,KAAK,OAAO,WAAW,UAAU;GACnD,KAAK,aAAa,IAAI,YAAY,CAAC,CAAC,OAAO,KAAK,CAAC;EACnD,CAAC;CACH;CAEA,OACE,SACA,MACA,WACA,YACM;EACN,MAAM,oBAAoB,KAAK,IAAI,GAAG,OAAO;EAC7C,MAAM,iBAAiB,KAAK,IAAI,GAAG,IAAI;EACvC,KAAK,YAAY,iBAAiB,OAAO,iBAAiB;EAC1D,KAAK,YAAY,cAAc,OAAO,cAAc;EACpD,KAAK,eAAe;GAClB,SAAS;GACT,MAAM;GACN;GACA;EACF;EACA,KAAK,MAAM,MAAM,2BAA2B,SAAS,MAAM,WAAW,UAAU,CAAC;EACjF,KAAK,MAAM,YAAY,KAAK,iBAC1B,SAAS,mBAAmB,gBAAgB,WAAW,UAAU;CAErE;CAEA,kBACE,OACM;EACN,KAAK,YAAY,sBAAsB,uCAAuC,KAAK;EACnF,KAAK,MAAM,MAAM,gCAAgC,KAAK,CAAC;CACzD;CAEA,UACE,OACM;EACN,KAAK,MAAM,MAAM,KAAK;CACxB;CAEA,gBACE,UAMY;EACZ,KAAK,gBAAgB,IAAI,QAAQ;EACjC,SACE,KAAK,aAAa,SAClB,KAAK,aAAa,MAClB,KAAK,aAAa,WAClB,KAAK,aAAa,UACpB;EACA,aAAa;GACX,KAAK,gBAAgB,OAAO,QAAQ;EACtC;CACF;CAEA,UAAgB;EACd,KAAK,eAAe;EACpB,KAAK,eAAe;EACpB,KAAK,gBAAgB,MAAM;EAC3B,KAAK,MAAM,MAAM;EACjB,KAAK,OAAO,MAAM;EAClB,KAAK,OAAO,MAAM;CACpB;AACF"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
//#region src/wasi/SharedInputQueue.d.ts
|
|
2
|
+
declare const sharedInputQueueDefaultCapacity: number;
|
|
3
|
+
interface SharedInputQueueBuffers {
|
|
4
|
+
readonly controlBuffer: SharedArrayBuffer;
|
|
5
|
+
readonly dataBuffer: SharedArrayBuffer;
|
|
6
|
+
}
|
|
7
|
+
type SharedInputReadiness = "readable" | "closed" | "timedOut";
|
|
8
|
+
interface SharedInputQueueState {
|
|
9
|
+
readonly control: Int32Array;
|
|
10
|
+
readonly data: Uint8Array;
|
|
11
|
+
}
|
|
12
|
+
declare function createSharedInputQueue(capacity?: number): SharedInputQueueBuffers;
|
|
13
|
+
declare function hydrateSharedInputQueue(buffers: SharedInputQueueBuffers): SharedInputQueueState;
|
|
14
|
+
declare class SharedInputQueueWriter {
|
|
15
|
+
private readonly queue;
|
|
16
|
+
constructor(buffers: SharedInputQueueBuffers);
|
|
17
|
+
write(chunk: Uint8Array | string): void;
|
|
18
|
+
close(): void;
|
|
19
|
+
}
|
|
20
|
+
declare class SharedInputQueueReader {
|
|
21
|
+
private readonly queue;
|
|
22
|
+
constructor(buffers: SharedInputQueueBuffers);
|
|
23
|
+
read(maxBytes: number): Uint8Array | undefined;
|
|
24
|
+
readAvailable(maxBytes: number): Uint8Array | undefined;
|
|
25
|
+
availableBytes(): number;
|
|
26
|
+
waitForReadable(timeoutMilliseconds?: number): SharedInputReadiness;
|
|
27
|
+
isClosed(): boolean;
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { SharedInputQueueBuffers, SharedInputQueueReader, SharedInputQueueWriter, SharedInputReadiness, createSharedInputQueue, hydrateSharedInputQueue, sharedInputQueueDefaultCapacity };
|
|
31
|
+
//# sourceMappingURL=SharedInputQueue.d.ts.map
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
//#region src/wasi/SharedInputQueue.ts
|
|
2
|
+
const controlSlots = 3;
|
|
3
|
+
const sharedInputQueueDefaultCapacity = 64 * 1024;
|
|
4
|
+
function createSharedInputQueue(capacity = sharedInputQueueDefaultCapacity) {
|
|
5
|
+
if (typeof SharedArrayBuffer === "undefined") throw new Error("SharedArrayBuffer is unavailable. Serve the app with COOP/COEP headers so browser WASI stdin can stay live.");
|
|
6
|
+
if (!Number.isInteger(capacity) || capacity <= 0) throw new Error(`Shared input queue capacity must be a positive integer, received ${capacity}.`);
|
|
7
|
+
return {
|
|
8
|
+
controlBuffer: new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * controlSlots),
|
|
9
|
+
dataBuffer: new SharedArrayBuffer(capacity)
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
function hydrateSharedInputQueue(buffers) {
|
|
13
|
+
return {
|
|
14
|
+
control: new Int32Array(buffers.controlBuffer),
|
|
15
|
+
data: new Uint8Array(buffers.dataBuffer)
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
var SharedInputQueueWriter = class {
|
|
19
|
+
queue;
|
|
20
|
+
constructor(buffers) {
|
|
21
|
+
this.queue = hydrateSharedInputQueue(buffers);
|
|
22
|
+
}
|
|
23
|
+
write(chunk) {
|
|
24
|
+
if (Atomics.load(this.queue.control, 2) !== 0) return;
|
|
25
|
+
const bytes = normalizeChunk(chunk);
|
|
26
|
+
if (bytes.length == 0) return;
|
|
27
|
+
const readIndex = Atomics.load(this.queue.control, 0);
|
|
28
|
+
const writeIndex = Atomics.load(this.queue.control, 1);
|
|
29
|
+
const usedCapacity = writeIndex - readIndex;
|
|
30
|
+
const availableCapacity = this.queue.data.length - usedCapacity;
|
|
31
|
+
if (bytes.length > availableCapacity) throw new Error(`Shared input queue overflow: cannot enqueue ${bytes.length} byte(s) into ${availableCapacity} byte(s) of free space.`);
|
|
32
|
+
writeToRingBuffer(this.queue.data, bytes, writeIndex);
|
|
33
|
+
Atomics.store(this.queue.control, 1, writeIndex + bytes.length);
|
|
34
|
+
Atomics.notify(this.queue.control, 1);
|
|
35
|
+
}
|
|
36
|
+
close() {
|
|
37
|
+
Atomics.store(this.queue.control, 2, 1);
|
|
38
|
+
Atomics.notify(this.queue.control, 1);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
var SharedInputQueueReader = class {
|
|
42
|
+
queue;
|
|
43
|
+
constructor(buffers) {
|
|
44
|
+
this.queue = hydrateSharedInputQueue(buffers);
|
|
45
|
+
}
|
|
46
|
+
read(maxBytes) {
|
|
47
|
+
while (true) {
|
|
48
|
+
const next = this.readAvailable(maxBytes);
|
|
49
|
+
if (next) return next;
|
|
50
|
+
if (this.isClosed()) return;
|
|
51
|
+
const writeIndex = Atomics.load(this.queue.control, 1);
|
|
52
|
+
Atomics.wait(this.queue.control, 1, writeIndex);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
readAvailable(maxBytes) {
|
|
56
|
+
if (!Number.isInteger(maxBytes) || maxBytes <= 0) return new Uint8Array();
|
|
57
|
+
const readIndex = Atomics.load(this.queue.control, 0);
|
|
58
|
+
const availableBytes = Atomics.load(this.queue.control, 1) - readIndex;
|
|
59
|
+
if (availableBytes <= 0) return;
|
|
60
|
+
const byteCount = Math.min(maxBytes, availableBytes);
|
|
61
|
+
const chunk = readFromRingBuffer(this.queue.data, readIndex, byteCount);
|
|
62
|
+
Atomics.store(this.queue.control, 0, readIndex + byteCount);
|
|
63
|
+
return chunk;
|
|
64
|
+
}
|
|
65
|
+
availableBytes() {
|
|
66
|
+
const readIndex = Atomics.load(this.queue.control, 0);
|
|
67
|
+
const writeIndex = Atomics.load(this.queue.control, 1);
|
|
68
|
+
return Math.max(0, writeIndex - readIndex);
|
|
69
|
+
}
|
|
70
|
+
waitForReadable(timeoutMilliseconds) {
|
|
71
|
+
while (true) {
|
|
72
|
+
if (this.availableBytes() > 0) return "readable";
|
|
73
|
+
if (this.isClosed()) return "closed";
|
|
74
|
+
const writeIndex = Atomics.load(this.queue.control, 1);
|
|
75
|
+
if (Atomics.wait(this.queue.control, 1, writeIndex, timeoutMilliseconds) === "timed-out") return "timedOut";
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
isClosed() {
|
|
79
|
+
return Atomics.load(this.queue.control, 2) !== 0;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
function normalizeChunk(chunk) {
|
|
83
|
+
return typeof chunk == "string" ? new TextEncoder().encode(chunk) : new Uint8Array(chunk);
|
|
84
|
+
}
|
|
85
|
+
function writeToRingBuffer(buffer, chunk, startIndex) {
|
|
86
|
+
const offset = startIndex % buffer.length;
|
|
87
|
+
const firstSegmentLength = Math.min(chunk.length, buffer.length - offset);
|
|
88
|
+
buffer.set(chunk.subarray(0, firstSegmentLength), offset);
|
|
89
|
+
if (firstSegmentLength < chunk.length) buffer.set(chunk.subarray(firstSegmentLength), 0);
|
|
90
|
+
}
|
|
91
|
+
function readFromRingBuffer(buffer, startIndex, byteCount) {
|
|
92
|
+
const chunk = new Uint8Array(byteCount);
|
|
93
|
+
const offset = startIndex % buffer.length;
|
|
94
|
+
const firstSegmentLength = Math.min(byteCount, buffer.length - offset);
|
|
95
|
+
chunk.set(buffer.subarray(offset, offset + firstSegmentLength), 0);
|
|
96
|
+
if (firstSegmentLength < byteCount) chunk.set(buffer.subarray(0, byteCount - firstSegmentLength), firstSegmentLength);
|
|
97
|
+
return chunk;
|
|
98
|
+
}
|
|
99
|
+
//#endregion
|
|
100
|
+
export { SharedInputQueueReader, SharedInputQueueWriter, createSharedInputQueue, hydrateSharedInputQueue, sharedInputQueueDefaultCapacity };
|
|
101
|
+
|
|
102
|
+
//# sourceMappingURL=SharedInputQueue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SharedInputQueue.js","names":[],"sources":["../../../src/wasi/SharedInputQueue.ts"],"sourcesContent":["const controlSlots = 3;\n\nconst enum ControlSlot {\n readIndex = 0,\n writeIndex = 1,\n closed = 2,\n}\n\nexport const sharedInputQueueDefaultCapacity = 64 * 1024;\n\nexport interface SharedInputQueueBuffers {\n readonly controlBuffer: SharedArrayBuffer;\n readonly dataBuffer: SharedArrayBuffer;\n}\n\nexport type SharedInputReadiness = \"readable\" | \"closed\" | \"timedOut\";\n\ninterface SharedInputQueueState {\n readonly control: Int32Array;\n readonly data: Uint8Array;\n}\n\nexport function createSharedInputQueue(\n capacity: number = sharedInputQueueDefaultCapacity\n): SharedInputQueueBuffers {\n if (typeof SharedArrayBuffer === \"undefined\") {\n throw new Error(\n \"SharedArrayBuffer is unavailable. Serve the app with COOP/COEP headers so browser WASI stdin can stay live.\"\n );\n }\n\n if (!Number.isInteger(capacity) || capacity <= 0) {\n throw new Error(`Shared input queue capacity must be a positive integer, received ${capacity}.`);\n }\n\n return {\n controlBuffer: new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * controlSlots),\n dataBuffer: new SharedArrayBuffer(capacity),\n };\n}\n\nexport function hydrateSharedInputQueue(\n buffers: SharedInputQueueBuffers\n): SharedInputQueueState {\n return {\n control: new Int32Array(buffers.controlBuffer),\n data: new Uint8Array(buffers.dataBuffer),\n };\n}\n\nexport class SharedInputQueueWriter {\n private readonly queue: SharedInputQueueState;\n\n constructor(buffers: SharedInputQueueBuffers) {\n this.queue = hydrateSharedInputQueue(buffers);\n }\n\n write(chunk: Uint8Array | string): void {\n if (Atomics.load(this.queue.control, ControlSlot.closed) !== 0) {\n return;\n }\n\n const bytes = normalizeChunk(chunk);\n if (bytes.length == 0) {\n return;\n }\n\n const readIndex = Atomics.load(this.queue.control, ControlSlot.readIndex);\n const writeIndex = Atomics.load(this.queue.control, ControlSlot.writeIndex);\n const usedCapacity = writeIndex - readIndex;\n const availableCapacity = this.queue.data.length - usedCapacity;\n\n if (bytes.length > availableCapacity) {\n throw new Error(\n `Shared input queue overflow: cannot enqueue ${bytes.length} byte(s) into ${availableCapacity} byte(s) of free space.`\n );\n }\n\n writeToRingBuffer(this.queue.data, bytes, writeIndex);\n Atomics.store(this.queue.control, ControlSlot.writeIndex, writeIndex + bytes.length);\n Atomics.notify(this.queue.control, ControlSlot.writeIndex);\n }\n\n close(): void {\n Atomics.store(this.queue.control, ControlSlot.closed, 1);\n Atomics.notify(this.queue.control, ControlSlot.writeIndex);\n }\n}\n\nexport class SharedInputQueueReader {\n private readonly queue: SharedInputQueueState;\n\n constructor(buffers: SharedInputQueueBuffers) {\n this.queue = hydrateSharedInputQueue(buffers);\n }\n\n read(maxBytes: number): Uint8Array | undefined {\n while (true) {\n const next = this.readAvailable(maxBytes);\n if (next) {\n return next;\n }\n\n if (this.isClosed()) {\n return undefined;\n }\n\n const writeIndex = Atomics.load(this.queue.control, ControlSlot.writeIndex);\n Atomics.wait(this.queue.control, ControlSlot.writeIndex, writeIndex);\n }\n }\n\n readAvailable(maxBytes: number): Uint8Array | undefined {\n if (!Number.isInteger(maxBytes) || maxBytes <= 0) {\n return new Uint8Array();\n }\n\n const readIndex = Atomics.load(this.queue.control, ControlSlot.readIndex);\n const writeIndex = Atomics.load(this.queue.control, ControlSlot.writeIndex);\n const availableBytes = writeIndex - readIndex;\n\n if (availableBytes <= 0) {\n return undefined;\n }\n\n const byteCount = Math.min(maxBytes, availableBytes);\n const chunk = readFromRingBuffer(this.queue.data, readIndex, byteCount);\n Atomics.store(this.queue.control, ControlSlot.readIndex, readIndex + byteCount);\n return chunk;\n }\n\n availableBytes(): number {\n const readIndex = Atomics.load(this.queue.control, ControlSlot.readIndex);\n const writeIndex = Atomics.load(this.queue.control, ControlSlot.writeIndex);\n return Math.max(0, writeIndex - readIndex);\n }\n\n waitForReadable(\n timeoutMilliseconds?: number\n ): SharedInputReadiness {\n while (true) {\n if (this.availableBytes() > 0) {\n return \"readable\";\n }\n if (this.isClosed()) {\n return \"closed\";\n }\n\n const writeIndex = Atomics.load(this.queue.control, ControlSlot.writeIndex);\n const result = Atomics.wait(\n this.queue.control,\n ControlSlot.writeIndex,\n writeIndex,\n timeoutMilliseconds\n );\n if (result === \"timed-out\") {\n return \"timedOut\";\n }\n }\n }\n\n isClosed(): boolean {\n return Atomics.load(this.queue.control, ControlSlot.closed) !== 0;\n }\n}\n\nfunction normalizeChunk(\n chunk: Uint8Array | string\n): Uint8Array {\n return typeof chunk == \"string\" ? new TextEncoder().encode(chunk) : new Uint8Array(chunk);\n}\n\nfunction writeToRingBuffer(\n buffer: Uint8Array,\n chunk: Uint8Array,\n startIndex: number\n): void {\n const offset = startIndex % buffer.length;\n const firstSegmentLength = Math.min(chunk.length, buffer.length - offset);\n buffer.set(chunk.subarray(0, firstSegmentLength), offset);\n if (firstSegmentLength < chunk.length) {\n buffer.set(chunk.subarray(firstSegmentLength), 0);\n }\n}\n\nfunction readFromRingBuffer(\n buffer: Uint8Array,\n startIndex: number,\n byteCount: number\n): Uint8Array {\n const chunk = new Uint8Array(byteCount);\n const offset = startIndex % buffer.length;\n const firstSegmentLength = Math.min(byteCount, buffer.length - offset);\n chunk.set(buffer.subarray(offset, offset + firstSegmentLength), 0);\n if (firstSegmentLength < byteCount) {\n chunk.set(buffer.subarray(0, byteCount - firstSegmentLength), firstSegmentLength);\n }\n return chunk;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/wasi/StdIOPipe.d.ts
|
|
2
|
+
declare class StdIOPipe implements AsyncIterable<Uint8Array> {
|
|
3
|
+
private readonly chunks;
|
|
4
|
+
private readonly waiters;
|
|
5
|
+
private readonly listeners;
|
|
6
|
+
private closed;
|
|
7
|
+
write(chunk: Uint8Array | string): void;
|
|
8
|
+
close(): void;
|
|
9
|
+
read(): Promise<Uint8Array | undefined>;
|
|
10
|
+
subscribe(listener: (chunk: Uint8Array) => void): () => void;
|
|
11
|
+
[Symbol.asyncIterator](): AsyncIterator<Uint8Array>;
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
export { StdIOPipe };
|
|
15
|
+
//# sourceMappingURL=StdIOPipe.d.ts.map
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
//#region src/wasi/StdIOPipe.ts
|
|
2
|
+
var StdIOPipe = class {
|
|
3
|
+
chunks = [];
|
|
4
|
+
waiters = [];
|
|
5
|
+
listeners = /* @__PURE__ */ new Set();
|
|
6
|
+
closed = false;
|
|
7
|
+
write(chunk) {
|
|
8
|
+
if (this.closed) return;
|
|
9
|
+
const bytes = typeof chunk === "string" ? new TextEncoder().encode(chunk) : new Uint8Array(chunk);
|
|
10
|
+
const waiter = this.waiters.shift();
|
|
11
|
+
if (waiter) {
|
|
12
|
+
waiter({
|
|
13
|
+
done: false,
|
|
14
|
+
value: bytes
|
|
15
|
+
});
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
this.chunks.push(bytes);
|
|
19
|
+
for (const listener of this.listeners) listener(bytes);
|
|
20
|
+
}
|
|
21
|
+
close() {
|
|
22
|
+
if (this.closed) return;
|
|
23
|
+
this.closed = true;
|
|
24
|
+
while (this.waiters.length > 0) this.waiters.shift()?.({
|
|
25
|
+
done: true,
|
|
26
|
+
value: void 0
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
async read() {
|
|
30
|
+
const next = this.chunks.shift();
|
|
31
|
+
if (next) return next;
|
|
32
|
+
if (this.closed) return;
|
|
33
|
+
return await new Promise((resolve) => {
|
|
34
|
+
this.waiters.push((result) => {
|
|
35
|
+
resolve(result.done ? void 0 : result.value);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
subscribe(listener) {
|
|
40
|
+
this.listeners.add(listener);
|
|
41
|
+
return () => {
|
|
42
|
+
this.listeners.delete(listener);
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
async *[Symbol.asyncIterator]() {
|
|
46
|
+
while (true) {
|
|
47
|
+
const next = await this.read();
|
|
48
|
+
if (!next) return;
|
|
49
|
+
yield next;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
//#endregion
|
|
54
|
+
export { StdIOPipe };
|
|
55
|
+
|
|
56
|
+
//# sourceMappingURL=StdIOPipe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StdIOPipe.js","names":[],"sources":["../../../src/wasi/StdIOPipe.ts"],"sourcesContent":["export class StdIOPipe implements AsyncIterable<Uint8Array> {\n private readonly chunks: Uint8Array[] = [];\n private readonly waiters: Array<(value: IteratorResult<Uint8Array>) => void> = [];\n private readonly listeners = new Set<(chunk: Uint8Array) => void>();\n private closed = false;\n\n write(chunk: Uint8Array | string): void {\n if (this.closed) {\n return;\n }\n\n const bytes = typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : new Uint8Array(chunk);\n const waiter = this.waiters.shift();\n if (waiter) {\n waiter({ done: false, value: bytes });\n return;\n }\n\n this.chunks.push(bytes);\n for (const listener of this.listeners) {\n listener(bytes);\n }\n }\n\n close(): void {\n if (this.closed) {\n return;\n }\n\n this.closed = true;\n while (this.waiters.length > 0) {\n const waiter = this.waiters.shift();\n waiter?.({ done: true, value: undefined as never });\n }\n }\n\n async read(): Promise<Uint8Array | undefined> {\n const next = this.chunks.shift();\n if (next) {\n return next;\n }\n\n if (this.closed) {\n return undefined;\n }\n\n return await new Promise<Uint8Array | undefined>((resolve) => {\n this.waiters.push((result) => {\n resolve(result.done ? undefined : result.value);\n });\n });\n }\n\n subscribe(\n listener: (chunk: Uint8Array) => void\n ): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n async *[Symbol.asyncIterator](): AsyncIterator<Uint8Array> {\n while (true) {\n const next = await this.read();\n if (!next) {\n return;\n }\n yield next;\n }\n }\n}\n"],"mappings":";AAAA,IAAa,YAAb,MAA4D;CAC1D,SAAwC,CAAC;CACzC,UAA+E,CAAC;CAChF,4BAA6B,IAAI,IAAiC;CAClE,SAAiB;CAEjB,MAAM,OAAkC;EACtC,IAAI,KAAK,QACP;EAGF,MAAM,QAAQ,OAAO,UAAU,WAAW,IAAI,YAAY,CAAC,CAAC,OAAO,KAAK,IAAI,IAAI,WAAW,KAAK;EAChG,MAAM,SAAS,KAAK,QAAQ,MAAM;EAClC,IAAI,QAAQ;GACV,OAAO;IAAE,MAAM;IAAO,OAAO;GAAM,CAAC;GACpC;EACF;EAEA,KAAK,OAAO,KAAK,KAAK;EACtB,KAAK,MAAM,YAAY,KAAK,WAC1B,SAAS,KAAK;CAElB;CAEA,QAAc;EACZ,IAAI,KAAK,QACP;EAGF,KAAK,SAAS;EACd,OAAO,KAAK,QAAQ,SAAS,GAE3B,KADoB,QAAQ,MACvB,CAAC,GAAG;GAAE,MAAM;GAAM,OAAO,KAAA;EAAmB,CAAC;CAEtD;CAEA,MAAM,OAAwC;EAC5C,MAAM,OAAO,KAAK,OAAO,MAAM;EAC/B,IAAI,MACF,OAAO;EAGT,IAAI,KAAK,QACP;EAGF,OAAO,MAAM,IAAI,SAAiC,YAAY;GAC5D,KAAK,QAAQ,MAAM,WAAW;IAC5B,QAAQ,OAAO,OAAO,KAAA,IAAY,OAAO,KAAK;GAChD,CAAC;EACH,CAAC;CACH;CAEA,UACE,UACY;EACZ,KAAK,UAAU,IAAI,QAAQ;EAC3B,aAAa;GACX,KAAK,UAAU,OAAO,QAAQ;EAChC;CACF;CAEA,QAAQ,OAAO,iBAA4C;EACzD,OAAO,MAAM;GACX,MAAM,OAAO,MAAM,KAAK,KAAK;GAC7B,IAAI,CAAC,MACH;GAEF,MAAM;EACR;CACF;AACF"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { wasi } from "@bjorn3/browser_wasi_shim";
|
|
2
|
+
//#region src/wasi/WasiPollScheduler.ts
|
|
3
|
+
const subscriptionByteLength = 48;
|
|
4
|
+
const eventByteLength = 32;
|
|
5
|
+
const maximumAtomicsWaitMilliseconds = 2147483647;
|
|
6
|
+
var WasiPollScheduler = class {
|
|
7
|
+
memory;
|
|
8
|
+
stdin;
|
|
9
|
+
fallbackPoll;
|
|
10
|
+
nowMilliseconds;
|
|
11
|
+
waitBuffer = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT));
|
|
12
|
+
constructor(options) {
|
|
13
|
+
this.memory = options.memory;
|
|
14
|
+
this.stdin = options.stdin;
|
|
15
|
+
this.fallbackPoll = options.fallbackPoll;
|
|
16
|
+
this.nowMilliseconds = options.nowMilliseconds ?? (() => performance.now());
|
|
17
|
+
}
|
|
18
|
+
pollOneOff(inPtr, outPtr, nsubscriptions, neventsPtr) {
|
|
19
|
+
const memory = this.memory();
|
|
20
|
+
if (!memory || nsubscriptions <= 0) return this.fallbackPoll(inPtr, outPtr, nsubscriptions, neventsPtr);
|
|
21
|
+
const view = new DataView(memory.buffer);
|
|
22
|
+
const subscriptions = readSubscriptions(view, inPtr, nsubscriptions, this.nowMilliseconds());
|
|
23
|
+
if (subscriptions === void 0) return this.fallbackPoll(inPtr, outPtr, nsubscriptions, neventsPtr);
|
|
24
|
+
while (true) {
|
|
25
|
+
const ready = readySubscriptions(subscriptions, this.stdin, this.nowMilliseconds());
|
|
26
|
+
if (ready.length > 0) {
|
|
27
|
+
writeEvents(view, outPtr, ready, this.stdin);
|
|
28
|
+
if (neventsPtr !== void 0) view.setUint32(neventsPtr, ready.length, true);
|
|
29
|
+
return wasi.ERRNO_SUCCESS;
|
|
30
|
+
}
|
|
31
|
+
const timeoutMilliseconds = shortestClockTimeoutMilliseconds(subscriptions, this.nowMilliseconds());
|
|
32
|
+
if (hasFdReadSubscription(subscriptions)) this.stdin.waitForReadable(timeoutMilliseconds);
|
|
33
|
+
else if (timeoutMilliseconds !== void 0) Atomics.wait(this.waitBuffer, 0, 0, Math.min(timeoutMilliseconds, maximumAtomicsWaitMilliseconds));
|
|
34
|
+
else return this.fallbackPoll(inPtr, outPtr, nsubscriptions, neventsPtr);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
function readSubscriptions(view, inPtr, nsubscriptions, nowMilliseconds) {
|
|
39
|
+
const subscriptions = [];
|
|
40
|
+
for (let index = 0; index < nsubscriptions; index += 1) {
|
|
41
|
+
const subscription = wasi.Subscription.read_bytes(view, inPtr + index * subscriptionByteLength);
|
|
42
|
+
switch (subscription.eventtype) {
|
|
43
|
+
case wasi.EVENTTYPE_CLOCK:
|
|
44
|
+
if (!isSupportedClockId(subscription.clockid)) return;
|
|
45
|
+
subscriptions.push({
|
|
46
|
+
type: "clock",
|
|
47
|
+
userdata: subscription.userdata,
|
|
48
|
+
clockid: subscription.clockid,
|
|
49
|
+
deadlineMilliseconds: clockDeadlineMilliseconds(subscription, nowMilliseconds)
|
|
50
|
+
});
|
|
51
|
+
break;
|
|
52
|
+
case wasi.EVENTTYPE_FD_READ:
|
|
53
|
+
if (subscription.clockid !== wasi.FD_STDIN) return;
|
|
54
|
+
subscriptions.push({
|
|
55
|
+
type: "fdRead",
|
|
56
|
+
userdata: subscription.userdata,
|
|
57
|
+
fd: subscription.clockid
|
|
58
|
+
});
|
|
59
|
+
break;
|
|
60
|
+
default: return;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return subscriptions;
|
|
64
|
+
}
|
|
65
|
+
function isSupportedClockId(clockid) {
|
|
66
|
+
return clockid === wasi.CLOCKID_MONOTONIC || clockid === wasi.CLOCKID_REALTIME;
|
|
67
|
+
}
|
|
68
|
+
function shortestClockTimeoutMilliseconds(subscriptions, nowMilliseconds) {
|
|
69
|
+
let timeoutMilliseconds;
|
|
70
|
+
for (const subscription of subscriptions) {
|
|
71
|
+
if (subscription.type !== "clock") continue;
|
|
72
|
+
const remaining = clockRemainingMilliseconds(subscription, nowMilliseconds);
|
|
73
|
+
timeoutMilliseconds = timeoutMilliseconds === void 0 ? remaining : Math.min(timeoutMilliseconds, remaining);
|
|
74
|
+
}
|
|
75
|
+
return timeoutMilliseconds;
|
|
76
|
+
}
|
|
77
|
+
function readySubscriptions(subscriptions, stdin, nowMilliseconds) {
|
|
78
|
+
return subscriptions.filter((subscription) => {
|
|
79
|
+
switch (subscription.type) {
|
|
80
|
+
case "clock": return clockRemainingMilliseconds(subscription, nowMilliseconds) <= 0;
|
|
81
|
+
case "fdRead": return stdin.availableBytes() > 0 || stdin.isClosed();
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
function hasFdReadSubscription(subscriptions) {
|
|
86
|
+
return subscriptions.some((subscription) => subscription.type === "fdRead");
|
|
87
|
+
}
|
|
88
|
+
function clockRemainingMilliseconds(subscription, nowMilliseconds) {
|
|
89
|
+
return Math.max(0, subscription.deadlineMilliseconds - nowMillisecondsForClock(subscription.clockid, nowMilliseconds));
|
|
90
|
+
}
|
|
91
|
+
function clockDeadlineMilliseconds(subscription, nowMilliseconds) {
|
|
92
|
+
if ((subscription.flags & wasi.SUBCLOCKFLAGS_SUBSCRIPTION_CLOCK_ABSTIME) !== 0) return Number(subscription.timeout) / 1e6;
|
|
93
|
+
return nowMillisecondsForClock(subscription.clockid, nowMilliseconds) + Number(subscription.timeout) / 1e6;
|
|
94
|
+
}
|
|
95
|
+
function nowMillisecondsForClock(clockid, nowMilliseconds) {
|
|
96
|
+
if (clockid === wasi.CLOCKID_REALTIME) return Date.now();
|
|
97
|
+
return nowMilliseconds;
|
|
98
|
+
}
|
|
99
|
+
function writeEvents(view, outPtr, subscriptions, stdin) {
|
|
100
|
+
subscriptions.forEach((subscription, index) => {
|
|
101
|
+
const eventtype = subscription.type === "clock" ? wasi.EVENTTYPE_CLOCK : wasi.EVENTTYPE_FD_READ;
|
|
102
|
+
const offset = outPtr + index * eventByteLength;
|
|
103
|
+
new wasi.Event(subscription.userdata, wasi.ERRNO_SUCCESS, eventtype).write_bytes(view, offset);
|
|
104
|
+
if (subscription.type === "fdRead") {
|
|
105
|
+
const availableBytes = Math.max(0, stdin.availableBytes());
|
|
106
|
+
view.setBigUint64(offset + 16, BigInt(availableBytes), true);
|
|
107
|
+
if (availableBytes === 0 && stdin.isClosed()) view.setUint16(offset + 24, wasi.EVENTRWFLAGS_FD_READWRITE_HANGUP, true);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
//#endregion
|
|
112
|
+
export { WasiPollScheduler };
|
|
113
|
+
|
|
114
|
+
//# sourceMappingURL=WasiPollScheduler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WasiPollScheduler.js","names":[],"sources":["../../../src/wasi/WasiPollScheduler.ts"],"sourcesContent":["import { wasi } from \"@bjorn3/browser_wasi_shim\";\n\nimport type { SharedInputReadiness } from \"./SharedInputQueue.ts\";\n\nconst subscriptionByteLength = 48;\nconst eventByteLength = 32;\nconst maximumAtomicsWaitMilliseconds = 2_147_483_647;\n\ninterface ClockSubscription {\n readonly type: \"clock\";\n readonly userdata: bigint;\n readonly clockid: number;\n readonly deadlineMilliseconds: number;\n}\n\ninterface FdReadSubscription {\n readonly type: \"fdRead\";\n readonly userdata: bigint;\n readonly fd: number;\n}\n\ntype SupportedSubscription = ClockSubscription | FdReadSubscription;\n\nexport interface WasiPollReadableSource {\n availableBytes(): number;\n isClosed(): boolean;\n waitForReadable(timeoutMilliseconds?: number): SharedInputReadiness;\n}\n\nexport interface WasiPollSchedulerOptions {\n memory(): WebAssembly.Memory | undefined;\n stdin: WasiPollReadableSource;\n fallbackPoll(\n inPtr: number,\n outPtr: number,\n nsubscriptions: number,\n neventsPtr?: number\n ): number;\n nowMilliseconds?(): number;\n}\n\nexport class WasiPollScheduler {\n private readonly memory: WasiPollSchedulerOptions[\"memory\"];\n private readonly stdin: WasiPollReadableSource;\n private readonly fallbackPoll: WasiPollSchedulerOptions[\"fallbackPoll\"];\n private readonly nowMilliseconds: () => number;\n private readonly waitBuffer = new Int32Array(\n new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT)\n );\n\n constructor(options: WasiPollSchedulerOptions) {\n this.memory = options.memory;\n this.stdin = options.stdin;\n this.fallbackPoll = options.fallbackPoll;\n this.nowMilliseconds = options.nowMilliseconds ?? (() => performance.now());\n }\n\n pollOneOff(\n inPtr: number,\n outPtr: number,\n nsubscriptions: number,\n neventsPtr?: number\n ): number {\n const memory = this.memory();\n if (!memory || nsubscriptions <= 0) {\n return this.fallbackPoll(inPtr, outPtr, nsubscriptions, neventsPtr);\n }\n\n const view = new DataView(memory.buffer);\n const subscriptions = readSubscriptions(\n view,\n inPtr,\n nsubscriptions,\n this.nowMilliseconds()\n );\n if (subscriptions === undefined) {\n return this.fallbackPoll(inPtr, outPtr, nsubscriptions, neventsPtr);\n }\n\n while (true) {\n const ready = readySubscriptions(subscriptions, this.stdin, this.nowMilliseconds());\n if (ready.length > 0) {\n writeEvents(view, outPtr, ready, this.stdin);\n if (neventsPtr !== undefined) {\n view.setUint32(neventsPtr, ready.length, true);\n }\n return wasi.ERRNO_SUCCESS;\n }\n\n const timeoutMilliseconds = shortestClockTimeoutMilliseconds(\n subscriptions,\n this.nowMilliseconds()\n );\n if (hasFdReadSubscription(subscriptions)) {\n this.stdin.waitForReadable(timeoutMilliseconds);\n } else if (timeoutMilliseconds !== undefined) {\n Atomics.wait(\n this.waitBuffer,\n 0,\n 0,\n Math.min(timeoutMilliseconds, maximumAtomicsWaitMilliseconds)\n );\n } else {\n return this.fallbackPoll(inPtr, outPtr, nsubscriptions, neventsPtr);\n }\n }\n }\n}\n\nfunction readSubscriptions(\n view: DataView,\n inPtr: number,\n nsubscriptions: number,\n nowMilliseconds: number\n): SupportedSubscription[] | undefined {\n const subscriptions: SupportedSubscription[] = [];\n for (let index = 0; index < nsubscriptions; index += 1) {\n const subscription = wasi.Subscription.read_bytes(\n view,\n inPtr + index * subscriptionByteLength\n );\n switch (subscription.eventtype) {\n case wasi.EVENTTYPE_CLOCK:\n if (!isSupportedClockId(subscription.clockid)) {\n return undefined;\n }\n subscriptions.push({\n type: \"clock\",\n userdata: subscription.userdata,\n clockid: subscription.clockid,\n deadlineMilliseconds: clockDeadlineMilliseconds(subscription, nowMilliseconds),\n });\n break;\n case wasi.EVENTTYPE_FD_READ:\n if (subscription.clockid !== wasi.FD_STDIN) {\n return undefined;\n }\n subscriptions.push({\n type: \"fdRead\",\n userdata: subscription.userdata,\n fd: subscription.clockid,\n });\n break;\n default:\n return undefined;\n }\n }\n return subscriptions;\n}\n\nfunction isSupportedClockId(\n clockid: number\n): boolean {\n return clockid === wasi.CLOCKID_MONOTONIC || clockid === wasi.CLOCKID_REALTIME;\n}\n\nfunction shortestClockTimeoutMilliseconds(\n subscriptions: readonly SupportedSubscription[],\n nowMilliseconds: number\n): number | undefined {\n let timeoutMilliseconds: number | undefined;\n for (const subscription of subscriptions) {\n if (subscription.type !== \"clock\") {\n continue;\n }\n const remaining = clockRemainingMilliseconds(subscription, nowMilliseconds);\n timeoutMilliseconds = timeoutMilliseconds === undefined\n ? remaining\n : Math.min(timeoutMilliseconds, remaining);\n }\n return timeoutMilliseconds;\n}\n\nfunction readySubscriptions(\n subscriptions: readonly SupportedSubscription[],\n stdin: WasiPollReadableSource,\n nowMilliseconds: number\n): SupportedSubscription[] {\n return subscriptions.filter((subscription) => {\n switch (subscription.type) {\n case \"clock\":\n return clockRemainingMilliseconds(subscription, nowMilliseconds) <= 0;\n case \"fdRead\":\n return stdin.availableBytes() > 0 || stdin.isClosed();\n }\n });\n}\n\nfunction hasFdReadSubscription(\n subscriptions: readonly SupportedSubscription[]\n): boolean {\n return subscriptions.some((subscription) => subscription.type === \"fdRead\");\n}\n\nfunction clockRemainingMilliseconds(\n subscription: ClockSubscription,\n nowMilliseconds: number\n): number {\n return Math.max(0, subscription.deadlineMilliseconds - nowMillisecondsForClock(\n subscription.clockid,\n nowMilliseconds\n ));\n}\n\nfunction clockDeadlineMilliseconds(\n subscription: wasi.Subscription,\n nowMilliseconds: number\n): number {\n if ((subscription.flags & wasi.SUBCLOCKFLAGS_SUBSCRIPTION_CLOCK_ABSTIME) !== 0) {\n return Number(subscription.timeout) / 1_000_000;\n }\n return nowMillisecondsForClock(subscription.clockid, nowMilliseconds)\n + Number(subscription.timeout) / 1_000_000;\n}\n\nfunction nowMillisecondsForClock(\n clockid: number,\n nowMilliseconds: number\n): number {\n if (clockid === wasi.CLOCKID_REALTIME) {\n return Date.now();\n }\n return nowMilliseconds;\n}\n\nfunction writeEvents(\n view: DataView,\n outPtr: number,\n subscriptions: readonly SupportedSubscription[],\n stdin: WasiPollReadableSource\n): void {\n subscriptions.forEach((subscription, index) => {\n const eventtype = subscription.type === \"clock\"\n ? wasi.EVENTTYPE_CLOCK\n : wasi.EVENTTYPE_FD_READ;\n const offset = outPtr + index * eventByteLength;\n new wasi.Event(\n subscription.userdata,\n wasi.ERRNO_SUCCESS,\n eventtype\n ).write_bytes(view, offset);\n if (subscription.type === \"fdRead\") {\n const availableBytes = Math.max(0, stdin.availableBytes());\n view.setBigUint64(offset + 16, BigInt(availableBytes), true);\n if (availableBytes === 0 && stdin.isClosed()) {\n view.setUint16(offset + 24, wasi.EVENTRWFLAGS_FD_READWRITE_HANGUP, true);\n }\n }\n });\n}\n\nexport function writeClockSubscriptionForTesting(\n view: DataView,\n offset: number,\n subscription: {\n userdata: bigint;\n timeoutNanoseconds: bigint;\n clockid?: number;\n flags?: number;\n }\n): void {\n clearRecord(view, offset, subscriptionByteLength);\n view.setBigUint64(offset, subscription.userdata, true);\n view.setUint8(offset + 8, wasi.EVENTTYPE_CLOCK);\n view.setUint32(offset + 16, subscription.clockid ?? wasi.CLOCKID_MONOTONIC, true);\n view.setBigUint64(offset + 24, subscription.timeoutNanoseconds, true);\n view.setUint16(offset + 36, subscription.flags ?? 0, true);\n}\n\nexport function writeFdReadSubscriptionForTesting(\n view: DataView,\n offset: number,\n subscription: {\n userdata: bigint;\n fd: number;\n }\n): void {\n clearRecord(view, offset, subscriptionByteLength);\n view.setBigUint64(offset, subscription.userdata, true);\n view.setUint8(offset + 8, wasi.EVENTTYPE_FD_READ);\n view.setUint32(offset + 16, subscription.fd, true);\n}\n\nexport function readPollEventsForTesting(\n view: DataView,\n offset: number,\n count: number\n): Array<{ userdata: bigint; errno: number; eventtype: number }> {\n return Array.from({ length: count }, (_, index) => {\n const eventOffset = offset + index * eventByteLength;\n return {\n userdata: view.getBigUint64(eventOffset, true),\n errno: view.getUint16(eventOffset + 8, true),\n eventtype: view.getUint8(eventOffset + 10),\n };\n });\n}\n\nfunction clearRecord(\n view: DataView,\n offset: number,\n byteLength: number\n): void {\n new Uint8Array(view.buffer, offset, byteLength).fill(0);\n}\n"],"mappings":";;AAIA,MAAM,yBAAyB;AAC/B,MAAM,kBAAkB;AACxB,MAAM,iCAAiC;AAmCvC,IAAa,oBAAb,MAA+B;CAC7B;CACA;CACA;CACA;CACA,aAA8B,IAAI,WAChC,IAAI,kBAAkB,WAAW,iBAAiB,CACpD;CAEA,YAAY,SAAmC;EAC7C,KAAK,SAAS,QAAQ;EACtB,KAAK,QAAQ,QAAQ;EACrB,KAAK,eAAe,QAAQ;EAC5B,KAAK,kBAAkB,QAAQ,0BAA0B,YAAY,IAAI;CAC3E;CAEA,WACE,OACA,QACA,gBACA,YACQ;EACR,MAAM,SAAS,KAAK,OAAO;EAC3B,IAAI,CAAC,UAAU,kBAAkB,GAC/B,OAAO,KAAK,aAAa,OAAO,QAAQ,gBAAgB,UAAU;EAGpE,MAAM,OAAO,IAAI,SAAS,OAAO,MAAM;EACvC,MAAM,gBAAgB,kBACpB,MACA,OACA,gBACA,KAAK,gBAAgB,CACvB;EACA,IAAI,kBAAkB,KAAA,GACpB,OAAO,KAAK,aAAa,OAAO,QAAQ,gBAAgB,UAAU;EAGpE,OAAO,MAAM;GACX,MAAM,QAAQ,mBAAmB,eAAe,KAAK,OAAO,KAAK,gBAAgB,CAAC;GAClF,IAAI,MAAM,SAAS,GAAG;IACpB,YAAY,MAAM,QAAQ,OAAO,KAAK,KAAK;IAC3C,IAAI,eAAe,KAAA,GACjB,KAAK,UAAU,YAAY,MAAM,QAAQ,IAAI;IAE/C,OAAO,KAAK;GACd;GAEA,MAAM,sBAAsB,iCAC1B,eACA,KAAK,gBAAgB,CACvB;GACA,IAAI,sBAAsB,aAAa,GACrC,KAAK,MAAM,gBAAgB,mBAAmB;QACzC,IAAI,wBAAwB,KAAA,GACjC,QAAQ,KACN,KAAK,YACL,GACA,GACA,KAAK,IAAI,qBAAqB,8BAA8B,CAC9D;QAEA,OAAO,KAAK,aAAa,OAAO,QAAQ,gBAAgB,UAAU;EAEtE;CACF;AACF;AAEA,SAAS,kBACP,MACA,OACA,gBACA,iBACqC;CACrC,MAAM,gBAAyC,CAAC;CAChD,KAAK,IAAI,QAAQ,GAAG,QAAQ,gBAAgB,SAAS,GAAG;EACtD,MAAM,eAAe,KAAK,aAAa,WACrC,MACA,QAAQ,QAAQ,sBAClB;EACA,QAAQ,aAAa,WAArB;GACA,KAAK,KAAK;IACR,IAAI,CAAC,mBAAmB,aAAa,OAAO,GAC1C;IAEF,cAAc,KAAK;KACjB,MAAM;KACN,UAAU,aAAa;KACvB,SAAS,aAAa;KACtB,sBAAsB,0BAA0B,cAAc,eAAe;IAC/E,CAAC;IACD;GACF,KAAK,KAAK;IACR,IAAI,aAAa,YAAY,KAAK,UAChC;IAEF,cAAc,KAAK;KACjB,MAAM;KACN,UAAU,aAAa;KACvB,IAAI,aAAa;IACnB,CAAC;IACD;GACF,SACE;EACF;CACF;CACA,OAAO;AACT;AAEA,SAAS,mBACP,SACS;CACT,OAAO,YAAY,KAAK,qBAAqB,YAAY,KAAK;AAChE;AAEA,SAAS,iCACP,eACA,iBACoB;CACpB,IAAI;CACJ,KAAK,MAAM,gBAAgB,eAAe;EACxC,IAAI,aAAa,SAAS,SACxB;EAEF,MAAM,YAAY,2BAA2B,cAAc,eAAe;EAC1E,sBAAsB,wBAAwB,KAAA,IAC1C,YACA,KAAK,IAAI,qBAAqB,SAAS;CAC7C;CACA,OAAO;AACT;AAEA,SAAS,mBACP,eACA,OACA,iBACyB;CACzB,OAAO,cAAc,QAAQ,iBAAiB;EAC5C,QAAQ,aAAa,MAArB;GACA,KAAK,SACH,OAAO,2BAA2B,cAAc,eAAe,KAAK;GACtE,KAAK,UACH,OAAO,MAAM,eAAe,IAAI,KAAK,MAAM,SAAS;EACtD;CACF,CAAC;AACH;AAEA,SAAS,sBACP,eACS;CACT,OAAO,cAAc,MAAM,iBAAiB,aAAa,SAAS,QAAQ;AAC5E;AAEA,SAAS,2BACP,cACA,iBACQ;CACR,OAAO,KAAK,IAAI,GAAG,aAAa,uBAAuB,wBACrD,aAAa,SACb,eACF,CAAC;AACH;AAEA,SAAS,0BACP,cACA,iBACQ;CACR,KAAK,aAAa,QAAQ,KAAK,8CAA8C,GAC3E,OAAO,OAAO,aAAa,OAAO,IAAI;CAExC,OAAO,wBAAwB,aAAa,SAAS,eAAe,IAChE,OAAO,aAAa,OAAO,IAAI;AACrC;AAEA,SAAS,wBACP,SACA,iBACQ;CACR,IAAI,YAAY,KAAK,kBACnB,OAAO,KAAK,IAAI;CAElB,OAAO;AACT;AAEA,SAAS,YACP,MACA,QACA,eACA,OACM;CACN,cAAc,SAAS,cAAc,UAAU;EAC7C,MAAM,YAAY,aAAa,SAAS,UACpC,KAAK,kBACL,KAAK;EACT,MAAM,SAAS,SAAS,QAAQ;EAChC,IAAI,KAAK,MACP,aAAa,UACb,KAAK,eACL,SACF,CAAC,CAAC,YAAY,MAAM,MAAM;EAC1B,IAAI,aAAa,SAAS,UAAU;GAClC,MAAM,iBAAiB,KAAK,IAAI,GAAG,MAAM,eAAe,CAAC;GACzD,KAAK,aAAa,SAAS,IAAI,OAAO,cAAc,GAAG,IAAI;GAC3D,IAAI,mBAAmB,KAAK,MAAM,SAAS,GACzC,KAAK,UAAU,SAAS,IAAI,KAAK,kCAAkC,IAAI;EAE3E;CACF,CAAC;AACH"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { WebHostSceneRuntime, WebHostSceneRuntimeOptions } from "../WebHostSceneRuntime.js";
|
|
2
|
+
|
|
3
|
+
//#region src/wasi/WasmSceneRuntime.d.ts
|
|
4
|
+
interface WasmSceneResizeEvent {
|
|
5
|
+
sceneId: string;
|
|
6
|
+
columns: number;
|
|
7
|
+
rows: number;
|
|
8
|
+
cellWidth?: number;
|
|
9
|
+
cellHeight?: number;
|
|
10
|
+
}
|
|
11
|
+
interface WasmSceneRuntimeHandle {
|
|
12
|
+
readonly descriptor: WebHostSceneRuntime["descriptor"];
|
|
13
|
+
sendInput(chunk: Uint8Array): void;
|
|
14
|
+
}
|
|
15
|
+
interface WasmSceneRuntimeFactoryOptions {
|
|
16
|
+
onSceneResize?(event: WasmSceneResizeEvent): void;
|
|
17
|
+
onRuntimeCreated?(runtime: WasmSceneRuntimeHandle): void;
|
|
18
|
+
workerModuleURL?: string | URL;
|
|
19
|
+
}
|
|
20
|
+
declare function createWasmSceneRuntimeFactory(wasmURL: URL, factoryOptions?: WasmSceneRuntimeFactoryOptions): (options: WebHostSceneRuntimeOptions) => WebHostSceneRuntime;
|
|
21
|
+
//#endregion
|
|
22
|
+
export { WasmSceneResizeEvent, WasmSceneRuntimeFactoryOptions, WasmSceneRuntimeHandle, createWasmSceneRuntimeFactory };
|
|
23
|
+
//# sourceMappingURL=WasmSceneRuntime.d.ts.map
|