sandboxedjs 0.1.53 → 0.1.55

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.
@@ -1,6 +1,229 @@
1
- import { V as Vfs, C as Cred } from './vfs-DzEcPbMY.js';
2
- export { l as ROOT_CRED, u as makeCred } from './vfs-DzEcPbMY.js';
3
- export { M as MemoryVolume } from './memory-volume-CTOXNJ6n.js';
1
+ import { V as Vfs, C as Cred, a as VirtualTcpNetwork } from './contracts-CVgctitO.js';
2
+ export { m as ROOT_CRED, v as makeCred } from './contracts-CVgctitO.js';
3
+ export { M as MemoryVolume } from './memory-volume-CWuWScIs.js';
4
+
5
+ /**
6
+ * Open-file descriptions: the thing a descriptor points *at*.
7
+ *
8
+ * POSIX has three levels and collapsing any two of them produces bugs that look
9
+ * like something else entirely:
10
+ *
11
+ * - a **pathname** is a directory entry, and may be renamed or removed;
12
+ * - an **inode** is the file's identity and content, and outlives its names;
13
+ * - an **open-file description** holds the offset and the status flags.
14
+ *
15
+ * `dup()` makes two descriptors share one description — so they share an offset.
16
+ * Two separate `open()` calls on the same path make two descriptions, so their
17
+ * offsets are independent. A file stays readable through an open description
18
+ * after its last name is unlinked. None of that is expressible if a descriptor
19
+ * is just a path and a number, which is why this layer exists rather than the
20
+ * path-based {@link Vfs} calls being used directly.
21
+ *
22
+ * The identity used here is the volume's inode number, so a rename moves a name
23
+ * without disturbing anything already open.
24
+ */
25
+
26
+ /** A failure carrying the errno the guest's libc should see. */
27
+ declare class PosixError extends Error {
28
+ readonly errno: number;
29
+ constructor(errno: number, message?: string);
30
+ }
31
+ declare const O_RDONLY = 0;
32
+ declare const O_WRONLY = 1;
33
+ declare const O_RDWR = 2;
34
+ declare const O_CREAT = 64;
35
+ declare const O_EXCL = 128;
36
+ declare const O_TRUNC = 512;
37
+ declare const O_APPEND = 1024;
38
+ declare const O_NONBLOCK = 2048;
39
+ declare const O_DIRECTORY = 65536;
40
+ declare const O_CLOEXEC = 524288;
41
+ /** Access mode alone, with the flag bits masked off. */
42
+ declare function accessMode(flags: number): number;
43
+ interface DescriptionStat {
44
+ ino: number;
45
+ mode: number;
46
+ size: number;
47
+ uid: number;
48
+ gid: number;
49
+ nlink: number;
50
+ atimeMs: number;
51
+ mtimeMs: number;
52
+ ctimeMs: number;
53
+ }
54
+ /**
55
+ * What every kind of open thing can do.
56
+ *
57
+ * `read` and `write` are permitted to move fewer bytes than asked for: that is
58
+ * ordinary POSIX behaviour, and a guest that assumes otherwise is already
59
+ * broken on Linux.
60
+ */
61
+ interface OpenFileDescription {
62
+ readonly kind: "file" | "dir" | "pipe" | "stream" | "socket";
63
+ flags: number;
64
+ read(length: number): Uint8Array;
65
+ write(data: Uint8Array): number;
66
+ pread?(length: number, offset: number): Uint8Array;
67
+ pwrite?(data: Uint8Array, offset: number): number;
68
+ seek?(offset: number, whence: number): number;
69
+ stat(): DescriptionStat;
70
+ truncate?(length: number): void;
71
+ /** Ready to read now, or at end of input (which is also "ready"). */
72
+ readable(): boolean;
73
+ /** Ready to accept at least one byte. */
74
+ writable(): boolean;
75
+ /** Resolves when readiness may have changed; used only to park a poll. */
76
+ whenReady(): Promise<void>;
77
+ /** Last reference dropped. */
78
+ close(): void;
79
+ }
80
+ declare const SEEK_SET = 0;
81
+ declare const SEEK_CUR = 1;
82
+ declare const SEEK_END = 2;
83
+ /**
84
+ * The bytes behind an open regular file.
85
+ *
86
+ * Content lives in the volume while a name still points at it, and moves into
87
+ * `detached` when the last name goes away with the file still open. That is the
88
+ * only way to honour "an unlinked file stays readable until the last close" on
89
+ * top of a path-addressed volume.
90
+ *
91
+ * A name removed by something that does not go through this service — the
92
+ * shell, or the Node side — cannot be intercepted, and the description will
93
+ * then fail with ENOENT rather than reading stale bytes. Documented in
94
+ * docs/python/abi.md; correctness holds for everything using the host ABI.
95
+ */
96
+ declare class Inode {
97
+ readonly ino: number;
98
+ path: string;
99
+ private readonly vfs;
100
+ private readonly cred;
101
+ detached: Uint8Array | null;
102
+ refs: number;
103
+ constructor(ino: number, path: string, vfs: Vfs, cred: Cred);
104
+ /** Read the whole file, wherever it currently lives. */
105
+ contents(): Uint8Array;
106
+ replace(data: Uint8Array): void;
107
+ /** Called when the last name is about to be removed. */
108
+ detach(): void;
109
+ size(): number;
110
+ stat(): DescriptionStat;
111
+ }
112
+ /** One `open()`: an offset and status flags over an {@link Inode}. */
113
+ declare class FileDescription implements OpenFileDescription {
114
+ readonly inode: Inode;
115
+ flags: number;
116
+ readonly kind = "file";
117
+ offset: number;
118
+ constructor(inode: Inode, flags: number);
119
+ read(length: number): Uint8Array;
120
+ pread(length: number, offset: number): Uint8Array;
121
+ write(data: Uint8Array): number;
122
+ pwrite(data: Uint8Array, offset: number): number;
123
+ private writeAt;
124
+ seek(offset: number, whence: number): number;
125
+ truncate(length: number): void;
126
+ stat(): DescriptionStat;
127
+ readable(): boolean;
128
+ writable(): boolean;
129
+ whenReady(): Promise<void>;
130
+ close(): void;
131
+ }
132
+ /** An open directory: `getdents` reads from a snapshot at the description's offset. */
133
+ declare class DirectoryDescription implements OpenFileDescription {
134
+ readonly path: string;
135
+ flags: number;
136
+ private readonly vfs;
137
+ private readonly cred;
138
+ readonly kind = "dir";
139
+ private entries;
140
+ private index;
141
+ constructor(path: string, flags: number, vfs: Vfs, cred: Cred);
142
+ /** Entry names, NUL-terminated, as many as fit in `length`. */
143
+ read(length: number): Uint8Array;
144
+ write(): number;
145
+ seek(offset: number, whence: number): number;
146
+ stat(): DescriptionStat;
147
+ readable(): boolean;
148
+ writable(): boolean;
149
+ whenReady(): Promise<void>;
150
+ close(): void;
151
+ }
152
+ /** The shared buffer between a pipe's two ends. */
153
+ declare class PipeBuffer {
154
+ private chunks;
155
+ private queued;
156
+ readers: number;
157
+ writers: number;
158
+ private waiters;
159
+ get available(): number;
160
+ get space(): number;
161
+ push(data: Uint8Array): void;
162
+ take(length: number): Uint8Array;
163
+ /** Anything that may have changed readiness for either end. */
164
+ wake(): void;
165
+ whenReady(): Promise<void>;
166
+ }
167
+ declare class PipeReadEnd implements OpenFileDescription {
168
+ private readonly buffer;
169
+ flags: number;
170
+ readonly kind = "pipe";
171
+ constructor(buffer: PipeBuffer, flags: number);
172
+ read(length: number): Uint8Array;
173
+ write(): number;
174
+ stat(): DescriptionStat;
175
+ readable(): boolean;
176
+ writable(): boolean;
177
+ whenReady(): Promise<void>;
178
+ close(): void;
179
+ }
180
+ declare class PipeWriteEnd implements OpenFileDescription {
181
+ private readonly buffer;
182
+ flags: number;
183
+ readonly kind = "pipe";
184
+ constructor(buffer: PipeBuffer, flags: number);
185
+ read(): Uint8Array;
186
+ write(data: Uint8Array): number;
187
+ stat(): DescriptionStat;
188
+ readable(): boolean;
189
+ writable(): boolean;
190
+ whenReady(): Promise<void>;
191
+ close(): void;
192
+ }
193
+ declare function createPipe(flags?: number): [PipeReadEnd, PipeWriteEnd];
194
+ /**
195
+ * A process's standard streams.
196
+ *
197
+ * Bytes, not text: the terminal boundary is where multi-byte characters get cut
198
+ * in half, so nothing here decodes. Input arrives from the host asynchronously
199
+ * and is queued; a blocked reader parks on {@link whenReady} rather than
200
+ * spinning.
201
+ */
202
+ declare class StreamDescription implements OpenFileDescription {
203
+ flags: number;
204
+ private readonly sink;
205
+ readonly isTty: boolean;
206
+ readonly kind = "stream";
207
+ private queue;
208
+ private queued;
209
+ private ended;
210
+ private waiters;
211
+ constructor(flags: number, sink: ((data: Uint8Array) => void) | null, isTty?: boolean);
212
+ /** Host side: give the guest more input. */
213
+ push(data: Uint8Array): void;
214
+ /** Host side: no more input will arrive. */
215
+ end(): void;
216
+ read(length: number): Uint8Array;
217
+ write(data: Uint8Array): number;
218
+ stat(): DescriptionStat;
219
+ readable(): boolean;
220
+ writable(): boolean;
221
+ whenReady(): Promise<void>;
222
+ close(): void;
223
+ private wake;
224
+ }
225
+ /** Translate a volume error into the errno a guest expects. */
226
+ declare function toPosixError(error: unknown): PosixError;
4
227
 
