@cloudflare/sandbox 1.0.0-rc.1 → 1.0.0
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 +9 -9
- package/dist/index.d.mts +21 -18
- package/dist/index.mjs +40 -22
- package/package.json +1 -1
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
|
-
- [`
|
|
14
|
-
- [`
|
|
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`, `
|
|
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-
|
|
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-
|
|
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
|
|
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. */
|
|
@@ -41,7 +41,7 @@ interface DirectoryBackupOptions {
|
|
|
41
41
|
interface DirectoryRestoreOptions {
|
|
42
42
|
/** Absolute path to restore into instead of the record's `dir`. */
|
|
43
43
|
dir?: string;
|
|
44
|
-
/** Cancels the
|
|
44
|
+
/** Cancels the restore until the download is verified, without imposing a timeout. */
|
|
45
45
|
signal?: AbortSignal;
|
|
46
46
|
}
|
|
47
47
|
interface DirectoryBackupDeleteOptions {
|
|
@@ -93,10 +93,10 @@ interface DirectoryBackupGatewayBinding {
|
|
|
93
93
|
}): Fetcher & DirectoryBackupGatewayControl;
|
|
94
94
|
}
|
|
95
95
|
//#endregion
|
|
96
|
-
//#region src/directory-
|
|
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 `
|
|
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-
|
|
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
|
|
124
|
+
declare class DirectoryBackup {
|
|
125
125
|
#private;
|
|
126
126
|
constructor(container: DirectoryBackupContainer, gateway: DirectoryBackupGatewayBinding, storage: DirectoryBackupStorage);
|
|
127
127
|
/**
|
|
@@ -142,24 +142,27 @@ 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<
|
|
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
|
-
* extracted beside the target and swapped in only after the download is verified
|
|
149
|
-
* or
|
|
150
|
-
*
|
|
148
|
+
* extracted beside the target and swapped in only after the download is verified. A
|
|
149
|
+
* `SandboxFileError` or `SandboxBackupError` means the target was not replaced, and so does
|
|
150
|
+
* an abort before the download is verified; after that, aborting no longer ends the call. If the
|
|
151
|
+
* connection to the Container is lost, as when the Durable Object restarts, the target may or
|
|
152
|
+
* may not have been replaced, and restoring again settles it. The target's parent must exist;
|
|
153
|
+
* the target need not.
|
|
151
154
|
*
|
|
152
155
|
* @throws {SandboxFileError} The target's parent is missing (`ENOENT`), the target isn't a
|
|
153
156
|
* directory (`ENOTDIR`), is a mount point or has one inside it (`EBUSY`), the swap fails (for
|
|
154
157
|
* example `EXDEV`), or the disk fills (`ENOSPC`).
|
|
155
158
|
* @throws {SandboxBackupError} `BACKUP_NOT_FOUND`, `BACKUP_INTEGRITY`, or `BACKUP_TRANSFER`.
|
|
156
159
|
*/
|
|
157
|
-
restore(backup:
|
|
160
|
+
restore(backup: DirectoryBackupRecord, options?: DirectoryRestoreOptions): Promise<void>;
|
|
158
161
|
/**
|
|
159
162
|
* Deletes the backup's object. Needs no running Container. Deleting an object that is already
|
|
160
163
|
* gone succeeds. A restore reading it at the same time fails, and nothing is swapped.
|
|
161
164
|
*/
|
|
162
|
-
delete(backup:
|
|
165
|
+
delete(backup: DirectoryBackupRecord, options?: DirectoryBackupDeleteOptions): Promise<void>;
|
|
163
166
|
}
|
|
164
167
|
//#endregion
|
|
165
168
|
//#region src/files/content.d.ts
|
|
@@ -321,7 +324,7 @@ declare class Files {
|
|
|
321
324
|
remove(path: string, options?: RemoveOptions): Promise<void>;
|
|
322
325
|
}
|
|
323
326
|
//#endregion
|
|
324
|
-
//#region src/s3-
|
|
327
|
+
//#region src/s3-mount/contracts.d.ts
|
|
325
328
|
type S3MountAccess = "read-only" | "read-write";
|
|
326
329
|
type S3MountCredentials = {
|
|
327
330
|
readonly type: "static";
|
|
@@ -448,12 +451,12 @@ interface S3GatewayBinding {
|
|
|
448
451
|
}): Fetcher;
|
|
449
452
|
}
|
|
450
453
|
//#endregion
|
|
451
|
-
//#region src/s3-
|
|
454
|
+
//#region src/s3-mount/s3-gateway.d.ts
|
|
452
455
|
declare class S3Gateway extends WorkerEntrypoint<object, S3GatewayProps> {
|
|
453
456
|
fetch(request: Request): Promise<Response>;
|
|
454
457
|
}
|
|
455
458
|
//#endregion
|
|
456
|
-
//#region src/s3-
|
|
459
|
+
//#region src/s3-mount/s3-mount.d.ts
|
|
457
460
|
type S3MountContainer = Pick<Container, "exec" | "interceptOutboundHttp">;
|
|
458
461
|
/**
|
|
459
462
|
* Attaches an S3-compatible bucket or prefix to a running Container.
|
|
@@ -467,7 +470,7 @@ type S3MountContainer = Pick<Container, "exec" | "interceptOutboundHttp">;
|
|
|
467
470
|
* monitors, or replaces it. The mounted path is not a POSIX filesystem. Do not
|
|
468
471
|
* use it for locking or atomic rename.
|
|
469
472
|
*/
|
|
470
|
-
declare class
|
|
473
|
+
declare class S3Mount {
|
|
471
474
|
#private;
|
|
472
475
|
constructor(container: S3MountContainer, gateway: S3GatewayBinding);
|
|
473
476
|
/**
|
|
@@ -554,4 +557,4 @@ declare const SandboxBackupError: {
|
|
|
554
557
|
is(cause: unknown): cause is SandboxBackupError;
|
|
555
558
|
};
|
|
556
559
|
//#endregion
|
|
557
|
-
export {
|
|
560
|
+
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-
|
|
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-
|
|
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 `
|
|
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-
|
|
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
|
|
@@ -367,6 +367,10 @@ var ShimSession = class ShimSession {
|
|
|
367
367
|
waitFor(operation) {
|
|
368
368
|
return this.#abort.waitFor(operation);
|
|
369
369
|
}
|
|
370
|
+
/** Stops following the caller's signal: later waits no longer reject when it aborts. */
|
|
371
|
+
stopFollowingSignal() {
|
|
372
|
+
this.#abort.dispose();
|
|
373
|
+
}
|
|
370
374
|
finish() {
|
|
371
375
|
if (this.#settled) return;
|
|
372
376
|
this.#settled = true;
|
|
@@ -479,7 +483,7 @@ function validateHeader(header) {
|
|
|
479
483
|
if (header[4] !== PROTOCOL_VERSION) throw protocolError(`sandbox-shim protocol ${header[4]} is not supported`);
|
|
480
484
|
}
|
|
481
485
|
//#endregion
|
|
482
|
-
//#region src/directory-
|
|
486
|
+
//#region src/directory-backup/protocol.ts
|
|
483
487
|
/** The one intercepted host every operation's grant is registered on. */
|
|
484
488
|
const GATEWAY_HOST = "backups.sandbox.internal";
|
|
485
489
|
const ACKNOWLEDGEMENT = new Uint8Array([1]);
|
|
@@ -490,6 +494,7 @@ const errorSchema = z.object({
|
|
|
490
494
|
detail: z.string()
|
|
491
495
|
});
|
|
492
496
|
const lockedSchema = z.strictObject({ kind: z.literal("locked") });
|
|
497
|
+
const verifiedSchema = z.strictObject({ kind: z.literal("verified") });
|
|
493
498
|
/**
|
|
494
499
|
* Runs one `directory-backup` shim exchange: wait for the lock, register the grant, acknowledge,
|
|
495
500
|
* wait for the result, then deny and close stdin, in that order on every path. The shim holds
|
|
@@ -497,7 +502,10 @@ const lockedSchema = z.strictObject({ kind: z.literal("locked") });
|
|
|
497
502
|
* operation's deny.
|
|
498
503
|
*
|
|
499
504
|
* An abort closes stdin rather than killing the shim, which then removes whatever it had
|
|
500
|
-
* partly written, and rejects
|
|
505
|
+
* partly written, and rejects with the signal's reason without waiting for the shim. A restore
|
|
506
|
+
* reports `verified` before it swaps and swaps only once acknowledged, so the exchange
|
|
507
|
+
* acknowledges it only while the signal hasn't aborted, and from then on reports the swap's
|
|
508
|
+
* outcome instead of the abort.
|
|
501
509
|
*/
|
|
502
510
|
async function runShimExchange(container, exchange) {
|
|
503
511
|
const { signal } = exchange;
|
|
@@ -535,6 +543,13 @@ async function runShimExchange(container, exchange) {
|
|
|
535
543
|
granting = exchange.grant();
|
|
536
544
|
await session.waitFor(granting);
|
|
537
545
|
await session.waitFor(input.write(ACKNOWLEDGEMENT));
|
|
546
|
+
if (exchange.command === "restore") {
|
|
547
|
+
const verified = await readMessage(control, operation, exchange.path);
|
|
548
|
+
if (!verifiedSchema.safeParse(verified).success) throw protocolError("sandbox-shim did not report a verified restore");
|
|
549
|
+
signal?.throwIfAborted();
|
|
550
|
+
session.stopFollowingSignal();
|
|
551
|
+
await input.write(ACKNOWLEDGEMENT);
|
|
552
|
+
}
|
|
538
553
|
const result = await readMessage(control, operation, exchange.path);
|
|
539
554
|
const done = exchange.done.safeParse(result);
|
|
540
555
|
if (!done.success) throw protocolError("sandbox-shim returned an invalid backup result");
|
|
@@ -578,7 +593,7 @@ function closeStdin(input) {
|
|
|
578
593
|
input.close().catch(() => void 0);
|
|
579
594
|
}
|
|
580
595
|
//#endregion
|
|
581
|
-
//#region src/directory-
|
|
596
|
+
//#region src/directory-backup/directory-backup.ts
|
|
582
597
|
const absolutePath = z.string().check(z.startsWith("/"), z.refine((value) => !value.includes("\0")));
|
|
583
598
|
const SIGNAL = {
|
|
584
599
|
schema: z.instanceof(AbortSignal),
|
|
@@ -637,7 +652,7 @@ const restoreDoneSchema = z.strictObject({ kind: z.literal("done") });
|
|
|
637
652
|
* starts, retries, or times out anything. The application stores the returned records and
|
|
638
653
|
* decides when to delete them.
|
|
639
654
|
*/
|
|
640
|
-
var
|
|
655
|
+
var DirectoryBackup = class {
|
|
641
656
|
#container;
|
|
642
657
|
#gateway;
|
|
643
658
|
#binding;
|
|
@@ -704,9 +719,12 @@ var DirectoryBackups = class {
|
|
|
704
719
|
}
|
|
705
720
|
/**
|
|
706
721
|
* Replaces `options.dir`, or the record's `dir`, with the backup's contents. The directory is
|
|
707
|
-
* extracted beside the target and swapped in only after the download is verified
|
|
708
|
-
* or
|
|
709
|
-
*
|
|
722
|
+
* extracted beside the target and swapped in only after the download is verified. A
|
|
723
|
+
* `SandboxFileError` or `SandboxBackupError` means the target was not replaced, and so does
|
|
724
|
+
* an abort before the download is verified; after that, aborting no longer ends the call. If the
|
|
725
|
+
* connection to the Container is lost, as when the Durable Object restarts, the target may or
|
|
726
|
+
* may not have been replaced, and restoring again settles it. The target's parent must exist;
|
|
727
|
+
* the target need not.
|
|
710
728
|
*
|
|
711
729
|
* @throws {SandboxFileError} The target's parent is missing (`ENOENT`), the target isn't a
|
|
712
730
|
* directory (`ENOTDIR`), is a mount point or has one inside it (`EBUSY`), the swap fails (for
|
|
@@ -1446,7 +1464,7 @@ async function readBoundedBody(body, limit, cancelReason) {
|
|
|
1446
1464
|
};
|
|
1447
1465
|
}
|
|
1448
1466
|
//#endregion
|
|
1449
|
-
//#region src/s3-
|
|
1467
|
+
//#region src/s3-mount/credentials.ts
|
|
1450
1468
|
const CREDENTIAL_PROVIDER_URL = "https://credentials.sandbox.internal/";
|
|
1451
1469
|
const MAX_CREDENTIAL_RESPONSE_BYTES = 16384;
|
|
1452
1470
|
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
@@ -1498,12 +1516,12 @@ async function readCredentialResponse(body) {
|
|
|
1498
1516
|
}
|
|
1499
1517
|
}
|
|
1500
1518
|
//#endregion
|
|
1501
|
-
//#region src/s3-
|
|
1519
|
+
//#region src/s3-mount/route.ts
|
|
1502
1520
|
function routeHost(routeId) {
|
|
1503
1521
|
return `s3-${routeId}.sandbox.internal`;
|
|
1504
1522
|
}
|
|
1505
1523
|
//#endregion
|
|
1506
|
-
//#region src/s3-
|
|
1524
|
+
//#region src/s3-mount/gateway-policy.ts
|
|
1507
1525
|
const LIST_V1_PARAMETERS = /* @__PURE__ */ new Set([
|
|
1508
1526
|
"delimiter",
|
|
1509
1527
|
"encoding-type",
|
|
@@ -1738,7 +1756,7 @@ function usesAwsChunkedPayload(headers) {
|
|
|
1738
1756
|
return (headers.get("content-encoding") ?? "").split(",").some((encoding) => encoding.trim().toLowerCase() === "aws-chunked");
|
|
1739
1757
|
}
|
|
1740
1758
|
//#endregion
|
|
1741
|
-
//#region src/s3-
|
|
1759
|
+
//#region src/s3-mount/gateway.ts
|
|
1742
1760
|
const INSPECTION_VERSION_HEADER = "x-sandbox-s3-gateway-version";
|
|
1743
1761
|
const INSPECTION_RESULT_HEADER = "x-sandbox-s3-inspection-result";
|
|
1744
1762
|
const INSPECTION_DETAIL_HEADER = "x-sandbox-s3-inspection-detail";
|
|
@@ -1849,14 +1867,14 @@ function inspectionResponse(result, detail, status) {
|
|
|
1849
1867
|
});
|
|
1850
1868
|
}
|
|
1851
1869
|
//#endregion
|
|
1852
|
-
//#region src/s3-
|
|
1870
|
+
//#region src/s3-mount/s3-gateway.ts
|
|
1853
1871
|
var S3Gateway = class extends WorkerEntrypoint {
|
|
1854
1872
|
fetch(request) {
|
|
1855
1873
|
return handleS3GatewayRequest(request, this.ctx.props);
|
|
1856
1874
|
}
|
|
1857
1875
|
};
|
|
1858
1876
|
//#endregion
|
|
1859
|
-
//#region src/s3-
|
|
1877
|
+
//#region src/s3-mount/request.ts
|
|
1860
1878
|
const objectSchema = z.object({});
|
|
1861
1879
|
const stringSchema = z.string();
|
|
1862
1880
|
const fetcherSchema = z.object({ fetch: z.function() });
|
|
@@ -2024,7 +2042,7 @@ function requiredString(value, name) {
|
|
|
2024
2042
|
return parsed.data;
|
|
2025
2043
|
}
|
|
2026
2044
|
//#endregion
|
|
2027
|
-
//#region src/s3-
|
|
2045
|
+
//#region src/s3-mount/protocol.ts
|
|
2028
2046
|
const ROUTE_READY = new Uint8Array([1]);
|
|
2029
2047
|
const routeIdSchema = z.string().check(z.regex(/^[A-Za-z0-9](?:[A-Za-z0-9-]{0,58}[A-Za-z0-9])?$/));
|
|
2030
2048
|
const keyPrefixSchema = z.optional(z.string().check(z.refine((value) => value.endsWith("/"))));
|
|
@@ -2324,7 +2342,7 @@ function parseGatewayState(state) {
|
|
|
2324
2342
|
}
|
|
2325
2343
|
}
|
|
2326
2344
|
//#endregion
|
|
2327
|
-
//#region src/s3-
|
|
2345
|
+
//#region src/s3-mount/reconcile.ts
|
|
2328
2346
|
function assembleInspection(mountPath, evidence) {
|
|
2329
2347
|
const state = evidence.state;
|
|
2330
2348
|
switch (state.kind) {
|
|
@@ -2367,7 +2385,7 @@ function gatewayFor(evidence) {
|
|
|
2367
2385
|
throw protocolError("sandbox-shim omitted managed mount gateway evidence");
|
|
2368
2386
|
}
|
|
2369
2387
|
//#endregion
|
|
2370
|
-
//#region src/s3-
|
|
2388
|
+
//#region src/s3-mount/s3-mount.ts
|
|
2371
2389
|
/**
|
|
2372
2390
|
* Attaches an S3-compatible bucket or prefix to a running Container.
|
|
2373
2391
|
*
|
|
@@ -2380,7 +2398,7 @@ function gatewayFor(evidence) {
|
|
|
2380
2398
|
* monitors, or replaces it. The mounted path is not a POSIX filesystem. Do not
|
|
2381
2399
|
* use it for locking or atomic rename.
|
|
2382
2400
|
*/
|
|
2383
|
-
var
|
|
2401
|
+
var S3Mount = class {
|
|
2384
2402
|
#container;
|
|
2385
2403
|
#gateway;
|
|
2386
2404
|
constructor(container, gateway) {
|
|
@@ -2460,4 +2478,4 @@ var S3Mounts = class {
|
|
|
2460
2478
|
}
|
|
2461
2479
|
};
|
|
2462
2480
|
//#endregion
|
|
2463
|
-
export {
|
|
2481
|
+
export { DirectoryBackup, DirectoryBackupGateway, Files, S3Gateway, S3Mount, SandboxBackupError, SandboxFileError, SandboxProtocolError, SandboxS3MountError };
|