@agen-ai/sandbox 0.0.0-stage → 0.4.4

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.
Files changed (113) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +141 -2
  3. package/dist/acp/index.d.ts +9 -0
  4. package/dist/acp/index.js +25 -0
  5. package/dist/backend/contracts.d.ts +41 -0
  6. package/dist/backend/contracts.js +0 -0
  7. package/dist/backend/index.d.ts +6 -0
  8. package/dist/backend/index.js +64 -0
  9. package/dist/backend/spill.d.ts +15 -0
  10. package/dist/backend/spill.js +0 -0
  11. package/dist/contracts.d.ts +37 -0
  12. package/dist/contracts.js +0 -0
  13. package/dist/errors.d.ts +46 -0
  14. package/dist/errors.js +73 -0
  15. package/dist/files/bytes.d.ts +31 -0
  16. package/dist/files/bytes.js +134 -0
  17. package/dist/files/iterator.d.ts +13 -0
  18. package/dist/files/iterator.js +59 -0
  19. package/dist/files/metadata/index.d.ts +12 -0
  20. package/dist/files/metadata/index.js +193 -0
  21. package/dist/files/metadata/records.d.ts +21 -0
  22. package/dist/files/metadata/records.js +50 -0
  23. package/dist/files/metadata/sort.d.ts +13 -0
  24. package/dist/files/metadata/sort.js +63 -0
  25. package/dist/files/metadata/storage.d.ts +12 -0
  26. package/dist/files/metadata/storage.js +69 -0
  27. package/dist/files/metadata/types.d.ts +19 -0
  28. package/dist/files/metadata/types.js +0 -0
  29. package/dist/files/parse.d.ts +20 -0
  30. package/dist/files/parse.js +62 -0
  31. package/dist/files/pathSchemas.d.ts +5 -0
  32. package/dist/files/pathSchemas.js +16 -0
  33. package/dist/files/paths.d.ts +4 -0
  34. package/dist/files/paths.js +12 -0
  35. package/dist/files/quotas.d.ts +18 -0
  36. package/dist/files/quotas.js +37 -0
  37. package/dist/files/types.d.ts +81 -0
  38. package/dist/files/types.js +0 -0
  39. package/dist/index.d.ts +15 -0
  40. package/dist/index.js +35 -0
  41. package/dist/internal/data.d.ts +6 -0
  42. package/dist/internal/data.js +68 -0
  43. package/dist/internal/operations.d.ts +4 -0
  44. package/dist/internal/operations.js +30 -0
  45. package/dist/internal/parse.d.ts +3 -0
  46. package/dist/internal/parse.js +12 -0
  47. package/dist/lifecycle/deadline.d.ts +3 -0
  48. package/dist/lifecycle/deadline.js +18 -0
  49. package/dist/lifecycle/journal.d.ts +14 -0
  50. package/dist/lifecycle/journal.js +51 -0
  51. package/dist/lifecycle/observation.d.ts +9 -0
  52. package/dist/lifecycle/observation.js +41 -0
  53. package/dist/lifecycle/owner.d.ts +38 -0
  54. package/dist/lifecycle/owner.js +288 -0
  55. package/dist/lifecycle/recovered.d.ts +16 -0
  56. package/dist/lifecycle/recovered.js +62 -0
  57. package/dist/lifecycle/recoveryIdentity.d.ts +3 -0
  58. package/dist/lifecycle/recoveryIdentity.js +18 -0
  59. package/dist/lifecycle/transfer.d.ts +10 -0
  60. package/dist/lifecycle/transfer.js +339 -0
  61. package/dist/node/directories/closing.d.ts +2 -0
  62. package/dist/node/directories/closing.js +19 -0
  63. package/dist/node/directories/export.d.ts +6 -0
  64. package/dist/node/directories/export.js +43 -0
  65. package/dist/node/directories/file.d.ts +26 -0
  66. package/dist/node/directories/file.js +104 -0
  67. package/dist/node/directories/import.d.ts +6 -0
  68. package/dist/node/directories/import.js +38 -0
  69. package/dist/node/directories/options.d.ts +4 -0
  70. package/dist/node/directories/options.js +10 -0
  71. package/dist/node/directories/ownership.d.ts +33 -0
  72. package/dist/node/directories/ownership.js +148 -0
  73. package/dist/node/directories/source.d.ts +25 -0
  74. package/dist/node/directories/source.js +143 -0
  75. package/dist/node/directories/stage.d.ts +43 -0
  76. package/dist/node/directories/stage.js +302 -0
  77. package/dist/node/directories/types.d.ts +23 -0
  78. package/dist/node/directories/types.js +17 -0
  79. package/dist/node/hostPath.d.ts +7 -0
  80. package/dist/node/hostPath.js +37 -0
  81. package/dist/node/index.d.ts +8 -0
  82. package/dist/node/index.js +14 -0
  83. package/dist/node/spill.d.ts +14 -0
  84. package/dist/node/spill.js +97 -0
  85. package/dist/node/spillDirectory.d.ts +4 -0
  86. package/dist/node/spillDirectory.js +17 -0
  87. package/dist/node/spillFile.d.ts +24 -0
  88. package/dist/node/spillFile.js +96 -0
  89. package/dist/policy/limits.d.ts +31 -0
  90. package/dist/policy/limits.js +35 -0
  91. package/dist/policy/parse.d.ts +11 -0
  92. package/dist/policy/parse.js +47 -0
  93. package/dist/policy/schemas.d.ts +148 -0
  94. package/dist/policy/schemas.js +75 -0
  95. package/dist/policy/types.d.ts +105 -0
  96. package/dist/policy/types.js +0 -0
  97. package/dist/process/input.d.ts +23 -0
  98. package/dist/process/input.js +93 -0
  99. package/dist/process/output.d.ts +13 -0
  100. package/dist/process/output.js +43 -0
  101. package/dist/process/parse.d.ts +4 -0
  102. package/dist/process/parse.js +32 -0
  103. package/dist/process/streams.d.ts +9 -0
  104. package/dist/process/streams.js +61 -0
  105. package/dist/process/types.d.ts +38 -0
  106. package/dist/process/types.js +0 -0
  107. package/dist/recovery/parse.d.ts +4 -0
  108. package/dist/recovery/parse.js +67 -0
  109. package/dist/recovery/types.d.ts +59 -0
  110. package/dist/recovery/types.js +0 -0
  111. package/dist/withSandbox.d.ts +4 -0
  112. package/dist/withSandbox.js +39 -0
  113. package/package.json +76 -3
