@cloudflare/sandbox 1.0.0-rc.1 → 1.0.0-rc.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 CHANGED
@@ -10,8 +10,8 @@ Run untrusted or generated code in a Linux sandbox that belongs to one user, tas
10
10
  A sandbox is a Durable Object and the [Container](https://developers.cloudflare.com/containers/) it starts. The Durable Object starts the instance and runs commands with the Container API on `this.ctx.container`. `@cloudflare/sandbox` adds three things that API does not have:
11
11
 
12
12
  - [`Files`](https://developers.cloudflare.com/sandbox/reference/files/) streams files in and out of the running instance and reports Linux errors such as `ENOENT`.
13
- - [`S3Mounts`](https://developers.cloudflare.com/sandbox/reference/s3-mounts/) mounts an S3-compatible bucket at a path. Your Worker signs each storage request, so the credentials never enter the sandbox.
14
- - [`DirectoryBackups`](https://developers.cloudflare.com/sandbox/reference/directory-backups/) saves a directory to R2 and restores it into any Container, including one on a newer image. The Container reaches only the one object each operation needs.
13
+ - [`S3Mount`](https://developers.cloudflare.com/sandbox/reference/s3-mounts/) mounts an S3-compatible bucket at a path. Your Worker signs each storage request, so the credentials never enter the sandbox.
14
+ - [`DirectoryBackup`](https://developers.cloudflare.com/sandbox/reference/directory-backups/) saves a directory to R2 and restores it into any Container, including one on a newer image. The Container reaches only the one object each operation needs.
15
15
 
16
16
  **[Read the documentation](https://developers.cloudflare.com/sandbox/)**
17
17
 
@@ -82,14 +82,14 @@ Version 0.x provided a `Sandbox` class that owned the Container and ran commands
82
82
 
83
83
  ## Repository
84
84
 
85
- | Path | Contents |
86
- | ---------------------------------------------- | ------------------------------------------------------------------------------------- |
87
- | [`packages/sandbox`](packages/sandbox) | The `@cloudflare/sandbox` package |
88
- | [`crates/sandbox-tools`](crates/sandbox-tools) | `sandbox-shim`, the Linux helper that `Files`, `S3Mounts`, and `DirectoryBackups` run |
89
- | [`images/sandbox-tools`](images/sandbox-tools) | The `cloudflare/sandbox` image that ships `sandbox-shim` |
90
- | [`examples`](examples) | Deployable Workers, one per goal |
85
+ | Path | Contents |
86
+ | ---------------------------------------------- | ----------------------------------------------------------------------------------- |
87
+ | [`packages/sandbox`](packages/sandbox) | The `@cloudflare/sandbox` package |
88
+ | [`crates/sandbox-tools`](crates/sandbox-tools) | `sandbox-shim`, the Linux helper that `Files`, `S3Mount`, and `DirectoryBackup` run |
89
+ | [`images/sandbox-tools`](images/sandbox-tools) | The `cloudflare/sandbox` image that ships `sandbox-shim` |
90
+ | [`examples`](examples) | Deployable Workers, one per goal |
91
91
 
92
- To learn how these parts fit together, read [Architecture](docs/architecture.md). The package and `sandbox-shim` exchange frames described in [Shim protocol](docs/shim-protocol.md). [S3 mounts design](docs/s3-mounts-design.md) explains `S3Mounts` and `S3Gateway`. To add an example, read [Examples](docs/examples.md).
92
+ To learn how these parts fit together, read [Architecture](docs/architecture.md). The package and `sandbox-shim` exchange frames described in [Shim protocol](docs/shim-protocol.md). [S3 mounts design](docs/s3-mount-design.md) explains `S3Mount` and `S3Gateway`. To add an example, read [Examples](docs/examples.md).
93
93
 
94
94
  Build and test with Node.js and Docker:
95
95
 
package/dist/index.d.mts CHANGED
@@ -1,13 +1,13 @@
1
1
  import { WorkerEntrypoint } from "cloudflare:workers";
2
2
  import "zod/mini";
3
- //#region src/directory-backups/contracts.d.ts
3
+ //#region src/directory-backup/contracts.d.ts
4
4
  /** The only archive format this version writes and reads. */
5
5
  declare const DIRECTORY_BACKUP_FORMAT = "tar+zstd/1";
6
6
  /**
7
7
  * A saved directory. A plain, serializable object: store it wherever the application keeps
8
8
  * state. It only works with the same R2 binding and key prefix that created it.
9
9
  */
10
- interface DirectoryBackup {
10
+ interface DirectoryBackupRecord {
11
11
  /** UUID. The object key is `<prefix><id>.tar.zst`. */
12
12
  readonly id: string;
13
13
  /** The directory the backup came from, and the default restore target. */
@@ -93,10 +93,10 @@ interface DirectoryBackupGatewayBinding {
93
93
  }): Fetcher & DirectoryBackupGatewayControl;
94
94
  }
95
95
  //#endregion
96
- //#region src/directory-backups/directory-backup-gateway.d.ts
96
+ //#region src/directory-backup/directory-backup-gateway.d.ts
97
97
  /**
98
98
  * Moves directory backups between a container and an R2 bucket binding. Export it from the
99
- * Worker and pass `ctx.exports.DirectoryBackupGateway` to `DirectoryBackups`.
99
+ * Worker and pass `ctx.exports.DirectoryBackupGateway` to `DirectoryBackup`.
100
100
  *
101
101
  * The container reaches `fetch()` through the outbound intercept and can only use the grant
102
102
  * its current operation holds. The other methods are for the Durable Object alone.
@@ -110,7 +110,7 @@ declare class DirectoryBackupGateway extends WorkerEntrypoint<object, DirectoryB
110
110
  deleteObject(): Promise<void>;
111
111
  }
112
112
  //#endregion
113
- //#region src/directory-backups/directory-backups.d.ts
113
+ //#region src/directory-backup/directory-backup.d.ts
114
114
  type DirectoryBackupContainer = Pick<Container, "exec" | "interceptOutboundHttp">;
115
115
  /**
116
116
  * Saves one directory from the running Container to an R2 bucket, and restores it as
@@ -121,7 +121,7 @@ type DirectoryBackupContainer = Pick<Container, "exec" | "interceptOutboundHttp"
121
121
  * starts, retries, or times out anything. The application stores the returned records and
122
122
  * decides when to delete them.
123
123
  */
124
- declare class DirectoryBackups {
124
+ declare class DirectoryBackup {
125
125
  #private;
126
126
  constructor(container: DirectoryBackupContainer, gateway: DirectoryBackupGatewayBinding, storage: DirectoryBackupStorage);
127
127
  /**
@@ -142,7 +142,7 @@ declare class DirectoryBackups {
142
142
  * @throws {SandboxBackupError} `BACKUP_TRANSFER` when a part upload fails, or
143
143
  * `BACKUP_INTEGRITY` when R2 stored a different size than was uploaded.
144
144
  */
145
- backup(options: DirectoryBackupOptions): Promise<DirectoryBackup>;
145
+ backup(options: DirectoryBackupOptions): Promise<DirectoryBackupRecord>;
146
146
  /**
147
147
  * Replaces `options.dir`, or the record's `dir`, with the backup's contents. The directory is
148
148
  * extracted beside the target and swapped in only after the download is verified, so a failed
@@ -154,12 +154,12 @@ declare class DirectoryBackups {
154
154
  * example `EXDEV`), or the disk fills (`ENOSPC`).
155
155
  * @throws {SandboxBackupError} `BACKUP_NOT_FOUND`, `BACKUP_INTEGRITY`, or `BACKUP_TRANSFER`.
156
156
  */
157
- restore(backup: DirectoryBackup, options?: DirectoryRestoreOptions): Promise<void>;
157
+ restore(backup: DirectoryBackupRecord, options?: DirectoryRestoreOptions): Promise<void>;
158
158
  /**
159
159
  * Deletes the backup's object. Needs no running Container. Deleting an object that is already
160
160
  * gone succeeds. A restore reading it at the same time fails, and nothing is swapped.
161
161
  */
162
- delete(backup: DirectoryBackup, options?: DirectoryBackupDeleteOptions): Promise<void>;
162
+ delete(backup: DirectoryBackupRecord, options?: DirectoryBackupDeleteOptions): Promise<void>;
163
163
  }
164
164
  //#endregion
165
165
  //#region src/files/content.d.ts
@@ -321,7 +321,7 @@ declare class Files {
321
321
  remove(path: string, options?: RemoveOptions): Promise<void>;
322
322
  }
323
323
  //#endregion
324
- //#region src/s3-mounts/contracts.d.ts
324
+ //#region src/s3-mount/contracts.d.ts
325
325
  type S3MountAccess = "read-only" | "read-write";
326
326
  type S3MountCredentials = {
327
327
  readonly type: "static";
@@ -448,12 +448,12 @@ interface S3GatewayBinding {
448
448
  }): Fetcher;
449
449
  }
450
450
  //#endregion
451
- //#region src/s3-mounts/s3-gateway.d.ts
451
+ //#region src/s3-mount/s3-gateway.d.ts
452
452
  declare class S3Gateway extends WorkerEntrypoint<object, S3GatewayProps> {
453
453
  fetch(request: Request): Promise<Response>;
454
454
  }
455
455
  //#endregion
456
- //#region src/s3-mounts/s3-mounts.d.ts
456
+ //#region src/s3-mount/s3-mount.d.ts
457
457
  type S3MountContainer = Pick<Container, "exec" | "interceptOutboundHttp">;
458
458
  /**
459
459
  * Attaches an S3-compatible bucket or prefix to a running Container.
@@ -467,7 +467,7 @@ type S3MountContainer = Pick<Container, "exec" | "interceptOutboundHttp">;
467
467
  * monitors, or replaces it. The mounted path is not a POSIX filesystem. Do not
468
468
  * use it for locking or atomic rename.
469
469
  */
470
- declare class S3Mounts {
470
+ declare class S3Mount {
471
471
  #private;
472
472
  constructor(container: S3MountContainer, gateway: S3GatewayBinding);
473
473
  /**
@@ -554,4 +554,4 @@ declare const SandboxBackupError: {
554
554
  is(cause: unknown): cause is SandboxBackupError;
555
555
  };
556
556
  //#endregion
557
- export { type DirectoryBackup, type DirectoryBackupDeleteOptions, DirectoryBackupGateway, type DirectoryBackupGatewayBinding, type DirectoryBackupOperation, type DirectoryBackupOptions, type DirectoryBackupStorage, DirectoryBackups, type DirectoryRestoreOptions, type FileContent, type FileOperationOptions, Files, type MkdirOptions, type RemoveOptions, S3Gateway, type S3GatewayBinding, type S3MountInspection, type S3MountOperation, type S3MountOperationOptions, type S3MountRequest, S3Mounts, SandboxBackupError, type SandboxBackupErrorCode, type SandboxDirectoryEntry, SandboxFileError, type SandboxFileStat, type SandboxFileType, SandboxProtocolError, SandboxS3MountError, type SandboxS3MountErrorCode };
557
+ export { DirectoryBackup, type DirectoryBackupDeleteOptions, DirectoryBackupGateway, type DirectoryBackupGatewayBinding, type DirectoryBackupOperation, type DirectoryBackupOptions, type DirectoryBackupRecord, type DirectoryBackupStorage, type DirectoryRestoreOptions, type FileContent, type FileOperationOptions, Files, type MkdirOptions, type RemoveOptions, S3Gateway, type S3GatewayBinding, S3Mount, type S3MountInspection, type S3MountOperation, type S3MountOperationOptions, type S3MountRequest, SandboxBackupError, type SandboxBackupErrorCode, type SandboxDirectoryEntry, SandboxFileError, type SandboxFileStat, type SandboxFileType, SandboxProtocolError, SandboxS3MountError, type SandboxS3MountErrorCode };
package/dist/index.mjs CHANGED
@@ -2,7 +2,7 @@ import { WorkerEntrypoint } from "cloudflare:workers";
2
2
  import * as z from "zod/mini";
3
3
  import { constants } from "node:os";
4
4
  import { AwsClient } from "aws4fetch";
5
- //#region src/directory-backups/gateway.ts
5
+ //#region src/directory-backup/gateway.ts
6
6
  const PART_PATH = /^\/parts\/([1-9][0-9]{0,8})$/;
7
7
  const RANGE = /^bytes=([0-9]{1,15})-([0-9]{1,15})$/;
8
8
  const MAX_DETAIL_LENGTH = 1024;
@@ -61,10 +61,10 @@ function text(status, detail) {
61
61
  return new Response(detail.slice(0, MAX_DETAIL_LENGTH), { status });
62
62
  }
63
63
  //#endregion
64
- //#region src/directory-backups/directory-backup-gateway.ts
64
+ //#region src/directory-backup/directory-backup-gateway.ts
65
65
  /**
66
66
  * Moves directory backups between a container and an R2 bucket binding. Export it from the
67
- * Worker and pass `ctx.exports.DirectoryBackupGateway` to `DirectoryBackups`.
67
+ * Worker and pass `ctx.exports.DirectoryBackupGateway` to `DirectoryBackup`.
68
68
  *
69
69
  * The container reaches `fetch()` through the outbound intercept and can only use the grant
70
70
  * its current operation holds. The other methods are for the Durable Object alone.
@@ -268,7 +268,7 @@ function validateOptions(options, rules) {
268
268
  }
269
269
  }
270
270
  //#endregion
271
- //#region src/directory-backups/contracts.ts
271
+ //#region src/directory-backup/contracts.ts
272
272
  /** The only archive format this version writes and reads. */
273
273
  const DIRECTORY_BACKUP_FORMAT = "tar+zstd/1";
274
274
  //#endregion
@@ -479,7 +479,7 @@ function validateHeader(header) {
479
479
  if (header[4] !== PROTOCOL_VERSION) throw protocolError(`sandbox-shim protocol ${header[4]} is not supported`);
480
480
  }
481
481
  //#endregion
482
- //#region src/directory-backups/protocol.ts
482
+ //#region src/directory-backup/protocol.ts
483
483
  /** The one intercepted host every operation's grant is registered on. */
484
484
  const GATEWAY_HOST = "backups.sandbox.internal";
485
485
  const ACKNOWLEDGEMENT = new Uint8Array([1]);
@@ -578,7 +578,7 @@ function closeStdin(input) {
578
578
  input.close().catch(() => void 0);
579
579
  }
580
580
  //#endregion
581
- //#region src/directory-backups/directory-backups.ts
581
+ //#region src/directory-backup/directory-backup.ts
582
582
  const absolutePath = z.string().check(z.startsWith("/"), z.refine((value) => !value.includes("\0")));
583
583
  const SIGNAL = {
584
584
  schema: z.instanceof(AbortSignal),
@@ -637,7 +637,7 @@ const restoreDoneSchema = z.strictObject({ kind: z.literal("done") });
637
637
  * starts, retries, or times out anything. The application stores the returned records and
638
638
  * decides when to delete them.
639
639
  */
640
- var DirectoryBackups = class {
640
+ var DirectoryBackup = class {
641
641
  #container;
642
642
  #gateway;
643
643
  #binding;
@@ -1446,7 +1446,7 @@ async function readBoundedBody(body, limit, cancelReason) {
1446
1446
  };
1447
1447
  }
1448
1448
  //#endregion
1449
- //#region src/s3-mounts/credentials.ts
1449
+ //#region src/s3-mount/credentials.ts
1450
1450
  const CREDENTIAL_PROVIDER_URL = "https://credentials.sandbox.internal/";
1451
1451
  const MAX_CREDENTIAL_RESPONSE_BYTES = 16384;
1452
1452
  const decoder = new TextDecoder("utf-8", { fatal: true });
@@ -1498,12 +1498,12 @@ async function readCredentialResponse(body) {
1498
1498
  }
1499
1499
  }
1500
1500
  //#endregion
1501
- //#region src/s3-mounts/route.ts
1501
+ //#region src/s3-mount/route.ts
1502
1502
  function routeHost(routeId) {
1503
1503
  return `s3-${routeId}.sandbox.internal`;
1504
1504
  }
1505
1505
  //#endregion
1506
- //#region src/s3-mounts/gateway-policy.ts
1506
+ //#region src/s3-mount/gateway-policy.ts
1507
1507
  const LIST_V1_PARAMETERS = /* @__PURE__ */ new Set([
1508
1508
  "delimiter",
1509
1509
  "encoding-type",
@@ -1738,7 +1738,7 @@ function usesAwsChunkedPayload(headers) {
1738
1738
  return (headers.get("content-encoding") ?? "").split(",").some((encoding) => encoding.trim().toLowerCase() === "aws-chunked");
1739
1739
  }
1740
1740
  //#endregion
1741
- //#region src/s3-mounts/gateway.ts
1741
+ //#region src/s3-mount/gateway.ts
1742
1742
  const INSPECTION_VERSION_HEADER = "x-sandbox-s3-gateway-version";
1743
1743
  const INSPECTION_RESULT_HEADER = "x-sandbox-s3-inspection-result";
1744
1744
  const INSPECTION_DETAIL_HEADER = "x-sandbox-s3-inspection-detail";
@@ -1849,14 +1849,14 @@ function inspectionResponse(result, detail, status) {
1849
1849
  });
1850
1850
  }
1851
1851
  //#endregion
1852
- //#region src/s3-mounts/s3-gateway.ts
1852
+ //#region src/s3-mount/s3-gateway.ts
1853
1853
  var S3Gateway = class extends WorkerEntrypoint {
1854
1854
  fetch(request) {
1855
1855
  return handleS3GatewayRequest(request, this.ctx.props);
1856
1856
  }
1857
1857
  };
1858
1858
  //#endregion
1859
- //#region src/s3-mounts/request.ts
1859
+ //#region src/s3-mount/request.ts
1860
1860
  const objectSchema = z.object({});
1861
1861
  const stringSchema = z.string();
1862
1862
  const fetcherSchema = z.object({ fetch: z.function() });
@@ -2024,7 +2024,7 @@ function requiredString(value, name) {
2024
2024
  return parsed.data;
2025
2025
  }
2026
2026
  //#endregion
2027
- //#region src/s3-mounts/protocol.ts
2027
+ //#region src/s3-mount/protocol.ts
2028
2028
  const ROUTE_READY = new Uint8Array([1]);
2029
2029
  const routeIdSchema = z.string().check(z.regex(/^[A-Za-z0-9](?:[A-Za-z0-9-]{0,58}[A-Za-z0-9])?$/));
2030
2030
  const keyPrefixSchema = z.optional(z.string().check(z.refine((value) => value.endsWith("/"))));
@@ -2324,7 +2324,7 @@ function parseGatewayState(state) {
2324
2324
  }
2325
2325
  }
2326
2326
  //#endregion
2327
- //#region src/s3-mounts/reconcile.ts
2327
+ //#region src/s3-mount/reconcile.ts
2328
2328
  function assembleInspection(mountPath, evidence) {
2329
2329
  const state = evidence.state;
2330
2330
  switch (state.kind) {
@@ -2367,7 +2367,7 @@ function gatewayFor(evidence) {
2367
2367
  throw protocolError("sandbox-shim omitted managed mount gateway evidence");
2368
2368
  }
2369
2369
  //#endregion
2370
- //#region src/s3-mounts/s3-mounts.ts
2370
+ //#region src/s3-mount/s3-mount.ts
2371
2371
  /**
2372
2372
  * Attaches an S3-compatible bucket or prefix to a running Container.
2373
2373
  *
@@ -2380,7 +2380,7 @@ function gatewayFor(evidence) {
2380
2380
  * monitors, or replaces it. The mounted path is not a POSIX filesystem. Do not
2381
2381
  * use it for locking or atomic rename.
2382
2382
  */
2383
- var S3Mounts = class {
2383
+ var S3Mount = class {
2384
2384
  #container;
2385
2385
  #gateway;
2386
2386
  constructor(container, gateway) {
@@ -2460,4 +2460,4 @@ var S3Mounts = class {
2460
2460
  }
2461
2461
  };
2462
2462
  //#endregion
2463
- export { DirectoryBackupGateway, DirectoryBackups, Files, S3Gateway, S3Mounts, SandboxBackupError, SandboxFileError, SandboxProtocolError, SandboxS3MountError };
2463
+ export { DirectoryBackup, DirectoryBackupGateway, Files, S3Gateway, S3Mount, SandboxBackupError, SandboxFileError, SandboxProtocolError, SandboxS3MountError };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudflare/sandbox",
3
- "version": "1.0.0-rc.1",
3
+ "version": "1.0.0-rc.2",
4
4
  "description": "Structured workspace file operations for Cloudflare sandboxes",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {