sandboxedjs 0.1.48 → 0.1.49
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/dist/agent.d.cts +2 -1
- package/dist/agent.d.ts +2 -1
- package/dist/{container-DyRF-bY0.d.cts → container-DBMPLbUu.d.ts} +103 -410
- package/dist/{container-DyRF-bY0.d.ts → container-Dg8NwBc7.d.cts} +103 -410
- package/dist/index.cjs +2335 -306
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -65
- package/dist/index.d.ts +20 -65
- package/dist/index.js +2331 -305
- package/dist/index.js.map +1 -1
- package/dist/memory-volume-CTOXNJ6n.d.ts +66 -0
- package/dist/memory-volume-DCzGZFJb.d.cts +66 -0
- package/dist/python/python.data +16026 -66
- package/dist/python/python.js +2 -0
- package/dist/python/python.wasm +0 -0
- package/dist/python/python.worker.js +87 -0
- package/dist/python/runtime.json +34 -0
- package/dist/python-abi.cjs +2892 -0
- package/dist/python-abi.cjs.map +1 -0
- package/dist/python-abi.d.cts +645 -0
- package/dist/python-abi.d.ts +645 -0
- package/dist/python-abi.js +2839 -0
- package/dist/python-abi.js.map +1 -0
- package/dist/python-worker.js +865 -0
- package/dist/python-worker.js.map +1 -0
- package/dist/rolldown-wasi-worker.js +5 -1
- package/dist/rolldown-wasi-worker.js.map +1 -1
- package/dist/vfs-DzEcPbMY.d.cts +427 -0
- package/dist/vfs-DzEcPbMY.d.ts +427 -0
- package/package.json +8 -3
|
@@ -0,0 +1,645 @@
|
|
|
1
|
+
import { V as Vfs, C as Cred } from './vfs-DzEcPbMY.cjs';
|
|
2
|
+
export { l as ROOT_CRED, u as makeCred } from './vfs-DzEcPbMY.cjs';
|
|
3
|
+
export { M as MemoryVolume } from './memory-volume-DCzGZFJb.cjs';
|
|
4
|
+
|
|
5
|
+
/** Protocol version carried in every frame. */
|
|
6
|
+
declare const SBX_HOST_ABI_VERSION = 1;
|
|
7
|
+
declare const SBX_REQUEST_HEADER_BYTES = 16;
|
|
8
|
+
declare const SBX_RESPONSE_HEADER_BYTES = 20;
|
|
9
|
+
/** Operation codes. Families are 256 apart so a family stays contiguous. */
|
|
10
|
+
declare const Op: {
|
|
11
|
+
readonly handshake: 0;
|
|
12
|
+
readonly openat: 1;
|
|
13
|
+
readonly close: 2;
|
|
14
|
+
readonly read: 3;
|
|
15
|
+
readonly write: 4;
|
|
16
|
+
readonly pread: 5;
|
|
17
|
+
readonly pwrite: 6;
|
|
18
|
+
readonly lseek: 7;
|
|
19
|
+
readonly fstat: 8;
|
|
20
|
+
readonly statat: 9;
|
|
21
|
+
readonly ftruncate: 10;
|
|
22
|
+
readonly renameat: 11;
|
|
23
|
+
readonly unlinkat: 12;
|
|
24
|
+
readonly mkdirat: 13;
|
|
25
|
+
readonly readlinkat: 14;
|
|
26
|
+
readonly symlinkat: 15;
|
|
27
|
+
readonly getdents: 16;
|
|
28
|
+
readonly fsync: 17;
|
|
29
|
+
readonly dup: 256;
|
|
30
|
+
readonly dup2: 257;
|
|
31
|
+
readonly get_flags: 258;
|
|
32
|
+
readonly set_flags: 259;
|
|
33
|
+
readonly pipe: 512;
|
|
34
|
+
readonly poll: 768;
|
|
35
|
+
readonly clock_gettime: 1024;
|
|
36
|
+
readonly sleep: 1025;
|
|
37
|
+
readonly getpid: 1280;
|
|
38
|
+
readonly getcwd: 1281;
|
|
39
|
+
readonly chdir: 1282;
|
|
40
|
+
readonly environ: 1283;
|
|
41
|
+
readonly getrandom: 1536;
|
|
42
|
+
};
|
|
43
|
+
type OpCode = (typeof Op)[keyof typeof Op];
|
|
44
|
+
/** Canonical (Linux/musl) errno values. A negative status is `-Errno.X`. */
|
|
45
|
+
declare const Errno: {
|
|
46
|
+
readonly EPERM: 1;
|
|
47
|
+
readonly ENOENT: 2;
|
|
48
|
+
readonly ESRCH: 3;
|
|
49
|
+
readonly EINTR: 4;
|
|
50
|
+
readonly EIO: 5;
|
|
51
|
+
readonly ENXIO: 6;
|
|
52
|
+
readonly E2BIG: 7;
|
|
53
|
+
readonly EBADF: 9;
|
|
54
|
+
readonly EAGAIN: 11;
|
|
55
|
+
readonly ENOMEM: 12;
|
|
56
|
+
readonly EACCES: 13;
|
|
57
|
+
readonly EFAULT: 14;
|
|
58
|
+
readonly EBUSY: 16;
|
|
59
|
+
readonly EEXIST: 17;
|
|
60
|
+
readonly EXDEV: 18;
|
|
61
|
+
readonly ENODEV: 19;
|
|
62
|
+
readonly ENOTDIR: 20;
|
|
63
|
+
readonly EISDIR: 21;
|
|
64
|
+
readonly EINVAL: 22;
|
|
65
|
+
readonly ENFILE: 23;
|
|
66
|
+
readonly EMFILE: 24;
|
|
67
|
+
readonly ENOTTY: 25;
|
|
68
|
+
readonly EFBIG: 27;
|
|
69
|
+
readonly ENOSPC: 28;
|
|
70
|
+
readonly ESPIPE: 29;
|
|
71
|
+
readonly EROFS: 30;
|
|
72
|
+
readonly EMLINK: 31;
|
|
73
|
+
readonly EPIPE: 32;
|
|
74
|
+
readonly ERANGE: 34;
|
|
75
|
+
readonly ENAMETOOLONG: 36;
|
|
76
|
+
readonly ENOSYS: 38;
|
|
77
|
+
readonly ENOTEMPTY: 39;
|
|
78
|
+
readonly ELOOP: 40;
|
|
79
|
+
readonly ENODATA: 61;
|
|
80
|
+
readonly EPROTO: 71;
|
|
81
|
+
readonly EOVERFLOW: 75;
|
|
82
|
+
readonly ETIMEDOUT: 110;
|
|
83
|
+
readonly ECANCELED: 125;
|
|
84
|
+
readonly EDQUOT: 122;
|
|
85
|
+
};
|
|
86
|
+
type ErrnoName = keyof typeof Errno;
|
|
87
|
+
/** Capability names a host may advertise in its handshake. */
|
|
88
|
+
declare const CAPABILITIES: readonly ["files", "descriptors", "pipes", "readiness", "time", "identity", "entropy", "sockets", "processes", "signals", "storage", "services", "threads"];
|
|
89
|
+
type Capability = (typeof CAPABILITIES)[number];
|
|
90
|
+
/** Names by code, for diagnostics. Never used for dispatch. */
|
|
91
|
+
declare const OP_NAMES: Record<number, string>;
|
|
92
|
+
declare const ERRNO_NAMES: Record<number, string>;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Framing for the host ABI.
|
|
96
|
+
*
|
|
97
|
+
* Every field is fixed-width and little-endian, because the two sides are
|
|
98
|
+
* compiled by different toolchains and a shared struct layout is the one thing
|
|
99
|
+
* they cannot negotiate at runtime. Text is UTF-8; file content and network
|
|
100
|
+
* traffic are raw bytes and are never decoded in transit.
|
|
101
|
+
*
|
|
102
|
+
* `request_id` and `process_generation` exist so a late answer can be
|
|
103
|
+
* recognised as late. A worker that exits and is replaced must not have its
|
|
104
|
+
* successor accept a completion addressed to the process before it, and the
|
|
105
|
+
* failure mode for a mismatched frame is an error — never an empty success.
|
|
106
|
+
*/
|
|
107
|
+
|
|
108
|
+
interface RequestHeader {
|
|
109
|
+
version: number;
|
|
110
|
+
op: number;
|
|
111
|
+
requestId: number;
|
|
112
|
+
generation: number;
|
|
113
|
+
}
|
|
114
|
+
interface ResponseFrame {
|
|
115
|
+
header: RequestHeader;
|
|
116
|
+
status: number;
|
|
117
|
+
payload: Uint8Array;
|
|
118
|
+
}
|
|
119
|
+
declare class ProtocolError extends Error {
|
|
120
|
+
readonly code = "ERR_SBX_ABI_PROTOCOL";
|
|
121
|
+
}
|
|
122
|
+
declare function encodeRequest(header: RequestHeader, payload: Uint8Array): Uint8Array;
|
|
123
|
+
declare function decodeRequest(frame: Uint8Array): {
|
|
124
|
+
header: RequestHeader;
|
|
125
|
+
payload: Uint8Array;
|
|
126
|
+
};
|
|
127
|
+
declare function encodeResponse(header: RequestHeader, status: number, payload: Uint8Array): Uint8Array;
|
|
128
|
+
declare function decodeResponse(frame: Uint8Array, expected?: RequestHeader): ResponseFrame;
|
|
129
|
+
/** Little-endian reader over a payload. Bounds-checked: the guest owns this memory. */
|
|
130
|
+
declare class Reader {
|
|
131
|
+
private at;
|
|
132
|
+
private readonly view;
|
|
133
|
+
private readonly bytes;
|
|
134
|
+
constructor(bytes: Uint8Array);
|
|
135
|
+
private need;
|
|
136
|
+
i32(): number;
|
|
137
|
+
u32(): number;
|
|
138
|
+
i64(): number;
|
|
139
|
+
u64(): number;
|
|
140
|
+
bytes32(): Uint8Array;
|
|
141
|
+
string(): string;
|
|
142
|
+
get remaining(): number;
|
|
143
|
+
}
|
|
144
|
+
/** Little-endian writer. Grows as needed; payload sizes are bounded by the caller. */
|
|
145
|
+
declare class Writer {
|
|
146
|
+
private parts;
|
|
147
|
+
i32(value: number): this;
|
|
148
|
+
u32(value: number): this;
|
|
149
|
+
i64(value: number): this;
|
|
150
|
+
u64(value: number): this;
|
|
151
|
+
bytes32(value: Uint8Array): this;
|
|
152
|
+
string(value: string): this;
|
|
153
|
+
finish(): Uint8Array;
|
|
154
|
+
}
|
|
155
|
+
/** A status the guest reads as `-errno`. */
|
|
156
|
+
declare function failure(errno: number): number;
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* The transport under the host ABI: one blocking client, one non-blocking host.
|
|
160
|
+
*
|
|
161
|
+
* This is deliberately not `runtime/sync-channel.ts`. That channel predates the
|
|
162
|
+
* ABI and carries no request identity, so a late or duplicated answer is
|
|
163
|
+
* indistinguishable from the right one; worse, its server answers a failed
|
|
164
|
+
* handler with a zero-length frame, which a caller can only read as a
|
|
165
|
+
* successful empty result. Both are acceptable for `spawnSync`, where the
|
|
166
|
+
* payload is self-describing JSON, and neither is acceptable for `read()`,
|
|
167
|
+
* where an empty result means end of input.
|
|
168
|
+
*
|
|
169
|
+
* So the framing here always carries a full response header, a transport
|
|
170
|
+
* failure is always an error, and the client verifies that the answer it got
|
|
171
|
+
* belongs to the question it asked.
|
|
172
|
+
*
|
|
173
|
+
* Only the client blocks, and the client never owns shared state. The host
|
|
174
|
+
* services requests from its ordinary event loop and may take as long as it
|
|
175
|
+
* likes — which is what lets a guest's synchronous `read()` wait for a
|
|
176
|
+
* keystroke that has not been typed yet.
|
|
177
|
+
*/
|
|
178
|
+
interface HostTransportBuffers {
|
|
179
|
+
control: SharedArrayBuffer;
|
|
180
|
+
data: SharedArrayBuffer;
|
|
181
|
+
}
|
|
182
|
+
declare function createHostTransportBuffers(windowBytes?: number): HostTransportBuffers;
|
|
183
|
+
declare class HostTransportError extends Error {
|
|
184
|
+
code: string;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* The guest side. Lives in the worker with the compiled program and blocks.
|
|
188
|
+
*
|
|
189
|
+
* `wake` nudges the host's event loop: the host cannot poll shared memory
|
|
190
|
+
* without spinning, so each window is announced with an ordinary message.
|
|
191
|
+
*/
|
|
192
|
+
declare class HostCallClient {
|
|
193
|
+
private control;
|
|
194
|
+
private data;
|
|
195
|
+
private capacity;
|
|
196
|
+
private wake;
|
|
197
|
+
private closed;
|
|
198
|
+
constructor(buffers: HostTransportBuffers, wake: () => void);
|
|
199
|
+
/** Send a frame and block until the whole answer is back. Never returns empty. */
|
|
200
|
+
call(request: Uint8Array): Uint8Array;
|
|
201
|
+
private send;
|
|
202
|
+
private receive;
|
|
203
|
+
private publish;
|
|
204
|
+
private waitWhile;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* The host side. Lives wherever the volume and the process table do, and never
|
|
208
|
+
* blocks; `handle` is free to be asynchronous.
|
|
209
|
+
*/
|
|
210
|
+
declare class HostCallServer {
|
|
211
|
+
private control;
|
|
212
|
+
private data;
|
|
213
|
+
private capacity;
|
|
214
|
+
private handle;
|
|
215
|
+
private onFault;
|
|
216
|
+
private incoming;
|
|
217
|
+
private outgoing;
|
|
218
|
+
private sent;
|
|
219
|
+
private closed;
|
|
220
|
+
constructor(buffers: HostTransportBuffers, handle: (request: Uint8Array) => Promise<Uint8Array> | Uint8Array, onFault?: (error: unknown) => void);
|
|
221
|
+
/** Call on each wake message from the client. */
|
|
222
|
+
pump(): Promise<void>;
|
|
223
|
+
/** Release a blocked client — container teardown, or the worker being killed. */
|
|
224
|
+
close(): void;
|
|
225
|
+
private sendWindow;
|
|
226
|
+
private publish;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Open-file descriptions: the thing a descriptor points *at*.
|
|
231
|
+
*
|
|
232
|
+
* POSIX has three levels and collapsing any two of them produces bugs that look
|
|
233
|
+
* like something else entirely:
|
|
234
|
+
*
|
|
235
|
+
* - a **pathname** is a directory entry, and may be renamed or removed;
|
|
236
|
+
* - an **inode** is the file's identity and content, and outlives its names;
|
|
237
|
+
* - an **open-file description** holds the offset and the status flags.
|
|
238
|
+
*
|
|
239
|
+
* `dup()` makes two descriptors share one description — so they share an offset.
|
|
240
|
+
* Two separate `open()` calls on the same path make two descriptions, so their
|
|
241
|
+
* offsets are independent. A file stays readable through an open description
|
|
242
|
+
* after its last name is unlinked. None of that is expressible if a descriptor
|
|
243
|
+
* is just a path and a number, which is why this layer exists rather than the
|
|
244
|
+
* path-based {@link Vfs} calls being used directly.
|
|
245
|
+
*
|
|
246
|
+
* The identity used here is the volume's inode number, so a rename moves a name
|
|
247
|
+
* without disturbing anything already open.
|
|
248
|
+
*/
|
|
249
|
+
|
|
250
|
+
/** A failure carrying the errno the guest's libc should see. */
|
|
251
|
+
declare class PosixError extends Error {
|
|
252
|
+
readonly errno: number;
|
|
253
|
+
constructor(errno: number, message?: string);
|
|
254
|
+
}
|
|
255
|
+
declare const O_RDONLY = 0;
|
|
256
|
+
declare const O_WRONLY = 1;
|
|
257
|
+
declare const O_RDWR = 2;
|
|
258
|
+
declare const O_CREAT = 64;
|
|
259
|
+
declare const O_EXCL = 128;
|
|
260
|
+
declare const O_TRUNC = 512;
|
|
261
|
+
declare const O_APPEND = 1024;
|
|
262
|
+
declare const O_NONBLOCK = 2048;
|
|
263
|
+
declare const O_DIRECTORY = 65536;
|
|
264
|
+
declare const O_CLOEXEC = 524288;
|
|
265
|
+
/** Access mode alone, with the flag bits masked off. */
|
|
266
|
+
declare function accessMode(flags: number): number;
|
|
267
|
+
interface DescriptionStat {
|
|
268
|
+
ino: number;
|
|
269
|
+
mode: number;
|
|
270
|
+
size: number;
|
|
271
|
+
uid: number;
|
|
272
|
+
gid: number;
|
|
273
|
+
nlink: number;
|
|
274
|
+
atimeMs: number;
|
|
275
|
+
mtimeMs: number;
|
|
276
|
+
ctimeMs: number;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* What every kind of open thing can do.
|
|
280
|
+
*
|
|
281
|
+
* `read` and `write` are permitted to move fewer bytes than asked for: that is
|
|
282
|
+
* ordinary POSIX behaviour, and a guest that assumes otherwise is already
|
|
283
|
+
* broken on Linux.
|
|
284
|
+
*/
|
|
285
|
+
interface OpenFileDescription {
|
|
286
|
+
readonly kind: "file" | "dir" | "pipe" | "stream";
|
|
287
|
+
flags: number;
|
|
288
|
+
read(length: number): Uint8Array;
|
|
289
|
+
write(data: Uint8Array): number;
|
|
290
|
+
pread?(length: number, offset: number): Uint8Array;
|
|
291
|
+
pwrite?(data: Uint8Array, offset: number): number;
|
|
292
|
+
seek?(offset: number, whence: number): number;
|
|
293
|
+
stat(): DescriptionStat;
|
|
294
|
+
truncate?(length: number): void;
|
|
295
|
+
/** Ready to read now, or at end of input (which is also "ready"). */
|
|
296
|
+
readable(): boolean;
|
|
297
|
+
/** Ready to accept at least one byte. */
|
|
298
|
+
writable(): boolean;
|
|
299
|
+
/** Resolves when readiness may have changed; used only to park a poll. */
|
|
300
|
+
whenReady(): Promise<void>;
|
|
301
|
+
/** Last reference dropped. */
|
|
302
|
+
close(): void;
|
|
303
|
+
}
|
|
304
|
+
declare const SEEK_SET = 0;
|
|
305
|
+
declare const SEEK_CUR = 1;
|
|
306
|
+
declare const SEEK_END = 2;
|
|
307
|
+
/**
|
|
308
|
+
* The bytes behind an open regular file.
|
|
309
|
+
*
|
|
310
|
+
* Content lives in the volume while a name still points at it, and moves into
|
|
311
|
+
* `detached` when the last name goes away with the file still open. That is the
|
|
312
|
+
* only way to honour "an unlinked file stays readable until the last close" on
|
|
313
|
+
* top of a path-addressed volume.
|
|
314
|
+
*
|
|
315
|
+
* A name removed by something that does not go through this service — the
|
|
316
|
+
* shell, or the Node side — cannot be intercepted, and the description will
|
|
317
|
+
* then fail with ENOENT rather than reading stale bytes. Documented in
|
|
318
|
+
* docs/python/abi.md; correctness holds for everything using the host ABI.
|
|
319
|
+
*/
|
|
320
|
+
declare class Inode {
|
|
321
|
+
readonly ino: number;
|
|
322
|
+
path: string;
|
|
323
|
+
private readonly vfs;
|
|
324
|
+
private readonly cred;
|
|
325
|
+
detached: Uint8Array | null;
|
|
326
|
+
refs: number;
|
|
327
|
+
constructor(ino: number, path: string, vfs: Vfs, cred: Cred);
|
|
328
|
+
/** Read the whole file, wherever it currently lives. */
|
|
329
|
+
contents(): Uint8Array;
|
|
330
|
+
replace(data: Uint8Array): void;
|
|
331
|
+
/** Called when the last name is about to be removed. */
|
|
332
|
+
detach(): void;
|
|
333
|
+
size(): number;
|
|
334
|
+
stat(): DescriptionStat;
|
|
335
|
+
}
|
|
336
|
+
/** One `open()`: an offset and status flags over an {@link Inode}. */
|
|
337
|
+
declare class FileDescription implements OpenFileDescription {
|
|
338
|
+
readonly inode: Inode;
|
|
339
|
+
flags: number;
|
|
340
|
+
readonly kind = "file";
|
|
341
|
+
offset: number;
|
|
342
|
+
constructor(inode: Inode, flags: number);
|
|
343
|
+
read(length: number): Uint8Array;
|
|
344
|
+
pread(length: number, offset: number): Uint8Array;
|
|
345
|
+
write(data: Uint8Array): number;
|
|
346
|
+
pwrite(data: Uint8Array, offset: number): number;
|
|
347
|
+
private writeAt;
|
|
348
|
+
seek(offset: number, whence: number): number;
|
|
349
|
+
truncate(length: number): void;
|
|
350
|
+
stat(): DescriptionStat;
|
|
351
|
+
readable(): boolean;
|
|
352
|
+
writable(): boolean;
|
|
353
|
+
whenReady(): Promise<void>;
|
|
354
|
+
close(): void;
|
|
355
|
+
}
|
|
356
|
+
/** An open directory: `getdents` reads from a snapshot at the description's offset. */
|
|
357
|
+
declare class DirectoryDescription implements OpenFileDescription {
|
|
358
|
+
readonly path: string;
|
|
359
|
+
flags: number;
|
|
360
|
+
private readonly vfs;
|
|
361
|
+
private readonly cred;
|
|
362
|
+
readonly kind = "dir";
|
|
363
|
+
private entries;
|
|
364
|
+
private index;
|
|
365
|
+
constructor(path: string, flags: number, vfs: Vfs, cred: Cred);
|
|
366
|
+
/** Entry names, NUL-terminated, as many as fit in `length`. */
|
|
367
|
+
read(length: number): Uint8Array;
|
|
368
|
+
write(): number;
|
|
369
|
+
seek(offset: number, whence: number): number;
|
|
370
|
+
stat(): DescriptionStat;
|
|
371
|
+
readable(): boolean;
|
|
372
|
+
writable(): boolean;
|
|
373
|
+
whenReady(): Promise<void>;
|
|
374
|
+
close(): void;
|
|
375
|
+
}
|
|
376
|
+
/** The shared buffer between a pipe's two ends. */
|
|
377
|
+
declare class PipeBuffer {
|
|
378
|
+
private chunks;
|
|
379
|
+
private queued;
|
|
380
|
+
readers: number;
|
|
381
|
+
writers: number;
|
|
382
|
+
private waiters;
|
|
383
|
+
get available(): number;
|
|
384
|
+
get space(): number;
|
|
385
|
+
push(data: Uint8Array): void;
|
|
386
|
+
take(length: number): Uint8Array;
|
|
387
|
+
/** Anything that may have changed readiness for either end. */
|
|
388
|
+
wake(): void;
|
|
389
|
+
whenReady(): Promise<void>;
|
|
390
|
+
}
|
|
391
|
+
declare class PipeReadEnd implements OpenFileDescription {
|
|
392
|
+
private readonly buffer;
|
|
393
|
+
flags: number;
|
|
394
|
+
readonly kind = "pipe";
|
|
395
|
+
constructor(buffer: PipeBuffer, flags: number);
|
|
396
|
+
read(length: number): Uint8Array;
|
|
397
|
+
write(): number;
|
|
398
|
+
stat(): DescriptionStat;
|
|
399
|
+
readable(): boolean;
|
|
400
|
+
writable(): boolean;
|
|
401
|
+
whenReady(): Promise<void>;
|
|
402
|
+
close(): void;
|
|
403
|
+
}
|
|
404
|
+
declare class PipeWriteEnd implements OpenFileDescription {
|
|
405
|
+
private readonly buffer;
|
|
406
|
+
flags: number;
|
|
407
|
+
readonly kind = "pipe";
|
|
408
|
+
constructor(buffer: PipeBuffer, flags: number);
|
|
409
|
+
read(): Uint8Array;
|
|
410
|
+
write(data: Uint8Array): number;
|
|
411
|
+
stat(): DescriptionStat;
|
|
412
|
+
readable(): boolean;
|
|
413
|
+
writable(): boolean;
|
|
414
|
+
whenReady(): Promise<void>;
|
|
415
|
+
close(): void;
|
|
416
|
+
}
|
|
417
|
+
declare function createPipe(flags?: number): [PipeReadEnd, PipeWriteEnd];
|
|
418
|
+
/**
|
|
419
|
+
* A process's standard streams.
|
|
420
|
+
*
|
|
421
|
+
* Bytes, not text: the terminal boundary is where multi-byte characters get cut
|
|
422
|
+
* in half, so nothing here decodes. Input arrives from the host asynchronously
|
|
423
|
+
* and is queued; a blocked reader parks on {@link whenReady} rather than
|
|
424
|
+
* spinning.
|
|
425
|
+
*/
|
|
426
|
+
declare class StreamDescription implements OpenFileDescription {
|
|
427
|
+
flags: number;
|
|
428
|
+
private readonly sink;
|
|
429
|
+
readonly isTty: boolean;
|
|
430
|
+
readonly kind = "stream";
|
|
431
|
+
private queue;
|
|
432
|
+
private queued;
|
|
433
|
+
private ended;
|
|
434
|
+
private waiters;
|
|
435
|
+
constructor(flags: number, sink: ((data: Uint8Array) => void) | null, isTty?: boolean);
|
|
436
|
+
/** Host side: give the guest more input. */
|
|
437
|
+
push(data: Uint8Array): void;
|
|
438
|
+
/** Host side: no more input will arrive. */
|
|
439
|
+
end(): void;
|
|
440
|
+
read(length: number): Uint8Array;
|
|
441
|
+
write(data: Uint8Array): number;
|
|
442
|
+
stat(): DescriptionStat;
|
|
443
|
+
readable(): boolean;
|
|
444
|
+
writable(): boolean;
|
|
445
|
+
whenReady(): Promise<void>;
|
|
446
|
+
close(): void;
|
|
447
|
+
private wake;
|
|
448
|
+
}
|
|
449
|
+
/** Translate a volume error into the errno a guest expects. */
|
|
450
|
+
declare function toPosixError(error: unknown): PosixError;
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Per-process descriptor tables, and the path operations that have to know
|
|
454
|
+
* about them.
|
|
455
|
+
*
|
|
456
|
+
* A descriptor is a small integer plus a close-on-exec bit; everything else
|
|
457
|
+
* lives in the {@link OpenFileDescription} it names. Several descriptors — in
|
|
458
|
+
* one process or across a spawn — may name the same description, and that is
|
|
459
|
+
* how `dup2(fd, 1)` redirects a child's output without copying anything.
|
|
460
|
+
*
|
|
461
|
+
* `unlink` and `rename` live here rather than being left to {@link Vfs}
|
|
462
|
+
* because they are the two operations whose correctness depends on what is
|
|
463
|
+
* currently open: a removed name must not take an open file's contents with
|
|
464
|
+
* it, and a renamed one must not strand it.
|
|
465
|
+
*/
|
|
466
|
+
|
|
467
|
+
/** Descriptors are handed out lowest-free-first, as POSIX requires. */
|
|
468
|
+
declare class DescriptorTable {
|
|
469
|
+
private readonly slots;
|
|
470
|
+
/** Descriptions this table shares with others, so close counts correctly. */
|
|
471
|
+
private static readonly refs;
|
|
472
|
+
/** Install at a chosen number, closing whatever was there. */
|
|
473
|
+
set(fd: number, description: OpenFileDescription, cloexec?: boolean): number;
|
|
474
|
+
/** Install at the lowest free number at or above `from`. */
|
|
475
|
+
add(description: OpenFileDescription, cloexec?: boolean, from?: number): number;
|
|
476
|
+
get(fd: number): OpenFileDescription;
|
|
477
|
+
has(fd: number): boolean;
|
|
478
|
+
cloexec(fd: number): boolean;
|
|
479
|
+
setCloexec(fd: number, value: boolean): void;
|
|
480
|
+
/** `dup`: a second name for one description, so the offset is shared. */
|
|
481
|
+
dup(fd: number, from?: number): number;
|
|
482
|
+
dup2(fd: number, target: number): number;
|
|
483
|
+
close(fd: number): void;
|
|
484
|
+
/** Everything a child inherits: a spawn keeps all but the close-on-exec ones. */
|
|
485
|
+
inherit(): DescriptorTable;
|
|
486
|
+
/** Drop every descriptor. Every resource has an owner and a cleanup path. */
|
|
487
|
+
closeAll(): void;
|
|
488
|
+
get openCount(): number;
|
|
489
|
+
private release;
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Path operations bound to one container's volume and one process's credentials.
|
|
493
|
+
*
|
|
494
|
+
* Open inodes are tracked per volume so that two processes opening the same
|
|
495
|
+
* file agree about its identity — which is what makes "unlink it in one, keep
|
|
496
|
+
* reading it in the other" behave.
|
|
497
|
+
*/
|
|
498
|
+
declare class FileService {
|
|
499
|
+
private readonly vfs;
|
|
500
|
+
private readonly cred;
|
|
501
|
+
private readonly openInodes;
|
|
502
|
+
constructor(vfs: Vfs, cred: Cred);
|
|
503
|
+
open(path: string, flags: number, mode?: number): OpenFileDescription;
|
|
504
|
+
/**
|
|
505
|
+
* Remove a name.
|
|
506
|
+
*
|
|
507
|
+
* If something still has the file open, its contents move into the open
|
|
508
|
+
* description first: POSIX guarantees a reader keeps reading, and a volume
|
|
509
|
+
* that only knows about paths cannot provide that on its own.
|
|
510
|
+
*/
|
|
511
|
+
unlink(path: string): void;
|
|
512
|
+
/** Rename a name. Anything already open follows the file to its new name. */
|
|
513
|
+
rename(from: string, to: string): void;
|
|
514
|
+
/** One {@link Inode} per file identity, shared by every open description. */
|
|
515
|
+
private inodeFor;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* The kernel side of the host ABI: turn frames into real operations.
|
|
520
|
+
*
|
|
521
|
+
* This runs on whichever thread owns the volume and the process table, and it
|
|
522
|
+
* never blocks. A guest that asks to read a terminal with nothing typed yet
|
|
523
|
+
* parks in `Atomics.wait` inside its own worker; the handler here simply
|
|
524
|
+
* awaits {@link OpenFileDescription.whenReady} and answers when input arrives.
|
|
525
|
+
* That asymmetry is the whole reason a synchronous `read()` can exist at all
|
|
526
|
+
* without freezing the host — and it is why keyboard input must be delivered to
|
|
527
|
+
* *this* side rather than to the worker that is blocked waiting for it.
|
|
528
|
+
*/
|
|
529
|
+
|
|
530
|
+
/** Everything one guest process is allowed to see. */
|
|
531
|
+
interface HostAbiProcess {
|
|
532
|
+
readonly pid: number;
|
|
533
|
+
readonly ppid: number;
|
|
534
|
+
readonly generation: number;
|
|
535
|
+
readonly vfs: Vfs;
|
|
536
|
+
readonly cred: Cred;
|
|
537
|
+
readonly table: DescriptorTable;
|
|
538
|
+
readonly env: Record<string, string>;
|
|
539
|
+
cwd: string;
|
|
540
|
+
/** Aborts when the process is killed; wakes anything parked in a call. */
|
|
541
|
+
readonly signal: AbortSignal;
|
|
542
|
+
}
|
|
543
|
+
declare function createHostAbiServer(proc: HostAbiProcess): (frame: Uint8Array) => Promise<Uint8Array>;
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* The guest side of the host ABI, as the compiled code sees it.
|
|
547
|
+
*
|
|
548
|
+
* Compiled programs reach this through `sbx_host_call` in
|
|
549
|
+
* `python-runtime/native/js/library_sbx.js`, which copies a frame out of the
|
|
550
|
+
* module's memory, calls {@link HostAbiClient.callRaw}, and copies the answer
|
|
551
|
+
* back. The typed methods below are for the JavaScript side of the worker —
|
|
552
|
+
* loaders, the probe harness, and tests — which need the same operations
|
|
553
|
+
* without going through Wasm memory.
|
|
554
|
+
*/
|
|
555
|
+
|
|
556
|
+
declare class HostAbiError extends Error {
|
|
557
|
+
errno: number;
|
|
558
|
+
code: string;
|
|
559
|
+
constructor(errno: number, op: number);
|
|
560
|
+
}
|
|
561
|
+
interface HostAbiResult {
|
|
562
|
+
status: number;
|
|
563
|
+
payload: Uint8Array;
|
|
564
|
+
}
|
|
565
|
+
/**
|
|
566
|
+
* One process's connection to the kernel.
|
|
567
|
+
*
|
|
568
|
+
* `generation` is stamped into every frame and checked on the way back, so a
|
|
569
|
+
* completion belonging to a previous incarnation of this PID is rejected rather
|
|
570
|
+
* than applied to the wrong descriptor table.
|
|
571
|
+
*/
|
|
572
|
+
declare class HostAbiClient {
|
|
573
|
+
private transport;
|
|
574
|
+
private generation;
|
|
575
|
+
private nextRequestId;
|
|
576
|
+
constructor(transport: HostCallClient, generation: number);
|
|
577
|
+
/** Send one frame, blocking. Returns the status and payload verbatim. */
|
|
578
|
+
callRaw(op: number, payload: Uint8Array): HostAbiResult;
|
|
579
|
+
/** As {@link callRaw}, but a negative status becomes an exception. */
|
|
580
|
+
private call;
|
|
581
|
+
handshake(): {
|
|
582
|
+
version: number;
|
|
583
|
+
capabilities: Record<string, boolean>;
|
|
584
|
+
};
|
|
585
|
+
open(path: string, flags: number, mode?: number): number;
|
|
586
|
+
close(fd: number): void;
|
|
587
|
+
read(fd: number, length: number): Uint8Array;
|
|
588
|
+
write(fd: number, data: Uint8Array): number;
|
|
589
|
+
/** Write every byte, looping over short writes the way a guest's libc must. */
|
|
590
|
+
writeAll(fd: number, data: Uint8Array): void;
|
|
591
|
+
pread(fd: number, length: number, offset: number): Uint8Array;
|
|
592
|
+
pwrite(fd: number, data: Uint8Array, offset: number): number;
|
|
593
|
+
seek(fd: number, offset: number, whence: number): number;
|
|
594
|
+
fstat(fd: number): HostStat;
|
|
595
|
+
stat(path: string, followLinks?: boolean): HostStat;
|
|
596
|
+
ftruncate(fd: number, length: number): void;
|
|
597
|
+
rename(from: string, to: string): void;
|
|
598
|
+
unlink(path: string, removeDirectory?: boolean): void;
|
|
599
|
+
mkdir(path: string, mode?: number): void;
|
|
600
|
+
readdir(fd: number, bufferSize?: number): string[];
|
|
601
|
+
dup(fd: number, from?: number): number;
|
|
602
|
+
dup2(fd: number, target: number): number;
|
|
603
|
+
getFlags(fd: number): {
|
|
604
|
+
flags: number;
|
|
605
|
+
cloexec: boolean;
|
|
606
|
+
};
|
|
607
|
+
setFlags(fd: number, flags: number, cloexec: boolean): void;
|
|
608
|
+
pipe(flags?: number): [number, number];
|
|
609
|
+
poll(entries: {
|
|
610
|
+
fd: number;
|
|
611
|
+
events: number;
|
|
612
|
+
}[], timeoutMs: number): {
|
|
613
|
+
fd: number;
|
|
614
|
+
revents: number;
|
|
615
|
+
}[];
|
|
616
|
+
clockGettime(monotonic: boolean): {
|
|
617
|
+
seconds: number;
|
|
618
|
+
nanos: number;
|
|
619
|
+
};
|
|
620
|
+
sleep(nanos: number): void;
|
|
621
|
+
identity(): {
|
|
622
|
+
pid: number;
|
|
623
|
+
ppid: number;
|
|
624
|
+
uid: number;
|
|
625
|
+
gid: number;
|
|
626
|
+
umask: number;
|
|
627
|
+
};
|
|
628
|
+
getcwd(): string;
|
|
629
|
+
chdir(path: string): void;
|
|
630
|
+
environ(): Record<string, string>;
|
|
631
|
+
getrandom(length: number): Uint8Array;
|
|
632
|
+
}
|
|
633
|
+
interface HostStat {
|
|
634
|
+
ino: number;
|
|
635
|
+
mode: number;
|
|
636
|
+
size: number;
|
|
637
|
+
uid: number;
|
|
638
|
+
gid: number;
|
|
639
|
+
nlink: number;
|
|
640
|
+
atimeNs: number;
|
|
641
|
+
mtimeNs: number;
|
|
642
|
+
ctimeNs: number;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
export { CAPABILITIES, type Capability, Cred, type DescriptionStat, DescriptorTable, DirectoryDescription, ERRNO_NAMES, Errno, type ErrnoName, FileDescription, FileService, HostAbiClient, HostAbiError, type HostAbiProcess, HostCallClient, HostCallServer, type HostStat, type HostTransportBuffers, HostTransportError, Inode, OP_NAMES, O_APPEND, O_CLOEXEC, O_CREAT, O_DIRECTORY, O_EXCL, O_NONBLOCK, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY, Op, type OpCode, type OpenFileDescription, PipeReadEnd, PipeWriteEnd, PosixError, ProtocolError, Reader, type RequestHeader, type ResponseFrame, SBX_HOST_ABI_VERSION, SBX_REQUEST_HEADER_BYTES, SBX_RESPONSE_HEADER_BYTES, SEEK_CUR, SEEK_END, SEEK_SET, StreamDescription, Vfs, Writer, accessMode, createHostAbiServer, createHostTransportBuffers, createPipe, decodeRequest, decodeResponse, encodeRequest, encodeResponse, failure, toPosixError };
|