5
228
  /** Protocol version carried in every frame. */
6
229
  declare const SBX_HOST_ABI_VERSION = 1;
@@ -39,6 +262,19 @@ declare const Op: {
39
262
  readonly chdir: 1282;
40
263
  readonly environ: 1283;
41
264
  readonly getrandom: 1536;
265
+ readonly socket: 1792;
266
+ readonly bind: 1793;
267
+ readonly listen: 1794;
268
+ readonly accept: 1795;
269
+ readonly connect: 1796;
270
+ readonly send: 1797;
271
+ readonly recv: 1798;
272
+ readonly shutdown: 1799;
273
+ readonly getsockname: 1800;
274
+ readonly getpeername: 1801;
275
+ readonly setsockopt: 1802;
276
+ readonly getsockopt: 1803;
277
+ readonly socket_close: 1804;
42
278
  };
43
279
  type OpCode = (typeof Op)[keyof typeof Op];
44
280
  /** Canonical (Linux/musl) errno values. A negative status is `-Errno.X`. */
@@ -77,6 +313,15 @@ declare const Errno: {
77
313
  readonly ENOTEMPTY: 39;
78
314
  readonly ELOOP: 40;
79
315
  readonly ENODATA: 61;
316
+ readonly ENOTSOCK: 88;
317
+ readonly EAFNOSUPPORT: 97;
318
+ readonly EADDRINUSE: 98;
319
+ readonly EADDRNOTAVAIL: 99;
320
+ readonly ENETUNREACH: 101;
321
+ readonly ECONNRESET: 104;
322
+ readonly EISCONN: 106;
323
+ readonly ENOTCONN: 107;
324
+ readonly ECONNREFUSED: 111;
80
325
  readonly EPROTO: 71;
81
326
  readonly EOVERFLOW: 75;
82
327
  readonly ETIMEDOUT: 110;
@@ -226,229 +471,6 @@ declare class HostCallServer {
226
471
  private publish;
227
472
  }
228
473
 
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
474
  /**
453
475
  * Per-process descriptor tables, and the path operations that have to know
454
476
  * about them.
@@ -539,6 +561,7 @@ interface HostAbiProcess {
539
561
  cwd: string;
540
562
  /** Aborts when the process is killed; wakes anything parked in a call. */
541
563
  readonly signal: AbortSignal;
564
+ readonly sockets?: VirtualTcpNetwork;
542
565
  }
543
566
  declare function createHostAbiServer(proc: HostAbiProcess): (frame: Uint8Array) => Promise<Uint8Array>;
544
567
 
@@ -629,6 +652,22 @@ declare class HostAbiClient {
629
652
  chdir(path: string): void;
630
653
  environ(): Record<string, string>;
631
654
  getrandom(length: number): Uint8Array;
655
+ socket(family: number, type: number, protocol?: number): number;
656
+ bind(fd: number, address: string, port: number): void;
657
+ listen(fd: number, backlog?: number): void;
658
+ accept(fd: number): {
659
+ fd: number;
660
+ address: string;
661
+ port: number;
662
+ };
663
+ connect(fd: number, address: string, port: number): void;
664
+ send(fd: number, data: Uint8Array): number;
665
+ recv(fd: number, length: number): Uint8Array;
666
+ shutdown(fd: number, how: number): void;
667
+ socketName(fd: number, peer?: boolean): {
668
+ address: string;
669
+ port: number;
670
+ };
632
671
  }
633
672
  interface HostStat {
634
673
  ino: number;