@@ -0,0 +1,20 @@
1
+ import type { SandboxTransferBudget, SandboxTransferOptions, SandboxTransferSummary } from './types.js';
2
+ export declare function transferData(input: unknown, allowed: readonly string[]): Record<string, unknown>;
3
+ export interface ParsedTransferOptions {
4
+ readonly signal?: AbortSignal;
5
+ readonly deadlineAt?: number;
6
+ readonly quotas: SandboxTransferBudget;
7
+ }
8
+ export declare function parseTransferOptions(input: SandboxTransferOptions | undefined): ParsedTransferOptions;
9
+ export declare function parseTreeMetadata(input: unknown, bodyField: 'open' | 'bytes'): Readonly<{
10
+ kind: "directory";
11
+ path: import("./types.js").SandboxRelativePath;
12
+ }> | Readonly<{
13
+ kind: "file";
14
+ path: import("./types.js").SandboxRelativePath;
15
+ byteLength: number;
16
+ executable: boolean;
17
+ body: unknown;
18
+ }>;
19
+ export declare function parseTransferSummary(input: unknown): SandboxTransferSummary;
20
+ //# sourceMappingURL=parse.d.ts.map
@@ -0,0 +1,62 @@
1
+ import { z } from "zod/v4";
2
+ import { invalidInput } from "../internal/data.js";
3
+ import { parseOperationOptions } from "../internal/operations.js";
4
+ import { parseSandboxRelativePath } from "./paths.js";
5
+ function transferData(input, allowed) {
6
+ if (input === null || typeof input !== "object" || Object.getPrototypeOf(input) !== Object.prototype && Object.getPrototypeOf(input) !== null) invalidInput("Transfer metadata must be a plain object");
7
+ const result = /* @__PURE__ */ Object.create(null);
8
+ for (const key of Reflect.ownKeys(input)) {
9
+ if (typeof key !== "string" || !allowed.includes(key)) invalidInput("Unexpected transfer metadata field");
10
+ const descriptor = Object.getOwnPropertyDescriptor(input, key);
11
+ if (!descriptor || !("value" in descriptor) || !descriptor.enumerable) invalidInput("Transfer metadata must contain enumerable data fields");
12
+ result[key] = descriptor.value;
13
+ }
14
+ return result;
15
+ }
16
+ function parseTransferOptions(input) {
17
+ const data = input === void 0 ? {} : transferData(input, ["signal", "deadlineAt", "quotas"]);
18
+ const cancellation = parseOperationOptions(data.signal === void 0 ? void 0 : { signal: data.signal });
19
+ let deadlineAt;
20
+ if (data.deadlineAt !== void 0) {
21
+ if (!z.iso.datetime({ offset: true }).safeParse(data.deadlineAt).success) invalidInput("Transfer deadlineAt must be an ISO timestamp");
22
+ deadlineAt = Date.parse(String(data.deadlineAt));
23
+ if (!Number.isSafeInteger(deadlineAt)) invalidInput("Transfer deadlineAt must be representable in milliseconds");
24
+ }
25
+ const quotas = {};
26
+ if (data.quotas !== void 0) {
27
+ const selected = transferData(data.quotas, ["maxFiles", "maxFileBytes", "maxTotalBytes", "maxArchiveBytes", "maxPaths"]);
28
+ for (const key of ["maxFiles", "maxFileBytes", "maxTotalBytes", "maxArchiveBytes", "maxPaths"]) {
29
+ const value = selected[key];
30
+ if (value === void 0) continue;
31
+ if (typeof value !== "bigint" && (typeof value !== "number" || !Number.isSafeInteger(value))) invalidInput("Transfer quotas must be nonnegative integers");
32
+ if (value < 0) invalidInput("Transfer quotas must be nonnegative integers");
33
+ quotas[key] = BigInt(value);
34
+ }
35
+ }
36
+ return Object.freeze({ ...cancellation, ...deadlineAt === void 0 ? {} : { deadlineAt }, quotas: Object.freeze(quotas) });
37
+ }
38
+ function parseTreeMetadata(input, bodyField) {
39
+ const data = transferData(input, ["kind", "path", "byteLength", "executable", bodyField]);
40
+ const path = parseSandboxRelativePath(data.path);
41
+ if (data.kind === "directory") {
42
+ if (Reflect.ownKeys(data).length !== 2) invalidInput("Directories require only kind and path");
43
+ return Object.freeze({ kind: "directory", path });
44
+ }
45
+ if (data.kind !== "file" || Reflect.ownKeys(data).length !== 5) invalidInput("Files require kind, path, byteLength, executable and a body source");
46
+ if (typeof data.byteLength !== "number" || !Number.isSafeInteger(data.byteLength) || data.byteLength < 0) invalidInput("File byteLength must be a nonnegative safe integer");
47
+ if (typeof data.executable !== "boolean") invalidInput("File executable must be boolean");
48
+ if (bodyField === "open" && typeof data.open !== "function") invalidInput("Input files require an open function");
49
+ return Object.freeze({ kind: "file", path, byteLength: data.byteLength, executable: data.executable, body: data[bodyField] });
50
+ }
51
+ function parseTransferSummary(input) {
52
+ const data = transferData(input, ["files", "directories", "payloadBytes", "archiveBytes"]);
53
+ const { files, directories, payloadBytes, archiveBytes } = data;
54
+ if (typeof files !== "bigint" || files < 0n || typeof directories !== "bigint" || directories < 0n || typeof payloadBytes !== "bigint" || payloadBytes < 0n || typeof archiveBytes !== "bigint" || archiveBytes < 0n) invalidInput("Transfer summaries require nonnegative bigint counters");
55
+ return Object.freeze({ files, directories, payloadBytes, archiveBytes });
56
+ }
57
+ export {
58
+ parseTransferOptions,
59
+ parseTransferSummary,
60
+ parseTreeMetadata,
61
+ transferData
62
+ };
@@ -0,0 +1,5 @@
1
+ import { z } from 'zod/v4';
2
+ import type { SandboxGuestPath, SandboxRelativePath } from './types.js';
3
+ export declare const relativePathSchema: z.ZodCustom<SandboxRelativePath, SandboxRelativePath>;
4
+ export declare const guestPathSchema: z.ZodCustom<SandboxGuestPath, SandboxGuestPath>;
5
+ //# sourceMappingURL=pathSchemas.d.ts.map
@@ -0,0 +1,16 @@
1
+ import { z } from "zod/v4";
2
+ import { utf8Within } from "../internal/data.js";
3
+ import { SANDBOX_LIMITS } from "../policy/limits.js";
4
+ function safeSegments(path) {
5
+ const segments = path.split("/");
6
+ return segments.length <= SANDBOX_LIMITS.maxPathSegments && segments.every((segment) => segment.length > 0 && segment !== "." && segment !== ".." && utf8Within(segment, SANDBOX_LIMITS.maxPathSegmentBytes));
7
+ }
8
+ function safePath(value) {
9
+ return typeof value === "string" && value.length > 0 && utf8Within(value, SANDBOX_LIMITS.maxPathBytes) && !/[\\\u0000-\u001f\u007f]/u.test(value);
10
+ }
11
+ const relativePathSchema = z.custom((value) => safePath(value) && safeSegments(value), "Expected a bounded canonical relative file path");
12
+ const guestPathSchema = z.custom((value) => safePath(value) && value.startsWith("/") && (value === "/" || safeSegments(value.slice(1))), "Expected a bounded canonical absolute guest path");
13
+ export {
14
+ guestPathSchema,
15
+ relativePathSchema
16
+ };
@@ -0,0 +1,4 @@
1
+ import type { SandboxGuestPath, SandboxRelativePath } from './types.js';
2
+ export declare function parseSandboxRelativePath(input: unknown): SandboxRelativePath;
3
+ export declare function parseSandboxGuestPath(input: unknown): SandboxGuestPath;
4
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1,12 @@
1
+ import { parseData } from "../internal/parse.js";
2
+ import { guestPathSchema, relativePathSchema } from "./pathSchemas.js";
3
+ function parseSandboxRelativePath(input) {
4
+ return parseData(relativePathSchema, input);
5
+ }
6
+ function parseSandboxGuestPath(input) {
7
+ return parseData(guestPathSchema, input);
8
+ }
9
+ export {
10
+ parseSandboxGuestPath,
11
+ parseSandboxRelativePath
12
+ };
@@ -0,0 +1,18 @@
1
+ import type { SandboxTransferBudget, SandboxTransferSummary } from './types.js';
2
+ export declare class TransferCounters {
3
+ private readonly quotas;
4
+ private readonly direction;
5
+ files: bigint;
6
+ directories: bigint;
7
+ payloadBytes: bigint;
8
+ constructor(quotas: SandboxTransferBudget, direction: 'import' | 'export');
9
+ admit(entry: Readonly<{
10
+ kind: 'file';
11
+ byteLength: number;
12
+ }> | Readonly<{
13
+ kind: 'directory';
14
+ }>): void;
15
+ check(name: keyof SandboxTransferBudget, actual: bigint): void;
16
+ verify(input: unknown): SandboxTransferSummary;
17
+ }
18
+ //# sourceMappingURL=quotas.d.ts.map
@@ -0,0 +1,37 @@
1
+ import { SandboxOperationError } from "../errors.js";
2
+ import { parseTransferSummary } from "./parse.js";
3
+ class TransferCounters {
4
+ constructor(quotas, direction) {
5
+ this.quotas = quotas;
6
+ this.direction = direction;
7
+ }
8
+ files = 0n;
9
+ directories = 0n;
10
+ payloadBytes = 0n;
11
+ admit(entry) {
12
+ if (entry.kind === "directory") this.directories += 1n;
13
+ else {
14
+ this.files += 1n;
15
+ const bytes = BigInt(entry.byteLength);
16
+ this.payloadBytes += bytes;
17
+ this.check("maxFileBytes", bytes);
18
+ this.check("maxFiles", this.files);
19
+ this.check("maxTotalBytes", this.payloadBytes);
20
+ }
21
+ }
22
+ check(name, actual) {
23
+ const ceiling = this.quotas[name];
24
+ if (ceiling !== void 0 && actual > ceiling) throw new SandboxOperationError(this.direction === "import" ? "input_limit" : "output_limit", `Transfer exceeded caller quota ${name}.`);
25
+ }
26
+ verify(input) {
27
+ const summary = parseTransferSummary(input);
28
+ if (summary.files !== this.files || summary.directories !== this.directories || summary.payloadBytes !== this.payloadBytes) {
29
+ throw new SandboxOperationError("driver_failure", "Backend transfer summary disagrees with completely consumed entries.");
30
+ }
31
+ this.check("maxArchiveBytes", summary.archiveBytes);
32
+ return summary;
33
+ }
34
+ }
35
+ export {
36
+ TransferCounters
37
+ };
@@ -0,0 +1,81 @@
1
+ declare const relativePathBrand: unique symbol;
2
+ declare const guestPathBrand: unique symbol;
3
+ export type SandboxRelativePath = string & {
4
+ readonly [relativePathBrand]: true;
5
+ };
6
+ export type SandboxGuestPath = string & {
7
+ readonly [guestPathBrand]: true;
8
+ };
9
+ export type SandboxByteSource = AsyncIterable<Uint8Array> | Iterable<Uint8Array>;
10
+ export type SandboxTreeEntry = Readonly<{
11
+ kind: 'directory';
12
+ path: string;
13
+ }> | Readonly<{
14
+ kind: 'file';
15
+ path: string;
16
+ byteLength: number;
17
+ executable: boolean;
18
+ open(input: Readonly<{
19
+ signal: AbortSignal;
20
+ }>): SandboxByteSource;
21
+ }>;
22
+ export type SandboxTreeSource = AsyncIterable<SandboxTreeEntry> | Iterable<SandboxTreeEntry>;
23
+ export type SandboxInputTreeEntry = Readonly<{
24
+ kind: 'directory';
25
+ path: SandboxRelativePath;
26
+ }> | Readonly<{
27
+ kind: 'file';
28
+ path: SandboxRelativePath;
29
+ byteLength: number;
30
+ executable: boolean;
31
+ open(input: Readonly<{
32
+ signal: AbortSignal;
33
+ }>): SandboxByteSource;
34
+ }>;
35
+ export type SandboxExportEntry = Readonly<{
36
+ kind: 'directory';
37
+ path: string;
38
+ }> | Readonly<{
39
+ kind: 'file';
40
+ path: string;
41
+ byteLength: number;
42
+ executable: boolean;
43
+ bytes: AsyncIterable<Uint8Array>;
44
+ }>;
45
+ export type SandboxExportConsumer = (entry: SandboxExportEntry, input: Readonly<{
46
+ signal: AbortSignal;
47
+ }>) => Promise<void>;
48
+ export type SandboxTreeSelection = Readonly<{
49
+ kind: 'workspace';
50
+ }> | Readonly<{
51
+ kind: 'files';
52
+ paths: AsyncIterable<string> | Iterable<string>;
53
+ }> | Readonly<{
54
+ kind: 'subtree';
55
+ path: string;
56
+ }>;
57
+ export type SandboxInputTreeSelection = Readonly<{
58
+ kind: 'workspace';
59
+ }> | Readonly<{
60
+ kind: 'files';
61
+ paths: AsyncIterable<SandboxRelativePath>;
62
+ }> | Readonly<{
63
+ kind: 'subtree';
64
+ path: SandboxRelativePath;
65
+ }>;
66
+ export type SandboxTransferQuotaName = 'maxFiles' | 'maxFileBytes' | 'maxTotalBytes' | 'maxArchiveBytes' | 'maxPaths';
67
+ export type SandboxTransferQuotas = Readonly<Partial<Record<SandboxTransferQuotaName, number | bigint>>>;
68
+ export type SandboxTransferBudget = Readonly<Partial<Record<SandboxTransferQuotaName, bigint>>>;
69
+ export interface SandboxTransferOptions {
70
+ readonly signal?: AbortSignal;
71
+ readonly deadlineAt?: string;
72
+ readonly quotas?: SandboxTransferQuotas;
73
+ }
74
+ export interface SandboxTransferSummary {
75
+ readonly files: bigint;
76
+ readonly directories: bigint;
77
+ readonly payloadBytes: bigint;
78
+ readonly archiveBytes: bigint;
79
+ }
80
+ export {};
81
+ //# sourceMappingURL=types.d.ts.map
File without changes
@@ -0,0 +1,15 @@
1
+ export type { OperationOptions, SandboxState, SandboxBackend, SandboxReservation, Sandbox, SandboxRunOptions } from './contracts.js';
2
+ export type { SandboxNamespace, SandboxId, SandboxProcessId, SandboxResources, SandboxTemporaryStorage, SandboxNetworkPolicy, SandboxWorkspaceDiskQuota, SandboxExecutionPolicy, SandboxDeadlines, SandboxPolicyInput, SandboxPolicy, SandboxRequestInput, SandboxRequest, SandboxTransferBuffers, SandboxStreamLimits, SandboxSupport, SandboxEffectivePolicy } from './policy/types.js';
3
+ export type { SandboxGuestPath, SandboxRelativePath, SandboxByteSource, SandboxTreeEntry, SandboxTreeSource, SandboxInputTreeEntry, SandboxExportEntry, SandboxExportConsumer, SandboxTreeSelection, SandboxInputTreeSelection, SandboxTransferQuotaName, SandboxTransferQuotas, SandboxTransferBudget, SandboxTransferOptions, SandboxTransferSummary } from './files/types.js';
4
+ export type { SandboxProcessInput, SandboxProcessSpec, SandboxProcessExit, SandboxProcessStreams, SandboxProcessReservation } from './process/types.js';
5
+ export type { SandboxRecoveryPhase, SandboxResourceIdentity, SandboxRecoveryResource, SandboxRecoveryAuthority, SandboxRecoveryRecord, SandboxRecoveryPolicy, SandboxCleanupOwner, SandboxReconciliation } from './recovery/types.js';
6
+ export type { SandboxOperationErrorCode } from './errors.js';
7
+ export { SandboxValidationError, SandboxUnsupportedError, SandboxStateError, SandboxOperationError, SandboxCleanupError, SandboxStartError, SandboxRunError } from './errors.js';
8
+ export { SANDBOX_LIMITS, SANDBOX_DEFAULT_TRANSFER_BUFFERS, SANDBOX_DEFAULT_STREAM_LIMITS } from './policy/limits.js';
9
+ export { parseSandboxNamespace, parseSandboxId, parseSandboxProcessId, parseSandboxPolicy, parseSandboxRequest, parseSandboxSupport, parseSandboxEffectivePolicy } from './policy/parse.js';
10
+ export { parseSandboxRelativePath, parseSandboxGuestPath } from './files/paths.js';
11
+ export { fileFromBytes } from './files/bytes.js';
12
+ export { parseSandboxProcessSpec, parseSandboxProcessExit } from './process/parse.js';
13
+ export { parseSandboxRecoveryRecord, parseSandboxRecoveryPolicy } from './recovery/parse.js';
14
+ export { withSandbox } from './withSandbox.js';
15
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,35 @@
1
+ import { SandboxValidationError, SandboxUnsupportedError, SandboxStateError, SandboxOperationError, SandboxCleanupError, SandboxStartError, SandboxRunError } from "./errors.js";
2
+ import { SANDBOX_LIMITS, SANDBOX_DEFAULT_TRANSFER_BUFFERS, SANDBOX_DEFAULT_STREAM_LIMITS } from "./policy/limits.js";
3
+ import { parseSandboxNamespace, parseSandboxId, parseSandboxProcessId, parseSandboxPolicy, parseSandboxRequest, parseSandboxSupport, parseSandboxEffectivePolicy } from "./policy/parse.js";
4
+ import { parseSandboxRelativePath, parseSandboxGuestPath } from "./files/paths.js";
5
+ import { fileFromBytes } from "./files/bytes.js";
6
+ import { parseSandboxProcessSpec, parseSandboxProcessExit } from "./process/parse.js";
7
+ import { parseSandboxRecoveryRecord, parseSandboxRecoveryPolicy } from "./recovery/parse.js";
8
+ import { withSandbox } from "./withSandbox.js";
9
+ export {
10
+ SANDBOX_DEFAULT_STREAM_LIMITS,
11
+ SANDBOX_DEFAULT_TRANSFER_BUFFERS,
12
+ SANDBOX_LIMITS,
13
+ SandboxCleanupError,
14
+ SandboxOperationError,
15
+ SandboxRunError,
16
+ SandboxStartError,
17
+ SandboxStateError,
18
+ SandboxUnsupportedError,
19
+ SandboxValidationError,
20
+ fileFromBytes,
21
+ parseSandboxEffectivePolicy,
22
+ parseSandboxGuestPath,
23
+ parseSandboxId,
24
+ parseSandboxNamespace,
25
+ parseSandboxPolicy,
26
+ parseSandboxProcessExit,
27
+ parseSandboxProcessId,
28
+ parseSandboxProcessSpec,
29
+ parseSandboxRecoveryPolicy,
30
+ parseSandboxRecoveryRecord,
31
+ parseSandboxRelativePath,
32
+ parseSandboxRequest,
33
+ parseSandboxSupport,
34
+ withSandbox
35
+ };
@@ -0,0 +1,6 @@
1
+ export declare function invalidInput(message: string, path?: readonly (string | number)[]): never;
2
+ /** Capture plain data without invoking caller-controlled accessors or retaining mutable input. */
3
+ export declare function captureData(input: unknown): unknown;
4
+ export declare function freezeData<Value>(value: Value): Value;
5
+ export declare function utf8Within(value: string, maximum: number): boolean;
6
+ //# sourceMappingURL=data.d.ts.map
@@ -0,0 +1,68 @@
1
+ import { Buffer } from "node:buffer";
2
+ import { SandboxValidationError } from "../errors.js";
3
+ function invalidInput(message, path = []) {
4
+ throw new SandboxValidationError([{ code: "invalid_input", path, message }]);
5
+ }
6
+ function captureData(input) {
7
+ const seen = /* @__PURE__ */ new Set();
8
+ let nodes = 0;
9
+ let bytes = 0;
10
+ function capture(value, depth) {
11
+ nodes += 1;
12
+ if (nodes > 8192 || depth > 16) invalidInput("Sandbox input exceeds structural bounds");
13
+ if (typeof value === "string") {
14
+ bytes += Buffer.byteLength(value, "utf8");
15
+ if (bytes > 1024 * 1024) invalidInput("Sandbox input exceeds text bounds");
16
+ if (!value.isWellFormed()) invalidInput("Sandbox strings must contain well-formed Unicode");
17
+ return value;
18
+ }
19
+ if (value === null || typeof value === "number" || typeof value === "boolean" || value === void 0) return value;
20
+ if (typeof value !== "object") invalidInput("Sandbox inputs must contain plain data");
21
+ if (seen.has(value)) invalidInput("Sandbox inputs cannot contain cycles");
22
+ seen.add(value);
23
+ const array = Array.isArray(value);
24
+ const prototype = Object.getPrototypeOf(value);
25
+ if (!array && prototype !== Object.prototype && prototype !== null) invalidInput("Sandbox inputs must contain plain objects");
26
+ const keys = Reflect.ownKeys(value);
27
+ if (keys.length > 8192) invalidInput("Sandbox input exceeds structural bounds");
28
+ if (array) {
29
+ const result2 = [];
30
+ for (let index = 0; index < value.length; index += 1) {
31
+ const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
32
+ if (descriptor === void 0 || !("value" in descriptor)) invalidInput("Sandbox arrays must be dense data arrays");
33
+ result2.push(capture(descriptor.value, depth + 1));
34
+ }
35
+ if (keys.length !== value.length + 1) invalidInput("Sandbox arrays cannot have extra properties");
36
+ seen.delete(value);
37
+ return result2;
38
+ }
39
+ const result = /* @__PURE__ */ Object.create(null);
40
+ for (const key of keys) {
41
+ if (typeof key !== "string") invalidInput("Sandbox inputs cannot contain symbol keys");
42
+ if (key === "__proto__") invalidInput("Sandbox inputs cannot contain prototype mutation keys");
43
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
44
+ if (descriptor === void 0 || !("value" in descriptor) || !descriptor.enumerable) invalidInput("Sandbox inputs cannot contain accessors or hidden fields");
45
+ result[key] = capture(descriptor.value, depth + 1);
46
+ }
47
+ seen.delete(value);
48
+ return result;
49
+ }
50
+ return capture(input, 0);
51
+ }
52
+ function freezeData(value) {
53
+ if (value !== null && typeof value === "object") {
54
+ if (Array.isArray(value)) value.forEach(freezeData);
55
+ else Object.values(value).forEach(freezeData);
56
+ Object.freeze(value);
57
+ }
58
+ return value;
59
+ }
60
+ function utf8Within(value, maximum) {
61
+ return value.isWellFormed() && Buffer.byteLength(value, "utf8") <= maximum;
62
+ }
63
+ export {
64
+ captureData,
65
+ freezeData,
66
+ invalidInput,
67
+ utf8Within
68
+ };
@@ -0,0 +1,4 @@
1
+ import type { OperationOptions, SandboxRunOptions } from '../contracts.js';
2
+ export declare function parseOperationOptions(input?: unknown): OperationOptions;
3
+ export declare function parseSandboxRunOptions(input: unknown): SandboxRunOptions;
4
+ //# sourceMappingURL=operations.d.ts.map
@@ -0,0 +1,30 @@
1
+ import { parseSandboxRecoveryPolicy } from "../recovery/parse.js";
2
+ import { invalidInput } from "./data.js";
3
+ function parseOperationOptions(input = void 0) {
4
+ if (input === void 0) return Object.freeze({});
5
+ if (input === null || typeof input !== "object" || Object.getPrototypeOf(input) !== Object.prototype && Object.getPrototypeOf(input) !== null) invalidInput("Operation options must be a plain object");
6
+ const keys = Reflect.ownKeys(input);
7
+ if (keys.some((key) => key !== "signal")) invalidInput("Operation options support only signal");
8
+ const descriptor = Object.getOwnPropertyDescriptor(input, "signal");
9
+ if (descriptor === void 0) return Object.freeze({});
10
+ if (!("value" in descriptor) || !descriptor.enumerable) invalidInput("Operation signal must be a data field");
11
+ const signal = descriptor.value;
12
+ if (signal === void 0) return Object.freeze({});
13
+ if (!(signal instanceof AbortSignal)) invalidInput("Operation signal must be an AbortSignal");
14
+ return Object.freeze({ signal });
15
+ }
16
+ function parseSandboxRunOptions(input) {
17
+ if (input === null || typeof input !== "object" || Object.getPrototypeOf(input) !== Object.prototype && Object.getPrototypeOf(input) !== null) invalidInput("Sandbox run options must be a plain object");
18
+ if (Reflect.ownKeys(input).some((key) => key !== "signal" && key !== "recovery")) invalidInput("Sandbox run options support only recovery and signal");
19
+ const descriptor = Object.getOwnPropertyDescriptor(input, "recovery");
20
+ if (descriptor === void 0 || !("value" in descriptor) || !descriptor.enumerable) invalidInput("Sandbox run options require an explicit recovery policy");
21
+ const recovery = parseSandboxRecoveryPolicy(descriptor.value);
22
+ const signal = Object.getOwnPropertyDescriptor(input, "signal");
23
+ if (signal === void 0) return Object.freeze({ recovery });
24
+ if (!("value" in signal) || !signal.enumerable) invalidInput("Operation signal must be a data field");
25
+ return Object.freeze({ ...parseOperationOptions({ signal: signal.value }), recovery });
26
+ }
27
+ export {
28
+ parseOperationOptions,
29
+ parseSandboxRunOptions
30
+ };
@@ -0,0 +1,3 @@
1
+ import type { ZodType } from 'zod/v4';
2
+ export declare function parseData<Value>(schema: ZodType<Value>, input: unknown): Value;
3
+ //# sourceMappingURL=parse.d.ts.map
@@ -0,0 +1,12 @@
1
+ import { normalizeZodValidationError } from "@agen-ai/validation/zod";
2
+ import { SandboxValidationError } from "../errors.js";
3
+ import { captureData, freezeData } from "./data.js";
4
+ function parseData(schema, input) {
5
+ const captured = captureData(input);
6
+ const result = schema.safeParse(captured);
7
+ if (!result.success) throw new SandboxValidationError(normalizeZodValidationError(schema, result.error, captured));
8
+ return freezeData(result.data);
9
+ }
10
+ export {
11
+ parseData
12
+ };
@@ -0,0 +1,3 @@
1
+ /** Slices an admitted finite duration without turning Node timer overflow into immediate expiry. */
2
+ export declare function scheduleDeadline(timeoutMs: number, expire: () => void): () => void;
3
+ //# sourceMappingURL=deadline.d.ts.map
@@ -0,0 +1,18 @@
1
+ const MAX_TIMER_DELAY_MS = 2147483647;
2
+ function scheduleDeadline(timeoutMs, expire) {
3
+ const started = performance.now();
4
+ let timer;
5
+ const check = () => {
6
+ const remaining = timeoutMs - (performance.now() - started);
7
+ if (remaining <= 0) {
8
+ expire();
9
+ return;
10
+ }
11
+ timer = setTimeout(check, Math.min(Math.ceil(remaining), MAX_TIMER_DELAY_MS));
12
+ };
13
+ timer = setTimeout(check, Math.min(timeoutMs, MAX_TIMER_DELAY_MS));
14
+ return () => clearTimeout(timer);
15
+ }
16
+ export {
17
+ scheduleDeadline
18
+ };
@@ -0,0 +1,14 @@
1
+ import type { SandboxRecoveryPolicy, SandboxRecoveryRecord } from '../recovery/types.js';
2
+ export declare class RecoveryJournal {
3
+ private readonly policy;
4
+ private readonly onFailure;
5
+ private tail;
6
+ private failure;
7
+ private record;
8
+ constructor(record: SandboxRecoveryRecord, policy: SandboxRecoveryPolicy, onFailure: (error: unknown) => void);
9
+ get current(): SandboxRecoveryRecord;
10
+ initialize(): Promise<void>;
11
+ checkpoint: (input: SandboxRecoveryRecord) => Promise<void>;
12
+ private fail;
13
+ }
14
+ //# sourceMappingURL=journal.d.ts.map
@@ -0,0 +1,51 @@
1
+ import { SandboxOperationError } from "../errors.js";
2
+ import { parseSandboxRecoveryRecord } from "../recovery/parse.js";
3
+ import { assertRecoveryContinuation } from "./recoveryIdentity.js";
4
+ class RecoveryJournal {
5
+ constructor(record, policy, onFailure) {
6
+ this.policy = policy;
7
+ this.onFailure = onFailure;
8
+ this.record = record;
9
+ }
10
+ tail = Promise.resolve();
11
+ failure;
12
+ record;
13
+ get current() {
14
+ return this.record;
15
+ }
16
+ initialize() {
17
+ return this.checkpoint(this.record);
18
+ }
19
+ checkpoint = (input) => {
20
+ let next;
21
+ try {
22
+ next = parseSandboxRecoveryRecord(input);
23
+ } catch (error) {
24
+ return this.fail(error);
25
+ }
26
+ const work = this.tail.then(async () => {
27
+ if (this.failure) throw this.failure.error;
28
+ assertRecoveryContinuation(this.record, next, "checkpoint");
29
+ this.record = next;
30
+ if (this.policy.kind === "persisted") await this.policy.persist(next);
31
+ }).catch((error) => {
32
+ if (!this.failure) {
33
+ this.failure = { error: new SandboxOperationError("persistence_failure", "Sandbox recovery checkpoint failed.", { cause: error }) };
34
+ this.onFailure(this.failure.error);
35
+ }
36
+ throw this.failure.error;
37
+ });
38
+ this.tail = work;
39
+ void work.catch(() => {
40
+ });
41
+ return work;
42
+ };
43
+ fail(error) {
44
+ this.failure ??= { error: new SandboxOperationError("persistence_failure", "Sandbox recovery checkpoint is invalid.", { cause: error }) };
45
+ this.onFailure(this.failure.error);
46
+ return Promise.reject(this.failure.error);
47
+ }
48
+ }
49
+ export {
50
+ RecoveryJournal
51
+ };
@@ -0,0 +1,9 @@
1
+ import { SandboxOperationError } from '../errors.js';
2
+ /** Limits a caller's wait without replacing or abandoning the actual operation. */
3
+ export declare function observe<T>(actual: Promise<T>, deadlineMs: number | undefined, options?: {
4
+ readonly signal?: AbortSignal;
5
+ readonly onInterrupt?: (error: SandboxOperationError) => void;
6
+ }): Promise<T>;
7
+ export declare function actualOperation<T>(perform: () => Promise<T>): Promise<T>;
8
+ export declare function settled(actual: Promise<unknown> | undefined): Promise<void>;
9
+ //# sourceMappingURL=observation.d.ts.map
@@ -0,0 +1,41 @@
1
+ import { SandboxOperationError } from "../errors.js";
2
+ import { scheduleDeadline } from "./deadline.js";
3
+ function observe(actual, deadlineMs, options = {}) {
4
+ return new Promise((resolve, reject) => {
5
+ let settled2 = false;
6
+ const finish = (complete) => {
7
+ if (settled2) return;
8
+ settled2 = true;
9
+ cancelDeadline?.();
10
+ options.signal?.removeEventListener("abort", abort);
11
+ complete();
12
+ };
13
+ const interrupt = (error) => finish(() => {
14
+ options.onInterrupt?.(error);
15
+ reject(error);
16
+ });
17
+ const abort = () => interrupt(options.signal?.reason instanceof SandboxOperationError ? options.signal.reason : new SandboxOperationError("cancelled", "Sandbox operation was cancelled."));
18
+ const cancelDeadline = deadlineMs === void 0 ? void 0 : scheduleDeadline(
19
+ deadlineMs,
20
+ () => interrupt(new SandboxOperationError("deadline_exceeded", "Sandbox operation exceeded its observation deadline."))
21
+ );
22
+ options.signal?.addEventListener("abort", abort, { once: true });
23
+ if (options.signal?.aborted) abort();
24
+ actual.then((value) => finish(() => resolve(value)), (error) => finish(() => reject(error)));
25
+ });
26
+ }
27
+ function actualOperation(perform) {
28
+ try {
29
+ return Promise.resolve(perform());
30
+ } catch (error) {
31
+ return Promise.reject(error);
32
+ }
33
+ }
34
+ function settled(actual) {
35
+ return actual?.then(() => void 0, () => void 0) ?? Promise.resolve();
36
+ }
37
+ export {
38
+ actualOperation,
39
+ observe,
40
+ settled
41
+ };
@@ -0,0 +1,38 @@
1
+ import type { SandboxDriverReservation } from '../backend/contracts.js';
2
+ import type { OperationOptions, Sandbox, SandboxReservation, SandboxState } from '../contracts.js';
3
+ import type { SandboxRequest } from '../policy/types.js';
4
+ import type { SandboxRecoveryPolicy, SandboxRecoveryRecord } from '../recovery/types.js';
5
+ export declare class SandboxOwner implements SandboxReservation {
6
+ private readonly driver;
7
+ private readonly request;
8
+ private snapshot;
9
+ private readonly journal;
10
+ private readonly startupController;
11
+ private startup;
12
+ private ready;
13
+ private transfer;
14
+ private processReserved;
15
+ private process;
16
+ private streams;
17
+ private cancelExecutionDeadline;
18
+ private stopActual;
19
+ private destroyActual;
20
+ private stopObservation;
21
+ private destroyObservation;
22
+ constructor(driver: SandboxDriverReservation, request: SandboxRequest, recovery: SandboxRecoveryPolicy, record: SandboxRecoveryRecord);
23
+ get id(): import("../index.js").SandboxId;
24
+ get state(): SandboxState;
25
+ get recoveryRecord(): SandboxRecoveryRecord;
26
+ start(input?: OperationOptions): Promise<Sandbox>;
27
+ stop(): Promise<void>;
28
+ destroy(): Promise<void>;
29
+ private beginStop;
30
+ private importTree;
31
+ private exportTree;
32
+ private enterFile;
33
+ private cleanupTransfer;
34
+ private reserveProcess;
35
+ private readyPort;
36
+ private fence;
37
+ }
38
+ //# sourceMappingURL=owner.d.ts.map