@claxedo/sandbox-manager 0.10.3 → 0.10.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/dist/driver-catalog.d.ts +1 -2
- package/dist/driver-catalog.mjs +4 -8
- package/dist/drivers/agent37.mjs +3 -5
- package/dist/drivers/boat-client.d.ts +1 -1
- package/dist/drivers/boat-template.mjs +20 -21
- package/dist/drivers/boat.mjs +14 -12
- package/dist/drivers/cloudflare.mjs +33 -39
- package/dist/drivers/docker.mjs +18 -17
- package/dist/drivers/local-brokering.mjs +2 -0
- package/dist/drivers/modal.mjs +4 -9
- package/dist/drivers/vercel.mjs +9 -12
- package/dist/index.mjs +0 -11
- package/dist/json.d.ts +1 -4
- package/dist/lease-failure.d.ts +0 -2
- package/dist/runtime-env.d.ts +0 -7
- package/dist/runtime-env.mjs +0 -10
- package/package.json +3 -3
package/dist/driver-catalog.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { validateSandboxPersistenceCapabilities, type SandboxDriverMetadata } from "./contract";
|
|
2
2
|
import { type SandboxDriverBilling } from "./driver-billing";
|
|
3
|
-
import { sandboxDriverId, type
|
|
3
|
+
import { sandboxDriverId, type SandboxDriverID } from "@claxedo/sandbox-contract";
|
|
4
4
|
export { sandboxDriverId };
|
|
5
5
|
export { sandboxMachineCostUsd, sandboxMachineRate, type SandboxDriverBilling, type SandboxMachineRate } from "./driver-billing";
|
|
6
6
|
export type SandboxDriverCatalogEntry<ID extends string = SandboxDriverID> = {
|
|
@@ -50,4 +50,3 @@ export declare const localBrokeringTestDriverCatalogEntry: {
|
|
|
50
50
|
};
|
|
51
51
|
};
|
|
52
52
|
export declare const sandboxDriverCatalog: Record<SandboxDriverID, SandboxDriverCatalogEntry>;
|
|
53
|
-
export declare function dockerSandboxDriverEnabled(env?: SandboxDriverEnv): boolean;
|
package/dist/driver-catalog.mjs
CHANGED
|
@@ -82,6 +82,9 @@ function trimToUndefined(value) {
|
|
|
82
82
|
const trimmed = value.trim();
|
|
83
83
|
return trimmed.length > 0 ? trimmed : void 0;
|
|
84
84
|
}
|
|
85
|
+
function isEnabledFlag(value) {
|
|
86
|
+
return ["1", "true", "yes", "on"].includes(value?.trim().toLowerCase() ?? "");
|
|
87
|
+
}
|
|
85
88
|
var sandboxDriverIds = ["modal", "vercel", "cloudflare", "boat", "agent37", "docker"];
|
|
86
89
|
var sandboxDriverCredentialFields = {
|
|
87
90
|
modal: [
|
|
@@ -112,11 +115,8 @@ var sandboxDriverLabels = {
|
|
|
112
115
|
function isSandboxDriverID(input) {
|
|
113
116
|
return !!input && sandboxDriverIds.includes(input);
|
|
114
117
|
}
|
|
115
|
-
function enabled(input) {
|
|
116
|
-
return ["1", "true", "yes", "on"].includes(input?.trim().toLowerCase() ?? "");
|
|
117
|
-
}
|
|
118
118
|
function dockerSandboxDriverEnabled(env = process.env) {
|
|
119
|
-
return
|
|
119
|
+
return isEnabledFlag(env.CLAXEDO_ENABLE_DOCKER_SANDBOX) || isEnabledFlag(env.CLAXEDO_DEV_DOCKER_SANDBOX);
|
|
120
120
|
}
|
|
121
121
|
function sandboxDriverAuthValues(cfg, id, env = process.env) {
|
|
122
122
|
if (id === "modal") {
|
|
@@ -351,11 +351,7 @@ var sandboxDriverCatalog = {
|
|
|
351
351
|
}
|
|
352
352
|
}
|
|
353
353
|
};
|
|
354
|
-
function dockerSandboxDriverEnabled2(env = process.env) {
|
|
355
|
-
return dockerSandboxDriverEnabled(env);
|
|
356
|
-
}
|
|
357
354
|
export {
|
|
358
|
-
dockerSandboxDriverEnabled2 as dockerSandboxDriverEnabled,
|
|
359
355
|
localBrokeringTestDriverCatalogEntry,
|
|
360
356
|
sandboxDriverCatalog,
|
|
361
357
|
sandboxDriverId,
|
package/dist/drivers/agent37.mjs
CHANGED
|
@@ -298,10 +298,8 @@ function isRecord(value) {
|
|
|
298
298
|
function asRecord(value) {
|
|
299
299
|
return isRecord(value) ? value : void 0;
|
|
300
300
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
function num(input) {
|
|
304
|
-
return typeof input === "number" ? input : void 0;
|
|
301
|
+
function asNumber(value) {
|
|
302
|
+
return typeof value === "number" ? value : void 0;
|
|
305
303
|
}
|
|
306
304
|
|
|
307
305
|
// src/lease-failure.ts
|
|
@@ -581,7 +579,7 @@ function driverErrorSignals(err) {
|
|
|
581
579
|
return {
|
|
582
580
|
// `response.status` is the axios shape; `statusCode` is what SDK-native
|
|
583
581
|
// error classes expose instead.
|
|
584
|
-
status:
|
|
582
|
+
status: asNumber(nested.status) ?? asNumber(shaped.status) ?? asNumber(shaped.statusCode),
|
|
585
583
|
text: `${textOf(shaped.code)} ${textOf(shaped.name)} ${textOf(shaped.message)}`.toLowerCase()
|
|
586
584
|
};
|
|
587
585
|
}
|
|
@@ -44,7 +44,7 @@ export declare class BoatApiError extends Error {
|
|
|
44
44
|
});
|
|
45
45
|
}
|
|
46
46
|
export declare function invalid(): never;
|
|
47
|
-
export declare function
|
|
47
|
+
export declare function responseString(value: unknown): string;
|
|
48
48
|
export type BoatClientOptions = {
|
|
49
49
|
apiKey: string;
|
|
50
50
|
baseUrl?: string;
|
|
@@ -429,10 +429,8 @@ function isRecord(value) {
|
|
|
429
429
|
function asRecord(value) {
|
|
430
430
|
return isRecord(value) ? value : void 0;
|
|
431
431
|
}
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
function num(input) {
|
|
435
|
-
return typeof input === "number" ? input : void 0;
|
|
432
|
+
function asNumber(value) {
|
|
433
|
+
return typeof value === "number" ? value : void 0;
|
|
436
434
|
}
|
|
437
435
|
|
|
438
436
|
// ../claxedo-helpers/dist/deadline.mjs
|
|
@@ -497,7 +495,7 @@ function startLimitOf(body) {
|
|
|
497
495
|
function invalid() {
|
|
498
496
|
throw new BoatApiError("Boat API returned an invalid response", "invalid_response");
|
|
499
497
|
}
|
|
500
|
-
function
|
|
498
|
+
function responseString(value) {
|
|
501
499
|
return typeof value === "string" ? value : invalid();
|
|
502
500
|
}
|
|
503
501
|
function requiredFlag(value) {
|
|
@@ -511,7 +509,7 @@ function isSandboxState(value) {
|
|
|
511
509
|
}
|
|
512
510
|
function sandbox(body) {
|
|
513
511
|
const value = asRecord(body.sandbox) ?? invalid();
|
|
514
|
-
const id =
|
|
512
|
+
const id = responseString(value.id);
|
|
515
513
|
if (!/^bx_[23456789abcdefghjkmnpqrstuvwxyz]{8}$/.test(id) || !isSandboxState(value.state)) invalid();
|
|
516
514
|
return { id, state: value.state, hydrated: value.hydrated === true };
|
|
517
515
|
}
|
|
@@ -634,8 +632,8 @@ function createBoatClient(options) {
|
|
|
634
632
|
const body = await api(`${path(id)}/commands`, ["command.finished"], { method: "POST", body: input, timeoutMs });
|
|
635
633
|
return {
|
|
636
634
|
success: requiredFlag(body.success),
|
|
637
|
-
stdout:
|
|
638
|
-
stderr:
|
|
635
|
+
stdout: responseString(body.stdout),
|
|
636
|
+
stderr: responseString(body.stderr),
|
|
639
637
|
exitCode: commandExitCode(body.exitCode),
|
|
640
638
|
timedOut: requiredFlag(body.timedOut)
|
|
641
639
|
};
|
|
@@ -653,7 +651,7 @@ function driverErrorSignals(err) {
|
|
|
653
651
|
return {
|
|
654
652
|
// `response.status` is the axios shape; `statusCode` is what SDK-native
|
|
655
653
|
// error classes expose instead.
|
|
656
|
-
status:
|
|
654
|
+
status: asNumber(nested.status) ?? asNumber(shaped.status) ?? asNumber(shaped.statusCode),
|
|
657
655
|
text: `${textOf(shaped.code)} ${textOf(shaped.name)} ${textOf(shaped.message)}`.toLowerCase()
|
|
658
656
|
};
|
|
659
657
|
}
|
|
@@ -766,6 +764,13 @@ function machineBootScripts(boot) {
|
|
|
766
764
|
};
|
|
767
765
|
}
|
|
768
766
|
|
|
767
|
+
// ../claxedo-helpers/dist/index.mjs
|
|
768
|
+
function sleep(ms) {
|
|
769
|
+
return new Promise((resolve) => {
|
|
770
|
+
setTimeout(resolve, ms);
|
|
771
|
+
});
|
|
772
|
+
}
|
|
773
|
+
|
|
769
774
|
// src/drivers/boat.ts
|
|
770
775
|
var DEFAULT_RUNTIME_COMMAND = "/usr/local/bin/workspace-runtime";
|
|
771
776
|
var DEFAULT_WORKSPACE_DIR = "/workspace";
|
|
@@ -800,9 +805,6 @@ function archivedOrThrow(err) {
|
|
|
800
805
|
if (err instanceof BoatApiError && err.code === "stop_failed" && err.sandboxState === "archived") return;
|
|
801
806
|
hostGoneOrThrow(err);
|
|
802
807
|
}
|
|
803
|
-
function sleep(ms) {
|
|
804
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
805
|
-
}
|
|
806
808
|
function scrubbedTail(text, secrets) {
|
|
807
809
|
return redactWorkspaceRuntimeBootSecrets(text, secrets).trim().slice(-STDERR_TAIL_CHARS);
|
|
808
810
|
}
|
|
@@ -1108,13 +1110,13 @@ var STATUSES = ["saving", "ready", "failed"];
|
|
|
1108
1110
|
function namedSnapshot(value) {
|
|
1109
1111
|
const snapshot = asRecord(value) ?? invalid();
|
|
1110
1112
|
const status = STATUSES.find((known) => known === snapshot.status) ?? invalid();
|
|
1111
|
-
return { name:
|
|
1113
|
+
return { name: responseString(snapshot.name), status, createdAt: responseString(snapshot.createdAt) };
|
|
1112
1114
|
}
|
|
1113
1115
|
function share(value) {
|
|
1114
1116
|
const entry = asRecord(value) ?? invalid();
|
|
1115
|
-
const status =
|
|
1117
|
+
const status = responseString(entry.status);
|
|
1116
1118
|
if (status !== "active" && status !== "revoked") invalid();
|
|
1117
|
-
return { id:
|
|
1119
|
+
return { id: responseString(entry.id), status, createdAt: responseString(entry.createdAt) };
|
|
1118
1120
|
}
|
|
1119
1121
|
function list(value, item) {
|
|
1120
1122
|
return Array.isArray(value) ? value.map(item) : invalid();
|
|
@@ -1145,7 +1147,7 @@ function createBoatNamedSnapshotClient(options) {
|
|
|
1145
1147
|
/** Boat shows the code only in this answer and keeps a hash of it. */
|
|
1146
1148
|
async share(name) {
|
|
1147
1149
|
const body = await api(`${path(name)}/shares`, ["snapshot.share.created"], { method: "POST" });
|
|
1148
|
-
return { shareCode:
|
|
1150
|
+
return { shareCode: responseString(body.shareCode), share: share(body.share) };
|
|
1149
1151
|
},
|
|
1150
1152
|
async shares(name) {
|
|
1151
1153
|
return list((await api(`${path(name)}/shares`, ["snapshot.share.list"])).shares, share);
|
|
@@ -1164,9 +1166,6 @@ var DEFAULT_POLL_INTERVAL_MS = 2e3;
|
|
|
1164
1166
|
var DEFAULT_HYDRATION_TIMEOUT_MS = 10 * 6e4;
|
|
1165
1167
|
var DEFAULT_STOP_TIMEOUT_MS = 10 * 6e4;
|
|
1166
1168
|
var DEFAULT_SAVE_TIMEOUT_MS = 10 * 6e4;
|
|
1167
|
-
function sleep2(ms) {
|
|
1168
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1169
|
-
}
|
|
1170
1169
|
async function boatRuntimeTemplateName(image, prefix = DEFAULT_PREFIX) {
|
|
1171
1170
|
const digest = new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(image)));
|
|
1172
1171
|
const name = `${prefix}${Array.from(digest, (byte) => byte.toString(16).padStart(2, "0")).join("").slice(0, NAME_HASH_CHARS)}`;
|
|
@@ -1188,7 +1187,7 @@ async function pollBoat(label, timeoutMs, intervalMs, read) {
|
|
|
1188
1187
|
const value = await read();
|
|
1189
1188
|
if (value !== void 0) return value;
|
|
1190
1189
|
if (Date.now() >= deadline) throw new Error(`${label} did not happen within ${Math.round(timeoutMs / 1e3)} s`);
|
|
1191
|
-
await
|
|
1190
|
+
await sleep(intervalMs);
|
|
1192
1191
|
}
|
|
1193
1192
|
}
|
|
1194
1193
|
async function ensureBoatRuntimeTemplate(options) {
|
|
@@ -1236,7 +1235,7 @@ async function buildTemplate(options, name) {
|
|
|
1236
1235
|
const lease = sandboxLease({ workspaceId, homeRegion: "auto", driver: "boat", epoch, sandboxId });
|
|
1237
1236
|
const result = sandboxId ? await driver.resumeHost({ lease, ensure: ensure(epoch) }) : await driver.ensureHost(ensure(epoch));
|
|
1238
1237
|
if (!("provisioning" in result)) return result;
|
|
1239
|
-
await
|
|
1238
|
+
await sleep(result.retryAfterMs);
|
|
1240
1239
|
}
|
|
1241
1240
|
};
|
|
1242
1241
|
const archived = (id) => pollBoat(`Boat ${id} stop`, options.stopTimeoutMs ?? DEFAULT_STOP_TIMEOUT_MS, interval, async () => (await sandboxes.get(id)).state === "archived" ? true : void 0);
|
package/dist/drivers/boat.mjs
CHANGED
|
@@ -397,10 +397,8 @@ function isRecord(value) {
|
|
|
397
397
|
function asRecord(value) {
|
|
398
398
|
return isRecord(value) ? value : void 0;
|
|
399
399
|
}
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
function num(input) {
|
|
403
|
-
return typeof input === "number" ? input : void 0;
|
|
400
|
+
function asNumber(value) {
|
|
401
|
+
return typeof value === "number" ? value : void 0;
|
|
404
402
|
}
|
|
405
403
|
|
|
406
404
|
// ../claxedo-helpers/dist/deadline.mjs
|
|
@@ -465,7 +463,7 @@ function startLimitOf(body) {
|
|
|
465
463
|
function invalid() {
|
|
466
464
|
throw new BoatApiError("Boat API returned an invalid response", "invalid_response");
|
|
467
465
|
}
|
|
468
|
-
function
|
|
466
|
+
function responseString(value) {
|
|
469
467
|
return typeof value === "string" ? value : invalid();
|
|
470
468
|
}
|
|
471
469
|
function requiredFlag(value) {
|
|
@@ -479,7 +477,7 @@ function isSandboxState(value) {
|
|
|
479
477
|
}
|
|
480
478
|
function sandbox(body) {
|
|
481
479
|
const value = asRecord(body.sandbox) ?? invalid();
|
|
482
|
-
const id =
|
|
480
|
+
const id = responseString(value.id);
|
|
483
481
|
if (!/^bx_[23456789abcdefghjkmnpqrstuvwxyz]{8}$/.test(id) || !isSandboxState(value.state)) invalid();
|
|
484
482
|
return { id, state: value.state, hydrated: value.hydrated === true };
|
|
485
483
|
}
|
|
@@ -602,8 +600,8 @@ function createBoatClient(options) {
|
|
|
602
600
|
const body = await api(`${path(id)}/commands`, ["command.finished"], { method: "POST", body: input, timeoutMs });
|
|
603
601
|
return {
|
|
604
602
|
success: requiredFlag(body.success),
|
|
605
|
-
stdout:
|
|
606
|
-
stderr:
|
|
603
|
+
stdout: responseString(body.stdout),
|
|
604
|
+
stderr: responseString(body.stderr),
|
|
607
605
|
exitCode: commandExitCode(body.exitCode),
|
|
608
606
|
timedOut: requiredFlag(body.timedOut)
|
|
609
607
|
};
|
|
@@ -621,7 +619,7 @@ function driverErrorSignals(err) {
|
|
|
621
619
|
return {
|
|
622
620
|
// `response.status` is the axios shape; `statusCode` is what SDK-native
|
|
623
621
|
// error classes expose instead.
|
|
624
|
-
status:
|
|
622
|
+
status: asNumber(nested.status) ?? asNumber(shaped.status) ?? asNumber(shaped.statusCode),
|
|
625
623
|
text: `${textOf(shaped.code)} ${textOf(shaped.name)} ${textOf(shaped.message)}`.toLowerCase()
|
|
626
624
|
};
|
|
627
625
|
}
|
|
@@ -723,6 +721,13 @@ function machineBootScripts(boot) {
|
|
|
723
721
|
};
|
|
724
722
|
}
|
|
725
723
|
|
|
724
|
+
// ../claxedo-helpers/dist/index.mjs
|
|
725
|
+
function sleep(ms) {
|
|
726
|
+
return new Promise((resolve) => {
|
|
727
|
+
setTimeout(resolve, ms);
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
|
|
726
731
|
// src/drivers/boat.ts
|
|
727
732
|
function formatBoatRuntimeTemplate(template) {
|
|
728
733
|
return JSON.stringify({ image: template.image, shareCode: template.shareCode });
|
|
@@ -773,9 +778,6 @@ function archivedOrThrow(err) {
|
|
|
773
778
|
if (err instanceof BoatApiError && err.code === "stop_failed" && err.sandboxState === "archived") return;
|
|
774
779
|
hostGoneOrThrow(err);
|
|
775
780
|
}
|
|
776
|
-
function sleep(ms) {
|
|
777
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
778
|
-
}
|
|
779
781
|
function scrubbedTail(text, secrets) {
|
|
780
782
|
return redactWorkspaceRuntimeBootSecrets(text, secrets).trim().slice(-STDERR_TAIL_CHARS);
|
|
781
783
|
}
|
|
@@ -254,6 +254,17 @@ var sandboxDriverCatalog = {
|
|
|
254
254
|
}
|
|
255
255
|
};
|
|
256
256
|
|
|
257
|
+
// ../claxedo-helpers/dist/deadline.mjs
|
|
258
|
+
async function withDeadlineSignal(timeoutMs, work, parent) {
|
|
259
|
+
const deadline = new AbortController();
|
|
260
|
+
const timer = setTimeout(() => deadline.abort(new DOMException("The operation timed out.", "TimeoutError")), timeoutMs);
|
|
261
|
+
try {
|
|
262
|
+
return await work(parent ? AbortSignal.any([parent, deadline.signal]) : deadline.signal);
|
|
263
|
+
} finally {
|
|
264
|
+
clearTimeout(timer);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
257
268
|
// src/egress-policy.ts
|
|
258
269
|
function brokeredSecretPlaceholder(name) {
|
|
259
270
|
return `claxedo-broker:${name}`;
|
|
@@ -292,10 +303,11 @@ function isRecord(value) {
|
|
|
292
303
|
function asRecord(value) {
|
|
293
304
|
return isRecord(value) ? value : void 0;
|
|
294
305
|
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
306
|
+
function isNonEmptyString(value) {
|
|
307
|
+
return typeof value === "string" && value.length > 0;
|
|
308
|
+
}
|
|
309
|
+
function nonEmptyString(value) {
|
|
310
|
+
return isNonEmptyString(value) ? value : void 0;
|
|
299
311
|
}
|
|
300
312
|
|
|
301
313
|
// src/runtime-env.ts
|
|
@@ -387,19 +399,6 @@ var DEFAULT_RUNTIME_COMMAND = "/usr/local/bin/workspace-runtime";
|
|
|
387
399
|
var DEFAULT_TIMEOUT_MS = 45e3;
|
|
388
400
|
var DEFAULT_ENSURE_TIMEOUT_MS = 3e5;
|
|
389
401
|
var DEFAULT_SNAPSHOT_TIMEOUT_MS = 18e4;
|
|
390
|
-
function deadlineSignal(timeoutMs) {
|
|
391
|
-
const controller = new AbortController();
|
|
392
|
-
const timer = setTimeout(
|
|
393
|
-
() => controller.abort(new DOMException("The operation timed out", "TimeoutError")),
|
|
394
|
-
timeoutMs
|
|
395
|
-
);
|
|
396
|
-
return {
|
|
397
|
-
signal: controller.signal,
|
|
398
|
-
cleanup() {
|
|
399
|
-
clearTimeout(timer);
|
|
400
|
-
}
|
|
401
|
-
};
|
|
402
|
-
}
|
|
403
402
|
var RUNTIME_HOME = "/home/claxedo";
|
|
404
403
|
function sandboxIdFor(workspaceId) {
|
|
405
404
|
return `claxedo-${workspaceId}`;
|
|
@@ -431,19 +430,17 @@ function createCloudflareSandboxDriver(options) {
|
|
|
431
430
|
};
|
|
432
431
|
async function call(sandboxId, action, body, method = "POST") {
|
|
433
432
|
const url = `${base}/sandbox/${encodeURIComponent(sandboxId)}${action ? `/${action}` : ""}`;
|
|
434
|
-
const
|
|
435
|
-
|
|
433
|
+
const deadlineMs = action === "ensure-runtime" ? ensureTimeoutMs : action === "snapshot" ? snapshotTimeoutMs : timeoutMs;
|
|
434
|
+
return withDeadlineSignal(deadlineMs, async (signal) => {
|
|
436
435
|
const res = await doFetch(url, {
|
|
437
436
|
method,
|
|
438
437
|
headers,
|
|
439
438
|
...method === "POST" ? { body: JSON.stringify(body) } : {},
|
|
440
|
-
signal
|
|
439
|
+
signal
|
|
441
440
|
});
|
|
442
441
|
const data = asRecord(await res.json().catch(() => ({}))) ?? {};
|
|
443
442
|
return { status: res.status, data };
|
|
444
|
-
}
|
|
445
|
-
deadline.cleanup();
|
|
446
|
-
}
|
|
443
|
+
});
|
|
447
444
|
}
|
|
448
445
|
function workspaceDirectory(input) {
|
|
449
446
|
return input.workspaceRoot ?? workspaceDir;
|
|
@@ -521,16 +518,16 @@ function createCloudflareSandboxDriver(options) {
|
|
|
521
518
|
});
|
|
522
519
|
if (!response) return { provisioning: true, retryAfterMs: 0 };
|
|
523
520
|
const { status, data } = response;
|
|
524
|
-
const runtimeUrl =
|
|
521
|
+
const runtimeUrl = nonEmptyString(data.url);
|
|
525
522
|
if (status === 503 && data.error === "workspace-runtime did not become ready") {
|
|
526
523
|
return { provisioning: true, retryAfterMs: 0 };
|
|
527
524
|
}
|
|
528
|
-
if (data.exited === true) throw new SandboxRuntimeBootError(
|
|
525
|
+
if (data.exited === true) throw new SandboxRuntimeBootError(nonEmptyString(data.error) ?? "The workspace runtime exited before it was ready");
|
|
529
526
|
if (status === 410 && isSandboxCheckpointUnusableCause(data.checkpointUnusable)) {
|
|
530
|
-
throw new SandboxCheckpointUnusableError(data.checkpointUnusable,
|
|
527
|
+
throw new SandboxCheckpointUnusableError(data.checkpointUnusable, nonEmptyString(data.error) ?? "This workspace's saved files cannot be restored; choose Start fresh.");
|
|
531
528
|
}
|
|
532
529
|
if (status >= 400 || !runtimeUrl) {
|
|
533
|
-
const reason = `Cloudflare ensure-runtime failed (${status}): ${
|
|
530
|
+
const reason = `Cloudflare ensure-runtime failed (${status}): ${nonEmptyString(data.error) ?? "no runtime url"}`;
|
|
534
531
|
throw status === 401 || status === 403 ? new SandboxProviderKeyRefusedError(reason) : new Error(reason);
|
|
535
532
|
}
|
|
536
533
|
if (net && asRecord(data.egress)?.contained !== true) {
|
|
@@ -574,12 +571,11 @@ function createCloudflareSandboxDriver(options) {
|
|
|
574
571
|
//
|
|
575
572
|
// A missing registry route or R2 binding cannot establish an empty inventory.
|
|
576
573
|
async list() {
|
|
577
|
-
|
|
578
|
-
try {
|
|
574
|
+
return withDeadlineSignal(timeoutMs, async (signal) => {
|
|
579
575
|
const res = await doFetch(`${base}/sandboxes`, {
|
|
580
576
|
method: "GET",
|
|
581
577
|
headers,
|
|
582
|
-
signal
|
|
578
|
+
signal
|
|
583
579
|
});
|
|
584
580
|
if (res.status === 404 || res.status === 501) {
|
|
585
581
|
throw new CloudflareSandboxListingUnsupportedError(`Cloudflare sandbox Worker cannot enumerate sandboxes (${res.status}); requires the /sandboxes registry route and SANDBOX_REGISTRY binding`);
|
|
@@ -588,11 +584,11 @@ function createCloudflareSandboxDriver(options) {
|
|
|
588
584
|
if (!data) throw new Error("Invalid Cloudflare sandbox listing envelope");
|
|
589
585
|
if (data.supported === false) {
|
|
590
586
|
throw new CloudflareSandboxListingUnsupportedError(
|
|
591
|
-
|
|
587
|
+
nonEmptyString(data.error) ?? `Cloudflare sandbox Worker cannot enumerate sandboxes (${res.status}) \u2014 deploy a Worker with the /sandboxes registry route and an R2 SANDBOX_REGISTRY binding`
|
|
592
588
|
);
|
|
593
589
|
}
|
|
594
590
|
if (!res.ok) {
|
|
595
|
-
throw new Error(`Cloudflare sandbox listing failed (${res.status}): ${
|
|
591
|
+
throw new Error(`Cloudflare sandbox listing failed (${res.status}): ${nonEmptyString(data.error) ?? "unknown error"}`);
|
|
596
592
|
}
|
|
597
593
|
return registryEntries(data.sandboxes).flatMap((entry) => {
|
|
598
594
|
const sandboxId = entry.sandboxId;
|
|
@@ -611,9 +607,7 @@ function createCloudflareSandboxDriver(options) {
|
|
|
611
607
|
};
|
|
612
608
|
return [target];
|
|
613
609
|
});
|
|
614
|
-
}
|
|
615
|
-
deadline.cleanup();
|
|
616
|
-
}
|
|
610
|
+
});
|
|
617
611
|
},
|
|
618
612
|
metadata: {
|
|
619
613
|
driverRunsIn: ["worker"],
|
|
@@ -635,14 +629,14 @@ function createCloudflareSandboxDriver(options) {
|
|
|
635
629
|
async stop(target) {
|
|
636
630
|
const { status, data } = await call(target.sandboxId, "stop", { epoch: target.epoch });
|
|
637
631
|
if (status >= 400 || data.ok !== true) {
|
|
638
|
-
throw new Error(`Cloudflare stop failed (${status}) for ${target.sandboxId}: ${
|
|
632
|
+
throw new Error(`Cloudflare stop failed (${status}) for ${target.sandboxId}: ${nonEmptyString(data.error) ?? "not stopped"}`);
|
|
639
633
|
}
|
|
640
634
|
},
|
|
641
635
|
// The sandbox's object outlives its container and keeps the snapshots it took, so a container that is not running is a stopped host, never a gone one.
|
|
642
636
|
async inspect(target) {
|
|
643
637
|
const { status, data } = await call(target.sandboxId, "inspect", {});
|
|
644
638
|
if (status < 200 || status >= 300 || typeof data.running !== "boolean") {
|
|
645
|
-
throw new Error(`Cloudflare inspect failed (${status}) for ${target.sandboxId}: ${
|
|
639
|
+
throw new Error(`Cloudflare inspect failed (${status}) for ${target.sandboxId}: ${nonEmptyString(data.error) ?? "no container state"}`);
|
|
646
640
|
}
|
|
647
641
|
return data.running ? "serving" : "stopped";
|
|
648
642
|
},
|
|
@@ -654,9 +648,9 @@ function createCloudflareSandboxDriver(options) {
|
|
|
654
648
|
},
|
|
655
649
|
async snapshot(target) {
|
|
656
650
|
const { status, data } = await call(target.sandboxId, "snapshot", {});
|
|
657
|
-
const snapshotId =
|
|
651
|
+
const snapshotId = nonEmptyString(data.snapshotId);
|
|
658
652
|
if (status >= 400 || !snapshotId) {
|
|
659
|
-
throw new Error(`Cloudflare snapshot failed (${status}): ${
|
|
653
|
+
throw new Error(`Cloudflare snapshot failed (${status}): ${nonEmptyString(data.error) ?? "no snapshot id"}`);
|
|
660
654
|
}
|
|
661
655
|
return { snapshotId };
|
|
662
656
|
}
|
package/dist/drivers/docker.mjs
CHANGED
|
@@ -368,10 +368,8 @@ var sandboxDriverCatalog = {
|
|
|
368
368
|
function isRecord(value) {
|
|
369
369
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
370
370
|
}
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
function num(input) {
|
|
374
|
-
return typeof input === "number" ? input : void 0;
|
|
371
|
+
function asNumber(value) {
|
|
372
|
+
return typeof value === "number" ? value : void 0;
|
|
375
373
|
}
|
|
376
374
|
|
|
377
375
|
// src/drivers/transient-error.ts
|
|
@@ -384,7 +382,7 @@ function driverErrorSignals(err) {
|
|
|
384
382
|
return {
|
|
385
383
|
// `response.status` is the axios shape; `statusCode` is what SDK-native
|
|
386
384
|
// error classes expose instead.
|
|
387
|
-
status:
|
|
385
|
+
status: asNumber(nested.status) ?? asNumber(shaped.status) ?? asNumber(shaped.statusCode),
|
|
388
386
|
text: `${textOf(shaped.code)} ${textOf(shaped.name)} ${textOf(shaped.message)}`.toLowerCase()
|
|
389
387
|
};
|
|
390
388
|
}
|
|
@@ -406,6 +404,18 @@ async function withDeadlineSignal(timeoutMs, work, parent) {
|
|
|
406
404
|
}
|
|
407
405
|
}
|
|
408
406
|
|
|
407
|
+
// ../claxedo-helpers/dist/index.mjs
|
|
408
|
+
function sleep(ms) {
|
|
409
|
+
return new Promise((resolve) => {
|
|
410
|
+
setTimeout(resolve, ms);
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// ../claxedo-helpers/dist/env.mjs
|
|
415
|
+
function isEnabledFlag(value) {
|
|
416
|
+
return ["1", "true", "yes", "on"].includes(value?.trim().toLowerCase() ?? "");
|
|
417
|
+
}
|
|
418
|
+
|
|
409
419
|
// src/drivers/docker.ts
|
|
410
420
|
var execFileAsync = promisify(execFile);
|
|
411
421
|
var DEFAULT_OPERATION_TIMEOUT_MS = 6e4;
|
|
@@ -416,7 +426,7 @@ var DEFAULT_WORKSPACE_DIR = "/workspace";
|
|
|
416
426
|
var DOCKER_LABEL = "claxedo";
|
|
417
427
|
var AUTH_STAGE_DIR = "/tmp/claxedo-auth";
|
|
418
428
|
function dockerSandboxSyncLocalAuth(env = process.env) {
|
|
419
|
-
return
|
|
429
|
+
return isEnabledFlag(env.CLAXEDO_DOCKER_SANDBOX_SYNC_LOCAL_AUTH);
|
|
420
430
|
}
|
|
421
431
|
function dockerSandboxAuthHome(env = process.env) {
|
|
422
432
|
return trimToUndefined(env.CLAXEDO_DOCKER_SANDBOX_AUTH_HOME) ?? trimToUndefined(env.HOME) ?? os.homedir();
|
|
@@ -453,9 +463,6 @@ function dockerLocalAuthCandidates(home) {
|
|
|
453
463
|
}
|
|
454
464
|
];
|
|
455
465
|
}
|
|
456
|
-
function enabledFlag(input) {
|
|
457
|
-
return ["1", "true", "yes", "on"].includes(input?.trim().toLowerCase() ?? "");
|
|
458
|
-
}
|
|
459
466
|
function nameFor(workspaceId) {
|
|
460
467
|
const cleanId = workspaceId.toLowerCase().replace(/[^a-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
461
468
|
return `claxedo-${cleanId || "workspace"}-${Date.now().toString(36)}`.slice(0, 63);
|
|
@@ -467,9 +474,6 @@ async function docker(args, timeoutMs = DEFAULT_OPERATION_TIMEOUT_MS, env) {
|
|
|
467
474
|
...env ? { env: { ...process.env, ...env } } : {}
|
|
468
475
|
});
|
|
469
476
|
}
|
|
470
|
-
function sleep(ms) {
|
|
471
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
472
|
-
}
|
|
473
477
|
async function stageLocalAgentAuth(containerId, input) {
|
|
474
478
|
if (!input.syncLocalAuth) return;
|
|
475
479
|
const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "claxedo-docker-auth-"));
|
|
@@ -522,9 +526,6 @@ function labelArgs(input) {
|
|
|
522
526
|
return Object.entries(input).flatMap(([key, value]) => ["--label", `${key}=${value}`]);
|
|
523
527
|
}
|
|
524
528
|
var TRANSIENT_MARKERS = ["timeout", "temporarily unavailable", "connection refused"];
|
|
525
|
-
function transientDriverError(err) {
|
|
526
|
-
return isTransientDriverError(err, TRANSIENT_MARKERS);
|
|
527
|
-
}
|
|
528
529
|
function createDockerSandboxDriver(options) {
|
|
529
530
|
const dockerCommand = options.docker ?? docker;
|
|
530
531
|
const runtimeCommand = options.runtimeCommand ?? DEFAULT_RUNTIME_COMMAND;
|
|
@@ -621,7 +622,7 @@ function createDockerSandboxDriver(options) {
|
|
|
621
622
|
"-lc",
|
|
622
623
|
bootScript(workspaceDirectory(input), runtimeCommand)
|
|
623
624
|
], 12e4, env).catch((err) => {
|
|
624
|
-
if (
|
|
625
|
+
if (isTransientDriverError(err, TRANSIENT_MARKERS)) return void 0;
|
|
625
626
|
throw err;
|
|
626
627
|
});
|
|
627
628
|
if (!created) return { provisioning: true, retryAfterMs: TRANSIENT_DRIVER_RETRY_MS };
|
|
@@ -635,7 +636,7 @@ function createDockerSandboxDriver(options) {
|
|
|
635
636
|
if (!sandboxId) return ensureHost(input.ensure);
|
|
636
637
|
await dockerCommand(["inspect", "-f", "{{.Id}}", sandboxId], timeoutMs);
|
|
637
638
|
await dockerCommand(["start", sandboxId], timeoutMs).catch((err) => {
|
|
638
|
-
if (
|
|
639
|
+
if (isTransientDriverError(err, TRANSIENT_MARKERS)) return void 0;
|
|
639
640
|
throw err;
|
|
640
641
|
});
|
|
641
642
|
return readyTarget(input.ensure, sandboxId, input.ensure.hostId ?? sandboxId);
|
|
@@ -48,6 +48,8 @@ var CLAXEDO_TOOL_NAMES = [
|
|
|
48
48
|
"ui_guide"
|
|
49
49
|
];
|
|
50
50
|
var CLAXEDO_TOOL_NAME_SET = new Set(CLAXEDO_TOOL_NAMES);
|
|
51
|
+
var PROMPT_ATTACHMENT_MAX_BYTES = 32 * 1024 * 1024;
|
|
52
|
+
var PROMPT_ATTACHMENT_UPLOAD_MAX_BODY_BYTES = Math.ceil(PROMPT_ATTACHMENT_MAX_BYTES / 3) * 4 + 64 * 1024;
|
|
51
53
|
var CREDENTIAL_BROKER_ERRORS = {
|
|
52
54
|
binding_route_required: {
|
|
53
55
|
fault: "harness",
|
package/dist/drivers/modal.mjs
CHANGED
|
@@ -347,10 +347,8 @@ function isRecord(value) {
|
|
|
347
347
|
function asRecord(value) {
|
|
348
348
|
return isRecord(value) ? value : void 0;
|
|
349
349
|
}
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
function num(input) {
|
|
353
|
-
return typeof input === "number" ? input : void 0;
|
|
350
|
+
function asNumber(value) {
|
|
351
|
+
return typeof value === "number" ? value : void 0;
|
|
354
352
|
}
|
|
355
353
|
|
|
356
354
|
// src/drivers/transient-error.ts
|
|
@@ -363,7 +361,7 @@ function driverErrorSignals(err) {
|
|
|
363
361
|
return {
|
|
364
362
|
// `response.status` is the axios shape; `statusCode` is what SDK-native
|
|
365
363
|
// error classes expose instead.
|
|
366
|
-
status:
|
|
364
|
+
status: asNumber(nested.status) ?? asNumber(shaped.status) ?? asNumber(shaped.statusCode),
|
|
367
365
|
text: `${textOf(shaped.code)} ${textOf(shaped.name)} ${textOf(shaped.message)}`.toLowerCase()
|
|
368
366
|
};
|
|
369
367
|
}
|
|
@@ -389,9 +387,6 @@ function nameFor(workspaceId) {
|
|
|
389
387
|
return `claxedo-${workspaceId}`;
|
|
390
388
|
}
|
|
391
389
|
var TRANSIENT_MARKERS = ["timeout", "unavailable", "deadline"];
|
|
392
|
-
function transientDriverError(err) {
|
|
393
|
-
return isTransientDriverError(err, TRANSIENT_MARKERS);
|
|
394
|
-
}
|
|
395
390
|
function createModalSandboxDriver(options) {
|
|
396
391
|
let defaultClient;
|
|
397
392
|
function resolveClient() {
|
|
@@ -489,7 +484,7 @@ function createModalSandboxDriver(options) {
|
|
|
489
484
|
...network(input)
|
|
490
485
|
}
|
|
491
486
|
).catch((err) => {
|
|
492
|
-
if (
|
|
487
|
+
if (isTransientDriverError(err, TRANSIENT_MARKERS)) return void 0;
|
|
493
488
|
throw err;
|
|
494
489
|
});
|
|
495
490
|
if (!sandbox) return { provisioning: true, retryAfterMs: TRANSIENT_DRIVER_RETRY_MS };
|
package/dist/drivers/vercel.mjs
CHANGED
|
@@ -334,10 +334,8 @@ function isRecord(value) {
|
|
|
334
334
|
function asRecord(value) {
|
|
335
335
|
return isRecord(value) ? value : void 0;
|
|
336
336
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
function num(input) {
|
|
340
|
-
return typeof input === "number" ? input : void 0;
|
|
337
|
+
function asNumber(value) {
|
|
338
|
+
return typeof value === "number" ? value : void 0;
|
|
341
339
|
}
|
|
342
340
|
|
|
343
341
|
// src/drivers/transient-error.ts
|
|
@@ -350,7 +348,7 @@ function driverErrorSignals(err) {
|
|
|
350
348
|
return {
|
|
351
349
|
// `response.status` is the axios shape; `statusCode` is what SDK-native
|
|
352
350
|
// error classes expose instead.
|
|
353
|
-
status:
|
|
351
|
+
status: asNumber(nested.status) ?? asNumber(shaped.status) ?? asNumber(shaped.statusCode),
|
|
354
352
|
text: `${textOf(shaped.code)} ${textOf(shaped.name)} ${textOf(shaped.message)}`.toLowerCase()
|
|
355
353
|
};
|
|
356
354
|
}
|
|
@@ -379,7 +377,8 @@ var HARNESS_RELEASE_AGE_EXCLUSIONS = `printf '%s\\n' ${[
|
|
|
379
377
|
"@anthropic-ai/claude-*",
|
|
380
378
|
"@cursor/sdk*",
|
|
381
379
|
"@earendil-works/*",
|
|
382
|
-
"@openai/codex"
|
|
380
|
+
"@openai/codex",
|
|
381
|
+
"@opencode/*"
|
|
383
382
|
].map((name) => `'min-release-age-exclude[]=${name}'`).join(" ")} >> "$HOME/.npmrc"`;
|
|
384
383
|
var DEFAULT_RUNTIME_COMMAND = "/usr/local/bin/workspace-runtime";
|
|
385
384
|
var DEFAULT_WORKSPACE_DIR = "/workspace";
|
|
@@ -401,9 +400,6 @@ function nameFor(workspaceId) {
|
|
|
401
400
|
return `claxedo-${workspaceId}`;
|
|
402
401
|
}
|
|
403
402
|
var TRANSIENT_MARKERS = ["timeout", "unavailable", "deadline", "pending"];
|
|
404
|
-
function transientDriverError(err) {
|
|
405
|
-
return isTransientDriverError(err, TRANSIENT_MARKERS);
|
|
406
|
-
}
|
|
407
403
|
function network(input) {
|
|
408
404
|
if (!input.net || input.net.mode === "allow-all") return void 0;
|
|
409
405
|
const hosts = input.net.hosts ?? [];
|
|
@@ -538,7 +534,9 @@ function createVercelSandboxDriver(options) {
|
|
|
538
534
|
await runSetup(builder, "sudo dnf install -y git make gcc-c++ python3 > /dev/null 2>&1");
|
|
539
535
|
await runSetup(builder, [
|
|
540
536
|
HARNESS_RELEASE_AGE_EXCLUSIONS,
|
|
541
|
-
"npm i -g --min-release-age=2 tsx@4.22.3
|
|
537
|
+
"npm i -g --min-release-age=2 tsx@4.22.3 @anthropic-ai/claude-code@2.1.323 @openai/codex@0.165.0",
|
|
538
|
+
"sudo mkdir -p /etc/codex",
|
|
539
|
+
"printf 'check_for_update_on_startup = false\\n' | sudo tee /etc/codex/config.toml > /dev/null",
|
|
542
540
|
"curl https://cursor.com/install -fsS | bash",
|
|
543
541
|
"curl -fsSL https://ampcode.com/install.sh | bash",
|
|
544
542
|
"curl -fsSL https://app.factory.ai/cli | sh",
|
|
@@ -548,7 +546,6 @@ function createVercelSandboxDriver(options) {
|
|
|
548
546
|
"sudo ln -sf $HOME/.local/bin/amp /usr/local/bin/amp",
|
|
549
547
|
"sudo ln -sf $HOME/.local/bin/droid /usr/local/bin/droid",
|
|
550
548
|
"sudo ln -sf $HOME/.local/bin/agy /usr/local/bin/agy",
|
|
551
|
-
"command -v opencode",
|
|
552
549
|
"command -v claude",
|
|
553
550
|
"command -v codex",
|
|
554
551
|
"command -v agent",
|
|
@@ -631,7 +628,7 @@ function createVercelSandboxDriver(options) {
|
|
|
631
628
|
env,
|
|
632
629
|
...createPolicy ? { networkPolicy: createPolicy } : {}
|
|
633
630
|
}).catch((err) => {
|
|
634
|
-
if (
|
|
631
|
+
if (isTransientDriverError(err, TRANSIENT_MARKERS)) return void 0;
|
|
635
632
|
throw err;
|
|
636
633
|
});
|
|
637
634
|
if (!sandbox) return { provisioning: true, retryAfterMs: TRANSIENT_DRIVER_RETRY_MS };
|
package/dist/index.mjs
CHANGED
|
@@ -553,10 +553,8 @@ function sandboxRuntimeBootFailure(error) {
|
|
|
553
553
|
return workspaceRuntimeBootReason(diagnostic) ?? diagnostic;
|
|
554
554
|
}
|
|
555
555
|
var SANDBOX_RUNTIME_UNHEALTHY = "runtime_unhealthy";
|
|
556
|
-
var SANDBOX_RETRY_CAP_EXCEEDED = "runtime_retry_cap_exceeded";
|
|
557
556
|
var CODED_REASONS = /* @__PURE__ */ new Map([
|
|
558
557
|
[SANDBOX_RUNTIME_UNHEALTHY, "The workspace machine stopped answering."],
|
|
559
|
-
[SANDBOX_RETRY_CAP_EXCEEDED, "Several tries in a row failed; try again later."],
|
|
560
558
|
[SANDBOX_UPDATE_DOWNLOAD_INTERRUPTED, "The update couldn't finish downloading; your workspace is still running. Try again."]
|
|
561
559
|
]);
|
|
562
560
|
function firstLine(text) {
|
|
@@ -1543,14 +1541,6 @@ function createSandboxManager(options) {
|
|
|
1543
1541
|
...existing.retryCount >= maxRetryCount ? { exhausted: true } : {}
|
|
1544
1542
|
};
|
|
1545
1543
|
}
|
|
1546
|
-
if (existing.status === "unavailable" && existing.retryCount >= maxRetryCount && existing.nextRetryAt === void 0 && sandboxProviderRateLimit(existing.lastError) !== "day") {
|
|
1547
|
-
return {
|
|
1548
|
-
status: "unavailable",
|
|
1549
|
-
error: existing.lastError ?? SANDBOX_RETRY_CAP_EXCEEDED,
|
|
1550
|
-
epoch: existing.epoch,
|
|
1551
|
-
homeRegion: existing.homeRegion
|
|
1552
|
-
};
|
|
1553
|
-
}
|
|
1554
1544
|
return void 0;
|
|
1555
1545
|
}
|
|
1556
1546
|
function continues(lease) {
|
|
@@ -1757,7 +1747,6 @@ export {
|
|
|
1757
1747
|
SANDBOX_IMAGE_LABEL,
|
|
1758
1748
|
SANDBOX_MODEL_PROVIDER_HOSTS,
|
|
1759
1749
|
SANDBOX_PACKAGE_REGISTRY_HOSTS,
|
|
1760
|
-
SANDBOX_RETRY_CAP_EXCEEDED,
|
|
1761
1750
|
SANDBOX_RUNTIME_UNHEALTHY,
|
|
1762
1751
|
SANDBOX_START_WINDOWS,
|
|
1763
1752
|
SANDBOX_UPDATE_DOWNLOAD_INTERRUPTED,
|
package/dist/json.d.ts
CHANGED
|
@@ -1,4 +1 @@
|
|
|
1
|
-
export { asRecord as record, isRecord } from "@claxedo/helpers/guards";
|
|
2
|
-
/** An empty string is absent. */
|
|
3
|
-
export declare function text(input: unknown): string | undefined;
|
|
4
|
-
export declare function num(input: unknown): number | undefined;
|
|
1
|
+
export { asNumber as num, asRecord as record, isRecord, nonEmptyString as text } from "@claxedo/helpers/guards";
|
package/dist/lease-failure.d.ts
CHANGED
|
@@ -158,8 +158,6 @@ export declare function runtimeBootDiagnostic(log: string, maxChars: number): st
|
|
|
158
158
|
export declare function sandboxRuntimeBootFailure(error: string | undefined): string | undefined;
|
|
159
159
|
/** The error a lease keeps when the runtime it serves stopped answering its health reports. */
|
|
160
160
|
export declare const SANDBOX_RUNTIME_UNHEALTHY = "runtime_unhealthy";
|
|
161
|
-
/** The error a capped lease answers when it kept none of its own. */
|
|
162
|
-
export declare const SANDBOX_RETRY_CAP_EXCEEDED = "runtime_retry_cap_exceeded";
|
|
163
161
|
/**
|
|
164
162
|
* The one line a person is told for a start step's error: the runtime's own
|
|
165
163
|
* reason for a boot that failed, the provider's refusal in Claxedo's words,
|
package/dist/runtime-env.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { SandboxDriverID } from "@claxedo/sandbox-contract";
|
|
2
1
|
export type WorkspaceRuntimeControlEnv = {
|
|
3
2
|
relayJwksUrl?: string;
|
|
4
3
|
relayVerifyPem?: string;
|
|
@@ -35,9 +34,3 @@ export declare function workspaceRuntimeSourceEnv(input: {
|
|
|
35
34
|
kind: "empty";
|
|
36
35
|
};
|
|
37
36
|
}): Record<string, string>;
|
|
38
|
-
export declare function workspaceRuntimeServiceExposureEnv(input: {
|
|
39
|
-
driver: SandboxDriverID;
|
|
40
|
-
source: "driver-service-url";
|
|
41
|
-
access: "private" | "public" | "driver-authenticated" | "unknown";
|
|
42
|
-
note?: string;
|
|
43
|
-
}): Record<string, string>;
|
package/dist/runtime-env.mjs
CHANGED
|
@@ -66,22 +66,12 @@ function workspaceRuntimeSourceEnv(input) {
|
|
|
66
66
|
...input.source.branch ? { WORKSPACE_RUNTIME_GIT_BRANCH: input.source.branch } : {}
|
|
67
67
|
};
|
|
68
68
|
}
|
|
69
|
-
function workspaceRuntimeServiceExposureEnv(input) {
|
|
70
|
-
return {
|
|
71
|
-
...input.driver === "docker" ? { WORKSPACE_RUNTIME_HOST: "0.0.0.0" } : {},
|
|
72
|
-
WORKSPACE_RUNTIME_SERVICE_EXPOSURE_SOURCE: input.source,
|
|
73
|
-
WORKSPACE_RUNTIME_SERVICE_EXPOSURE_ACCESS: input.access,
|
|
74
|
-
WORKSPACE_RUNTIME_SERVICE_EXPOSURE_DRIVER: input.driver,
|
|
75
|
-
...input.note ? { WORKSPACE_RUNTIME_SERVICE_EXPOSURE_NOTE: input.note } : {}
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
69
|
export {
|
|
79
70
|
assertWorkspaceRuntimeIdentityEnv,
|
|
80
71
|
redactWorkspaceRuntimeBootSecrets,
|
|
81
72
|
workspaceRuntimeBootEnv,
|
|
82
73
|
workspaceRuntimeBootSecrets,
|
|
83
74
|
workspaceRuntimeIdentityEnvConflicts,
|
|
84
|
-
workspaceRuntimeServiceExposureEnv,
|
|
85
75
|
workspaceRuntimeSourceEnv,
|
|
86
76
|
workspaceRuntimeTargetEnv
|
|
87
77
|
};
|
package/package.json
CHANGED
|
@@ -171,7 +171,7 @@
|
|
|
171
171
|
"access": "public"
|
|
172
172
|
},
|
|
173
173
|
"name": "@claxedo/sandbox-manager",
|
|
174
|
-
"version": "0.10.
|
|
174
|
+
"version": "0.10.4",
|
|
175
175
|
"scripts": {
|
|
176
176
|
"build": "bun scripts/build.ts",
|
|
177
177
|
"prepublishOnly": "npm run build",
|
|
@@ -180,8 +180,8 @@
|
|
|
180
180
|
"test": "mkdir -p .artifacts/unit && node ../../script/test-deadline.mjs bun test src --reporter=junit --reporter-outfile=.artifacts/unit/junit.xml"
|
|
181
181
|
},
|
|
182
182
|
"dependencies": {
|
|
183
|
-
"@claxedo/helpers": "0.2.
|
|
184
|
-
"@claxedo/sandbox-contract": "0.10.
|
|
183
|
+
"@claxedo/helpers": "0.2.4",
|
|
184
|
+
"@claxedo/sandbox-contract": "0.10.4",
|
|
185
185
|
"@vercel/sandbox": "3.3.0",
|
|
186
186
|
"modal": "0.10.1"
|
|
187
187
|
},
|