@deepseek-ai/dsh-experimental-webworker-runtime 0.1.6-alpha.1
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/LICENSE +21 -0
- package/README.i18n.yaml +6 -0
- package/README.md +75 -0
- package/README.zh.md +75 -0
- package/lib/client.js +854 -0
- package/lib/index.js +3506 -0
- package/lib/types/client/apply-injections.d.ts +15 -0
- package/lib/types/client/client.d.ts +102 -0
- package/lib/types/client/index.d.ts +66 -0
- package/lib/types/client/source-chooser.d.ts +8 -0
- package/lib/types/compile/transform.d.ts +39 -0
- package/lib/types/fixture-manifest.d.ts +26 -0
- package/lib/types/image-layout.d.ts +43 -0
- package/lib/types/index.d.ts +23 -0
- package/lib/types/module-proxies.d.ts +25 -0
- package/lib/types/module-system/module-loader.d.ts +177 -0
- package/lib/types/module-system/posix-path.d.ts +98 -0
- package/lib/types/node/builtin_modules/implemented/abort-error.d.ts +11 -0
- package/lib/types/node/builtin_modules/implemented/async_hooks.d.ts +174 -0
- package/lib/types/node/builtin_modules/implemented/buffer.d.ts +28 -0
- package/lib/types/node/builtin_modules/implemented/child_process.d.ts +178 -0
- package/lib/types/node/builtin_modules/implemented/crypto.d.ts +53 -0
- package/lib/types/node/builtin_modules/implemented/events.d.ts +84 -0
- package/lib/types/node/builtin_modules/implemented/fs/promises.d.ts +39 -0
- package/lib/types/node/builtin_modules/implemented/fs-watch.d.ts +119 -0
- package/lib/types/node/builtin_modules/implemented/fs.d.ts +502 -0
- package/lib/types/node/builtin_modules/implemented/http.d.ts +113 -0
- package/lib/types/node/builtin_modules/implemented/module.d.ts +50 -0
- package/lib/types/node/builtin_modules/implemented/os.d.ts +115 -0
- package/lib/types/node/builtin_modules/implemented/path.d.ts +138 -0
- package/lib/types/node/builtin_modules/implemented/perf_hooks.d.ts +13 -0
- package/lib/types/node/builtin_modules/implemented/stream.d.ts +22 -0
- package/lib/types/node/builtin_modules/implemented/timers/promises.d.ts +36 -0
- package/lib/types/node/builtin_modules/implemented/tty.d.ts +18 -0
- package/lib/types/node/builtin_modules/implemented/url.d.ts +61 -0
- package/lib/types/node/builtin_modules/implemented/util/types.d.ts +12 -0
- package/lib/types/node/builtin_modules/implemented/util.d.ts +95 -0
- package/lib/types/node/builtin_modules/implemented/zlib.d.ts +65 -0
- package/lib/types/node/builtin_modules/mock/dns/promises.d.ts +10 -0
- package/lib/types/node/builtin_modules/mock/net.d.ts +61 -0
- package/lib/types/node/builtin_modules/mock/sqlite.d.ts +19 -0
- package/lib/types/node/builtin_modules/mock/vm.d.ts +25 -0
- package/lib/types/node/builtin_modules/mock/worker_threads.d.ts +34 -0
- package/lib/types/node/builtins.d.ts +13 -0
- package/lib/types/node/external_packages/koffi.d.ts +63 -0
- package/lib/types/node/external_packages/node-addon-system-flock.d.ts +19 -0
- package/lib/types/node/external_packages/node-pty.d.ts +13 -0
- package/lib/types/node/external_packages/pi-ai.d.ts +51 -0
- package/lib/types/node/external_packages/replaced-externals.d.ts +9 -0
- package/lib/types/node/external_packages/ripgrep.d.ts +16 -0
- package/lib/types/node/external_packages/sharp.d.ts +6 -0
- package/lib/types/node/external_packages/ws.d.ts +38 -0
- package/lib/types/node/globals/crypto.d.ts +3 -0
- package/lib/types/node/globals/process.d.ts +78 -0
- package/lib/types/node/globals/timers.d.ts +10 -0
- package/lib/types/node/notImplementedFail.d.ts +34 -0
- package/lib/types/node/process-table.d.ts +50 -0
- package/lib/types/polyfill/async-context/als-runtime.d.ts +45 -0
- package/lib/types/polyfill/async-context/async-context-hooks.d.ts +6 -0
- package/lib/types/shell/ast.d.ts +23 -0
- package/lib/types/shell/expand.d.ts +65 -0
- package/lib/types/shell/fs-access.d.ts +43 -0
- package/lib/types/shell/interpret.d.ts +54 -0
- package/lib/types/shell/process/child.d.ts +26 -0
- package/lib/types/shell/process/host.d.ts +58 -0
- package/lib/types/shell/process/landlock.d.ts +33 -0
- package/lib/types/shell/process/protocol.d.ts +74 -0
- package/lib/types/shell/process/virtual-executables.d.ts +49 -0
- package/lib/types/shell/programs/builtins.d.ts +9 -0
- package/lib/types/shell/programs/files.d.ts +11 -0
- package/lib/types/shell/programs/index.d.ts +14 -0
- package/lib/types/shell/programs/options.d.ts +40 -0
- package/lib/types/shell/programs/text.d.ts +9 -0
- package/lib/types/shell/types.d.ts +138 -0
- package/lib/types/storage/active.d.ts +18 -0
- package/lib/types/storage/image-gzip.d.ts +39 -0
- package/lib/types/storage/memory.d.ts +308 -0
- package/lib/types/storage/paths.d.ts +18 -0
- package/lib/types/storage/tar.d.ts +41 -0
- package/lib/types/storage/types.d.ts +279 -0
- package/lib/types/transport/frames.d.ts +108 -0
- package/lib/types/transport/synthetic-http.d.ts +50 -0
- package/lib/types/transport/tunnel.d.ts +132 -0
- package/lib/types/worker-host.d.ts +165 -0
- package/lib/types/worker.d.ts +2 -0
- package/lib/worker.js +21879 -0
- package/package.json +73 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tunnel frame protocol between the page and the worker host. Frames cross
|
|
3
|
+
* `postMessage`, so inbound frames are validated before use.
|
|
4
|
+
* @module @deepseek-ai/dsh-experimental-webworker-runtime/src/transport/frames
|
|
5
|
+
*/
|
|
6
|
+
/** Request identifier minted by the page. */
|
|
7
|
+
export type TunnelRequestId = string | number;
|
|
8
|
+
/** One request; `body` carries cloneable or transferable raw bytes. */
|
|
9
|
+
export interface TunnelRequestFrame {
|
|
10
|
+
readonly t: 'req';
|
|
11
|
+
readonly id: TunnelRequestId;
|
|
12
|
+
readonly method: string;
|
|
13
|
+
readonly url: string;
|
|
14
|
+
readonly headers: Readonly<Record<string, string>>;
|
|
15
|
+
readonly body?: ArrayBuffer | Blob | ReadableStream<Uint8Array> | undefined;
|
|
16
|
+
}
|
|
17
|
+
/** Open one Gateway Remote stream over the worker-local carrier. */
|
|
18
|
+
export interface TunnelStreamOpenFrame {
|
|
19
|
+
readonly t: 'stream-open';
|
|
20
|
+
readonly id: TunnelRequestId;
|
|
21
|
+
readonly endpoint: string;
|
|
22
|
+
readonly payload: unknown;
|
|
23
|
+
}
|
|
24
|
+
/** Page-side cancellation of an in-flight request or stream. */
|
|
25
|
+
export interface TunnelAbortFrame {
|
|
26
|
+
readonly t: 'abort';
|
|
27
|
+
readonly id: TunnelRequestId;
|
|
28
|
+
}
|
|
29
|
+
/** Frames the worker accepts. */
|
|
30
|
+
/**
|
|
31
|
+
* First inbound frame: the base image URL and ordered data overlays selected
|
|
32
|
+
* before the worker assembly starts.
|
|
33
|
+
*/
|
|
34
|
+
export interface TunnelInitFrame {
|
|
35
|
+
readonly t: 'init';
|
|
36
|
+
readonly image: string;
|
|
37
|
+
readonly overlays: readonly string[];
|
|
38
|
+
}
|
|
39
|
+
/** Every frame the page sends the worker. */
|
|
40
|
+
export type TunnelInboundFrame = TunnelInitFrame | TunnelRequestFrame | TunnelStreamOpenFrame | TunnelAbortFrame;
|
|
41
|
+
/** Complete response for unary requests and static files. */
|
|
42
|
+
export interface TunnelResponseFrame {
|
|
43
|
+
readonly t: 'res';
|
|
44
|
+
readonly id: TunnelRequestId;
|
|
45
|
+
readonly status: number;
|
|
46
|
+
readonly headers: Record<string, string>;
|
|
47
|
+
readonly body?: ArrayBuffer | undefined;
|
|
48
|
+
/** Present when the worker itself refused the request, so the page can surface the reason. */
|
|
49
|
+
readonly message?: string | undefined;
|
|
50
|
+
}
|
|
51
|
+
/** Head of a streamed response, followed by chunks and one terminator. */
|
|
52
|
+
export interface TunnelResponseHeadFrame {
|
|
53
|
+
readonly t: 'res-head';
|
|
54
|
+
readonly id: TunnelRequestId;
|
|
55
|
+
readonly status: number;
|
|
56
|
+
readonly headers: Record<string, string>;
|
|
57
|
+
}
|
|
58
|
+
/** One body chunk of a streamed response. */
|
|
59
|
+
export interface TunnelResponseChunkFrame {
|
|
60
|
+
readonly t: 'res-chunk';
|
|
61
|
+
readonly id: TunnelRequestId;
|
|
62
|
+
readonly chunk: ArrayBuffer;
|
|
63
|
+
}
|
|
64
|
+
/** Normal end of a streamed response. */
|
|
65
|
+
export interface TunnelResponseEndFrame {
|
|
66
|
+
readonly t: 'res-end';
|
|
67
|
+
readonly id: TunnelRequestId;
|
|
68
|
+
}
|
|
69
|
+
/** Failure of a streamed response after its head was sent. */
|
|
70
|
+
export interface TunnelResponseErrorFrame {
|
|
71
|
+
readonly t: 'res-err';
|
|
72
|
+
readonly id: TunnelRequestId;
|
|
73
|
+
readonly message: string;
|
|
74
|
+
}
|
|
75
|
+
/** One decoded value from a worker-local Gateway Remote stream. */
|
|
76
|
+
export interface TunnelStreamItemFrame {
|
|
77
|
+
readonly t: 'stream-item';
|
|
78
|
+
readonly id: TunnelRequestId;
|
|
79
|
+
readonly value?: unknown;
|
|
80
|
+
}
|
|
81
|
+
/** Normal completion of a worker-local Gateway Remote stream. */
|
|
82
|
+
export interface TunnelStreamEndFrame {
|
|
83
|
+
readonly t: 'stream-end';
|
|
84
|
+
readonly id: TunnelRequestId;
|
|
85
|
+
}
|
|
86
|
+
/** Stable Host failure or worker-carrier failure for one logical stream. */
|
|
87
|
+
export interface TunnelStreamErrorFrame {
|
|
88
|
+
readonly t: 'stream-error';
|
|
89
|
+
readonly id: TunnelRequestId;
|
|
90
|
+
readonly failure: {
|
|
91
|
+
readonly kind: 'remote';
|
|
92
|
+
readonly code: string;
|
|
93
|
+
readonly message: string;
|
|
94
|
+
readonly details: object;
|
|
95
|
+
} | {
|
|
96
|
+
readonly kind: 'carrier';
|
|
97
|
+
readonly message: string;
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
/** Frames the worker emits. */
|
|
101
|
+
export type TunnelOutboundFrame = TunnelResponseFrame | TunnelResponseHeadFrame | TunnelResponseChunkFrame | TunnelResponseEndFrame | TunnelResponseErrorFrame | TunnelStreamItemFrame | TunnelStreamEndFrame | TunnelStreamErrorFrame;
|
|
102
|
+
/**
|
|
103
|
+
* Validate a `postMessage` payload as a tunnel frame.
|
|
104
|
+
* @param data - Message data received by the worker.
|
|
105
|
+
* @returns The frame.
|
|
106
|
+
*/
|
|
107
|
+
export declare function parseInboundFrame(data: unknown): TunnelInboundFrame;
|
|
108
|
+
//# sourceMappingURL=frames.d.ts.map
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `IncomingMessage`/`ServerResponse` synthesis for tunnel requests. The app's
|
|
3
|
+
* `node:http` proxy reports a successful bind and captures the webserver's
|
|
4
|
+
* request listener; the tunnel feeds that listener these pairs, so the real
|
|
5
|
+
* route table, its trust fences, and every handler run unchanged.
|
|
6
|
+
*
|
|
7
|
+
* Synthesized members are exactly the ones the route handlers read; anything
|
|
8
|
+
* else is absent on purpose so a new consumer
|
|
9
|
+
* fails loud instead of silently reading a stub.
|
|
10
|
+
* @module @deepseek-ai/dsh-experimental-webworker-runtime/src/transport/synthetic-http
|
|
11
|
+
*/
|
|
12
|
+
import type { TunnelRequestFrame } from './frames.ts';
|
|
13
|
+
/** Where a synthesized response writes to. */
|
|
14
|
+
export interface ResponseSink {
|
|
15
|
+
/** Head of a streaming response. */
|
|
16
|
+
head(status: number, headers: Record<string, string>): void;
|
|
17
|
+
/** One body chunk after {@link ResponseSink.head}. */
|
|
18
|
+
chunk(bytes: Uint8Array): void;
|
|
19
|
+
/** Completion; the payload is present only for unary answers. */
|
|
20
|
+
end(payload?: {
|
|
21
|
+
status: number;
|
|
22
|
+
headers: Record<string, string>;
|
|
23
|
+
body?: Uint8Array | undefined;
|
|
24
|
+
}): void;
|
|
25
|
+
/** Failure of the exchange. */
|
|
26
|
+
fail(message: string): void;
|
|
27
|
+
}
|
|
28
|
+
/** Request listener shape the app's `createServer` captured. */
|
|
29
|
+
export type RequestListener = (req: unknown, res: unknown) => void;
|
|
30
|
+
/** The pair a route handler consumes, plus abort control for the tunnel. */
|
|
31
|
+
export interface SyntheticExchange {
|
|
32
|
+
readonly req: unknown;
|
|
33
|
+
readonly res: unknown;
|
|
34
|
+
/** Whether the page abandoned the request before it finished. */
|
|
35
|
+
readonly aborted: boolean;
|
|
36
|
+
/** Mark the page as gone: emits `close` and stops further frames. */
|
|
37
|
+
abort(): void;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Build the request/response pair for one tunnel request.
|
|
41
|
+
*
|
|
42
|
+
* `res.end()` is the settle point: the captured listener returns void, so the
|
|
43
|
+
* response object itself reports completion. `write()` always returns true,
|
|
44
|
+
* which skips backpressure waiting the tunnel cannot observe anyway.
|
|
45
|
+
* @param frame - Validated request frame.
|
|
46
|
+
* @param sink - Frame emitter for the response.
|
|
47
|
+
* @returns The pair handed to the captured request listener.
|
|
48
|
+
*/
|
|
49
|
+
export declare function createSyntheticExchange(frame: TunnelRequestFrame, sink: ResponseSink): SyntheticExchange;
|
|
50
|
+
//# sourceMappingURL=synthetic-http.d.ts.map
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Worker end of the postMessage tunnel. It owns the dispatch lanes and the queue
|
|
3
|
+
* that holds requests until the host tree is serving:
|
|
4
|
+
*
|
|
5
|
+
* - `GET /__boot__` answers from tunnel glue, never from the host API surface,
|
|
6
|
+
* because the page needs the boot payload before its Cordis tree exists.
|
|
7
|
+
* - Privileged `/api` methods take that same direct entry. The method set is not
|
|
8
|
+
* restated here: a 401 or 403 from the route lane is retried on the direct
|
|
9
|
+
* lane because the page owns the worker and needs no network authentication.
|
|
10
|
+
* - Everything else is fed into the real webserver route table through the
|
|
11
|
+
* request listener the app's fake `node:http` captured, keeping the trust
|
|
12
|
+
* fences, byte limits, and status semantics intact.
|
|
13
|
+
*
|
|
14
|
+
* A boot failure rejects the whole queue with 503 rather than leaving the page
|
|
15
|
+
* waiting.
|
|
16
|
+
* @module @deepseek-ai/dsh-experimental-webworker-runtime/src/transport/tunnel
|
|
17
|
+
*/
|
|
18
|
+
import { type TunnelOutboundFrame } from './frames.ts';
|
|
19
|
+
import { type RequestListener } from './synthetic-http.ts';
|
|
20
|
+
/** Prefix owning the API methods. */
|
|
21
|
+
export declare const API_PREFIX = "/api";
|
|
22
|
+
/** Host header the synthesized requests carry; the API trust fence requires one. */
|
|
23
|
+
export declare const SYNTHETIC_HOST = "127.0.0.1";
|
|
24
|
+
/**
|
|
25
|
+
* Render a failure with everything nested inside it.
|
|
26
|
+
*
|
|
27
|
+
* A boot failure is usually an `AggregateError` of per-entry failures, each
|
|
28
|
+
* wrapping the plugin's own error as `cause`; only the outermost message names
|
|
29
|
+
* "loader entries failed to apply", which says nothing about which row broke.
|
|
30
|
+
*
|
|
31
|
+
* The page logs the rendered text verbatim for refusals; keep it stable for
|
|
32
|
+
* anyone matching boot-failure output.
|
|
33
|
+
* @param reason - Thrown value.
|
|
34
|
+
* @returns One line per nested failure, indented by depth.
|
|
35
|
+
*/
|
|
36
|
+
export declare function describeFailure(reason: unknown): string;
|
|
37
|
+
/** Message channel the tunnel posts frames on. */
|
|
38
|
+
export interface TunnelPort {
|
|
39
|
+
postMessage(message: TunnelOutboundFrame, transfer?: Transferable[]): void;
|
|
40
|
+
}
|
|
41
|
+
/** What the tunnel gains once the host tree is up. */
|
|
42
|
+
export interface TunnelSeams {
|
|
43
|
+
/**
|
|
44
|
+
* Direct entry to the API fetch handler for privileged methods and any unary
|
|
45
|
+
* call the route lane refused with 401 or 403.
|
|
46
|
+
*/
|
|
47
|
+
readonly directFetch: (request: Request) => Promise<Response>;
|
|
48
|
+
/** Boot payload for `GET /__boot__`: the structured index injection table. */
|
|
49
|
+
readonly bootPayload: () => unknown;
|
|
50
|
+
/** Open one decoded Gateway Remote stream without another network carrier. */
|
|
51
|
+
readonly openStream: (endpoint: string, payload: unknown, signal: AbortSignal) => Promise<AsyncIterable<unknown>>;
|
|
52
|
+
/** Convert a Gateway stream failure to stable Client fields. */
|
|
53
|
+
readonly streamFailure: (error: unknown) => {
|
|
54
|
+
readonly code: string;
|
|
55
|
+
readonly message: string;
|
|
56
|
+
readonly details: object;
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/** Construction inputs for {@link TunnelServer}. */
|
|
60
|
+
export interface TunnelServerOptions {
|
|
61
|
+
/** Channel back to the page. */
|
|
62
|
+
readonly port: TunnelPort;
|
|
63
|
+
/**
|
|
64
|
+
* The webserver's request listener, captured by the app's fake `node:http`.
|
|
65
|
+
* Awaited on first use, so requests may arrive before the server binds.
|
|
66
|
+
*/
|
|
67
|
+
readonly requestListener: () => Promise<RequestListener>;
|
|
68
|
+
/**
|
|
69
|
+
* Methods that skip the route lane outright. Supply the host's own privileged
|
|
70
|
+
* set when it is reachable; omitting it leaves the 401/403 retry as the mechanism.
|
|
71
|
+
*/
|
|
72
|
+
readonly privilegedMethods?: ReadonlySet<string>;
|
|
73
|
+
/**
|
|
74
|
+
* Escape hatch for the unary `/api` lane. `route` (default) keeps every fence
|
|
75
|
+
* and byte limit with a 401/403 retry on the direct lane; `direct` sends every
|
|
76
|
+
* unary `/api` call straight to the fetch handler.
|
|
77
|
+
*/
|
|
78
|
+
readonly unaryApiLane?: 'route' | 'direct';
|
|
79
|
+
}
|
|
80
|
+
/** One tunnel per worker; wire {@link TunnelServer.handleMessage} to `onmessage` first. */
|
|
81
|
+
export declare class TunnelServer {
|
|
82
|
+
private readonly port;
|
|
83
|
+
private readonly requestListener;
|
|
84
|
+
private readonly privilegedMethods;
|
|
85
|
+
private readonly unaryApiLane;
|
|
86
|
+
private readonly queue;
|
|
87
|
+
private readonly inFlight;
|
|
88
|
+
private seams;
|
|
89
|
+
private failure;
|
|
90
|
+
private listener;
|
|
91
|
+
constructor(options: TunnelServerOptions);
|
|
92
|
+
/**
|
|
93
|
+
* Accept one `postMessage` payload.
|
|
94
|
+
* @param data - Message data from the page.
|
|
95
|
+
*/
|
|
96
|
+
handleMessage(data: unknown): void;
|
|
97
|
+
/**
|
|
98
|
+
* Start serving: drains everything queued during boot.
|
|
99
|
+
* @param seams - Faces that exist only after the host tree is up.
|
|
100
|
+
*/
|
|
101
|
+
serve(seams: TunnelSeams): void;
|
|
102
|
+
/**
|
|
103
|
+
* Refuse every queued and future request; the page renders this like a server
|
|
104
|
+
* that failed to start.
|
|
105
|
+
* @param reason - Boot failure to report.
|
|
106
|
+
*/
|
|
107
|
+
fail(reason: unknown): void;
|
|
108
|
+
private send;
|
|
109
|
+
private refuse;
|
|
110
|
+
private dispatchFrame;
|
|
111
|
+
private serveStream;
|
|
112
|
+
private sinkFor;
|
|
113
|
+
/** The page sends an absolute URL; route handlers read `req.url` as a path. */
|
|
114
|
+
private pathFrame;
|
|
115
|
+
private serveRequest;
|
|
116
|
+
/**
|
|
117
|
+
* The listener is captured once and reused, so only requests that arrive
|
|
118
|
+
* before the web server binds pay an await.
|
|
119
|
+
* @returns The webserver request listener.
|
|
120
|
+
*/
|
|
121
|
+
private whenListener;
|
|
122
|
+
/** Feed the real route table through the captured listener. */
|
|
123
|
+
private dispatch;
|
|
124
|
+
/**
|
|
125
|
+
* Unary `/api`: keep the route lane's fences, but fall back to the direct lane
|
|
126
|
+
* when network authentication or trust rejects the worker-owning page.
|
|
127
|
+
*/
|
|
128
|
+
private serveApi;
|
|
129
|
+
private serveBoot;
|
|
130
|
+
private serveDirect;
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=tunnel.d.ts.map
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Worker assembly entry: the whole harness Cordis tree inside one dedicated
|
|
3
|
+
* Web Worker.
|
|
4
|
+
*
|
|
5
|
+
* Every platform object arrives through options — the `node:*` proxy table, the
|
|
6
|
+
* request listener the app's fake `node:http` captured, the image bytes — so this
|
|
7
|
+
* package never reaches back into the application that composes it. **Platform
|
|
8
|
+
* readiness before the call is the caller's responsibility**: anything the
|
|
9
|
+
* proxies need initialized (the zstd WebAssembly module, for one) must be ready
|
|
10
|
+
* before {@link startWorkerHost} runs.
|
|
11
|
+
*
|
|
12
|
+
* Construction is split in two on purpose. {@link createWorkerHost} is
|
|
13
|
+
* synchronous so the worker can accept messages and queue requests that arrive
|
|
14
|
+
* during boot; {@link WorkerHost.start} then mounts the image, the module
|
|
15
|
+
* loader, and the tree. {@link startWorkerHost} performs both and installs the
|
|
16
|
+
* message handler before its first await.
|
|
17
|
+
*
|
|
18
|
+
* The tree itself boots through the host's own `boot()` glue loaded from the
|
|
19
|
+
* image, so entry mounting, the activation audit, and its diagnostics are the
|
|
20
|
+
* same code the Node deployment runs. Only the module seam and the command line
|
|
21
|
+
* are supplied from here.
|
|
22
|
+
* @module @deepseek-ai/dsh-experimental-webworker-runtime/src/worker-host
|
|
23
|
+
*/
|
|
24
|
+
import { WorkerModuleLoader, type StaticModuleFactory } from './module-system/module-loader.ts';
|
|
25
|
+
import type { AlsCausality } from './polyfill/async-context/als-runtime.ts';
|
|
26
|
+
import type { RequestListener } from './transport/synthetic-http.ts';
|
|
27
|
+
import { type TunnelPort } from './transport/tunnel.ts';
|
|
28
|
+
import { MemoryVfs } from './storage/memory.ts';
|
|
29
|
+
export { DEFAULT_ROOT } from './image-layout.ts';
|
|
30
|
+
/** Port reported to the tree when the caller names none; the bind is fake either way. */
|
|
31
|
+
export declare const DEFAULT_PORT = 3080;
|
|
32
|
+
/** One structured log record, as cordis delivers it to an exporter. */
|
|
33
|
+
export interface LogMessage {
|
|
34
|
+
readonly name: string;
|
|
35
|
+
readonly type: 'error' | 'info' | 'warn' | 'debug';
|
|
36
|
+
readonly args: readonly unknown[];
|
|
37
|
+
}
|
|
38
|
+
/** The exporter face `ctx.logger.exporter()` accepts. */
|
|
39
|
+
export interface LogExporter {
|
|
40
|
+
readonly colors: false;
|
|
41
|
+
/** Verbosity gate, per logger name or `default`; cordis drops a message when its level exceeds this. */
|
|
42
|
+
readonly levels: {
|
|
43
|
+
readonly default: number;
|
|
44
|
+
};
|
|
45
|
+
export(message: LogMessage): void;
|
|
46
|
+
}
|
|
47
|
+
/** Minimal view of the Cordis context the entry itself touches. */
|
|
48
|
+
export interface HostContext {
|
|
49
|
+
loader: {
|
|
50
|
+
internal: unknown;
|
|
51
|
+
};
|
|
52
|
+
logger: {
|
|
53
|
+
exporter(exporter: LogExporter): unknown;
|
|
54
|
+
};
|
|
55
|
+
get(service: string): unknown;
|
|
56
|
+
provide(name: string, value: unknown): void;
|
|
57
|
+
fiber: {
|
|
58
|
+
dispose(): Promise<void>;
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/** Construction inputs for {@link createWorkerHost}. */
|
|
62
|
+
export interface WorkerHostOptions {
|
|
63
|
+
/**
|
|
64
|
+
* Modules served from the worker bundle rather than the image: the `node:*`
|
|
65
|
+
* proxies, the not-implemented stubs for excluded npm packages, and anything else whose
|
|
66
|
+
* platform behavior differs. `node:process` and `process` are added when absent,
|
|
67
|
+
* as factories reading the installed global.
|
|
68
|
+
*/
|
|
69
|
+
readonly staticModules: Readonly<Record<string, StaticModuleFactory>>;
|
|
70
|
+
/** Prefix-matched proxies, for packages whose subpaths are open-ended. */
|
|
71
|
+
readonly staticModulePrefixes?: Readonly<Record<string, StaticModuleFactory>>;
|
|
72
|
+
/**
|
|
73
|
+
* The webserver's request listener, captured by the app's fake `node:http`.
|
|
74
|
+
* Awaited on first tunnel use, so it may resolve after the tree binds.
|
|
75
|
+
*/
|
|
76
|
+
readonly requestListener: () => Promise<RequestListener>;
|
|
77
|
+
/** Image bytes, or the URL the worker fetches them from. */
|
|
78
|
+
readonly image: Uint8Array | string;
|
|
79
|
+
/** Ordered data overlays applied after the base image and before boot. */
|
|
80
|
+
readonly overlays?: readonly (Uint8Array | string)[];
|
|
81
|
+
/** Virtual root; defaults to {@link DEFAULT_ROOT}. */
|
|
82
|
+
readonly root?: string;
|
|
83
|
+
/** Composed configuration inside the image; defaults to `<root>/config/cordis.yml`. */
|
|
84
|
+
readonly configPath?: string;
|
|
85
|
+
/**
|
|
86
|
+
* Inner arguments the tree parses. The default binds the web server to the
|
|
87
|
+
* loopback authority the tunnel synthesizes, which also keeps
|
|
88
|
+
* `networkInterfaces()` out of the trust snapshot.
|
|
89
|
+
*/
|
|
90
|
+
readonly cmdlineArgs?: readonly string[];
|
|
91
|
+
/** Port named on the default command line; defaults to {@link DEFAULT_PORT}. */
|
|
92
|
+
readonly port?: number;
|
|
93
|
+
/** Environment for the process shim; `DSH_HOME` defaults to `<root>/home`. */
|
|
94
|
+
readonly env?: Readonly<Record<string, string>>;
|
|
95
|
+
/**
|
|
96
|
+
* Image manifest path; defaults to `<root>/config/vfs-manifest.json`. Its
|
|
97
|
+
* `lowered` field must name this build's wrapper contract.
|
|
98
|
+
*/
|
|
99
|
+
readonly manifestPath?: string;
|
|
100
|
+
/**
|
|
101
|
+
* Ambient-store snapshot face exported by the app's `node:async_hooks` proxy.
|
|
102
|
+
* The rewrite that carries stores across suspension points moves state through
|
|
103
|
+
* it; the proxy remains the only owner of that state.
|
|
104
|
+
*/
|
|
105
|
+
readonly alsCausality?: AlsCausality;
|
|
106
|
+
/** Privileged API methods that skip the route lane; see {@link TunnelServer}. */
|
|
107
|
+
readonly privilegedMethods?: ReadonlySet<string>;
|
|
108
|
+
/** Escape hatch for the unary `/api` lane; see {@link TunnelServer}. */
|
|
109
|
+
readonly unaryApiLane?: 'route' | 'direct';
|
|
110
|
+
/** Channel back to the page; defaults to the worker global scope. */
|
|
111
|
+
readonly channel?: TunnelPort;
|
|
112
|
+
}
|
|
113
|
+
/** The assembled worker host. */
|
|
114
|
+
export interface WorkerHost {
|
|
115
|
+
/** Feed one `postMessage` payload; safe before {@link WorkerHost.start}. */
|
|
116
|
+
handleMessage(data: unknown): void;
|
|
117
|
+
/**
|
|
118
|
+
* Mount the image and boot the tree, then start serving queued requests.
|
|
119
|
+
* @returns Resolves once the tree is active and the tunnel is serving.
|
|
120
|
+
*/
|
|
121
|
+
start(): Promise<void>;
|
|
122
|
+
/** Dispose the tree; the tunnel keeps refusing afterwards. */
|
|
123
|
+
stop(): Promise<void>;
|
|
124
|
+
/** Filesystem the tree reads, once {@link WorkerHost.start} mounted it. */
|
|
125
|
+
readonly vfs: MemoryVfs | undefined;
|
|
126
|
+
/** Module loader behind the Cordis module seam. */
|
|
127
|
+
readonly modules: WorkerModuleLoader | undefined;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Build the worker host without touching the network or the image.
|
|
131
|
+
* @param options - Assembly inputs.
|
|
132
|
+
* @returns Handle whose `handleMessage` is ready immediately.
|
|
133
|
+
*/
|
|
134
|
+
export declare function createWorkerHost(options: WorkerHostOptions): WorkerHost;
|
|
135
|
+
/** The cordis message renderer this sink formats through. */
|
|
136
|
+
export interface LogRenderer {
|
|
137
|
+
format(exporter: LogExporter, message: LogMessage): string;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Send the tree's own warnings and errors to the worker console.
|
|
141
|
+
*
|
|
142
|
+
* Cordis's `LoggerService` always exists and always accepts messages, but with
|
|
143
|
+
* no exporter mounted it only fills a ring buffer — and no profile in this
|
|
144
|
+
* repository mounts one, so `ctx.logger.warn(...)` reaches nothing. A provider
|
|
145
|
+
* that fails and is skipped (the skill registry logs exactly that) then looks
|
|
146
|
+
* identical to one that found nothing, which is how an empty skill catalog hid a
|
|
147
|
+
* filesystem fault twice.
|
|
148
|
+
*
|
|
149
|
+
* Warnings and errors only: `info`/`debug` from 131 plugin rows would bury the
|
|
150
|
+
* page console, and this exists to make failures visible rather than to trace.
|
|
151
|
+
* @param ctx - Host context, before any entry mounts.
|
|
152
|
+
* @param require - Image resolver, for cordis's own message renderer.
|
|
153
|
+
*/
|
|
154
|
+
export declare function installLogSink(ctx: HostContext, require: (specifier: string) => unknown): void;
|
|
155
|
+
/**
|
|
156
|
+
* Install the message handler and boot the tree.
|
|
157
|
+
*
|
|
158
|
+
* The handler is attached before the first await, so requests that arrive
|
|
159
|
+
* during boot queue instead of being dropped. A boot failure refuses the queue
|
|
160
|
+
* with 503 and rejects.
|
|
161
|
+
* @param options - Assembly inputs; `channel` also replaces the message source.
|
|
162
|
+
* @returns Resolves once the tunnel is serving.
|
|
163
|
+
*/
|
|
164
|
+
export declare function startWorkerHost(options: WorkerHostOptions): Promise<void>;
|
|
165
|
+
//# sourceMappingURL=worker-host.d.ts.map
|