@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.
- package/LICENSE +21 -0
- package/README.md +141 -2
- package/dist/acp/index.d.ts +9 -0
- package/dist/acp/index.js +25 -0
- package/dist/backend/contracts.d.ts +41 -0
- package/dist/backend/contracts.js +0 -0
- package/dist/backend/index.d.ts +6 -0
- package/dist/backend/index.js +64 -0
- package/dist/backend/spill.d.ts +15 -0
- package/dist/backend/spill.js +0 -0
- package/dist/contracts.d.ts +37 -0
- package/dist/contracts.js +0 -0
- package/dist/errors.d.ts +46 -0
- package/dist/errors.js +73 -0
- package/dist/files/bytes.d.ts +31 -0
- package/dist/files/bytes.js +134 -0
- package/dist/files/iterator.d.ts +13 -0
- package/dist/files/iterator.js +59 -0
- package/dist/files/metadata/index.d.ts +12 -0
- package/dist/files/metadata/index.js +193 -0
- package/dist/files/metadata/records.d.ts +21 -0
- package/dist/files/metadata/records.js +50 -0
- package/dist/files/metadata/sort.d.ts +13 -0
- package/dist/files/metadata/sort.js +63 -0
- package/dist/files/metadata/storage.d.ts +12 -0
- package/dist/files/metadata/storage.js +69 -0
- package/dist/files/metadata/types.d.ts +19 -0
- package/dist/files/metadata/types.js +0 -0
- package/dist/files/parse.d.ts +20 -0
- package/dist/files/parse.js +62 -0
- package/dist/files/pathSchemas.d.ts +5 -0
- package/dist/files/pathSchemas.js +16 -0
- package/dist/files/paths.d.ts +4 -0
- package/dist/files/paths.js +12 -0
- package/dist/files/quotas.d.ts +18 -0
- package/dist/files/quotas.js +37 -0
- package/dist/files/types.d.ts +81 -0
- package/dist/files/types.js +0 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +35 -0
- package/dist/internal/data.d.ts +6 -0
- package/dist/internal/data.js +68 -0
- package/dist/internal/operations.d.ts +4 -0
- package/dist/internal/operations.js +30 -0
- package/dist/internal/parse.d.ts +3 -0
- package/dist/internal/parse.js +12 -0
- package/dist/lifecycle/deadline.d.ts +3 -0
- package/dist/lifecycle/deadline.js +18 -0
- package/dist/lifecycle/journal.d.ts +14 -0
- package/dist/lifecycle/journal.js +51 -0
- package/dist/lifecycle/observation.d.ts +9 -0
- package/dist/lifecycle/observation.js +41 -0
- package/dist/lifecycle/owner.d.ts +38 -0
- package/dist/lifecycle/owner.js +288 -0
- package/dist/lifecycle/recovered.d.ts +16 -0
- package/dist/lifecycle/recovered.js +62 -0
- package/dist/lifecycle/recoveryIdentity.d.ts +3 -0
- package/dist/lifecycle/recoveryIdentity.js +18 -0
- package/dist/lifecycle/transfer.d.ts +10 -0
- package/dist/lifecycle/transfer.js +339 -0
- package/dist/node/directories/closing.d.ts +2 -0
- package/dist/node/directories/closing.js +19 -0
- package/dist/node/directories/export.d.ts +6 -0
- package/dist/node/directories/export.js +43 -0
- package/dist/node/directories/file.d.ts +26 -0
- package/dist/node/directories/file.js +104 -0
- package/dist/node/directories/import.d.ts +6 -0
- package/dist/node/directories/import.js +38 -0
- package/dist/node/directories/options.d.ts +4 -0
- package/dist/node/directories/options.js +10 -0
- package/dist/node/directories/ownership.d.ts +33 -0
- package/dist/node/directories/ownership.js +148 -0
- package/dist/node/directories/source.d.ts +25 -0
- package/dist/node/directories/source.js +143 -0
- package/dist/node/directories/stage.d.ts +43 -0
- package/dist/node/directories/stage.js +302 -0
- package/dist/node/directories/types.d.ts +23 -0
- package/dist/node/directories/types.js +17 -0
- package/dist/node/hostPath.d.ts +7 -0
- package/dist/node/hostPath.js +37 -0
- package/dist/node/index.d.ts +8 -0
- package/dist/node/index.js +14 -0
- package/dist/node/spill.d.ts +14 -0
- package/dist/node/spill.js +97 -0
- package/dist/node/spillDirectory.d.ts +4 -0
- package/dist/node/spillDirectory.js +17 -0
- package/dist/node/spillFile.d.ts +24 -0
- package/dist/node/spillFile.js +96 -0
- package/dist/policy/limits.d.ts +31 -0
- package/dist/policy/limits.js +35 -0
- package/dist/policy/parse.d.ts +11 -0
- package/dist/policy/parse.js +47 -0
- package/dist/policy/schemas.d.ts +148 -0
- package/dist/policy/schemas.js +75 -0
- package/dist/policy/types.d.ts +105 -0
- package/dist/policy/types.js +0 -0
- package/dist/process/input.d.ts +23 -0
- package/dist/process/input.js +93 -0
- package/dist/process/output.d.ts +13 -0
- package/dist/process/output.js +43 -0
- package/dist/process/parse.d.ts +4 -0
- package/dist/process/parse.js +32 -0
- package/dist/process/streams.d.ts +9 -0
- package/dist/process/streams.js +61 -0
- package/dist/process/types.d.ts +38 -0
- package/dist/process/types.js +0 -0
- package/dist/recovery/parse.d.ts +4 -0
- package/dist/recovery/parse.js +67 -0
- package/dist/recovery/types.d.ts +59 -0
- package/dist/recovery/types.js +0 -0
- package/dist/withSandbox.d.ts +4 -0
- package/dist/withSandbox.js +39 -0
- package/package.json +76 -3
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
|
+
import { utf8Within } from "../internal/data.js";
|
|
3
|
+
import { SANDBOX_LIMITS } from "./limits.js";
|
|
4
|
+
const safeIdentity = (value, maximum) => typeof value === "string" && value.length > 0 && utf8Within(value, maximum) && !/[\u0000-\u0020\u007f/\\]/u.test(value);
|
|
5
|
+
const identitySchema = z.string().refine((value) => safeIdentity(value, SANDBOX_LIMITS.maxIdentityBytes), "Expected a bounded identity without whitespace or separators");
|
|
6
|
+
const namespaceSchema = z.custom((value) => safeIdentity(value, SANDBOX_LIMITS.maxNamespaceBytes), "Expected a bounded namespace");
|
|
7
|
+
const sandboxIdSchema = z.custom((value) => safeIdentity(value, SANDBOX_LIMITS.maxIdentityBytes), "Expected a bounded sandbox ID");
|
|
8
|
+
const processIdSchema = z.custom((value) => safeIdentity(value, SANDBOX_LIMITS.maxIdentityBytes), "Expected a bounded process ID");
|
|
9
|
+
const positiveInteger = z.number().int().positive().max(Number.MAX_SAFE_INTEGER);
|
|
10
|
+
const bounded = (maximum) => positiveInteger.max(maximum);
|
|
11
|
+
const resourcesSchema = z.strictObject({ cpus: z.number().finite().positive(), memoryBytes: positiveInteger, pids: positiveInteger });
|
|
12
|
+
const temporaryStorageSchema = z.strictObject({ homeBytes: positiveInteger, tempBytes: positiveInteger });
|
|
13
|
+
const networkSchema = z.discriminatedUnion("kind", [z.strictObject({ kind: z.literal("isolated") }), z.strictObject({ kind: z.literal("outbound") })]);
|
|
14
|
+
const noWorkspaceDiskQuotaSchema = z.strictObject({ kind: z.literal("not_requested") });
|
|
15
|
+
const workspaceDiskQuotaSchema = z.discriminatedUnion("kind", [
|
|
16
|
+
noWorkspaceDiskQuotaSchema,
|
|
17
|
+
z.strictObject({ kind: z.literal("required"), bytes: positiveInteger, accounting: z.literal("allocated_blocks") })
|
|
18
|
+
]);
|
|
19
|
+
const executionSchema = z.discriminatedUnion("kind", [
|
|
20
|
+
z.strictObject({ kind: z.literal("until_stopped") }),
|
|
21
|
+
z.strictObject({ kind: z.literal("deadline"), timeoutMs: positiveInteger })
|
|
22
|
+
]);
|
|
23
|
+
const transferBuffersSchema = z.strictObject({
|
|
24
|
+
chunkBytes: bounded(SANDBOX_LIMITS.maxTransferChunkBytes).min(512),
|
|
25
|
+
metadataBatchBytes: bounded(SANDBOX_LIMITS.maxMetadataBatchBytes).min(SANDBOX_LIMITS.maxPathBytes + 5),
|
|
26
|
+
metadataMergeFanIn: bounded(SANDBOX_LIMITS.maxMetadataMergeFanIn).min(2)
|
|
27
|
+
});
|
|
28
|
+
const streamLimitsSchema = z.strictObject({
|
|
29
|
+
maxStdinBytes: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER).optional(),
|
|
30
|
+
maxOutputBytes: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER).optional(),
|
|
31
|
+
maxBufferedInputBytes: bounded(SANDBOX_LIMITS.maxBufferedInputBytes),
|
|
32
|
+
maxBufferedOutputBytes: bounded(SANDBOX_LIMITS.maxBufferedOutputBytes),
|
|
33
|
+
highWaterMarkBytes: bounded(SANDBOX_LIMITS.highWaterMarkBytes)
|
|
34
|
+
}).refine((value) => value.highWaterMarkBytes <= value.maxBufferedOutputBytes && value.highWaterMarkBytes <= value.maxBufferedInputBytes, "Stream high-water mark must fit within its buffer bounds");
|
|
35
|
+
const policySchema = z.strictObject({
|
|
36
|
+
resources: resourcesSchema,
|
|
37
|
+
temporaryStorage: temporaryStorageSchema,
|
|
38
|
+
network: networkSchema,
|
|
39
|
+
workspaceDiskQuota: workspaceDiskQuotaSchema.default({ kind: "not_requested" }),
|
|
40
|
+
execution: executionSchema.default({ kind: "until_stopped" }),
|
|
41
|
+
deadlines: z.strictObject({ startupMs: bounded(SANDBOX_LIMITS.startupMs), cleanupMs: bounded(SANDBOX_LIMITS.cleanupMs) }),
|
|
42
|
+
transfers: transferBuffersSchema,
|
|
43
|
+
streams: streamLimitsSchema
|
|
44
|
+
});
|
|
45
|
+
const requestSchema = z.strictObject({ policy: policySchema });
|
|
46
|
+
const supportSchema = z.strictObject({
|
|
47
|
+
backendId: identitySchema,
|
|
48
|
+
backendRevision: identitySchema,
|
|
49
|
+
networkModes: z.array(z.enum(["isolated", "outbound"])).min(1).max(2).refine((modes) => new Set(modes).size === modes.length, "Network modes must be unique"),
|
|
50
|
+
workspaceDiskQuota: z.literal(false),
|
|
51
|
+
networkAllowlist: z.literal(false),
|
|
52
|
+
independentProcessTermination: z.literal(false)
|
|
53
|
+
});
|
|
54
|
+
const effectiveSchema = z.strictObject({
|
|
55
|
+
backendIdentity: identitySchema,
|
|
56
|
+
isolation: z.enum(["container", "virtual_machine"]),
|
|
57
|
+
resources: resourcesSchema,
|
|
58
|
+
temporaryStorage: temporaryStorageSchema,
|
|
59
|
+
network: networkSchema,
|
|
60
|
+
nonRoot: z.literal(true),
|
|
61
|
+
readOnlyRoot: z.literal(true),
|
|
62
|
+
workspaceDiskQuota: noWorkspaceDiskQuotaSchema
|
|
63
|
+
});
|
|
64
|
+
export {
|
|
65
|
+
effectiveSchema,
|
|
66
|
+
identitySchema,
|
|
67
|
+
namespaceSchema,
|
|
68
|
+
policySchema,
|
|
69
|
+
processIdSchema,
|
|
70
|
+
requestSchema,
|
|
71
|
+
sandboxIdSchema,
|
|
72
|
+
streamLimitsSchema,
|
|
73
|
+
supportSchema,
|
|
74
|
+
transferBuffersSchema
|
|
75
|
+
};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
declare const namespaceBrand: unique symbol;
|
|
2
|
+
declare const sandboxIdBrand: unique symbol;
|
|
3
|
+
declare const processIdBrand: unique symbol;
|
|
4
|
+
export type SandboxNamespace = string & {
|
|
5
|
+
readonly [namespaceBrand]: true;
|
|
6
|
+
};
|
|
7
|
+
export type SandboxId = string & {
|
|
8
|
+
readonly [sandboxIdBrand]: true;
|
|
9
|
+
};
|
|
10
|
+
export type SandboxProcessId = string & {
|
|
11
|
+
readonly [processIdBrand]: true;
|
|
12
|
+
};
|
|
13
|
+
export interface SandboxResources {
|
|
14
|
+
readonly cpus: number;
|
|
15
|
+
readonly memoryBytes: number;
|
|
16
|
+
readonly pids: number;
|
|
17
|
+
}
|
|
18
|
+
export interface SandboxTemporaryStorage {
|
|
19
|
+
readonly homeBytes: number;
|
|
20
|
+
readonly tempBytes: number;
|
|
21
|
+
}
|
|
22
|
+
export type SandboxNetworkPolicy = Readonly<{
|
|
23
|
+
kind: 'isolated';
|
|
24
|
+
}> | Readonly<{
|
|
25
|
+
kind: 'outbound';
|
|
26
|
+
}>;
|
|
27
|
+
export type SandboxWorkspaceDiskQuota = Readonly<{
|
|
28
|
+
kind: 'not_requested';
|
|
29
|
+
}>
|
|
30
|
+
/** Allocated filesystem blocks; this does not request inode or logical-file-size enforcement. */
|
|
31
|
+
| Readonly<{
|
|
32
|
+
kind: 'required';
|
|
33
|
+
bytes: number;
|
|
34
|
+
accounting: 'allocated_blocks';
|
|
35
|
+
}>;
|
|
36
|
+
export type SandboxExecutionPolicy = Readonly<{
|
|
37
|
+
kind: 'until_stopped';
|
|
38
|
+
}>
|
|
39
|
+
/** Starts at process launch entry; withSandbox also bounds its callback by this duration. */
|
|
40
|
+
| Readonly<{
|
|
41
|
+
kind: 'deadline';
|
|
42
|
+
timeoutMs: number;
|
|
43
|
+
}>;
|
|
44
|
+
export interface SandboxDeadlines {
|
|
45
|
+
readonly startupMs: number;
|
|
46
|
+
readonly cleanupMs: number;
|
|
47
|
+
}
|
|
48
|
+
export interface SandboxPolicy {
|
|
49
|
+
readonly resources: SandboxResources;
|
|
50
|
+
readonly temporaryStorage: SandboxTemporaryStorage;
|
|
51
|
+
readonly network: SandboxNetworkPolicy;
|
|
52
|
+
readonly workspaceDiskQuota: SandboxWorkspaceDiskQuota;
|
|
53
|
+
readonly execution: SandboxExecutionPolicy;
|
|
54
|
+
readonly deadlines: SandboxDeadlines;
|
|
55
|
+
readonly transfers: SandboxTransferBuffers;
|
|
56
|
+
readonly streams: SandboxStreamLimits;
|
|
57
|
+
}
|
|
58
|
+
export type SandboxPolicyInput = Omit<SandboxPolicy, 'execution' | 'workspaceDiskQuota'> & {
|
|
59
|
+
/** Omission normalizes to until_stopped, with no execution timer. */
|
|
60
|
+
readonly execution?: SandboxExecutionPolicy;
|
|
61
|
+
/** Omission requests no hard workspace disk quota. Backend storage limits remain independent. */
|
|
62
|
+
readonly workspaceDiskQuota?: SandboxWorkspaceDiskQuota;
|
|
63
|
+
};
|
|
64
|
+
export interface SandboxRequestInput {
|
|
65
|
+
readonly policy: SandboxPolicyInput;
|
|
66
|
+
}
|
|
67
|
+
export interface SandboxRequest {
|
|
68
|
+
readonly policy: SandboxPolicy;
|
|
69
|
+
}
|
|
70
|
+
export interface SandboxTransferBuffers {
|
|
71
|
+
readonly chunkBytes: number;
|
|
72
|
+
readonly metadataBatchBytes: number;
|
|
73
|
+
readonly metadataMergeFanIn: number;
|
|
74
|
+
}
|
|
75
|
+
export interface SandboxStreamLimits {
|
|
76
|
+
readonly maxStdinBytes?: number;
|
|
77
|
+
readonly maxOutputBytes?: number;
|
|
78
|
+
/** Public stdin staging, including writes made without respecting backpressure. */
|
|
79
|
+
readonly maxBufferedInputBytes: number;
|
|
80
|
+
/** Combined public stdout/stderr staging; backend transport buffers are bounded separately. */
|
|
81
|
+
readonly maxBufferedOutputBytes: number;
|
|
82
|
+
readonly highWaterMarkBytes: number;
|
|
83
|
+
}
|
|
84
|
+
export interface SandboxSupport {
|
|
85
|
+
readonly backendId: string;
|
|
86
|
+
readonly backendRevision: string;
|
|
87
|
+
readonly networkModes: readonly SandboxNetworkPolicy['kind'][];
|
|
88
|
+
readonly workspaceDiskQuota: false;
|
|
89
|
+
readonly networkAllowlist: false;
|
|
90
|
+
readonly independentProcessTermination: false;
|
|
91
|
+
}
|
|
92
|
+
export interface SandboxEffectivePolicy {
|
|
93
|
+
readonly backendIdentity: string;
|
|
94
|
+
readonly isolation: 'container' | 'virtual_machine';
|
|
95
|
+
readonly resources: SandboxResources;
|
|
96
|
+
readonly temporaryStorage: SandboxTemporaryStorage;
|
|
97
|
+
readonly network: SandboxNetworkPolicy;
|
|
98
|
+
readonly nonRoot: true;
|
|
99
|
+
readonly readOnlyRoot: true;
|
|
100
|
+
readonly workspaceDiskQuota: Readonly<{
|
|
101
|
+
kind: 'not_requested';
|
|
102
|
+
}>;
|
|
103
|
+
}
|
|
104
|
+
export {};
|
|
105
|
+
//# sourceMappingURL=types.d.ts.map
|
|
File without changes
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Writable } from 'node:stream';
|
|
2
|
+
type WriteCallback = (error?: Error | null) => void;
|
|
3
|
+
export declare class SandboxInput extends Writable {
|
|
4
|
+
private readonly target;
|
|
5
|
+
private readonly maximumBytes;
|
|
6
|
+
private readonly maximumBufferedBytes;
|
|
7
|
+
private readonly fail;
|
|
8
|
+
readonly settled: Promise<void>;
|
|
9
|
+
private admitted;
|
|
10
|
+
private closing;
|
|
11
|
+
private activeWrite;
|
|
12
|
+
constructor(target: Writable, maximumBytes: number | undefined, maximumBufferedBytes: number, highWaterMark: number, fail: (error: Error) => void);
|
|
13
|
+
write(chunk: unknown, encodingOrCallback?: BufferEncoding | WriteCallback, callback?: WriteCallback): boolean;
|
|
14
|
+
end(chunkOrCallback?: unknown, encodingOrCallback?: BufferEncoding | (() => void), callback?: () => void): this;
|
|
15
|
+
_write(chunk: Uint8Array, _encoding: BufferEncoding, callback: WriteCallback): void;
|
|
16
|
+
_final(callback: WriteCallback): void;
|
|
17
|
+
_destroy(error: Error | null, callback: WriteCallback): void;
|
|
18
|
+
close(error?: Error): void;
|
|
19
|
+
private admit;
|
|
20
|
+
private ownCallback;
|
|
21
|
+
}
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=input.d.ts.map
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { Writable } from "node:stream";
|
|
2
|
+
import { finished } from "node:stream/promises";
|
|
3
|
+
import { SandboxOperationError } from "../errors.js";
|
|
4
|
+
class SandboxInput extends Writable {
|
|
5
|
+
constructor(target, maximumBytes, maximumBufferedBytes, highWaterMark, fail) {
|
|
6
|
+
super({ highWaterMark, decodeStrings: false });
|
|
7
|
+
this.target = target;
|
|
8
|
+
this.maximumBytes = maximumBytes;
|
|
9
|
+
this.maximumBufferedBytes = maximumBufferedBytes;
|
|
10
|
+
this.fail = fail;
|
|
11
|
+
this.settled = finished(target, { readable: false, cleanup: true }).then(() => void 0, () => void 0);
|
|
12
|
+
this.on("error", () => {
|
|
13
|
+
});
|
|
14
|
+
target.on("error", (error) => this.destroy(error));
|
|
15
|
+
target.on("close", () => {
|
|
16
|
+
if (!this.writableFinished) this.destroy();
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
settled;
|
|
20
|
+
admitted = 0n;
|
|
21
|
+
closing = false;
|
|
22
|
+
activeWrite;
|
|
23
|
+
write(chunk, encodingOrCallback, callback) {
|
|
24
|
+
const complete = typeof encodingOrCallback === "function" ? encodingOrCallback : callback;
|
|
25
|
+
const error = this.admit(chunk);
|
|
26
|
+
if (error) {
|
|
27
|
+
if (complete) queueMicrotask(() => complete(error));
|
|
28
|
+
this.destroy(error);
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
return typeof encodingOrCallback === "string" ? super.write(chunk, encodingOrCallback, callback) : super.write(chunk, complete);
|
|
32
|
+
}
|
|
33
|
+
end(chunkOrCallback, encodingOrCallback, callback) {
|
|
34
|
+
if (typeof chunkOrCallback === "function") return super.end(chunkOrCallback);
|
|
35
|
+
const complete = typeof encodingOrCallback === "function" ? encodingOrCallback : callback;
|
|
36
|
+
if (chunkOrCallback !== void 0 && chunkOrCallback !== null) this.write(chunkOrCallback);
|
|
37
|
+
return super.end(complete);
|
|
38
|
+
}
|
|
39
|
+
_write(chunk, _encoding, callback) {
|
|
40
|
+
const complete = this.ownCallback(callback);
|
|
41
|
+
try {
|
|
42
|
+
this.target.write(chunk, complete);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
complete(error instanceof Error ? error : new SandboxOperationError("stream_failure", "Sandbox input failed.", { cause: error }));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
_final(callback) {
|
|
48
|
+
const complete = this.ownCallback(callback);
|
|
49
|
+
try {
|
|
50
|
+
this.target.end(complete);
|
|
51
|
+
} catch (error) {
|
|
52
|
+
complete(error instanceof Error ? error : new SandboxOperationError("stream_failure", "Sandbox input failed.", { cause: error }));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
_destroy(error, callback) {
|
|
56
|
+
this.activeWrite?.(error ?? new SandboxOperationError("cancelled", "Sandbox input was closed before its pending write settled."));
|
|
57
|
+
this.target.destroy(error ?? void 0);
|
|
58
|
+
if (!this.closing && (!this.writableFinished || error)) {
|
|
59
|
+
this.fail(error ?? new SandboxOperationError("stream_failure", "Sandbox input was abandoned."));
|
|
60
|
+
}
|
|
61
|
+
callback(error);
|
|
62
|
+
}
|
|
63
|
+
close(error) {
|
|
64
|
+
this.closing = true;
|
|
65
|
+
this.destroy(error);
|
|
66
|
+
}
|
|
67
|
+
admit(chunk) {
|
|
68
|
+
if (!(chunk instanceof Uint8Array)) return new SandboxOperationError("stream_failure", "Sandbox stdin accepts only binary byte chunks.");
|
|
69
|
+
if (chunk.byteLength > this.maximumBufferedBytes - this.writableLength) {
|
|
70
|
+
return new SandboxOperationError("input_limit", "Sandbox stdin exceeded its buffered byte limit.");
|
|
71
|
+
}
|
|
72
|
+
const next = this.admitted + BigInt(chunk.byteLength);
|
|
73
|
+
if (this.maximumBytes !== void 0 && next > BigInt(this.maximumBytes)) {
|
|
74
|
+
return new SandboxOperationError("input_limit", "Sandbox stdin exceeded its caller-selected lifetime byte limit.");
|
|
75
|
+
}
|
|
76
|
+
this.admitted = next;
|
|
77
|
+
return void 0;
|
|
78
|
+
}
|
|
79
|
+
ownCallback(callback) {
|
|
80
|
+
let settled = false;
|
|
81
|
+
const complete = (error) => {
|
|
82
|
+
if (settled) return;
|
|
83
|
+
settled = true;
|
|
84
|
+
this.activeWrite = void 0;
|
|
85
|
+
callback(error);
|
|
86
|
+
};
|
|
87
|
+
this.activeWrite = complete;
|
|
88
|
+
return complete;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
export {
|
|
92
|
+
SandboxInput
|
|
93
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Readable } from 'node:stream';
|
|
2
|
+
export declare class SandboxOutput extends Readable {
|
|
3
|
+
private readonly abandoned;
|
|
4
|
+
private demand;
|
|
5
|
+
private complete;
|
|
6
|
+
constructor(highWaterMark: number, abandoned: (error: Error) => void);
|
|
7
|
+
_read(): void;
|
|
8
|
+
deliver(chunk: Uint8Array): Promise<void>;
|
|
9
|
+
finish(): void;
|
|
10
|
+
close(error?: Error): void;
|
|
11
|
+
_destroy(error: Error | null, callback: (error?: Error | null) => void): void;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=output.d.ts.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Readable } from "node:stream";
|
|
2
|
+
import { SandboxOperationError } from "../errors.js";
|
|
3
|
+
class SandboxOutput extends Readable {
|
|
4
|
+
constructor(highWaterMark, abandoned) {
|
|
5
|
+
super({ highWaterMark });
|
|
6
|
+
this.abandoned = abandoned;
|
|
7
|
+
this.on("error", () => {
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
demand;
|
|
11
|
+
complete = false;
|
|
12
|
+
_read() {
|
|
13
|
+
this.demand?.();
|
|
14
|
+
this.demand = void 0;
|
|
15
|
+
}
|
|
16
|
+
async deliver(chunk) {
|
|
17
|
+
if (this.destroyed) throw new SandboxOperationError("stream_failure", "Sandbox output is closed.");
|
|
18
|
+
const demand = Promise.withResolvers();
|
|
19
|
+
this.demand = demand.resolve;
|
|
20
|
+
if (this.push(chunk) || this.readableLength < this.readableHighWaterMark) {
|
|
21
|
+
this.demand = void 0;
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
await demand.promise;
|
|
25
|
+
}
|
|
26
|
+
finish() {
|
|
27
|
+
this.complete = true;
|
|
28
|
+
this.push(null);
|
|
29
|
+
}
|
|
30
|
+
close(error) {
|
|
31
|
+
this.complete = true;
|
|
32
|
+
this.destroy(error);
|
|
33
|
+
}
|
|
34
|
+
_destroy(error, callback) {
|
|
35
|
+
this.demand?.();
|
|
36
|
+
this.demand = void 0;
|
|
37
|
+
if (!this.complete) this.abandoned(error ?? new SandboxOperationError("stream_failure", "Sandbox output reader was abandoned."));
|
|
38
|
+
callback(error);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export {
|
|
42
|
+
SandboxOutput
|
|
43
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { SandboxProcessExit, SandboxProcessSpec } from './types.js';
|
|
2
|
+
export declare function parseSandboxProcessSpec(input: unknown): SandboxProcessSpec;
|
|
3
|
+
export declare function parseSandboxProcessExit(input: unknown): SandboxProcessExit;
|
|
4
|
+
//# sourceMappingURL=parse.d.ts.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Buffer } from "node:buffer";
|
|
2
|
+
import { z } from "zod/v4";
|
|
3
|
+
import { guestPathSchema } from "../files/pathSchemas.js";
|
|
4
|
+
import { utf8Within } from "../internal/data.js";
|
|
5
|
+
import { parseData } from "../internal/parse.js";
|
|
6
|
+
import { SANDBOX_LIMITS } from "../policy/limits.js";
|
|
7
|
+
const argumentSchema = z.string().refine((value) => !value.includes("\0") && utf8Within(value, SANDBOX_LIMITS.maxRecipeBytes), "Process arguments must be bounded and NUL-free");
|
|
8
|
+
const environmentSchema = z.record(
|
|
9
|
+
z.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/u).max(SANDBOX_LIMITS.maxIdentityBytes),
|
|
10
|
+
z.string().refine((value) => !value.includes("\0") && utf8Within(value, SANDBOX_LIMITS.maxEnvValueBytes), "Environment values must be bounded and NUL-free")
|
|
11
|
+
).refine((value) => Object.keys(value).length <= SANDBOX_LIMITS.maxEnvEntries, "Too many explicit environment entries");
|
|
12
|
+
const processSchema = z.strictObject({
|
|
13
|
+
executable: guestPathSchema,
|
|
14
|
+
args: z.array(argumentSchema).max(SANDBOX_LIMITS.maxArgs),
|
|
15
|
+
env: environmentSchema,
|
|
16
|
+
cwd: guestPathSchema
|
|
17
|
+
}).refine((value) => Buffer.byteLength(JSON.stringify(value), "utf8") <= SANDBOX_LIMITS.maxRecipeBytes, "Process recipe exceeds its aggregate UTF-8 bound");
|
|
18
|
+
const exitSchema = z.discriminatedUnion("kind", [
|
|
19
|
+
z.strictObject({ kind: z.literal("exited"), code: z.number().int().min(0).max(255) }),
|
|
20
|
+
z.strictObject({ kind: z.literal("signaled"), signal: z.string().regex(/^SIG[A-Z0-9]+$/u).max(64) }),
|
|
21
|
+
z.strictObject({ kind: z.literal("unavailable"), reason: z.literal("sandbox_stopped") })
|
|
22
|
+
]);
|
|
23
|
+
function parseSandboxProcessSpec(input) {
|
|
24
|
+
return parseData(processSchema, input);
|
|
25
|
+
}
|
|
26
|
+
function parseSandboxProcessExit(input) {
|
|
27
|
+
return parseData(exitSchema, input);
|
|
28
|
+
}
|
|
29
|
+
export {
|
|
30
|
+
parseSandboxProcessExit,
|
|
31
|
+
parseSandboxProcessSpec
|
|
32
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { SandboxStreamLimits } from '../policy/types.js';
|
|
2
|
+
import type { SandboxProcessStreams } from './types.js';
|
|
3
|
+
export interface OwnedProcessStreams {
|
|
4
|
+
readonly streams: SandboxProcessStreams;
|
|
5
|
+
readonly settled: Promise<void>;
|
|
6
|
+
close(error?: Error): void;
|
|
7
|
+
}
|
|
8
|
+
export declare function ownProcessStreams(raw: SandboxProcessStreams, limits: SandboxStreamLimits, onFailure: (error: Error) => void): OwnedProcessStreams;
|
|
9
|
+
//# sourceMappingURL=streams.d.ts.map
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Readable, Writable } from "node:stream";
|
|
2
|
+
import { SandboxOperationError } from "../errors.js";
|
|
3
|
+
import { parseSandboxProcessExit } from "./parse.js";
|
|
4
|
+
import { SandboxInput } from "./input.js";
|
|
5
|
+
import { SandboxOutput } from "./output.js";
|
|
6
|
+
function ownProcessStreams(raw, limits, onFailure) {
|
|
7
|
+
if (!(raw.stdin instanceof Writable) || !(raw.stdout instanceof Readable) || !(raw.stderr instanceof Readable) || raw.stdin.writableObjectMode || raw.stdout.readableObjectMode || raw.stderr.readableObjectMode || raw.stdout.readableEncoding !== null || raw.stderr.readableEncoding !== null) {
|
|
8
|
+
throw new SandboxOperationError("stream_failure", "The backend must supply distinct binary Node stdin, stdout and stderr streams.");
|
|
9
|
+
}
|
|
10
|
+
if (Object.is(raw.stdout, raw.stderr) || Object.is(raw.stdin, raw.stdout) || Object.is(raw.stdin, raw.stderr)) {
|
|
11
|
+
throw new SandboxOperationError("stream_failure", "Sandbox standard streams must remain separate.");
|
|
12
|
+
}
|
|
13
|
+
let outputBytes = 0n;
|
|
14
|
+
let closed = false;
|
|
15
|
+
let failure;
|
|
16
|
+
const fail = (error) => {
|
|
17
|
+
if (closed || failure) return;
|
|
18
|
+
failure = error;
|
|
19
|
+
close(error);
|
|
20
|
+
onFailure(error);
|
|
21
|
+
};
|
|
22
|
+
const stdin = new SandboxInput(raw.stdin, limits.maxStdinBytes, limits.maxBufferedInputBytes, limits.highWaterMarkBytes, fail);
|
|
23
|
+
const stdout = new SandboxOutput(limits.highWaterMarkBytes, fail);
|
|
24
|
+
const stderr = new SandboxOutput(limits.highWaterMarkBytes, fail);
|
|
25
|
+
const close = (error) => {
|
|
26
|
+
if (closed) return;
|
|
27
|
+
closed = true;
|
|
28
|
+
stdin.close(error);
|
|
29
|
+
stdout.close(error);
|
|
30
|
+
stderr.close(error);
|
|
31
|
+
raw.stdout.destroy(error);
|
|
32
|
+
raw.stderr.destroy(error);
|
|
33
|
+
};
|
|
34
|
+
const pump = async (source, target) => {
|
|
35
|
+
try {
|
|
36
|
+
for await (const chunk of source) {
|
|
37
|
+
if (closed) return;
|
|
38
|
+
if (!(chunk instanceof Uint8Array)) throw new SandboxOperationError("stream_failure", "Backend output contained a non-binary chunk.");
|
|
39
|
+
if (limits.maxOutputBytes !== void 0 && outputBytes + BigInt(chunk.byteLength) > BigInt(limits.maxOutputBytes)) {
|
|
40
|
+
throw new SandboxOperationError("output_limit", "Sandbox output exceeded its caller-selected combined lifetime byte limit.");
|
|
41
|
+
}
|
|
42
|
+
if (chunk.byteLength + stdout.readableLength + stderr.readableLength > limits.maxBufferedOutputBytes) {
|
|
43
|
+
throw new SandboxOperationError("output_limit", "Sandbox output exceeded its aggregate buffered byte limit.");
|
|
44
|
+
}
|
|
45
|
+
outputBytes += BigInt(chunk.byteLength);
|
|
46
|
+
await target.deliver(chunk);
|
|
47
|
+
}
|
|
48
|
+
if (!closed) target.finish();
|
|
49
|
+
} catch (error) {
|
|
50
|
+
if (!closed) fail(error instanceof Error ? error : new SandboxOperationError("stream_failure", "Sandbox output failed.", { cause: error }));
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
const pumps = Promise.all([pump(raw.stdout, stdout), pump(raw.stderr, stderr)]).then(() => void 0);
|
|
54
|
+
const exit = Promise.resolve(raw.exit).then(parseSandboxProcessExit);
|
|
55
|
+
void exit.catch((error) => fail(error instanceof Error ? error : new SandboxOperationError("driver_failure", "Sandbox leader exit failed.", { cause: error })));
|
|
56
|
+
const settled = Promise.all([pumps, stdin.settled, exit.then(() => void 0, () => void 0)]).then(() => void 0);
|
|
57
|
+
return Object.freeze({ streams: Object.freeze({ stdin, stdout, stderr, exit }), settled, close });
|
|
58
|
+
}
|
|
59
|
+
export {
|
|
60
|
+
ownProcessStreams
|
|
61
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Readable, Writable } from 'node:stream';
|
|
2
|
+
import type { OperationOptions } from '../contracts.js';
|
|
3
|
+
import type { SandboxGuestPath } from '../files/types.js';
|
|
4
|
+
import type { SandboxProcessId } from '../policy/types.js';
|
|
5
|
+
export interface SandboxProcessInput {
|
|
6
|
+
readonly executable: string;
|
|
7
|
+
readonly args: readonly string[];
|
|
8
|
+
readonly env: Readonly<Record<string, string>>;
|
|
9
|
+
readonly cwd: string;
|
|
10
|
+
}
|
|
11
|
+
export interface SandboxProcessSpec extends Omit<SandboxProcessInput, 'executable' | 'cwd'> {
|
|
12
|
+
readonly executable: SandboxGuestPath;
|
|
13
|
+
readonly cwd: SandboxGuestPath;
|
|
14
|
+
}
|
|
15
|
+
export type SandboxProcessExit = Readonly<{
|
|
16
|
+
kind: 'exited';
|
|
17
|
+
code: number;
|
|
18
|
+
}> | Readonly<{
|
|
19
|
+
kind: 'signaled';
|
|
20
|
+
signal: string;
|
|
21
|
+
}> | Readonly<{
|
|
22
|
+
kind: 'unavailable';
|
|
23
|
+
reason: 'sandbox_stopped';
|
|
24
|
+
}>;
|
|
25
|
+
export interface SandboxProcessStreams {
|
|
26
|
+
readonly stdin: Writable;
|
|
27
|
+
readonly stdout: Readable;
|
|
28
|
+
readonly stderr: Readable;
|
|
29
|
+
/** The leader's exit observation does not establish descendant quiescence. */
|
|
30
|
+
readonly exit: Promise<SandboxProcessExit>;
|
|
31
|
+
}
|
|
32
|
+
export interface SandboxProcessReservation {
|
|
33
|
+
readonly id: SandboxProcessId;
|
|
34
|
+
readonly stopScope: 'sandbox';
|
|
35
|
+
start(options?: OperationOptions): Promise<SandboxProcessStreams>;
|
|
36
|
+
stop(): Promise<void>;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=types.d.ts.map
|
|
File without changes
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { SandboxRecoveryPolicy, SandboxRecoveryRecord } from './types.js';
|
|
2
|
+
export declare function parseSandboxRecoveryRecord(input: unknown): SandboxRecoveryRecord;
|
|
3
|
+
export declare function parseSandboxRecoveryPolicy(input: unknown): SandboxRecoveryPolicy;
|
|
4
|
+
//# sourceMappingURL=parse.d.ts.map
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Buffer } from "node:buffer";
|
|
2
|
+
import { z } from "zod/v4";
|
|
3
|
+
import { SandboxValidationError } from "../errors.js";
|
|
4
|
+
import { captureData, invalidInput } from "../internal/data.js";
|
|
5
|
+
import { parseData } from "../internal/parse.js";
|
|
6
|
+
import { SANDBOX_LIMITS } from "../policy/limits.js";
|
|
7
|
+
import { identitySchema, namespaceSchema, sandboxIdSchema } from "../policy/schemas.js";
|
|
8
|
+
const digestSchema = z.string().regex(/^sha256:[a-f0-9]{64}$/u);
|
|
9
|
+
const resourceSchema = z.strictObject({
|
|
10
|
+
role: z.enum(["compute", "storage", "export", "network"]),
|
|
11
|
+
name: identitySchema,
|
|
12
|
+
identity: z.discriminatedUnion("kind", [
|
|
13
|
+
z.strictObject({ kind: z.literal("planned") }),
|
|
14
|
+
z.strictObject({ kind: z.literal("creating") }),
|
|
15
|
+
z.strictObject({ kind: z.literal("identified"), id: identitySchema, fingerprint: digestSchema })
|
|
16
|
+
])
|
|
17
|
+
});
|
|
18
|
+
const recoverySchema = z.strictObject({
|
|
19
|
+
format: z.literal("agenai.sandbox-recovery.v2"),
|
|
20
|
+
backendId: identitySchema,
|
|
21
|
+
backendRevision: identitySchema,
|
|
22
|
+
namespace: namespaceSchema,
|
|
23
|
+
operationId: identitySchema,
|
|
24
|
+
sandboxId: sandboxIdSchema,
|
|
25
|
+
imageDigest: digestSchema,
|
|
26
|
+
policyDigest: digestSchema,
|
|
27
|
+
configurationDigest: digestSchema,
|
|
28
|
+
phase: z.enum(["reserved", "starting", "running", "stopping", "stopped", "destroying", "destroyed", "uncertain"]),
|
|
29
|
+
authority: z.discriminatedUnion("kind", [
|
|
30
|
+
z.strictObject({ kind: z.literal("unverified") }),
|
|
31
|
+
z.strictObject({ kind: z.literal("verified"), backendIdentity: identitySchema })
|
|
32
|
+
]),
|
|
33
|
+
resources: z.array(resourceSchema).min(1).max(4)
|
|
34
|
+
}).superRefine((record, context) => {
|
|
35
|
+
if (new Set(record.resources.map((resource) => resource.role)).size !== record.resources.length) context.addIssue({ code: "custom", path: ["resources"], message: "Recovery resource roles must be unique" });
|
|
36
|
+
if (new Set(record.resources.map((resource) => resource.name)).size !== record.resources.length) context.addIssue({ code: "custom", path: ["resources"], message: "Recovery resource names must be unique" });
|
|
37
|
+
if (record.authority.kind === "unverified" && (record.phase !== "reserved" || record.resources.some((resource) => resource.identity.kind !== "planned"))) {
|
|
38
|
+
context.addIssue({ code: "custom", path: ["authority"], message: "Entered resource operations require verified backend authority" });
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
function parseSandboxRecoveryRecord(input) {
|
|
42
|
+
const captured = captureData(input);
|
|
43
|
+
const serialized = JSON.stringify(captured);
|
|
44
|
+
if (serialized === void 0 || Buffer.byteLength(serialized, "utf8") > SANDBOX_LIMITS.maxRecoveryBytes) invalidInput("Recovery record exceeds its serialized UTF-8 bound");
|
|
45
|
+
return parseData(recoverySchema, captured);
|
|
46
|
+
}
|
|
47
|
+
function parseSandboxRecoveryPolicy(input) {
|
|
48
|
+
if (input === null || typeof input !== "object" || Object.getPrototypeOf(input) !== Object.prototype && Object.getPrototypeOf(input) !== null) invalidInput("Recovery policy must be a plain object");
|
|
49
|
+
const keys = Reflect.ownKeys(input);
|
|
50
|
+
const kind = Object.getOwnPropertyDescriptor(input, "kind");
|
|
51
|
+
if (kind === void 0 || !("value" in kind)) invalidInput("Recovery policy requires a data kind");
|
|
52
|
+
if (kind.value === "in_process" && keys.length === 1) return Object.freeze({ kind: "in_process" });
|
|
53
|
+
const persist = Object.getOwnPropertyDescriptor(input, "persist");
|
|
54
|
+
if (kind.value !== "persisted" || keys.length !== 2 || persist === void 0 || !("value" in persist) || typeof persist.value !== "function") invalidInput("Persisted recovery requires only a persist function");
|
|
55
|
+
const callback = persist.value;
|
|
56
|
+
return Object.freeze({ kind: "persisted", async persist(record) {
|
|
57
|
+
const result = callback(record);
|
|
58
|
+
if (result === null || typeof result !== "object" || !("then" in result) || typeof result.then !== "function") {
|
|
59
|
+
throw new SandboxValidationError([{ code: "invalid_input", path: ["persist"], message: "Recovery persistence must return a promise" }]);
|
|
60
|
+
}
|
|
61
|
+
await result;
|
|
62
|
+
} });
|
|
63
|
+
}
|
|
64
|
+
export {
|
|
65
|
+
parseSandboxRecoveryPolicy,
|
|
66
|
+
parseSandboxRecoveryRecord
|
|
67
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { SandboxId, SandboxNamespace } from '../policy/types.js';
|
|
2
|
+
export type SandboxRecoveryPhase = 'reserved' | 'starting' | 'running' | 'stopping' | 'stopped' | 'destroying' | 'destroyed' | 'uncertain';
|
|
3
|
+
export type SandboxResourceIdentity = Readonly<{
|
|
4
|
+
kind: 'planned';
|
|
5
|
+
}> | Readonly<{
|
|
6
|
+
kind: 'creating';
|
|
7
|
+
}> | Readonly<{
|
|
8
|
+
kind: 'identified';
|
|
9
|
+
id: string;
|
|
10
|
+
fingerprint: string;
|
|
11
|
+
}>;
|
|
12
|
+
export interface SandboxRecoveryResource {
|
|
13
|
+
readonly role: 'compute' | 'storage' | 'export' | 'network';
|
|
14
|
+
readonly name: string;
|
|
15
|
+
readonly identity: SandboxResourceIdentity;
|
|
16
|
+
}
|
|
17
|
+
export type SandboxRecoveryAuthority = Readonly<{
|
|
18
|
+
kind: 'unverified';
|
|
19
|
+
}> | Readonly<{
|
|
20
|
+
kind: 'verified';
|
|
21
|
+
backendIdentity: string;
|
|
22
|
+
}>;
|
|
23
|
+
export interface SandboxRecoveryRecord {
|
|
24
|
+
readonly format: 'agenai.sandbox-recovery.v2';
|
|
25
|
+
readonly backendId: string;
|
|
26
|
+
readonly backendRevision: string;
|
|
27
|
+
readonly namespace: SandboxNamespace;
|
|
28
|
+
readonly operationId: string;
|
|
29
|
+
readonly sandboxId: SandboxId;
|
|
30
|
+
readonly imageDigest: string;
|
|
31
|
+
readonly policyDigest: string;
|
|
32
|
+
/** Exact backend configuration identity, independent of the requested policy digest. */
|
|
33
|
+
readonly configurationDigest: string;
|
|
34
|
+
readonly phase: SandboxRecoveryPhase;
|
|
35
|
+
readonly authority: SandboxRecoveryAuthority;
|
|
36
|
+
readonly resources: readonly SandboxRecoveryResource[];
|
|
37
|
+
}
|
|
38
|
+
export type SandboxRecoveryPolicy = Readonly<{
|
|
39
|
+
kind: 'in_process';
|
|
40
|
+
}> | Readonly<{
|
|
41
|
+
kind: 'persisted';
|
|
42
|
+
persist(record: SandboxRecoveryRecord): Promise<void>;
|
|
43
|
+
}>;
|
|
44
|
+
export interface SandboxCleanupOwner {
|
|
45
|
+
readonly recoveryRecord: SandboxRecoveryRecord;
|
|
46
|
+
stop(): Promise<void>;
|
|
47
|
+
destroy(): Promise<void>;
|
|
48
|
+
}
|
|
49
|
+
export type SandboxReconciliation = Readonly<{
|
|
50
|
+
kind: 'matched' | 'uncertain';
|
|
51
|
+
owner: SandboxCleanupOwner;
|
|
52
|
+
}> | Readonly<{
|
|
53
|
+
kind: 'conflict';
|
|
54
|
+
reason: string;
|
|
55
|
+
}> | Readonly<{
|
|
56
|
+
kind: 'absent';
|
|
57
|
+
record: SandboxRecoveryRecord;
|
|
58
|
+
}>;
|
|
59
|
+
//# sourceMappingURL=types.d.ts.map
|
|
File without changes
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { SandboxBackend, SandboxRunOptions, Sandbox } from './contracts.js';
|
|
2
|
+
import type { SandboxRequestInput } from './policy/types.js';
|
|
3
|
+
export declare function withSandbox<T>(backend: SandboxBackend, request: SandboxRequestInput, use: (sandbox: Sandbox) => Promise<T>, options: SandboxRunOptions): Promise<T>;
|
|
4
|
+
//# sourceMappingURL=withSandbox.d.ts.map
|