@claxedo/sandbox-manager 0.6.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -15
- package/dist/checkpoint-manager.d.ts +47 -0
- package/dist/checkpoint-manager.mjs +116 -0
- package/dist/daytona-allow-list.d.ts +11 -0
- package/dist/daytona-allow-list.mjs +5 -1
- package/dist/driver-catalog.d.ts +5 -52
- package/dist/driver-catalog.mjs +263 -121
- package/dist/drivers/box.mjs +309 -39
- package/dist/drivers/cloudflare.d.ts +18 -7
- package/dist/drivers/cloudflare.mjs +423 -34
- package/dist/drivers/daytona.d.ts +82 -13
- package/dist/drivers/daytona.mjs +495 -45
- package/dist/drivers/docker.mjs +284 -38
- package/dist/drivers/exe.d.ts +26 -0
- package/dist/drivers/exe.mjs +492 -0
- package/dist/drivers/fetch-bridge.mjs +29 -5
- package/dist/drivers/modal.d.ts +2 -5
- package/dist/drivers/modal.mjs +296 -46
- package/dist/drivers/transient-error.d.ts +11 -0
- package/dist/drivers/vercel.d.ts +27 -11
- package/dist/drivers/vercel.mjs +339 -59
- package/dist/hosted-network-policy.d.ts +87 -0
- package/dist/hosted-network-policy.mjs +61 -0
- package/dist/image-name.mjs +34 -0
- package/dist/image.d.ts +18 -3
- package/dist/image.mjs +47 -32
- package/dist/index.d.ts +281 -17
- package/dist/index.mjs +393 -26
- package/dist/json.d.ts +13 -0
- package/dist/lease-policy.d.ts +6 -3
- package/dist/lease-policy.mjs +213 -54
- package/dist/lease-types.d.ts +17 -3
- package/dist/runtime-env.d.ts +12 -1
- package/dist/runtime-env.mjs +14 -0
- package/dist/runtime-version.mjs +1 -9
- package/dist/service-url-exposure.d.ts +1 -2
- package/dist/service-url-exposure.mjs +1 -17
- package/dist/stores/memory.mjs +39 -4
- package/package.json +67 -51
- package/dist/drivers/cloudflare-egress.d.ts +0 -40
- package/dist/drivers/cloudflare-egress.mjs +0 -113
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ The package owns the generic pieces:
|
|
|
11
11
|
- `SandboxDriver`
|
|
12
12
|
- provider drivers for Cloudflare, Daytona, Docker, fetch bridge, Modal, and Vercel
|
|
13
13
|
|
|
14
|
-
It deliberately does not own Claxedo product auth, billing,
|
|
14
|
+
It deliberately does not own Claxedo product auth, billing, app storage schema, routes, or relay tokens. Applications provide those through adapters and call `createSandboxManager`.
|
|
15
15
|
|
|
16
16
|
## Install
|
|
17
17
|
|
|
@@ -59,8 +59,8 @@ Swap `createDockerSandboxDriver` for `createDaytonaSandboxDriver`,
|
|
|
59
59
|
`@claxedo/sandbox-manager/drivers/*`) to place on a hosted provider instead —
|
|
60
60
|
see [`docs/architecture.md`](docs/architecture.md) for the full driver
|
|
61
61
|
comparison and each provider's required options. Swap `createMemoryLeaseStore`
|
|
62
|
-
for a persisted `SandboxLeaseStore` implementation (e.g. backed by SQLite
|
|
63
|
-
|
|
62
|
+
for a persisted `SandboxLeaseStore` implementation (e.g. backed by SQLite) to
|
|
63
|
+
survive process restarts.
|
|
64
64
|
|
|
65
65
|
## Credentials & secrets
|
|
66
66
|
|
|
@@ -99,26 +99,71 @@ Per-provider mechanism (from each provider's official docs):
|
|
|
99
99
|
| Driver | `secretBrokering` | Mechanism |
|
|
100
100
|
| --- | --- | --- |
|
|
101
101
|
| Daytona | `native` | `daytona.secret.create({name, value, hosts})`; the sandbox env holds an opaque `dtn_secret_…` placeholder and an egress proxy substitutes the real value only for allowlisted hosts ([docs](https://www.daytona.io/docs/en/secrets/)). |
|
|
102
|
-
| Vercel | `native` | Firewall header-transform (`updateNetworkPolicy`): the value is spliced onto egress to the allowlisted hosts as `header
|
|
103
|
-
| Cloudflare | `
|
|
102
|
+
| Vercel | `native` | Firewall header-transform (`updateNetworkPolicy`): the value is spliced onto egress to the allowlisted hosts as `header`, so the sandbox makes an unauthenticated request ([docs](https://vercel.com/docs/sandbox/concepts/firewall)). `updateNetworkPolicy` replaces the whole policy, so the driver sends the **union** of the create-time allow-list and the brokered hosts — attaching a credential must not revoke egress the caller was already granted (a mid-run `npm install` would start failing), nor widen it to a brokered host the create-time policy never approved. |
|
|
103
|
+
| Cloudflare | `native` | The driver sends named registrations to the API-token-gated Worker. KV holds the values outside the container; native HTTPS outbound handlers replace named placeholders in registered headers. Each request reads KV, so there is no expiring container JWT. KV propagation delay still applies to rotation and withdrawal. |
|
|
104
104
|
| Modal | `none` | Modal [Secrets](https://modal.com/docs/guide/secrets) are an encrypted by-reference store, but exposed as **readable env vars** inside the sandbox — they cannot satisfy the never-readable contract. |
|
|
105
105
|
| Docker, fetch | `none` | Plaintext env only. |
|
|
106
106
|
|
|
107
107
|
**Fail-closed contract.** A brokered secret is never silently downgraded to
|
|
108
|
-
readable env. `native`
|
|
109
|
-
|
|
110
|
-
only a `none` driver makes the manager refuse to provision (`status:
|
|
108
|
+
readable env. Only `native` keeps the value out of the sandbox and provisions
|
|
109
|
+
normally; a `none` driver makes the manager refuse to provision (`status:
|
|
111
110
|
"unavailable", error: "secret_brokering_unsupported"`) rather than expose or
|
|
112
111
|
drop the credential. Brokered secret values are also never written to labels,
|
|
113
112
|
never logged, and never captured in a driver snapshot.
|
|
114
113
|
|
|
115
|
-
>
|
|
116
|
-
>
|
|
117
|
-
>
|
|
118
|
-
>
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
114
|
+
> Native brokering keeps the original upstream URL. Cloudflare accepts its
|
|
115
|
+
> named placeholder as the complete credential header, or with a Bearer prefix
|
|
116
|
+
> for Authorization API-key clients. Modal remains `none`: its encrypted store
|
|
117
|
+
> exposes credentials as readable environment variables inside the sandbox.
|
|
118
|
+
|
|
119
|
+
## Egress containment
|
|
120
|
+
|
|
121
|
+
`SandboxManagerInput.net` restricts what the sandbox can reach on the network.
|
|
122
|
+
It is a *separate* control from brokered secrets, with a **different** posture,
|
|
123
|
+
and the difference matters:
|
|
124
|
+
|
|
125
|
+
- **Brokered secrets fail closed.** A driver that cannot broker refuses to
|
|
126
|
+
provision (`error: "secret_brokering_unsupported"`).
|
|
127
|
+
- **Egress does not.** Only `daytona` (names + CIDRs) and `vercel` (names) can
|
|
128
|
+
enforce an allowlist. Every other driver declares
|
|
129
|
+
`metadata.egressControl: "none"`, and for those the manager **withholds** the
|
|
130
|
+
policy and provisions anyway — the sandbox runs with unrestricted egress.
|
|
131
|
+
|
|
132
|
+
Withholding rather than passing is deliberate: `exe`, `docker`, `modal` and
|
|
133
|
+
`box` throw when handed a restricted policy, and `cloudflare` and the fetch
|
|
134
|
+
bridge accept one and silently ignore it. Withholding at the manager means the
|
|
135
|
+
throwing drivers never see a policy (their throws stay as their own last line of
|
|
136
|
+
defence) and the silently-dropping ones stop pretending.
|
|
137
|
+
|
|
138
|
+
The gap is never silent. `createSandboxManager` warns at composition, and again
|
|
139
|
+
each time a policy is withheld:
|
|
140
|
+
|
|
141
|
+
```text
|
|
142
|
+
[sandbox-manager] SANDBOX EGRESS IS UNRESTRICTED: driver "cloudflare" declares
|
|
143
|
+
egressControl: "none", so workspace ws_1 can reach ANY host on the internet …
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Pass `onEgressUnenforced` to route that into telemetry instead of `console.warn`
|
|
147
|
+
— it receives a structured `SandboxEgressUnenforcedEvent`. Overriding the sink
|
|
148
|
+
replaces the console warning, so only do it if the replacement is as visible.
|
|
149
|
+
|
|
150
|
+
**Reuse and resume reapply the policy.** A restricted policy only reaches a
|
|
151
|
+
provider as *creation* parameters, so a sandbox handed back rather than created
|
|
152
|
+
— reuse in `ensureHost`, resume in `resumeHost` — would otherwise run on the
|
|
153
|
+
policy in force when it was first created, possibly a wider one from an earlier
|
|
154
|
+
caller. Daytona's allow-list is mutable post-create
|
|
155
|
+
(`Sandbox.updateNetworkSettings`), so `daytona` reapplies the requested policy
|
|
156
|
+
on both paths. A client too old to expose that call makes the driver **refuse
|
|
157
|
+
the reuse**: a policy reported as applied but not in force is worse than no
|
|
158
|
+
sandbox. Requesting no containment leaves the existing policy alone rather than
|
|
159
|
+
clearing it — "not requested" is not "please unrestrict".
|
|
160
|
+
|
|
161
|
+
`driver.metadata.egressControl` is the machine-readable source of truth, and
|
|
162
|
+
`sandboxEgressDisposition(control, net)` is the pure predicate the manager uses,
|
|
163
|
+
so you can ask the same question before composing. One exception stays fail
|
|
164
|
+
closed: a hosts-only driver handed an address-only policy is refused
|
|
165
|
+
(`sandbox_egress_policy_unenforceable`) rather than degraded, because that
|
|
166
|
+
driver *does* enforce egress — it just cannot express that encoding.
|
|
122
167
|
|
|
123
168
|
> SDK conformance: the Daytona secret API and Vercel network-policy transform
|
|
124
169
|
> shapes follow the providers' official docs and are validated structurally
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { SandboxCheckpointReference, SandboxEnsureResult, SandboxLease, SandboxLeaseStore, SandboxManagerInput, SandboxSnapshotManagerResult, SandboxTargetResult } from ".";
|
|
2
|
+
export type SandboxCheckpointRuntime = {
|
|
3
|
+
freeze: (policy: "drain" | "interrupt") => Promise<void>;
|
|
4
|
+
flush: () => Promise<void>;
|
|
5
|
+
scrub: () => Promise<void>;
|
|
6
|
+
resume: () => Promise<void>;
|
|
7
|
+
reconcile: (input: {
|
|
8
|
+
epoch: number;
|
|
9
|
+
checkpointId: string;
|
|
10
|
+
}) => Promise<void>;
|
|
11
|
+
};
|
|
12
|
+
export type SandboxCheckpointCaptureInput = {
|
|
13
|
+
runtime: SandboxCheckpointRuntime;
|
|
14
|
+
policy?: "drain" | "interrupt";
|
|
15
|
+
retentionExpiresAt?: number;
|
|
16
|
+
};
|
|
17
|
+
export type SandboxCheckpointRestoreInput = {
|
|
18
|
+
runtime: SandboxCheckpointRuntime;
|
|
19
|
+
checkpointId?: string;
|
|
20
|
+
ensure?: Omit<SandboxManagerInput, "homeRegion">;
|
|
21
|
+
};
|
|
22
|
+
export type SandboxCheckpointResult = {
|
|
23
|
+
status: "ready";
|
|
24
|
+
lease: SandboxLease;
|
|
25
|
+
checkpoint: SandboxCheckpointReference;
|
|
26
|
+
} | {
|
|
27
|
+
status: "provisioning";
|
|
28
|
+
lease: SandboxLease;
|
|
29
|
+
checkpoint: SandboxCheckpointReference;
|
|
30
|
+
retryAfterMs: number;
|
|
31
|
+
};
|
|
32
|
+
export declare function captureSandboxCheckpoint(input: {
|
|
33
|
+
workspaceId: string;
|
|
34
|
+
request: SandboxCheckpointCaptureInput;
|
|
35
|
+
leaseStore: SandboxLeaseStore;
|
|
36
|
+
target: (workspaceId: string) => Promise<SandboxTargetResult>;
|
|
37
|
+
snapshot: (workspaceId: string) => Promise<SandboxSnapshotManagerResult>;
|
|
38
|
+
now?: () => number;
|
|
39
|
+
checkpointId?: () => string;
|
|
40
|
+
}): Promise<SandboxCheckpointResult>;
|
|
41
|
+
export declare function restoreSandboxCheckpoint(input: {
|
|
42
|
+
workspaceId: string;
|
|
43
|
+
request: SandboxCheckpointRestoreInput;
|
|
44
|
+
leaseStore: SandboxLeaseStore;
|
|
45
|
+
ensure: (workspaceId: string, input: SandboxManagerInput) => Promise<SandboxEnsureResult>;
|
|
46
|
+
now?: () => number;
|
|
47
|
+
}): Promise<SandboxCheckpointResult>;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// src/checkpoint-manager.ts
|
|
2
|
+
async function captureSandboxCheckpoint(input) {
|
|
3
|
+
const lease = await requireLease(input.leaseStore, input.workspaceId);
|
|
4
|
+
if (lease.status !== "ready") throw new Error("workspace_checkpoint_lease_not_ready");
|
|
5
|
+
const persistence = lease.persistence;
|
|
6
|
+
if (!persistence || persistence.capture === "none") throw new Error("workspace_checkpoint_unsupported");
|
|
7
|
+
const target = await input.target(input.workspaceId);
|
|
8
|
+
if (target.status !== "ready") throw new Error(target.reason);
|
|
9
|
+
await input.request.runtime.freeze(input.request.policy ?? "drain");
|
|
10
|
+
let capturedSource = false;
|
|
11
|
+
try {
|
|
12
|
+
await input.request.runtime.flush();
|
|
13
|
+
await input.request.runtime.scrub();
|
|
14
|
+
const captured = persistence.capture === "same-resource" ? { ok: true, snapshotId: target.driverResourceId ?? target.sandboxId } : await input.snapshot(input.workspaceId);
|
|
15
|
+
if (!captured.ok) throw new Error(captured.reason);
|
|
16
|
+
capturedSource = true;
|
|
17
|
+
const capturedAt = (input.now ?? Date.now)();
|
|
18
|
+
const checkpoint = {
|
|
19
|
+
id: input.checkpointId?.() ?? `cp_${lease.epoch}_${crypto.randomUUID()}`,
|
|
20
|
+
providerReference: captured.snapshotId,
|
|
21
|
+
sourceEpoch: lease.epoch,
|
|
22
|
+
capturedAt,
|
|
23
|
+
metadata: {
|
|
24
|
+
scope: persistence.capture,
|
|
25
|
+
sourceBehavior: requireCaptureSource(persistence.captureSource),
|
|
26
|
+
...input.request.retentionExpiresAt === void 0 ? {} : { retentionExpiresAt: input.request.retentionExpiresAt },
|
|
27
|
+
restoreMount: requireRestoreMount(persistence.restoreMount)
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
const updated = await input.leaseStore.update(input.workspaceId, lease.epoch, {
|
|
31
|
+
checkpoint,
|
|
32
|
+
restore: null,
|
|
33
|
+
...persistence.captureSource === "stopped" || persistence.captureSource === "deleted" ? { status: "stopped" } : {}
|
|
34
|
+
});
|
|
35
|
+
if (!updated) throw new Error("workspace_checkpoint_epoch_fenced");
|
|
36
|
+
return { status: "ready", lease: updated, checkpoint };
|
|
37
|
+
} finally {
|
|
38
|
+
if (!capturedSource || persistence.captureSource === "preserved") {
|
|
39
|
+
await input.request.runtime.resume();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
async function restoreSandboxCheckpoint(input) {
|
|
44
|
+
const lease = await requireLease(input.leaseStore, input.workspaceId);
|
|
45
|
+
const checkpoint = lease.checkpoint;
|
|
46
|
+
if (!checkpoint || input.request.checkpointId && checkpoint.id !== input.request.checkpointId) {
|
|
47
|
+
throw new Error("workspace_checkpoint_not_found");
|
|
48
|
+
}
|
|
49
|
+
if (lease.restore?.state === "ready" && lease.restore.checkpointId === checkpoint.id) {
|
|
50
|
+
return { status: "ready", lease, checkpoint };
|
|
51
|
+
}
|
|
52
|
+
const requestedAt = lease.restore?.checkpointId === checkpoint.id ? lease.restore.requestedAt : (input.now ?? Date.now)();
|
|
53
|
+
const restoring = lease.restore?.checkpointId === checkpoint.id && lease.restore.state !== "pending" ? lease.restore : {
|
|
54
|
+
checkpointId: checkpoint.id,
|
|
55
|
+
sourceEpoch: checkpoint.sourceEpoch,
|
|
56
|
+
state: "restoring",
|
|
57
|
+
requestedAt,
|
|
58
|
+
startedAt: (input.now ?? Date.now)()
|
|
59
|
+
};
|
|
60
|
+
const staged = lease.status === "ready" && lease.epoch === checkpoint.sourceEpoch ? await input.leaseStore.update(input.workspaceId, lease.epoch, { status: "stopped", restore: restoring }) : await input.leaseStore.update(input.workspaceId, lease.epoch, { restore: restoring });
|
|
61
|
+
if (!staged) throw new Error("workspace_restore_epoch_fenced");
|
|
62
|
+
const result = await input.ensure(input.workspaceId, {
|
|
63
|
+
homeRegion: staged.homeRegion,
|
|
64
|
+
...input.request.ensure,
|
|
65
|
+
bootSource: checkpoint.metadata.restoreMount === "same-resource" ? { kind: "default" } : { kind: "driver-snapshot", snapshotId: checkpoint.providerReference }
|
|
66
|
+
});
|
|
67
|
+
const current = await requireLease(input.leaseStore, input.workspaceId);
|
|
68
|
+
if (result.status === "provisioning") {
|
|
69
|
+
return { status: "provisioning", lease: current, checkpoint, retryAfterMs: result.retryAfterMs };
|
|
70
|
+
}
|
|
71
|
+
if (result.status !== "ready") {
|
|
72
|
+
const failedAt = (input.now ?? Date.now)();
|
|
73
|
+
await input.leaseStore.update(input.workspaceId, current.epoch, {
|
|
74
|
+
restore: {
|
|
75
|
+
checkpointId: checkpoint.id,
|
|
76
|
+
sourceEpoch: checkpoint.sourceEpoch,
|
|
77
|
+
state: "failed",
|
|
78
|
+
requestedAt,
|
|
79
|
+
startedAt: "startedAt" in restoring ? restoring.startedAt : void 0,
|
|
80
|
+
failedAt,
|
|
81
|
+
error: result.error ?? "workspace_restore_unavailable"
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
throw new Error(result.error ?? "workspace_restore_unavailable");
|
|
85
|
+
}
|
|
86
|
+
await input.request.runtime.reconcile({ epoch: result.epoch, checkpointId: checkpoint.id });
|
|
87
|
+
const ready = await input.leaseStore.update(input.workspaceId, result.epoch, {
|
|
88
|
+
restore: {
|
|
89
|
+
checkpointId: checkpoint.id,
|
|
90
|
+
sourceEpoch: checkpoint.sourceEpoch,
|
|
91
|
+
state: "ready",
|
|
92
|
+
requestedAt,
|
|
93
|
+
startedAt: "startedAt" in restoring && restoring.startedAt !== void 0 ? restoring.startedAt : (input.now ?? Date.now)(),
|
|
94
|
+
completedAt: (input.now ?? Date.now)()
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
if (!ready) throw new Error("workspace_restore_epoch_fenced");
|
|
98
|
+
return { status: "ready", lease: ready, checkpoint };
|
|
99
|
+
}
|
|
100
|
+
async function requireLease(store, workspaceId) {
|
|
101
|
+
const lease = await store.get(workspaceId);
|
|
102
|
+
if (!lease) throw new Error("workspace_checkpoint_lease_missing");
|
|
103
|
+
return lease;
|
|
104
|
+
}
|
|
105
|
+
function requireCaptureSource(value) {
|
|
106
|
+
if (value === "preserved" || value === "stopped" || value === "deleted") return value;
|
|
107
|
+
throw new Error("workspace_checkpoint_capabilities_invalid");
|
|
108
|
+
}
|
|
109
|
+
function requireRestoreMount(value) {
|
|
110
|
+
if (value === "same-resource" || value === "copy-on-write" || value === "new-resource") return value;
|
|
111
|
+
throw new Error("workspace_checkpoint_capabilities_invalid");
|
|
112
|
+
}
|
|
113
|
+
export {
|
|
114
|
+
captureSandboxCheckpoint,
|
|
115
|
+
restoreSandboxCheckpoint
|
|
116
|
+
};
|
|
@@ -3,3 +3,14 @@
|
|
|
3
3
|
* Daytona currently accepts at most 10 entries.
|
|
4
4
|
*/
|
|
5
5
|
export declare function formatDaytonaAllowList(cidrs: string[]): string;
|
|
6
|
+
/**
|
|
7
|
+
* Format hostnames for Daytona SDK `domainAllowList` parameter.
|
|
8
|
+
*
|
|
9
|
+
* Deliberately does NOT truncate, unlike the CIDR formatter above. Silently
|
|
10
|
+
* dropping entries from an egress allowlist is the worst of both worlds: the
|
|
11
|
+
* sandbox stays contained, but it loses reachability the caller believed it
|
|
12
|
+
* granted and nothing anywhere says so. Daytona documents no cap on
|
|
13
|
+
* `domainAllowList`; if one exists, an over-long list fails the create call
|
|
14
|
+
* loudly, which is the outcome we want.
|
|
15
|
+
*/
|
|
16
|
+
export declare function formatDaytonaDomainAllowList(hosts: string[]): string;
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
function formatDaytonaAllowList(cidrs) {
|
|
3
3
|
return cidrs.slice(0, 10).join(",");
|
|
4
4
|
}
|
|
5
|
+
function formatDaytonaDomainAllowList(hosts) {
|
|
6
|
+
return [...new Set(hosts)].join(",");
|
|
7
|
+
}
|
|
5
8
|
export {
|
|
6
|
-
formatDaytonaAllowList
|
|
9
|
+
formatDaytonaAllowList,
|
|
10
|
+
formatDaytonaDomainAllowList
|
|
7
11
|
};
|
package/dist/driver-catalog.d.ts
CHANGED
|
@@ -1,65 +1,18 @@
|
|
|
1
|
-
import type
|
|
2
|
-
|
|
3
|
-
export
|
|
4
|
-
export type SandboxDriverAuth = {
|
|
5
|
-
daytona?: {
|
|
6
|
-
api_key?: string;
|
|
7
|
-
};
|
|
8
|
-
modal?: {
|
|
9
|
-
token_id?: string;
|
|
10
|
-
token_secret?: string;
|
|
11
|
-
};
|
|
12
|
-
vercel?: {
|
|
13
|
-
access_token?: string;
|
|
14
|
-
team_id?: string;
|
|
15
|
-
project_id?: string;
|
|
16
|
-
};
|
|
17
|
-
cloudflare?: {
|
|
18
|
-
api_token?: string;
|
|
19
|
-
worker_url?: string;
|
|
20
|
-
};
|
|
21
|
-
box?: {
|
|
22
|
-
api_key?: string;
|
|
23
|
-
};
|
|
24
|
-
docker?: {
|
|
25
|
-
image?: string;
|
|
26
|
-
};
|
|
27
|
-
};
|
|
28
|
-
export type SandboxDriverConfig = {
|
|
29
|
-
default_driver?: SandboxDriverID;
|
|
30
|
-
auth?: SandboxDriverAuth;
|
|
31
|
-
};
|
|
1
|
+
import { validateSandboxPersistenceCapabilities, type SandboxDriverMetadata } from "./index";
|
|
2
|
+
import { defaultSandboxDriverID, listSandboxDrivers, sandboxDriverId, type SandboxDriverAuth, type SandboxDriverConfig, type SandboxDriverEnv, type SandboxDriverID } from "@claxedo/sandbox-contract";
|
|
3
|
+
export { defaultSandboxDriverID, listSandboxDrivers, sandboxDriverId };
|
|
32
4
|
export type SandboxDriverCatalogEntry = {
|
|
33
5
|
id: SandboxDriverID;
|
|
34
6
|
label: string;
|
|
35
7
|
metadata: SandboxDriverMetadata;
|
|
36
|
-
credentialFields:
|
|
8
|
+
credentialFields: ReadonlyArray<{
|
|
37
9
|
key: string;
|
|
38
10
|
label: string;
|
|
39
11
|
secret?: boolean;
|
|
40
12
|
}>;
|
|
41
13
|
};
|
|
14
|
+
export { validateSandboxPersistenceCapabilities };
|
|
42
15
|
export declare const sandboxDriverCatalog: Record<SandboxDriverID, SandboxDriverCatalogEntry>;
|
|
43
|
-
export declare function isSandboxDriverID(input: string | undefined): input is SandboxDriverID;
|
|
44
|
-
export declare function sandboxDriverId(input: string | undefined, cfg?: SandboxDriverConfig, env?: SandboxDriverEnv): "box" | "cloudflare" | "daytona" | "docker" | "modal" | "vercel" | undefined;
|
|
45
|
-
export declare function defaultSandboxDriverID(cfg?: SandboxDriverConfig, env?: SandboxDriverEnv): SandboxDriverID;
|
|
46
16
|
export declare function sandboxDriverAuth<T extends SandboxDriverID>(cfg: SandboxDriverConfig | undefined, id: T, env?: SandboxDriverEnv): SandboxDriverAuth[T] | undefined;
|
|
47
17
|
export declare function hasSandboxDriverAuth(cfg: SandboxDriverConfig | undefined, id: SandboxDriverID, env?: SandboxDriverEnv): boolean;
|
|
48
18
|
export declare function dockerSandboxDriverEnabled(env?: SandboxDriverEnv): boolean;
|
|
49
|
-
export declare function listSandboxDrivers(cfg?: SandboxDriverConfig, env?: SandboxDriverEnv, managedDriverIds?: ReadonlySet<string>): {
|
|
50
|
-
default_driver: "box" | "cloudflare" | "daytona" | "docker" | "modal" | "vercel";
|
|
51
|
-
drivers: {
|
|
52
|
-
id: "box" | "cloudflare" | "daytona" | "docker" | "modal" | "vercel";
|
|
53
|
-
label: string;
|
|
54
|
-
fields: {
|
|
55
|
-
key: string;
|
|
56
|
-
label: string;
|
|
57
|
-
secret?: boolean;
|
|
58
|
-
}[];
|
|
59
|
-
configured: boolean;
|
|
60
|
-
source: "config" | "managed" | "none";
|
|
61
|
-
default: boolean;
|
|
62
|
-
}[];
|
|
63
|
-
};
|
|
64
|
-
type SandboxDriverEnv = Record<string, string | undefined>;
|
|
65
|
-
export {};
|