@claxedo/sandbox-manager 0.5.1
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 +78 -0
- package/dist/command.d.ts +3 -0
- package/dist/command.mjs +18 -0
- package/dist/constants.d.ts +1 -0
- package/dist/constants.mjs +7 -0
- package/dist/daytona-allow-list.d.ts +5 -0
- package/dist/daytona-allow-list.mjs +9 -0
- package/dist/defaults.d.ts +3 -0
- package/dist/defaults.mjs +14 -0
- package/dist/driver-catalog.d.ts +62 -0
- package/dist/driver-catalog.mjs +206 -0
- package/dist/drivers/cloudflare-egress.d.ts +40 -0
- package/dist/drivers/cloudflare-egress.mjs +115 -0
- package/dist/drivers/cloudflare.d.ts +37 -0
- package/dist/drivers/cloudflare.mjs +151 -0
- package/dist/drivers/daytona.d.ts +94 -0
- package/dist/drivers/daytona.mjs +235 -0
- package/dist/drivers/docker.d.ts +36 -0
- package/dist/drivers/docker.mjs +329 -0
- package/dist/drivers/fetch-bridge.d.ts +10 -0
- package/dist/drivers/fetch-bridge.mjs +104 -0
- package/dist/drivers/modal.d.ts +68 -0
- package/dist/drivers/modal.mjs +227 -0
- package/dist/drivers/vercel.d.ts +109 -0
- package/dist/drivers/vercel.mjs +297 -0
- package/dist/image-name.d.ts +7 -0
- package/dist/image.d.ts +8 -0
- package/dist/image.mjs +124 -0
- package/dist/index.d.ts +316 -0
- package/dist/index.mjs +330 -0
- package/dist/lease-policy.d.ts +49 -0
- package/dist/lease-policy.mjs +126 -0
- package/dist/lease-types.d.ts +89 -0
- package/dist/lease-types.mjs +1 -0
- package/dist/runtime-env.d.ts +24 -0
- package/dist/runtime-env.mjs +35 -0
- package/dist/runtime-version.d.ts +1 -0
- package/dist/runtime-version.mjs +24 -0
- package/dist/service-url-exposure.d.ts +10 -0
- package/dist/service-url-exposure.mjs +46 -0
- package/dist/stores/memory.d.ts +6 -0
- package/dist/stores/memory.mjs +117 -0
- package/package.json +178 -0
package/dist/image.mjs
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from 'module';var require = __createRequire(import.meta.url);
|
|
2
|
+
|
|
3
|
+
// src/image.ts
|
|
4
|
+
import { Image, DaytonaNotFoundError } from "@daytona/sdk";
|
|
5
|
+
|
|
6
|
+
// src/constants.ts
|
|
7
|
+
var DEFAULT_WORKSPACE_RUNTIME_PORT = 2593;
|
|
8
|
+
|
|
9
|
+
// src/defaults.ts
|
|
10
|
+
var WORKSPACE_RUNTIME_PORT = DEFAULT_WORKSPACE_RUNTIME_PORT;
|
|
11
|
+
var WORKSPACE_DIR = "/workspace";
|
|
12
|
+
var RUNTIME_DIR = "/opt/workspace-runtime";
|
|
13
|
+
|
|
14
|
+
// src/runtime-version.ts
|
|
15
|
+
import { createRequire } from "module";
|
|
16
|
+
var require2 = createRequire(import.meta.url);
|
|
17
|
+
var versionCache;
|
|
18
|
+
function workspaceRuntimeVersion() {
|
|
19
|
+
if (versionCache) return versionCache;
|
|
20
|
+
const envVersion = process.env.WORKSPACE_RUNTIME_VERSION;
|
|
21
|
+
if (envVersion) {
|
|
22
|
+
versionCache = envVersion;
|
|
23
|
+
return versionCache;
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
versionCache = require2("@claxedo/workspace-runtime/package.json").version;
|
|
27
|
+
return versionCache;
|
|
28
|
+
} catch {
|
|
29
|
+
}
|
|
30
|
+
versionCache = "0.0.0";
|
|
31
|
+
return versionCache;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// src/image-name.ts
|
|
35
|
+
var SNAPSHOT_SCHEMA_VERSION = 8;
|
|
36
|
+
var DEFAULT_SANDBOX_IMAGE_REPOSITORY = "ghcr.io/kyashrathore/claxedo-sandbox";
|
|
37
|
+
function snapshotVersion(value) {
|
|
38
|
+
return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
39
|
+
}
|
|
40
|
+
function sandboxImageRepository(env = process.env) {
|
|
41
|
+
const repository = env.CLAXEDO_SANDBOX_IMAGE_REPOSITORY?.trim();
|
|
42
|
+
return repository ? repository : DEFAULT_SANDBOX_IMAGE_REPOSITORY;
|
|
43
|
+
}
|
|
44
|
+
function buildIdSuffix(buildId, env) {
|
|
45
|
+
const id = (buildId ?? env.CLAXEDO_SANDBOX_BUILD_ID)?.trim();
|
|
46
|
+
return id ? `-${snapshotVersion(id)}` : "";
|
|
47
|
+
}
|
|
48
|
+
function defaultSandboxImage(version = workspaceRuntimeVersion(), buildId, env = process.env) {
|
|
49
|
+
return `${sandboxImageRepository(env)}:workspace-runtime-${snapshotVersion(version)}${buildIdSuffix(buildId, env)}-v${SNAPSHOT_SCHEMA_VERSION}`;
|
|
50
|
+
}
|
|
51
|
+
function defaultSnapshotName(version = workspaceRuntimeVersion(), buildId, env = process.env) {
|
|
52
|
+
return `claxedo-workspace-runtime-${snapshotVersion(version)}${buildIdSuffix(buildId, env)}-v${SNAPSHOT_SCHEMA_VERSION}`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// src/image.ts
|
|
56
|
+
var log = {
|
|
57
|
+
info(_message, _context) {
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
var SANDBOX_IMAGE_REPOSITORY = sandboxImageRepository();
|
|
61
|
+
var SANDBOX_IMAGE = process.env.CLAXEDO_SANDBOX_IMAGE || defaultSandboxImage();
|
|
62
|
+
var SNAPSHOT_NAME = process.env.CLAXEDO_SNAPSHOT_NAME || defaultSnapshotName();
|
|
63
|
+
function buildSandboxImage() {
|
|
64
|
+
return Image.base(SANDBOX_IMAGE);
|
|
65
|
+
}
|
|
66
|
+
function snapshotUsable(state) {
|
|
67
|
+
return state === "ready" || state === "active";
|
|
68
|
+
}
|
|
69
|
+
async function createSnapshot(daytona) {
|
|
70
|
+
log.info("Creating sandbox snapshot (this may take a few minutes)...", { name: SNAPSHOT_NAME });
|
|
71
|
+
await daytona.snapshot.create(
|
|
72
|
+
{ name: SNAPSHOT_NAME, image: buildSandboxImage() },
|
|
73
|
+
{
|
|
74
|
+
timeout: 120,
|
|
75
|
+
onLogs: (chunk) => log.info("[snapshot]", { text: chunk })
|
|
76
|
+
}
|
|
77
|
+
);
|
|
78
|
+
return SNAPSHOT_NAME;
|
|
79
|
+
}
|
|
80
|
+
async function ensureSnapshot(daytona) {
|
|
81
|
+
try {
|
|
82
|
+
const existing = await daytona.snapshot.get(SNAPSHOT_NAME);
|
|
83
|
+
if (existing.state === "inactive") {
|
|
84
|
+
log.info("Snapshot is inactive, reactivating...", { name: SNAPSHOT_NAME, id: existing.id });
|
|
85
|
+
await daytona.snapshot.activate({ id: existing.id });
|
|
86
|
+
for (let i = 0; i < 120; i++) {
|
|
87
|
+
const snap = await daytona.snapshot.get(SNAPSHOT_NAME);
|
|
88
|
+
if (snapshotUsable(snap.state)) return SNAPSHOT_NAME;
|
|
89
|
+
if (snap.state === "error") throw new Error(`Snapshot activation failed: ${snap.errorReason}`);
|
|
90
|
+
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
91
|
+
}
|
|
92
|
+
throw new Error("Snapshot activation timed out");
|
|
93
|
+
}
|
|
94
|
+
if (existing.state === "building") {
|
|
95
|
+
log.info("Snapshot is building, waiting (up to 10 min)...", { name: SNAPSHOT_NAME });
|
|
96
|
+
for (let i = 0; i < 300; i++) {
|
|
97
|
+
const snap = await daytona.snapshot.get(SNAPSHOT_NAME);
|
|
98
|
+
if (snapshotUsable(snap.state)) return SNAPSHOT_NAME;
|
|
99
|
+
if (snap.state === "error") throw new Error(`Snapshot build failed: ${snap.errorReason}`);
|
|
100
|
+
if (i % 15 === 0) log.info("Still waiting for snapshot...", { state: snap.state, elapsed: `${i * 2}s` });
|
|
101
|
+
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
102
|
+
}
|
|
103
|
+
throw new Error("Snapshot build timed out after 10 minutes");
|
|
104
|
+
}
|
|
105
|
+
return SNAPSHOT_NAME;
|
|
106
|
+
} catch (err) {
|
|
107
|
+
if (!(err instanceof DaytonaNotFoundError)) throw err;
|
|
108
|
+
}
|
|
109
|
+
return createSnapshot(daytona);
|
|
110
|
+
}
|
|
111
|
+
export {
|
|
112
|
+
RUNTIME_DIR,
|
|
113
|
+
SANDBOX_IMAGE,
|
|
114
|
+
SANDBOX_IMAGE_REPOSITORY,
|
|
115
|
+
SNAPSHOT_NAME,
|
|
116
|
+
SNAPSHOT_SCHEMA_VERSION,
|
|
117
|
+
WORKSPACE_DIR,
|
|
118
|
+
WORKSPACE_RUNTIME_PORT,
|
|
119
|
+
buildSandboxImage,
|
|
120
|
+
defaultSandboxImage,
|
|
121
|
+
defaultSnapshotName,
|
|
122
|
+
ensureSnapshot,
|
|
123
|
+
snapshotVersion
|
|
124
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
import { DEFAULT_WORKSPACE_RUNTIME_PORT } from "./constants";
|
|
2
|
+
import type { SandboxDriverID } from "./driver-catalog";
|
|
3
|
+
export { DEFAULT_WORKSPACE_RUNTIME_PORT };
|
|
4
|
+
export type SandboxRegion = string;
|
|
5
|
+
export type SandboxDriverId = SandboxDriverID | "fetch";
|
|
6
|
+
export type SandboxDriverMetadata = {
|
|
7
|
+
/** Where the sandbox driver code can execute. This is not sandbox infrastructure. */
|
|
8
|
+
driverRunsIn: Array<"worker" | "node" | "local">;
|
|
9
|
+
/** What `SandboxManager.stop()` actually does to the driver-owned resource. */
|
|
10
|
+
hostStopBehavior: "not-supported" | "suspends-host" | "terminates-host";
|
|
11
|
+
/** Whether a stopped/stale lease can resume the same driver-owned resource. */
|
|
12
|
+
hostResumeBehavior: "same-host" | "replacement-host";
|
|
13
|
+
/** How the control plane reaches the sandbox target returned by the driver. */
|
|
14
|
+
targetAccess: "relay" | "loopback";
|
|
15
|
+
/**
|
|
16
|
+
* How the driver can honor a `SandboxBrokeredSecret` — a credential the
|
|
17
|
+
* sandbox may USE for outbound requests but must NEVER be able to READ.
|
|
18
|
+
*
|
|
19
|
+
* - `"native"` — the provider brokers it automatically on egress to the
|
|
20
|
+
* allowlisted hosts, with no extra infrastructure: Daytona secret
|
|
21
|
+
* placeholders + egress proxy; Vercel firewall header transforms. The
|
|
22
|
+
* driver injects it during `ensureHost`.
|
|
23
|
+
* - `"proxy"` — brokering is achievable but only via a host-operated egress
|
|
24
|
+
* proxy the driver routes through (Cloudflare's official Worker-proxy
|
|
25
|
+
* pattern: the sandbox gets a short-lived JWT, egress hits the Worker,
|
|
26
|
+
* the Worker injects the real credential — the raw value never enters the
|
|
27
|
+
* sandbox). Not automatic; requires the host's proxy to be wired.
|
|
28
|
+
* - `"none"` — no way to keep the value out of sandbox processes. The
|
|
29
|
+
* provider may still have an encrypted secret STORE (e.g. Modal secrets),
|
|
30
|
+
* but those are exposed as readable env vars, so they cannot satisfy the
|
|
31
|
+
* never-readable contract.
|
|
32
|
+
*
|
|
33
|
+
* The manager fails closed unless the driver actually injects brokered
|
|
34
|
+
* secrets (today: `"native"` only). `"proxy"` records an achievable ceiling
|
|
35
|
+
* that is not yet wired and therefore also fails closed.
|
|
36
|
+
*/
|
|
37
|
+
secretBrokering: "native" | "proxy" | "none";
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* A credential the SANDBOX must be able to USE for outbound requests but must
|
|
41
|
+
* NEVER be able to READ. Unlike `env` (plaintext, readable — reserved for
|
|
42
|
+
* credentials the agent is trusted with, e.g. the user's own model
|
|
43
|
+
* subscription), a brokered secret's `value` never enters the sandbox: the
|
|
44
|
+
* provider injects it on egress to `hosts` only. Non-model credentials
|
|
45
|
+
* (connection tokens, deploy tokens) belong here.
|
|
46
|
+
*
|
|
47
|
+
* Guarantees enforced by the manager: brokered secrets are never written to
|
|
48
|
+
* labels, never logged, and never captured in a driver snapshot. A driver
|
|
49
|
+
* whose `metadata.secretBrokering !== "native"` cannot honor them and the
|
|
50
|
+
* manager refuses to provision (fail-closed).
|
|
51
|
+
*/
|
|
52
|
+
export type SandboxBrokeredSecret = {
|
|
53
|
+
/** Env var name the sandbox references (Daytona placeholder key). */
|
|
54
|
+
name: string;
|
|
55
|
+
/** The secret material. Never enters the sandbox in plaintext. */
|
|
56
|
+
value: string;
|
|
57
|
+
/** Egress allowlist: the only hosts for which the value is substituted/injected. */
|
|
58
|
+
hosts: string[];
|
|
59
|
+
/**
|
|
60
|
+
* When set, the value is injected as this HTTP header on egress to `hosts`
|
|
61
|
+
* (required for the Vercel firewall-transform model). When omitted, the
|
|
62
|
+
* driver exposes the credential via its native placeholder mechanism for
|
|
63
|
+
* the sandbox to attach itself (Daytona).
|
|
64
|
+
*/
|
|
65
|
+
header?: string;
|
|
66
|
+
};
|
|
67
|
+
export type SandboxExposure = {
|
|
68
|
+
kind: "loopback";
|
|
69
|
+
} | {
|
|
70
|
+
kind: "relay";
|
|
71
|
+
} | {
|
|
72
|
+
kind: "private-network";
|
|
73
|
+
} | {
|
|
74
|
+
kind: "embedded";
|
|
75
|
+
};
|
|
76
|
+
export type SandboxLeaseStatus = "acquiring" | "ready" | "unavailable" | "stopped" | "destroyed";
|
|
77
|
+
export type SandboxLease = {
|
|
78
|
+
workspaceId: string;
|
|
79
|
+
homeRegion: SandboxRegion;
|
|
80
|
+
driver: string;
|
|
81
|
+
epoch: number;
|
|
82
|
+
status: SandboxLeaseStatus;
|
|
83
|
+
retryCount: number;
|
|
84
|
+
updatedAt: number;
|
|
85
|
+
createdAt: number;
|
|
86
|
+
sandboxId?: string;
|
|
87
|
+
url?: string;
|
|
88
|
+
hostId?: string;
|
|
89
|
+
driverResourceId?: string;
|
|
90
|
+
nextRetryAt?: number;
|
|
91
|
+
lastError?: string;
|
|
92
|
+
lastHeartbeatAt?: number;
|
|
93
|
+
lastActivityAt?: number;
|
|
94
|
+
labels?: Record<string, string>;
|
|
95
|
+
};
|
|
96
|
+
export type SandboxLeaseAcquireInput = {
|
|
97
|
+
homeRegion: SandboxRegion;
|
|
98
|
+
driver: string;
|
|
99
|
+
staleAfterMs: number;
|
|
100
|
+
now?: number;
|
|
101
|
+
};
|
|
102
|
+
export type SandboxLeaseAcquireResult = {
|
|
103
|
+
acquired: true;
|
|
104
|
+
lease: SandboxLease;
|
|
105
|
+
} | {
|
|
106
|
+
acquired: false;
|
|
107
|
+
lease: SandboxLease;
|
|
108
|
+
retryAfterMs: number;
|
|
109
|
+
};
|
|
110
|
+
export type SandboxLeasePatch = Partial<Pick<SandboxLease, "status" | "sandboxId" | "url" | "hostId" | "driverResourceId" | "retryCount" | "lastHeartbeatAt" | "lastActivityAt" | "labels">> & {
|
|
111
|
+
/** `null` clears the stored value; `undefined` leaves it unchanged. */
|
|
112
|
+
nextRetryAt?: number | null;
|
|
113
|
+
/** `null` clears the stored value; `undefined` leaves it unchanged. */
|
|
114
|
+
lastError?: string | null;
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* Canonical SandboxLeasePatch merge semantics shared by every lease store driver:
|
|
118
|
+
* absent/`undefined` keeps the current value, `null` clears it.
|
|
119
|
+
*/
|
|
120
|
+
export declare function applySandboxLeasePatch(current: SandboxLease, patch: SandboxLeasePatch, updatedAt: number): SandboxLease;
|
|
121
|
+
export type SandboxLeaseStore = {
|
|
122
|
+
acquire: (workspaceId: string, input: SandboxLeaseAcquireInput) => Promise<SandboxLeaseAcquireResult>;
|
|
123
|
+
update: (workspaceId: string, expectedEpoch: number, patch: SandboxLeasePatch) => Promise<SandboxLease | undefined>;
|
|
124
|
+
recordFailure: (workspaceId: string, expectedEpoch: number, error: string, nextRetryAt?: number) => Promise<SandboxLease | undefined>;
|
|
125
|
+
release: (workspaceId: string) => Promise<void>;
|
|
126
|
+
get: (workspaceId: string) => Promise<SandboxLease | undefined>;
|
|
127
|
+
list: () => Promise<SandboxLease[]>;
|
|
128
|
+
};
|
|
129
|
+
export type SandboxNetworkPolicy = {
|
|
130
|
+
mode: "allow-all" | "restricted";
|
|
131
|
+
hosts?: string[];
|
|
132
|
+
cidrs?: string[];
|
|
133
|
+
};
|
|
134
|
+
export type SandboxBootSource = {
|
|
135
|
+
kind: "image";
|
|
136
|
+
image: string;
|
|
137
|
+
} | {
|
|
138
|
+
kind: "driver-snapshot";
|
|
139
|
+
snapshotId: string;
|
|
140
|
+
} | {
|
|
141
|
+
kind: "default";
|
|
142
|
+
};
|
|
143
|
+
export type SandboxSource = {
|
|
144
|
+
kind: "git";
|
|
145
|
+
repoUrl: string;
|
|
146
|
+
branch?: string;
|
|
147
|
+
} | {
|
|
148
|
+
kind: "empty";
|
|
149
|
+
};
|
|
150
|
+
export type SandboxDriverEnsureInput = {
|
|
151
|
+
workspaceId: string;
|
|
152
|
+
hostId?: string;
|
|
153
|
+
homeRegion: SandboxRegion;
|
|
154
|
+
epoch: number;
|
|
155
|
+
labels: Record<string, string>;
|
|
156
|
+
bootSource?: SandboxBootSource;
|
|
157
|
+
workspaceRoot?: string;
|
|
158
|
+
runtimeCwd?: string;
|
|
159
|
+
workspaceRuntimePort?: number;
|
|
160
|
+
env?: Record<string, string>;
|
|
161
|
+
/** Brokered secrets: injected on egress, never readable inside the sandbox. */
|
|
162
|
+
secrets?: SandboxBrokeredSecret[];
|
|
163
|
+
source?: SandboxSource;
|
|
164
|
+
exposure?: SandboxExposure;
|
|
165
|
+
/** Optional egress policy (allow-all when omitted). */
|
|
166
|
+
net?: SandboxNetworkPolicy;
|
|
167
|
+
/** Optional snapshot/image to boot from (user-supplied or pre-built). */
|
|
168
|
+
snapshot?: string;
|
|
169
|
+
};
|
|
170
|
+
export type SandboxTarget = {
|
|
171
|
+
workspaceId?: string;
|
|
172
|
+
sandboxId: string;
|
|
173
|
+
url: string;
|
|
174
|
+
hostId: string;
|
|
175
|
+
driverResourceId?: string;
|
|
176
|
+
labels?: Record<string, string>;
|
|
177
|
+
driver?: {
|
|
178
|
+
id: string;
|
|
179
|
+
resourceId: string;
|
|
180
|
+
metadata?: Record<string, string>;
|
|
181
|
+
};
|
|
182
|
+
};
|
|
183
|
+
export type SandboxSnapshotResult = {
|
|
184
|
+
snapshotId: string;
|
|
185
|
+
};
|
|
186
|
+
export type SandboxDriver = {
|
|
187
|
+
id: string;
|
|
188
|
+
metadata: SandboxDriverMetadata;
|
|
189
|
+
ensureHost: (input: SandboxDriverEnsureInput) => Promise<SandboxTarget | {
|
|
190
|
+
provisioning: true;
|
|
191
|
+
retryAfterMs: number;
|
|
192
|
+
}>;
|
|
193
|
+
resumeHost?: (input: {
|
|
194
|
+
lease: SandboxLease;
|
|
195
|
+
ensure: SandboxDriverEnsureInput;
|
|
196
|
+
}) => Promise<SandboxTarget | {
|
|
197
|
+
provisioning: true;
|
|
198
|
+
retryAfterMs: number;
|
|
199
|
+
}>;
|
|
200
|
+
list?: () => Promise<SandboxTarget[]>;
|
|
201
|
+
touch?: (target: SandboxTarget) => Promise<void>;
|
|
202
|
+
suspend?: (target: SandboxTarget) => Promise<void>;
|
|
203
|
+
stop?: (target: SandboxTarget) => Promise<void>;
|
|
204
|
+
destroy?: (target: SandboxTarget) => Promise<void>;
|
|
205
|
+
snapshot?: (target: SandboxTarget) => Promise<SandboxSnapshotResult>;
|
|
206
|
+
};
|
|
207
|
+
export type SandboxManager = {
|
|
208
|
+
ensure: (workspaceId: string, input: SandboxManagerInput) => Promise<SandboxEnsureResult>;
|
|
209
|
+
register: (workspaceId: string, input: SandboxRegisterInput) => Promise<SandboxMutationResult>;
|
|
210
|
+
heartbeat: (workspaceId: string, input: SandboxHeartbeatInput) => Promise<SandboxMutationResult>;
|
|
211
|
+
target: (workspaceId: string) => Promise<SandboxTargetResult>;
|
|
212
|
+
touch: (workspaceId: string) => Promise<SandboxTouchResult>;
|
|
213
|
+
snapshot: (workspaceId: string) => Promise<SandboxSnapshotManagerResult>;
|
|
214
|
+
stop: (workspaceId: string) => Promise<SandboxMutationResult>;
|
|
215
|
+
destroy: (workspaceId: string) => Promise<SandboxMutationResult>;
|
|
216
|
+
release: (workspaceId: string) => Promise<{
|
|
217
|
+
released: boolean;
|
|
218
|
+
}>;
|
|
219
|
+
garbageCollect: () => Promise<SandboxGarbageCollectResult>;
|
|
220
|
+
list: () => Promise<SandboxLease[]>;
|
|
221
|
+
};
|
|
222
|
+
export type SandboxManagerInput = {
|
|
223
|
+
homeRegion: SandboxRegion;
|
|
224
|
+
hostId?: string;
|
|
225
|
+
labels?: Record<string, string>;
|
|
226
|
+
bootSource?: SandboxBootSource;
|
|
227
|
+
workspaceRoot?: string;
|
|
228
|
+
runtimeCwd?: string;
|
|
229
|
+
workspaceRuntimePort?: number;
|
|
230
|
+
env?: Record<string, string>;
|
|
231
|
+
/** Brokered secrets: injected on egress, never readable inside the sandbox. */
|
|
232
|
+
secrets?: SandboxBrokeredSecret[];
|
|
233
|
+
source?: SandboxSource;
|
|
234
|
+
exposure?: SandboxExposure;
|
|
235
|
+
net?: SandboxNetworkPolicy;
|
|
236
|
+
snapshot?: string;
|
|
237
|
+
};
|
|
238
|
+
export type SandboxRegisterInput = {
|
|
239
|
+
epoch?: number;
|
|
240
|
+
ok: boolean;
|
|
241
|
+
status?: string;
|
|
242
|
+
sandboxId?: string | null;
|
|
243
|
+
url?: string | null;
|
|
244
|
+
hostId?: string | null;
|
|
245
|
+
driverResourceId?: string | null;
|
|
246
|
+
active?: boolean;
|
|
247
|
+
now?: number;
|
|
248
|
+
};
|
|
249
|
+
export type SandboxHeartbeatInput = SandboxRegisterInput;
|
|
250
|
+
export type SandboxEnsureResult = ({
|
|
251
|
+
status: "ready";
|
|
252
|
+
} & SandboxTarget & {
|
|
253
|
+
epoch: number;
|
|
254
|
+
homeRegion: SandboxRegion;
|
|
255
|
+
}) | {
|
|
256
|
+
status: "provisioning";
|
|
257
|
+
retryAfterMs: number;
|
|
258
|
+
epoch: number;
|
|
259
|
+
homeRegion: SandboxRegion;
|
|
260
|
+
} | {
|
|
261
|
+
status: "unavailable";
|
|
262
|
+
retryAfterMs?: number;
|
|
263
|
+
error?: string;
|
|
264
|
+
epoch?: number;
|
|
265
|
+
homeRegion: SandboxRegion;
|
|
266
|
+
};
|
|
267
|
+
export type SandboxTargetResult = ({
|
|
268
|
+
status: "ready";
|
|
269
|
+
} & SandboxTarget & {
|
|
270
|
+
epoch: number;
|
|
271
|
+
homeRegion: SandboxRegion;
|
|
272
|
+
}) | {
|
|
273
|
+
status: "unavailable";
|
|
274
|
+
reason: string;
|
|
275
|
+
};
|
|
276
|
+
export type SandboxTouchResult = {
|
|
277
|
+
touched: boolean;
|
|
278
|
+
status: SandboxLeaseStatus | "missing";
|
|
279
|
+
};
|
|
280
|
+
export type SandboxMutationResult = {
|
|
281
|
+
ok: true;
|
|
282
|
+
status: SandboxLeaseStatus;
|
|
283
|
+
} | {
|
|
284
|
+
ok: false;
|
|
285
|
+
reason: string;
|
|
286
|
+
};
|
|
287
|
+
export type SandboxSnapshotManagerResult = ({
|
|
288
|
+
ok: true;
|
|
289
|
+
} & SandboxSnapshotResult) | {
|
|
290
|
+
ok: false;
|
|
291
|
+
reason: string;
|
|
292
|
+
};
|
|
293
|
+
export type SandboxGarbageCollectResult = {
|
|
294
|
+
destroyed: SandboxTarget[];
|
|
295
|
+
kept: SandboxTarget[];
|
|
296
|
+
skipped: Array<{
|
|
297
|
+
target: SandboxTarget;
|
|
298
|
+
reason: string;
|
|
299
|
+
}>;
|
|
300
|
+
failed: Array<{
|
|
301
|
+
target: SandboxTarget;
|
|
302
|
+
error: string;
|
|
303
|
+
}>;
|
|
304
|
+
};
|
|
305
|
+
export type SandboxManagerOptions = {
|
|
306
|
+
leaseStore: SandboxLeaseStore;
|
|
307
|
+
driver: SandboxDriver;
|
|
308
|
+
staleAfterMs?: number;
|
|
309
|
+
retryAfterMs?: number;
|
|
310
|
+
retryDelayMs?: (retryCount: number) => number;
|
|
311
|
+
maxRetryCount?: number;
|
|
312
|
+
retryCapCooldownMs?: number;
|
|
313
|
+
now?: () => number;
|
|
314
|
+
appLabel?: string;
|
|
315
|
+
};
|
|
316
|
+
export declare function createSandboxManager(options: SandboxManagerOptions): SandboxManager;
|