@ai-ecoverse/slicc-kernel 1.7.0 → 1.7.2
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 +2 -2
- package/dist/index.js +33 -11
- package/dist/index.js.map +3 -3
- package/dist/kernel-worker.js +16 -5
- package/dist/kernel-worker.js.map +2 -2
- package/dist/node-process-worker.js +11 -8
- package/dist/node-process-worker.js.map +2 -2
- package/dist/node.js +33 -5
- package/dist/node.js.map +3 -3
- package/dist/process-worker.js +11 -8
- package/dist/process-worker.js.map +2 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -134,8 +134,8 @@ await kernel.run(['curl', '-sS', 'https://registry.npmjs.org/@ai-ecoverse/wasm-b
|
|
|
134
134
|
- **Sockets**: `AF_INET` stream sockets on `127.x` and `AF_UNIX` sockets are kernel descriptors on one loopback network per kernel, so processes can serve and connect to each other. They survive `dup`, `fork` and `exec` and work with `select` and `poll`, like pipe ends. A bind of an `AF_UNIX` socket creates its path in OPFS. Other addresses are unreachable: programs reach the outside world only through the proxy.
|
|
135
135
|
- **The proxy** listens on `127.0.0.1:3128` from the first connection on. It takes absolute-form `http:` requests and `CONNECT` tunnels, which it terminates with a certificate for the requested host, issued by the kernel's own CA, then hands each request to the transport. Programs start with `http_proxy`, `https_proxy` (and the upper-case names) pointing at it, `no_proxy` covering loopback, and `SSL_CERT_FILE`, `CURL_CA_BUNDLE` and `GIT_SSL_CAINFO` pointing at the CA certificate in `/etc/ssl/certs/slicc-kernel-ca.pem`; variables in `env` override them. The CA's key never leaves WebCrypto; it is kept in IndexedDB (`<metadata>-ca`, or in memory with `metadata: false`).
|
|
136
136
|
- **TLS** needs [`@ai-ecoverse/wasm-tls-engine`](https://www.npmjs.com/package/@ai-ecoverse/wasm-tls-engine) installed under `modules`, like a command. Without it, `CONNECT` is answered `501` with the reason.
|
|
137
|
-
- **The transport** is an object on the page with `traits` (`manualRedirects`, `encodedBodies`, `maxRequestBody`, and `crossOrigin`: `'cors'` or `'any'`) and `fetch(request)`, which answers `{ status, statusText, headers, body, cancel }` with `body` an async iterable of `Uint8Array`. The kernel pulls the body one chunk at a time, so a slow program slows the download. A rejection with a numeric `status` is answered with that status; any other with `502`. `fetchTransport()` is the plain `fetch` of the page, bound by CORS; its `hint` option is appended to the message of a request it could not make, so a program's 502 can name a way around CORS (`registry.npmjs.org` and jsDelivr allow it); an embedder with a way around CORS passes its own.
|
|
138
|
-
- **`localProxyTransport({ url, key })`** sends every request to a local proxy on loopback, such as [slicc-node](https://github.com/ai-ecoverse/slicc-node) or slicc-swift, which fetches it without CORS. Redirects reach the program unfollowed, with every `Set-Cookie`; bodies arrive decoded. `probeLocalProxy({ url, key })` resolves with the proxy's capabilities, or `null` when it is gone or refuses the key, so a page can fall back to `fetchTransport()`. `checkLocalProxy({ url, key })` says why: it resolves with `{ state }`, which is `ready` (with `probe`), `blocked` (the user denied Chrome's Local Network Access permission, `loopback-network`), `unreachable` (nothing answered; its `permission` is `granted`, `prompt` or `unknown`, and with `prompt` the page cannot tell a dismissed prompt from a proxy that is not running, since Chrome asks only once it has a connection), `refused` (with `status` and `error`, such as a stale key) or `incompatible`. The permission is not consulted when the page itself is on loopback. Both take a `fetch` option, and the transport
|
|
137
|
+
- **The transport** is an object on the page with `traits` (`manualRedirects`, `encodedBodies`, `maxRequestBody`, and `crossOrigin`: `'cors'` or `'any'`) and `fetch(request)`, which answers `{ status, statusText, headers, body, cancel }` with `body` an async iterable of `Uint8Array`. The kernel pulls the body one chunk at a time, so a slow program slows the download. A rejection with a numeric `status` is answered with that status; any other with `502`. `fetchTransport()` is the plain `fetch` of the page, bound by CORS; its `hint` option is appended to the message of a request it could not make, so a program's 502 can name a way around CORS (`registry.npmjs.org` and jsDelivr allow it); an embedder with a way around CORS passes its own. A response body that delivers no data for `bodyIdleMs` (default 5 minutes; `0` or `Infinity` turns it off) fails with `ETIMEDOUT` instead of waiting forever, which matters because Chrome under heavy load can stop handing a page the rest of a body. A slow body that keeps delivering is never cut off.
|
|
138
|
+
- **`localProxyTransport({ url, key })`** sends every request to a local proxy on loopback, such as [slicc-node](https://github.com/ai-ecoverse/slicc-node) or slicc-swift, which fetches it without CORS. Redirects reach the program unfollowed, with every `Set-Cookie`; bodies arrive decoded. `probeLocalProxy({ url, key })` resolves with the proxy's capabilities, or `null` when it is gone or refuses the key, so a page can fall back to `fetchTransport()`. `checkLocalProxy({ url, key })` says why: it resolves with `{ state }`, which is `ready` (with `probe`), `blocked` (the user denied Chrome's Local Network Access permission, `loopback-network`), `unreachable` (nothing answered; its `permission` is `granted`, `prompt` or `unknown`, and with `prompt` the page cannot tell a dismissed prompt from a proxy that is not running, since Chrome asks only once it has a connection), `refused` (with `status` and `error`, such as a stale key) or `incompatible`. The permission is not consulted when the page itself is on loopback. Both take a `fetch` option, and the transport `maxRequestBody` (default 64 MiB) and `bodyIdleMs` like `fetchTransport`.
|
|
139
139
|
- **Without a transport**, every request is answered `502` with `slicc-kernel: no network transport (createKernel({ network: { transport } }))`.
|
|
140
140
|
|
|
141
141
|
Process workers can also use the transport directly, without a socket: the `net-request`, `net-read` and `net-close` syscalls (`Module.sliccKernel.http` in a process) open a request and read its body in pieces. Requests are per process and closed when it exits, and a request body has no size limit of its own (the transport's `maxRequestBody` applies to the proxy). `net-traits` answers the transport's `traits` with `crossOrigin`: `'cors'` when it is bound by CORS like `fetchTransport()`, `'any'` (the default for a transport that does not say) when it is not; without a transport it fails with `ENETUNREACH`.
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
// src/body-idle.ts
|
|
2
|
+
var BODY_IDLE_MS = 5 * 60 * 1e3;
|
|
3
|
+
function idleFailure(ms) {
|
|
4
|
+
return Object.assign(new Error(`the response body sent no data for ${ms} ms`), {
|
|
5
|
+
code: "ETIMEDOUT"
|
|
6
|
+
});
|
|
7
|
+
}
|
|
8
|
+
async function readWithin(reader, ms) {
|
|
9
|
+
if (!(ms > 0 && ms < Number.POSITIVE_INFINITY)) return reader.read();
|
|
10
|
+
let timer;
|
|
11
|
+
const idle = new Promise((_, reject) => {
|
|
12
|
+
timer = setTimeout(() => reject(idleFailure(ms)), ms);
|
|
13
|
+
});
|
|
14
|
+
try {
|
|
15
|
+
return await Promise.race([reader.read(), idle]);
|
|
16
|
+
} finally {
|
|
17
|
+
clearTimeout(timer);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
1
21
|
// src/transport.ts
|
|
2
22
|
var MAX_REQUEST_BODY = 64 * 1024 * 1024;
|
|
3
23
|
function joinHeaders(headers) {
|
|
@@ -10,11 +30,11 @@ function joinHeaders(headers) {
|
|
|
10
30
|
}
|
|
11
31
|
return out;
|
|
12
32
|
}
|
|
13
|
-
async function* chunks(body) {
|
|
33
|
+
async function* chunks(body, idleMs) {
|
|
14
34
|
if (!body) return;
|
|
15
35
|
const reader = body.getReader();
|
|
16
36
|
try {
|
|
17
|
-
for (let next = await reader
|
|
37
|
+
for (let next = await readWithin(reader, idleMs); !next.done; next = await readWithin(reader, idleMs)) {
|
|
18
38
|
if (next.value.byteLength > 0) yield next.value;
|
|
19
39
|
}
|
|
20
40
|
} finally {
|
|
@@ -55,7 +75,7 @@ function fetchTransport(options = {}) {
|
|
|
55
75
|
response.headers.forEach((value, name) => {
|
|
56
76
|
headers.push([name, value]);
|
|
57
77
|
});
|
|
58
|
-
const body = chunks(response.body);
|
|
78
|
+
const body = chunks(response.body, options.bodyIdleMs ?? BODY_IDLE_MS);
|
|
59
79
|
return {
|
|
60
80
|
status: response.status,
|
|
61
81
|
statusText: response.statusText,
|
|
@@ -73,12 +93,13 @@ function serveTransport(peer, transport) {
|
|
|
73
93
|
const open = /* @__PURE__ */ new Map();
|
|
74
94
|
const fail = (nid, e) => {
|
|
75
95
|
open.delete(nid);
|
|
76
|
-
const status = e
|
|
96
|
+
const { status, code } = e;
|
|
77
97
|
peer.postMessage({
|
|
78
98
|
net: "error",
|
|
79
99
|
nid,
|
|
80
100
|
message: e instanceof Error ? e.message : String(e),
|
|
81
|
-
...typeof status === "number" ? { status } : {}
|
|
101
|
+
...typeof status === "number" ? { status } : {},
|
|
102
|
+
...typeof code === "string" ? { code } : {}
|
|
82
103
|
});
|
|
83
104
|
};
|
|
84
105
|
const start = async (call) => {
|
|
@@ -197,7 +218,7 @@ function concat(a, b) {
|
|
|
197
218
|
out.set(b, a.byteLength);
|
|
198
219
|
return out;
|
|
199
220
|
}
|
|
200
|
-
async function readHead(reader) {
|
|
221
|
+
async function readHead(reader, idleMs) {
|
|
201
222
|
let buffer = new Uint8Array(0);
|
|
202
223
|
for (; ; ) {
|
|
203
224
|
if (buffer.byteLength >= 4) {
|
|
@@ -213,15 +234,15 @@ async function readHead(reader) {
|
|
|
213
234
|
return { head, rest: buffer.subarray(4 + length) };
|
|
214
235
|
}
|
|
215
236
|
}
|
|
216
|
-
const next = await reader
|
|
237
|
+
const next = await readWithin(reader, idleMs);
|
|
217
238
|
if (next.done) throw failure("closed before the response head");
|
|
218
239
|
buffer = concat(buffer, next.value);
|
|
219
240
|
}
|
|
220
241
|
}
|
|
221
|
-
async function* chunks2(rest, reader) {
|
|
242
|
+
async function* chunks2(rest, reader, idleMs) {
|
|
222
243
|
try {
|
|
223
244
|
if (rest.byteLength > 0) yield rest;
|
|
224
|
-
for (let next = await reader
|
|
245
|
+
for (let next = await readWithin(reader, idleMs); !next.done; next = await readWithin(reader, idleMs)) {
|
|
225
246
|
if (next.value.byteLength > 0) yield next.value;
|
|
226
247
|
}
|
|
227
248
|
} finally {
|
|
@@ -298,14 +319,15 @@ function localProxyTransport(options) {
|
|
|
298
319
|
throw await refusal(response);
|
|
299
320
|
}
|
|
300
321
|
const reader = response.body.getReader();
|
|
322
|
+
const idleMs = options.bodyIdleMs ?? BODY_IDLE_MS;
|
|
301
323
|
let framed;
|
|
302
324
|
try {
|
|
303
|
-
framed = await readHead(reader);
|
|
325
|
+
framed = await readHead(reader, idleMs);
|
|
304
326
|
} catch (e) {
|
|
305
327
|
await reader.cancel().catch(() => void 0);
|
|
306
328
|
throw e;
|
|
307
329
|
}
|
|
308
|
-
const body = chunks2(framed.rest, reader);
|
|
330
|
+
const body = chunks2(framed.rest, reader, idleMs);
|
|
309
331
|
return {
|
|
310
332
|
status: framed.head.status,
|
|
311
333
|
statusText: framed.head.statusText,
|
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/transport.ts", "../src/local-proxy-transport.ts", "../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["import type { TransportCall, TransportReply } from './kernel/net/remote-transport.ts';\nimport type {\n HeaderList,\n RealmTransport,\n RealmTransportRequest,\n RealmTransportResponse,\n RealmTransportTraits,\n} from './kernel/net/transport.ts';\n\nexport type {\n HeaderList,\n RealmTransport as NetworkTransport,\n RealmTransportRequest as NetworkRequest,\n RealmTransportResponse as NetworkResponse,\n RealmTransportTraits as NetworkTraits,\n};\n\nexport interface FetchTransportOptions {\n fetch?: typeof globalThis.fetch;\n maxRequestBody?: number;\n hint?: string;\n}\n\nconst MAX_REQUEST_BODY = 64 * 1024 * 1024;\n\nfunction joinHeaders(headers: HeaderList): Headers {\n const out = new Headers();\n for (const [name, value] of headers) {\n try {\n out.append(name, value);\n } catch {}\n }\n return out;\n}\n\nasync function* chunks(body: ReadableStream<Uint8Array> | null): AsyncGenerator<Uint8Array> {\n if (!body) return;\n const reader = body.getReader();\n try {\n for (let next = await reader.read(); !next.done; next = await reader.read()) {\n if (next.value.byteLength > 0) yield next.value;\n }\n } finally {\n await reader.cancel().catch(() => undefined);\n }\n}\n\nexport function fetchTransport(options: FetchTransportOptions = {}): RealmTransport {\n const send = options.fetch ?? globalThis.fetch.bind(globalThis);\n return {\n traits: {\n manualRedirects: false,\n encodedBodies: false,\n maxRequestBody: options.maxRequestBody ?? MAX_REQUEST_BODY,\n crossOrigin: 'cors',\n },\n async fetch(request: RealmTransportRequest): Promise<RealmTransportResponse> {\n let response: Response;\n try {\n response = await send(request.url, {\n method: request.method,\n headers: joinHeaders(request.headers),\n ...(request.body ? { body: request.body as BodyInit } : {}),\n signal: request.signal,\n redirect: 'follow',\n credentials: 'omit',\n mode: 'cors',\n });\n } catch (e) {\n if (request.signal.aborted) throw e;\n throw Object.assign(\n new Error(\n `fetch ${request.url} failed (unreachable, or not allowed by CORS)${options.hint ? `: ${options.hint}` : ''}`\n ),\n { status: 502 }\n );\n }\n const headers: Array<[string, string]> = [];\n response.headers.forEach((value, name) => {\n headers.push([name, value]);\n });\n const body = chunks(response.body);\n return {\n status: response.status,\n statusText: response.statusText,\n headers,\n body,\n cancel: async () => {\n await body.return(undefined);\n await response.body?.cancel().catch(() => undefined);\n },\n };\n },\n };\n}\n\nexport interface TransportPeer {\n postMessage(message: TransportReply, transfer?: Transferable[]): void;\n}\n\nexport interface TransportServer {\n answer(call: TransportCall): void;\n close(): void;\n}\n\nexport function serveTransport(peer: TransportPeer, transport: RealmTransport): TransportServer {\n const open = new Map<\n number,\n { abort: AbortController; body?: AsyncIterator<Uint8Array>; response?: RealmTransportResponse }\n >();\n const fail = (nid: number, e: unknown) => {\n open.delete(nid);\n const status = (e as { status?: unknown }).status;\n peer.postMessage({\n net: 'error',\n nid,\n message: e instanceof Error ? e.message : String(e),\n ...(typeof status === 'number' ? { status } : {}),\n });\n };\n const start = async (call: Extract<TransportCall, { net: 'fetch' }>) => {\n const abort = new AbortController();\n const entry: { abort: AbortController; body?: AsyncIterator<Uint8Array> } = { abort };\n open.set(call.nid, entry);\n try {\n const response = await transport.fetch({\n url: call.url,\n method: call.method,\n headers: call.headers,\n ...(call.body ? { body: call.body } : {}),\n signal: abort.signal,\n });\n if (!open.has(call.nid)) {\n await response.cancel();\n return;\n }\n open.set(call.nid, { abort, body: response.body[Symbol.asyncIterator](), response });\n peer.postMessage({\n net: 'head',\n nid: call.nid,\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n });\n } catch (e) {\n fail(call.nid, e);\n }\n };\n const read = async (nid: number) => {\n const body = open.get(nid)?.body;\n if (!body) return;\n try {\n const next = await body.next();\n if (next.done) {\n open.delete(nid);\n peer.postMessage({ net: 'end', nid });\n } else {\n const bytes = next.value.slice();\n peer.postMessage({ net: 'chunk', nid, bytes }, [bytes.buffer]);\n }\n } catch (e) {\n fail(nid, e);\n }\n };\n const drop = (nid: number) => {\n const entry = open.get(nid);\n open.delete(nid);\n entry?.abort.abort();\n void entry?.response?.cancel().catch(() => undefined);\n };\n return {\n answer(call) {\n if (call.net === 'fetch') void start(call);\n else if (call.net === 'read') void read(call.nid);\n else drop(call.nid);\n },\n close() {\n for (const nid of [...open.keys()]) drop(nid);\n },\n };\n}\n", "import type {\n HeaderList,\n RealmTransport,\n RealmTransportRequest,\n RealmTransportResponse,\n} from './kernel/net/transport.ts';\n\nexport interface LocalProxyOptions {\n url: string;\n key: string;\n fetch?: typeof globalThis.fetch;\n}\n\nexport interface LocalProxyCheckOptions extends LocalProxyOptions {\n permissions?: Pick<Permissions, 'query'>;\n}\n\nexport interface LocalProxyTransportOptions extends LocalProxyOptions {\n maxRequestBody?: number;\n}\n\nexport interface LocalProxyProbe {\n rawFetch: number;\n requestBodyStreaming: boolean;\n maxRequestBodyBytes: number;\n}\n\nexport type LocalProxyStatus =\n | { state: 'ready'; probe: LocalProxyProbe }\n | { state: 'blocked' }\n | { state: 'unreachable'; permission: 'granted' | 'prompt' | 'unknown' }\n | { state: 'refused'; status: number; error: string }\n | { state: 'incompatible' };\n\nconst PATH = '/api/fetch-proxy';\nconst RAW_CONTENT_TYPE = 'application/vnd.slicc.raw-fetch';\nconst MAX_HEAD = 1024 * 1024;\nconst MAX_REQUEST_BODY = 64 * 1024 * 1024;\nconst PERMISSIONS = ['loopback-network', 'local-network-access'];\nconst LOOPBACK_PAGE = /^(127\\.\\d+\\.\\d+\\.\\d+|localhost|\\[::1\\])$/;\n\ninterface ResponseHead {\n status: number;\n statusText: string;\n headers: Array<[string, string]>;\n}\n\nconst failure = (message: string, status = 502) =>\n Object.assign(new Error(`local proxy: ${message}`), { status });\n\nfunction encodeHead(url: string, method: string, headers: HeaderList): string {\n return JSON.stringify({ url, method, headers }).replace(\n /[\\u007f-\uFFFF]/g,\n (c) => `\\\\u${c.charCodeAt(0).toString(16).padStart(4, '0')}`\n );\n}\n\nfunction hopHeaders(options: LocalProxyOptions, extra: Record<string, string>): Headers {\n return new Headers({ 'X-Bridge-Token': options.key, ...extra });\n}\n\nfunction send(options: LocalProxyOptions) {\n return options.fetch ?? globalThis.fetch.bind(globalThis);\n}\n\nasync function refusalMessage(response: Response): Promise<string> {\n const text = await response.text().catch(() => '');\n try {\n const parsed = JSON.parse(text) as { error?: unknown };\n if (typeof parsed.error === 'string') return parsed.error;\n } catch {}\n return text || response.statusText || `answered ${response.status}`;\n}\n\nasync function refusal(response: Response): Promise<Error> {\n return failure(await refusalMessage(response), response.ok ? 502 : response.status);\n}\n\nasync function permission(permissions: Pick<Permissions, 'query'> | undefined): Promise<string> {\n if (!permissions) return 'unknown';\n for (const name of PERMISSIONS) {\n try {\n return (await permissions.query({ name } as PermissionDescriptor)).state;\n } catch {}\n }\n return 'unknown';\n}\n\nfunction isHead(value: unknown): value is ResponseHead {\n const head = value as Partial<ResponseHead> | null;\n return (\n !!head &&\n typeof head.status === 'number' &&\n typeof head.statusText === 'string' &&\n Array.isArray(head.headers) &&\n head.headers.every(\n (pair) =>\n Array.isArray(pair) &&\n pair.length === 2 &&\n typeof pair[0] === 'string' &&\n typeof pair[1] === 'string'\n )\n );\n}\n\nfunction concat(a: Uint8Array, b: Uint8Array): Uint8Array {\n const out = new Uint8Array(a.byteLength + b.byteLength);\n out.set(a);\n out.set(b, a.byteLength);\n return out;\n}\n\nasync function readHead(\n reader: ReadableStreamDefaultReader<Uint8Array>\n): Promise<{ head: ResponseHead; rest: Uint8Array }> {\n let buffer: Uint8Array = new Uint8Array(0);\n for (;;) {\n if (buffer.byteLength >= 4) {\n const length = new DataView(buffer.buffer, buffer.byteOffset, 4).getUint32(0);\n if (length > MAX_HEAD) throw failure(`response head of ${length} bytes`);\n if (buffer.byteLength >= 4 + length) {\n let head: unknown;\n try {\n head = JSON.parse(new TextDecoder().decode(buffer.subarray(4, 4 + length)));\n } catch {}\n if (!isHead(head)) throw failure('malformed response head');\n return { head, rest: buffer.subarray(4 + length) };\n }\n }\n const next = await reader.read();\n if (next.done) throw failure('closed before the response head');\n buffer = concat(buffer, next.value);\n }\n}\n\nasync function* chunks(\n rest: Uint8Array,\n reader: ReadableStreamDefaultReader<Uint8Array>\n): AsyncGenerator<Uint8Array> {\n try {\n if (rest.byteLength > 0) yield rest;\n for (let next = await reader.read(); !next.done; next = await reader.read()) {\n if (next.value.byteLength > 0) yield next.value;\n }\n } finally {\n await reader.cancel().catch(() => undefined);\n }\n}\n\nexport async function checkLocalProxy(options: LocalProxyCheckOptions): Promise<LocalProxyStatus> {\n const onLoopback = LOOPBACK_PAGE.test(globalThis.location?.hostname ?? '');\n const permissions = onLoopback\n ? undefined\n : (options.permissions ?? globalThis.navigator?.permissions);\n if ((await permission(permissions)) === 'denied') return { state: 'blocked' };\n let response: Response;\n try {\n response = await send(options)(new URL(PATH, options.url), {\n method: 'POST',\n headers: hopHeaders(options, { 'X-Slicc-Raw-Probe': '1' }),\n credentials: 'omit',\n mode: 'cors',\n });\n } catch {\n const now = await permission(permissions);\n if (now === 'denied') return { state: 'blocked' };\n return {\n state: 'unreachable',\n permission: now === 'granted' || now === 'prompt' ? now : 'unknown',\n };\n }\n if (!response.ok) {\n return { state: 'refused', status: response.status, error: await refusalMessage(response) };\n }\n const reply = (await response.json().catch(() => null)) as Partial<LocalProxyProbe> | null;\n if (\n !reply ||\n typeof reply.rawFetch !== 'number' ||\n reply.rawFetch < 1 ||\n typeof reply.requestBodyStreaming !== 'boolean' ||\n typeof reply.maxRequestBodyBytes !== 'number'\n ) {\n return { state: 'incompatible' };\n }\n return {\n state: 'ready',\n probe: {\n rawFetch: reply.rawFetch,\n requestBodyStreaming: reply.requestBodyStreaming,\n maxRequestBodyBytes: reply.maxRequestBodyBytes,\n },\n };\n}\n\nexport async function probeLocalProxy(\n options: LocalProxyCheckOptions\n): Promise<LocalProxyProbe | null> {\n const status = await checkLocalProxy(options);\n return status.state === 'ready' ? status.probe : null;\n}\n\nexport function localProxyTransport(options: LocalProxyTransportOptions): RealmTransport {\n const endpoint = new URL(PATH, options.url);\n return {\n traits: {\n manualRedirects: true,\n encodedBodies: false,\n maxRequestBody: options.maxRequestBody ?? MAX_REQUEST_BODY,\n },\n async fetch(request: RealmTransportRequest): Promise<RealmTransportResponse> {\n let response: Response;\n try {\n response = await send(options)(endpoint, {\n method: 'POST',\n headers: hopHeaders(options, {\n 'X-Slicc-Raw-Request': encodeHead(request.url, request.method, request.headers),\n }),\n ...(request.body ? { body: request.body as BodyInit } : {}),\n signal: request.signal,\n credentials: 'omit',\n mode: 'cors',\n });\n } catch (e) {\n if (request.signal.aborted) throw e;\n throw failure(`${endpoint.origin} is unreachable or refuses this origin`);\n }\n const type = response.headers.get('content-type') ?? '';\n if (response.status !== 200 || !type.startsWith(RAW_CONTENT_TYPE) || !response.body) {\n throw await refusal(response);\n }\n const reader = response.body.getReader();\n let framed: { head: ResponseHead; rest: Uint8Array };\n try {\n framed = await readHead(reader);\n } catch (e) {\n await reader.cancel().catch(() => undefined);\n throw e;\n }\n const body = chunks(framed.rest, reader);\n return {\n status: framed.head.status,\n statusText: framed.head.statusText,\n headers: framed.head.headers,\n body,\n cancel: async () => {\n await body.return(undefined);\n await reader.cancel().catch(() => undefined);\n },\n };\n },\n };\n}\n", "import type { TransportCall } from './kernel/net/remote-transport.ts';\nimport type { KernelCall, TerminalAction } from './serve.ts';\nimport { type NetworkTransport, serveTransport } from './transport.ts';\n\nexport {\n checkLocalProxy,\n type LocalProxyCheckOptions,\n type LocalProxyOptions,\n type LocalProxyProbe,\n type LocalProxyStatus,\n type LocalProxyTransportOptions,\n localProxyTransport,\n probeLocalProxy,\n} from './local-proxy-transport.ts';\nexport {\n type FetchTransportOptions,\n fetchTransport,\n type HeaderList,\n type NetworkRequest,\n type NetworkResponse,\n type NetworkTraits,\n type NetworkTransport,\n} from './transport.ts';\n\nexport interface NetworkOptions {\n transport?: NetworkTransport;\n}\n\nexport interface KernelOptions {\n root?: FileSystemDirectoryHandle;\n modules?: string;\n env?: Record<string, string>;\n metadata?: string | false;\n worker?: string | URL;\n network?: NetworkOptions;\n}\n\nexport interface RunOptions {\n cwd?: string;\n env?: Record<string, string>;\n stdin?: string | Uint8Array;\n onStdout?: (text: string) => void;\n onStderr?: (text: string) => void;\n}\n\nexport interface RunResult {\n status: number;\n stdout: string;\n stderr: string;\n}\n\nexport interface Kernel {\n run(argv: string[], options?: RunOptions): Promise<RunResult>;\n openTerminal(argv: string[], options?: TerminalOptions): Promise<Terminal>;\n terminate(): void;\n}\n\nexport interface TerminalOptions {\n cwd?: string;\n env?: Record<string, string>;\n cols?: number;\n rows?: number;\n onData?: (bytes: Uint8Array) => void;\n}\n\nexport type TerminalSignal =\n | 'SIGINT'\n | 'SIGTSTP'\n | 'SIGQUIT'\n | 'SIGHUP'\n | 'SIGTERM'\n | 'SIGKILL'\n | 'SIGCONT';\n\nexport interface Terminal {\n readonly pid: number;\n readonly exited: Promise<number>;\n onData: ((bytes: Uint8Array) => void) | null;\n write(data: string | Uint8Array): void;\n resize(cols: number, rows: number): void;\n signal(name: TerminalSignal): void;\n close(): void;\n}\n\ninterface Reply {\n id: number;\n result?: unknown;\n error?: string;\n fd?: 1 | 2;\n bytes?: Uint8Array;\n started?: number;\n}\n\ninterface Pending {\n resolve: (value: unknown) => void;\n reject: (error: Error) => void;\n output?: (fd: 1 | 2, bytes: Uint8Array) => void;\n started?: (pid: number) => void;\n}\n\ninterface Handlers {\n output?: Pending['output'];\n started?: Pending['started'];\n}\n\nconst ISOLATION =\n 'slicc-kernel needs a cross-origin isolated page (Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp or credentialless)';\n\nfunction streamer(callback: ((text: string) => void) | undefined) {\n const decoder = new TextDecoder();\n return (bytes: Uint8Array) => callback?.(decoder.decode(bytes, { stream: true }));\n}\n\nexport async function createKernel(options: KernelOptions = {}): Promise<Kernel> {\n if (!globalThis.crossOriginIsolated) throw new Error(ISOLATION);\n const url = options.worker ?? new URL('./kernel-worker.js', import.meta.url);\n const worker = new Worker(url, { type: 'module', name: 'slicc-kernel' });\n const pending = new Map<number, Pending>();\n let nextId = 0;\n let failure: Error | undefined;\n\n const fail = (error: Error) => {\n failure = error;\n bridge?.close();\n for (const call of pending.values()) call.reject(error);\n pending.clear();\n };\n const transport = options.network?.transport;\n const bridge = transport ? serveTransport(worker, transport) : undefined;\n worker.addEventListener('message', ({ data }: MessageEvent<Reply | TransportCall>) => {\n if ('net' in data) return bridge?.answer(data);\n const call = pending.get(data.id);\n if (!call) return;\n if (data.fd !== undefined) return call.output?.(data.fd, data.bytes as Uint8Array);\n if (data.started !== undefined) return call.started?.(data.started);\n pending.delete(data.id);\n if (data.error !== undefined) call.reject(new Error(data.error));\n else call.resolve(data.result);\n });\n worker.addEventListener('error', (event) => {\n event.preventDefault();\n fail(new Error(`slicc-kernel worker failed: ${event.message}`));\n });\n\n function request(\n req: KernelCall,\n handlers: Handlers = {}\n ): { id: number; done: Promise<unknown> } {\n const id = ++nextId;\n if (failure) return { id, done: Promise.reject(failure) };\n const done = new Promise((resolve, reject) => {\n pending.set(id, { resolve, reject, ...handlers });\n worker.postMessage({ ...req, id });\n });\n return { id, done };\n }\n\n const call = (req: KernelCall, handlers?: Handlers) => request(req, handlers).done;\n\n async function openTerminal(argv: string[], opts: TerminalOptions = {}): Promise<Terminal> {\n const { onData, ...options } = opts;\n let listener = onData ?? null;\n const backlog: Uint8Array[] = [];\n const started = Promise.withResolvers<number>();\n const { id, done } = request(\n { op: 'open-terminal', argv, options },\n {\n output: (_fd, bytes) => (listener ? listener(bytes) : backlog.push(bytes)),\n started: started.resolve,\n }\n );\n done.catch(started.reject);\n const pid = await started.promise;\n const send = (action: TerminalAction) =>\n void call({ op: 'terminal', terminal: id, ...action }).catch(() => undefined);\n return {\n pid,\n exited: done as Promise<number>,\n get onData() {\n return listener;\n },\n set onData(next) {\n listener = next;\n if (next) for (const bytes of backlog.splice(0)) next(bytes);\n },\n write: (data) =>\n send({\n action: 'write',\n bytes: typeof data === 'string' ? new TextEncoder().encode(data) : data,\n }),\n resize: (cols, rows) => send({ action: 'resize', cols, rows }),\n signal: (name) => send({ action: 'signal', signal: name }),\n close: () => send({ action: 'close' }),\n };\n }\n\n await call({\n op: 'init',\n ...(options.root ? { root: options.root } : {}),\n ...(options.modules ? { modules: options.modules } : {}),\n ...(options.env ? { env: options.env } : {}),\n ...(options.metadata !== undefined ? { metadata: options.metadata } : {}),\n ...(transport ? { transport: transport.traits } : {}),\n });\n\n return {\n async run(argv, runOptions = {}) {\n const { onStdout, onStderr, stdin, ...rest } = runOptions;\n const streams = { 1: streamer(onStdout), 2: streamer(onStderr) };\n const input = typeof stdin === 'string' ? new TextEncoder().encode(stdin) : stdin;\n const result = (await call(\n { op: 'run', argv, options: { ...rest, ...(input ? { stdin: input } : {}) } },\n { output: (fd, bytes) => streams[fd](bytes) }\n )) as { status: number; stdout: Uint8Array; stderr: Uint8Array };\n const decoder = new TextDecoder();\n return {\n status: result.status,\n stdout: decoder.decode(result.stdout),\n stderr: decoder.decode(result.stderr),\n };\n },\n openTerminal,\n terminate() {\n fail(new Error('slicc-kernel terminated'));\n worker.terminate();\n },\n };\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
3
|
+
"sources": ["../src/body-idle.ts", "../src/transport.ts", "../src/local-proxy-transport.ts", "../src/index.ts"],
|
|
4
|
+
"sourcesContent": ["export const BODY_IDLE_MS = 5 * 60 * 1000;\n\nexport function idleFailure(ms: number): Error {\n return Object.assign(new Error(`the response body sent no data for ${ms} ms`), {\n code: 'ETIMEDOUT',\n });\n}\n\nexport async function readWithin<T>(\n reader: ReadableStreamDefaultReader<T>,\n ms: number\n): Promise<ReadableStreamReadResult<T>> {\n if (!(ms > 0 && ms < Number.POSITIVE_INFINITY)) return reader.read();\n let timer: ReturnType<typeof setTimeout> | undefined;\n const idle = new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(idleFailure(ms)), ms);\n });\n try {\n return await Promise.race([reader.read(), idle]);\n } finally {\n clearTimeout(timer);\n }\n}\n", "import { BODY_IDLE_MS, readWithin } from './body-idle.ts';\nimport type { TransportCall, TransportReply } from './kernel/net/remote-transport.ts';\nimport type {\n HeaderList,\n RealmTransport,\n RealmTransportRequest,\n RealmTransportResponse,\n RealmTransportTraits,\n} from './kernel/net/transport.ts';\n\nexport type {\n HeaderList,\n RealmTransport as NetworkTransport,\n RealmTransportRequest as NetworkRequest,\n RealmTransportResponse as NetworkResponse,\n RealmTransportTraits as NetworkTraits,\n};\n\nexport interface FetchTransportOptions {\n fetch?: typeof globalThis.fetch;\n maxRequestBody?: number;\n hint?: string;\n bodyIdleMs?: number;\n}\n\nconst MAX_REQUEST_BODY = 64 * 1024 * 1024;\n\nfunction joinHeaders(headers: HeaderList): Headers {\n const out = new Headers();\n for (const [name, value] of headers) {\n try {\n out.append(name, value);\n } catch {}\n }\n return out;\n}\n\nasync function* chunks(\n body: ReadableStream<Uint8Array> | null,\n idleMs: number\n): AsyncGenerator<Uint8Array> {\n if (!body) return;\n const reader = body.getReader();\n try {\n for (\n let next = await readWithin(reader, idleMs);\n !next.done;\n next = await readWithin(reader, idleMs)\n ) {\n if (next.value.byteLength > 0) yield next.value;\n }\n } finally {\n await reader.cancel().catch(() => undefined);\n }\n}\n\nexport function fetchTransport(options: FetchTransportOptions = {}): RealmTransport {\n const send = options.fetch ?? globalThis.fetch.bind(globalThis);\n return {\n traits: {\n manualRedirects: false,\n encodedBodies: false,\n maxRequestBody: options.maxRequestBody ?? MAX_REQUEST_BODY,\n crossOrigin: 'cors',\n },\n async fetch(request: RealmTransportRequest): Promise<RealmTransportResponse> {\n let response: Response;\n try {\n response = await send(request.url, {\n method: request.method,\n headers: joinHeaders(request.headers),\n ...(request.body ? { body: request.body as BodyInit } : {}),\n signal: request.signal,\n redirect: 'follow',\n credentials: 'omit',\n mode: 'cors',\n });\n } catch (e) {\n if (request.signal.aborted) throw e;\n throw Object.assign(\n new Error(\n `fetch ${request.url} failed (unreachable, or not allowed by CORS)${options.hint ? `: ${options.hint}` : ''}`\n ),\n { status: 502 }\n );\n }\n const headers: Array<[string, string]> = [];\n response.headers.forEach((value, name) => {\n headers.push([name, value]);\n });\n const body = chunks(response.body, options.bodyIdleMs ?? BODY_IDLE_MS);\n return {\n status: response.status,\n statusText: response.statusText,\n headers,\n body,\n cancel: async () => {\n await body.return(undefined);\n await response.body?.cancel().catch(() => undefined);\n },\n };\n },\n };\n}\n\nexport interface TransportPeer {\n postMessage(message: TransportReply, transfer?: Transferable[]): void;\n}\n\nexport interface TransportServer {\n answer(call: TransportCall): void;\n close(): void;\n}\n\nexport function serveTransport(peer: TransportPeer, transport: RealmTransport): TransportServer {\n const open = new Map<\n number,\n { abort: AbortController; body?: AsyncIterator<Uint8Array>; response?: RealmTransportResponse }\n >();\n const fail = (nid: number, e: unknown) => {\n open.delete(nid);\n const { status, code } = e as { status?: unknown; code?: unknown };\n peer.postMessage({\n net: 'error',\n nid,\n message: e instanceof Error ? e.message : String(e),\n ...(typeof status === 'number' ? { status } : {}),\n ...(typeof code === 'string' ? { code } : {}),\n });\n };\n const start = async (call: Extract<TransportCall, { net: 'fetch' }>) => {\n const abort = new AbortController();\n const entry: { abort: AbortController; body?: AsyncIterator<Uint8Array> } = { abort };\n open.set(call.nid, entry);\n try {\n const response = await transport.fetch({\n url: call.url,\n method: call.method,\n headers: call.headers,\n ...(call.body ? { body: call.body } : {}),\n signal: abort.signal,\n });\n if (!open.has(call.nid)) {\n await response.cancel();\n return;\n }\n open.set(call.nid, { abort, body: response.body[Symbol.asyncIterator](), response });\n peer.postMessage({\n net: 'head',\n nid: call.nid,\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n });\n } catch (e) {\n fail(call.nid, e);\n }\n };\n const read = async (nid: number) => {\n const body = open.get(nid)?.body;\n if (!body) return;\n try {\n const next = await body.next();\n if (next.done) {\n open.delete(nid);\n peer.postMessage({ net: 'end', nid });\n } else {\n const bytes = next.value.slice();\n peer.postMessage({ net: 'chunk', nid, bytes }, [bytes.buffer]);\n }\n } catch (e) {\n fail(nid, e);\n }\n };\n const drop = (nid: number) => {\n const entry = open.get(nid);\n open.delete(nid);\n entry?.abort.abort();\n void entry?.response?.cancel().catch(() => undefined);\n };\n return {\n answer(call) {\n if (call.net === 'fetch') void start(call);\n else if (call.net === 'read') void read(call.nid);\n else drop(call.nid);\n },\n close() {\n for (const nid of [...open.keys()]) drop(nid);\n },\n };\n}\n", "import { BODY_IDLE_MS, readWithin } from './body-idle.ts';\nimport type {\n HeaderList,\n RealmTransport,\n RealmTransportRequest,\n RealmTransportResponse,\n} from './kernel/net/transport.ts';\n\nexport interface LocalProxyOptions {\n url: string;\n key: string;\n fetch?: typeof globalThis.fetch;\n}\n\nexport interface LocalProxyCheckOptions extends LocalProxyOptions {\n permissions?: Pick<Permissions, 'query'>;\n}\n\nexport interface LocalProxyTransportOptions extends LocalProxyOptions {\n maxRequestBody?: number;\n bodyIdleMs?: number;\n}\n\nexport interface LocalProxyProbe {\n rawFetch: number;\n requestBodyStreaming: boolean;\n maxRequestBodyBytes: number;\n}\n\nexport type LocalProxyStatus =\n | { state: 'ready'; probe: LocalProxyProbe }\n | { state: 'blocked' }\n | { state: 'unreachable'; permission: 'granted' | 'prompt' | 'unknown' }\n | { state: 'refused'; status: number; error: string }\n | { state: 'incompatible' };\n\nconst PATH = '/api/fetch-proxy';\nconst RAW_CONTENT_TYPE = 'application/vnd.slicc.raw-fetch';\nconst MAX_HEAD = 1024 * 1024;\nconst MAX_REQUEST_BODY = 64 * 1024 * 1024;\nconst PERMISSIONS = ['loopback-network', 'local-network-access'];\nconst LOOPBACK_PAGE = /^(127\\.\\d+\\.\\d+\\.\\d+|localhost|\\[::1\\])$/;\n\ninterface ResponseHead {\n status: number;\n statusText: string;\n headers: Array<[string, string]>;\n}\n\nconst failure = (message: string, status = 502) =>\n Object.assign(new Error(`local proxy: ${message}`), { status });\n\nfunction encodeHead(url: string, method: string, headers: HeaderList): string {\n return JSON.stringify({ url, method, headers }).replace(\n /[\\u007f-\uFFFF]/g,\n (c) => `\\\\u${c.charCodeAt(0).toString(16).padStart(4, '0')}`\n );\n}\n\nfunction hopHeaders(options: LocalProxyOptions, extra: Record<string, string>): Headers {\n return new Headers({ 'X-Bridge-Token': options.key, ...extra });\n}\n\nfunction send(options: LocalProxyOptions) {\n return options.fetch ?? globalThis.fetch.bind(globalThis);\n}\n\nasync function refusalMessage(response: Response): Promise<string> {\n const text = await response.text().catch(() => '');\n try {\n const parsed = JSON.parse(text) as { error?: unknown };\n if (typeof parsed.error === 'string') return parsed.error;\n } catch {}\n return text || response.statusText || `answered ${response.status}`;\n}\n\nasync function refusal(response: Response): Promise<Error> {\n return failure(await refusalMessage(response), response.ok ? 502 : response.status);\n}\n\nasync function permission(permissions: Pick<Permissions, 'query'> | undefined): Promise<string> {\n if (!permissions) return 'unknown';\n for (const name of PERMISSIONS) {\n try {\n return (await permissions.query({ name } as PermissionDescriptor)).state;\n } catch {}\n }\n return 'unknown';\n}\n\nfunction isHead(value: unknown): value is ResponseHead {\n const head = value as Partial<ResponseHead> | null;\n return (\n !!head &&\n typeof head.status === 'number' &&\n typeof head.statusText === 'string' &&\n Array.isArray(head.headers) &&\n head.headers.every(\n (pair) =>\n Array.isArray(pair) &&\n pair.length === 2 &&\n typeof pair[0] === 'string' &&\n typeof pair[1] === 'string'\n )\n );\n}\n\nfunction concat(a: Uint8Array, b: Uint8Array): Uint8Array {\n const out = new Uint8Array(a.byteLength + b.byteLength);\n out.set(a);\n out.set(b, a.byteLength);\n return out;\n}\n\nasync function readHead(\n reader: ReadableStreamDefaultReader<Uint8Array>,\n idleMs: number\n): Promise<{ head: ResponseHead; rest: Uint8Array }> {\n let buffer: Uint8Array = new Uint8Array(0);\n for (;;) {\n if (buffer.byteLength >= 4) {\n const length = new DataView(buffer.buffer, buffer.byteOffset, 4).getUint32(0);\n if (length > MAX_HEAD) throw failure(`response head of ${length} bytes`);\n if (buffer.byteLength >= 4 + length) {\n let head: unknown;\n try {\n head = JSON.parse(new TextDecoder().decode(buffer.subarray(4, 4 + length)));\n } catch {}\n if (!isHead(head)) throw failure('malformed response head');\n return { head, rest: buffer.subarray(4 + length) };\n }\n }\n const next = await readWithin(reader, idleMs);\n if (next.done) throw failure('closed before the response head');\n buffer = concat(buffer, next.value);\n }\n}\n\nasync function* chunks(\n rest: Uint8Array,\n reader: ReadableStreamDefaultReader<Uint8Array>,\n idleMs: number\n): AsyncGenerator<Uint8Array> {\n try {\n if (rest.byteLength > 0) yield rest;\n for (\n let next = await readWithin(reader, idleMs);\n !next.done;\n next = await readWithin(reader, idleMs)\n ) {\n if (next.value.byteLength > 0) yield next.value;\n }\n } finally {\n await reader.cancel().catch(() => undefined);\n }\n}\n\nexport async function checkLocalProxy(options: LocalProxyCheckOptions): Promise<LocalProxyStatus> {\n const onLoopback = LOOPBACK_PAGE.test(globalThis.location?.hostname ?? '');\n const permissions = onLoopback\n ? undefined\n : (options.permissions ?? globalThis.navigator?.permissions);\n if ((await permission(permissions)) === 'denied') return { state: 'blocked' };\n let response: Response;\n try {\n response = await send(options)(new URL(PATH, options.url), {\n method: 'POST',\n headers: hopHeaders(options, { 'X-Slicc-Raw-Probe': '1' }),\n credentials: 'omit',\n mode: 'cors',\n });\n } catch {\n const now = await permission(permissions);\n if (now === 'denied') return { state: 'blocked' };\n return {\n state: 'unreachable',\n permission: now === 'granted' || now === 'prompt' ? now : 'unknown',\n };\n }\n if (!response.ok) {\n return { state: 'refused', status: response.status, error: await refusalMessage(response) };\n }\n const reply = (await response.json().catch(() => null)) as Partial<LocalProxyProbe> | null;\n if (\n !reply ||\n typeof reply.rawFetch !== 'number' ||\n reply.rawFetch < 1 ||\n typeof reply.requestBodyStreaming !== 'boolean' ||\n typeof reply.maxRequestBodyBytes !== 'number'\n ) {\n return { state: 'incompatible' };\n }\n return {\n state: 'ready',\n probe: {\n rawFetch: reply.rawFetch,\n requestBodyStreaming: reply.requestBodyStreaming,\n maxRequestBodyBytes: reply.maxRequestBodyBytes,\n },\n };\n}\n\nexport async function probeLocalProxy(\n options: LocalProxyCheckOptions\n): Promise<LocalProxyProbe | null> {\n const status = await checkLocalProxy(options);\n return status.state === 'ready' ? status.probe : null;\n}\n\nexport function localProxyTransport(options: LocalProxyTransportOptions): RealmTransport {\n const endpoint = new URL(PATH, options.url);\n return {\n traits: {\n manualRedirects: true,\n encodedBodies: false,\n maxRequestBody: options.maxRequestBody ?? MAX_REQUEST_BODY,\n },\n async fetch(request: RealmTransportRequest): Promise<RealmTransportResponse> {\n let response: Response;\n try {\n response = await send(options)(endpoint, {\n method: 'POST',\n headers: hopHeaders(options, {\n 'X-Slicc-Raw-Request': encodeHead(request.url, request.method, request.headers),\n }),\n ...(request.body ? { body: request.body as BodyInit } : {}),\n signal: request.signal,\n credentials: 'omit',\n mode: 'cors',\n });\n } catch (e) {\n if (request.signal.aborted) throw e;\n throw failure(`${endpoint.origin} is unreachable or refuses this origin`);\n }\n const type = response.headers.get('content-type') ?? '';\n if (response.status !== 200 || !type.startsWith(RAW_CONTENT_TYPE) || !response.body) {\n throw await refusal(response);\n }\n const reader = response.body.getReader();\n const idleMs = options.bodyIdleMs ?? BODY_IDLE_MS;\n let framed: { head: ResponseHead; rest: Uint8Array };\n try {\n framed = await readHead(reader, idleMs);\n } catch (e) {\n await reader.cancel().catch(() => undefined);\n throw e;\n }\n const body = chunks(framed.rest, reader, idleMs);\n return {\n status: framed.head.status,\n statusText: framed.head.statusText,\n headers: framed.head.headers,\n body,\n cancel: async () => {\n await body.return(undefined);\n await reader.cancel().catch(() => undefined);\n },\n };\n },\n };\n}\n", "import type { TransportCall } from './kernel/net/remote-transport.ts';\nimport type { KernelCall, TerminalAction } from './serve.ts';\nimport { type NetworkTransport, serveTransport } from './transport.ts';\n\nexport {\n checkLocalProxy,\n type LocalProxyCheckOptions,\n type LocalProxyOptions,\n type LocalProxyProbe,\n type LocalProxyStatus,\n type LocalProxyTransportOptions,\n localProxyTransport,\n probeLocalProxy,\n} from './local-proxy-transport.ts';\nexport {\n type FetchTransportOptions,\n fetchTransport,\n type HeaderList,\n type NetworkRequest,\n type NetworkResponse,\n type NetworkTraits,\n type NetworkTransport,\n} from './transport.ts';\n\nexport interface NetworkOptions {\n transport?: NetworkTransport;\n}\n\nexport interface KernelOptions {\n root?: FileSystemDirectoryHandle;\n modules?: string;\n env?: Record<string, string>;\n metadata?: string | false;\n worker?: string | URL;\n network?: NetworkOptions;\n}\n\nexport interface RunOptions {\n cwd?: string;\n env?: Record<string, string>;\n stdin?: string | Uint8Array;\n onStdout?: (text: string) => void;\n onStderr?: (text: string) => void;\n}\n\nexport interface RunResult {\n status: number;\n stdout: string;\n stderr: string;\n}\n\nexport interface Kernel {\n run(argv: string[], options?: RunOptions): Promise<RunResult>;\n openTerminal(argv: string[], options?: TerminalOptions): Promise<Terminal>;\n terminate(): void;\n}\n\nexport interface TerminalOptions {\n cwd?: string;\n env?: Record<string, string>;\n cols?: number;\n rows?: number;\n onData?: (bytes: Uint8Array) => void;\n}\n\nexport type TerminalSignal =\n | 'SIGINT'\n | 'SIGTSTP'\n | 'SIGQUIT'\n | 'SIGHUP'\n | 'SIGTERM'\n | 'SIGKILL'\n | 'SIGCONT';\n\nexport interface Terminal {\n readonly pid: number;\n readonly exited: Promise<number>;\n onData: ((bytes: Uint8Array) => void) | null;\n write(data: string | Uint8Array): void;\n resize(cols: number, rows: number): void;\n signal(name: TerminalSignal): void;\n close(): void;\n}\n\ninterface Reply {\n id: number;\n result?: unknown;\n error?: string;\n fd?: 1 | 2;\n bytes?: Uint8Array;\n started?: number;\n}\n\ninterface Pending {\n resolve: (value: unknown) => void;\n reject: (error: Error) => void;\n output?: (fd: 1 | 2, bytes: Uint8Array) => void;\n started?: (pid: number) => void;\n}\n\ninterface Handlers {\n output?: Pending['output'];\n started?: Pending['started'];\n}\n\nconst ISOLATION =\n 'slicc-kernel needs a cross-origin isolated page (Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp or credentialless)';\n\nfunction streamer(callback: ((text: string) => void) | undefined) {\n const decoder = new TextDecoder();\n return (bytes: Uint8Array) => callback?.(decoder.decode(bytes, { stream: true }));\n}\n\nexport async function createKernel(options: KernelOptions = {}): Promise<Kernel> {\n if (!globalThis.crossOriginIsolated) throw new Error(ISOLATION);\n const url = options.worker ?? new URL('./kernel-worker.js', import.meta.url);\n const worker = new Worker(url, { type: 'module', name: 'slicc-kernel' });\n const pending = new Map<number, Pending>();\n let nextId = 0;\n let failure: Error | undefined;\n\n const fail = (error: Error) => {\n failure = error;\n bridge?.close();\n for (const call of pending.values()) call.reject(error);\n pending.clear();\n };\n const transport = options.network?.transport;\n const bridge = transport ? serveTransport(worker, transport) : undefined;\n worker.addEventListener('message', ({ data }: MessageEvent<Reply | TransportCall>) => {\n if ('net' in data) return bridge?.answer(data);\n const call = pending.get(data.id);\n if (!call) return;\n if (data.fd !== undefined) return call.output?.(data.fd, data.bytes as Uint8Array);\n if (data.started !== undefined) return call.started?.(data.started);\n pending.delete(data.id);\n if (data.error !== undefined) call.reject(new Error(data.error));\n else call.resolve(data.result);\n });\n worker.addEventListener('error', (event) => {\n event.preventDefault();\n fail(new Error(`slicc-kernel worker failed: ${event.message}`));\n });\n\n function request(\n req: KernelCall,\n handlers: Handlers = {}\n ): { id: number; done: Promise<unknown> } {\n const id = ++nextId;\n if (failure) return { id, done: Promise.reject(failure) };\n const done = new Promise((resolve, reject) => {\n pending.set(id, { resolve, reject, ...handlers });\n worker.postMessage({ ...req, id });\n });\n return { id, done };\n }\n\n const call = (req: KernelCall, handlers?: Handlers) => request(req, handlers).done;\n\n async function openTerminal(argv: string[], opts: TerminalOptions = {}): Promise<Terminal> {\n const { onData, ...options } = opts;\n let listener = onData ?? null;\n const backlog: Uint8Array[] = [];\n const started = Promise.withResolvers<number>();\n const { id, done } = request(\n { op: 'open-terminal', argv, options },\n {\n output: (_fd, bytes) => (listener ? listener(bytes) : backlog.push(bytes)),\n started: started.resolve,\n }\n );\n done.catch(started.reject);\n const pid = await started.promise;\n const send = (action: TerminalAction) =>\n void call({ op: 'terminal', terminal: id, ...action }).catch(() => undefined);\n return {\n pid,\n exited: done as Promise<number>,\n get onData() {\n return listener;\n },\n set onData(next) {\n listener = next;\n if (next) for (const bytes of backlog.splice(0)) next(bytes);\n },\n write: (data) =>\n send({\n action: 'write',\n bytes: typeof data === 'string' ? new TextEncoder().encode(data) : data,\n }),\n resize: (cols, rows) => send({ action: 'resize', cols, rows }),\n signal: (name) => send({ action: 'signal', signal: name }),\n close: () => send({ action: 'close' }),\n };\n }\n\n await call({\n op: 'init',\n ...(options.root ? { root: options.root } : {}),\n ...(options.modules ? { modules: options.modules } : {}),\n ...(options.env ? { env: options.env } : {}),\n ...(options.metadata !== undefined ? { metadata: options.metadata } : {}),\n ...(transport ? { transport: transport.traits } : {}),\n });\n\n return {\n async run(argv, runOptions = {}) {\n const { onStdout, onStderr, stdin, ...rest } = runOptions;\n const streams = { 1: streamer(onStdout), 2: streamer(onStderr) };\n const input = typeof stdin === 'string' ? new TextEncoder().encode(stdin) : stdin;\n const result = (await call(\n { op: 'run', argv, options: { ...rest, ...(input ? { stdin: input } : {}) } },\n { output: (fd, bytes) => streams[fd](bytes) }\n )) as { status: number; stdout: Uint8Array; stderr: Uint8Array };\n const decoder = new TextDecoder();\n return {\n status: result.status,\n stdout: decoder.decode(result.stdout),\n stderr: decoder.decode(result.stderr),\n };\n },\n openTerminal,\n terminate() {\n fail(new Error('slicc-kernel terminated'));\n worker.terminate();\n },\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["send", "MAX_REQUEST_BODY", "chunks", "failure", "call", "options", "send"]
|
|
7
7
|
}
|
package/dist/kernel-worker.js
CHANGED
|
@@ -2400,9 +2400,11 @@ function enableNetwork(net, options) {
|
|
|
2400
2400
|
// src/kernel/net/remote-transport.ts
|
|
2401
2401
|
var TransportError = class extends Error {
|
|
2402
2402
|
status;
|
|
2403
|
-
|
|
2403
|
+
code;
|
|
2404
|
+
constructor(message2, status, code) {
|
|
2404
2405
|
super(message2);
|
|
2405
2406
|
this.status = status;
|
|
2407
|
+
this.code = code;
|
|
2406
2408
|
}
|
|
2407
2409
|
};
|
|
2408
2410
|
var RemoteTransport = class {
|
|
@@ -2418,8 +2420,9 @@ var RemoteTransport = class {
|
|
|
2418
2420
|
const waiter = this.waiting.get(reply.nid);
|
|
2419
2421
|
if (!waiter) return;
|
|
2420
2422
|
this.waiting.delete(reply.nid);
|
|
2421
|
-
if (reply.net === "error")
|
|
2422
|
-
|
|
2423
|
+
if (reply.net === "error") {
|
|
2424
|
+
waiter.reject(new TransportError(reply.message, reply.status, reply.code));
|
|
2425
|
+
} else waiter.resolve(reply);
|
|
2423
2426
|
}
|
|
2424
2427
|
ask(call) {
|
|
2425
2428
|
return new Promise((resolve, reject) => {
|
|
@@ -3094,6 +3097,8 @@ var SAB_I_STATUS = 2;
|
|
|
3094
3097
|
var SAB_I_TOTAL = 3;
|
|
3095
3098
|
var SAB_I_CHUNK = 4;
|
|
3096
3099
|
var SAB_I_OFFSET = 5;
|
|
3100
|
+
var SAB_I_REQ = 6;
|
|
3101
|
+
var SAB_I_PUB = 7;
|
|
3097
3102
|
var SAB_I_SIGNALS = 8;
|
|
3098
3103
|
var SAB_I_TIMERS = 9;
|
|
3099
3104
|
var SAB_STATE_READY = 2;
|
|
@@ -3148,6 +3153,10 @@ function attachSyncSabResponder(port, sab, token, opts) {
|
|
|
3148
3153
|
pending.delete(id);
|
|
3149
3154
|
}
|
|
3150
3155
|
function publish(id, entry, offset) {
|
|
3156
|
+
if (Atomics.load(header2, SAB_I_REQ) !== id) {
|
|
3157
|
+
drop(id);
|
|
3158
|
+
return;
|
|
3159
|
+
}
|
|
3151
3160
|
const chunk2 = Math.min(window.byteLength, entry.payload.byteLength - offset);
|
|
3152
3161
|
if (chunk2 > 0) window.set(entry.payload.subarray(offset, offset + chunk2));
|
|
3153
3162
|
Atomics.store(header2, SAB_I_STATUS, entry.status);
|
|
@@ -3156,7 +3165,8 @@ function attachSyncSabResponder(port, sab, token, opts) {
|
|
|
3156
3165
|
Atomics.store(header2, SAB_I_OFFSET, offset);
|
|
3157
3166
|
Atomics.store(header2, SAB_I_SEQ, id);
|
|
3158
3167
|
Atomics.store(header2, SAB_I_STATE, SAB_STATE_READY);
|
|
3159
|
-
Atomics.
|
|
3168
|
+
Atomics.add(header2, SAB_I_PUB, 1);
|
|
3169
|
+
Atomics.notify(header2, SAB_I_PUB);
|
|
3160
3170
|
if (offset + chunk2 >= entry.payload.byteLength) drop(id);
|
|
3161
3171
|
}
|
|
3162
3172
|
function settle2(id, result) {
|
|
@@ -3472,7 +3482,8 @@ var HttpHandles = class {
|
|
|
3472
3482
|
else entry.left = next.value;
|
|
3473
3483
|
} catch (e) {
|
|
3474
3484
|
entry.done = true;
|
|
3475
|
-
|
|
3485
|
+
const timedOut = e?.code === "ETIMEDOUT";
|
|
3486
|
+
return { ok: false, errno: timedOut ? "ETIMEDOUT" : "EIO", message: message(e) };
|
|
3476
3487
|
}
|
|
3477
3488
|
}
|
|
3478
3489
|
const bytes = entry.left.subarray(0, Math.max(0, max));
|