@void/platform 0.20.2 → 0.20.3
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/index.d.mts +2 -2
- package/dist/index.mjs +3 -2
- package/dist/installer.d.mts +1 -1
- package/dist/installer.mjs +1 -1
- package/dist/runtime/api/README.md +1 -1
- package/dist/runtime/api/index.js +1146 -371
- package/dist/runtime/api/index.js.map +4 -4
- package/dist/runtime/dispatch/README.md +1 -1
- package/dist/runtime/dispatch/index.js +9 -5
- package/dist/runtime/dispatch/index.js.map +2 -2
- package/dist/runtime/emailGateway/README.md +1 -1
- package/dist/runtime/manifest.json +9 -9
- package/dist/runtime/proxy/README.md +1 -1
- package/dist/runtime/proxy/index.js +23 -4
- package/dist/runtime/proxy/index.js.map +2 -2
- package/dist/runtime/tail/README.md +1 -1
- package/package.json +1 -1
|
@@ -10368,7 +10368,7 @@ var init_schema2 = __esm({
|
|
|
10368
10368
|
commit_url: text("commit_url"),
|
|
10369
10369
|
git_ref: text("git_ref"),
|
|
10370
10370
|
cli_version: text("cli_version"),
|
|
10371
|
-
admission_protocol: integer("admission_protocol").notNull().default(0).$default(() =>
|
|
10371
|
+
admission_protocol: integer("admission_protocol").notNull().default(0).$default(() => 3),
|
|
10372
10372
|
error_message: text("error_message"),
|
|
10373
10373
|
asset_hashes: text("asset_hashes"),
|
|
10374
10374
|
created_at: timestamp("created_at", { mode: "string" }).notNull().defaultNow(),
|
|
@@ -10992,7 +10992,7 @@ function getPlatformCapabilities(env) {
|
|
|
10992
10992
|
}
|
|
10993
10993
|
}
|
|
10994
10994
|
return Object.fromEntries(
|
|
10995
|
-
CAPABILITY_NAMES.map((name) => [name,
|
|
10995
|
+
CAPABILITY_NAMES.map((name) => [name, record2[name]])
|
|
10996
10996
|
);
|
|
10997
10997
|
}
|
|
10998
10998
|
function capabilityMiddleware(capability) {
|
|
@@ -11023,9 +11023,7 @@ var init_capabilities = __esm({
|
|
|
11023
11023
|
githubOAuth: true,
|
|
11024
11024
|
googleOAuth: true,
|
|
11025
11025
|
managedBuilds: true,
|
|
11026
|
-
|
|
11027
|
-
// this false even on hosted installations where configuration is absent.
|
|
11028
|
-
sandbox: false
|
|
11026
|
+
sandbox: true
|
|
11029
11027
|
};
|
|
11030
11028
|
CAPABILITY_NAMES = Object.keys(HOSTED_CAPABILITIES);
|
|
11031
11029
|
__name(getPlatformCapabilities, "getPlatformCapabilities");
|
|
@@ -17686,20 +17684,23 @@ async function selectProjectAccess(db, projectId, actorUserId) {
|
|
|
17686
17684
|
memberRole: row.project.user_id === actorUserId ? "owner" : row.memberRole
|
|
17687
17685
|
};
|
|
17688
17686
|
}
|
|
17687
|
+
function projectAccessErrorBody(error) {
|
|
17688
|
+
return { error: error.message, message: error.userMessage };
|
|
17689
|
+
}
|
|
17689
17690
|
async function requireProjectCapability(db, projectId, actorUserId, capability) {
|
|
17690
17691
|
const row = await selectProjectAccess(db, projectId, actorUserId);
|
|
17691
17692
|
if (!row) {
|
|
17692
17693
|
throw new ProjectNotFoundError();
|
|
17693
17694
|
}
|
|
17694
17695
|
if (!row.memberRole || !hasProjectCapability(row.memberRole, capability)) {
|
|
17695
|
-
throw new ProjectAccessDeniedError();
|
|
17696
|
+
throw new ProjectAccessDeniedError("forbidden", PROJECT_PERMISSION_MESSAGES[capability]);
|
|
17696
17697
|
}
|
|
17697
17698
|
if (isAdminSuspended(row.owner.suspended_reason)) {
|
|
17698
17699
|
throw new ProjectOwnerSuspendedError();
|
|
17699
17700
|
}
|
|
17700
17701
|
return { project: row.project, role: row.memberRole, owner: row.owner };
|
|
17701
17702
|
}
|
|
17702
|
-
var PROJECT_ROLE_CAPABILITIES, projectOwner, ProjectNotFoundError, ProjectAccessDeniedError, ProjectOwnerSuspendedError;
|
|
17703
|
+
var PROJECT_ROLE_CAPABILITIES, PROJECT_PERMISSION_MESSAGES, projectOwner, ProjectNotFoundError, ProjectAccessDeniedError, ProjectOwnerSuspendedError;
|
|
17703
17704
|
var init_project_access = __esm({
|
|
17704
17705
|
"../../home/runner/work/void/void/platform/packages/api/src/project-access.ts"() {
|
|
17705
17706
|
"use strict";
|
|
@@ -17714,6 +17715,18 @@ var init_project_access = __esm({
|
|
|
17714
17715
|
admin: ["read", "deploy", "configure", "settings", "members"],
|
|
17715
17716
|
owner: ["read", "deploy", "configure", "settings", "members", "delete"]
|
|
17716
17717
|
};
|
|
17718
|
+
PROJECT_PERMISSION_MESSAGES = {
|
|
17719
|
+
read: "You need project access to view this project. Ask a project admin or owner to invite you.",
|
|
17720
|
+
deploy: "Deploying requires the collaborator, admin, or owner role. Ask a project admin or owner to update your access.",
|
|
17721
|
+
configure: "Changing project configuration requires the collaborator, admin, or owner role. Ask a project admin or owner to update your access.",
|
|
17722
|
+
settings: "Changing project settings requires the admin or owner role. Ask a project admin or owner to update your access.",
|
|
17723
|
+
members: "Managing project members and invitations requires the admin or owner role. Ask a project admin or owner to update your access.",
|
|
17724
|
+
delete: "Only the project owner can delete this project. Ask the owner to delete it.",
|
|
17725
|
+
tokens: "Only the project owner can manage deploy tokens. Ask the owner to create or manage a token.",
|
|
17726
|
+
"database-url": "Only the project owner can view the database connection URL. Ask the owner to share the connection details you need.",
|
|
17727
|
+
"owner-suspended": "This project's owner account is suspended. Ask the owner to contact the platform administrator to restore access.",
|
|
17728
|
+
"not-found": "This project could not be found. Check the project ID or refresh your project list."
|
|
17729
|
+
};
|
|
17717
17730
|
__name(hasProjectCapability, "hasProjectCapability");
|
|
17718
17731
|
projectOwner = alias(users, "project_owner");
|
|
17719
17732
|
__name(selectProjectAccess, "selectProjectAccess");
|
|
@@ -17722,30 +17735,34 @@ var init_project_access = __esm({
|
|
|
17722
17735
|
__name(this, "ProjectNotFoundError");
|
|
17723
17736
|
}
|
|
17724
17737
|
status = 404;
|
|
17738
|
+
userMessage = PROJECT_PERMISSION_MESSAGES["not-found"];
|
|
17725
17739
|
constructor() {
|
|
17726
17740
|
super("project not found");
|
|
17727
17741
|
this.name = "ProjectNotFoundError";
|
|
17728
17742
|
}
|
|
17729
17743
|
};
|
|
17730
17744
|
ProjectAccessDeniedError = class extends Error {
|
|
17745
|
+
constructor(message2 = "forbidden", userMessage = PROJECT_PERMISSION_MESSAGES.read) {
|
|
17746
|
+
super(message2);
|
|
17747
|
+
this.userMessage = userMessage;
|
|
17748
|
+
this.name = "ProjectAccessDeniedError";
|
|
17749
|
+
}
|
|
17750
|
+
userMessage;
|
|
17731
17751
|
static {
|
|
17732
17752
|
__name(this, "ProjectAccessDeniedError");
|
|
17733
17753
|
}
|
|
17734
17754
|
status = 403;
|
|
17735
|
-
constructor(message2 = "forbidden") {
|
|
17736
|
-
super(message2);
|
|
17737
|
-
this.name = "ProjectAccessDeniedError";
|
|
17738
|
-
}
|
|
17739
17755
|
};
|
|
17740
17756
|
ProjectOwnerSuspendedError = class extends ProjectAccessDeniedError {
|
|
17741
17757
|
static {
|
|
17742
17758
|
__name(this, "ProjectOwnerSuspendedError");
|
|
17743
17759
|
}
|
|
17744
17760
|
constructor() {
|
|
17745
|
-
super("project owner suspended");
|
|
17761
|
+
super("project owner suspended", PROJECT_PERMISSION_MESSAGES["owner-suspended"]);
|
|
17746
17762
|
this.name = "ProjectOwnerSuspendedError";
|
|
17747
17763
|
}
|
|
17748
17764
|
};
|
|
17765
|
+
__name(projectAccessErrorBody, "projectAccessErrorBody");
|
|
17749
17766
|
__name(requireProjectCapability, "requireProjectCapability");
|
|
17750
17767
|
}
|
|
17751
17768
|
});
|
|
@@ -17858,8 +17875,8 @@ async function deleteD1Database(accountId, apiToken, databaseId) {
|
|
|
17858
17875
|
method: "DELETE"
|
|
17859
17876
|
});
|
|
17860
17877
|
}
|
|
17861
|
-
async function deleteKVNamespace(accountId, apiToken,
|
|
17862
|
-
await cfFetch(`${CF_API_BASE}/${accountId}/storage/kv/namespaces/${
|
|
17878
|
+
async function deleteKVNamespace(accountId, apiToken, namespaceId2) {
|
|
17879
|
+
await cfFetch(`${CF_API_BASE}/${accountId}/storage/kv/namespaces/${namespaceId2}`, apiToken, {
|
|
17863
17880
|
method: "DELETE"
|
|
17864
17881
|
});
|
|
17865
17882
|
}
|
|
@@ -18815,7 +18832,11 @@ async function requireProjectManagedEmailAccess(db, projectId, actor) {
|
|
|
18815
18832
|
}
|
|
18816
18833
|
} catch (error) {
|
|
18817
18834
|
if (error instanceof ProjectNotFoundError || error instanceof ProjectAccessDeniedError) {
|
|
18818
|
-
throw new EmailOperationError(
|
|
18835
|
+
throw new EmailOperationError(
|
|
18836
|
+
"forbidden",
|
|
18837
|
+
403,
|
|
18838
|
+
error instanceof ProjectAccessDeniedError ? error.userMessage : PROJECT_PERMISSION_MESSAGES.settings
|
|
18839
|
+
);
|
|
18819
18840
|
}
|
|
18820
18841
|
throw error;
|
|
18821
18842
|
}
|
|
@@ -18950,7 +18971,11 @@ async function resumeBlockedEmailOperationTx(tx, env, operationId, actor, expect
|
|
|
18950
18971
|
}
|
|
18951
18972
|
if (route && actor.kind === "owner") {
|
|
18952
18973
|
if (!route.project_id || route.managed_by !== "owner") {
|
|
18953
|
-
throw new EmailOperationError(
|
|
18974
|
+
throw new EmailOperationError(
|
|
18975
|
+
"forbidden",
|
|
18976
|
+
403,
|
|
18977
|
+
"This email connection is managed by the platform. Contact a platform administrator to change it."
|
|
18978
|
+
);
|
|
18954
18979
|
}
|
|
18955
18980
|
await requireProjectManagedEmailAccess(tx, route.project_id, actor);
|
|
18956
18981
|
}
|
|
@@ -20152,7 +20177,11 @@ async function requestExistingOperation(db, env, routeId, actor, kind, key, expe
|
|
|
20152
20177
|
}
|
|
20153
20178
|
if (actor.kind === "owner") {
|
|
20154
20179
|
if (!project || route.managed_by !== "owner") {
|
|
20155
|
-
throw new EmailOperationError(
|
|
20180
|
+
throw new EmailOperationError(
|
|
20181
|
+
"forbidden",
|
|
20182
|
+
403,
|
|
20183
|
+
"This email connection is managed by the platform. Contact a platform administrator to change it."
|
|
20184
|
+
);
|
|
20156
20185
|
}
|
|
20157
20186
|
}
|
|
20158
20187
|
if (kind === "sync" && !canManageConnection(actor, connection) && !await hasDelegatedConnectionAccess(tx, connection.id, actor)) {
|
|
@@ -21207,11 +21236,13 @@ var init_connection_service = __esm({
|
|
|
21207
21236
|
init_domain_name();
|
|
21208
21237
|
init_relay_worker();
|
|
21209
21238
|
EmailOperationError = class extends Error {
|
|
21210
|
-
constructor(message2, status2 = 409) {
|
|
21239
|
+
constructor(message2, status2 = 409, userMessage) {
|
|
21211
21240
|
super(message2);
|
|
21212
21241
|
this.status = status2;
|
|
21242
|
+
this.userMessage = userMessage;
|
|
21213
21243
|
}
|
|
21214
21244
|
status;
|
|
21245
|
+
userMessage;
|
|
21215
21246
|
static {
|
|
21216
21247
|
__name(this, "EmailOperationError");
|
|
21217
21248
|
}
|
|
@@ -42990,6 +43021,35 @@ __name(isDevBypass, "isDevBypass");
|
|
|
42990
43021
|
|
|
42991
43022
|
// ../../home/runner/work/void/void/platform/packages/api/src/admin/middleware/auth.ts
|
|
42992
43023
|
init_suspension();
|
|
43024
|
+
|
|
43025
|
+
// ../../home/runner/work/void/void/platform/packages/api/src/admin/middleware/request-rejection.ts
|
|
43026
|
+
init_performance2();
|
|
43027
|
+
function adminAccessRejected(context, reason) {
|
|
43028
|
+
if (reason === "suspended") {
|
|
43029
|
+
return context.html(
|
|
43030
|
+
'<h1>Administrator access suspended</h1><p>Contact another platform administrator to restore access.</p><p><a href="/admin/logout">Sign in with another account</a></p>',
|
|
43031
|
+
403
|
|
43032
|
+
);
|
|
43033
|
+
}
|
|
43034
|
+
return context.html(
|
|
43035
|
+
'<h1>Administrator access required</h1><p>Sign in with an administrator account for this platform.</p><p><a href="/admin/logout">Sign in with another account</a></p>',
|
|
43036
|
+
403
|
|
43037
|
+
);
|
|
43038
|
+
}
|
|
43039
|
+
__name(adminAccessRejected, "adminAccessRejected");
|
|
43040
|
+
function adminRequestRejected(context, error, format) {
|
|
43041
|
+
const message2 = "Return to the admin page, refresh it, and try again.";
|
|
43042
|
+
if (context.req.header("Accept")?.includes("text/html")) {
|
|
43043
|
+
return context.html(
|
|
43044
|
+
'<h1>Request could not be verified</h1><p>Return to the admin page, refresh it, and try again.</p><p><a href="/admin/">Return to admin</a></p>',
|
|
43045
|
+
403
|
|
43046
|
+
);
|
|
43047
|
+
}
|
|
43048
|
+
return format === "json" ? context.json({ error, message: message2 }, 403) : context.text(`${error} ${message2}`, 403);
|
|
43049
|
+
}
|
|
43050
|
+
__name(adminRequestRejected, "adminRequestRejected");
|
|
43051
|
+
|
|
43052
|
+
// ../../home/runner/work/void/void/platform/packages/api/src/admin/middleware/auth.ts
|
|
42993
43053
|
var adminAuthMiddleware = /* @__PURE__ */ __name(async (context, next) => {
|
|
42994
43054
|
const method = context.req.method.toUpperCase();
|
|
42995
43055
|
if (method !== "GET" && method !== "HEAD" && method !== "OPTIONS") {
|
|
@@ -42998,7 +43058,7 @@ var adminAuthMiddleware = /* @__PURE__ */ __name(async (context, next) => {
|
|
|
42998
43058
|
const requestHost = new URL(context.req.url).host;
|
|
42999
43059
|
const sourceHost = origin ? safeHost(origin) : referer ? safeHost(referer) : null;
|
|
43000
43060
|
if (sourceHost === null || sourceHost !== requestHost) {
|
|
43001
|
-
return context
|
|
43061
|
+
return adminRequestRejected(context, "cross-site request blocked", "json");
|
|
43002
43062
|
}
|
|
43003
43063
|
}
|
|
43004
43064
|
if (isDevBypass(context.env)) {
|
|
@@ -43020,8 +43080,11 @@ var adminAuthMiddleware = /* @__PURE__ */ __name(async (context, next) => {
|
|
|
43020
43080
|
return context.redirect("/admin/login");
|
|
43021
43081
|
}
|
|
43022
43082
|
const user = await getUser(context.get("db"), payload.sub);
|
|
43023
|
-
if (!user || user.role !== "admin"
|
|
43024
|
-
return context
|
|
43083
|
+
if (!user || user.role !== "admin") {
|
|
43084
|
+
return adminAccessRejected(context, "required");
|
|
43085
|
+
}
|
|
43086
|
+
if (isAdminSuspended(user.suspended_reason)) {
|
|
43087
|
+
return adminAccessRejected(context, "suspended");
|
|
43025
43088
|
}
|
|
43026
43089
|
context.set("user", user);
|
|
43027
43090
|
if (payload.sid) {
|
|
@@ -43050,14 +43113,14 @@ var adminCsrfMiddleware = /* @__PURE__ */ __name(async (context, next) => {
|
|
|
43050
43113
|
const origin = context.req.header("Origin");
|
|
43051
43114
|
if (origin) {
|
|
43052
43115
|
if (parseOrigin(origin) !== expectedOrigin) {
|
|
43053
|
-
return context
|
|
43116
|
+
return adminRequestRejected(context, "Forbidden: invalid request origin.", "text");
|
|
43054
43117
|
}
|
|
43055
43118
|
await next();
|
|
43056
43119
|
return;
|
|
43057
43120
|
}
|
|
43058
43121
|
const referer = context.req.header("Referer");
|
|
43059
43122
|
if (!referer || parseOrigin(referer) !== expectedOrigin) {
|
|
43060
|
-
return context
|
|
43123
|
+
return adminRequestRejected(context, "Forbidden: missing request origin.", "text");
|
|
43061
43124
|
}
|
|
43062
43125
|
await next();
|
|
43063
43126
|
}, "adminCsrfMiddleware");
|
|
@@ -51560,7 +51623,10 @@ function serializeEmailRoute(route, connection, operationId) {
|
|
|
51560
51623
|
__name(serializeEmailRoute, "serializeEmailRoute");
|
|
51561
51624
|
function serviceError(context, error) {
|
|
51562
51625
|
if (error instanceof EmailOperationError) {
|
|
51563
|
-
return context.json(
|
|
51626
|
+
return context.json(
|
|
51627
|
+
{ error: error.message, ...error.userMessage ? { message: error.userMessage } : {} },
|
|
51628
|
+
error.status
|
|
51629
|
+
);
|
|
51564
51630
|
}
|
|
51565
51631
|
throw error;
|
|
51566
51632
|
}
|
|
@@ -52608,7 +52674,13 @@ var renderOperationError = /* @__PURE__ */ __name((error, context) => {
|
|
|
52608
52674
|
if (!(error instanceof OperatorError)) {
|
|
52609
52675
|
throw error;
|
|
52610
52676
|
}
|
|
52611
|
-
return context.html(
|
|
52677
|
+
return context.html(
|
|
52678
|
+
/* @__PURE__ */ jsxDEV(Fragment, { children: [
|
|
52679
|
+
/* @__PURE__ */ jsxDEV("h1", { children: error.message }),
|
|
52680
|
+
/* @__PURE__ */ jsxDEV("p", { children: error.status === 401 ? /* @__PURE__ */ jsxDEV("a", { href: "/admin/logout", children: "Sign in again" }) : /* @__PURE__ */ jsxDEV("a", { href: "/admin/", children: "Return to admin" }) })
|
|
52681
|
+
] }),
|
|
52682
|
+
error.status
|
|
52683
|
+
);
|
|
52612
52684
|
}, "renderOperationError");
|
|
52613
52685
|
|
|
52614
52686
|
// ../../home/runner/work/void/void/platform/packages/api/src/admin/views/email-settings.tsx
|
|
@@ -53958,11 +54030,11 @@ async function handleAdminOAuthCallback(context) {
|
|
|
53958
54030
|
context.env.PLATFORM_BOOTSTRAP_GITHUB_ID
|
|
53959
54031
|
);
|
|
53960
54032
|
}
|
|
53961
|
-
if (!user || user.role !== "admin"
|
|
53962
|
-
return context
|
|
53963
|
-
|
|
53964
|
-
|
|
53965
|
-
);
|
|
54033
|
+
if (!user || user.role !== "admin") {
|
|
54034
|
+
return adminAccessRejected(context, "required");
|
|
54035
|
+
}
|
|
54036
|
+
if (isAdminSuspended(user.suspended_reason)) {
|
|
54037
|
+
return adminAccessRejected(context, "suspended");
|
|
53966
54038
|
}
|
|
53967
54039
|
const jwt = await signJwt({ sub: user.id, login, aud: "admin" }, context.env.JWT_SECRET);
|
|
53968
54040
|
setCookie(context, "admin_token", jwt, {
|
|
@@ -54729,6 +54801,20 @@ __name(PlatformPage, "PlatformPage");
|
|
|
54729
54801
|
var app7 = new Hono2();
|
|
54730
54802
|
app7.use("*", async (context, next) => {
|
|
54731
54803
|
if (context.env.PLATFORM_INSTALLATION_ID) {
|
|
54804
|
+
if (context.req.header("Accept")?.includes("text/html")) {
|
|
54805
|
+
return context.html(
|
|
54806
|
+
/* @__PURE__ */ jsxDEV(Fragment, { children: [
|
|
54807
|
+
/* @__PURE__ */ jsxDEV("h1", { children: "Manage this platform with the CLI" }),
|
|
54808
|
+
/* @__PURE__ */ jsxDEV("p", { children: [
|
|
54809
|
+
"To upgrade this self-hosted Void platform, run ",
|
|
54810
|
+
/* @__PURE__ */ jsxDEV("code", { children: "void platform upgrade" }),
|
|
54811
|
+
"."
|
|
54812
|
+
] }),
|
|
54813
|
+
/* @__PURE__ */ jsxDEV("p", { children: /* @__PURE__ */ jsxDEV("a", { href: "/admin/", children: "Return to admin" }) })
|
|
54814
|
+
] }),
|
|
54815
|
+
501
|
|
54816
|
+
);
|
|
54817
|
+
}
|
|
54732
54818
|
return context.json(
|
|
54733
54819
|
{
|
|
54734
54820
|
error: "platform capability unavailable",
|
|
@@ -59482,27 +59568,6 @@ init_drizzle_orm();
|
|
|
59482
59568
|
init_schema2();
|
|
59483
59569
|
var SANDBOX_DRAIN_STATE_KEY = "__void/platform/sandbox-drain/v1";
|
|
59484
59570
|
var LEASE_MS2 = 12e4;
|
|
59485
|
-
async function readSandboxDrainState(routing) {
|
|
59486
|
-
const raw2 = await routing.get(SANDBOX_DRAIN_STATE_KEY);
|
|
59487
|
-
if (!raw2) {
|
|
59488
|
-
return null;
|
|
59489
|
-
}
|
|
59490
|
-
let parsed;
|
|
59491
|
-
try {
|
|
59492
|
-
parsed = JSON.parse(raw2);
|
|
59493
|
-
} catch {
|
|
59494
|
-
throw new Error(`${SANDBOX_DRAIN_STATE_KEY} contains invalid JSON.`);
|
|
59495
|
-
}
|
|
59496
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
59497
|
-
throw new Error(`${SANDBOX_DRAIN_STATE_KEY} contains an invalid state document.`);
|
|
59498
|
-
}
|
|
59499
|
-
const state = parsed;
|
|
59500
|
-
if (state.version !== 1 || typeof state.generation !== "string" || state.state !== "draining" && state.state !== "complete" || typeof state.startedAt !== "string" || typeof state.updatedAt !== "string" || state.completedAt !== void 0 && typeof state.completedAt !== "string") {
|
|
59501
|
-
throw new Error(`${SANDBOX_DRAIN_STATE_KEY} contains an invalid state document.`);
|
|
59502
|
-
}
|
|
59503
|
-
return state;
|
|
59504
|
-
}
|
|
59505
|
-
__name(readSandboxDrainState, "readSandboxDrainState");
|
|
59506
59571
|
async function writeSandboxDrainMirror(routing, checkpoint) {
|
|
59507
59572
|
const state = {
|
|
59508
59573
|
version: 1,
|
|
@@ -59525,7 +59590,7 @@ async function readSandboxDrainCheckpoint(db) {
|
|
|
59525
59590
|
}
|
|
59526
59591
|
__name(readSandboxDrainCheckpoint, "readSandboxDrainCheckpoint");
|
|
59527
59592
|
function assertValidCheckpoint(row) {
|
|
59528
|
-
if (row.admission_protocol !== 0 && row.admission_protocol !== 2 || !row.generation || row.state !== "draining" && row.state !== "complete" || row.phase !== "deployments" && row.phase !== "resources" || !row.cursor || row.cursor.pass !== "1" && row.cursor.pass !== "2") {
|
|
59593
|
+
if (row.admission_protocol !== 0 && row.admission_protocol !== 2 && row.admission_protocol !== 3 || !row.generation || row.state !== "draining" && row.state !== "complete" || row.phase !== "deployments" && row.phase !== "resources" || !row.cursor || row.cursor.pass !== "1" && row.cursor.pass !== "2") {
|
|
59529
59594
|
throw new Error("Sandbox drain database checkpoint is invalid.");
|
|
59530
59595
|
}
|
|
59531
59596
|
}
|
|
@@ -59607,12 +59672,6 @@ async function completeSandboxDrain(db, lease) {
|
|
|
59607
59672
|
return row;
|
|
59608
59673
|
}
|
|
59609
59674
|
__name(completeSandboxDrain, "completeSandboxDrain");
|
|
59610
|
-
async function assertSandboxContainerCreationAllowed(routing) {
|
|
59611
|
-
if (await readSandboxDrainState(routing)) {
|
|
59612
|
-
throw new Error("Managed Sandbox container creation is disabled by the platform drain gate.");
|
|
59613
|
-
}
|
|
59614
|
-
}
|
|
59615
|
-
__name(assertSandboxContainerCreationAllowed, "assertSandboxContainerCreationAllowed");
|
|
59616
59675
|
|
|
59617
59676
|
// ../../home/runner/work/void/void/platform/packages/api/src/provisioning/containers.ts
|
|
59618
59677
|
init_cloudflare_api();
|
|
@@ -59717,69 +59776,342 @@ function perDeployContainerApplicationName(projectId, deploymentId, containerNam
|
|
|
59717
59776
|
return `${projectId}-${deploymentId}-${containerName}`.toLowerCase().replaceAll("_", "-");
|
|
59718
59777
|
}
|
|
59719
59778
|
__name(perDeployContainerApplicationName, "perDeployContainerApplicationName");
|
|
59720
|
-
|
|
59721
|
-
|
|
59722
|
-
|
|
59723
|
-
|
|
59724
|
-
|
|
59725
|
-
|
|
59726
|
-
|
|
59727
|
-
|
|
59728
|
-
|
|
59729
|
-
|
|
59730
|
-
className
|
|
59731
|
-
|
|
59732
|
-
|
|
59733
|
-
|
|
59734
|
-
|
|
59735
|
-
|
|
59736
|
-
|
|
59737
|
-
|
|
59738
|
-
|
|
59739
|
-
|
|
59740
|
-
|
|
59741
|
-
|
|
59742
|
-
|
|
59743
|
-
|
|
59779
|
+
|
|
59780
|
+
// ../../home/runner/work/void/void/platform/packages/api/src/provisioning/sandbox-controller.ts
|
|
59781
|
+
init_performance2();
|
|
59782
|
+
init_drizzle_orm();
|
|
59783
|
+
|
|
59784
|
+
// ../../home/runner/work/void/void/platform/packages/api/src/sandbox-controller-source.ts
|
|
59785
|
+
init_performance2();
|
|
59786
|
+
|
|
59787
|
+
// sandbox-controller-source.ts
|
|
59788
|
+
init_performance2();
|
|
59789
|
+
var sandbox_controller_source_default = 'var Zs=Object.defineProperty;var a=(t,e)=>Zs(t,"name",{value:e,configurable:!0});function ge(t){return new Error(`[unenv] ${t} is not implemented yet!`)}a(ge,"createNotImplementedError");var Lt=globalThis.performance?.timeOrigin??Date.now(),Mt=globalThis.performance?.now?globalThis.performance.now.bind(globalThis.performance):()=>Date.now()-Lt,ei={name:"node",entryType:"node",startTime:0,duration:0,nodeStart:0,v8Start:0,bootstrapComplete:0,environment:0,loopStart:0,loopExit:0,idleTime:0,uvMetricsInfo:{loopCount:0,events:0,eventsWaiting:0},detail:void 0,toJSON(){return this}},we=class{static{a(this,"PerformanceEntry")}__unenv__=!0;detail;entryType="event";name;startTime;constructor(e,r){this.name=e,this.startTime=r?.startTime||Mt(),this.detail=r?.detail}get duration(){return Mt()-this.startTime}toJSON(){return{name:this.name,entryType:this.entryType,startTime:this.startTime,duration:this.duration,detail:this.detail}}},Ut=class extends we{static{a(this,"PerformanceMark")}entryType="mark";constructor(){super(...arguments)}get duration(){return 0}},De=class extends we{static{a(this,"PerformanceMeasure")}entryType="measure"},Le=class extends we{static{a(this,"PerformanceResourceTiming")}entryType="resource";serverTiming=[];connectEnd=0;connectStart=0;decodedBodySize=0;domainLookupEnd=0;domainLookupStart=0;encodedBodySize=0;fetchStart=0;initiatorType="";name="";nextHopProtocol="";redirectEnd=0;redirectStart=0;requestStart=0;responseEnd=0;responseStart=0;secureConnectionStart=0;startTime=0;transferSize=0;workerStart=0;responseStatus=0},at=class{static{a(this,"PerformanceObserverEntryList")}__unenv__=!0;getEntries(){return[]}getEntriesByName(e,r){return[]}getEntriesByType(e){return[]}},Ie=class{static{a(this,"Performance")}__unenv__=!0;timeOrigin=Lt;eventCounts=new Map;_entries=[];_resourceTimingBufferSize=0;navigation=void 0;timing=void 0;timerify(e,r){throw ge("Performance.timerify")}get nodeTiming(){return ei}eventLoopUtilization(){return{}}markResourceTiming(){return new Le("")}onresourcetimingbufferfull=null;now(){return this.timeOrigin===Lt?Mt():Date.now()-this.timeOrigin}clearMarks(e){this._entries=e?this._entries.filter(r=>r.name!==e):this._entries.filter(r=>r.entryType!=="mark")}clearMeasures(e){this._entries=e?this._entries.filter(r=>r.name!==e):this._entries.filter(r=>r.entryType!=="measure")}clearResourceTimings(){this._entries=this._entries.filter(e=>e.entryType!=="resource"||e.entryType!=="navigation")}getEntries(){return this._entries}getEntriesByName(e,r){return this._entries.filter(n=>n.name===e&&(!r||n.entryType===r))}getEntriesByType(e){return this._entries.filter(r=>r.entryType===e)}mark(e,r){let n=new Ut(e,r);return this._entries.push(n),n}measure(e,r,n){let s,i;typeof r=="string"?(s=this.getEntriesByName(r,"mark")[0]?.startTime,i=this.getEntriesByName(n,"mark")[0]?.startTime):(s=Number.parseFloat(r?.start)||this.now(),i=Number.parseFloat(r?.end)||this.now());let o=new De(e,{startTime:s,detail:{start:s,end:i}});return this._entries.push(o),o}setResourceTimingBufferSize(e){this._resourceTimingBufferSize=e}addEventListener(e,r,n){throw ge("Performance.addEventListener")}removeEventListener(e,r,n){throw ge("Performance.removeEventListener")}dispatchEvent(e){throw ge("Performance.dispatchEvent")}toJSON(){return this}},ct=class{static{a(this,"PerformanceObserver")}__unenv__=!0;static supportedEntryTypes=[];_callback=null;constructor(e){this._callback=e}takeRecords(){return[]}disconnect(){throw ge("PerformanceObserver.disconnect")}observe(e){throw ge("PerformanceObserver.observe")}bind(e){return e}runInAsyncScope(e,r,...n){return e.call(r,...n)}asyncId(){return 0}triggerAsyncId(){return 0}emitDestroy(){return this}},Me=globalThis.performance&&"addEventListener"in globalThis.performance?globalThis.performance:new Ie;if(!("__unenv__"in Me)){let t=Ie.prototype;for(let e of Object.getOwnPropertyNames(t))if(e!=="constructor"&&!(e in Me)){let r=Object.getOwnPropertyDescriptor(t,e);r&&Object.defineProperty(Me,e,r)}}globalThis.performance=Me;globalThis.Performance=Ie;globalThis.PerformanceEntry=we;globalThis.PerformanceMark=Ut;globalThis.PerformanceMeasure=De;globalThis.PerformanceObserver=ct;globalThis.PerformanceObserverEntryList=at;globalThis.PerformanceResourceTiming=Le;function D(t,e){let r=t?.[e];return typeof r=="string"?r:void 0}a(D,"getEnvString");function lt(t){let e={};for(let[r,n]of Object.entries(t))n!=null&&typeof n=="string"&&(e[r]=n);return e}a(lt,"filterEnvVars");function Ft(t){let e={},r=[];for(let[n,s]of Object.entries(t))s!=null&&typeof s=="string"?e[n]=s:r.push(n);return{toSet:e,toUnset:r}}a(Ft,"partitionEnvVars");var ti=/([?&])(X-Amz-Credential|X-Amz-Signature|X-Amz-Security-Token|token|secret|password)=[^&\\s"\'`<>]*/gi;function ri(t){let e=t,r=0;for(;r<e.length;){let n=e.indexOf("http://",r),s=e.indexOf("https://",r),i=-1,o=0;if(n===-1&&s===-1)break;n!==-1&&(s===-1||n<s)?(i=n,o=7):(i=s,o=8);let c=i+o,u=e.indexOf("@",c),l=c;for(;l<e.length;){let d=e[l];if(/[\\s"\'`<>,;{}[\\]]/.test(d))break;l++}u!==-1&&u<l?(e=`${e.substring(0,c)}******${e.substring(u)}`,r=c+6):r=i+o}return e}a(ri,"redactCredentials");function ni(t){return!t.includes("?")||!t.includes("=")?t:t.replace(ti,"$1$2=REDACTED")}a(ni,"redactSensitiveParams");function ce(t){return ni(ri(t))}a(ce,"redactCommand");function $r(t,e=120){if(t.length<=e)return{value:t,truncated:!1};let r=Math.max(0,e-3);return{value:`${t.substring(0,r)}...`,truncated:!0}}a($r,"truncateForLog");var si="repository",Hr=6e5;function Wr(t){try{let e=new URL(t).pathname.split("/"),r=e[e.length-1];if(r)return r.replace(/\\.git$/,"")}catch{}if(t.includes(":")||t.includes("/")){let e=t.split(/[:/]/).filter(Boolean),r=e[e.length-1];if(r)return r.replace(/\\.git$/,"")}return si}a(Wr,"extractRepoName");function Ue(t){if(typeof t=="string")return ce(t);if(t==null)return t;if(Array.isArray(t))return t.map(e=>Ue(e));if(typeof t=="object"){let e={};for(let[r,n]of Object.entries(t))e[r]=Ue(n);return e}return t}a(Ue,"sanitizeGitData");var Kr=class jr{static{a(this,"GitLogger")}baseLogger;constructor(e){this.baseLogger=e}sanitizeContext(e){return e&&Ue(e)}sanitizeError(e){if(!e)return e;let r=new Error(ce(e.message));r.name=e.name,e.stack&&(r.stack=ce(e.stack));let n=r,s=e;for(let i of Object.keys(e))i!=="message"&&i!=="stack"&&i!=="name"&&(n[i]=Ue(s[i]));return r}debug(e,r){this.baseLogger.debug(e,this.sanitizeContext(r))}info(e,r){this.baseLogger.info(e,this.sanitizeContext(r))}warn(e,r){this.baseLogger.warn(e,this.sanitizeContext(r))}error(e,r,n){this.baseLogger.error(e,this.sanitizeError(r),this.sanitizeContext(n))}child(e){let r=Ue(e);return new jr(this.baseLogger.child(r))}},zr=class{static{a(this,"Execution")}code;context;results=[];logs={stdout:[],stderr:[]};error;executionCount;constructor(t,e){this.code=t,this.context=e}toJSON(){return{code:this.code,logs:this.logs,error:this.error,executionCount:this.executionCount,results:this.results.map(t=>({text:t.text,html:t.html,png:t.png,jpeg:t.jpeg,svg:t.svg,latex:t.latex,markdown:t.markdown,javascript:t.javascript,json:t.json,chart:t.chart,data:t.data}))}}},Bt=class{static{a(this,"ResultImpl")}text;html;png;jpeg;svg;latex;markdown;javascript;json;chart;data;constructor(t){this.text=t.text||t.data?.["text/plain"],this.html=t.html||t.data?.["text/html"],this.png=t.png||t.data?.["image/png"],this.jpeg=t.jpeg||t.data?.["image/jpeg"],this.svg=t.svg||t.data?.["image/svg+xml"],this.latex=t.latex||t.data?.["text/latex"],this.markdown=t.markdown||t.data?.["text/markdown"],this.javascript=t.javascript||t.data?.["application/javascript"],this.json=t.json||t.data?.["application/json"],this.chart=t.chart,this.data=t.data}formats(){let t=[];return this.text&&t.push("text"),this.html&&t.push("html"),this.png&&t.push("png"),this.jpeg&&t.push("jpeg"),this.svg&&t.push("svg"),this.latex&&t.push("latex"),this.markdown&&t.push("markdown"),this.javascript&&t.push("javascript"),this.json&&t.push("json"),this.chart&&t.push("chart"),t}},ii=new Set(["session.create","session.destroy","file.read","file.write","file.delete","file.mkdir"]);function oi(t,e){return t.outcome==="error"?"error":e?.successLevel?e.successLevel:t.origin==="internal"||ii.has(t.event)?"debug":"info"}a(oi,"resolveLogLevel");function ai(t){if(!t)return;let e=new Error(ce(t.message));return e.name=t.name,e.stack=t.stack?ce(t.stack):void 0,e}a(ai,"sanitizeError");function ci(t){if(t.command===void 0)return{commandTruncated:!1};let{value:e,truncated:r}=$r(ce(t.command));return{sanitizedCommand:e,commandTruncated:r}}a(ci,"sanitizePayload");function ui(t,e){let{event:r}=t;if(r==="version.check"){let i=["version.check"];return t.sdkVersion&&i.push(`sdk=${t.sdkVersion}`),t.containerVersion&&i.push(`container=${t.containerVersion}`),t.versionOutcome&&t.versionOutcome!=="compatible"&&i.push(`(${t.versionOutcome})`),i.join(" ")}let n=[r,t.outcome];if(e!==void 0)n.push(e);else if(t.command!==void 0){let{value:i}=$r(ce(t.command));n.push(i)}else if(t.path!==void 0)n.push(t.path);else if(r.includes("session")&&t.sessionId!==void 0)n.push(t.sessionId);else if(t.port!==void 0)n.push(String(t.port));else if(t.repoUrl!==void 0){let i=t.repoUrl;t.branch!==void 0&&(i+=` ${t.branch}`),n.push(i)}else if(t.pid!==void 0)n.push(String(t.pid));else if(t.backupId!==void 0)n.push(t.backupId);else if(t.repoPath!==void 0){let i=t.repoPath;t.branch!==void 0&&(i+=` branch=${t.branch}`),n.push(i)}else if(t.mountsProcessed!==void 0){let i=`${t.mountsProcessed} mounts`;t.mountFailures&&(i+=`, ${t.mountFailures} failed`),n.push(i)}else t.mountPath!==void 0&&n.push(t.mountPath);t.outcome==="error"&&(t.errorMessage!==void 0?n.push(`\\u2014 ${t.errorMessage}`):t.exitCode!==void 0&&n.push(`\\u2014 exitCode=${t.exitCode}`));let s=t.sizeBytes!==void 0?`(${t.durationMs}ms, ${t.sizeBytes}B)`:`(${t.durationMs}ms)`;return n.push(s),n.join(" ")}a(ui,"buildMessage");function N(t,e,r){let n=e.errorMessage??e.error?.message,s=n?ce(n):void 0,i=s!==void 0?{...e,errorMessage:s}:e,{sanitizedCommand:o,commandTruncated:c}=ci(i),u=ui(i,o),l={};for(let[p,g]of Object.entries(i))p!=="error"&&(l[p]=g);o!==void 0&&(l.command=o,c&&(l.commandTruncated=!0));let d=oi(i,r);d==="error"?t.error(u,ai(e.error),l):d==="warn"?t.warn(u,l):d==="debug"?t.debug(u,l):t.info(u,l)}a(N,"logCanonicalEvent");var j;(function(t){t[t.DEBUG=0]="DEBUG",t[t.INFO=1]="INFO",t[t.WARN=2]="WARN",t[t.ERROR=3]="ERROR"})(j||(j={}));var Z={reset:"\\x1B[0m",debug:"\\x1B[36m",info:"\\x1B[32m",warn:"\\x1B[33m",error:"\\x1B[31m",dim:"\\x1B[2m"},li=class Gr{static{a(this,"CloudflareLogger")}baseContext;minLevel;outputMode;constructor(e,r=j.INFO,n="structured"){this.baseContext=e,this.minLevel=r,this.outputMode=n}debug(e,r){if(this.shouldLog(j.DEBUG)){let n=this.buildLogData("debug",e,r);this.output(console.log,n)}}info(e,r){if(this.shouldLog(j.INFO)){let n=this.buildLogData("info",e,r);this.output(console.log,n)}}warn(e,r){if(this.shouldLog(j.WARN)){let n=this.buildLogData("warn",e,r);this.output(console.warn,n)}}error(e,r,n){if(this.shouldLog(j.ERROR)){let s=this.buildLogData("error",e,n,r);this.output(console.error,s)}}child(e){return new Gr({...this.baseContext,...e},this.minLevel,this.outputMode)}shouldLog(e){return e>=this.minLevel}buildLogData(e,r,n,s){let i={level:e,message:r,...this.baseContext,...n,timestamp:new Date().toISOString()};return s&&(i.error={message:s.message,stack:s.stack,name:s.name}),i}output(e,r){switch(this.outputMode){case"pretty":this.outputPretty(e,r);break;case"json-line":this.outputJsonLine(e,r);break;case"structured":this.outputStructured(e,r);break}}outputJsonLine(e,r){e(JSON.stringify(r))}outputStructured(e,r){e(r)}outputPretty(e,r){let{level:n,message:s,timestamp:i,traceId:o,component:c,sandboxId:u,sessionId:l,processId:d,commandId:p,durationMs:g,serviceVersion:m,instanceId:f,error:w,...y}=r,E=String(n||"INFO").toUpperCase(),T=this.getLevelColor(E),x=c?`[${c}]`:"",b=`${i?`${Z.dim}${new Date(i).toISOString().substring(11,23)}${Z.reset} `:""}${T}${E.padEnd(5)}${Z.reset} ${x} ${s}`,I=[];o&&I.push(`trace=${String(o).substring(0,12)}`),p&&I.push(`cmd=${String(p).substring(0,12)}`),u&&I.push(`sandbox=${u}`),l&&I.push(`session=${String(l).substring(0,12)}`),d&&I.push(`proc=${d}`),g!==void 0&&I.push(`dur=${g}ms`);for(let[C,P]of Object.entries(y)){if(P==null)continue;let H=typeof P=="object"?JSON.stringify(P):this.sanitizePrettyValue(String(P));I.push(`${C}=${H}`)}if(w&&typeof w=="object"){let C=w;C.name&&I.push(`err.name=${this.sanitizePrettyValue(C.name)}`),C.message&&I.push(`err.msg=${this.sanitizePrettyValue(C.message)}`),C.stack&&I.push(`err.stack=${this.sanitizePrettyValue(C.stack)}`)}I.length>0&&(b+=` ${Z.dim}${I.join(" ")}${Z.reset}`),e(b)}sanitizePrettyValue(e){return e.replace(/\\r/g,"\\\\r").replace(/\\n/g,"\\\\n")}getLevelColor(e){switch(e.toLowerCase()){case"debug":return Z.debug;case"info":return Z.info;case"warn":return Z.warn;case"error":return Z.error;default:return Z.reset}}},Be=class ut{static{a(this,"TraceContext")}static TRACE_HEADER="X-Trace-Id";static generate(){return`tr_${crypto.randomUUID().replace(/-/g,"").substring(0,16)}`}static fromHeaders(e){return e.get(ut.TRACE_HEADER)}static toHeaders(e){return{[ut.TRACE_HEADER]:e}}static getHeaderName(){return ut.TRACE_HEADER}};function Ce(){return{debug:a(()=>{},"debug"),info:a(()=>{},"info"),warn:a(()=>{},"warn"),error:a(()=>{},"error"),child:a(()=>Ce(),"child")}}a(Ce,"createNoOpLogger");function dt(t){let e=di(),r=hi(t.component);return new li({...t,traceId:t.traceId||Be.generate(),component:t.component,serviceVersion:t.serviceVersion||Fe("SANDBOX_VERSION")||void 0,instanceId:t.instanceId||Fe("HOSTNAME")||Fe("SANDBOX_INSTANCE_ID")||void 0},e,r)}a(dt,"createLogger");function di(){switch((Fe("SANDBOX_LOG_LEVEL")||"info").toLowerCase()){case"debug":return j.DEBUG;case"info":return j.INFO;case"warn":return j.WARN;case"error":return j.ERROR;default:return j.INFO}}a(di,"getLogLevelFromEnv");function hi(t){return Fe("SANDBOX_LOG_FORMAT")?.toLowerCase()==="pretty"?"pretty":t==="container"||t==="executor"?"json-line":"structured"}a(hi,"getOutputMode");function Fe(t){if(typeof process<"u"&&process.env)return process.env[t];if(typeof Bun<"u"){let e=Bun.env;if(e)return e[t]}}a(Fe,"getEnvVar");function S(t){return`\'${t.replace(/\'/g,"\'\\\\\'\'")}\'`}a(S,"shellEscape");function ye(t,e={data:[]}){let r=[],n=0;for(;n<t.length;){let s=t.indexOf(`\n`,n);if(s===-1)break;let i=t.substring(n,s),o=i.endsWith("\\r")?i.slice(0,-1):i;if(n=s+1,o===""&&e.data.length>0){r.push({event:e.event,data:e.data.join(`\n`)}),e={data:[]};continue}if(o.startsWith("event:")){e.event=o.startsWith("event: ")?o.substring(7):o.substring(6);continue}if(o.startsWith("data:")){let c=o.startsWith("data: ")?o.substring(6):o.substring(5);e.data.push(c)}}return{events:r,remaining:t.substring(n),currentEvent:e}}a(ye,"parseSSEFrames");function ht(t){return t&&typeof t.id=="string"&&typeof t.command=="string"&&typeof t.status=="string"}a(ht,"isProcess");function Vr(t){return typeof t=="object"&&t!==null&&"type"in t&&t.type==="response"}a(Vr,"isWSResponse");function qr(t){return typeof t=="object"&&t!==null&&"type"in t&&t.type==="stream"}a(qr,"isWSStreamChunk");function Xr(t){return typeof t=="object"&&t!==null&&"type"in t&&t.type==="error"}a(Xr,"isWSError");function $t(){return`ws_${Date.now()}_${Math.random().toString(36).substring(2,10)}`}a($t,"generateRequestId");var h={FILE_NOT_FOUND:"FILE_NOT_FOUND",PERMISSION_DENIED:"PERMISSION_DENIED",FILE_EXISTS:"FILE_EXISTS",IS_DIRECTORY:"IS_DIRECTORY",NOT_DIRECTORY:"NOT_DIRECTORY",FILE_TOO_LARGE:"FILE_TOO_LARGE",NO_SPACE:"NO_SPACE",TOO_MANY_FILES:"TOO_MANY_FILES",RESOURCE_BUSY:"RESOURCE_BUSY",READ_ONLY:"READ_ONLY",NAME_TOO_LONG:"NAME_TOO_LONG",TOO_MANY_LINKS:"TOO_MANY_LINKS",FILESYSTEM_ERROR:"FILESYSTEM_ERROR",COMMAND_NOT_FOUND:"COMMAND_NOT_FOUND",COMMAND_PERMISSION_DENIED:"COMMAND_PERMISSION_DENIED",INVALID_COMMAND:"INVALID_COMMAND",COMMAND_EXECUTION_ERROR:"COMMAND_EXECUTION_ERROR",STREAM_START_ERROR:"STREAM_START_ERROR",PROCESS_NOT_FOUND:"PROCESS_NOT_FOUND",PROCESS_PERMISSION_DENIED:"PROCESS_PERMISSION_DENIED",PROCESS_ERROR:"PROCESS_ERROR",SESSION_ALREADY_EXISTS:"SESSION_ALREADY_EXISTS",SESSION_DESTROYED:"SESSION_DESTROYED",SESSION_TERMINATED:"SESSION_TERMINATED",PORT_ALREADY_EXPOSED:"PORT_ALREADY_EXPOSED",PORT_IN_USE:"PORT_IN_USE",PORT_NOT_EXPOSED:"PORT_NOT_EXPOSED",INVALID_PORT_NUMBER:"INVALID_PORT_NUMBER",INVALID_PORT:"INVALID_PORT",SERVICE_NOT_RESPONDING:"SERVICE_NOT_RESPONDING",PORT_OPERATION_ERROR:"PORT_OPERATION_ERROR",CUSTOM_DOMAIN_REQUIRED:"CUSTOM_DOMAIN_REQUIRED",GIT_REPOSITORY_NOT_FOUND:"GIT_REPOSITORY_NOT_FOUND",GIT_BRANCH_NOT_FOUND:"GIT_BRANCH_NOT_FOUND",GIT_AUTH_FAILED:"GIT_AUTH_FAILED",GIT_NETWORK_ERROR:"GIT_NETWORK_ERROR",INVALID_GIT_URL:"INVALID_GIT_URL",GIT_CLONE_FAILED:"GIT_CLONE_FAILED",GIT_CHECKOUT_FAILED:"GIT_CHECKOUT_FAILED",GIT_OPERATION_FAILED:"GIT_OPERATION_FAILED",BUCKET_MOUNT_ERROR:"BUCKET_MOUNT_ERROR",BUCKET_UNMOUNT_ERROR:"BUCKET_UNMOUNT_ERROR",S3FS_MOUNT_ERROR:"S3FS_MOUNT_ERROR",MISSING_CREDENTIALS:"MISSING_CREDENTIALS",INVALID_MOUNT_CONFIG:"INVALID_MOUNT_CONFIG",BACKUP_CREATE_FAILED:"BACKUP_CREATE_FAILED",BACKUP_RESTORE_FAILED:"BACKUP_RESTORE_FAILED",BACKUP_NOT_FOUND:"BACKUP_NOT_FOUND",BACKUP_EXPIRED:"BACKUP_EXPIRED",INVALID_BACKUP_CONFIG:"INVALID_BACKUP_CONFIG",INTERPRETER_NOT_READY:"INTERPRETER_NOT_READY",CONTEXT_NOT_FOUND:"CONTEXT_NOT_FOUND",CODE_EXECUTION_ERROR:"CODE_EXECUTION_ERROR",PYTHON_NOT_AVAILABLE:"PYTHON_NOT_AVAILABLE",JAVASCRIPT_NOT_AVAILABLE:"JAVASCRIPT_NOT_AVAILABLE",OPENCODE_STARTUP_FAILED:"OPENCODE_STARTUP_FAILED",PROCESS_READY_TIMEOUT:"PROCESS_READY_TIMEOUT",PROCESS_EXITED_BEFORE_READY:"PROCESS_EXITED_BEFORE_READY",WATCH_NOT_FOUND:"WATCH_NOT_FOUND",WATCH_START_ERROR:"WATCH_START_ERROR",WATCH_STOP_ERROR:"WATCH_STOP_ERROR",VALIDATION_FAILED:"VALIDATION_FAILED",INVALID_JSON_RESPONSE:"INVALID_JSON_RESPONSE",UNKNOWN_ERROR:"UNKNOWN_ERROR",INTERNAL_ERROR:"INTERNAL_ERROR",RPC_TRANSPORT_ERROR:"RPC_TRANSPORT_ERROR",CONTAINER_UNAVAILABLE:"CONTAINER_UNAVAILABLE",OPERATION_INTERRUPTED:"OPERATION_INTERRUPTED"},pi={[h.FILE_NOT_FOUND]:404,[h.COMMAND_NOT_FOUND]:404,[h.PROCESS_NOT_FOUND]:404,[h.PORT_NOT_EXPOSED]:404,[h.GIT_REPOSITORY_NOT_FOUND]:404,[h.GIT_BRANCH_NOT_FOUND]:404,[h.CONTEXT_NOT_FOUND]:404,[h.WATCH_NOT_FOUND]:404,[h.IS_DIRECTORY]:400,[h.NOT_DIRECTORY]:400,[h.INVALID_COMMAND]:400,[h.INVALID_PORT_NUMBER]:400,[h.INVALID_PORT]:400,[h.INVALID_GIT_URL]:400,[h.CUSTOM_DOMAIN_REQUIRED]:400,[h.INVALID_JSON_RESPONSE]:400,[h.NAME_TOO_LONG]:400,[h.VALIDATION_FAILED]:400,[h.MISSING_CREDENTIALS]:400,[h.INVALID_MOUNT_CONFIG]:400,[h.GIT_AUTH_FAILED]:401,[h.PERMISSION_DENIED]:403,[h.COMMAND_PERMISSION_DENIED]:403,[h.PROCESS_PERMISSION_DENIED]:403,[h.READ_ONLY]:403,[h.FILE_EXISTS]:409,[h.PORT_ALREADY_EXPOSED]:409,[h.PORT_IN_USE]:409,[h.RESOURCE_BUSY]:409,[h.SESSION_ALREADY_EXISTS]:409,[h.OPERATION_INTERRUPTED]:409,[h.SESSION_DESTROYED]:410,[h.SESSION_TERMINATED]:410,[h.FILE_TOO_LARGE]:413,[h.SERVICE_NOT_RESPONDING]:502,[h.GIT_NETWORK_ERROR]:502,[h.BACKUP_NOT_FOUND]:404,[h.BACKUP_EXPIRED]:400,[h.INVALID_BACKUP_CONFIG]:400,[h.BACKUP_CREATE_FAILED]:500,[h.BACKUP_RESTORE_FAILED]:500,[h.PYTHON_NOT_AVAILABLE]:501,[h.JAVASCRIPT_NOT_AVAILABLE]:501,[h.INTERPRETER_NOT_READY]:503,[h.OPENCODE_STARTUP_FAILED]:503,[h.RPC_TRANSPORT_ERROR]:503,[h.CONTAINER_UNAVAILABLE]:503,[h.PROCESS_READY_TIMEOUT]:408,[h.PROCESS_EXITED_BEFORE_READY]:500,[h.NO_SPACE]:500,[h.TOO_MANY_FILES]:500,[h.TOO_MANY_LINKS]:500,[h.FILESYSTEM_ERROR]:500,[h.COMMAND_EXECUTION_ERROR]:500,[h.STREAM_START_ERROR]:500,[h.PROCESS_ERROR]:500,[h.PORT_OPERATION_ERROR]:500,[h.GIT_CLONE_FAILED]:500,[h.GIT_CHECKOUT_FAILED]:500,[h.GIT_OPERATION_FAILED]:500,[h.CODE_EXECUTION_ERROR]:500,[h.BUCKET_MOUNT_ERROR]:500,[h.BUCKET_UNMOUNT_ERROR]:500,[h.S3FS_MOUNT_ERROR]:500,[h.WATCH_START_ERROR]:500,[h.WATCH_STOP_ERROR]:500,[h.UNKNOWN_ERROR]:500,[h.INTERNAL_ERROR]:500};function F(t){return pi[t]||500}a(F,"getHttpStatus");function W(t,e){switch(t){case h.FILE_NOT_FOUND:return`Ensure the file exists at ${e.path} before attempting to access it`;case h.FILE_EXISTS:return`File already exists at ${e.path}. Use a different path or delete the existing file first`;case h.COMMAND_NOT_FOUND:return`Check that "${e.command}" is installed and available in the system PATH`;case h.PROCESS_NOT_FOUND:return"Verify the process ID is correct and the process has not already exited";case h.PORT_NOT_EXPOSED:return`Port ${e.port} is not currently available for this operation`;case h.PORT_ALREADY_EXPOSED:return`Port ${e.port} already has preview URL authorization or activation state`;case h.PORT_IN_USE:return`Port ${e.port} is already in use by another service. Choose a different port`;case h.SESSION_ALREADY_EXISTS:return`Session "${e.sessionId}" already exists. Use a different session ID or reuse the existing session`;case h.SESSION_DESTROYED:return`Session "${e.sessionId}" was destroyed. Create a new session to continue executing commands`;case h.SESSION_TERMINATED:return`Session "${e.sessionId}" ended because its shell exited (exit code: ${e.exitCode??"unknown"}). Session-local state (env vars, cwd, shell functions) has been lost. Retry the call to start a fresh session, or call createSession() with the same id to recreate it explicitly`;case h.INVALID_PORT:return`Port must be between 1 and 65535. Port ${e.port} is ${e.reason}`;case h.GIT_REPOSITORY_NOT_FOUND:return"Verify the repository URL is correct and accessible";case h.GIT_AUTH_FAILED:return"Check authentication credentials or use a public repository";case h.GIT_BRANCH_NOT_FOUND:return`Branch "${e.branch}" does not exist in the repository. Check the branch name or use the default branch`;case h.INTERPRETER_NOT_READY:return e.retryAfter?`Code interpreter is starting up. Retry after ${e.retryAfter} seconds`:"Code interpreter is not ready. Please wait a moment and try again";case h.CONTEXT_NOT_FOUND:return`Context "${e.contextId}" does not exist. Create a context first using createContext()`;case h.VALIDATION_FAILED:return"Check the request parameters and ensure they match the required format";case h.NO_SPACE:return"Not enough disk space available. Consider cleaning up temporary files or increasing storage";case h.PERMISSION_DENIED:return"Operation not permitted. Check file/directory permissions";case h.IS_DIRECTORY:return`Cannot perform this operation on a directory. Path ${e.path} is a directory`;case h.NOT_DIRECTORY:return`Expected a directory but found a file at ${e.path}`;case h.RESOURCE_BUSY:return"Resource is currently in use. Wait for the current operation to complete";case h.READ_ONLY:return"Cannot modify a read-only resource";case h.SERVICE_NOT_RESPONDING:return"Service is not responding. Check if the service is running and accessible";case h.BACKUP_NOT_FOUND:return`Backup "${e.backupId}" does not exist. Verify the backup ID is correct`;case h.BACKUP_EXPIRED:return`Backup "${e.backupId}" has expired. Create a new backup`;case h.INVALID_BACKUP_CONFIG:return`Invalid backup configuration: ${e.reason}`;case h.BACKUP_CREATE_FAILED:return"Backup creation failed. Check that the directory exists and you have sufficient disk space";case h.BACKUP_RESTORE_FAILED:return"Backup restoration failed. The archive may be corrupted or the target directory may be in use";case h.CONTAINER_UNAVAILABLE:return"The sandbox container is temporarily unavailable. Retry the same operation \\u2014 it will succeed once the container is ready.";case h.OPERATION_INTERRUPTED:return"The sandbox operation was interrupted by a runtime change. Retry only if the operation is idempotent, or verify sandbox state before retrying.";case h.RPC_TRANSPORT_ERROR:switch(e.kind){case"peer_closed":return"The container closed the WebSocket mid-call (likely a container restart, eviction, or crash). Retry the call \\u2014 the SDK will open a fresh connection.";case"connection_failed":return"The WebSocket connection failed. Retry the call; if the failure persists, check container health and network connectivity.";case"upgrade_failed":return"The WebSocket upgrade was rejected by the container. Verify the container is running and reachable on the configured port.";case"invalid_frame":return"The container sent a frame the RPC transport cannot handle. This usually indicates a version mismatch between the SDK and the container image.";case"protocol_error":return"The peer sent a malformed RPC message (could not parse the wire format). This usually indicates a version mismatch between the SDK and the container image.";case"session_disposed":return"The RPC session was disposed while a call was in flight. Avoid reusing stubs after disconnect(); the next method call will reconnect automatically.";default:return"The RPC transport raised an error. Retry the call \\u2014 the SDK will open a fresh connection."}default:return}}a(W,"getSuggestion");function Yr(t=9){let e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",r=new Uint8Array(t);crypto.getRandomValues(r);let n="";for(let s=0;s<t;s++)n+=e[r[s]%e.length];return n}a(Yr,"generateId");function Jr(t){if(typeof t=="number")return t;if(typeof t=="string"){let e=t.match(/^(\\d+)([smh])$/);if(!e)throw new Error(`invalid time expression ${t}`);let r=parseInt(e[1]),n=e[2];switch(n){case"s":return r;case"m":return r*60;case"h":return r*60*60;default:throw new Error(`unknown time unit ${n}`)}}throw new Error(`invalid type for a time expression: ${typeof t}`)}a(Jr,"parseTimeExpression");import{DurableObject as fi,WorkerEntrypoint as mi}from"cloudflare:workers";var an="there is no container instance that can be provided to this durable object",gi="you are requesting too many containers per second",Kt="runtime signalled the container to exit:",jt="container exited with unexpected exit code:",wi="the container is not listening",Qr="__CF_CONTAINER_STATE",Zr="OUTBOUND_CONFIGURATION",yi=3,en=5e3,Ei="10m",pt=300,Ht=8e3,tn=2e4,rn=33;var ue=new Map,zt=new Map,Gt=new Map,Si={SIGINT:2,SIGTERM:15,SIGKILL:9};function He(t,e){return(t instanceof Error?t.message:String(t)).toLowerCase().includes(e)}a(He,"isErrorOfType");var Wt=a(t=>He(t,an),"isNoInstanceError"),bi=a(t=>He(t,gi),"isRateLimitedError"),Ri=a(t=>He(t,Kt),"isRuntimeSignalledError"),nn=a(t=>He(t,wi),"isNotListeningError"),Ti=a(t=>He(t,jt),"isContainerExitNonZeroError");function Ii(t){return t instanceof Error?Ri(t)?+t.message.toLowerCase().slice(t.message.toLowerCase().indexOf(Kt)+Kt.length+1):Ti(t)?+t.message.toLowerCase().slice(t.message.toLowerCase().indexOf(jt)+jt.length+1):null:null}a(Ii,"getExitCodeFromError");function sn(t,e){let r=new AbortController;if(t?.aborted)return r.abort(),r.signal;t?.addEventListener("abort",()=>r.abort());let n=setTimeout(()=>r.abort(),e);return r.signal.addEventListener("abort",()=>clearTimeout(n)),r.signal}a(sn,"addTimeoutSignal");function Vt(t,e){let r=t.split("*");if(r.length===1)return t===e;if(!e.startsWith(r[0])||!e.endsWith(r[r.length-1]))return!1;let n=r[0].length;for(let s=1;s<r.length-1;s++){let i=e.indexOf(r[s],n);if(i===-1)return!1;n=i+r[s].length}return n<=e.length-r[r.length-1].length}a(Vt,"simpleGlobMatch");function on(t,e){return e.some(r=>Vt(r,t))}a(on,"matchesHostList");function Ci(t){let e=t.length;for(;e>0&&t[e-1]===".";)e--;return t.slice(0,e)}a(Ci,"normalizeHostname");var qt=class{static{a(this,"ContainerState")}storage;status;constructor(e){this.storage=e}async setRunning(){await this.setStatusAndupdate("running")}async setHealthy(){await this.setStatusAndupdate("healthy")}async setStopping(){await this.setStatusAndupdate("stopping")}async setStopped(){await this.setStatusAndupdate("stopped")}async setStoppedIfUnchanged(e){this.status===e&&await this.setStopped()}async setStoppedWithCode(e){this.status={status:"stopped_with_code",lastChange:Date.now(),exitCode:e},await this.update()}async getState(){if(!this.status){let e=await this.storage.get(Qr);e?this.status=e:(this.status={status:"stopped",lastChange:Date.now()},await this.update())}return this.status}async setStatusAndupdate(e){this.status={status:e,lastChange:Date.now()},await this.update()}async update(){if(!this.status)throw new Error("status should be init");await this.storage.put(Qr,this.status)}},$e=class extends mi{static{a(this,"ContainerProxy")}async fetch(e){let r=new URL(e.url),n=Ci(r.hostname),{className:s,containerId:i,outboundByHostOverrides:o,outboundHandlerOverride:c,enableInternet:u,allowedHosts:l,deniedHosts:d,interceptAll:p}=this.ctx.props,g={containerId:i,className:s};if(d&&on(n,d))return new Response("Origin is disallowed",{status:520});if(l&&!on(n,l))return new Response("Origin is disallowed",{status:520});let m=ue.get(s);if(o&&m){let y=o[n]??Object.entries(o).find(([E])=>E!==n&&Vt(E,n))?.[1];if(y&&m[y.method])return m[y.method](e,this.env,{...g,params:y.params})}let f=Gt.get(s);if(f){let y=f[n]??Object.entries(f).find(([E])=>E!==n&&Vt(E,n))?.[1];if(y)return y(e,this.env,g)}if(!p)return l||u?fetch(e):new Response("Origin is disallowed",{status:520});if(c&&m?.[c.method])return m[c.method](e,this.env,{...g,params:c.params});let w=zt.get(s);return w&&m?.[w]?m[w](e,this.env,g):l||u?fetch(e):new Response("Origin is disallowed",{status:520})}},xe=class extends fi{static{a(this,"Container")}static get outboundByHost(){return Gt.get(this.name)}static set outboundByHost(e){Gt.set(this.name,e)}static get outboundHandlers(){return ue.get(this.name)}static set outboundHandlers(e){let r=ue.get(this.name)??{};ue.set(this.name,{...r,...e})}static get outbound(){let e=zt.get(this.name);if(e)return ue.get(this.name)?.[e]}static set outbound(e){let r="__outbound__",n=ue.get(this.name)??{};ue.set(this.name,{...n,[r]:e}),zt.set(this.name,r)}static get outboundProxies(){return this.outboundHandlers}static set outboundProxies(e){this.outboundHandlers=e}static get outboundProxy(){return this.outbound}static set outboundProxy(e){this.outbound=e}defaultPort;requiredPorts;sleepAfter=Ei;envVars={};entrypoint;enableInternet=!0;labels={};interceptHttps=!1;allowedHosts;deniedHosts;pingEndpoint="ping";applyOutboundInterceptionPromise=Promise.resolve();usingInterception=!1;constructor(e,r,n){if(super(e,r),e.container===void 0)throw new Error("Containers have not been enabled for this Durable Object class. Have you correctly setup your Wrangler config? More info: https://developers.cloudflare.com/containers/get-started/#configuration");this.state=new qt(this.ctx.storage);let s=this.restoreOutboundConfiguration();this.ctx.blockConcurrencyWhile(async()=>{await this.scheduleNextAlarm(),this.renewActivityTimeout();let i=this.constructor;(s!==void 0||i.outboundByHost!==void 0||i.outbound!==void 0||i.outboundHandlers!==void 0||this.effectiveAllowedHosts!==void 0||this.effectiveDeniedHosts!==void 0)&&(this.usingInterception=!0),this.container.running&&(this.applyOutboundInterceptionPromise=this.applyOutboundInterception())}),this.container=e.container,n&&(n.defaultPort!==void 0&&(this.defaultPort=n.defaultPort),n.sleepAfter!==void 0&&(this.sleepAfter=n.sleepAfter),n.envVars!==void 0&&(this.envVars=n.envVars),n.entrypoint!==void 0&&(this.entrypoint=n.entrypoint),n.enableInternet!==void 0&&(this.enableInternet=n.enableInternet)),this.sql`\n CREATE TABLE IF NOT EXISTS container_schedules (\n id TEXT PRIMARY KEY NOT NULL DEFAULT (randomblob(9)),\n callback TEXT NOT NULL,\n payload TEXT,\n type TEXT NOT NULL CHECK(type IN (\'scheduled\', \'delayed\')),\n time INTEGER NOT NULL,\n delayInSeconds INTEGER,\n created_at INTEGER DEFAULT (unixepoch())\n )\n `,this.container.running&&(this.monitor=this.container.monitor(),this.setupMonitorCallbacks())}async getState(){return{...await this.state.getState()}}async setOutboundHandler(e,...r){this.validateOutboundHandlerMethodName(e),this.outboundHandlerOverride=r.length===0?{method:e}:{method:e,params:r[0]},await this.refreshOutboundInterception()}async setOutboundByHost(e,r,...n){this.validateOutboundHandlerMethodName(r),this.outboundByHostOverrides[e]=n.length===0?{method:r}:{method:r,params:n[0]},await this.refreshOutboundInterception()}async removeOutboundByHost(e){delete this.outboundByHostOverrides[e],await this.refreshOutboundInterception()}async setOutboundByHosts(e){for(let r of Object.values(e)){let n=typeof r=="string"?r:r.method;this.validateOutboundHandlerMethodName(n)}this.outboundByHostOverrides=Object.fromEntries(Object.entries(e).map(([r,n])=>[r,typeof n=="string"?{method:n}:n])),await this.refreshOutboundInterception()}async setAllowedHosts(e){this.allowedHostsOverride=[...e],this.usingInterception=!0,await this.refreshOutboundInterception()}async setDeniedHosts(e){this.deniedHostsOverride=[...e],this.usingInterception=!0,await this.refreshOutboundInterception()}async allowHost(e){let r=this.effectiveAllowedHosts??[];r.includes(e)||(this.allowedHostsOverride=[...r,e]),this.usingInterception=!0,await this.refreshOutboundInterception()}async denyHost(e){let r=this.effectiveDeniedHosts??[];r.includes(e)||(this.deniedHostsOverride=[...r,e]),this.usingInterception=!0,await this.refreshOutboundInterception()}async removeAllowedHost(e){this.allowedHostsOverride=(this.effectiveAllowedHosts??[]).filter(r=>r!==e),await this.refreshOutboundInterception()}async removeDeniedHost(e){this.deniedHostsOverride=(this.effectiveDeniedHosts??[]).filter(r=>r!==e),await this.refreshOutboundInterception()}async start(e,r){let n=r?.portToCheck??this.defaultPort??(this.requiredPorts?this.requiredPorts[0]:rn),s=r?.waitInterval??pt;await this.startContainerIfNotRunning({signal:r?.signal,waitInterval:s,retries:r?.retries??Math.ceil(Ht/s),portToCheck:n},e),this.setupMonitorCallbacks(),await this.ctx.blockConcurrencyWhile(async()=>{await this.onStart()})}async startAndWaitForPorts(e,r,n){let s,i,o;typeof e=="object"&&e!==null&&!Array.isArray(e)?(s=e.ports,i=e.cancellationOptions,o=e.startOptions):(s=e,i=r,o=n);let c=await this.getPortsToCheck(s);await this.syncPendingStoppedEvents(),i??={};let u=i.instanceGetTimeoutMS??Ht,l=i.waitInterval??pt,d=Math.ceil(u/l),p={signal:i.abort,retries:d,waitInterval:l,portToCheck:c[0]},g=await this.startContainerIfNotRunning(p,o),f=Math.ceil((i.portReadyTimeoutMS??tn)/l)-g;for(let w of c)f=await this.waitForPort({signal:i.abort,waitInterval:l,retries:f,portToCheck:w});this.setupMonitorCallbacks(),await this.ctx.blockConcurrencyWhile(async()=>{await this.state.setHealthy(),await this.onStart()})}async waitForPort(e){let r=e.portToCheck,n=this.container.getTcpPort(r),s=new Promise(c=>{e.signal?.addEventListener("abort",()=>{c(!0)})}),i=e.waitInterval??pt,o=e.retries??Math.ceil(tn/i);for(let c=0;c<o;c++)try{let u=sn(e.signal,en);await n.fetch(`http://${this.pingEndpoint}`,{signal:u});break}catch(u){let l=u instanceof Error?u.message:String(u);if(!this.container.running){try{await this.onError(new Error("Container crashed while checking for ports, did you start the container and setup the entrypoint correctly?"))}catch{}throw u}if(c===o-1){try{await this.onError(`Failed to verify port ${r} is available after ${(c+1)*i}ms, last error: ${l}`)}catch{}throw u}if(await Promise.any([new Promise(d=>setTimeout(d,i)),s]),e.signal?.aborted)throw new Error("Container request aborted.",{cause:u})}return o}async stop(e="SIGTERM"){this.container.running&&this.container.signal(typeof e=="string"?Si[e]:e),await this.syncPendingStoppedEvents()}async destroy(){await this.container.destroy()}onStart(){}onStop(e){}async onActivityExpired(){console.log("Activity expired, signalling container to stop"),this.container.running&&await this.stop()}onError(e){throw console.error("Container error:",e),e}renewActivityTimeout(){let e=Jr(this.sleepAfter)*1e3;this.sleepAfterMs=Date.now()+e}decrementInflight(){this.inflightRequests=Math.max(0,this.inflightRequests-1),this.inflightRequests===0&&this.renewActivityTimeout()}async schedule(e,r,n){let s=Yr(9);if(typeof r!="string")throw new Error("Callback must be a string (method name)");if(typeof this[r]!="function")throw new Error(`this.${r} is not a function`);if(e instanceof Date){let i=Math.floor(e.getTime()/1e3);return this.sql`\n INSERT OR REPLACE INTO container_schedules (id, callback, payload, type, time)\n VALUES (${s}, ${r}, ${JSON.stringify(n)}, \'scheduled\', ${i})\n `,await this.scheduleNextAlarm(),{taskId:s,callback:r,payload:n,time:i,type:"scheduled"}}if(typeof e=="number"){let i=Math.floor(Date.now()/1e3+e);return this.sql`\n INSERT OR REPLACE INTO container_schedules (id, callback, payload, type, delayInSeconds, time)\n VALUES (${s}, ${r}, ${JSON.stringify(n)}, \'delayed\', ${e}, ${i})\n `,await this.scheduleNextAlarm(),{taskId:s,callback:r,payload:n,delayInSeconds:e,time:i,type:"delayed"}}throw new Error("Invalid schedule type. \'when\' must be a Date or number of seconds")}async containerFetch(e,r,n){let{request:s,port:i}=this.requestAndPortFromContainerFetchArgs(e,r,n),o=await this.state.getState();if(!this.container.running||o.status!=="healthy")try{await this.startAndWaitForPorts(i,{abort:s.signal})}catch(l){return Wt(l)?new Response(`There is no Container instance available at this time.\nThis is likely because you have reached your max concurrent instance count (set in wrangler config) or are you currently provisioning the Container.\nIf you are deploying your Container for the first time, check your dashboard to see provisioning status, this may take a few minutes.`,{status:503}):bi(l)?new Response(l instanceof Error?l.message:String(l),{status:429}):new Response(`Failed to start container: ${l instanceof Error?l.message:String(l)}`,{status:500})}let c=this.container.getTcpPort(i),u=s.url.replace("https:","http:");this.inflightRequests++;try{this.renewActivityTimeout();let l=await c.fetch(u,s);if(l.webSocket!==null){let d=l.webSocket,[p,g]=Object.values(new WebSocketPair),m=!1,f=a(()=>{m||(m=!0,this.decrementInflight())},"settleInflight");return d.accept(),g.accept(),g.addEventListener("message",async w=>{this.renewActivityTimeout();try{let y=w.data instanceof Blob?await w.data.arrayBuffer():w.data;d.send(y)}catch{g.close(1011,"Failed to forward message to container")}}),d.addEventListener("message",async w=>{this.renewActivityTimeout();try{let y=w.data instanceof Blob?await w.data.arrayBuffer():w.data;g.send(y)}catch{d.close(1011,"Failed to forward message to client")}}),g.addEventListener("close",w=>{f();let y=w.code===1005||w.code===1006?1e3:w.code;d.close(y,w.reason)}),d.addEventListener("close",w=>{f();let y=w.code===1005||w.code===1006?1e3:w.code;g.close(y,w.reason)}),g.addEventListener("error",()=>{f(),d.close(1011,"Client WebSocket error")}),d.addEventListener("error",()=>{f(),g.close(1011,"Container WebSocket error")}),new Response(null,{status:l.status,webSocket:p,headers:l.headers})}if(l.body!==null){let{readable:d,writable:p}=new IdentityTransformStream;return l.body?.pipeTo(p).finally(()=>{this.decrementInflight()}),new Response(d,l)}return this.decrementInflight(),l}catch(l){if(this.decrementInflight(),!(l instanceof Error))throw l;return l.message.includes("Network connection lost.")?new Response("Container suddenly disconnected, try again",{status:500}):(console.error(`Error proxying request to container ${this.ctx.id}:`,l),new Response(`Error proxying request to container: ${l instanceof Error?l.message:String(l)}`,{status:500}))}}async fetch(e){if(this.defaultPort===void 0&&!e.headers.has("cf-container-target-port"))throw new Error("No port configured for this container. Set the `defaultPort` in your Container subclass, or specify a port with `container.fetch(switchPort(request, port))`.");let r=this.defaultPort;if(e.headers.has("cf-container-target-port")){let n=parseInt(e.headers.get("cf-container-target-port")??"");if(isNaN(n))throw new Error("port value from switchPort is not a number");r=n}return await this.containerFetch(e,r)}container;onStopCalled=!1;state;monitor;startInFlight;monitoredPromise;sleepAfterMs=0;inflightRequests=0;outboundByHostOverrides={};outboundHandlerOverride;allowedHostsOverride;deniedHostsOverride;hasInterceptAllRegistration=!1;validateOutboundHandlerMethodName(e){let r=ue.get(this.constructor.name);if(!r||!(e in r))throw new Error(`Outbound handler method \'${e}\' not found in outboundHandlers for ${this.constructor.name}`)}get effectiveAllowedHosts(){return this.allowedHostsOverride??this.allowedHosts}get effectiveDeniedHosts(){return this.deniedHostsOverride??this.deniedHosts}getOutboundConfiguration(){return{outboundByHostOverrides:Object.keys(this.outboundByHostOverrides).length>0?this.outboundByHostOverrides:void 0,outboundHandlerOverride:this.outboundHandlerOverride,allowedHosts:this.effectiveAllowedHosts,deniedHosts:this.effectiveDeniedHosts,hasInterceptAllRegistration:this.hasInterceptAllRegistration||void 0}}persistOutboundConfiguration(e){this.ctx.storage.kv.put(Zr,{...e,allowedHosts:this.allowedHostsOverride,deniedHosts:this.deniedHostsOverride})}restoreOutboundConfiguration(){let e=this.ctx.storage.kv.get(Zr);if(e){if(this.outboundHandlerOverride=void 0,e.outboundHandlerOverride!==void 0)try{this.validateOutboundHandlerMethodName(e.outboundHandlerOverride.method),this.outboundHandlerOverride=e.outboundHandlerOverride}catch(r){console.warn("Ignoring invalid persisted outbound handler override:",r)}this.outboundByHostOverrides={};for(let[r,n]of Object.entries(e.outboundByHostOverrides??{}))try{this.validateOutboundHandlerMethodName(n.method),this.outboundByHostOverrides[r]=n}catch(s){console.warn(`Ignoring invalid persisted outbound override for ${r}:`,s)}return this.hasInterceptAllRegistration=e.hasInterceptAllRegistration===!0,e.allowedHosts&&(this.allowedHostsOverride=e.allowedHosts),e.deniedHosts&&(this.deniedHostsOverride=e.deniedHosts),this.getOutboundConfiguration()}}needsCatchAllInterception(){return this.constructor.outbound!==void 0||this.outboundHandlerOverride!==void 0}hasMutableOutboundConfiguration(){return Object.keys(this.outboundByHostOverrides).length>0||this.allowedHostsOverride!==void 0||this.deniedHostsOverride!==void 0}shouldInterceptAllOutbound(){return this.hasInterceptAllRegistration||this.needsCatchAllInterception()||this.effectiveAllowedHosts!==void 0||this.effectiveDeniedHosts!==void 0||this.hasMutableOutboundConfiguration()}getStaticOutboundByHostKeys(){let e=this.constructor;return e.outboundByHost?Object.keys(e.outboundByHost):[]}getHostsToIntercept(){let e=new Set,r=this.constructor;if(r.outboundByHost)for(let n of Object.keys(r.outboundByHost))e.add(n);for(let n of Object.keys(this.outboundByHostOverrides))e.add(n);return[...e]}async refreshOutboundInterception(){this.usingInterception&&(this.applyOutboundInterceptionPromise=this.applyOutboundInterception(),await this.applyOutboundInterceptionPromise)}async applyOutboundInterception(){let e=this.ctx;if(e.exports===void 0)throw new Error("ctx.exports is undefined, please try to update your compatibility date or export ContainerProxy from the containers package in your worker entrypoint");if(e.exports.ContainerProxy===void 0)throw new Error("ctx.exports.ContainerProxy is undefined, export ContainerProxy from the containers package in your worker entrypoint");let r=this.shouldInterceptAllOutbound();r&&(this.hasInterceptAllRegistration=r);let n=this.getOutboundConfiguration();this.persistOutboundConfiguration(n);let s=this.getHostsToIntercept(),i={enableInternet:this.enableInternet,containerId:this.ctx.id.toString(),className:this.constructor.name,outboundByHostOverrides:n.outboundByHostOverrides,outboundHandlerOverride:n.outboundHandlerOverride,allowedHosts:n.allowedHosts,deniedHosts:n.deniedHosts,interceptAll:r},o=e.exports.ContainerProxy({props:i});if(r){for(let c of this.getStaticOutboundByHostKeys())await this.container.interceptOutboundHttp(c,o),this.interceptHttps&&await this.container.interceptOutboundHttps(c,o);this.interceptHttps&&await this.container.interceptOutboundHttps("*",o),await this.container.interceptAllOutboundHttp(o)}else for(let c of s)await this.container.interceptOutboundHttp(c,o),this.interceptHttps&&await this.container.interceptOutboundHttps(c,o)}sql(e,...r){let n=e.reduce((s,i,o)=>s+i+(o<r.length?"?":""),"");return[...this.ctx.storage.sql.exec(n,...r)]}requestAndPortFromContainerFetchArgs(e,r,n){let s,i;if(e instanceof Request)s=e,i=typeof r=="number"?r:void 0;else{let o=typeof e=="string"?e:e.toString(),c=typeof r=="number"?{}:r||{};i=typeof r=="number"?r:typeof n=="number"?n:void 0,s=new Request(o,c)}if(i??=this.defaultPort,i===void 0)throw new Error("No port specified for container fetch. Set defaultPort or specify a port parameter.");return{request:s,port:i}}async getPortsToCheck(e){return e!==void 0?Array.isArray(e)?e:[e]:this.requiredPorts&&this.requiredPorts.length>0?[...this.requiredPorts]:[this.defaultPort??rn]}async startContainerIfNotRunning(e,r){if(this.startInFlight)return this.startInFlight;if(this.container.running)return this.monitor||(this.monitor=this.container.monitor()),0;let n=this.doStartContainer(e,r);this.startInFlight=n;try{return await n}finally{this.startInFlight===n&&(this.startInFlight=void 0)}}async doStartContainer(e,r){let n=new Promise(o=>{e.signal?.addEventListener("abort",()=>{o(!0)})}),s=e.waitInterval??pt,i=e.retries??Math.ceil(Ht/s);for(let o=0;o<i;o++){let c=r?.envVars??this.envVars,u=r?.entrypoint??this.entrypoint,l=r?.enableInternet??this.enableInternet,d=r?.labels??this.labels,p={enableInternet:l};c&&Object.keys(c).length>0&&(p.env=c),u&&(p.entrypoint=u),d&&Object.keys(d).length>0&&(p.labels=d),this.renewActivityTimeout();let g=a(async()=>{let f=await this.monitor?.catch(w=>w);if(typeof f=="number"){let w=new Error(`Container exited before we could determine the container health, exit code: ${f}`);await this.state.setStoppedWithCode(f),this.monitor=void 0;try{await this.onError(w)}catch{}throw w}else if(!Wt(f)){await this.state.setStopped(),this.monitor=void 0;try{await this.onError(f)}catch{}throw f}},"handleError");o>0&&!this.container.running&&await g(),await this.scheduleNextAlarm(),this.container.running?await this.scheduleNextAlarm():(await this.refreshOutboundInterception(),this.container.start(p),this.monitor=this.container.monitor(),await this.state.setRunning()),this.renewActivityTimeout();let m=this.container.getTcpPort(e.portToCheck);try{let f=sn(e.signal,en);return await m.fetch("http://containerstarthealthcheck",{signal:f}),o}catch(f){if(nn(f)&&this.container.running)return o;if(!this.container.running&&nn(f)&&await g(),await Promise.any([new Promise(w=>setTimeout(w,e.waitInterval)),n]),e.signal?.aborted)throw new Error("Aborted waiting for container to start as we received a cancellation signal",{cause:f});if(i===o+1)throw f instanceof Error&&f.message.includes("Network connection lost")&&this.ctx.abort(),await g(),await this.state.setStopped(),this.monitor=void 0,new Error(an,{cause:f});continue}}throw new Error(`Container did not start after ${i*s}ms`)}setupMonitorCallbacks(){let e=this.monitor;!e||this.monitoredPromise===e||(this.monitoredPromise=e,e.then(async()=>{await this.ctx.blockConcurrencyWhile(async()=>{this.monitor===e&&await this.state.setStoppedWithCode(0)})}).catch(async r=>{if(this.monitor!==e)return;if(Wt(r)){await this.ctx.blockConcurrencyWhile(async()=>{this.monitor===e&&await this.state.setStopped()});return}let n=Ii(r);if(n!==null){await this.ctx.blockConcurrencyWhile(async()=>{this.monitor===e&&await this.state.setStoppedWithCode(n)});return}if(await this.ctx.blockConcurrencyWhile(async()=>{this.monitor===e&&await this.state.setStopped()}),this.monitor===e)try{await this.onError(r)}catch{}}).finally(()=>{this.monitor===e&&(this.monitoredPromise=void 0,this.monitor=void 0,this.timeout&&(this.resolve&&this.resolve(),clearTimeout(this.timeout)))}))}deleteSchedules(e){this.sql`DELETE FROM container_schedules WHERE callback = ${e}`}async alarm(e){if(e!==void 0&&e.isRetry&&e.retryCount>yi){((Number(this.sql`SELECT COUNT(*) as count FROM container_schedules`[0]?.count)||0)>0||this.container.running)&&await this.scheduleNextAlarm();return}let r=Date.now();await this.ctx.storage.setAlarm(r),await this.ctx.storage.sync();let n=this.sql`\n SELECT * FROM container_schedules;\n `,s=Date.now()+180*1e3,i=Date.now()/1e3;for(let l of n){if(l.time>i)continue;let d=this[l.callback];if(!d||typeof d!="function"){console.error(`Callback ${l.callback} not found or is not a function`);continue}let p=this.getSchedule(l.id);try{let g=l.payload?JSON.parse(l.payload):void 0;await d.call(this,g,await p)}catch(g){console.error(`Error executing scheduled callback "${l.callback}":`,g)}this.sql`DELETE FROM container_schedules WHERE id = ${l.id}`}let o=this.sql`\n SELECT * FROM container_schedules;\n `,c=Math.min(...o.map(l=>l.time*1e3));if(!this.container.running){await this.syncPendingStoppedEvents(),o.length==0?await this.ctx.storage.deleteAlarm():await this.ctx.storage.setAlarm(c);return}if(this.isActivityExpired()){await this.onActivityExpired(),this.renewActivityTimeout();return}s=Math.min(c,s,this.sleepAfterMs);let u=Math.max(0,s-Date.now());await new Promise(l=>{if(this.resolve=l,!this.container.running){l();return}this.timeout=setTimeout(()=>{l()},u)}),await this.ctx.storage.setAlarm(Date.now())}timeout;resolve;async syncPendingStoppedEvents(){let e=await this.state.getState();if(!this.container.running&&(e.status==="healthy"||e.status==="running")){await this.callOnStop({exitCode:0,reason:"exit"},e);return}if(!this.container.running&&e.status==="stopped_with_code"){await this.callOnStop({exitCode:e.exitCode??0,reason:"exit"},e);return}}async callOnStop(e,r){if(this.onStopCalled)return;this.onStopCalled=!0;let n=this.onStop(e);n instanceof Promise?await n.finally(()=>{this.onStopCalled=!1}):this.onStopCalled=!1,await this.state.setStoppedIfUnchanged(r)}async scheduleNextAlarm(e=1e3){let r=e+Date.now();this.timeout&&(this.resolve&&this.resolve(),clearTimeout(this.timeout)),await this.ctx.storage.setAlarm(r),await this.ctx.storage.sync()}async listSchedules(e){let r=this.sql`\n SELECT * FROM container_schedules WHERE callback = ${e} LIMIT 1\n `;return!r||r.length===0?[]:r.map(this.toSchedule)}toSchedule(e){let r;try{r=JSON.parse(e.payload)}catch(n){console.error(`Error parsing payload for schedule ${e.id}:`,n),r=void 0}return e.type==="delayed"?{taskId:e.id,callback:e.callback,payload:r,type:"delayed",time:e.time,delayInSeconds:e.delayInSeconds}:{taskId:e.id,callback:e.callback,payload:r,type:"scheduled",time:e.time}}async getSchedule(e){let r=this.sql`\n SELECT * FROM container_schedules WHERE id = ${e} LIMIT 1\n `;if(!r||r.length===0)return;let n=r[0];return this.toSchedule(n)}isActivityExpired(){return this.inflightRequests>0?(this.renewActivityTimeout(),!1):this.sleepAfterMs<=Date.now()}};var xi="cf-singleton-container";function Xt(t,e=xi){let r=t.idFromName(e);return t.get(r)}a(Xt,"getContainer");function ft(t,e){let r=new Headers(t.headers);return r.set("cf-container-target-port",e.toString()),new Request(t,{headers:r})}a(ft,"switchPort");var Jt=new TextEncoder,vi={appstream2:"appstream",cloudhsmv2:"cloudhsm",email:"ses",marketplace:"aws-marketplace",mobile:"AWSMobileHubService",pinpoint:"mobiletargeting",queue:"sqs","git-codecommit":"codecommit","mturk-requester-sandbox":"mturk-requester","personalize-runtime":"personalize"},Oi=new Set(["authorization","content-type","content-length","user-agent","presigned-expires","expect","x-amzn-trace-id","range","connection"]),Ke=class{static{a(this,"AwsClient")}constructor({accessKeyId:e,secretAccessKey:r,sessionToken:n,service:s,region:i,cache:o,retries:c,initRetryMs:u}){if(e==null)throw new TypeError("accessKeyId is a required option");if(r==null)throw new TypeError("secretAccessKey is a required option");this.accessKeyId=e,this.secretAccessKey=r,this.sessionToken=n,this.service=s,this.region=i,this.cache=o||new Map,this.retries=c??10,this.initRetryMs=u||50}async sign(e,r){if(e instanceof Request){let{method:i,url:o,headers:c,body:u}=e;r=Object.assign({method:i,url:o,headers:c},r),r.body==null&&c.has("Content-Type")&&(r.body=u!=null&&c.has("X-Amz-Content-Sha256")?u:await e.clone().arrayBuffer()),e=o}let n=new Qt(Object.assign({url:e.toString()},r,this,r&&r.aws)),s=Object.assign({},r,await n.sign());delete s.aws;try{return new Request(s.url.toString(),s)}catch(i){if(i instanceof TypeError)return new Request(s.url.toString(),Object.assign({duplex:"half"},s));throw i}}async fetch(e,r){for(let n=0;n<=this.retries;n++){let s=fetch(await this.sign(e,r));if(n===this.retries)return s;let i=await s;if(i.status<500&&i.status!==429)return i;await new Promise(o=>setTimeout(o,Math.random()*this.initRetryMs*Math.pow(2,n)))}throw new Error("An unknown error occurred, ensure retries is not negative")}},Qt=class{static{a(this,"AwsV4Signer")}constructor({method:e,url:r,headers:n,body:s,accessKeyId:i,secretAccessKey:o,sessionToken:c,service:u,region:l,cache:d,datetime:p,signQuery:g,appendSessionToken:m,allHeaders:f,singleEncode:w}){if(r==null)throw new TypeError("url is a required option");if(i==null)throw new TypeError("accessKeyId is a required option");if(o==null)throw new TypeError("secretAccessKey is a required option");this.method=e||(s?"POST":"GET"),this.url=new URL(r),this.headers=new Headers(n||{}),this.body=s,this.accessKeyId=i,this.secretAccessKey=o,this.sessionToken=c;let y,E;(!u||!l)&&([y,E]=_i(this.url,this.headers)),this.service=u||y||"",this.region=l||E||"us-east-1",this.cache=d||new Map,this.datetime=p||new Date().toISOString().replace(/[:-]|\\.\\d{3}/g,""),this.signQuery=g,this.appendSessionToken=m||this.service==="iotdevicegateway",this.headers.delete("Host"),this.service==="s3"&&!this.signQuery&&!this.headers.has("X-Amz-Content-Sha256")&&this.headers.set("X-Amz-Content-Sha256","UNSIGNED-PAYLOAD");let T=this.signQuery?this.url.searchParams:this.headers;if(T.set("X-Amz-Date",this.datetime),this.sessionToken&&!this.appendSessionToken&&T.set("X-Amz-Security-Token",this.sessionToken),this.signableHeaders=["host",...this.headers.keys()].filter(b=>f||!Oi.has(b)).sort(),this.signedHeaders=this.signableHeaders.join(";"),this.canonicalHeaders=this.signableHeaders.map(b=>b+":"+(b==="host"?this.url.host:(this.headers.get(b)||"").replace(/\\s+/g," "))).join(`\n`),this.credentialString=[this.datetime.slice(0,8),this.region,this.service,"aws4_request"].join("/"),this.signQuery&&(this.service==="s3"&&!T.has("X-Amz-Expires")&&T.set("X-Amz-Expires","86400"),T.set("X-Amz-Algorithm","AWS4-HMAC-SHA256"),T.set("X-Amz-Credential",this.accessKeyId+"/"+this.credentialString),T.set("X-Amz-SignedHeaders",this.signedHeaders)),this.service==="s3")try{this.encodedPath=decodeURIComponent(this.url.pathname.replace(/\\+/g," "))}catch{this.encodedPath=this.url.pathname}else this.encodedPath=this.url.pathname.replace(/\\/+/g,"/");w||(this.encodedPath=encodeURIComponent(this.encodedPath).replace(/%2F/g,"/")),this.encodedPath=ln(this.encodedPath);let x=new Set;this.encodedSearch=[...this.url.searchParams].filter(([b])=>{if(!b)return!1;if(this.service==="s3"){if(x.has(b))return!1;x.add(b)}return!0}).map(b=>b.map(I=>ln(encodeURIComponent(I)))).sort(([b,I],[C,P])=>b<C?-1:b>C?1:I<P?-1:I>P?1:0).map(b=>b.join("=")).join("&")}async sign(){return this.signQuery?(this.url.searchParams.set("X-Amz-Signature",await this.signature()),this.sessionToken&&this.appendSessionToken&&this.url.searchParams.set("X-Amz-Security-Token",this.sessionToken)):this.headers.set("Authorization",await this.authHeader()),{method:this.method,url:this.url,headers:this.headers,body:this.body}}async authHeader(){return["AWS4-HMAC-SHA256 Credential="+this.accessKeyId+"/"+this.credentialString,"SignedHeaders="+this.signedHeaders,"Signature="+await this.signature()].join(", ")}async signature(){let e=this.datetime.slice(0,8),r=[this.secretAccessKey,e,this.region,this.service].join(),n=this.cache.get(r);if(!n){let s=await We("AWS4"+this.secretAccessKey,e),i=await We(s,this.region),o=await We(i,this.service);n=await We(o,"aws4_request"),this.cache.set(r,n)}return Yt(await We(n,await this.stringToSign()))}async stringToSign(){return["AWS4-HMAC-SHA256",this.datetime,this.credentialString,Yt(await cn(await this.canonicalString()))].join(`\n`)}async canonicalString(){return[this.method.toUpperCase(),this.encodedPath,this.encodedSearch,this.canonicalHeaders+`\n`,this.signedHeaders,await this.hexBodyHash()].join(`\n`)}async hexBodyHash(){let e=this.headers.get("X-Amz-Content-Sha256")||(this.service==="s3"&&this.signQuery?"UNSIGNED-PAYLOAD":null);if(e==null){if(this.body&&typeof this.body!="string"&&!("byteLength"in this.body))throw new Error("body must be a string, ArrayBuffer or ArrayBufferView, unless you include the X-Amz-Content-Sha256 header");e=Yt(await cn(this.body||""))}return e}};async function We(t,e){let r=await crypto.subtle.importKey("raw",typeof t=="string"?Jt.encode(t):t,{name:"HMAC",hash:{name:"SHA-256"}},!1,["sign"]);return crypto.subtle.sign("HMAC",r,Jt.encode(e))}a(We,"hmac");async function cn(t){return crypto.subtle.digest("SHA-256",typeof t=="string"?Jt.encode(t):t)}a(cn,"hash");var un=["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"];function Yt(t){let e=new Uint8Array(t),r="";for(let n=0;n<e.length;n++){let s=e[n];r+=un[s>>>4&15],r+=un[s&15]}return r}a(Yt,"buf2hex");function ln(t){return t.replace(/[!\'()*]/g,e=>"%"+e.charCodeAt(0).toString(16).toUpperCase())}a(ln,"encodeRfc3986");function _i(t,e){let{hostname:r,pathname:n}=t;if(r.endsWith(".on.aws")){let c=r.match(/^[^.]{1,63}\\.lambda-url\\.([^.]{1,63})\\.on\\.aws$/);return c!=null?["lambda",c[1]||""]:["",""]}if(r.endsWith(".r2.cloudflarestorage.com"))return["s3","auto"];if(r.endsWith(".backblazeb2.com")){let c=r.match(/^(?:[^.]{1,63}\\.)?s3\\.([^.]{1,63})\\.backblazeb2\\.com$/);return c!=null?["s3",c[1]||""]:["",""]}let s=r.replace("dualstack.","").match(/([^.]{1,63})\\.(?:([^.]{0,63})\\.)?amazonaws\\.com(?:\\.cn)?$/),i=s&&s[1]||"",o=s&&s[2];if(o==="us-gov")o="us-gov-west-1";else if(o==="s3"||o==="s3-accelerate")o="us-east-1",i="s3";else if(i==="iot")r.startsWith("iot.")?i="execute-api":r.startsWith("data.jobs.iot.")?i="iot-jobs-data":i=n==="/mqtt"?"iotdevicegateway":"iotdata";else if(i==="autoscaling"){let c=(e.get("X-Amz-Target")||"").split(".")[0];c==="AnyScaleFrontendService"?i="application-autoscaling":c==="AnyScaleScalingPlannerFrontendService"&&(i="autoscaling-plans")}else o==null&&i.startsWith("s3-")?(o=i.slice(3).replace(/^fips-|^external-1/,""),i="s3"):i.endsWith("-fips")?i=i.slice(0,-5):o&&/-\\d$/.test(i)&&!/-\\d$/.test(o)&&([i,o]=[o,i]);return[vi[i]||i,o||""]}a(_i,"guessServiceRegion");import*as Ai from"cloudflare:workers";var mn=Symbol("workers-module");globalThis[mn]=Ai;Symbol.dispose||(Symbol.dispose=Symbol.for("dispose"));Symbol.asyncDispose||(Symbol.asyncDispose=Symbol.for("asyncDispose"));Promise.withResolvers||(Promise.withResolvers=function(){let t,e;return{promise:new Promise((n,s)=>{t=n,e=s}),resolve:t,reject:e}});var be=globalThis[mn],gt=be?be.RpcTarget:class{},Pi=(async function(){}).constructor,ki=typeof Buffer<"u"?Buffer.prototype:void 0;function qe(t){switch(typeof t){case"boolean":case"number":case"string":return"primitive";case"undefined":return"undefined";case"object":case"function":break;case"bigint":return"bigint";default:return"unsupported"}if(t===null)return"primitive";let e=Object.getPrototypeOf(t);switch(e){case Object.prototype:return"object";case Function.prototype:case Pi.prototype:return"function";case Array.prototype:return"array";case Date.prototype:return"date";case Uint8Array.prototype:case ki:return"bytes";case WritableStream.prototype:return"writable";case ReadableStream.prototype:return"readable";case Headers.prototype:return"headers";case Request.prototype:return"request";case Response.prototype:return"response";case Blob.prototype:return"blob";case re.prototype:return"stub";case A.prototype:return"rpc-promise";default:if(be){if(e==be.RpcStub.prototype||t instanceof be.ServiceStub)return"rpc-target";if(e==be.RpcPromise.prototype||e==be.RpcProperty.prototype)return"rpc-thenable"}return t instanceof gt?"rpc-target":t instanceof Error?"error":"unsupported"}}a(qe,"typeForRpc");function dn(){throw new Error("RPC map() implementation was not loaded.")}a(dn,"mapNotLoaded");var yt={applyMap:dn,sendMap:dn};function Zt(){throw new Error("Stream implementation was not loaded.")}a(Zt,"streamNotLoaded");var L={createWritableStreamHook:Zt,createWritableStreamFromHook:Zt,createReadableStreamHook:Zt},he=class{static{a(this,"StubHook")}stream(t,e){let n=this.call(t,e).pull(),s;return n instanceof Promise?s=n.then(i=>{i.dispose()}):(n.dispose(),s=Promise.resolve()),{promise:s}}},$=class extends he{static{a(this,"ErrorStubHook")}constructor(t){super(),this.error=t}call(t,e){return this}map(t,e,r){return this}get(t){return this}dup(){return this}pull(){return Promise.reject(this.error)}ignoreUnhandledRejections(){}dispose(){}onBroken(t){try{t(this.error)}catch(e){Promise.resolve(e)}}},Ni=new $(new Error("Attempted to use RPC stub after it has been disposed.")),mt=a((t,e,r)=>t.call(e,r),"doCall");function Di(t,e){let r=mt;mt=t;try{return e()}finally{mt=r}}a(Di,"withCallInterceptor");var X=Symbol("realStub"),Li={apply(t,e,r){let n=t.raw;return new A(mt(n.hook,n.pathIfPromise||[],M.fromAppParams(r)),[])},get(t,e,r){let n=t.raw;return e===X?n:e in A.prototype?n[e]:typeof e=="string"?new A(n.hook,n.pathIfPromise?[...n.pathIfPromise,e]:[e]):e===Symbol.dispose&&(!n.pathIfPromise||n.pathIfPromise.length==0)?()=>{n.hook.dispose(),n.hook=Ni}:void 0},has(t,e){let r=t.raw;return e===X?!0:e in A.prototype?e in r:typeof e=="string"?!0:e===Symbol.dispose&&(!r.pathIfPromise||r.pathIfPromise.length==0)},construct(t,e){throw new Error("An RPC stub cannot be used as a constructor.")},defineProperty(t,e,r){throw new Error("Can\'t define properties on RPC stubs.")},deleteProperty(t,e){throw new Error("Can\'t delete properties on RPC stubs.")},getOwnPropertyDescriptor(t,e){},getPrototypeOf(t){return Object.getPrototypeOf(t.raw)},isExtensible(t){return!1},ownKeys(t){return[]},preventExtensions(t){return!0},set(t,e,r,n){throw new Error("Can\'t assign properties on RPC stubs.")},setPrototypeOf(t,e){throw new Error("Can\'t override prototype of RPC stubs.")}},re=class rr extends gt{static{a(this,"_RpcStub")}constructor(e,r){if(super(),!(e instanceof he)){let s=e;if(s instanceof gt||s instanceof Function?e=Ge.create(s,void 0):e=new K(M.fromAppReturn(s)),r)throw new TypeError("RpcStub constructor expected one argument, received two.")}this.hook=e,this.pathIfPromise=r;let n=a(()=>{},"func");return n.raw=this,new Proxy(n,Li)}hook;pathIfPromise;dup(){let e=this[X];return e.pathIfPromise?new rr(e.hook.get(e.pathIfPromise)):new rr(e.hook.dup())}onRpcBroken(e){this[X].hook.onBroken(e)}map(e){let{hook:r,pathIfPromise:n}=this[X];return yt.sendMap(r,n||[],e)}toString(){return"[object RpcStub]"}},A=class extends re{static{a(this,"RpcPromise")}constructor(t,e){super(t,e)}then(t,e){return er(this).then(...arguments)}catch(t){return er(this).catch(...arguments)}finally(t){return er(this).finally(...arguments)}toString(){return"[object RpcPromise]"}};function Mi(t){let{hook:e,pathIfPromise:r}=t[X];return r&&r.length>0?e.get(r):e}a(Mi,"unwrapStubTakingOwnership");function Ui(t){let{hook:e,pathIfPromise:r}=t[X];return r?e.get(r):e.dup()}a(Ui,"unwrapStubAndDup");function nr(t){let{hook:e,pathIfPromise:r}=t[X];if(!(r&&r.length>0))return e}a(nr,"unwrapStubNoProperties");function hn(t){return t[X].hook}a(hn,"unwrapStubOrParent");function wt(t){return t[X]}a(wt,"unwrapStubAndPath");async function er(t){let{hook:e,pathIfPromise:r}=t[X];return r.length>0&&(e=e.get(r)),(await e.pull()).deliverResolve()}a(er,"pullPromise");var M=class q{static{a(this,"_RpcPayload")}constructor(e,r,n,s){this.value=e,this.source=r,this.hooks=n,this.promises=s}static fromAppParams(e){return new q(e,"params")}static fromAppReturn(e){return new q(e,"return")}static fromArray(e){let r=[],n=[],s=[];for(let i of e){i.ensureDeepCopied();for(let o of i.hooks)r.push(o);for(let o of i.promises)o.parent===i&&(o={parent:s,property:s.length,promise:o.promise}),n.push(o);s.push(i.value)}return new q(s,"owned",r,n)}static forEvaluate(e,r){return new q(null,"owned",e,r)}static deepCopyFrom(e,r,n){let s=new q(null,"owned",[],[]);return s.value=s.deepCopy(e,r,"value",s,!0,n),s}rpcTargets;getHookForRpcTarget(e,r,n=!0){if(this.source==="params"){if(n){let s=e;typeof s.dup=="function"&&(e=s.dup())}return Ge.create(e,r)}else if(this.source==="return"){let s=this.rpcTargets?.get(e);return s?n?s.dup():(this.rpcTargets?.delete(e),s):(s=Ge.create(e,r),n?(this.rpcTargets||(this.rpcTargets=new Map),this.rpcTargets.set(e,s),s.dup()):s)}else throw new Error("owned payload shouldn\'t contain raw RpcTargets")}getHookForWritableStream(e,r,n=!0){if(this.source==="params")return L.createWritableStreamHook(e);if(this.source==="return"){let s=this.rpcTargets?.get(e);return s?n?s.dup():(this.rpcTargets?.delete(e),s):(s=L.createWritableStreamHook(e),n?(this.rpcTargets||(this.rpcTargets=new Map),this.rpcTargets.set(e,s),s.dup()):s)}else throw new Error("owned payload shouldn\'t contain raw WritableStreams")}getHookForReadableStream(e,r,n=!0){if(this.source==="params")return L.createReadableStreamHook(e);if(this.source==="return"){let s=this.rpcTargets?.get(e);return s?n?s.dup():(this.rpcTargets?.delete(e),s):(s=L.createReadableStreamHook(e),n?(this.rpcTargets||(this.rpcTargets=new Map),this.rpcTargets.set(e,s),s.dup()):s)}else throw new Error("owned payload shouldn\'t contain raw ReadableStreams")}deepCopy(e,r,n,s,i,o){switch(qe(e)){case"unsupported":return e;case"primitive":case"bigint":case"date":case"bytes":case"blob":case"error":case"undefined":return e;case"array":{let u=e,l=u.length,d=new Array(l);for(let p=0;p<l;p++)d[p]=this.deepCopy(u[p],u,p,d,i,o);return d}case"object":{let u={},l=e;for(let d in l)u[d]=this.deepCopy(l[d],l,d,u,i,o);return u}case"stub":case"rpc-promise":{let u=e,l;if(i?l=Ui(u):l=Mi(u),u instanceof A){let d=new A(l,[]);return this.promises.push({parent:s,property:n,promise:d}),d}else return this.hooks.push(l),new re(l)}case"function":case"rpc-target":{let u=e,l;return o?l=o.getHookForRpcTarget(u,r,i):l=Ge.create(u,r),this.hooks.push(l),new re(l)}case"rpc-thenable":{let u=e,l;return o?l=new A(o.getHookForRpcTarget(u,r,i),[]):l=new A(Ge.create(u,r),[]),this.promises.push({parent:s,property:n,promise:l}),l}case"writable":{let u=e,l;return o?l=o.getHookForWritableStream(u,r,i):l=L.createWritableStreamHook(u),this.hooks.push(l),u}case"readable":{let u=e,l;return o?l=o.getHookForReadableStream(u,r,i):l=L.createReadableStreamHook(u),this.hooks.push(l),u}case"headers":return new Headers(e);case"request":{let u=e;return u.body&&this.deepCopy(u.body,u,"body",u,i,o),new Request(u)}case"response":{let u=e;return u.body&&this.deepCopy(u.body,u,"body",u,i,o),new Response(u.body,u)}default:throw new Error("unreachable")}}ensureDeepCopied(){if(this.source!=="owned"){let e=this.source==="params";this.hooks=[],this.promises=[];try{this.value=this.deepCopy(this.value,void 0,"value",this,e,this)}catch(r){throw this.hooks=void 0,this.promises=void 0,r}if(this.source="owned",this.rpcTargets&&this.rpcTargets.size>0)throw new Error("Not all rpcTargets were accounted for in deep-copy?");this.rpcTargets=void 0}}deliverTo(e,r,n){if(this.ensureDeepCopied(),this.value instanceof A)q.deliverRpcPromiseTo(this.value,e,r,n);else{e[r]=this.value;for(let s of this.promises)q.deliverRpcPromiseTo(s.promise,s.parent,s.property,n)}}static deliverRpcPromiseTo(e,r,n,s){let i=nr(e);if(!i)throw new Error("property promises should have been resolved earlier");let o=i.pull();o instanceof q?o.deliverTo(r,n,s):s.push(o.then(c=>{let u=[];if(c.deliverTo(r,n,u),u.length>0)return Promise.all(u)}))}async deliverCall(e,r){try{let n=[];this.deliverTo(this,"value",n),n.length>0&&await Promise.all(n);let s=Function.prototype.apply.call(e,r,this.value);return s instanceof A?q.fromAppReturn(s):q.fromAppReturn(await s)}finally{this.dispose()}}async deliverResolve(){try{let e=[];this.deliverTo(this,"value",e),e.length>0&&await Promise.all(e);let r=this.value;return r instanceof Object&&(Symbol.dispose in r||Object.defineProperty(r,Symbol.dispose,{value:a(()=>this.dispose(),"value"),writable:!0,enumerable:!1,configurable:!0})),r}catch(e){throw this.dispose(),e}}dispose(){if(this.source==="owned")this.hooks.forEach(e=>e.dispose()),this.promises.forEach(e=>e.promise[Symbol.dispose]());else if(this.source==="return"&&(this.disposeImpl(this.value,void 0),this.rpcTargets&&this.rpcTargets.size>0))throw new Error("Not all rpcTargets were accounted for in disposeImpl()?");this.source="owned",this.hooks=[],this.promises=[]}disposeImpl(e,r){switch(qe(e)){case"unsupported":case"primitive":case"bigint":case"bytes":case"blob":case"date":case"error":case"undefined":return;case"array":{let s=e,i=s.length;for(let o=0;o<i;o++)this.disposeImpl(s[o],s);return}case"object":{let s=e;for(let i in s)this.disposeImpl(s[i],s);return}case"stub":case"rpc-promise":{let i=nr(e);i&&i.dispose();return}case"function":case"rpc-target":{let s=e,i=this.rpcTargets?.get(s);i?(i.dispose(),this.rpcTargets.delete(s)):yn(s);return}case"rpc-thenable":return;case"headers":return;case"request":{let s=e;s.body&&this.disposeImpl(s.body,s);return}case"response":{let s=e;s.body&&this.disposeImpl(s.body,s);return}case"writable":{let s=e,i=this.rpcTargets?.get(s);i?this.rpcTargets.delete(s):i=L.createWritableStreamHook(s),i.dispose();return}case"readable":{let s=e,i=this.rpcTargets?.get(s);i?this.rpcTargets.delete(s):i=L.createReadableStreamHook(s),i.dispose();return}default:return}}ignoreUnhandledRejections(){this.hooks?(this.hooks.forEach(e=>{e.ignoreUnhandledRejections()}),this.promises.forEach(e=>hn(e.promise).ignoreUnhandledRejections())):this.ignoreUnhandledRejectionsImpl(this.value)}ignoreUnhandledRejectionsImpl(e){switch(qe(e)){case"unsupported":case"primitive":case"bigint":case"bytes":case"blob":case"date":case"error":case"undefined":case"function":case"rpc-target":case"writable":case"readable":case"headers":case"request":case"response":return;case"array":{let n=e,s=n.length;for(let i=0;i<s;i++)this.ignoreUnhandledRejectionsImpl(n[i]);return}case"object":{let n=e;for(let s in n)this.ignoreUnhandledRejectionsImpl(n[s]);return}case"stub":case"rpc-promise":hn(e).ignoreUnhandledRejections();return;case"rpc-thenable":e.then(n=>{},n=>{});return;default:return}}};function tr(t,e,r,n){for(let s=0;s<r.length;s++){e=t;let i=r[s];if(i in Object.prototype){t=void 0;continue}switch(qe(t)){case"object":case"function":Object.hasOwn(t,i)?t=t[i]:t=void 0;break;case"array":Number.isInteger(i)&&i>=0?t=t[i]:t=void 0;break;case"rpc-target":case"rpc-thenable":{if(Object.hasOwn(t,i))throw new TypeError(`Attempted to access property \'${i}\', which is an instance property of the RpcTarget. To avoid leaking private internals, instance properties cannot be accessed over RPC. If you want to make this property available over RPC, define it as a method or getter on the class, instead of an instance property.`);t=t[i],n=null;break}case"stub":case"rpc-promise":{let{hook:c,pathIfPromise:u}=wt(t);return{hook:c,remainingPath:u?u.concat(r.slice(s)):r.slice(s)}}case"writable":t=void 0;break;case"readable":t=void 0;break;case"primitive":case"bigint":case"bytes":case"blob":case"date":case"error":case"headers":case"request":case"response":t=void 0;break;case"undefined":t=t[i];break;case"unsupported":{if(s===0)throw new TypeError("RPC stub points at a non-serializable type.");{let c=r.slice(0,s).join("."),u=r.slice(0,s).join(".");throw new TypeError(`\'${c}\' is not a serializable type, so property ${u} cannot be accessed.`)}}default:throw new TypeError("unreachable")}}if(t instanceof A){let{hook:s,pathIfPromise:i}=wt(t);return{hook:s,remainingPath:i||[]}}return{value:t,parent:e,owner:n}}a(tr,"followPath");var gn=class extends he{static{a(this,"ValueStubHook")}call(t,e){try{let{value:r,owner:n}=this.getValue(),s=tr(r,void 0,t,n);if(s.hook)return s.hook.call(s.remainingPath,e);if(typeof s.value!="function")throw new TypeError(`\'${t.join(".")}\' is not a function.`);let i=e.deliverCall(s.value,s.parent);return new Et(i.then(o=>new K(o)))}catch(r){return new $(r)}}map(t,e,r){try{let n;try{let{value:s,owner:i}=this.getValue();n=tr(s,void 0,t,i)}catch(s){for(let i of e)i.dispose();throw s}return n.hook?n.hook.map(n.remainingPath,e,r):yt.applyMap(n.value,n.parent,n.owner,e,r)}catch(n){return new $(n)}}get(t){try{let{value:e,owner:r}=this.getValue();if(t.length===0&&r===null)throw new Error("Can\'t dup an RpcTarget stub as a promise.");let n=tr(e,void 0,t,r);return n.hook?n.hook.get(n.remainingPath):new K(M.deepCopyFrom(n.value,n.parent,n.owner))}catch(e){return new $(e)}}},K=class wn extends gn{static{a(this,"_PayloadStubHook")}constructor(e){super(),this.payload=e}payload;getPayload(){if(this.payload)return this.payload;throw new Error("Attempted to use an RPC StubHook after it was disposed.")}getValue(){let e=this.getPayload();return{value:e.value,owner:e}}dup(){let e=this.getPayload();return new wn(M.deepCopyFrom(e.value,void 0,e))}pull(){return this.getPayload()}ignoreUnhandledRejections(){this.payload&&this.payload.ignoreUnhandledRejections()}dispose(){this.payload&&(this.payload.dispose(),this.payload=void 0)}onBroken(e){this.payload&&this.payload.value instanceof re&&this.payload.value.onRpcBroken(e)}};function yn(t){if(Symbol.dispose in t)try{t[Symbol.dispose]()}catch(e){Promise.reject(e)}}a(yn,"disposeRpcTarget");var Ge=class sr extends gn{static{a(this,"_TargetStubHook")}static create(e,r){return typeof e!="function"&&(r=void 0),new sr(e,r)}constructor(e,r,n){super(),this.target=e,this.parent=r,n?n.refcount&&(this.refcount=n.refcount,++this.refcount.count):Symbol.dispose in e&&(this.refcount={count:1})}target;parent;refcount;getTarget(){if(this.target)return this.target;throw new Error("Attempted to use an RPC StubHook after it was disposed.")}getValue(){return{value:this.getTarget(),owner:null}}dup(){return new sr(this.getTarget(),this.parent,this)}pull(){let e=this.getTarget();return"then"in e?Promise.resolve(e).then(r=>M.fromAppReturn(r)):Promise.reject(new Error("Tried to resolve a non-promise stub."))}ignoreUnhandledRejections(){}dispose(){this.target&&(this.refcount&&--this.refcount.count==0&&yn(this.target),this.target=void 0)}onBroken(e){}},Et=class Ve extends he{static{a(this,"_PromiseStubHook")}promise;resolution;constructor(e){super(),this.promise=e.then(r=>(this.resolution=r,r))}call(e,r){return r.ensureDeepCopied(),new Ve(this.promise.then(n=>n.call(e,r)))}stream(e,r){return r.ensureDeepCopied(),{promise:this.promise.then(s=>s.stream(e,r).promise)}}map(e,r,n){return new Ve(this.promise.then(s=>s.map(e,r,n),s=>{for(let i of r)i.dispose();throw s}))}get(e){return new Ve(this.promise.then(r=>r.get(e)))}dup(){return this.resolution?this.resolution.dup():new Ve(this.promise.then(e=>e.dup()))}pull(){return this.resolution?this.resolution.pull():this.promise.then(e=>e.pull())}ignoreUnhandledRejections(){this.resolution?this.resolution.ignoreUnhandledRejections():this.promise.then(e=>{e.ignoreUnhandledRejections()},e=>{})}dispose(){this.resolution?this.resolution.dispose():this.promise.then(e=>{e.dispose()},e=>{})}onBroken(e){this.resolution?this.resolution.onBroken(e):this.promise.then(r=>{r.onBroken(e)},e)}},Fi=class{static{a(this,"NullExporter")}exportStub(t){throw new Error("Cannot serialize RPC stubs without an RPC session.")}exportPromise(t){throw new Error("Cannot serialize RPC stubs without an RPC session.")}getImport(t){}unexport(t){}createPipe(t){throw new Error("Cannot create pipes without an RPC session.")}onSendError(t){}},Bi=new Fi;async function $i(t,e){let r=await new Response(t).blob();return r.type===e?r:r.slice(0,r.size,e)}a($i,"streamToBlob");var Hi={Error,EvalError,RangeError,ReferenceError,SyntaxError,TypeError,URIError,AggregateError},le=class En{static{a(this,"_Devaluator")}constructor(e,r){this.exporter=e,this.source=r}static devaluate(e,r,n=Bi,s){let i=new En(n,s);try{return i.devaluateImpl(e,r,0)}catch(o){if(i.exports)try{n.unexport(i.exports)}catch{}throw o}}exports;devaluateImpl(e,r,n){if(n>=64)throw new Error("Serialization exceeded maximum allowed depth. (Does the message contain cycles?)");switch(qe(e)){case"unsupported":{let i;try{i=`Cannot serialize value: ${e}`}catch{i="Cannot serialize value: (couldn\'t stringify value)"}throw new TypeError(i)}case"primitive":return typeof e=="number"&&!isFinite(e)?e===1/0?["inf"]:e===-1/0?["-inf"]:["nan"]:e;case"object":{let i=e,o={};for(let c in i)o[c]=this.devaluateImpl(i[c],i,n+1);return o}case"array":{let i=e,o=i.length,c=new Array(o);for(let u=0;u<o;u++)c[u]=this.devaluateImpl(i[u],i,n+1);return[c]}case"bigint":return["bigint",e.toString()];case"date":{let i=e.getTime();return["date",Number.isNaN(i)?null:i]}case"bytes":{let i=e;if(i.toBase64)return["bytes",i.toBase64({omitPadding:!0})];let o;if(typeof Buffer<"u")o=(i instanceof Buffer?i:Buffer.from(i.buffer,i.byteOffset,i.byteLength)).toString("base64");else{let c="";for(let u=0;u<i.length;u++)c+=String.fromCharCode(i[u]);o=btoa(c)}return["bytes",o.replace(/=+$/,"")]}case"headers":return["headers",[...e]];case"request":{let i=e,o={};i.method!=="GET"&&(o.method=i.method);let c=[...i.headers];if(c.length>0&&(o.headers=c),i.body)o.body=this.devaluateImpl(i.body,i,n+1),o.duplex=i.duplex||"half";else if(i.body===void 0&&!["GET","HEAD","OPTIONS","TRACE","DELETE"].includes(i.method)){let l=i.arrayBuffer(),d=new ReadableStream({async start(m){try{m.enqueue(new Uint8Array(await l)),m.close()}catch(f){m.error(f)}}}),p=L.createReadableStreamHook(d),g=this.exporter.createPipe(d,p);o.body=["readable",g],o.duplex=i.duplex||"half"}i.cache&&i.cache!=="default"&&(o.cache=i.cache),i.redirect!=="follow"&&(o.redirect=i.redirect),i.integrity&&(o.integrity=i.integrity),i.mode&&i.mode!=="cors"&&(o.mode=i.mode),i.credentials&&i.credentials!=="same-origin"&&(o.credentials=i.credentials),i.referrer&&i.referrer!=="about:client"&&(o.referrer=i.referrer),i.referrerPolicy&&(o.referrerPolicy=i.referrerPolicy),i.keepalive&&(o.keepalive=i.keepalive);let u=i;return u.cf&&(o.cf=u.cf),u.encodeResponseBody&&u.encodeResponseBody!=="automatic"&&(o.encodeResponseBody=u.encodeResponseBody),["request",i.url,o]}case"response":{let i=e,o=this.devaluateImpl(i.body,i,n+1),c={};i.status!==200&&(c.status=i.status),i.statusText&&(c.statusText=i.statusText);let u=[...i.headers];u.length>0&&(c.headers=u);let l=i;if(l.cf&&(c.cf=l.cf),l.encodeBody&&l.encodeBody!=="automatic"&&(c.encodeBody=l.encodeBody),l.webSocket)throw new TypeError("Can\'t serialize a Response containing a webSocket.");return["response",o,c]}case"blob":{let i=e,o=i.stream(),c=L.createReadableStreamHook(o),u=this.exporter.createPipe(o,c);return["blob",i.type,["readable",u]]}case"error":{let i=e,o=this.exporter.onSendError(i);o&&(i=o);let c=i,u,l=a((p,g)=>{let m=this.exports?.length??0;try{let f=this.devaluateImpl(g,i,n+1);u||(u={}),u[p]=f}catch{if(this.exports&&this.exports.length>m){let w=this.exports.splice(m);try{this.exporter.unexport(w)}catch{}}}},"captureProp");for(let p of Object.keys(i))p==="name"||p==="message"||p==="stack"||l(p,c[p]);"cause"in i&&l("cause",c.cause),i instanceof AggregateError&&l("errors",i.errors);let d=["error",i.name,i.message];return u?(d.push(o&&o.stack?o.stack:null),d.push(u)):o&&o.stack&&d.push(o.stack),d}case"undefined":return["undefined"];case"stub":case"rpc-promise":{if(!this.source)throw new Error("Can\'t serialize RPC stubs in this context.");let{hook:i,pathIfPromise:o}=wt(e),c=this.exporter.getImport(i);return c!==void 0?o?o.length>0?["pipeline",c,o]:["pipeline",c]:["import",c]:(o?i=i.get(o):i=i.dup(),this.devaluateHook(o?"promise":"export",i))}case"function":case"rpc-target":{if(!this.source)throw new Error("Can\'t serialize RPC stubs in this context.");let i=this.source.getHookForRpcTarget(e,r);return this.devaluateHook("export",i)}case"rpc-thenable":{if(!this.source)throw new Error("Can\'t serialize RPC stubs in this context.");let i=this.source.getHookForRpcTarget(e,r);return this.devaluateHook("promise",i)}case"writable":{if(!this.source)throw new Error("Can\'t serialize WritableStream in this context.");let i=this.source.getHookForWritableStream(e,r);return this.devaluateHook("writable",i)}case"readable":{if(!this.source)throw new Error("Can\'t serialize ReadableStream in this context.");let i=e,o=this.source.getHookForReadableStream(i,r);return["readable",this.exporter.createPipe(i,o)]}default:throw new Error("unreachable")}}devaluateHook(e,r){this.exports||(this.exports=[]);let n=e==="promise"?this.exporter.exportPromise(r):this.exporter.exportStub(r);return this.exports.push(n),[e,n]}};var Wi=class{static{a(this,"NullImporter")}importStub(t){throw new Error("Cannot deserialize RPC stubs without an RPC session.")}importPromise(t){throw new Error("Cannot deserialize RPC stubs without an RPC session.")}getExport(t){}getPipeReadable(t){throw new Error("Cannot retrieve pipe readable without an RPC session.")}},Ul=new Wi;function Ki(t,e){let r=new Response(e).arrayBuffer().then(n=>{let s=new Uint8Array(n),i=new Request(t,{body:s});return new K(M.fromAppReturn(i))});return new A(new Et(r),[])}a(Ki,"fixBrokenRequestBody");function ji(t,e){let r=$i(t,e).then(n=>new K(M.fromAppReturn(n)));return new A(new Et(r),[])}a(ji,"streamToBlobPromise");var de=class Sn{static{a(this,"_Evaluator")}constructor(e){this.importer=e}hooks=[];promises=[];evaluate(e){let r=M.forEvaluate(this.hooks,this.promises);try{return r.value=this.evaluateImpl(e,r,"value"),r}catch(n){throw r.dispose(),n}}evaluateCopy(e){return this.evaluate(structuredClone(e))}evaluateImpl(e,r,n){if(e instanceof Array){if(e.length==1&&e[0]instanceof Array){let s=e[0];for(let i=0;i<s.length;i++)s[i]=this.evaluateImpl(s[i],s,i);return s}else switch(e[0]){case"bigint":if(typeof e[1]=="string")return BigInt(e[1]);break;case"date":if(e[1]===null)return new Date(NaN);if(typeof e[1]=="number")return new Date(e[1]);break;case"bytes":{if(typeof e[1]=="string"){if(typeof Buffer<"u")return Buffer.from(e[1],"base64");if(Uint8Array.fromBase64)return Uint8Array.fromBase64(e[1]);{let s=atob(e[1]),i=s.length,o=new Uint8Array(i);for(let c=0;c<i;c++)o[c]=s.charCodeAt(c);return o}}break}case"error":if(e.length>=3&&typeof e[1]=="string"&&typeof e[2]=="string"){let s=Hi[e[1]]||Error,i=s===AggregateError?new s([],e[2]):new s(e[2]);if(typeof e[3]=="string"&&(i.stack=e[3]),e.length>=5){let o=e[4];if(!o||typeof o!="object"||Array.isArray(o))break;let c=i,u=o;for(let l of Object.keys(u))l==="name"||l==="message"||l==="stack"||(c[l]=this.evaluateImpl(u[l],i,l))}return i}break;case"undefined":if(e.length===1)return;break;case"inf":return 1/0;case"-inf":return-1/0;case"nan":return NaN;case"headers":if(e.length===2&&e[1]instanceof Array)return new Headers(e[1]);break;case"request":{if(e.length!==3||typeof e[1]!="string")break;let s=e[1],i=e[2];if(typeof i!="object"||i===null)break;if(i.body&&(i.body=this.evaluateImpl(i.body,i,"body"),!(i.body===null||typeof i.body=="string"||i.body instanceof Uint8Array||i.body instanceof ReadableStream)))throw new TypeError("Request body must be of type ReadableStream.");if(i.signal&&(i.signal=this.evaluateImpl(i.signal,i,"signal"),!(i.signal instanceof AbortSignal)))throw new TypeError("Request siganl must be of type AbortSignal.");if(i.headers&&!(i.headers instanceof Array))throw new TypeError("Request headers must be serialized as an array of pairs.");let o=new Request(s,i);if(i.body instanceof ReadableStream&&o.body===void 0){let c=Ki(o,i.body);return this.promises.push({promise:c,parent:r,property:n}),c}else return o}case"response":{if(e.length!==3)break;let s=this.evaluateImpl(e[1],r,n);if(!(s===null||typeof s=="string"||s instanceof Uint8Array||s instanceof ReadableStream))throw new TypeError("Response body must be of type ReadableStream.");let i=e[2];if(typeof i!="object"||i===null)break;if(i.webSocket)throw new TypeError("Can\'t deserialize a Response containing a webSocket.");if(i.headers&&!(i.headers instanceof Array))throw new TypeError("Request headers must be serialized as an array of pairs.");return new Response(s,i)}case"blob":{if(e.length!==3||typeof e[1]!="string")break;let s=e[1],i=this.evaluateImpl(e[2],r,n);if(!(i instanceof ReadableStream))throw new TypeError("Blob content must be serialized as a ReadableStream.");let o=ji(i,s);return this.promises.push({promise:o,parent:r,property:n}),o}case"import":case"pipeline":{if(e.length<2||e.length>4||typeof e[1]!="number")break;let s=this.importer.getExport(e[1]);if(!s)throw new Error(`no such entry on exports table: ${e[1]}`);let i=e[0]=="pipeline",o=a(d=>{if(i){let p=new A(d,[]);return this.promises.push({promise:p,parent:r,property:n}),p}else return this.hooks.push(d),new A(d,[])},"addStub");if(e.length==2)return o(i?s.get([]):s.dup());let c=e[2];if(!(c instanceof Array)||!c.every(d=>typeof d=="string"||typeof d=="number"))break;if(e.length==3)return o(s.get(c));let u=e[3];if(!(u instanceof Array))break;return u=new Sn(this.importer).evaluate([u]),o(s.call(c,u))}case"remap":{if(e.length!==5||typeof e[1]!="number"||!(e[2]instanceof Array)||!(e[3]instanceof Array)||!(e[4]instanceof Array))break;let s=this.importer.getExport(e[1]);if(!s)throw new Error(`no such entry on exports table: ${e[1]}`);let i=e[2];if(!i.every(d=>typeof d=="string"||typeof d=="number"))break;let o=e[3].map(d=>{if(!(d instanceof Array)||d.length!==2||d[0]!=="import"&&d[0]!=="export"||typeof d[1]!="number")throw new TypeError(`unknown map capture: ${JSON.stringify(d)}`);if(d[0]==="export")return this.importer.importStub(d[1]);{let p=this.importer.getExport(d[1]);if(!p)throw new Error(`no such entry on exports table: ${d[1]}`);return p.dup()}}),c=e[4],u=s.map(i,o,c),l=new A(u,[]);return this.promises.push({promise:l,parent:r,property:n}),l}case"export":case"promise":if(typeof e[1]=="number")if(e[0]=="promise"){let s=this.importer.importPromise(e[1]),i=new A(s,[]);return this.promises.push({parent:r,property:n,promise:i}),i}else{let s=this.importer.importStub(e[1]);return this.hooks.push(s),new re(s)}break;case"writable":if(typeof e[1]=="number"){let s=this.importer.importStub(e[1]),i=L.createWritableStreamFromHook(s);return this.hooks.push(s),i}break;case"readable":if(typeof e[1]=="number"){let s=this.importer.getPipeReadable(e[1]),i=L.createReadableStreamHook(s);return this.hooks.push(i),s}break}throw new TypeError(`unknown special value: ${JSON.stringify(e)}`)}else if(e instanceof Object){let s=e;for(let i in s)i in Object.prototype||i==="toJSON"?(this.evaluateImpl(s[i],s,i),delete s[i]):s[i]=this.evaluateImpl(s[i],s,i);return s}else return e}};var Ee=class{static{a(this,"ImportTableEntry")}constructor(t,e,r){this.session=t,this.importId=e,r&&(this.activePull=Promise.withResolvers())}localRefcount=0;remoteRefcount=1;activePull;resolution;onBrokenRegistrations;resolve(t){if(this.localRefcount==0){t.dispose();return}if(this.resolution=t,this.sendRelease(),this.onBrokenRegistrations){for(let e of this.onBrokenRegistrations){let r=this.session.onBrokenCallbacks[e],n=this.session.onBrokenCallbacks.length;t.onBroken(r),this.session.onBrokenCallbacks[n]===r?delete this.session.onBrokenCallbacks[n]:delete this.session.onBrokenCallbacks[e]}this.onBrokenRegistrations=void 0}this.activePull&&(this.activePull.resolve(),this.activePull=void 0)}async awaitResolution(){return this.activePull||(this.session.sendPull(this.importId),this.activePull=Promise.withResolvers()),await this.activePull.promise,this.resolution.pull()}dispose(){this.resolution?this.resolution.dispose():(this.abort(new Error("RPC was canceled because the RpcPromise was disposed.")),this.sendRelease())}abort(t){this.resolution||(this.resolution=new $(t),this.activePull&&(this.activePull.reject(t),this.activePull=void 0),this.onBrokenRegistrations=void 0)}onBroken(t){if(this.resolution)this.resolution.onBroken(t);else{let e=this.session.onBrokenCallbacks.length;this.session.onBrokenCallbacks.push(t),this.onBrokenRegistrations||(this.onBrokenRegistrations=[]),this.onBrokenRegistrations.push(e)}}sendRelease(){this.remoteRefcount>0&&(this.session.sendRelease(this.importId,this.remoteRefcount),this.remoteRefcount=0)}},Se=class bn extends he{static{a(this,"_RpcImportHook")}constructor(e,r){super(),this.isPromise=e,++r.localRefcount,this.entry=r}entry;collectPath(e){return this}getEntry(){if(this.entry)return this.entry;throw new Error("This RpcImportHook was already disposed.")}call(e,r){let n=this.getEntry();return n.resolution?n.resolution.call(e,r):n.session.sendCall(n.importId,e,r)}stream(e,r){let n=this.getEntry();return n.resolution?n.resolution.stream(e,r):n.session.sendStream(n.importId,e,r)}map(e,r,n){let s;try{s=this.getEntry()}catch(i){for(let o of r)o.dispose();throw i}return s.resolution?s.resolution.map(e,r,n):s.session.sendMap(s.importId,e,r,n)}get(e){let r=this.getEntry();return r.resolution?r.resolution.get(e):r.session.sendCall(r.importId,e)}dup(){return new bn(!1,this.getEntry())}pull(){let e=this.getEntry();if(!this.isPromise)throw new Error("Can\'t pull this hook because it\'s not a promise hook.");return e.resolution?e.resolution.pull():e.awaitResolution()}ignoreUnhandledRejections(){}dispose(){let e=this.entry;this.entry=void 0,e&&--e.localRefcount===0&&e.dispose()}onBroken(e){this.entry&&this.entry.onBroken(e)}},zi=class extends Se{static{a(this,"RpcMainHook")}session;constructor(t){super(!1,t),this.session=t.session}dispose(){if(this.session){let t=this.session;this.session=void 0,t.shutdown()}}},Gi=class{static{a(this,"RpcSessionImpl")}constructor(t,e,r){this.transport=t,this.options=r,this.exports.push({hook:e,refcount:1}),this.imports.push(new Ee(this,0,!1)),this.readLoop().catch(n=>this.abort(n))}exports=[];reverseExports=new Map;imports=[];abortReason;cancelReadLoop;nextExportId=-1;onBatchDone;pullCount=0;onBrokenCallbacks=[];getMainImport(){return new zi(this.imports[0])}shutdown(){this.abort(new Error("RPC session was shut down by disposing the main stub"),!1)}exportStub(t){if(this.abortReason)throw this.abortReason;let e=this.reverseExports.get(t);if(e!==void 0)return++this.exports[e].refcount,e;{let r=this.nextExportId--;return this.exports[r]={hook:t,refcount:1},this.reverseExports.set(t,r),r}}exportPromise(t){if(this.abortReason)throw this.abortReason;let e=this.nextExportId--;return this.exports[e]={hook:t,refcount:1},this.reverseExports.set(t,e),this.ensureResolvingExport(e),e}unexport(t){for(let e of t)this.releaseExport(e,1)}releaseExport(t,e){let r=this.exports[t];if(!r)throw new Error(`no such export ID: ${t}`);if(r.refcount<e)throw new Error(`refcount would go negative: ${r.refcount} < ${e}`);r.refcount-=e,r.refcount===0&&(delete this.exports[t],this.reverseExports.delete(r.hook),r.hook.dispose())}onSendError(t){if(this.options.onSendError)return this.options.onSendError(t)}ensureResolvingExport(t){let e=this.exports[t];if(!e)throw new Error(`no such export ID: ${t}`);if(!e.pull){let r=a(async()=>{let s=e.hook;for(;;){let i=await s.pull();if(i.value instanceof re){let{hook:o,pathIfPromise:c}=wt(i.value);if(c&&c.length==0&&this.getImport(s)===void 0){s=o;continue}}return i}},"resolve"),n=e.autoRelease;++this.pullCount,e.pull=r().then(s=>{let i=le.devaluate(s.value,void 0,this,s);this.send(["resolve",t,i]),n&&this.releaseExport(t,1)},s=>{this.send(["reject",t,le.devaluate(s,void 0,this)]),n&&this.releaseExport(t,1)}).catch(s=>{try{this.send(["reject",t,le.devaluate(s,void 0,this)]),n&&this.releaseExport(t,1)}catch(i){this.abort(i)}}).finally(()=>{--this.pullCount===0&&this.onBatchDone&&this.onBatchDone.resolve()})}}getImport(t){if(t instanceof Se&&t.entry&&t.entry.session===this)return t.entry.importId}importStub(t){if(this.abortReason)throw this.abortReason;let e=this.imports[t];return e||(e=new Ee(this,t,!1),this.imports[t]=e),new Se(!1,e)}importPromise(t){if(this.abortReason)throw this.abortReason;if(this.imports[t])return new $(new Error("Bug in RPC system: The peer sent a promise reusing an existing export ID."));let e=new Ee(this,t,!0);return this.imports[t]=e,new Se(!0,e)}getExport(t){return this.exports[t]?.hook}getPipeReadable(t){let e=this.exports[t];if(!e||!e.pipeReadable)throw new Error(`Export ${t} is not a pipe or its readable end was already consumed.`);let r=e.pipeReadable;return e.pipeReadable=void 0,r}createPipe(t,e){if(this.abortReason)throw this.abortReason;this.send(["pipe"]);let r=this.imports.length,n=new Ee(this,r,!1);this.imports.push(n);let s=new Se(!1,n),i=L.createWritableStreamFromHook(s);return t.pipeTo(i).catch(()=>{}).finally(()=>e.dispose()),r}send(t){if(this.abortReason!==void 0)return 0;let e;try{e=JSON.stringify(t)}catch(r){try{this.abort(r)}catch{}throw r}return this.transport.send(e).catch(r=>this.abort(r,!1)),e.length}sendCall(t,e,r){if(this.abortReason)throw this.abortReason;let n=["pipeline",t,e];if(r){let i=le.devaluate(r.value,void 0,this,r);n.push(i[0])}this.send(["push",n]);let s=new Ee(this,this.imports.length,!1);return this.imports.push(s),new Se(!0,s)}sendStream(t,e,r){if(this.abortReason)throw this.abortReason;let n=["pipeline",t,e],s=le.devaluate(r.value,void 0,this,r);n.push(s[0]);let i=this.send(["stream",n]),o=this.imports.length,c=new Ee(this,o,!0);return c.remoteRefcount=0,c.localRefcount=1,this.imports.push(c),{promise:c.awaitResolution().then(l=>{l.dispose(),delete this.imports[o]},l=>{throw delete this.imports[o],l}),size:i}}sendMap(t,e,r,n){if(this.abortReason){for(let c of r)c.dispose();throw this.abortReason}let s=r.map(c=>{let u=this.getImport(c);return u!==void 0?["import",u]:["export",this.exportStub(c)]}),i=["remap",t,e,s,n];this.send(["push",i]);let o=new Ee(this,this.imports.length,!1);return this.imports.push(o),new Se(!0,o)}sendPull(t){if(this.abortReason)throw this.abortReason;this.send(["pull",t])}sendRelease(t,e){this.abortReason||(this.send(["release",t,e]),delete this.imports[t])}abort(t,e=!0){if(this.abortReason===void 0){if(this.cancelReadLoop?.(t),this.cancelReadLoop=void 0,e)try{this.transport.send(JSON.stringify(["abort",le.devaluate(t,void 0,this)])).catch(r=>{})}catch{}if(t===void 0&&(t="undefined"),this.abortReason=t,this.onBatchDone&&this.onBatchDone.reject(t),this.transport.abort)try{this.transport.abort(t)}catch(r){Promise.resolve(r)}for(let r in this.onBrokenCallbacks)try{this.onBrokenCallbacks[r](t)}catch(n){Promise.resolve(n)}for(let r in this.imports)this.imports[r].abort(t);for(let r in this.exports)this.exports[r].hook.dispose()}}async readLoop(){for(;!this.abortReason;){let t=Promise.withResolvers();this.cancelReadLoop=t.reject;let e;try{e=await Promise.race([this.transport.receive(),t.promise])}finally{this.cancelReadLoop===t.reject&&(this.cancelReadLoop=void 0)}let r=JSON.parse(e);if(this.abortReason)break;if(r instanceof Array)switch(r[0]){case"push":if(r.length>1){let n=new de(this).evaluate(r[1]),s=new K(n);s.ignoreUnhandledRejections(),this.exports.push({hook:s,refcount:1});continue}break;case"stream":{if(r.length>1){let n=new de(this).evaluate(r[1]),s=new K(n);s.ignoreUnhandledRejections();let i=this.exports.length;this.exports.push({hook:s,refcount:1,autoRelease:!0}),this.ensureResolvingExport(i);continue}break}case"pipe":{let{readable:n,writable:s}=new TransformStream,i=L.createWritableStreamHook(s);this.exports.push({hook:i,refcount:1,pipeReadable:n});continue}case"pull":{let n=r[1];if(typeof n=="number"){this.ensureResolvingExport(n);continue}break}case"resolve":case"reject":{let n=r[1];if(typeof n=="number"&&r.length>2){let s=this.imports[n];if(s)if(r[0]=="resolve")s.resolve(new K(new de(this).evaluate(r[2])));else{let i=new de(this).evaluate(r[2]);i.dispose(),s.resolve(new $(i.value))}else r[0]=="resolve"&&new de(this).evaluate(r[2]).dispose();continue}break}case"release":{let n=r[1],s=r[2];if(typeof n=="number"&&typeof s=="number"){this.releaseExport(n,s);continue}break}case"abort":{let n=new de(this).evaluate(r[1]);n.dispose(),this.abort(n,!1);break}}throw new Error(`bad RPC message: ${JSON.stringify(r)}`)}}async drain(){if(this.abortReason)throw this.abortReason;if(this.pullCount>0){let{promise:t,resolve:e,reject:r}=Promise.withResolvers();this.onBatchDone={resolve:e,reject:r},await t}}getStats(){let t={imports:0,exports:0};for(let e in this.imports)++t.imports;for(let e in this.exports)++t.exports;return t}},Vi=class{static{a(this,"RpcSession")}#e;#t;constructor(t,e,r={}){let n;e?n=new K(M.fromAppReturn(e)):n=new $(new Error("This connection has no main object.")),this.#e=new Gi(t,n,r),this.#t=new re(this.#e.getMainImport())}getRemoteMain(){return this.#t}getStats(){return this.#e.getStats()}drain(){return this.#e.drain()}};var Re,qi=class{static{a(this,"MapBuilder")}context;captureMap=new Map;instructions=[];constructor(t,e){Re?this.context={parent:Re,captures:[],subject:Re.capture(t),path:e}:this.context={parent:void 0,captures:[],subject:t,path:e},Re=this}unregister(){Re=this.context.parent}makeInput(){return new ze(this,0)}makeOutput(t){let e;try{e=le.devaluate(t.value,void 0,this,t)}finally{t.dispose()}return this.instructions.push(e),this.context.parent?(this.context.parent.instructions.push(["remap",this.context.subject,this.context.path,this.context.captures.map(r=>["import",r]),this.instructions]),new ze(this.context.parent,this.context.parent.instructions.length)):this.context.subject.map(this.context.path,this.context.captures,this.instructions)}pushCall(t,e,r){let n=le.devaluate(r.value,void 0,this,r);n=n[0];let s=this.capture(t.dup());return this.instructions.push(["pipeline",s,e,n]),new ze(this,this.instructions.length)}pushGet(t,e){let r=this.capture(t.dup());return this.instructions.push(["pipeline",r,e]),new ze(this,this.instructions.length)}capture(t){if(t instanceof ze&&t.mapper===this)return t.idx;let e=this.captureMap.get(t);if(e===void 0){if(this.context.parent){let r=this.context.parent.capture(t);this.context.captures.push(r)}else this.context.captures.push(t);e=-this.context.captures.length,this.captureMap.set(t,e)}return e}exportStub(t){throw new Error("Can\'t construct an RpcTarget or RPC callback inside a mapper function. Try creating a new RpcStub outside the callback first, then using it inside the callback.")}exportPromise(t){return this.exportStub(t)}getImport(t){return this.capture(t)}unexport(t){}createPipe(t){throw new Error("Cannot send ReadableStream inside a mapper function.")}onSendError(t){}};yt.sendMap=(t,e,r)=>{let n=new qi(t,e),s;try{s=M.fromAppReturn(Di(n.pushCall.bind(n),()=>r(new A(n.makeInput(),[]))))}finally{n.unregister()}if(s instanceof Promise)throw s.catch(i=>{}),new Error("RPC map() callbacks cannot be async.");return new A(n.makeOutput(s),[])};function je(){throw new Error("Attempted to use an abstract placeholder from a mapper function. Please make sure your map function has no side effects.")}a(je,"throwMapperBuilderUseError");var ze=class extends he{static{a(this,"MapVariableHook")}constructor(t,e){super(),this.mapper=t,this.idx=e}dup(){return this}dispose(){}get(t){if(t.length==0)return this;if(Re)return Re.pushGet(this,t);je()}call(t,e){je()}map(t,e,r){je()}pull(){je()}ignoreUnhandledRejections(){}onBroken(t){je()}},Xi=class{static{a(this,"MapApplicator")}constructor(t,e){this.captures=t,this.variables=[e]}variables;dispose(){for(let t of this.variables)t.dispose()}apply(t){try{if(t.length<1)throw new Error("Invalid empty mapper function.");for(let e of t.slice(0,-1)){let r=new de(this).evaluateCopy(e);if(r.value instanceof re){let n=nr(r.value);if(n){this.variables.push(n);continue}}this.variables.push(new K(r))}return new de(this).evaluateCopy(t[t.length-1])}finally{for(let e of this.variables)e.dispose()}}importStub(t){throw new Error("A mapper function cannot refer to exports.")}importPromise(t){return this.importStub(t)}getExport(t){return t<0?this.captures[-t-1]:this.variables[t]}getPipeReadable(t){throw new Error("A mapper function cannot use pipe readables.")}};function pn(t,e,r,n,s){let i=new K(M.deepCopyFrom(t,e,r)),o=new Xi(n,i);try{return o.apply(s)}finally{o.dispose()}}a(pn,"applyMapToElement");yt.applyMap=(t,e,r,n,s)=>{try{let i;if(t instanceof A)throw new Error("applyMap() can\'t be called on RpcPromise");if(t instanceof Array){let o=[];try{for(let c of t)o.push(pn(c,t,r,n,s))}catch(c){for(let u of o)u.dispose();throw c}i=M.fromArray(o)}else t==null?i=M.fromAppReturn(t):i=pn(t,e,r,n,s);return new K(i)}finally{for(let i of n)i.dispose()}};var Yi=class ir extends he{static{a(this,"_WritableStreamStubHook")}state;static create(e){let r=e.getWriter();return new ir({refcount:1,writer:r,closed:!1})}constructor(e,r){super(),this.state=e,r&&++e.refcount}getState(){if(this.state)return this.state;throw new Error("Attempted to use a WritableStreamStubHook after it was disposed.")}call(e,r){try{let n=this.getState();if(e.length!==1||typeof e[0]!="string")throw new Error("WritableStream stub only supports direct method calls");let s=e[0];if(s!=="write"&&s!=="close"&&s!=="abort")throw r.dispose(),new Error(`Unknown WritableStream method: ${s}`);(s==="close"||s==="abort")&&(n.closed=!0);let i=n.writer[s],o=r.deliverCall(i,n.writer);return new Et(o.then(c=>new K(c)))}catch(n){return new $(n)}}map(e,r,n){for(let s of r)s.dispose();return new $(new Error("Cannot use map() on a WritableStream"))}get(e){return new $(new Error("Cannot access properties on a WritableStream stub"))}dup(){let e=this.getState();return new ir(e,this)}pull(){return Promise.reject(new Error("Cannot pull a WritableStream stub"))}ignoreUnhandledRejections(){}dispose(){let e=this.state;this.state=void 0,e&&--e.refcount===0&&(e.closed||e.writer.abort(new Error("WritableStream RPC stub was disposed without calling close()")).catch(()=>{}),e.writer.releaseLock())}onBroken(e){}},Ji=256*1024,Qi=1024*1024*1024,Zi=64*1024,eo=2,fn=1.25,to=.9,ro=3,no=class{static{a(this,"FlowController")}constructor(t){this.now=t}window=Ji;bytesInFlight=0;inStartupPhase=!0;delivered=0;deliveredTime=0;firstAckTime=0;firstAckDelivered=0;minRtt=1/0;roundsWithoutIncrease=0;lastRoundWindow=0;roundStartTime=0;onSend(t){this.bytesInFlight+=t;let e={sentTime:this.now(),size:t,deliveredAtSend:this.delivered,deliveredTimeAtSend:this.deliveredTime,windowAtSend:this.window,windowFullAtSend:this.bytesInFlight>=this.window};return{token:e,shouldBlock:e.windowFullAtSend}}onError(t){this.bytesInFlight-=t.size}onAck(t){let e=this.now();this.delivered+=t.size,this.deliveredTime=e,this.bytesInFlight-=t.size;let r=e-t.sentTime;if(this.minRtt=Math.min(this.minRtt,r),this.firstAckTime===0)this.firstAckTime=e,this.firstAckDelivered=this.delivered;else{let n,s;t.deliveredTimeAtSend===0?(n=this.firstAckTime,s=this.firstAckDelivered):(n=t.deliveredTimeAtSend,s=t.deliveredAtSend);let i=e-n,c=(this.delivered-s)/i,u=this.inStartupPhase?eo:fn,l=c*this.minRtt*u;l=Math.min(l,t.windowAtSend*u),t.windowFullAtSend?l=Math.max(l,t.windowAtSend*to):l=Math.max(l,this.window),this.window=Math.max(Math.min(l,Qi),Zi),this.inStartupPhase&&t.sentTime>=this.roundStartTime&&(this.window>this.lastRoundWindow*fn?this.roundsWithoutIncrease=0:++this.roundsWithoutIncrease>=ro&&(this.inStartupPhase=!1),this.roundStartTime=e,this.lastRoundWindow=this.window)}return this.bytesInFlight<this.window}};function so(t){let e,r=!1,n=new no(()=>performance.now()),s,i,o=a(()=>{r||(r=!0,t.dispose())},"disposeHook");return new WritableStream({write(c,u){if(e!==void 0)throw e;let l=M.fromAppParams([c]),{promise:d,size:p}=t.stream(["write"],l);if(p===void 0)return d.catch(g=>{throw e===void 0&&(e=g),g});{let{token:g,shouldBlock:m}=n.onSend(p);if(d.then(()=>{n.onAck(g)&&s&&(s(),s=void 0,i=void 0)},f=>{n.onError(g),e===void 0&&(e=f,u.error(f),o()),i&&(i(f),s=void 0,i=void 0)}),m)return new Promise((f,w)=>{s=f,i=w})}},async close(){if(e!==void 0)throw o(),e;let{promise:c}=t.stream(["close"],M.fromAppParams([]));try{await c}catch(u){throw e??u}finally{o()}},abort(c){if(e!==void 0)return;e=c??new Error("WritableStream was aborted"),i&&(i(e),s=void 0,i=void 0);let{promise:u}=t.stream(["abort"],M.fromAppParams([c]));u.then(()=>o(),()=>o())}})}a(so,"createWritableStreamFromHook");var io=class or extends he{static{a(this,"_ReadableStreamStubHook")}state;static create(e){return new or({refcount:1,stream:e,canceled:!1})}constructor(e,r){super(),this.state=e,r&&++e.refcount}call(e,r){return r.dispose(),new $(new Error("Cannot call methods on a ReadableStream stub"))}map(e,r,n){for(let s of r)s.dispose();return new $(new Error("Cannot use map() on a ReadableStream"))}get(e){return new $(new Error("Cannot access properties on a ReadableStream stub"))}dup(){let e=this.state;if(!e)throw new Error("Attempted to dup a ReadableStreamStubHook after it was disposed.");return new or(e,this)}pull(){return Promise.reject(new Error("Cannot pull a ReadableStream stub"))}ignoreUnhandledRejections(){}dispose(){let e=this.state;this.state=void 0,e&&--e.refcount===0&&(e.canceled||(e.canceled=!0,e.stream.locked||e.stream.cancel(new Error("ReadableStream RPC stub was disposed without being consumed")).catch(()=>{})))}onBroken(e){}};L.createWritableStreamHook=Yi.create;L.createWritableStreamFromHook=so;L.createReadableStreamHook=io.create;var Rn=Vi,Tn=gt;import{RpcTarget as oo,tracing as vt}from"cloudflare:workers";import Xe from"node:path/posix";var R=class extends Error{static{a(this,"SandboxError")}constructor(t,e){super(t.message,e),this.errorResponse=t,this.name="SandboxError"}get code(){return this.errorResponse.code}get context(){return this.errorResponse.context}get httpStatus(){return this.errorResponse.httpStatus}get operation(){return this.errorResponse.operation}get suggestion(){return this.errorResponse.suggestion}get timestamp(){return this.errorResponse.timestamp}get documentation(){return this.errorResponse.documentation}toJSON(){return{name:this.name,message:this.message,code:this.code,context:this.context,httpStatus:this.httpStatus,operation:this.operation,suggestion:this.suggestion,timestamp:this.timestamp,documentation:this.documentation,stack:this.stack}}},ao=class extends R{static{a(this,"FileNotFoundError")}constructor(t){super(t),this.name="FileNotFoundError"}get path(){return this.context.path}},co=class extends R{static{a(this,"FileExistsError")}constructor(t){super(t),this.name="FileExistsError"}get path(){return this.context.path}},uo=class extends R{static{a(this,"FileTooLargeError")}constructor(t){super(t),this.name="FileTooLargeError"}get path(){return this.context.path}},lo=class extends R{static{a(this,"FileSystemError")}constructor(t){super(t),this.name="FileSystemError"}get path(){return this.context.path}get stderr(){return this.context.stderr}get exitCode(){return this.context.exitCode}},ho=class extends R{static{a(this,"PermissionDeniedError")}constructor(t){super(t),this.name="PermissionDeniedError"}get path(){return this.context.path}},po=class extends R{static{a(this,"CommandNotFoundError")}constructor(t){super(t),this.name="CommandNotFoundError"}get command(){return this.context.command}},fo=class extends R{static{a(this,"CommandError")}constructor(t){super(t),this.name="CommandError"}get command(){return this.context.command}get exitCode(){return this.context.exitCode}get stdout(){return this.context.stdout}get stderr(){return this.context.stderr}},ns=class extends R{static{a(this,"ProcessNotFoundError")}constructor(t){super(t),this.name="ProcessNotFoundError"}get processId(){return this.context.processId}},mo=class extends R{static{a(this,"ProcessError")}constructor(t){super(t),this.name="ProcessError"}get processId(){return this.context.processId}get pid(){return this.context.pid}get exitCode(){return this.context.exitCode}get stderr(){return this.context.stderr}},ss=class extends R{static{a(this,"SessionAlreadyExistsError")}constructor(t){super(t),this.name="SessionAlreadyExistsError"}get sessionId(){return this.context.sessionId}get containerPlacementId(){return this.context.containerPlacementId}},go=class extends R{static{a(this,"SessionDestroyedError")}constructor(t){super(t),this.name="SessionDestroyedError"}get sessionId(){return this.context.sessionId}},is=class extends R{static{a(this,"SessionTerminatedError")}constructor(t){super(t),this.name="SessionTerminatedError"}get sessionId(){return this.context.sessionId}get exitCode(){return this.context.exitCode}},wo=class extends R{static{a(this,"PortAlreadyExposedError")}constructor(t){super(t),this.name="PortAlreadyExposedError"}get port(){return this.context.port}get portName(){return this.context.portName}},yo=class extends R{static{a(this,"PortNotExposedError")}constructor(t){super(t),this.name="PortNotExposedError"}get port(){return this.context.port}},Eo=class extends R{static{a(this,"InvalidPortError")}constructor(t){super(t),this.name="InvalidPortError"}get port(){return this.context.port}get reason(){return this.context.reason}},So=class extends R{static{a(this,"ServiceNotRespondingError")}constructor(t){super(t),this.name="ServiceNotRespondingError"}get port(){return this.context.port}get portName(){return this.context.portName}},bo=class extends R{static{a(this,"PortInUseError")}constructor(t){super(t),this.name="PortInUseError"}get port(){return this.context.port}},Ro=class extends R{static{a(this,"PortError")}constructor(t){super(t),this.name="PortError"}get port(){return this.context.port}get portName(){return this.context.portName}get stderr(){return this.context.stderr}},os=class extends R{static{a(this,"CustomDomainRequiredError")}constructor(t){super(t),this.name="CustomDomainRequiredError"}},To=class extends R{static{a(this,"GitRepositoryNotFoundError")}constructor(t){super(t),this.name="GitRepositoryNotFoundError"}get repository(){return this.context.repository}},Io=class extends R{static{a(this,"GitAuthenticationError")}constructor(t){super(t),this.name="GitAuthenticationError"}get repository(){return this.context.repository}},Co=class extends R{static{a(this,"GitBranchNotFoundError")}constructor(t){super(t),this.name="GitBranchNotFoundError"}get branch(){return this.context.branch}get repository(){return this.context.repository}},xo=class extends R{static{a(this,"GitNetworkError")}constructor(t){super(t),this.name="GitNetworkError"}get repository(){return this.context.repository}get branch(){return this.context.branch}get targetDir(){return this.context.targetDir}},vo=class extends R{static{a(this,"GitCloneError")}constructor(t){super(t),this.name="GitCloneError"}get repository(){return this.context.repository}get targetDir(){return this.context.targetDir}get stderr(){return this.context.stderr}get exitCode(){return this.context.exitCode}},Oo=class extends R{static{a(this,"GitCheckoutError")}constructor(t){super(t),this.name="GitCheckoutError"}get branch(){return this.context.branch}get repository(){return this.context.repository}get stderr(){return this.context.stderr}},_o=class extends R{static{a(this,"InvalidGitUrlError")}constructor(t){super(t),this.name="InvalidGitUrlError"}get validationErrors(){return this.context.validationErrors}},Ao=class extends R{static{a(this,"GitError")}constructor(t){super(t),this.name="GitError"}get repository(){return this.context.repository}get branch(){return this.context.branch}get targetDir(){return this.context.targetDir}get stderr(){return this.context.stderr}get exitCode(){return this.context.exitCode}},as=class extends R{static{a(this,"InterpreterNotReadyError")}constructor(t){super(t),this.name="InterpreterNotReadyError"}get retryAfter(){return this.context.retryAfter}get progress(){return this.context.progress}},Po=class extends R{static{a(this,"ContextNotFoundError")}constructor(t){super(t),this.name="ContextNotFoundError"}get contextId(){return this.context.contextId}},ko=class extends R{static{a(this,"CodeExecutionError")}constructor(t){super(t),this.name="CodeExecutionError"}get contextId(){return this.context.contextId}get ename(){return this.context.ename}get evalue(){return this.context.evalue}get traceback(){return this.context.traceback}},No=class extends R{static{a(this,"ValidationFailedError")}constructor(t){super(t),this.name="ValidationFailedError"}get validationErrors(){return this.context.validationErrors}},cs=class extends R{static{a(this,"ProcessReadyTimeoutError")}constructor(t){super(t),this.name="ProcessReadyTimeoutError"}get processId(){return this.context.processId}get command(){return this.context.command}get condition(){return this.context.condition}get timeout(){return this.context.timeout}},us=class extends R{static{a(this,"ProcessExitedBeforeReadyError")}constructor(t){super(t),this.name="ProcessExitedBeforeReadyError"}get processId(){return this.context.processId}get command(){return this.context.command}get condition(){return this.context.condition}get exitCode(){return this.context.exitCode}},Pe=class extends R{static{a(this,"BackupNotFoundError")}constructor(t){super(t),this.name="BackupNotFoundError"}get backupId(){return this.context.backupId}},Ot=class extends R{static{a(this,"BackupExpiredError")}constructor(t){super(t),this.name="BackupExpiredError"}get backupId(){return this.context.backupId}get expiredAt(){return this.context.expiredAt}},v=class extends R{static{a(this,"InvalidBackupConfigError")}constructor(t){super(t),this.name="InvalidBackupConfigError"}get reason(){return this.context.reason}},G=class extends R{static{a(this,"BackupCreateError")}constructor(t){super(t),this.name="BackupCreateError"}get dir(){return this.context.dir}get backupId(){return this.context.backupId}},V=class extends R{static{a(this,"BackupRestoreError")}constructor(t){super(t),this.name="BackupRestoreError"}get dir(){return this.context.dir}get backupId(){return this.context.backupId}},ls=class extends R{static{a(this,"ContainerUnavailableError")}constructor(t){super(t),this.name="ContainerUnavailableError"}get reason(){return this.context.reason}get retryAfterMs(){return this.context.retryAfterMs}},kt=class extends R{static{a(this,"RPCTransportError")}constructor(t,e){super(t,e),this.name="RPCTransportError"}get kind(){return this.errorResponse.context.kind}get originalMessage(){return this.errorResponse.context.originalMessage}},Q=class extends R{static{a(this,"OperationInterruptedError")}constructor(t,e){super(t,e),this.name="OperationInterruptedError"}get reason(){return this.context.reason}};function B(t,e){switch(t.code){case h.FILE_NOT_FOUND:return new ao(t);case h.FILE_EXISTS:return new co(t);case h.FILE_TOO_LARGE:return new uo(t);case h.PERMISSION_DENIED:return new ho(t);case h.IS_DIRECTORY:case h.NOT_DIRECTORY:case h.NO_SPACE:case h.TOO_MANY_FILES:case h.RESOURCE_BUSY:case h.READ_ONLY:case h.NAME_TOO_LONG:case h.TOO_MANY_LINKS:case h.FILESYSTEM_ERROR:return new lo(t);case h.COMMAND_NOT_FOUND:return new po(t);case h.COMMAND_PERMISSION_DENIED:case h.COMMAND_EXECUTION_ERROR:case h.INVALID_COMMAND:case h.STREAM_START_ERROR:return new fo(t);case h.PROCESS_NOT_FOUND:return new ns(t);case h.PROCESS_PERMISSION_DENIED:case h.PROCESS_ERROR:return new mo(t);case h.SESSION_ALREADY_EXISTS:return new ss(t);case h.SESSION_DESTROYED:return new go(t);case h.SESSION_TERMINATED:return new is(t);case h.PORT_ALREADY_EXPOSED:return new wo(t);case h.PORT_NOT_EXPOSED:return new yo(t);case h.INVALID_PORT_NUMBER:case h.INVALID_PORT:return new Eo(t);case h.SERVICE_NOT_RESPONDING:return new So(t);case h.PORT_IN_USE:return new bo(t);case h.PORT_OPERATION_ERROR:return new Ro(t);case h.CUSTOM_DOMAIN_REQUIRED:return new os(t);case h.GIT_REPOSITORY_NOT_FOUND:return new To(t);case h.GIT_AUTH_FAILED:return new Io(t);case h.GIT_BRANCH_NOT_FOUND:return new Co(t);case h.GIT_NETWORK_ERROR:return new xo(t);case h.GIT_CLONE_FAILED:return new vo(t);case h.GIT_CHECKOUT_FAILED:return new Oo(t);case h.INVALID_GIT_URL:return new _o(t);case h.GIT_OPERATION_FAILED:return new Ao(t);case h.BACKUP_NOT_FOUND:return new Pe(t);case h.BACKUP_EXPIRED:return new Ot(t);case h.INVALID_BACKUP_CONFIG:return new v(t);case h.BACKUP_CREATE_FAILED:return new G(t);case h.BACKUP_RESTORE_FAILED:return new V(t);case h.INTERPRETER_NOT_READY:return new as(t);case h.CONTEXT_NOT_FOUND:return new Po(t);case h.CODE_EXECUTION_ERROR:return new ko(t);case h.OPERATION_INTERRUPTED:return new Q(t,e);case h.CONTAINER_UNAVAILABLE:return new ls(t);case h.RPC_TRANSPORT_ERROR:return new kt(t,e);case h.VALIDATION_FAILED:return new No(t);case h.INVALID_JSON_RESPONSE:case h.UNKNOWN_ERROR:case h.INTERNAL_ERROR:return new R(t);default:return new R(t)}}a(B,"createErrorFromResponse");var Do=3e3,Lo=3e4,Mo=new Set([500,502,503,504]);function hr(t){return Mo.has(t.status)}a(hr,"isRetryableWebSocketUpgradeResponse");function In(t,e,r){let n=e-r;if(n<=0)return null;let s=Math.min(Do*2**t,Lo);return Math.min(s,n)}a(In,"nextRetryDelayMs");async function Rr(t,e){let r=Date.now(),n=0;for(;;){let s;try{s=await t()}catch(u){if(!e.shouldRetryError?.(u))throw u;let l=Date.now()-r,d=e.retryTimeoutMs-l,p=In(n,d,e.minTimeForRetryMs);if(p===null)throw u;e.logger.info(e.retryLogMessage,{attempt:n+1,delayMs:p,remainingSec:Math.floor(d/1e3),error:u instanceof Error?u.message:String(u)}),await new Promise(g=>setTimeout(g,p)),n++;continue}if(!e.shouldRetry(s))return s;let i=Date.now()-r,o=e.retryTimeoutMs-i,c=In(n,o,e.minTimeForRetryMs);if(c===null)return e.onRetryExhausted?.({attempts:n+1,elapsedMs:i,response:s}),s;e.logger.info(e.retryLogMessage,{status:s.status,attempt:n+1,delayMs:c,remainingSec:Math.floor(o/1e3),...e.getRetryLogContext?.(s)}),await new Promise(u=>setTimeout(u,c)),n++}}a(Rr,"fetchWithResponseRetry");var Uo=12e4,Fo=15e3,ds=class{static{a(this,"BaseTransport")}config;logger;retryTimeoutMs;constructor(t){this.config=t,this.logger=t.logger??Ce(),this.retryTimeoutMs=t.retryTimeoutMs??Uo}setRetryTimeoutMs(t){this.retryTimeoutMs=t}getRetryTimeoutMs(){return this.retryTimeoutMs}async fetch(t,e){return Rr(()=>this.doFetch(t,e),{retryTimeoutMs:this.retryTimeoutMs,minTimeForRetryMs:Fo,logger:this.logger,retryLogMessage:"Container not ready, retrying",shouldRetry:a(r=>r.status===503,"shouldRetry"),getRetryLogContext:a(()=>({mode:this.getMode()}),"getRetryLogContext"),onRetryExhausted:a(({attempts:r,elapsedMs:n})=>{this.logger.error("Container failed to become ready",new Error(`Failed after ${r} attempts over ${Math.floor(n/1e3)}s`))},"onRetryExhausted")})}buildContainerUrl(t){return this.config.stub?`http://localhost:${this.config.port||3e3}${t}`:`${this.config.baseUrl??`http://localhost:${this.config.port||3e3}`}${t}`}httpFetch(t,e){let r=this.buildContainerUrl(t);return this.config.stub?this.config.stub.containerFetch(r,e||{},this.config.port):globalThis.fetch(r,e)}async httpFetchStream(t,e,r="POST",n){let s=this.buildContainerUrl(t),i={method:r,headers:e&&r==="POST"?{...n,"Content-Type":"application/json"}:n,body:e&&r==="POST"?JSON.stringify(e):void 0},o;if(this.config.stub?o=await this.config.stub.containerFetch(s,i,this.config.port):o=await globalThis.fetch(s,i),!o.ok){let c=await o.text();throw new Error(`HTTP error! status: ${o.status} - ${c}`)}if(!o.body)throw new Error("No response body for streaming");return o.body}},Bo=class extends ds{static{a(this,"HttpTransport")}getMode(){return"http"}async connect(){}disconnect(){}isConnected(){return!0}async doFetch(t,e){return this.httpFetch(t,e)}async fetchStream(t,e,r="POST",n){return this.httpFetchStream(t,e,r,n)}},$o=12e4,Cn=3e5,xn=3e4,Ho=1e3,Wo=15e3,Ko=class extends ds{static{a(this,"WebSocketTransport")}ws=null;state="disconnected";pendingRequests=new Map;connectPromise=null;idleDisconnectTimer=null;boundHandleMessage;boundHandleClose;constructor(t){if(super(t),!t.wsUrl)throw new Error("wsUrl is required for WebSocket transport");this.boundHandleMessage=this.handleMessage.bind(this),this.boundHandleClose=this.handleClose.bind(this)}getMode(){return"websocket"}isConnected(){return this.state==="connected"&&this.ws?.readyState===WebSocket.OPEN}async connect(){if(this.clearIdleDisconnectTimer(),!this.isConnected()){if(this.connectPromise)return this.connectPromise;this.connectPromise=this.doConnect();try{await this.connectPromise}finally{this.connectPromise=null}}}disconnect(){this.cleanup()}isWebSocketConnecting(){return this.state==="connecting"}async doFetch(t,e){if(this.isWebSocketConnecting())return this.httpFetch(t,e);await this.connect();let r=e?.method||"GET",n=this.parseBody(e?.body),s=this.normalizeHeaders(e?.headers),i=await this.request(r,t,n,s,e?.requestTimeoutMs);return new Response(JSON.stringify(i.body),{status:i.status,headers:{"Content-Type":"application/json"}})}async fetchStream(t,e,r="POST",n){return this.requestStream(r,t,e,n)}parseBody(t){if(t){if(typeof t=="string")try{return JSON.parse(t)}catch(e){throw new Error(`Request body must be valid JSON: ${e instanceof Error?e.message:String(e)}`)}throw new Error(`WebSocket transport only supports string bodies. Got: ${typeof t}`)}}normalizeHeaders(t){if(!t)return;let e={};return new Headers(t).forEach((r,n)=>{e[n]=r}),Object.keys(e).length>0?e:void 0}async doConnect(){this.state="connecting",this.config.stub?await this.connectViaFetch():await this.connectViaWebSocket()}async fetchUpgradeWithRetry(t){return Rr(t,{retryTimeoutMs:this.getRetryTimeoutMs(),minTimeForRetryMs:Wo,logger:this.logger,retryLogMessage:"WebSocket upgrade returned retryable status, retrying",shouldRetry:hr})}async connectViaFetch(){let t=this.config.connectTimeoutMs??xn;try{let e=new URL(this.config.wsUrl).pathname,r=`http://localhost:${this.config.port||3e3}${e}`,n=await this.fetchUpgradeWithRetry(()=>this.fetchUpgradeAttempt(r,t));if(n.status!==101)throw new Error(`WebSocket upgrade failed: ${n.status} ${n.statusText}`);let s=n.webSocket;if(!s)throw new Error("No WebSocket in upgrade response");s.accept(),this.ws=s,this.state="connected",this.ws.addEventListener("close",this.boundHandleClose),this.ws.addEventListener("message",this.boundHandleMessage),this.logger.debug("WebSocket connected via fetch",{url:this.config.wsUrl})}catch(e){throw this.state="error",this.logger.error("WebSocket fetch connection failed",e instanceof Error?e:new Error(String(e))),e}}async fetchUpgradeAttempt(t,e){let r=new AbortController,n=setTimeout(()=>r.abort(),e);try{let s=new Request(t,{headers:{Upgrade:"websocket",Connection:"Upgrade"},signal:r.signal});return await this.config.stub.fetch(s)}finally{clearTimeout(n)}}connectViaWebSocket(){return new Promise((t,e)=>{let r=this.config.connectTimeoutMs??xn,n=setTimeout(()=>{this.cleanup(),e(new Error(`WebSocket connection timeout after ${r}ms`))},r);try{this.ws=new WebSocket(this.config.wsUrl);let s=a(()=>{clearTimeout(n),this.ws?.removeEventListener("open",s),this.ws?.removeEventListener("error",i),this.state="connected",this.logger.debug("WebSocket connected",{url:this.config.wsUrl}),t()},"onOpen"),i=a(()=>{clearTimeout(n),this.ws?.removeEventListener("open",s),this.ws?.removeEventListener("error",i),this.state="error",this.logger.error("WebSocket error",new Error("WebSocket connection failed")),e(new Error("WebSocket connection failed"))},"onConnectError");this.ws.addEventListener("open",s),this.ws.addEventListener("error",i),this.ws.addEventListener("close",this.boundHandleClose),this.ws.addEventListener("message",this.boundHandleMessage)}catch(s){clearTimeout(n),this.state="error",e(s)}})}async request(t,e,r,n,s){await this.connect(),this.clearIdleDisconnectTimer();let i=$t(),o={type:"request",id:i,method:t,path:e,body:r,headers:n};return new Promise((c,u)=>{let l=s??this.config.requestTimeoutMs??$o,d=setTimeout(()=>{this.pendingRequests.delete(i),this.scheduleIdleDisconnect(),u(new Error(`Request timeout after ${l}ms: ${t} ${e}`))},l);this.pendingRequests.set(i,{resolve:a(p=>{clearTimeout(d),this.pendingRequests.delete(i),this.scheduleIdleDisconnect(),c({status:p.status,body:p.body})},"resolve"),reject:a(p=>{clearTimeout(d),this.pendingRequests.delete(i),this.scheduleIdleDisconnect(),u(p)},"reject"),isStreaming:!1,timeoutId:d});try{this.send(o)}catch(p){clearTimeout(d),this.pendingRequests.delete(i),this.scheduleIdleDisconnect(),u(p instanceof Error?p:new Error(String(p)))}})}async requestStream(t,e,r,n){if(this.isWebSocketConnecting())return this.httpFetchStream(e,r,t,n);await this.connect(),this.clearIdleDisconnectTimer();let s=$t(),i={type:"request",id:s,method:t,path:e,body:r,headers:n},o=this.config.streamIdleTimeoutMs??Cn;return new Promise((c,u)=>{let l,d=!1,g=a(()=>setTimeout(()=>{this.pendingRequests.delete(s),this.scheduleIdleDisconnect();let f=new Error(`Stream idle timeout after ${o}ms: ${t} ${e}`);if(d)try{l?.error(f)}catch{}else u(f)},o),"createIdleTimeout")(),m=new ReadableStream({start:a(f=>{l=f},"start"),cancel:a(()=>{let f=this.pendingRequests.get(s);f?.timeoutId&&clearTimeout(f.timeoutId);try{this.send({type:"cancel",id:s})}catch(w){this.logger.debug("Failed to send stream cancel message",{id:s,error:w instanceof Error?w.message:String(w)})}this.pendingRequests.delete(s),this.scheduleIdleDisconnect()},"cancel")});this.pendingRequests.set(s,{resolve:a(f=>{let w=this.pendingRequests.get(s);if(w?.timeoutId&&clearTimeout(w.timeoutId),this.pendingRequests.delete(s),this.scheduleIdleDisconnect(),!d)d=!0,f.status>=400?u(new Error(`Stream error: ${f.status} - ${JSON.stringify(f.body)}`)):(l?.close(),c(m));else if(f.status>=400)try{l?.error(new Error(`Stream error: ${f.status} - ${JSON.stringify(f.body)}`))}catch{}else l?.close()},"resolve"),reject:a(f=>{let w=this.pendingRequests.get(s);if(w?.timeoutId&&clearTimeout(w.timeoutId),this.pendingRequests.delete(s),this.scheduleIdleDisconnect(),d)try{l?.error(f)}catch{}else u(f)},"reject"),streamController:void 0,isStreaming:!0,timeoutId:g,onFirstChunk:a(()=>{if(!d){d=!0;let f=this.pendingRequests.get(s);if(f&&(f.streamController=l,f.bufferedChunks)){try{for(let w of f.bufferedChunks)l.enqueue(w)}catch(w){this.logger.debug("Failed to flush buffered chunks, cleaning up",{id:s,error:w instanceof Error?w.message:String(w)}),f.timeoutId&&clearTimeout(f.timeoutId),this.pendingRequests.delete(s),this.scheduleIdleDisconnect()}f.bufferedChunks=void 0}c(m)}},"onFirstChunk")});try{this.send(i)}catch(f){clearTimeout(g),this.pendingRequests.delete(s),this.scheduleIdleDisconnect(),u(f instanceof Error?f:new Error(String(f)))}})}send(t){if(!this.ws||this.ws.readyState!==WebSocket.OPEN)throw new Error("WebSocket not connected");this.ws.send(JSON.stringify(t)),this.logger.debug("WebSocket sent",{id:t.id,type:t.type,method:t.type==="request"?t.method:void 0,path:t.type==="request"?t.path:void 0})}handleMessage(t){try{let e=JSON.parse(t.data);Vr(e)?this.handleResponse(e):qr(e)?this.handleStreamChunk(e):Xr(e)?this.handleError(e):this.logger.warn("Unknown WebSocket message type",{message:e})}catch(e){this.logger.error("Failed to parse WebSocket message",e instanceof Error?e:new Error(String(e)))}}handleResponse(t){let e=this.pendingRequests.get(t.id);if(!e){this.logger.warn("Received response for unknown request",{id:t.id});return}this.logger.debug("WebSocket response",{id:t.id,status:t.status,done:t.done}),t.done&&e.resolve(t)}handleStreamChunk(t){let e=this.pendingRequests.get(t.id);if(!e){this.logger.warn("Received stream chunk for unknown request",{id:t.id});return}if(e.onFirstChunk&&(e.onFirstChunk(),e.onFirstChunk=void 0),e.isStreaming&&this.resetStreamIdleTimeout(t.id,e),!e.streamController){e.bufferedChunks||(e.bufferedChunks=[]);let s=new TextEncoder,i;t.event?i=`event: ${t.event}\ndata: ${t.data}\n\n`:i=`data: ${t.data}\n\n`,e.bufferedChunks.push(s.encode(i));return}let r=new TextEncoder,n;t.event?n=`event: ${t.event}\ndata: ${t.data}\n\n`:n=`data: ${t.data}\n\n`;try{e.streamController.enqueue(r.encode(n))}catch(s){this.logger.debug("Failed to enqueue stream chunk, cleaning up",{id:t.id,error:s instanceof Error?s.message:String(s)}),e.timeoutId&&clearTimeout(e.timeoutId),this.pendingRequests.delete(t.id),this.scheduleIdleDisconnect()}}resetStreamIdleTimeout(t,e){e.timeoutId&&clearTimeout(e.timeoutId);let r=this.config.streamIdleTimeoutMs??Cn;e.timeoutId=setTimeout(()=>{if(this.pendingRequests.delete(t),this.scheduleIdleDisconnect(),e.streamController)try{e.streamController.error(new Error(`Stream idle timeout after ${r}ms`))}catch{}},r)}handleError(t){if(t.id){let e=this.pendingRequests.get(t.id);if(e){e.reject(new Error(`${t.code}: ${t.message}`));return}}this.logger.error("WebSocket error message",new Error(t.message),{code:t.code,status:t.status})}handleClose(t){this.state="disconnected",this.ws=null,this.connectPromise=null;let e=new Error(`WebSocket closed: ${t.code} ${t.reason||"No reason"}`);for(let[,r]of this.pendingRequests){if(r.timeoutId&&clearTimeout(r.timeoutId),r.streamController)try{r.streamController.error(e)}catch{}r.reject(e)}this.pendingRequests.clear()}cleanup(){this.clearIdleDisconnectTimer(),this.ws&&(this.ws.removeEventListener("close",this.boundHandleClose),this.ws.removeEventListener("message",this.boundHandleMessage),this.ws.close(),this.ws=null),this.state="disconnected",this.connectPromise=null;for(let t of this.pendingRequests.values())t.timeoutId&&clearTimeout(t.timeoutId);this.pendingRequests.clear()}scheduleIdleDisconnect(){!this.isConnected()||this.pendingRequests.size>0||(this.clearIdleDisconnectTimer(),this.idleDisconnectTimer=setTimeout(()=>{this.idleDisconnectTimer=null,this.pendingRequests.size===0&&this.isConnected()&&(this.logger.debug("Disconnecting idle WebSocket transport"),this.cleanup())},Ho))}clearIdleDisconnectTimer(){this.idleDisconnectTimer&&(clearTimeout(this.idleDisconnectTimer),this.idleDisconnectTimer=null)}};function hs(t){switch(t.mode){case"http":return new Bo(t);case"websocket":return new Ko(t)}}a(hs,"createTransport");var oe=class{static{a(this,"BaseHttpClient")}options;logger;transport;constructor(t={}){this.options=t,this.logger=t.logger??Ce(),t.transport?this.transport=t.transport:this.transport=hs({mode:t.transportMode??"http",baseUrl:t.baseUrl??"http://localhost:3000",wsUrl:t.wsUrl,logger:this.logger,stub:t.stub,port:t.port,retryTimeoutMs:t.retryTimeoutMs})}setRetryTimeoutMs(t){this.transport.setRetryTimeoutMs(t)}isWebSocketMode(){return this.transport.getMode()==="websocket"}async doFetch(t,e){let{defaultHeaders:r}=this.options;return r&&(e={...e,headers:{...r,...e?.headers}}),this.transport.fetch(t,e)}async post(t,e,r,n){let s=await this.doFetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e),...n});return await this.handleResponse(s,r)}async get(t,e){let r=await this.doFetch(t,{method:"GET"});return await this.handleResponse(r,e)}async delete(t,e){let r=await this.doFetch(t,{method:"DELETE"});return await this.handleResponse(r,e)}async handleResponse(t,e){if(t.ok||await this.handleErrorResponse(t),e)return e(t);try{return await t.json()}catch(r){throw B({code:h.INVALID_JSON_RESPONSE,message:`Invalid JSON response: ${r instanceof Error?r.message:"Unknown parsing error"}`,context:{},httpStatus:t.status,timestamp:new Date().toISOString()})}}async handleErrorResponse(t){let e;try{e=await t.json()}catch{e={code:h.INTERNAL_ERROR,message:`HTTP error! status: ${t.status}`,context:{statusText:t.statusText},httpStatus:t.status,timestamp:new Date().toISOString()}}let r=B(e);throw this.options.onError?.(e.message,void 0),r}async handleStreamResponse(t){if(t.ok||await this.handleErrorResponse(t),!t.body)throw new Error("No response body for streaming");return t.body}async doStreamFetch(t,e,r="POST"){let n=r==="POST"?{...this.options.defaultHeaders,"Content-Type":"application/json"}:this.options.defaultHeaders;if(this.transport.getMode()==="websocket")return this.transport.fetchStream(t,e,r,n);let s=await this.doFetch(t,{method:r,headers:{"Content-Type":"application/json"},body:e&&r==="POST"?JSON.stringify(e):void 0});return await this.handleStreamResponse(s)}},ps=class extends oe{static{a(this,"BackupClient")}async createArchive(t,e,r,n){let s={dir:t,archivePath:e,gitignore:n?.gitignore??!1,excludes:n?.excludes??[],compression:n?.compression,sessionId:r};return await this.post("/api/backup/create",s)}async restoreArchive(t,e,r){let n={dir:t,archivePath:e,sessionId:r};return await this.post("/api/backup/restore",n)}async uploadParts(t,e){return this.post("/api/backup/upload-parts",{...t,sessionId:e??t.sessionId})}},fs=class extends oe{static{a(this,"CommandClient")}async execute(t,e,r){try{let n={command:t,sessionId:e,...r?.timeoutMs!==void 0&&{timeoutMs:r.timeoutMs},...r?.env!==void 0&&{env:r.env},...r?.cwd!==void 0&&{cwd:r.cwd},...r?.origin!==void 0&&{origin:r.origin}},s=await this.post("/api/execute",n);return this.options.onCommandComplete?.(s.success,s.exitCode,s.stdout,s.stderr,s.command),s}catch(n){throw this.options.onError?.(n instanceof Error?n.message:String(n),t),n}}async executeStream(t,e,r){try{let n={command:t,sessionId:e,...r?.timeoutMs!==void 0&&{timeoutMs:r.timeoutMs},...r?.env!==void 0&&{env:r.env},...r?.cwd!==void 0&&{cwd:r.cwd},...r?.origin!==void 0&&{origin:r.origin}};return await this.doStreamFetch("/api/execute/stream",n)}catch(n){throw this.options.onError?.(n instanceof Error?n.message:String(n),t),n}}},ms=class extends oe{static{a(this,"FileClient")}async mkdir(t,e,r){let n={path:t,sessionId:e,recursive:r?.recursive??!1};return await this.post("/api/mkdir",n)}async writeFile(t,e,r,n){let s={path:t,content:e,sessionId:r,encoding:n?.encoding};return await this.post("/api/write",s)}async readFile(t,e,r){if(r?.encoding==="none")throw new Error("readFile with encoding: \'none\' requires the rpc transport. Set SANDBOX_TRANSPORT=rpc.");let n={path:t,sessionId:e,encoding:r?.encoding};return await this.post("/api/read",n)}async readFileStream(t,e){let r={path:t,sessionId:e};return await this.doStreamFetch("/api/read/stream",r)}async deleteFile(t,e){let r={path:t,sessionId:e};return await this.post("/api/delete",r)}async renameFile(t,e,r){let n={oldPath:t,newPath:e,sessionId:r};return await this.post("/api/rename",n)}async moveFile(t,e,r){let n={sourcePath:t,destinationPath:e,sessionId:r};return await this.post("/api/move",n)}async listFiles(t,e,r){let n={path:t,sessionId:e,options:r||{}};return await this.post("/api/list-files",n)}async exists(t,e){let r={path:t,sessionId:e};return await this.post("/api/exists",r)}writeFileStream(t,e,r){throw new Error("writeFileStream requires the rpc transport. Set SANDBOX_TRANSPORT=rpc.")}},gs=class ws extends oe{static{a(this,"GitClient")}static REQUEST_TIMEOUT_BUFFER_MS=3e4;constructor(e={}){super(e),this.logger=new Kr(this.logger)}async checkout(e,r,n){let s=n?.timeoutMs??Hr,i=n?.targetDir;i||(i=`/workspace/${Wr(e)}`);let o={repoUrl:e,sessionId:r,targetDir:i};if(n?.branch&&(o.branch=n.branch),n?.depth!==void 0){if(!Number.isInteger(n.depth)||n.depth<=0)throw new Error(`Invalid depth value: ${n.depth}. Must be a positive integer (e.g., 1, 5, 10).`);o.depth=n.depth}if(!Number.isInteger(s)||s<=0)throw new Error(`Invalid timeout value: ${s}. Must be a positive integer number of milliseconds.`);return o.timeoutMs=s,await this.post("/api/git/checkout",o,void 0,{requestTimeoutMs:s+ws.REQUEST_TIMEOUT_BUFFER_MS})}},jo=class extends oe{static{a(this,"InterpreterClient")}maxRetries=3;retryDelayMs=1e3;async createCodeContext(t={}){return this.executeWithRetry(async()=>{let e=await this.doFetch("/api/contexts",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({language:t.language||"python",cwd:t.cwd||"/workspace",env_vars:t.envVars})});if(!e.ok)throw await this.parseErrorResponse(e);let r=await e.json();if(!r.success)throw new Error(`Failed to create context: ${JSON.stringify(r)}`);return{id:r.contextId,language:r.language,cwd:r.cwd||"/workspace",createdAt:new Date(r.timestamp),lastUsed:new Date(r.timestamp)}})}async runCodeStream(t,e,r,n,s){return this.executeWithRetry(async()=>{let i=await this.doStreamFetch("/api/execute/code",{context_id:t,code:e,language:r,...s!==void 0&&{timeout_ms:s}});for await(let o of this.readLines(i))await this.parseExecutionResult(o,n)})}async listCodeContexts(){return this.executeWithRetry(async()=>{let t=await this.doFetch("/api/contexts",{method:"GET",headers:{"Content-Type":"application/json"}});if(!t.ok)throw await this.parseErrorResponse(t);let e=await t.json();if(!e.success)throw new Error(`Failed to list contexts: ${JSON.stringify(e)}`);return e.contexts.map(r=>({id:r.id,language:r.language,cwd:r.cwd||"/workspace",createdAt:new Date(e.timestamp),lastUsed:new Date(e.timestamp)}))})}async deleteCodeContext(t){return this.executeWithRetry(async()=>{let e=await this.doFetch(`/api/contexts/${t}`,{method:"DELETE",headers:{"Content-Type":"application/json"}});if(!e.ok)throw await this.parseErrorResponse(e)})}async streamCode(t,e,r){return this.doStreamFetch("/api/execute/code",{context_id:t,code:e,language:r})}async executeWithRetry(t){let e;for(let r=0;r<this.maxRetries;r++)try{return await t()}catch(n){if(e=n,this.isRetryableError(n)&&r<this.maxRetries-1){let s=this.retryDelayMs*2**r+Math.random()*1e3;await new Promise(i=>setTimeout(i,s));continue}throw n}throw e||new Error("Execution failed after retries")}isRetryableError(t){return t instanceof as?!0:t instanceof Error?t.message.includes("not ready")||t.message.includes("initializing"):!1}async parseErrorResponse(t){try{return B(await t.json())}catch{return B({code:h.INTERNAL_ERROR,message:`HTTP ${t.status}: ${t.statusText}`,context:{},httpStatus:t.status,timestamp:new Date().toISOString()})}}async*readLines(t){let e=t.getReader(),r="";try{for(;;){let{done:n,value:s}=await e.read();if(s&&(r+=new TextDecoder().decode(s)),n)break;let i=r.indexOf(`\n`);for(;i!==-1;)yield r.slice(0,i),r=r.slice(i+1),i=r.indexOf(`\n`)}r.length>0&&(yield r)}finally{try{await e.cancel()}catch{}e.releaseLock()}}async parseExecutionResult(t,e){if(t.trim()&&t.startsWith("data: "))try{let r=t.substring(6),n=JSON.parse(r);switch(n.type){case"stdout":e.onStdout&&n.text&&await e.onStdout({text:n.text,timestamp:n.timestamp||Date.now()});break;case"stderr":e.onStderr&&n.text&&await e.onStderr({text:n.text,timestamp:n.timestamp||Date.now()});break;case"result":if(e.onResult){let s=new Bt(n);await e.onResult(s)}break;case"error":e.onError&&await e.onError({name:n.ename||"Error",message:n.evalue||"Unknown error",traceback:n.traceback||[]});break;case"execution_complete":break}}catch{}}},ys=class extends oe{static{a(this,"PortClient")}async watchPort(t){return await this.doStreamFetch("/api/port-watch",t)}},Es=class extends oe{static{a(this,"ProcessClient")}async startProcess(t,e,r){let n={command:t,sessionId:e,...r?.origin!==void 0&&{origin:r.origin},...r?.processId!==void 0&&{processId:r.processId},...r?.timeoutMs!==void 0&&{timeoutMs:r.timeoutMs},...r?.env!==void 0&&{env:r.env},...r?.cwd!==void 0&&{cwd:r.cwd},...r?.encoding!==void 0&&{encoding:r.encoding},...r?.autoCleanup!==void 0&&{autoCleanup:r.autoCleanup}};return await this.post("/api/process/start",n)}async listProcesses(){return await this.get("/api/process/list")}async getProcess(t){let e=`/api/process/${t}`;return await this.get(e)}async killProcess(t){let e=`/api/process/${t}`;return await this.delete(e)}async killAllProcesses(){return await this.delete("/api/process/kill-all")}async getProcessLogs(t){let e=`/api/process/${t}/logs`;return await this.get(e)}async streamProcessLogs(t){let e=`/api/process/${t}/stream`;return await this.doStreamFetch(e,void 0,"GET")}},Ss=class extends oe{static{a(this,"UtilityClient")}async ping(){return(await this.get("/api/ping")).message}async getCommands(){return(await this.get("/api/commands")).availableCommands}async createSession(t){return await this.post("/api/session/create",t)}async deleteSession(t){return await this.post("/api/session/delete",{sessionId:t})}async getVersion(){try{return(await this.get("/api/version")).version}catch(t){return this.logger.debug("Failed to get container version (may be old container)",{error:t}),"unknown"}}listSessions(){throw new Error("listSessions requires the RPC transport. Set SANDBOX_TRANSPORT=rpc.")}},zo=class extends oe{static{a(this,"WatchClient")}async checkChanges(t){return this.post("/api/watch/check",t)}async watch(t){let e=await this.doStreamFetch("/api/watch",t);return await this.waitForReadiness(e)}async waitForReadiness(t){let e=t.getReader(),r=[],n=new TextDecoder,s="",i={data:[]},o=!1,c=a(l=>{let d;try{d=JSON.parse(l)}catch{return}if(d.type==="watching"&&(o=!0),d.type==="error")throw new Error(d.error||"Watch failed to establish")},"processEventData");try{for(;!o;){let{done:l,value:d}=await e.read();if(l){let g=ye(`${s}\n\n`,i);for(let m of g.events)if(c(m.data),o)break;if(o)break;throw new Error("Watch stream ended before watcher was established")}r.push(d),s+=n.decode(d,{stream:!0});let p=ye(s,i);s=p.remaining,i=p.currentEvent;for(let g of p.events)if(c(g.data),o)break}}catch(l){throw e.cancel().catch(()=>{}),l}let u=0;return new ReadableStream({pull(l){if(u<r.length){l.enqueue(r[u++]);return}return e.read().then(({done:d,value:p})=>{if(d){l.close();return}l.enqueue(p)})},cancel(){return e.cancel()}})}},bs=class{static{a(this,"SandboxClient")}backup;commands;files;processes;ports;git;interpreter;utils;watch;tunnels=Go();transport=null;constructor(t){t.transportMode==="websocket"&&t.wsUrl&&(this.transport=hs({mode:t.transportMode,wsUrl:t.wsUrl,baseUrl:t.baseUrl,logger:t.logger,stub:t.stub,port:t.port,retryTimeoutMs:t.retryTimeoutMs}));let e={baseUrl:"http://localhost:3000",...t,transport:this.transport??t.transport};this.backup=new ps(e),this.commands=new fs(e),this.files=new ms(e),this.processes=new Es(e),this.ports=new ys(e),this.git=new gs(e),this.interpreter=new jo(e),this.utils=new Ss(e),this.watch=new zo(e)}setRetryTimeoutMs(t){this.transport?this.transport.setRetryTimeoutMs(t):(this.backup.setRetryTimeoutMs(t),this.commands.setRetryTimeoutMs(t),this.files.setRetryTimeoutMs(t),this.processes.setRetryTimeoutMs(t),this.ports.setRetryTimeoutMs(t),this.git.setRetryTimeoutMs(t),this.interpreter.setRetryTimeoutMs(t),this.utils.setRetryTimeoutMs(t),this.watch.setRetryTimeoutMs(t))}getTransportMode(){return this.transport?.getMode()??"http"}isWebSocketConnected(){return this.transport?.isConnected()??!1}async connect(){this.transport&&await this.transport.connect()}disconnect(){this.transport&&this.transport.disconnect()}};function Go(){let t=\'sandbox.tunnels.* requires the RPC transport. Enable it with transport: "rpc" in sandbox options.\';return new Proxy({},{get(){return()=>{throw new Error(t)}}})}a(Go,"createTunnelsNotImplemented");var Vo=/reset because its code was updated|this script has been upgraded/i,qo=/network connection lost/i,Xo=/internal error while starting up durable object storage caused object to be reset/i;function Yo(t){return t instanceof Error?t.message:typeof t=="string"?t:""}a(Yo,"errorMessageOf");function Jo(t){let e=t?.message;return typeof e=="string"?e:String(t)}a(Jo,"realmSafeMessageOf");var Qo=[{substring:"there is no container instance that can be provided to this durable object",reason:"no_container_instance_available"},{substring:"there is no container instance available at this time",reason:"no_container_instance_available"},{substring:"maximum number of running container instances exceeded",reason:"max_container_instances_exceeded"}];function ke(t){for(let e of Rs(t)){let r=Jo(e).toLowerCase(),n=Qo.find(s=>r.includes(s.substring));if(n)return n.reason}return null}a(ke,"matchContainerUnavailable");function*Rs(t){let e=t;for(let r=0;r<8&&e!=null;r+=1)yield e,e=typeof e=="object"?e.cause:void 0}a(Rs,"selfAndCauses");function Zo(t){if(typeof t!="object"||t===null)return!1;let e=String(t),r=t;return r.retryable===!0&&r.overloaded!==!0&&!e.includes("Durable Object is overloaded")}a(Zo,"isErrorRetryable");function Ts(t){for(let e of Rs(t)){let r=Yo(e);if(Vo.test(r)||qo.test(r)||Xo.test(r)||Zo(e))return!0}return!1}a(Ts,"isPlatformTransientError");var vn=["/workspace","/home","/tmp","/var/tmp","/app"];function ea(t){let e=t;for(;e.startsWith("**/");)e=e.slice(3);for(;e.includes("/**/");)e=e.replace(/\\/\\*\\*\\//g,"/");return e.endsWith("/**")&&(e=e.slice(0,-3)),!e||e==="**"?null:e}a(ea,"normalizeBackupExcludePattern");var O="__DISABLE_SESSION__",ar="currentRuntimeIdentity",_t=class extends Error{static{a(this,"RuntimeIdentityInactiveError")}constructor(){super("Runtime identity is no longer active"),this.name="RuntimeIdentityInactiveError"}},On=class{static{a(this,"RuntimeIdentity")}id;constructor(t){this.id=t.id}owns(t){return t.runtimeIdentityID===this.id}scope(t){return{...t,runtimeIdentityID:this.id}}},ta=class{static{a(this,"CurrentRuntimeIdentity")}constructor(t,e,r){this.storage=t,this.getContainerState=e,this.isContainerRunning=r}async get(){let t=await this.getStatus();return t.status==="active"?t.runtime:null}async getStatus(){let t=await this.getContainerState();if(t.status!=="healthy")return{status:"inactive",reason:"runtime-not-healthy",containerStatus:t.status};if(!this.isContainerRunning())return{status:"inactive",reason:"runtime-not-running",containerStatus:t.status};let e=await this.getStored();return e?{status:"active",runtime:e,containerStatus:t.status}:{status:"inactive",reason:"missing-runtime-id",containerStatus:t.status}}async getStored(t=this.storage){let e=await t.get(ar)??null;return e?new On(e):null}async markStarted(){let t={id:crypto.randomUUID()};return await this.storage.put(ar,t),new On(t)}async clear(){await this.storage.delete(ar)}async isActive(t){return(await this.get())?.id===t.id}async assertActive(t){if(!await this.isActive(t))throw new _t}},cr="sandbox:lifetime",Tr=class extends Error{static{a(this,"SandboxLifetimeChangedError")}constructor(){super("Sandbox lifetime is no longer current"),this.name="SandboxLifetimeChangedError"}},ur=class{static{a(this,"SandboxLifetime")}id;generation;createdAt;updatedAt;constructor(t){this.record=t,this.id=t.id,this.generation=t.generation,this.createdAt=t.createdAt,this.updatedAt=t.updatedAt}owns(t){return t.sandboxLifetimeID===this.id}scope(t){return{...t,sandboxLifetimeID:this.id}}},ra=class{static{a(this,"CurrentSandboxLifetime")}constructor(t){this.storage=t}async get(){let t=await this.storage.get(cr)??null;return t?new ur(t):null}async getOrCreate(){let t=await this.get();if(t)return t;let e=new Date().toISOString(),r={id:crypto.randomUUID(),generation:1,createdAt:e,updatedAt:e};return await this.storage.put(cr,r),new ur(r)}async rotate(){let t=await this.get(),e=new Date().toISOString(),r={id:crypto.randomUUID(),generation:(t?.generation??0)+1,createdAt:e,updatedAt:e};return await this.storage.put(cr,r),new ur(r)}async isCurrent(t){return(await this.get())?.id===t.id}async assertCurrent(t){if(!await this.isCurrent(t))throw new Tr}},na="operations:";function sa(t,e){return`restore:${t}:${e}`}a(sa,"backupRestoreOperationKey");function ia(t){return{operationKey:sa(t.backupId,t.dir),kind:"backup.restore",sandboxLifetimeID:t.sandboxLifetimeID,phase:"validating",status:"running",payload:{backupId:t.backupId,dir:t.dir},createdAt:t.now,updatedAt:t.now}}a(ia,"createBackupRestoreOperationRecord");var oa=class{static{a(this,"BackupRestoreOperationStore")}constructor(t){this.storage=t}async get(t){return await this.storage.get(this.storageKey(t))??null}async put(t){await this.storage.put(this.storageKey(t.operationKey),t)}storageKey(t){return`${na}${t}`}},_n=2,aa=class{static{a(this,"RestoreLifecycleRunner")}operationRecords;constructor(t){this.deps=t,this.operationRecords=new oa(t.storage)}async execute(t){return await this.runWithRecovery(async()=>{let{lifetime:e,operation:r}=await this.startOperation(t.backupId,t.dir),n=r,s,i={lifetime:e,runtimeReady:a(async()=>{try{s=await this.captureRuntime(),await this.deps.currentLifetime.assertCurrent(e)}catch(o){throw await this.translateFenceError(o,n,"validating","unknown")??o}return n=await this.markRuntimeReady(n,s),{runtime:s,operation:n}},"runtimeReady"),archiveReady:a(async o=>{if(!s)throw new Error("Backup restore archiveReady requires runtimeReady()");try{await this.assertFences(s,e)}catch(c){throw await this.translateFenceError(c,n,n.phase,!0)??c}return n=await this.markArchiveReady(n,s,o),{runtime:s,operation:n}},"archiveReady"),verify:a(async o=>{if(!s)throw new Error("Backup restore verification requires runtimeReady()");try{await this.assertFences(s,e)}catch(c){throw await this.translateFenceError(c,n,"archive_ready",!0)??c}return n=await this.markVerified(n,s,o),n},"verify")};try{return await t.attempt(i)}catch(o){let c=await this.translateRPCError(o,n);if(c)throw c;let u=await this.translateFenceError(o,n,n.phase,"unknown");throw u||(o instanceof Q||await this.markFailed(n,o),o)}})}async runWithRecovery(t){let e=0;for(;;)try{return await t()}catch(r){if(!(r instanceof Q)||!r.context.retryable)throw r;if(e>=_n)throw this.createRecoveryExhaustedError(r,e);e++}}async startOperation(t,e){let r=await this.deps.currentLifetime.getOrCreate(),n=ia({sandboxLifetimeID:r.id,backupId:t,dir:e,now:new Date().toISOString()});return await this.operationRecords.put(n),{lifetime:r,operation:n}}async captureRuntime(){let t=await this.deps.currentRuntime.get()??await this.deps.currentRuntime.markStarted();return await this.deps.currentRuntime.assertActive(t),t}async assertFences(t,e){await this.deps.currentRuntime.assertActive(t),await this.deps.currentLifetime.assertCurrent(e)}async markRuntimeReady(t,e){let r={...t,phase:"runtime_ready",runtimeIdentityID:e.id,updatedAt:new Date().toISOString()};return await this.operationRecords.put(r),r}async markArchiveReady(t,e,r){let n={...t,phase:"archive_ready",runtimeIdentityID:e.id,payload:{...t.payload,...r!==void 0&&{archiveSize:r}},updatedAt:new Date().toISOString()};return await this.operationRecords.put(n),n}async markVerified(t,e,r){let n=new Date().toISOString(),s={...t,phase:"verified",status:"committed",runtimeIdentityID:e.id,result:r,completedAt:n,updatedAt:n};return await this.operationRecords.put(s),s}async markFailed(t,e){let r=new Date().toISOString(),n=e instanceof Error?e.message:String(e),s=e instanceof Error&&"code"in e&&typeof e.code=="string"?e.code:"UNKNOWN",i={...t,phase:"failed",status:"failed",error:{code:s,message:n,retryable:!1},completedAt:r,updatedAt:r};return await this.operationRecords.put(i),i}async markInterrupted(t,e,r){let n={...t,phase:"interrupted",status:"interrupted",error:{code:h.OPERATION_INTERRUPTED,message:e,retryable:r},updatedAt:new Date().toISOString()};return await this.operationRecords.put(n),n}async translateFenceError(t,e,r,n){if(!(t instanceof _t||t instanceof Tr))return null;let s=t instanceof _t?"runtime_replaced":"sandbox_lifetime_changed",i=s!=="sandbox_lifetime_changed",o="Backup restore was interrupted before completion could be verified",c=await this.markInterrupted(e,o,i);return this.createInterruptedError({reason:s,phase:r,admitted:n,retryable:i,message:o,operation:c})}async translateRPCError(t,e){if(!(t instanceof kt))return null;let r="Backup restore was interrupted before completion could be verified",n=e.phase,s=await this.markInterrupted(e,r,!0);return this.createInterruptedError({reason:"transport_disposed",phase:n,admitted:"unknown",retryable:!0,message:r,operation:s})}createInterruptedError(t){return new Q({message:t.message,code:h.OPERATION_INTERRUPTED,httpStatus:409,context:{reason:t.reason,operation:"backup.restore",phase:t.phase,admitted:t.admitted,retryable:t.retryable},timestamp:new Date().toISOString(),suggestion:this.suggestionFor(t.retryable)})}createRecoveryExhaustedError(t,e){return new Q({message:"Backup restore recovery attempts were exhausted",code:h.OPERATION_INTERRUPTED,httpStatus:409,context:{reason:"recovery_exhausted",operation:t.context.operation,phase:"interrupted",admitted:t.context.admitted,retryable:!1,recoveryAttempts:e,maxRecoveryAttempts:_n},timestamp:new Date().toISOString(),suggestion:this.suggestionFor(!1)})}suggestionFor(t){return t?"Retry restoreBackup() with the same backup handle so the SDK can reconcile the restore operation.":"Start a new restoreBackup() call only if restoring this backup is still desired for the current sandbox."}},ca=8;function An(t){let e=t?.code;return typeof e=="string"?e:void 0}a(An,"stringCode");function Pn(t){return t instanceof Error?t.message:String(t)}a(Pn,"messageOf");function ua(t){let e={};if(t instanceof Error){e.error=t.message,typeof t.stack=="string"&&(e["error.stack"]=t.stack);let o=An(t);o!==void 0&&(e["error.code"]=o)}else return e.error=String(t),e;let r=[],n=new Set([t]),s=t.cause,i=0;for(;s!=null&&i<ca&&!n.has(s);){if(n.add(s),i===0){e["error.cause"]=Pn(s);let o=An(s);o!==void 0&&(e["error.cause.code"]=o)}r.push(Pn(s)),s=s instanceof Error?s.cause:void 0,i++}return r.length>0&&(e["error.cause_chain"]=r.join(" <- ")),e}a(ua,"computeErrorAttributes");function la(t,e){for(let[r,n]of Object.entries(ua(e)))n!==void 0&&t.setAttribute(r,n)}a(la,"setErrorAttributes");async function pr(t,e,r){let n=vt?.enterSpan?.bind(vt);return typeof n!="function"?r({setAttribute:a(()=>{},"setAttribute")}):n(t,async s=>{for(let[i,o]of Object.entries(e))o!==void 0&&s.setAttribute(i,o);try{return await r(s)}catch(i){throw la(s,i),i}})}a(pr,"withSpan");function kn(t,e){let r=vt?.enterSpan?.bind(vt);if(typeof r=="function")try{r(t,n=>{for(let[s,i]of Object.entries(e))i!==void 0&&n.setAttribute(s,i)})}catch{}}a(kn,"traceEvent");async function da(t){if((t.headers.get("content-type")??"").includes("application/json"))try{let e=await t.clone().json();if(e.code!==h.CONTAINER_UNAVAILABLE)return null;let r={reason:e.context?.reason==="container_starting"||e.context?.reason==="container_unhealthy"||e.context?.reason==="container_replaced"||e.context?.reason==="rpc_upgrade_failed"||e.context?.reason==="no_container_instance_available"||e.context?.reason==="max_container_instances_exceeded"?e.context.reason:"container_replaced",retryable:!0,...typeof e.context?.retryAfterMs=="number"&&{retryAfterMs:e.context.retryAfterMs},...typeof e.context?.originalMessage=="string"&&{originalMessage:e.context.originalMessage}};return B({code:h.CONTAINER_UNAVAILABLE,message:e.message??"Container is unavailable",context:r,httpStatus:F(h.CONTAINER_UNAVAILABLE),suggestion:W(h.CONTAINER_UNAVAILABLE,r),timestamp:new Date().toISOString()})}catch{return null}try{let e=await t.clone().text(),r=ke(e);return r?Is(r,e):null}catch{return null}}a(da,"tryParseContainerUnavailable");function ha(t){return ke(t)!==null}a(ha,"isPlatformUnavailableError");function Is(t,e,r){let n={reason:t,retryable:!0,originalMessage:e};return B({code:h.CONTAINER_UNAVAILABLE,message:e,context:n,httpStatus:F(h.CONTAINER_UNAVAILABLE),suggestion:W(h.CONTAINER_UNAVAILABLE,n),timestamp:new Date().toISOString()},r!==void 0?{cause:r}:void 0)}a(Is,"buildContainerUnavailableError");function Nn(t){if(t instanceof R)return t;let e=ke(t);return e?Is(e,t instanceof Error?t.message:String(t),t):null}a(Nn,"tryConvertPlatformUnavailable");var pa=3e4,fa=12e4,ma=15e3,ga=class{static{a(this,"ContainerControlConnection")}stub;session;transport;ws=null;connected=!1;connectPromise=null;containerStub;port;logger;retryTimeoutMs;onClose;onConnectionError;onConnected;startContainer;getSandboxInfo;constructor(t){this.containerStub=t.stub,this.port=t.port??3e3,this.logger=t.logger??Ce(),this.retryTimeoutMs=t.retryTimeoutMs??fa,this.onClose=t.onClose,this.onConnectionError=t.onConnectionError,this.onConnected=t.onConnected,this.startContainer=t.startContainer,this.getSandboxInfo=t.getSandboxInfo,this.transport=new wa,this.session=new Rn(this.transport,t.localMain),this.stub=this.session.getRemoteMain()}rpc(){return!this.connected&&!this.connectPromise&&this.connect().catch(()=>{}),this.stub}getStats(){return this.session.getStats()}isConnected(){return this.connected}isConnecting(){return this.connectPromise!==null}async whenSettled(){let t=this.connectPromise;t&&await t.catch(()=>{})}async connect(){if(!this.connected){if(this.connectPromise)return this.connectPromise;this.connectPromise=this.doConnect();try{await this.connectPromise}finally{this.connectPromise=null}}}disconnect(t){t!==void 0?kn("sandbox.rpc.disconnect",{...this.spanAttrs(),reason:t instanceof Error?t.message:String(t)}):kn("sandbox.rpc.disconnect",this.spanAttrs());try{this.stub[Symbol.dispose]?.()}catch{}if(this.ws){this.ws.removeEventListener("close",this.onWebSocketClose),this.ws.removeEventListener("error",this.onWebSocketError);try{this.ws.close()}catch{}this.ws=null}this.connected=!1,this.connectPromise=null}setRetryTimeoutMs(t){this.retryTimeoutMs=t}spanAttrs(){let t=this.getSandboxInfo?.();return{"sandbox.rpc.port":this.port,"sandbox.id":t?.id,"sandbox.name":t?.name}}fireOnClose(){if(this.onClose)try{this.onClose()}catch(t){this.logger.warn("ContainerControlConnection onClose handler threw",{error:t instanceof Error?t.message:String(t)})}}fireConnectionError(t){if(this.onConnectionError)try{this.onConnectionError(t)}catch(e){this.logger.warn("ContainerControlConnection onConnectionError handler threw",{error:e instanceof Error?e.message:String(e)})}}onWebSocketClose=a(()=>{let t=this.connected;this.connected=!1,this.ws=null,this.logger.debug("ContainerControlConnection WebSocket closed"),t&&this.fireOnClose()},"onWebSocketClose");onWebSocketError=a(()=>{let t=this.connected;this.connected=!1,this.ws=null,t&&this.fireOnClose()},"onWebSocketError");async doConnect(){return pr("sandbox.rpc.connect",this.spanAttrs(),()=>this.doConnectInner())}async doConnectInner(){try{let t=await this.fetchUpgradeWithRetry();if(t.status!==101){let r=await da(t);throw r||(hr(t)?B({code:h.CONTAINER_UNAVAILABLE,message:`Container was unavailable after exhausting upgrade retry budget (status ${t.status})`,context:{reason:"rpc_upgrade_failed",retryable:!0},httpStatus:F(h.CONTAINER_UNAVAILABLE),suggestion:W(h.CONTAINER_UNAVAILABLE,{}),timestamp:new Date().toISOString()}):new Error(`WebSocket upgrade failed: ${t.status} ${t.statusText}`))}let e=t.webSocket;if(!e)throw new Error("No WebSocket in upgrade response");e.accept(),e.addEventListener("close",this.onWebSocketClose),e.addEventListener("error",this.onWebSocketError),this.ws=e,this.transport.activate(e),this.connected=!0;try{this.onConnected?.()}catch(r){this.logger.warn("ContainerControlConnection onConnected handler threw",{error:r instanceof Error?r.message:String(r)})}this.logger.debug("ContainerControlConnection established",{port:this.port})}catch(t){this.connected=!1;let e=Nn(t)??t;throw this.fireConnectionError(e),this.transport.abort(e),this.fireOnClose(),this.logger.error("ContainerControlConnection failed",e instanceof Error?e:new Error(String(e))),e}}async fetchUpgradeWithRetry(){return Rr(()=>this.fetchUpgradeAttempt(),{retryTimeoutMs:this.retryTimeoutMs,minTimeForRetryMs:ma,logger:this.logger,retryLogMessage:"ContainerControlConnection upgrade returned retryable status, retrying",shouldRetry:hr,shouldRetryError:ha})}async fetchUpgradeAttempt(){return pr("sandbox.rpc.connect.attempt",this.spanAttrs(),async()=>{if(this.startContainer)try{await this.startContainer()}catch(r){throw this.fireConnectionError(Nn(r)??r),r}let t=new AbortController,e=setTimeout(()=>t.abort(),pa);try{let r=`http://localhost:${this.port}/rpc`,n=new Request(r,{headers:{Upgrade:"websocket",Connection:"Upgrade"},signal:t.signal});return await this.containerStub.fetch(n)}finally{clearTimeout(e)}})}},wa=class{static{a(this,"DeferredTransport")}#e=null;#t=[];#r=[];#n;#o;#s;activate(t){this.#e=t,t.addEventListener("message",e=>{this.#s||(typeof e.data=="string"?this.#n?(this.#n(e.data),this.#n=void 0,this.#o=void 0):this.#r.push(e.data):this.#i(new TypeError("Received non-string message from WebSocket.")))}),t.addEventListener("close",e=>{this.#i(new Error(`Peer closed WebSocket: ${e.code} ${e.reason}`))}),t.addEventListener("error",()=>{this.#i(new Error("WebSocket connection failed."))});for(let e of this.#t)t.send(e);this.#t=[]}async send(t){this.#e?this.#e.send(t):this.#t.push(t)}async receive(){if(this.#r.length>0)return this.#r.shift();if(this.#s)throw this.#s;return new Promise((t,e)=>{this.#n=t,this.#o=e})}abort(t){if(this.#i(t instanceof Error?t:new Error(String(t))),this.#e){let e=t instanceof Error?t.message:String(t);this.#e.close(3e3,e)}}#i(t){this.#s||(this.#s=t,this.#o?.(t),this.#n=void 0,this.#o=void 0)}},ya=1e3,Ea=1e3,Sa=1,ba=1;function Dn(t,e={}){if(t instanceof R)throw t;if(t instanceof Error){let r=t;if(typeof r.code=="string"&&Object.hasOwn(h,r.code)){let o=r.code,c=r.details&&typeof r.details=="object"?r.details:{};throw B({code:o,message:t.message,context:c,httpStatus:F(o),timestamp:new Date().toISOString()})}let n;try{n=JSON.parse(t.message)}catch{}if(n&&typeof n.code=="string"&&typeof n.message=="string")throw B({code:n.code,message:n.message,context:n.context??{},httpStatus:F(n.code),timestamp:new Date().toISOString()});let s=Ln(t),i=va(s,e);throw i||(e.sessionEstablished===!1?B(Oa(s,e)??s,{cause:t}):B(_a(s,e)??s,{cause:t}))}throw B(Ln(new Error(String(t))),{cause:t})}a(Dn,"translateRPCError");function Ln(t){let e=t.message,r=t.name,n="unknown",s,i;if(r==="TypeError")n="invalid_frame";else if(r==="SyntaxError")n="protocol_error";else{let c=e.match(/^Peer closed WebSocket: (\\d+) ?(.*)$/);c?(n="peer_closed",s=Number(c[1]),i=c[2]||void 0):e==="WebSocket connection failed."?n="connection_failed":e.startsWith("WebSocket upgrade failed")||e==="No WebSocket in upgrade response"?n="upgrade_failed":(e==="RPC session was shut down by disposing the main stub"||e==="RPC was canceled because the RpcPromise was disposed.")&&(n="session_disposed")}let o={kind:n,originalMessage:e,errorName:r,...s!==void 0?{closeCode:s}:{},...i!==void 0?{closeReason:i}:{}};return{code:h.RPC_TRANSPORT_ERROR,message:e,context:o,httpStatus:F(h.RPC_TRANSPORT_ERROR),suggestion:W(h.RPC_TRANSPORT_ERROR,o),timestamp:new Date().toISOString()}}a(Ln,"buildTransportErrorResponse");function Ra(t){if(t instanceof R)return{code:t.code,message:t.message,context:t.context??{}};let e=t;if(!e||typeof e.code!="string"||!Object.hasOwn(h,e.code))return null;let r=e.code,n=e.context&&typeof e.context=="object"?e.context:e.details&&typeof e.details=="object"?e.details:{};return{code:r,message:typeof e.message=="string"?e.message:r,context:n}}a(Ra,"extractCapturedErrorShape");var Ta=new Set(["runtime_replaced","transport_disposed","sandbox_lifetime_changed","recovery_exhausted"]);function Ia(t){return typeof t=="string"&&Ta.has(t)?t:null}a(Ia,"asOperationInterruptedReason");function Ca(t){if(typeof t=="boolean"||t==="unknown")return t}a(Ca,"asInterruptedAdmitted");function xa(t,e,r){if(t.code!==h.OPERATION_INTERRUPTED||typeof e.operation!="string"||e.operation.length===0)return B({code:t.code,message:t.message,context:t.context,httpStatus:F(t.code),suggestion:W(t.code,t.context),timestamp:new Date().toISOString()},{cause:r});let n=Ia(t.context.reason)??"transport_disposed",s=e.sessionEstablished===!0?!0:e.sessionEstablished===!1?!1:Ca(t.context.admitted)??"unknown",i=typeof t.context.retryable=="boolean"?t.context.retryable:!1,o={reason:n,operation:e.operation,phase:"rpc_call",admitted:s,retryable:i,...typeof t.context.recoveryAttempts=="number"&&{recoveryAttempts:t.context.recoveryAttempts},...typeof t.context.maxRecoveryAttempts=="number"&&{maxRecoveryAttempts:t.context.maxRecoveryAttempts},...typeof t.context.containerExitCode=="number"&&{containerExitCode:t.context.containerExitCode},...typeof t.context.stopReason=="string"&&{stopReason:t.context.stopReason}};return new Q({code:h.OPERATION_INTERRUPTED,message:t.message,context:o,httpStatus:F(h.OPERATION_INTERRUPTED),suggestion:W(h.OPERATION_INTERRUPTED,o),timestamp:new Date().toISOString()},{cause:r})}a(xa,"rebindInterruptedOperationContext");function va(t,e){let r=e.connectionError;if(!r)return null;let{kind:n}=t.context;if(n!=="session_disposed"&&n!=="connection_failed"&&n!=="upgrade_failed"&&n!=="peer_closed")return null;let s=Ra(r);return s?xa(s,e,r):null}a(va,"maybePreferConnectionError");function Oa(t,e){if(e.sessionEstablished!==!1)return null;let{kind:r}=t.context;if(r!=="session_disposed"&&r!=="connection_failed"&&r!=="peer_closed")return null;let n={reason:"container_unreachable",retryable:!0,originalMessage:t.context.originalMessage};return{code:h.CONTAINER_UNAVAILABLE,message:"The sandbox container was unavailable: the connection was torn down before it became reachable. Retry the operation.",context:n,httpStatus:F(h.CONTAINER_UNAVAILABLE),suggestion:W(h.CONTAINER_UNAVAILABLE,n),timestamp:new Date().toISOString()}}a(Oa,"buildNeverConnectedUnavailableResponse");function _a(t,e){if(!e.operation)return null;let{kind:r}=t.context;if(r!=="session_disposed"&&r!=="peer_closed"&&r!=="connection_failed")return null;let n={reason:r==="session_disposed"?"transport_disposed":"runtime_replaced",operation:e.operation,phase:"rpc_call",admitted:e.sessionEstablished===!0?!0:e.sessionEstablished===!1?!1:"unknown",retryable:!1},s=r==="session_disposed"?"was closing":"closed unexpectedly";return{code:h.OPERATION_INTERRUPTED,message:`Sandbox operation ${e.operation} was interrupted while the runtime connection ${s}`,context:n,httpStatus:F(h.OPERATION_INTERRUPTED),suggestion:W(h.OPERATION_INTERRUPTED,n),timestamp:new Date().toISOString()}}a(_a,"buildInterruptedOperationResponse");function ee(t,e,r,n,s,i,o){return new Proxy(t,{get(c,u,l){let d=Reflect.get(c,u,l);return typeof d!="function"?d:(...p)=>{r();let g=typeof u=="string"?`${e}.${u}`:e;try{let m=Reflect.apply(d,c,p);return m!=null&&typeof m.then=="function"?pr(`sandbox.rpc.call ${g}`,{...o(),operation:g},()=>m.catch(f=>Dn(f,{operation:g,connectionError:s(),sessionEstablished:i()}))).finally(n):(n(),m)}catch(m){n(),Dn(m,{operation:g,connectionError:s(),sessionEstablished:i()})}}}})}a(ee,"wrapStub");var Aa=class{static{a(this,"ContainerControlClient")}connOptions;idleDisconnectMs;busyPollIntervalMs;logger;onActivity;onSessionBusy;onSessionIdle;conn=null;lastConnectionError=null;connectionErrorIsAuthoritative=!1;sessionEstablished=!1;idleTimer=null;busyPollTimer=null;activeCalls=0;busy=!1;constructor(t){this.connOptions={stub:t.stub,port:t.port,localMain:t.localMain,logger:t.logger,retryTimeoutMs:t.retryTimeoutMs,getSandboxInfo:t.getSandboxInfo,startContainer:t.startContainer,onConnected:a(()=>{this.sessionEstablished=!0,this.lastConnectionError=null,this.connectionErrorIsAuthoritative=!1},"onConnected"),onClose:a(()=>{this.conn&&this.destroyConnection()},"onClose"),onConnectionError:a(e=>{this.lastConnectionError=e,this.connectionErrorIsAuthoritative=!0},"onConnectionError")},this.idleDisconnectMs=t.idleDisconnectMs??ya,this.busyPollIntervalMs=t.busyPollIntervalMs??Ea,this.logger=t.logger??Ce(),this.onActivity=t.onActivity,this.onSessionBusy=t.onSessionBusy,this.onSessionIdle=t.onSessionIdle}getConnection(){return this.conn||(this.lastConnectionError=null,this.connectionErrorIsAuthoritative=!1,this.sessionEstablished=!1,this.conn=new ga(this.connOptions),this.startBusyPoll()),this.conn}stampWeakConnectionCause(t){t!==void 0&&(this.connectionErrorIsAuthoritative||(this.lastConnectionError=t))}fireUserCallback(t,e){if(e)try{e()}catch(r){this.logger.warn("ContainerControlClient callback threw",{callback:t,error:r instanceof Error?r.message:String(r)})}}fireActivity(){this.fireUserCallback("onActivity",this.onActivity)}fireSessionBusy(){this.fireUserCallback("onSessionBusy",this.onSessionBusy)}fireSessionIdle(){this.fireUserCallback("onSessionIdle",this.onSessionIdle)}markBusy(){this.busy||(this.busy=!0,this.fireSessionBusy()),this.clearIdleTimer()}isSessionBusy(t){let{imports:e,exports:r}=t.getStats();return this.activeCalls>0||e>Sa||r>ba}maybeTransitionIdle(){let t=this.conn;t&&t.isConnected()&&this.transitionIdleIfReady(t)}transitionIdleIfReady(t){if(this.isSessionBusy(t)){this.markBusy();return}this.busy?(this.busy=!1,this.fireSessionIdle(),this.scheduleIdleDisconnect()):this.idleTimer||this.scheduleIdleDisconnect()}recordCallStarted=a(()=>{this.activeCalls++,this.markBusy(),this.fireActivity()},"recordCallStarted");recordCallSettled=a(()=>{this.activeCalls=Math.max(0,this.activeCalls-1),this.maybeTransitionIdle()},"recordCallSettled");getLastConnectionError=a(()=>this.lastConnectionError,"getLastConnectionError");getSessionEstablished=a(()=>this.sessionEstablished,"getSessionEstablished");getSpanAttrs=a(()=>{let t=this.connOptions.getSandboxInfo?.();return{"sandbox.id":t?.id,"sandbox.name":t?.name,"sandbox.rpc.port":this.connOptions.port!==void 0?String(this.connOptions.port):void 0}},"getSpanAttrs");pollBusyState=a(()=>{let t=this.conn;if(t&&t.isConnected()){if(this.isSessionBusy(t)){this.markBusy(),this.fireActivity();return}this.transitionIdleIfReady(t)}},"pollBusyState");startBusyPoll(){this.busyPollTimer||(this.busyPollTimer=setInterval(this.pollBusyState,this.busyPollIntervalMs))}stopBusyPoll(){this.busyPollTimer&&(clearInterval(this.busyPollTimer),this.busyPollTimer=null)}scheduleIdleDisconnect(){this.clearIdleTimer(),this.idleTimer=setTimeout(()=>{this.idleTimer=null;let t=this.conn;!t||!t.isConnected()||this.isSessionBusy(t)||(this.logger.debug("Disconnecting idle RPC connection"),this.destroyConnection())},this.idleDisconnectMs)}clearIdleTimer(){this.idleTimer&&(clearTimeout(this.idleTimer),this.idleTimer=null)}destroyConnection(t){this.stopBusyPoll(),this.clearIdleTimer(),this.activeCalls=0,this.busy&&(this.busy=!1,this.fireSessionIdle()),this.conn&&(this.stampWeakConnectionCause(t),this.conn.disconnect(t),this.conn=null)}get commands(){return ee(this.getConnection().rpc().commands,"commands",this.recordCallStarted,this.recordCallSettled,this.getLastConnectionError,this.getSessionEstablished,this.getSpanAttrs)}get files(){return ee(this.getConnection().rpc().files,"files",this.recordCallStarted,this.recordCallSettled,this.getLastConnectionError,this.getSessionEstablished,this.getSpanAttrs)}get processes(){return ee(this.getConnection().rpc().processes,"processes",this.recordCallStarted,this.recordCallSettled,this.getLastConnectionError,this.getSessionEstablished,this.getSpanAttrs)}get ports(){return ee(this.getConnection().rpc().ports,"ports",this.recordCallStarted,this.recordCallSettled,this.getLastConnectionError,this.getSessionEstablished,this.getSpanAttrs)}get git(){return ee(this.getConnection().rpc().git,"git",this.recordCallStarted,this.recordCallSettled,this.getLastConnectionError,this.getSessionEstablished,this.getSpanAttrs)}get utils(){return ee(this.getConnection().rpc().utils,"utils",this.recordCallStarted,this.recordCallSettled,this.getLastConnectionError,this.getSessionEstablished,this.getSpanAttrs)}get backup(){return ee(this.getConnection().rpc().backup,"backup",this.recordCallStarted,this.recordCallSettled,this.getLastConnectionError,this.getSessionEstablished,this.getSpanAttrs)}get watch(){return ee(this.getConnection().rpc().watch,"watch",this.recordCallStarted,this.recordCallSettled,this.getLastConnectionError,this.getSessionEstablished,this.getSpanAttrs)}get tunnels(){return ee(this.getConnection().rpc().tunnels,"tunnels",this.recordCallStarted,this.recordCallSettled,this.getLastConnectionError,this.getSessionEstablished,this.getSpanAttrs)}get interpreter(){return ee(this.getConnection().rpc().interpreter,"interpreter",this.recordCallStarted,this.recordCallSettled,this.getLastConnectionError,this.getSessionEstablished,this.getSpanAttrs)}setRetryTimeoutMs(t){this.connOptions.retryTimeoutMs=t,this.conn?.setRetryTimeoutMs(t)}getTransportMode(){return"rpc"}isWebSocketConnected(){return this.conn?.isConnected()??!1}async connect(){await this.getConnection().connect()}disconnect(t){let e=this.conn;if(e?.isConnecting()){this.stopBusyPoll(),this.clearIdleTimer(),this.activeCalls=0,this.busy&&(this.busy=!1,this.fireSessionIdle()),this.stampWeakConnectionCause(t),e.whenSettled().then(()=>{this.conn===e&&this.destroyConnection(t)});return}this.destroyConnection(t)}};async function*Pa(t){let e=t.getReader(),r=new TextDecoder,n="",s={data:[]};try{for(;;){let{done:o,value:c}=await e.read();if(o)break;n+=r.decode(c,{stream:!0});let u=ye(n,s);n=u.remaining,s=u.currentEvent;for(let l of u.events)try{yield JSON.parse(l.data)}catch{}}let i=ye(`${n}\n\n`,s);for(let o of i.events)try{yield JSON.parse(o.data)}catch{}}finally{try{await e.cancel()}catch{}e.releaseLock()}}a(Pa,"parseSSE");async function*Cs(t){let e=null;for await(let r of Pa(t))switch(r.type){case"metadata":e={mimeType:r.mimeType,size:r.size,isBinary:r.isBinary,encoding:r.encoding};break;case"chunk":if(!e)throw new Error("Received chunk before metadata");if(e.isBinary&&e.encoding==="base64"){let n=atob(r.data),s=new Uint8Array(n.length);for(let i=0;i<n.length;i++)s[i]=n.charCodeAt(i);yield s}else yield r.data;break;case"complete":if(!e)throw new Error("Stream completed without metadata");return e;case"error":throw new Error(`File streaming error: ${r.error}`)}throw new Error("Stream ended unexpectedly")}a(Cs,"streamFile");var k=class extends Error{static{a(this,"SandboxSecurityError")}constructor(t,e){super(t),this.code=e,this.name="SandboxSecurityError"}};function se(t){return!(!Number.isInteger(t)||t<1024||t>65535||[3e3].includes(t))}a(se,"validatePort");function Ir(t){if(!t||t.length>63)throw new k("Sandbox ID must be 1-63 characters long.","INVALID_SANDBOX_ID_LENGTH");if(t.startsWith("-")||t.endsWith("-"))throw new k("Sandbox ID cannot start or end with hyphens (DNS requirement).","INVALID_SANDBOX_ID_HYPHENS");let e=["www","api","admin","root","system","cloudflare","workers"],r=t.toLowerCase();if(e.includes(r))throw new k(`Reserved sandbox ID \'${t}\' is not allowed.`,"RESERVED_SANDBOX_ID");return t}a(Ir,"sanitizeSandboxId");function ka(t){if(!t)return;let e=["python","python3","javascript","js","node","typescript","ts"],r=t.toLowerCase();if(!e.includes(r))throw new k(`Unsupported language \'${t}\'. Supported languages: python, javascript, typescript`,"INVALID_LANGUAGE")}a(ka,"validateLanguage");var Na=/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/;function Da(t){if(typeof t!="string")throw new k(`Tunnel name must be a string. Received: ${typeof t}`,"INVALID_TUNNEL_NAME");if(t.length===0||t.length>63)throw new k(`Tunnel name \'${t}\' must be 1\\u201363 characters long.`,"INVALID_TUNNEL_NAME_LENGTH");if(!Na.test(t))throw new k(`Tunnel name \'${t}\' is not a valid DNS label. Use lowercase letters, digits, and internal hyphens only (no dots, no leading/trailing hyphens).`,"INVALID_TUNNEL_NAME_FORMAT")}a(Da,"validateTunnelName");var Ct=class{static{a(this,"CodeInterpreter")}getInterpreterClient;contexts=new Map;constructor(t){this.getInterpreterClient=typeof t=="function"?t:()=>t}async createCodeContext(t={}){ka(t.language);let e=await this.getInterpreterClient().createCodeContext(t);return this.contexts.set(e.id,e),e}async runCode(t,e={}){let r=e.context;if(!r){let s=e.language||"python";r=await this.getOrCreateDefaultContext(s)}let n=new zr(t,r);return await this.getInterpreterClient().runCodeStream(r.id,t,e.language,{onStdout:a(s=>{if(n.logs.stdout.push(s.text),e.onStdout)return e.onStdout(s)},"onStdout"),onStderr:a(s=>{if(n.logs.stderr.push(s.text),e.onStderr)return e.onStderr(s)},"onStderr"),onResult:a(async s=>{if(n.results.push(new Bt(s)),e.onResult)return e.onResult(s)},"onResult"),onError:a(s=>{if(n.error=s,e.onError)return e.onError(s)},"onError")}),n}async runCodeStream(t,e={}){let r=e.context;if(!r){let n=e.language||"python";r=await this.getOrCreateDefaultContext(n)}return this.getInterpreterClient().streamCode(r.id,t,e.language)}async listCodeContexts(){let t=await this.getInterpreterClient().listCodeContexts();for(let e of t)this.contexts.set(e.id,e);return t}async deleteCodeContext(t){await this.getInterpreterClient().deleteCodeContext(t),this.contexts.delete(t)}async getOrCreateDefaultContext(t){for(let e of this.contexts.values())if(e.language===t)return e;return this.createCodeContext({language:t})}};async function*Te(t,e){let r=t.getReader(),n=new TextDecoder,s="",i={data:[]},o=e?.aborted??!1,c=a(l=>{if(!(l==="[DONE]"||l.trim()===""))try{return JSON.parse(l)}catch{return}},"emitEvent"),u=a(()=>{o=!0,r.cancel().catch(()=>{})},"onAbort");e&&!e.aborted&&e.addEventListener("abort",u);try{for(;;){if(o)throw new Error("Operation was aborted");let{done:d,value:p}=await r.read();if(o)throw new Error("Operation was aborted");if(d)break;s+=n.decode(p,{stream:!0});let g=ye(s,i);s=g.remaining,i=g.currentEvent;for(let m of g.events){let f=c(m.data);f!==void 0&&(yield f)}}if(o)throw new Error("Operation was aborted");let l=ye(`${s}\n\n`,i);for(let d of l.events){let p=c(d.data);p!==void 0&&(yield p)}}finally{e&&e.removeEventListener("abort",u);try{await r.cancel()}catch{}r.releaseLock()}}a(Te,"parseSSEStream");var nt=class extends Error{static{a(this,"BucketMountError")}code;constructor(t,e=h.BUCKET_MOUNT_ERROR){super(t),this.name="BucketMountError",this.code=e}},Ze=class extends nt{static{a(this,"S3FSMountError")}constructor(t){super(t,h.S3FS_MOUNT_ERROR),this.name="S3FSMountError"}},xs=class extends nt{static{a(this,"BucketUnmountError")}constructor(t){super(t,h.BUCKET_UNMOUNT_ERROR),this.name="BucketUnmountError"}},vs=class extends nt{static{a(this,"MissingCredentialsError")}constructor(t){super(t,h.MISSING_CREDENTIALS),this.name="MissingCredentialsError"}},_=class extends nt{static{a(this,"InvalidMountConfigError")}constructor(t){super(t,h.INVALID_MOUNT_CONFIG),this.name="InvalidMountConfigError"}};function La(t,e){if(t.credentials)return t.credentials;let r=e.AWS_ACCESS_KEY_ID,n=e.AWS_SECRET_ACCESS_KEY;if(r&&n)return{accessKeyId:r,secretAccessKey:n};let s=e.R2_ACCESS_KEY_ID,i=e.R2_SECRET_ACCESS_KEY;if(s&&i)return{accessKeyId:s,secretAccessKey:i};throw new vs("No credentials found. Set R2_ACCESS_KEY_ID and R2_SECRET_ACCESS_KEY or AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables, or pass explicit credentials in options.")}a(La,"detectCredentials");function Ma(t){try{let e=new URL(t).hostname.toLowerCase();return e.endsWith(".r2.cloudflarestorage.com")?"r2":e.endsWith(".amazonaws.com")||e==="s3.amazonaws.com"?"s3":e==="storage.googleapis.com"?"gcs":null}catch{return null}}a(Ma,"detectProviderFromUrl");function Ua(t){if(!t)return["use_path_request_style"];switch(t){case"r2":return["nomixupload"];case"s3":return[];case"gcs":return[];default:return["use_path_request_style"]}}a(Ua,"getProviderFlags");function Mn(t,e){let r=Ua(t);if(!e||e.length===0)return r;let n=[...r,...e],s=new Map;for(let i of n){let[o]=i.split("=");s.set(o,i)}return Array.from(s.values())}a(Mn,"resolveS3fsOptions");function Ae(t){return typeof t=="object"&&t!==null&&"put"in t&&typeof t.put=="function"&&"get"in t&&typeof t.get=="function"&&"head"in t&&typeof t.head=="function"&&"delete"in t&&typeof t.delete=="function"&&"list"in t&&typeof t.list=="function"}a(Ae,"isR2Bucket");function Os(t){if(!t.startsWith("/"))throw new _(`Prefix must start with \'/\': "${t}"`)}a(Os,"validatePrefix");function Fa(t,e){if(t.includes(":")){let[r,n]=t.split(":");throw new _(`Bucket name cannot contain \':\'. To mount a prefix, use the \'prefix\' option:\n mountBucket(\'${r}\', \'${e}\', { ...options, prefix: \'${n}\' })`)}if(!/^[a-z0-9]([a-z0-9.-]{0,61}[a-z0-9])?$/.test(t))throw new _(`Invalid bucket name: "${t}". Bucket names must be 3-63 characters, lowercase alphanumeric, dots, or hyphens, and cannot start/end with dots or hyphens.`)}a(Fa,"validateBucketName");function Ba(t,e){if(t.includes(":")){let[r,n]=t.split(":");throw new _(`Bucket name cannot contain \':\'. To mount a prefix, use the \'prefix\' option:\n mountBucket(\'${r}\', \'${e}\', { ...options, prefix: \'${n}\' })`)}if(!/^[A-Za-z_][A-Za-z0-9_]*$/.test(t))throw new _(`Invalid R2 binding name: "${t}". Binding names must start with a letter or underscore and contain only letters, numbers, or underscores.`)}a(Ba,"validateBucketBindingName");function $a(t,e){return e?`${t}:${e}`:t}a($a,"buildS3fsSource");var Ha=1e3,Wa=2e3,Un=3e4,St=5,Ka=class{static{a(this,"LocalMountSyncManager")}bucket;mountPath;prefix;readOnly;client;sessionId;logger;pollIntervalMs;echoSuppressTtlMs;snapshot=new Map;echoSuppressSet=new Set;pollTimer=null;watchReconnectTimer=null;watchAbortController=null;running=!1;consecutivePollFailures=0;consecutiveWatchFailures=0;constructor(t){this.bucket=t.bucket,this.mountPath=t.mountPath,t.prefix!==void 0&&Os(t.prefix),this.prefix=t.prefix?.replace(/^\\//,"")||void 0,this.readOnly=t.readOnly,this.client=t.client,this.sessionId=t.sessionId,this.logger=t.logger.child({operation:"local-mount-sync"}),this.pollIntervalMs=t.pollIntervalMs??Ha,this.echoSuppressTtlMs=t.echoSuppressTtlMs??Wa}async start(){this.running=!0,await this.client.files.mkdir(this.mountPath,this.sessionId,{recursive:!0}),await this.fullSyncR2ToContainer(),this.schedulePoll(),this.readOnly||this.startContainerWatch(),this.logger.info("Local mount sync started",{mountPath:this.mountPath,prefix:this.prefix,readOnly:this.readOnly,pollIntervalMs:this.pollIntervalMs})}async stop(){this.running=!1,this.pollTimer&&(clearTimeout(this.pollTimer),this.pollTimer=null),this.watchReconnectTimer&&(clearTimeout(this.watchReconnectTimer),this.watchReconnectTimer=null),this.watchAbortController&&(this.watchAbortController.abort(),this.watchAbortController=null),this.snapshot.clear(),this.echoSuppressSet.clear(),this.logger.info("Local mount sync stopped",{mountPath:this.mountPath})}async fullSyncR2ToContainer(){let t=await this.listAllR2Objects(),e=new Map;for(let r=0;r<t.length;r+=St){let n=t.slice(r,r+St);await Promise.all(n.map(async s=>{let i=this.r2KeyToContainerPath(s.key);e.set(s.key,{etag:s.etag,size:s.size}),await this.ensureParentDir(i),await this.transferR2ObjectToContainer(s.key,i)}))}this.snapshot=e,this.logger.debug("Initial R2 -> Container sync complete",{objectCount:t.length})}schedulePoll(){if(!this.running)return;let t=this.consecutivePollFailures>0?Math.min(this.pollIntervalMs*2**this.consecutivePollFailures,Un):this.pollIntervalMs;this.pollTimer=setTimeout(async()=>{try{await this.pollR2ForChanges(),this.consecutivePollFailures=0}catch(e){this.consecutivePollFailures++,this.logger.error("R2 poll cycle failed",e instanceof Error?e:new Error(String(e)))}this.schedulePoll()},t)}async pollR2ForChanges(){let t=await this.listAllR2Objects(),e=new Map,r=[];for(let n of t){e.set(n.key,{etag:n.etag,size:n.size});let s=this.snapshot.get(n.key);(!s||s.etag!==n.etag)&&r.push({key:n.key,action:s?"modified":"created"})}for(let n=0;n<r.length;n+=St){let s=r.slice(n,n+St);await Promise.all(s.map(async({key:i,action:o})=>{try{let c=this.r2KeyToContainerPath(i);await this.ensureParentDir(c),this.suppressEcho(c),await this.transferR2ObjectToContainer(i,c),this.logger.debug("R2 -> Container: synced object",{key:i,action:o})}catch(c){this.logger.error(`R2 -> Container: failed to sync object ${i}`,c instanceof Error?c:new Error(String(c)))}}))}for(let[n]of this.snapshot)if(!e.has(n)){let s=this.r2KeyToContainerPath(n);this.suppressEcho(s);try{await this.client.files.deleteFile(s,this.sessionId),this.logger.debug("R2 -> Container: deleted file",{key:n})}catch(i){this.logger.error("R2 -> Container: failed to delete",i instanceof Error?i:new Error(String(i)))}}this.snapshot=e}async listAllR2Objects(){let t=[],e;do{let r=await this.bucket.list({...this.prefix&&{prefix:this.prefix},...e&&{cursor:e}});for(let n of r.objects)t.push({key:n.key,etag:n.etag,size:n.size});e=r.truncated?r.cursor:void 0}while(e);return t}async transferR2ObjectToContainer(t,e){let r=await this.bucket.get(t);if(!r)return;let n=await r.arrayBuffer(),s=ja(new Uint8Array(n));await this.client.files.writeFile(e,s,this.sessionId,{encoding:"base64"})}async ensureParentDir(t){let e=t.substring(0,t.lastIndexOf("/"));e&&e!==this.mountPath&&await this.client.files.mkdir(e,this.sessionId,{recursive:!0})}startContainerWatch(){this.watchAbortController=new AbortController,this.runWatchWithRetry()}runWatchWithRetry(){this.running&&this.runContainerWatchLoop().then(()=>{this.consecutiveWatchFailures=0,this.scheduleWatchReconnect()}).catch(t=>{this.running&&(this.consecutiveWatchFailures++,this.logger.error("Container watch loop failed",t instanceof Error?t:new Error(String(t))),this.scheduleWatchReconnect())})}scheduleWatchReconnect(){if(!this.running)return;let t=this.consecutiveWatchFailures>0?Math.min(this.pollIntervalMs*2**this.consecutiveWatchFailures,Un):this.pollIntervalMs;this.logger.debug("Reconnecting container watch",{backoffMs:t,failures:this.consecutiveWatchFailures}),this.watchReconnectTimer=setTimeout(()=>{this.watchReconnectTimer=null,this.running&&(this.watchAbortController=new AbortController,this.runWatchWithRetry())},t)}async runContainerWatchLoop(){let t=await this.client.watch.watch({path:this.mountPath,recursive:!0,sessionId:this.sessionId});for await(let e of Te(t,this.watchAbortController?.signal)){if(!this.running)break;if(this.consecutiveWatchFailures=0,e.type!=="event"||e.isDirectory)continue;let r=e.path;if(this.echoSuppressSet.has(r))continue;let n=this.containerPathToR2Key(r);if(n)try{switch(e.eventType){case"create":case"modify":case"move_to":await this.uploadFileToR2(r,n),this.logger.debug("Container -> R2: synced file",{path:r,key:n,action:e.eventType});break;case"delete":case"move_from":await this.bucket.delete(n),this.snapshot.delete(n),this.logger.debug("Container -> R2: deleted object",{path:r,key:n});break}}catch(s){this.logger.error(`Container -> R2 sync failed for ${r}`,s instanceof Error?s:new Error(String(s)))}}}async uploadFileToR2(t,e){let r=za((await this.client.files.readFile(t,this.sessionId,{encoding:"base64"})).content);await this.bucket.put(e,r);let n=await this.bucket.head(e);n&&this.snapshot.set(e,{etag:n.etag,size:n.size})}suppressEcho(t){this.echoSuppressSet.add(t),setTimeout(()=>{this.echoSuppressSet.delete(t)},this.echoSuppressTtlMs)}r2KeyToContainerPath(t){let e=t;return this.prefix&&(e=t.startsWith(this.prefix)?t.slice(this.prefix.length):t),Xe.join(this.mountPath,e)}containerPathToR2Key(t){let e=Xe.resolve(t),r=Xe.resolve(this.mountPath);if(!e.startsWith(r))return null;let n=Xe.relative(r,e);return!n||n.startsWith("..")?null:this.prefix?Xe.join(this.prefix,n):n}};function ja(t){return Buffer.from(t).toString("base64")}a(ja,"uint8ArrayToBase64");function za(t){return new Uint8Array(Buffer.from(t,"base64"))}a(za,"base64ToUint8Array");async function Ga(t,e,r){let n=e.url.replace("https:","http:"),s=r.beginForward();try{let i=await t.fetch(n,e);if(i.webSocket!==null)return{status:"response",response:Va(i,r,s)};if(i.body!==null){let{readable:o,writable:c}=new TransformStream;return i.body.pipeTo(c).finally(s).catch(()=>{}),{status:"response",response:new Response(o,i)}}return s(),{status:"response",response:i}}catch(i){if(s(),i instanceof Error&&i.message.includes("Network connection lost."))return{status:"network-lost"};throw i}}a(Ga,"forwardPreviewRequest");function Va(t,e,r){let n=t.webSocket;if(n===null)return r(),t;let[s,i]=Object.values(new WebSocketPair),o=!1,c=a(()=>{o||(o=!0,r())},"settle");return n.accept(),i.accept(),i.addEventListener("message",async u=>{e.renewActivity();try{let l=u.data instanceof Blob?await u.data.arrayBuffer():u.data;n.send(l)}catch{i.close(1011,"Failed to forward message to container")}}),n.addEventListener("message",async u=>{e.renewActivity();try{let l=u.data instanceof Blob?await u.data.arrayBuffer():u.data;i.send(l)}catch{n.close(1011,"Failed to forward message to client")}}),i.addEventListener("close",u=>{c();let l=u.code===1005||u.code===1006?1e3:u.code;n.close(l,u.reason)}),n.addEventListener("close",u=>{c();let l=u.code===1005||u.code===1006?1e3:u.code;i.close(l,u.reason)}),i.addEventListener("error",()=>{c(),n.close(1011,"Client WebSocket error")}),n.addEventListener("error",()=>{c(),i.close(1011,"Container WebSocket error")}),new Response(null,{status:t.status,webSocket:s,headers:t.headers})}a(Va,"bridgePreviewWebSocket");var Cr="x-sandbox-preview-proxy",xr="x-sandbox-preview-port",vr="x-sandbox-preview-token",Or="x-sandbox-preview-sandbox-id",_s=[Cr,xr,vr,Or];function qa(t){if(t.startsWith("["))return t.includes("]:")?t.substring(0,t.indexOf("]:")+1)==="[::1]":t==="[::1]";if(t==="::1")return!0;let e=t.split(":")[0];return e==="localhost"||e==="127.0.0.1"||e==="0.0.0.0"}a(qa,"isLocalhostPattern");async function _r(t,e,r,n){if(!e||typeof e!="string")throw new Error("sessionId is required for terminal access");if(r.headers.get("Upgrade")?.toLowerCase()!=="websocket")throw new Error("terminal() requires a WebSocket upgrade request");let s=new URLSearchParams({sessionId:e});n?.cols&&s.set("cols",String(n.cols)),n?.rows&&s.set("rows",String(n.rows)),n?.shell&&s.set("shell",n.shell);let i=`http://localhost/ws/pty?${s}`,o=new Request(i,r);return t.fetch(ft(o,3e3))}a(_r,"proxyTerminal");var As=class extends Error{static{a(this,"SessionInitInvalidatedError")}constructor(){super("Default session initialization was invalidated by a container stop"),this.name="SessionInitInvalidatedError"}};function Xa(t){return t instanceof As}a(Xa,"isSessionInitInvalidated");var st=\'xmlns="http://s3.amazonaws.com/doc/2006-03-01/"\',Ya=`<?xml version="1.0" encoding="UTF-8"?>\n`;function U(t){return t.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}a(U,"escapeXML");function it(t,e=200){return new Response(Ya+t,{status:e,headers:{"Content-Type":"application/xml"}})}a(it,"xmlResponse");function Nt(t){return t.replace(/^\\/+/,"")}a(Nt,"normalizeObjectKey");function Ja(t){try{return decodeURIComponent(t)}catch{return t}}a(Ja,"decodeObjectKey");function Qa(t){let e=t.length;for(;e>0&&t[e-1]==="/";)e--;return t.slice(0,e)}a(Qa,"trimTrailingSlashes");function Ps(t){if(t)return Qa(Nt(t))||void 0}a(Ps,"normalizeMountPrefix");function ks(t){let e=t.startsWith("/")?t.slice(1):t;if(!e)return null;let r=e.indexOf("/");return r===-1?{bucket:e,key:""}:{bucket:e.slice(0,r),key:Nt(e.slice(r+1))}}a(ks,"parsePath");function Ns(t,e){if(typeof t!="object"||t===null)return null;let r=t[e];return Ae(r)?r:null}a(Ns,"resolveR2Bucket");function Za(t){if(!t)return;let e=t.match(/^bytes=(\\d*)-(\\d*)$/);if(!e)return;let r=e[1]?parseInt(e[1],10):void 0,n=e[2]?parseInt(e[2],10):void 0;if(r===void 0&&n!==void 0)return{suffix:n};if(r!==void 0&&n!==void 0)return{offset:r,length:n-r+1};if(r!==void 0)return{offset:r}}a(Za,"parseRange");function ec(t,e,r,n,s){let i=s.objects.map(l=>`<Contents><Key>${U(l.key)}</Key><LastModified>${l.uploaded.toISOString()}</LastModified><ETag>${U(l.httpEtag)}</ETag><Size>${l.size}</Size><StorageClass>STANDARD</StorageClass></Contents>`).join(""),o=s.delimitedPrefixes.map(l=>`<CommonPrefixes><Prefix>${U(l)}</Prefix></CommonPrefixes>`).join(""),c=s.truncated&&s.cursor?`<NextContinuationToken>${U(s.cursor)}</NextContinuationToken>`:"",u=s.objects.length+s.delimitedPrefixes.length;return`<ListBucketResult ${st}><Name>${U(t)}</Name><Prefix>${U(e)}</Prefix><KeyCount>${u}</KeyCount><MaxKeys>${n}</MaxKeys>`+(r?`<Delimiter>${U(r)}</Delimiter>`:"")+`<IsTruncated>${s.truncated}</IsTruncated>`+c+i+o+"</ListBucketResult>"}a(ec,"buildListObjectsV2Xml");function tc(){return`<LocationConstraint ${st}/>`}a(tc,"buildLocationXml");function rc(t,e,r){return`<InitiateMultipartUploadResult ${st}><Bucket>${U(t)}</Bucket><Key>${U(e)}</Key><UploadId>${U(r)}</UploadId></InitiateMultipartUploadResult>`}a(rc,"buildInitiateMultipartUploadXml");function nc(t,e,r){return`<CompleteMultipartUploadResult ${st}><Location>http://r2.internal/${U(t)}/${U(e)}</Location><Bucket>${U(t)}</Bucket><Key>${U(e)}</Key><ETag>${U(r)}</ETag></CompleteMultipartUploadResult>`}a(nc,"buildCompleteMultipartUploadXml");function sc(t,e){return`<CopyObjectResult ${st}><LastModified>${e.toISOString()}</LastModified><ETag>${U(t)}</ETag></CopyObjectResult>`}a(sc,"buildCopyObjectXml");function Fn(t,e){let r=`<${e}>`,n=`</${e}>`,s=t.indexOf(r);if(s===-1)return null;let i=s+r.length,o=t.indexOf(n,i);return o===-1?null:t.slice(i,o)}a(Fn,"extractXmlTagContent");function ic(t){let e=[],r=0;for(;r<t.length;){let n=t.indexOf("<Part>",r);if(n===-1)break;let s=t.indexOf("</Part>",n+6);if(s===-1)break;let i=t.slice(n,s+7);r=s+7;let o=Fn(i,"PartNumber"),c=Fn(i,"ETag"),u=o?parseInt(o,10):NaN;Number.isFinite(u)&&c&&e.push({partNumber:u,etag:c.replace(/^"|"$/g,"")})}return e}a(ic,"parseCompleteMultipartUploadBody");function fr(t){let e=new Headers;return e.set("ETag",t.httpEtag),e.set("Content-Length",String(t.size)),e.set("Last-Modified",t.uploaded.toUTCString()),e.set("Accept-Ranges","bytes"),t.httpMetadata?.contentType&&e.set("Content-Type",t.httpMetadata.contentType),t.httpMetadata?.contentDisposition&&e.set("Content-Disposition",t.httpMetadata.contentDisposition),t.httpMetadata?.contentEncoding&&e.set("Content-Encoding",t.httpMetadata.contentEncoding),t.httpMetadata?.contentLanguage&&e.set("Content-Language",t.httpMetadata.contentLanguage),t.httpMetadata?.cacheControl&&e.set("Cache-Control",t.httpMetadata.cacheControl),e}a(fr,"buildResponseHeaders");function oc(t,e){if("suffix"in t)return`bytes ${Math.max(0,e-t.suffix)}-${e-1}/${e}`;let r=t.offset??0;return`bytes ${r}-${t.length!==void 0?r+t.length-1:e-1}/${e}`}a(oc,"buildContentRange");function ac(t,e){if("suffix"in t)return Math.min(t.suffix,e);let r=t.offset??0;if(r>=e)return 0;let n=t.length!==void 0?t.length:e-r;return Math.min(n,e-r)}a(ac,"getRangeContentLength");function mr(t){let e={},r=t.headers.get("Content-Type");r&&(e.contentType=r);let n=t.headers.get("Content-Disposition");n&&(e.contentDisposition=n);let s=t.headers.get("Content-Encoding");s&&(e.contentEncoding=s);let i=t.headers.get("Content-Language");i&&(e.contentLanguage=i);let o=t.headers.get("Cache-Control");return o&&(e.cacheControl=o),e}a(mr,"extractHttpMetadata");function cc(t){let e=t.split("?")[0]??"";if(!e)return null;let r=decodeURIComponent(e),n=ks(r.startsWith("/")?r:`/${r}`);return n?{bucket:n.bucket,key:Nt(n.key)}:null}a(cc,"parseCopySource");function uc(t){if(t==="Standard"||t==="InfrequentAccess")return t}a(uc,"normalizeStorageClass");async function lc(t,e,r,n){let s=r.headers.get("Content-Length"),i=s?Number.parseInt(s,10):NaN;if(!Number.isFinite(i)||i<0)return new Response("Bad Request: missing or invalid Content-Length",{status:400});if(i===0)return t.put(e,new Uint8Array(0),n);if(!r.body)return new Response("Bad Request: missing request body",{status:400});let{readable:o,writable:c}=new FixedLengthStream(i),u=r.body.pipeTo(c),l=await t.put(e,o,n);return await u,l}a(lc,"putRequestBody");async function Bn(t,e,r,n){let s=Nt(r.searchParams.get("prefix")??""),i=r.searchParams.get("delimiter")??"",o=Math.min(parseInt(r.searchParams.get("max-keys")??"1000",10)||1e3,1e3),c=r.searchParams.get("continuation-token")??void 0,u={prefix:(n?`${n}/${s}`:s)||void 0,delimiter:i||void 0,limit:o,cursor:c},l=await t.list(u),d=n?p=>p.startsWith(`${n}/`)?p.slice(n.length+1):p:p=>p;return it(ec(e,s,i,o,{objects:l.objects.map(p=>({key:d(p.key),uploaded:p.uploaded,httpEtag:p.httpEtag,size:p.size})),delimitedPrefixes:l.delimitedPrefixes.map(d),truncated:l.truncated,cursor:l.truncated?l.cursor:void 0}))}a(Bn,"handleListObjects");async function dc(t,e){let r=await t.head(e);return r?new Response(null,{status:200,headers:fr(r)}):new Response(null,{status:404})}a(dc,"handleHeadObject");async function hc(t,e,r){let n=Za(r.headers.get("Range"));if(!n){let c=await t.get(e);return c?new Response(c.body,{status:200,headers:fr(c)}):new Response(null,{status:404})}let[s,i]=await Promise.all([t.head(e),t.get(e,{range:n})]);if(!s||!i)return new Response(null,{status:404});let o=fr(i);return o.set("Content-Range",oc(n,s.size)),o.set("Content-Length",String(ac(n,s.size))),new Response(i.body,{status:206,headers:o})}a(hc,"handleGetObject");async function pc(t,e,r,n,s,i){let o=n.headers.get("x-amz-copy-source");if(o){let l=cc(o);if(!l||!l.key)return new Response("Bad Request: invalid x-amz-copy-source",{status:400});if(!Object.hasOwn(i,l.bucket))return new Response(`Access to R2 bucket "${l.bucket}" is not permitted. Call mountBucket() with this bucket before accessing it.`,{status:403});let d=i[l.bucket],p=l.bucket===e?t:Ns(s,l.bucket);if(!p)return new Response(`R2 binding "${l.bucket}" not found in Worker env. Ensure the binding name matches the bucket name passed to mountBucket().`,{status:500});let g=Ps(d.prefix),m=g?`${g}/${l.key}`:l.key,f=await p.get(m);if(!f)return new Response(null,{status:404});let w=n.headers.get("x-amz-metadata-directive")?.toUpperCase()==="REPLACE"?mr(n):f.httpMetadata,y=await t.put(r,f.body,{httpMetadata:w,customMetadata:f.customMetadata,storageClass:uc(f.storageClass)});return it(sc(y.httpEtag,y.uploaded))}let c=await lc(t,r,n,{httpMetadata:mr(n)});if(c instanceof Response)return c;let u=new Headers;return u.set("ETag",c.httpEtag),new Response(null,{status:200,headers:u})}a(pc,"handlePutObject");async function fc(t,e){return await t.delete(e),new Response(null,{status:204})}a(fc,"handleDeleteObject");async function mc(t,e,r,n){let s=mr(n);return it(rc(e,r,(await t.createMultipartUpload(r,{httpMetadata:s})).uploadId))}a(mc,"handleCreateMultipartUpload");async function gc(t,e,r,n){let s=r.searchParams.get("uploadId")??"",i=parseInt(r.searchParams.get("partNumber")??"0",10);if(!s||!i)return new Response("Bad Request: missing uploadId or partNumber",{status:400});if(!n.body)return new Response("Bad Request: missing request body",{status:400});let o=n.headers.get("Content-Length"),c=o?Number.parseInt(o,10):NaN;if(!Number.isFinite(c)||c<0)return new Response("Bad Request: missing or invalid Content-Length",{status:400});let u=t.resumeMultipartUpload(e,s),l;if(c===0)l=await u.uploadPart(i,new Uint8Array(0));else{let{readable:p,writable:g}=new FixedLengthStream(c),m=n.body.pipeTo(g);l=await u.uploadPart(i,p),await m}let d=new Headers;return d.set("ETag",`"${l.etag}"`),new Response(null,{status:200,headers:d})}a(gc,"handleUploadPart");async function wc(t,e,r,n,s){let i=n.searchParams.get("uploadId")??"";if(!i)return new Response("Bad Request: missing uploadId",{status:400});let o=ic(await s.text()).map(c=>({partNumber:c.partNumber,etag:c.etag}));return it(nc(e,r,(await t.resumeMultipartUpload(r,i).complete(o)).httpEtag))}a(wc,"handleCompleteMultipartUpload");async function yc(t,e,r){let n=r.searchParams.get("uploadId")??"";return n?(await t.resumeMultipartUpload(e,n).abort(),new Response(null,{status:204})):new Response("Bad Request: missing uploadId",{status:400})}a(yc,"handleAbortMultipartUpload");var Ar=a(async(t,e,r)=>{let n=new URL(t.url),s=ks(n.pathname);if(!s)return new Response("Bad Request: empty path",{status:400});let{bucket:i,key:o}=s,c=Ja(o);if(!r.params?.buckets||!(i in r.params.buckets))return new Response(`Access to R2 bucket "${i}" is not permitted. Call mountBucket() with this bucket before accessing it.`,{status:403});let u=r.params.buckets[i],l=Ps(u.prefix),d=u.readOnly??!1,p=Ns(e,i);if(!p)return new Response(`R2 binding "${i}" not found in Worker env. Ensure the binding name matches the bucket name passed to mountBucket().`,{status:500});let{method:g}=t;if(!c)return g==="GET"&&n.searchParams.has("location")?it(tc()):g==="GET"&&n.searchParams.get("list-type")==="2"||g==="GET"?Bn(p,i,n,l):new Response("Method Not Allowed",{status:405});let m=l?`${l}/${c}`:c;if(d&&(g==="PUT"||g==="DELETE"||g==="POST"&&(n.searchParams.has("uploads")||n.searchParams.has("uploadId"))))return new Response("Forbidden: bucket mount is read-only",{status:403});if(g==="POST"&&n.searchParams.has("uploads"))return mc(p,i,m,t);if(g==="POST"&&n.searchParams.has("uploadId"))return wc(p,i,m,n,t);if(g==="PUT"&&n.searchParams.has("partNumber")&&n.searchParams.has("uploadId"))return gc(p,m,n,t);if(g==="DELETE"&&n.searchParams.has("uploadId"))return yc(p,m,n);switch(g){case"HEAD":return dc(p,m);case"GET":return hc(p,m,t);case"PUT":return pc(p,i,m,t,e,r.params.buckets);case"DELETE":return fc(p,m);default:return new Response("Method Not Allowed",{status:405})}},"r2EgressHandler"),Ec=".s3-credential-proxy.internal",Ds="/__sandbox_credential_proxy_self_test__",Sc="/__sandbox_credential_proxy_diagnostics__",bc=1e3,Rc=2048,Tc=500,Ls=new Set(["authorization","x-amz-date","x-amz-content-sha256","x-amz-security-token","x-goog-date","x-goog-content-sha256"]),gr=new Map,rt=new Map,tt=[],wr=0;function Ye(t){gr.delete(t)}a(Ye,"evictSigV4ClientCacheEntry");function Je(t){let e=`${t}:`;for(let r of rt.keys())r.startsWith(e)&&rt.delete(r)}a(Je,"evictDirectoryMarkerCacheForMount");function Ms(t){return Array.from(new Uint8Array(t)).map(e=>e.toString(16).padStart(2,"0")).join("")}a(Ms,"toHex");async function Ic(t){return Ms(await crypto.subtle.digest("SHA-256",new TextEncoder().encode(t)))}a(Ic,"sha256Hex");async function Qe(t,e){let r=await crypto.subtle.importKey("raw",t,{name:"HMAC",hash:"SHA-256"},!1,["sign"]);return crypto.subtle.sign("HMAC",r,new TextEncoder().encode(e))}a(Qe,"hmacSHA256");function Cc(t,e){if(t==="r2")return"auto";try{let r=new URL(e).hostname,n=r.match(/s3[.-]([a-z0-9-]+)\\.amazonaws\\.com/);if(n&&n[1]!=="amazonaws")return n[1];if(r==="s3.amazonaws.com")return"us-east-1"}catch{}return"auto"}a(Cc,"detectS3Region");function xc(t){let e=new Headers;for(let[n,s]of t){let i=n.toLowerCase();!Ls.has(i)&&i!=="host"&&e.set(n,s)}let r=t.get("x-amz-content-sha256");return r&&vc(r)&&e.set("x-amz-content-sha256",r),e}a(xc,"buildCleanHeaders");function vc(t){return t==="UNSIGNED-PAYLOAD"||/^[a-fA-F0-9]{64}$/.test(t)}a(vc,"isValidContentSHA256");function Oc(t){let e=t,r=e.SANDBOX_CREDENTIAL_PROXY_DEBUG==="true",n=e.SANDBOX_CREDENTIAL_PROXY_DIAGNOSTICS_ENDPOINT==="true",s=Number(e.SANDBOX_CREDENTIAL_PROXY_SLOW_REQUEST_MS);return{diagnosticsEndpointEnabled:n,enabled:r,slowRequestMs:Number.isFinite(s)&&s>=0?s:bc}}a(Oc,"getCredentialProxyDebugConfig");function _c(t){for(tt.push(t),wr++;tt.length>Tc;)tt.shift()}a(_c,"recordCredentialProxyDiagnosticEvent");function Ac(t,e){let r=Number(t.searchParams.get("since")??"0"),n=wr-tt.length,s=tt.filter((i,o)=>i.containerId!==e?!1:!Number.isFinite(r)||n+o>=r);return Response.json({nextCursor:wr,events:s})}a(Ac,"getCredentialProxyDiagnosticsResponse");async function bt(t,e,r,n,s){let i=Date.now();try{let o=await s(),c=Date.now()-i;if(e.enabled&&_c({...t,containerId:r,durationMs:c,ok:o.ok,path:n,status:o.status,timestamp:new Date().toISOString()}),(e.enabled||c>=e.slowRequestMs)&&console.info("sandbox.s3_credential_proxy.request",{...t,durationMs:c,ok:o.ok,status:o.status,responseContentLength:o.headers.get("content-length")}),!o.ok){let u=o.clone(),l={...t};u.text().then(d=>{console.warn("sandbox.s3_credential_proxy.upstream_error",{...l,durationMs:c,status:o.status,statusText:o.statusText,errorBody:d.slice(0,Rc)})}).catch(()=>{})}return o}catch(o){let c=Date.now()-i;throw console.warn("sandbox.s3_credential_proxy.request_error",{...t,durationMs:c,error:o instanceof Error?o.message:String(o)}),o}}a(bt,"withCredentialProxyDiagnostics");function Pc(t,e,r,n,s){let i=gr.get(t);if(i&&i.accessKeyId===n.accessKeyId&&i.secretAccessKey===n.secretAccessKey&&i.endpoint===e&&i.provider===r&&i.region===s)return i.client;let o=new Ke({accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey,service:"s3",region:s,retries:0});return gr.set(t,{client:o,accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey,endpoint:e,provider:r,region:s}),o}a(Pc,"getSigV4Client");function yr(t){return encodeURIComponent(t).replace(/[!\'()*]/g,e=>`%${e.charCodeAt(0).toString(16).toUpperCase()}`)}a(yr,"encodeCanonicalQueryPart");function kc(t){return t.pathname.split("/").map(e=>e.split(/(%[0-9A-Fa-f]{2})/g).map(r=>/^%[0-9A-Fa-f]{2}$/.test(r)?r.toUpperCase():yr(r)).join("")).join("/")}a(kc,"getCanonicalURI");function Nc(t){let e=t.search.startsWith("?")?t.search.slice(1):t.search;return e?e.split("&").map(r=>{let n=r.indexOf("=");return n===-1?[r,""]:[r.slice(0,n),r.slice(n+1)]}).map(([r,n])=>[yr($n(r)),yr($n(n))]).sort(([r,n],[s,i])=>r<s?-1:r>s?1:n<i?-1:n>i?1:0).map(([r,n])=>`${r}=${n}`).join("&"):""}a(Nc,"getCanonicalQueryString");function $n(t){try{return decodeURIComponent(t)}catch{return t}}a($n,"decodeURIEncodedQueryPart");function Er(t){let e=t.get("x-amz-content-sha256");return e&&e!=="UNSIGNED-PAYLOAD"?{hash:e,mode:"signed"}:{hash:"UNSIGNED-PAYLOAD",mode:"unsigned"}}a(Er,"getSigV4PayloadHash");function Dc(t,e){return t.method.toUpperCase()==="PUT"&&t.headers.get("content-length")==="0"&&e.endsWith("/")}a(Dc,"isZeroLengthDirectoryMarkerPUT");function Lc(t){return t.method.toUpperCase()==="HEAD"}a(Lc,"isDirectoryMarkerHEAD");function Sr(t,e){return`${t}:${e.replace(/\\/+$/,"")}`}a(Sr,"getDirectoryMarkerCacheKey");function Mc(t){let e=[["Accept-Ranges","bytes"],["Content-Length","0"],["ETag",\'"d41d8cd98f00b204e9800998ecf8427e"\'],["Last-Modified",new Date().toUTCString()]],r=t.headers.get("content-type");r&&e.push(["Content-Type",r]);for(let[n,s]of t.headers)n.toLowerCase().startsWith("x-amz-meta-")&&e.push([n,s]);return e}a(Mc,"getDirectoryMarkerResponseHeaders");function Us(t){if(t)return t.replace(/^\\/+/,"").replace(/\\/+$/,"")}a(Us,"normalizePrefix");function Fs(t,e){let r=t.split("/").filter(Boolean);return r[0]!==e?null:r.slice(1).join("/")}a(Fs,"getObjectKeyForPath");function br(t,e){let r=Us(e);return r?t===r||t.startsWith(`${r}/`):!0}a(br,"isObjectKeyWithinPrefix");function Uc(t){let e=t.split("?",1)[0];if(!e)return null;let r;try{r=decodeURIComponent(e)}catch{return null}let n=r.startsWith("/")?r.slice(1):r,s=n.indexOf("/");return s<=0||s===n.length-1?null:{bucket:n.slice(0,s),objectKey:n.slice(s+1)}}a(Uc,"parseCopySourceHeader");function Fc(t,e,r){let n=[["x-amz-copy-source",t.get("x-amz-copy-source")],["x-goog-copy-source",t.get("x-goog-copy-source")]].filter(c=>c[1]!==null);if(n.length>1)return new Response("Bad Request: multiple copy source headers",{status:400});if(n.length===0)return null;let[s,i]=n[0],o=Uc(i);return o?o.bucket!==e||!br(o.objectKey,r)?new Response("Forbidden: copy source is outside mounted scope",{status:403}):null:new Response(`Bad Request: invalid ${s}`,{status:400})}a(Fc,"validateCopySourceWithinMountScope");function Bc(t,e,r,n){let s=Fs(t,r);if(s===null)return!1;let i=e.searchParams.get("prefix");return s!==""&&!br(s,n)||s===""&&Us(n)!==void 0&&e.search!==""&&i===null?!1:i!==null?br(i,n):!0}a(Bc,"isRequestWithinMountScope");function $c(t,e,r,n){let s=t.method.toUpperCase();return(s==="GET"||s==="HEAD")&&r.search===""&&Fs(e,n)===""}a($c,"isBucketRootProbe");function Hc(t,e){rt.delete(Sr(t,e))}a(Hc,"deleteDirectoryMarkerCacheEntry");function Bs(t){let e=t.headers.get("content-length");if(e===null)return null;let r=Number(e);return!Number.isSafeInteger(r)||r<0?null:r}a(Bs,"getContentLength");function Wc(t){let e=Bs(t);if(e===0)return{body:new Uint8Array(0)};if(e===null||t.body===null)return{};let{readable:r,writable:n}=new FixedLengthStream(e);return t.body.pipeTo(n).catch(s=>{n.abort(s).catch(()=>{})}),{body:r}}a(Wc,"getSigV4ForwardInit");function Kc(t){let e=new Headers;for(let[r,n]of t.headers){let s=r.toLowerCase();if(!(Ls.has(s)||s==="host"||s==="content-length"||s==="expect")){if(s.startsWith("x-amz-meta-")){e.set(`x-goog-meta-${s.slice(11)}`,n);continue}s.startsWith("x-amz-")||e.set(r,n)}}return e}a(Kc,"getGCSHeaders");async function Hn(t,e,r,n,s,i){let o=Date.now(),c=Cc(n,r),u=Er(t.headers),l=Pc(e,r,n,s,c);i.payloadHashMode=u.mode,i.clientSetupMs=Date.now()-o;let d=Date.now(),p=Wc(t);i.bodyPresent=p?.body!==void 0||t.body!==null;let g=await l.fetch(t,p);return i.upstreamMs=Date.now()-d,g}a(Hn,"signAndForwardSigV4");async function Wn(t,e,r){let n=new URL(t.url),s=Kc(t),i=`${new Date().toISOString().replace(/[:-]/g,"").replace(/\\.\\d+Z$/,"")}Z`,o=i.slice(0,8),c="auto",u="storage",l=`${o}/${c}/${u}/goog4_request`,d="UNSIGNED-PAYLOAD",p=[["host",n.host],["x-goog-content-sha256",d],["x-goog-date",i]];for(let[I,C]of s)p.push([I.toLowerCase(),C.trim()]);p.sort((I,C)=>I[0].localeCompare(C[0]));let g=p.map(([I])=>I).join(";"),m=p.map(([I,C])=>`${I}:${C}\n`).join(""),f=["GOOG4-HMAC-SHA256",i,l,await Ic([t.method,kc(n),Nc(n),m,g,d].join(`\n`))].join(`\n`),w=Ms(await Qe(await Qe(await Qe(await Qe(await Qe(new TextEncoder().encode(`GOOG4${e.secretAccessKey}`),o),c),u),"goog4_request"),f)),y=`GOOG4-HMAC-SHA256 Credential=${e.accessKeyId}/${l}, SignedHeaders=${g}, Signature=${w}`,E=new Headers(s);E.set("x-goog-date",i),E.set("x-goog-content-sha256",d),E.set("Authorization",y);let T=Bs(t)===0?new Uint8Array(0):t.body,x=Date.now(),b=await fetch(new Request(t.url,{method:t.method,headers:E,body:T}));return r.upstreamMs=Date.now()-x,b}a(Wn,"signAndForwardGCS");var Pr=a(async(t,e,r)=>{let n=new URL(t.url);if(n.pathname===Ds)return new Response("OK",{status:200});let s=Oc(e);if(n.pathname===Sc)return!s.enabled||!s.diagnosticsEndpointEnabled?new Response("Not Found",{status:404}):Ac(n,r.containerId);let i=n.pathname.split("/").filter(Boolean),o=n.hostname,c,u;if(o.endsWith(Ec)?(c=o.slice(0,-29),u=n.pathname):(c=i[0]??null,u=c&&n.pathname.slice(`/${c}`.length)||"/"),!c)return new Response("Bad Request: missing mount ID",{status:400});let l=r.params?.mounts[c];if(!l)return new Response(`Forbidden: unknown mount ID "${c}"`,{status:403});if(l.readOnly){let w=t.method.toUpperCase();if(w!=="GET"&&w!=="HEAD"&&w!=="OPTIONS")return new Response("Forbidden: bucket mount is read-only",{status:403})}let d=new URL(u+(n.search||""),l.endpoint);if($c(t,u,n,l.bucket))return new Response(null,{status:200});if(!Bc(u,n,l.bucket,l.prefix))return new Response("Forbidden: request is outside mounted bucket scope",{status:403});let p=Fc(t.headers,l.bucket,l.prefix);if(p)return p;let g=xc(t.headers),m=new Request(d.toString(),{method:t.method,headers:g,body:t.body}),f={authStrategy:l.authStrategy,bucket:l.bucket,contentLength:t.headers.get("content-length"),method:t.method,mountId:c,query:[...n.searchParams.keys()].sort()};if(Dc(m,u)){let w=Mc(m);return f.bodyPresent=t.body!==null,l.authStrategy==="s3-sigv4"&&(f.payloadHashMode=Er(m.headers).mode),bt(f,s,r.containerId,u,async()=>{let y=l.authStrategy==="gcs"?await Wn(m,l.credentials,f):await Hn(m,c,l.endpoint,l.provider,l.credentials,f);return y.ok&&rt.set(Sr(c,u),w),y})}if(Lc(m)){let w=rt.get(Sr(c,u));if(w)return f.bodyPresent=!1,l.authStrategy==="s3-sigv4"&&(f.payloadHashMode=Er(m.headers).mode),bt(f,s,r.containerId,u,()=>Promise.resolve(new Response(null,{status:200,headers:w})))}return m.method.toUpperCase()!=="HEAD"&&Hc(c,u),l.authStrategy==="gcs"?bt(f,s,r.containerId,u,()=>Wn(m,l.credentials,f)):bt(f,s,r.containerId,u,()=>Hn(m,c,l.endpoint,l.provider,l.credentials,f))},"s3CredentialProxyHandler"),jc="https://api.cloudflare.com/client/v4/user/tokens/verify",Kn="https://api.cloudflare.com/client/v4/accounts",zc=1e4;async function At(t,e,r,n=zc){try{return await t(e,{...r,signal:AbortSignal.timeout(n)})}catch(s){throw s instanceof Error&&s.name==="TimeoutError"?new Error(`Cloudflare API request to ${e} timed out after ${n}ms`):s}}a(At,"fetchWithTimeout");var Gc=1e3;async function Vc(t,e){let r=D(t,e.overrideKey);if(r)return r;let n=D(t,"CLOUDFLARE_ACCOUNT_ID");if(n)return n;let s=D(t,"CLOUDFLARE_API_TOKEN");if(!s)throw new Error(`Cloudflare account id could not be resolved. Set one of: ${e.overrideKey}, CLOUDFLARE_ACCOUNT_ID, or CLOUDFLARE_API_TOKEN (a token scoped to a single account).`);let i=e.fetcher??fetch,o=await At(i,jc,{method:"GET",headers:{authorization:`Bearer ${s}`,"content-type":"application/json"}}),c;try{c=await o.json()}catch(u){let l=u instanceof Error?u.message:String(u);throw new Error(`Cloudflare token verification returned malformed JSON: ${l}`)}if(o.ok&&c?.success){let u=c.result_info?.account?.id;if(!u)throw new Error(`Cloudflare token is not scoped to a single account (ambiguous). Set ${e.overrideKey} or CLOUDFLARE_ACCOUNT_ID explicitly.`);return u}if(c?.errors?.some(u=>u.code===Gc))return await qc(s,i,e);throw new Error(`Cloudflare token verification failed with status ${o.status}. Check that CLOUDFLARE_API_TOKEN is valid or set ${e.overrideKey} / CLOUDFLARE_ACCOUNT_ID explicitly.`)}a(Vc,"resolveAccountId");async function qc(t,e,r){let n=await At(e,`${Kn}?per_page=2`,{method:"GET",headers:{authorization:`Bearer ${t}`,"content-type":"application/json"}}),s;try{s=await n.json()}catch(l){let d=l instanceof Error?l.message:String(l);throw new Error(`Cloudflare account-owned token: /accounts returned malformed JSON: ${d}`)}if(!n.ok||!s?.success)throw new Error(`Cloudflare account-owned token (cfat-...) detected, but /accounts returned status ${n.status}. The token may lack account:read scope. Set CLOUDFLARE_ACCOUNT_ID explicitly to skip introspection.`);let i=s.result??[];if(i.length===0)throw new Error("Cloudflare account-owned token has access to no accounts. Set CLOUDFLARE_ACCOUNT_ID explicitly.");if(i.length>1)throw new Error("Cloudflare account-owned token has access to multiple accounts (ambiguous). Set CLOUDFLARE_ACCOUNT_ID explicitly to disambiguate.");let o=i[0]?.id;if(!o)throw new Error("Cloudflare /accounts returned a result without an id field.");let c=await At(e,`${Kn}/${encodeURIComponent(o)}/tokens/verify`,{method:"GET",headers:{authorization:`Bearer ${t}`,"content-type":"application/json"}}),u;try{u=await c.json()}catch(l){let d=l instanceof Error?l.message:String(l);throw new Error(`Cloudflare account token verify returned malformed JSON: ${d}`)}if(!c.ok||!u?.success){let l=u?.errors?.map(d=>`${d.code}: ${d.message}`).join("; ")??`HTTP ${c.status}`;throw new Error(`Cloudflare account token verify failed for account ${o}: ${l}`)}return o}a(qc,"deriveAccountIdViaAccountToken");var Xc="https://api.cloudflare.com/client/v4/zones";async function Yc(t,e){let r=D(t,"CLOUDFLARE_ZONE_ID");if(r)return r;let n=await At(e.fetcher??fetch,`${Xc}?account.id=${encodeURIComponent(e.accountId)}&per_page=2`,{method:"GET",headers:{authorization:`Bearer ${e.token}`,"content-type":"application/json"}});if(!n.ok)throw new Error(`Cloudflare zones lookup failed with status ${n.status}. Set CLOUDFLARE_ZONE_ID explicitly or grant the API token Zone:Read.`);let s;try{s=await n.json()}catch(c){let u=c instanceof Error?c.message:String(c);throw new Error(`Cloudflare zones lookup returned malformed JSON: ${u}`)}let i=s.result??[];if(i.length===0)throw new Error(`Cloudflare API token has access to no zones in account ${e.accountId}. Set CLOUDFLARE_ZONE_ID explicitly or grant the token Zone:Read on the intended zone.`);if(i.length>1)throw new Error(`Cloudflare API token has access to multiple zones in account ${e.accountId} (ambiguous). Set CLOUDFLARE_ZONE_ID explicitly to disambiguate.`);let o=i[0]?.id;if(!o)throw new Error("Cloudflare zones lookup returned a result without an id field.");return o}a(Yc,"resolveZoneId");var Jc=class extends Tn{static{a(this,"SandboxControlCallbackImpl")}constructor(t,e){super(),this.getHandler=t,this.logger=e}async onTunnelExit(t,e,r,n){let s=this.getHandler();if(!s){this.logger.debug("onTunnelExit: no handler bound; ignoring",{id:t,port:e,exitCode:r,runId:n});return}await s(t,e,r,n)}},fe="https://api.cloudflare.com/client/v4",Qc=1e4;async function me(t,e,r,n={}){let s=n.timeoutMs??Qc,i={method:n.method??"GET",headers:{authorization:`Bearer ${e}`,"content-type":"application/json"},signal:AbortSignal.timeout(s)};n.body!==void 0&&(i.body=JSON.stringify(n.body));let o;try{o=await r(t,i)}catch(u){throw u instanceof Error&&u.name==="TimeoutError"?new Error(`Cloudflare API request to ${t} timed out after ${s}ms`):u}if(n.acceptStatuses?.includes(o.status))return;let c;try{c=await o.json()}catch(u){let l=u instanceof Error?u.message:String(u);throw new Error(`Cloudflare API returned non-JSON response (status ${o.status}): ${l}`)}if(!o.ok||c.success===!1){let u=c.errors??[],l=u.length?u.map(d=>`${d.code??"???"}: ${d.message??"unknown"}`).join(", "):`HTTP ${o.status}`;throw new Error(`Cloudflare API error: ${l}`)}return c.result}a(me,"cfRequest");function Zc(t){if(!(t instanceof Error))return!1;let e=t.message.toLowerCase();return e.includes("9300")&&e.includes("tag")?!0:e.includes("tag")?e.includes("quota")||e.includes("enterprise")||e.includes("not allowed")||e.includes("not entitled")||e.includes("not available")||e.includes("not supported"):!1}a(Zc,"isEnterpriseOnlyTagError");function eu(t){if(t)return[`sandboxId:${t}`]}a(eu,"buildSandboxTags");async function $s(t,e){let r=eu(t);if(!r)return e(void 0);try{return await e(r)}catch(n){if(!Zc(n))throw n;return e(void 0)}}a($s,"createWithTagFallback");async function tu(t){let e=t.fetcher??fetch,r=await $s(t.metadata.sandboxId,n=>me(`${fe}/accounts/${encodeURIComponent(t.accountId)}/cfd_tunnel`,t.token,e,{method:"POST",body:{name:t.tunnelName,config_src:"cloudflare",metadata:t.metadata,...n?{tags:n}:{}}}));if(!r)throw new Error("Cloudflare tunnel create returned no result body");return{id:r.id,token:r.token}}a(tu,"createTunnel");async function ru(t){let e=t.fetcher??fetch,r=await me(`${fe}/accounts/${encodeURIComponent(t.accountId)}/cfd_tunnel?name=${encodeURIComponent(t.tunnelName)}&is_deleted=false`,t.token,e);if(!r)return null;let n=r.find(s=>!s.deleted_at);return!n||t.expectedSandboxId!==void 0&&n.metadata?.sandboxId!==t.expectedSandboxId?null:{id:n.id,name:n.name}}a(ru,"findTunnelByName");async function nu(t){let e=t.fetcher??fetch;await me(`${fe}/accounts/${encodeURIComponent(t.accountId)}/cfd_tunnel/${encodeURIComponent(t.tunnelId)}`,t.token,e,{method:"DELETE",acceptStatuses:[404]})}a(nu,"deleteTunnel");async function su(t){let e=t.fetcher??fetch,r=await me(`${fe}/accounts/${encodeURIComponent(t.accountId)}/cfd_tunnel/${encodeURIComponent(t.tunnelId)}/token`,t.token,e);if(typeof r!="string"||r.length===0)throw new Error(`Cloudflare did not return a token for tunnel ${t.tunnelId}`);return r}a(su,"getTunnelToken");async function iu(t){let e=t.fetcher??fetch,r=await me(`${fe}/zones/${encodeURIComponent(t.zoneId)}`,t.token,e);if(!r?.name)throw new Error(`Cloudflare zone ${t.zoneId} did not return a name`);return r.name}a(iu,"getZoneName");async function ou(t){let e=t.fetcher??fetch,r=(await me(`${fe}/zones/${encodeURIComponent(t.zoneId)}/dns_records?type=CNAME&name=${encodeURIComponent(t.hostname)}`,t.token,e)??[]).find(s=>s.type==="CNAME"&&s.name===t.hostname);if(r){if(r.content===t.cnameTarget)return{recordId:r.id,reused:!0};throw new Error(`DNS record for ${t.hostname} already exists with different content (owned by you, not us): existing content="${r.content}", existing comment="${r.comment??""}". Delete the record manually to allow the sandbox to manage it.`)}let n=await $s(t.sandboxId,s=>me(`${fe}/zones/${encodeURIComponent(t.zoneId)}/dns_records`,t.token,e,{method:"POST",body:{type:"CNAME",name:t.hostname,content:t.cnameTarget,proxied:!0,comment:t.comment,...s?{tags:s}:{}}}));if(!n)throw new Error("Cloudflare DNS create returned no result body");return{recordId:n.id,reused:!1}}a(ou,"upsertCNAME");async function au(t){let e=t.fetcher??fetch;await me(`${fe}/zones/${encodeURIComponent(t.zoneId)}/dns_records/${encodeURIComponent(t.recordId)}`,t.token,e,{method:"DELETE",acceptStatuses:[404]})}a(au,"deleteDNSRecord");var cu="0123456789abcdefghjkmnpqrstvwxyz";function Hs(t=20){let e=new Uint8Array(t);crypto.getRandomValues(e);let r="";for(let n=0;n<t;n+=1)r+=cu[e[n]&31];return r}a(Hs,"randomId");var jn=2;function uu(){return`run-${Hs()}`}a(uu,"runtimeRunId");function xt(t){return new Q({message:t.reason==="recovery_exhausted"?"Tunnel recovery attempts were exhausted":"Tunnel operation was interrupted by a sandbox runtime change",code:h.OPERATION_INTERRUPTED,httpStatus:409,context:{reason:t.reason,operation:"tunnel.get",phase:t.phase,admitted:t.admitted,retryable:t.retryable,...t.recoveryAttempts!==void 0&&{recoveryAttempts:t.recoveryAttempts},...t.maxRecoveryAttempts!==void 0&&{maxRecoveryAttempts:t.maxRecoveryAttempts}},timestamp:new Date().toISOString(),suggestion:t.retryable?"Retry tunnels.get() for the same port so the SDK can establish a fresh tunnel run.":"Start a new tunnels.get() call only if this tunnel is still desired for the current sandbox."})}a(xt,"createTunnelInterruptedError");function Rt(t,e,r){return t instanceof Q?t:t instanceof _t?xt({reason:"runtime_replaced",phase:e,admitted:r,retryable:!0}):t instanceof Tr?xt({reason:"sandbox_lifetime_changed",phase:e,admitted:r,retryable:!1}):t instanceof kt?xt({reason:"transport_disposed",phase:e,admitted:"unknown",retryable:!0}):null}a(Rt,"translateTunnelInterruption");var pe="tunnels",ie="tunnels:meta";async function J(t){return await t.get(pe)??{}}a(J,"readMap");async function ne(t){return await t.get(ie)??{}}a(ne,"readMetaMap");function zn(t){return!t||!t.name?"v1:quick":`v1:named:${t.name}`}a(zn,"computeOptionsHash");function Gn(t){return t.startsWith("v1:")?t.slice(3):t}a(Gn,"normaliseHash");function lu(t,e){return Gn(t)===Gn(e)}a(lu,"optionsHashesEqual");async function Vn(t){await t.transaction(async e=>{let r=await J(e),n=await ne(e),s={},i={};for(let[o,c]of Object.entries(r))c.name&&(s[o]=c,i[o]={...n[o]??{optionsHash:`v1:named:${c.name}`},needsRespawn:!0});await e.put(pe,s),await e.put(ie,i)})}a(Vn,"pruneTunnelsForRestart");function du(t){if(!se(t))throw new k(`Invalid port number: ${t}. Must be 1024-65535, excluding reserved ports.`)}a(du,"validateTunnelPort");function hu(){let t=new Uint8Array(4);return crypto.getRandomValues(t),Array.from(t).map(e=>e.toString(16).padStart(2,"0")).join("")}a(hu,"shortId");function Ws(t,e){if(!t||typeof t!="object")return!1;let r=t;return r.code===e||r.errorResponse?.code===e}a(Ws,"hasErrorCode");function qn(t){return Ws(t,"TUNNEL_NOT_FOUND")}a(qn,"isTunnelNotFoundError");function pu(t){return Ws(t,"TUNNEL_ALREADY_RUNNING")}a(pu,"isTunnelAlreadyRunningError");var fu=class extends oo{static{a(this,"TunnelsRpcTarget")}#e;#t;#r=null;constructor(t,e){super(),this.#e=t,this.#t=e}async#n(t){if(!this.#r){let e=iu({token:t.token,zoneId:t.zoneId,fetcher:this.#e.fetcher});this.#r=e,e.catch(()=>{this.#r===e&&(this.#r=null)})}return this.#r}async get(t,e){let r=Date.now(),n="error",s="miss",i;try{du(t),e?.name!==void 0&&Da(e.name);let o=zn(e),c=await this.#t(t,()=>this.#o(t,e,async u=>{let l=(await J(this.#e.storage))[t.toString()];if(l){let d=(await ne(this.#e.storage))[t.toString()];if(!lu(d?.optionsHash??(l.name?`v1:named:${l.name}`:"v1:quick"),o))throw new Error(`Tunnel on port ${t} was created with different options. Call destroy(${t}) before changing tunnel options.`);if(!l.name&&await this.#i(d))return await this.#a(l,d),await this.#u(t,u);if(d?.needsRespawn&&l.name)return await this.#c(t,l.name);if(l.name&&this.#e.getNamedTunnelConfig){let p=await this.#e.getNamedTunnelConfig(),g=d?.accountId,m=d?.zoneId;if(g!==void 0&&g!==p.accountId||m!==void 0&&m!==p.zoneId)return this.#r=null,await this.#c(t,l.name)}return s="hit",l}return e?.name?await this.#c(t,e.name):await this.#u(t,u)}));return n="success",c}catch(o){throw i=o instanceof Error?o:new Error(String(o)),o}finally{N(this.#e.logger,{event:"tunnel.get",outcome:n,port:t,cacheState:s,durationMs:Date.now()-r,error:i})}}async#o(t,e,r){let n=0,s={};for(;;)try{return await r(s)}catch(i){let o=Rt(i,"provisioning","unknown");if(!o||e?.name||!o.context.retryable)throw i;if(n>=jn)throw await this.#s(t),xt({reason:"recovery_exhausted",phase:"interrupted",admitted:o.context.admitted,retryable:!1,recoveryAttempts:n,maxRecoveryAttempts:jn});n++,o.context.reason==="runtime_replaced"&&(s.quickRun=void 0),await this.#s(t)}}async#s(t){await this.#e.storage.transaction(async e=>{let r=await J(e);delete r[t.toString()],await e.put(pe,r);let n=await ne(e);delete n[t.toString()],await e.put(ie,n)})}async#i(t){if(!this.#e.currentRuntime||!this.#e.currentLifetime)return!1;if(!t?.runtimeIdentityID||!t.sandboxLifetimeID)return!0;let e=await this.#e.currentRuntime.get(),r=await this.#e.currentLifetime.getOrCreate();return e?.id!==t.runtimeIdentityID||r.id!==t.sandboxLifetimeID}async#a(t,e){try{e?.tunnelRunId?await this.#e.client.tunnels.stopTunnelRun({tunnelId:t.id,runId:e.tunnelRunId}):await this.#e.client.tunnels.destroyTunnel(t.id)}catch(r){if(!qn(r))throw r}}async#u(t,e){if(this.#e.currentRuntime&&this.#e.currentLifetime)return await this.#l(t,e);let r=3,n;for(let s=0;s<r;s+=1){let i=`quick-${hu()}`;try{let o=await this.#e.client.tunnels.runQuickTunnel(i,t);return await this.#e.storage.transaction(async c=>{let u=await J(c);u[t.toString()]=o,await c.put(pe,u);let l=await ne(c);l[t.toString()]={optionsHash:"v1:quick"},await c.put(ie,l)}),o}catch(o){if(!pu(o))throw o;n=o}}throw n??new Error("Failed to mint a unique quick-tunnel id")}async#l(t,e){if(!this.#e.currentRuntime||!this.#e.currentLifetime)throw new Error("Quick tunnel runtime fences are not configured");let r=await this.#e.currentLifetime.getOrCreate(),n=await this.#e.currentRuntime.get();try{await this.#e.currentLifetime.assertCurrent(r)}catch(d){throw Rt(d,"runtime_ready","unknown")??d}e.quickRun??={tunnelId:`quick-${Hs()}`,runId:uu()};let{tunnelId:s,runId:i}=e.quickRun,o,c=n;try{o=await this.#e.client.tunnels.ensureTunnelRun({tunnelId:s,runId:i,mode:"quick",port:t}),c??=await this.#e.currentRuntime.get()??await this.#e.currentRuntime.markStarted(),await this.#e.currentRuntime.assertActive(c),await this.#e.currentLifetime.assertCurrent(r)}catch(d){throw Rt(d,"runtime_ready","unknown")??d}let{run:u}=o;if(!u.url||!u.hostname)throw new Error("Quick tunnel run did not produce a public URL");let l={id:u.tunnelId,port:u.port,url:u.url,hostname:u.hostname,createdAt:u.startedAt};await this.#e.storage.transaction(async d=>{let p=await J(d);p[t.toString()]=l,await d.put(pe,p);let g=await ne(d);g[t.toString()]={optionsHash:"v1:quick",runtimeIdentityID:c.id,sandboxLifetimeID:r.id,tunnelRunId:u.runId},await d.put(ie,g)});try{await this.#e.currentRuntime.assertActive(c),await this.#e.currentLifetime.assertCurrent(r)}catch(d){throw Rt(d,"storage_committed",!0)??d}return l}async#c(t,e){if(!this.#e.sandboxId)throw new Error("Named tunnels require host.sandboxId on the tunnels handler.");if(!this.#e.getNamedTunnelConfig)throw new Error("Named tunnels require host.getNamedTunnelConfig on the tunnels handler.");let r=await this.#e.getNamedTunnelConfig(),n=`${e}.${await this.#n({token:r.token,zoneId:r.zoneId})}`,s=this.#e.sandboxId,i=`sandbox-${s}-${e}`,o,c,u=await ru({token:r.token,accountId:r.accountId,tunnelName:i,expectedSandboxId:s,fetcher:this.#e.fetcher});if(u)o=u.id,c=await su({token:r.token,accountId:r.accountId,tunnelId:o,fetcher:this.#e.fetcher});else{let p=await tu({token:r.token,accountId:r.accountId,tunnelName:i,metadata:{sandboxId:s,createdBy:"sandbox-sdk",name:e,port:t},fetcher:this.#e.fetcher});o=p.id,c=p.token}let l=await ou({token:r.token,zoneId:r.zoneId,hostname:n,cnameTarget:`${o}.cfargotunnel.com`,comment:`sandbox-${s}`,sandboxId:s,fetcher:this.#e.fetcher});await this.#e.client.tunnels.runNamedTunnel(o,c,t);let d={id:o,port:t,name:e,hostname:n,url:`https://${n}`,createdAt:new Date().toISOString()};return await this.#e.storage.transaction(async p=>{let g=await J(p);g[t.toString()]=d,await p.put(pe,g);let m=await ne(p);m[t.toString()]={optionsHash:zn({name:e}),dnsRecordId:l.recordId,accountId:r.accountId,zoneId:r.zoneId},await p.put(ie,m)}),d}async destroy(t){let e=typeof t=="number"?t:t.port,r=Date.now(),n="error",s,i;try{await this.#t(e,async()=>{let o=(await J(this.#e.storage))[e.toString()];if(!o)return;i=o.id;let c=(await ne(this.#e.storage))[e.toString()];await this.#e.storage.transaction(async g=>{let m=await J(g);delete m[e.toString()],await g.put(pe,m);let f=await ne(g);delete f[e.toString()],await g.put(ie,f)});try{c?.tunnelRunId?await this.#e.client.tunnels.stopTunnelRun({tunnelId:o.id,runId:c.tunnelRunId}):await this.#e.client.tunnels.destroyTunnel(o.id)}catch(g){if(!qn(g))if(c?.dnsRecordId)this.#e.logger.warn("tunnel.destroy: container tunnel cleanup failed",{port:e,tunnelId:i,error:g instanceof Error?g.message:String(g)});else throw g}if(!c?.dnsRecordId||!this.#e.getNamedTunnelConfig)return;let u;try{u=await this.#e.getNamedTunnelConfig()}catch(g){this.#e.logger.warn("tunnel.destroy: skipping CF cleanup, credentials unavailable",{port:e,tunnelId:i,dnsRecordId:c.dnsRecordId,error:g instanceof Error?g.message:String(g)});return}let l=this.#e.fetcher,d=c.accountId??u.accountId,p=c.zoneId??u.zoneId;await Promise.allSettled([c.dnsRecordId?au({token:u.token,zoneId:p,recordId:c.dnsRecordId,fetcher:l}).catch(g=>{this.#e.logger.warn("tunnel.destroy: dns delete failed",{port:e,tunnelId:i,recordId:c.dnsRecordId,zoneId:p,error:g instanceof Error?g.message:String(g)})}):Promise.resolve(),nu({token:u.token,accountId:d,tunnelId:o.id,fetcher:l}).catch(g=>{this.#e.logger.warn("tunnel.destroy: tunnel delete failed",{port:e,tunnelId:i,accountId:d,error:g instanceof Error?g.message:String(g)})})])}),n="success"}catch(o){throw s=o instanceof Error?o:new Error(String(o)),o}finally{N(this.#e.logger,{event:"tunnel.destroy",outcome:n,port:e,tunnelId:i,durationMs:Date.now()-r,error:s})}}async list(){let t=await J(this.#e.storage);return Object.values(t)}};function mu(t){let e=new Map,r=a((o,c)=>{let u=(e.get(o)??Promise.resolve()).then(c,c);return e.set(o,u.catch(()=>{})),u},"withPortLock"),n=new fu(t,r);return{tunnels:n,handleTunnelExit:a(async(o,c,u,l)=>{let d=Date.now(),p="error",g;try{await r(c,async()=>{await t.storage.transaction(async m=>{let f=await J(m),w=f[c.toString()];if(w?.id!==o)return;let y=await ne(m),E=y[c.toString()];if(!(l&&E?.tunnelRunId&&E.tunnelRunId!==l)){if(w.name){y[c.toString()]={...E,optionsHash:E?.optionsHash??`v1:named:${w.name}`,needsRespawn:!0},await m.put(ie,y);return}delete f[c.toString()],await m.put(pe,f),delete y[c.toString()],await m.put(ie,y)}})}),p="success"}catch(m){throw g=m instanceof Error?m:new Error(String(m)),m}finally{N(t.logger,{event:"tunnel.exit",outcome:p,port:c,tunnelId:o,exitCode:u??void 0,durationMs:Date.now()-d,error:g})}},"handleTunnelExit"),destroyAll:a(async()=>{let o=await J(t.storage),c=Object.keys(o).map(u=>Number(u));for(let u of c)try{await n.destroy(u)}catch(l){t.logger.warn("tunnels.destroyAll: destroy(port) failed",{port:u,error:l instanceof Error?l.message:String(l)})}},"destroyAll")}}a(mu,"createTunnelsHandler");var gu="0.12.9",Tt="portTokens",It="activePreviewPorts",et="ContainerProxy",lr="s3-credential-proxy.internal",wu="s3-credential-proxy.sandbox.test",Ks=class extends xe{static{a(this,"ContainerProxyOutboundTarget")}};Object.defineProperty(Ks,"name",{value:et});Ks.outboundHandlers={r2EgressMount:Ar,s3CredentialProxyMount:Pr};var js=class extends $e{static{a(this,"ContainerProxy$1")}async fetch(t){let e=new URL(t.url).hostname,r=this.ctx.props,n=r.outboundByHostOverrides?.[e];if(n){let s={containerId:r.containerId??"",className:r.className??"",params:n.params};if(n.method==="r2EgressMount")return Ar(t,this.env,s);if(n.method==="s3CredentialProxyMount")return Pr(t,this.env,s)}return super.fetch(t)}};function Xn(t){return typeof t=="object"&&t!==null&&"fetch"in t&&typeof t.fetch=="function"}a(Xn,"isFetcher");var Yn=new WeakMap,zs={stat_cache_expire:"60",enable_noobj_cache:!0,multipart_size:"5"},yu=Object.entries(zs).map(([t,e])=>e===!0?t:`${t}=${e}`),Eu=` Expect:\n`,Jn=259200,Su=8e3,ve=256,Y="/var/backups",z="backups",Oe="data.sqsh",_e="meta.json",bu="lz4",Ru=8,Tu=10*1024*1024,Iu=16,Cu=5*1024*1024,xu=64,vu=8,Ou=10*1024*1024,_u=64;function Qn(t,e,r){return t<100*1024*1024?e:t<1024*1024*1024?Math.min(32,e*2):r}a(Qn,"calculatePartCount");function Au(t,...e){let r=t[0];for(let n=0;n<e.length;n++)r+=S(String(e[n]))+t[n+1];return r}a(Au,"sh");function Pu(t){let e=new Uint8Array(t);return crypto.getRandomValues(e),Array.from(e,r=>r.toString(16).padStart(2,"0")).join("")}a(Pu,"randomHex");function dr(t){let e={};for(let r of t){let n=r.indexOf("=");n===-1?e[r]=!0:e[r.slice(0,n)]=r.slice(n+1)}return e}a(dr,"parseS3fsOptions");function Zn(t){return Object.entries(t).filter(([,e])=>e!==!1).map(([e,r])=>r===!0?e:`${e}=${r}`).join(",")}a(Zn,"serializeS3fsOptions");function ku(t){let e=Yn.get(t);if(e)return e;let r=new Map;return Yn.set(t,r),r}a(ku,"getNamespaceConfigurationCache");function Nu(t,e){return t?.instanceGetTimeoutMS===e?.instanceGetTimeoutMS&&t?.portReadyTimeoutMS===e?.portReadyTimeoutMS&&t?.waitIntervalMS===e?.waitIntervalMS}a(Nu,"sameContainerTimeouts");function Gs(t,e){if(t===e)return!0;if(!t||!e)return!1;let r=Object.entries(t),n=Object.entries(e);if(r.length!==n.length)return!1;for(let[s,i]of r)if(e[s]!==i)return!1;return!0}a(Gs,"sameLabels");function Pt(t){return{...t}}a(Pt,"cloneLabels");function Du(t,e,r){let n={};return(r?.sandboxName!==t||r.normalizeId!==e?.normalizeId)&&(n.sandboxName={name:t,normalizeId:e?.normalizeId}),e?.sleepAfter!==void 0&&r?.sleepAfter!==e.sleepAfter&&(n.sleepAfter=e.sleepAfter),e?.keepAlive!==void 0&&r?.keepAlive!==e.keepAlive&&(n.keepAlive=e.keepAlive),e?.containerTimeouts&&!Nu(r?.containerTimeouts,e.containerTimeouts)&&(n.containerTimeouts=e.containerTimeouts),e?.transport!==void 0&&r?.transport!==e.transport&&(n.transport=e.transport),e?.labels!==void 0&&!Gs(r?.labels,e.labels)&&(n.labels=Pt(e.labels)),n}a(Du,"buildSandboxConfiguration");function Lu(t){return t.sandboxName!==void 0||t.sleepAfter!==void 0||t.keepAlive!==void 0||t.containerTimeouts!==void 0||t.transport!==void 0||t.labels!==void 0}a(Lu,"hasSandboxConfiguration");function Mu(t,e){return{...t,...e.sandboxName&&{sandboxName:e.sandboxName.name,normalizeId:e.sandboxName.normalizeId},...e.sleepAfter!==void 0&&{sleepAfter:e.sleepAfter},...e.keepAlive!==void 0&&{keepAlive:e.keepAlive},...e.containerTimeouts!==void 0&&{containerTimeouts:e.containerTimeouts},...e.transport!==void 0&&{transport:e.transport},...e.labels!==void 0&&{labels:Pt(e.labels)}}}a(Mu,"mergeSandboxConfiguration");function Uu(t,e){if(t.configure)return t.configure(e);let r=[];return e.sandboxName&&r.push(t.setSandboxName?.(e.sandboxName.name,e.sandboxName.normalizeId)??Promise.resolve()),e.sleepAfter!==void 0&&r.push(t.setSleepAfter?.(e.sleepAfter)??Promise.resolve()),e.keepAlive!==void 0&&r.push(t.setKeepAlive?.(e.keepAlive)??Promise.resolve()),e.containerTimeouts!==void 0&&r.push(t.setContainerTimeouts?.(e.containerTimeouts)??Promise.resolve()),e.transport!==void 0&&r.push(t.setTransport?.(e.transport)??Promise.resolve()),e.labels!==void 0&&r.push(t.setLabels?.(e.labels)??Promise.resolve()),Promise.all(r).then(()=>{})}a(Uu,"applySandboxConfiguration");function Fu(t,e){if(!Ts(t))return null;let r={reason:"runtime_replaced",operation:e,phase:"durable_object_call",admitted:"unknown",retryable:!1};return new Q({code:h.OPERATION_INTERRUPTED,message:`Sandbox operation ${e} was interrupted while the platform was updating the sandbox runtime`,context:r,httpStatus:F(h.OPERATION_INTERRUPTED),suggestion:W(h.OPERATION_INTERRUPTED,r),timestamp:new Date().toISOString()},{cause:t})}a(Fu,"createPlatformInterruptedError");function es(t,e){throw Fu(t,e)??t}a(es,"translatePlatformInterruption");function ts(t,e){return(...r)=>{try{let n=e(...r);return n!=null&&typeof n.then=="function"?n.catch(s=>es(s,t)):n}catch(n){es(n,t)}}}a(ts,"withSandboxOperationContext");function kr(t,e,r){let n=Ir(e),s=r?.normalizeId?n.toLowerCase():n,i=/[A-Z]/.test(n);!r?.normalizeId&&i&&dt({component:"sandbox-do"}).warn(`Sandbox ID "${n}" contains uppercase letters, which causes issues with preview URLs (hostnames are case-insensitive). normalizeId will default to true in a future version to prevent this. Use lowercase IDs or pass { normalizeId: true } to prepare.`);let o=Xt(t,s),c=ku(t),u=c.get(s),l=Du(s,r,u);if(Lu(l)){let m=Mu(u,l);c.set(s,m),Uu(o,l).catch(()=>{if(u){c.set(s,u);return}c.delete(s)})}let d=`sandbox-${s}`,p=r?.enableDefaultSession!==!1,g={fetch:a(m=>o.fetch(m),"fetch"),exec:a((m,f)=>p?o.exec(m,f):o.execWithSessionToken(m,O,f),"exec"),startProcess:a((m,f)=>p||f?.sessionId!==void 0?o.startProcess(m,f):o.startProcess(m,{...f,sessionId:O}),"startProcess"),listProcesses:a(m=>p||m!==void 0?o.listProcesses(m):o.listProcesses(O),"listProcesses"),getProcess:a((m,f)=>p||f!==void 0?o.getProcess(m,f):o.getProcess(m,O),"getProcess"),execStream:a((m,f)=>p||f?.sessionId!==void 0?o.execStream(m,f):o.execStreamWithSessionToken(m,O,f),"execStream"),writeFile:a((m,f,w={})=>p||w.sessionId!==void 0?o.writeFile(m,f,w):o.writeFile(m,f,{...w,sessionId:O}),"writeFile"),readFile:a((m,f={})=>{let w=p||f.sessionId!==void 0?f:{...f,sessionId:O};return w.encoding==="none",o.readFile(m,w)},"readFile"),readFileStream:a((m,f={})=>p||f.sessionId!==void 0?o.readFileStream(m,f):o.readFileStream(m,{sessionId:O}),"readFileStream"),mkdir:a((m,f={})=>p||f.sessionId!==void 0?o.mkdir(m,f):o.mkdir(m,{...f,sessionId:O}),"mkdir"),deleteFile:a(m=>p?o.deleteFile(m):o.deleteFile(m,O),"deleteFile"),renameFile:a((m,f)=>p?o.renameFile(m,f):o.renameFile(m,f,O),"renameFile"),moveFile:a((m,f)=>p?o.moveFile(m,f):o.moveFile(m,f,O),"moveFile"),listFiles:a((m,f)=>p||f?.sessionId!==void 0?o.listFiles(m,f):o.listFiles(m,{...f,sessionId:O}),"listFiles"),exists:a((m,f)=>p||f!==void 0?o.exists(m,f):o.exists(m,O),"exists"),gitCheckout:a((m,f)=>p||f?.sessionId!==void 0?o.gitCheckout(m,f):o.gitCheckout(m,{...f,sessionId:O}),"gitCheckout"),createSession:a(async m=>rs(o,await o.createSession(m)),"createSession"),getSession:a(async m=>rs(o,await o.getSession(m)),"getSession"),watch:a((m,f={})=>p||f.sessionId!==void 0?o.watch(m,f):o.watch(m,{...f,sessionId:O}),"watch"),checkChanges:a((m,f={})=>p||f.sessionId!==void 0?o.checkChanges(m,f):o.checkChanges(m,{...f,sessionId:O}),"checkChanges"),terminal:a((m,f)=>_r(o,d,m,f),"terminal"),wsConnect:Bu(o),tunnels:new Proxy({},{get:a((m,f)=>{if(!(typeof f!="string"||f==="then"))return ts(`sandbox.tunnels.${f}`,(...w)=>o.callTunnels(f,w))},"get")})};return new Proxy(o,{get(m,f){if(typeof f=="string"&&f in g){let w=g[f];return typeof w=="function"?ts(`sandbox.${f}`,w):w}return m[f]}})}a(kr,"getSandbox");function rs(t,e){return{...e,terminal:a((r,n)=>_r(t,e.id,r,n),"terminal")}}a(rs,"enhanceSession");function Bu(t){return async(e,r)=>{if(!se(r))throw new k(`Invalid port number: ${r}. Must be 1024-65535, excluding 3000 (sandbox control plane).`);let n=ft(e,r);return await t.fetch(n)}}a(Bu,"connect");var Nr=class te extends xe{static{a(this,"Sandbox")}defaultPort=3e3;sleepAfter="10m";client;codeInterpreter;sandboxName=null;tunnelsHandler=null;tunnelExitHandler=null;destroyAllTunnels=null;controlCallback;normalizeId=!1;defaultSession=null;containerGeneration=0;defaultSessionInit=null;envVars={};logger;keepAliveEnabled=!1;activeMounts=new Map;mountOperationQueue=Promise.resolve();currentRuntime;currentLifetime;transport="http";hasStoredTransport=!1;backupBucket=null;backupInProgress=Promise.resolve();r2AccessKeyId=null;r2SecretAccessKey=null;r2AccountId=null;backupBucketName=null;backupBucketEndpoint=null;r2Client=null;tunnelAccountIdPromise=null;tunnelZoneIdPromise=null;DEFAULT_CONTAINER_TIMEOUTS={instanceGetTimeoutMS:3e4,portReadyTimeoutMS:9e4,waitIntervalMS:300};containerTimeouts={...this.DEFAULT_CONTAINER_TIMEOUTS};hasStoredContainerTimeouts=!1;async callTunnels(e,r){if(!["get","list","destroy"].includes(e))throw new Error(`Unknown tunnels method: ${e}`);let n=this.tunnels,s=n[e];if(typeof s!="function")throw new Error(`sandbox.tunnels missing method: ${e}`);return s.apply(n,r)}computeRetryTimeoutMs(){let e=this.containerTimeouts.instanceGetTimeoutMS+this.containerTimeouts.portReadyTimeoutMS;return Math.max(12e4,e+3e4)}createSandboxClient(){return new bs({logger:this.logger,port:3e3,stub:this,retryTimeoutMs:this.computeRetryTimeoutMs(),defaultHeaders:{"X-Sandbox-Id":this.ctx.id.toString()},...this.transport==="websocket"&&{transportMode:"websocket",wsUrl:"ws://localhost:3000/ws"}})}createClientForTransport(e){if(e==="rpc"){let r=this;return new Aa({stub:this,port:3e3,logger:this.logger,retryTimeoutMs:this.computeRetryTimeoutMs(),getSandboxInfo:a(()=>({id:this.ctx.id.toString(),name:this.sandboxName??void 0}),"getSandboxInfo"),startContainer:a(()=>this.startContainerForRPC(),"startContainer"),localMain:this.controlCallback,onActivity:a(()=>{this.renewActivityTimeout()},"onActivity"),onSessionBusy:a(()=>{r.inflightRequests++},"onSessionBusy"),onSessionIdle:a(()=>{r.inflightRequests=Math.max(0,r.inflightRequests-1),r.inflightRequests===0&&this.renewActivityTimeout()},"onSessionIdle")})}return this.createSandboxClient()}constructor(e,r){super(e,r);let n=r;["SANDBOX_LOG_LEVEL","SANDBOX_LOG_FORMAT"].forEach(c=>{n?.[c]&&(this.envVars[c]=String(n[c]))}),this.containerTimeouts=this.getDefaultTimeouts(n),this.logger=dt({component:"sandbox-do",sandboxId:this.ctx.id.toString()}),this.currentRuntime=new ta(this.ctx.storage,()=>this.getState(),()=>this.ctx.container?.running===!0),this.currentLifetime=new ra(this.ctx.storage);let s=n?.SANDBOX_TRANSPORT;s==="websocket"||s==="rpc"?this.transport=s:s!=null&&s!=="http"&&this.logger.warn(`Invalid SANDBOX_TRANSPORT value: "${s}". Must be "http", "websocket", or "rpc". Defaulting to "http".`),this.logger.info(`Using ${this.transport} transport`);let i=n?.BACKUP_BUCKET;Ae(i)&&(this.backupBucket=i),this.r2AccountId=D(n,"CLOUDFLARE_R2_ACCOUNT_ID")??D(n,"CLOUDFLARE_ACCOUNT_ID")??null,this.r2AccessKeyId=D(n,"R2_ACCESS_KEY_ID")??null,this.r2SecretAccessKey=D(n,"R2_SECRET_ACCESS_KEY")??null,this.backupBucketName=D(n,"BACKUP_BUCKET_NAME")??null;let o=D(n,"BACKUP_BUCKET_ENDPOINT")??null;if(o!==null){let c;try{c=new URL(o)}catch{let u=`BACKUP_BUCKET_ENDPOINT is not a valid URL: "${o}". Expected format: https://<account_id>.eu.r2.cloudflarestorage.com`;throw new v({message:u,code:h.INVALID_BACKUP_CONFIG,httpStatus:400,context:{reason:u},timestamp:new Date().toISOString()})}if(c.protocol!=="https:"){let u=`BACKUP_BUCKET_ENDPOINT must use https://, got "${c.protocol.slice(0,-1)}://"`;throw new v({message:u,code:h.INVALID_BACKUP_CONFIG,httpStatus:400,context:{reason:u},timestamp:new Date().toISOString()})}if(c.pathname!=="/"){let u=`BACKUP_BUCKET_ENDPOINT must not include a path (got "${c.pathname}"). Provide only the origin, e.g. https://<account_id>.eu.r2.cloudflarestorage.com`;throw new v({message:u,code:h.INVALID_BACKUP_CONFIG,httpStatus:400,context:{reason:u},timestamp:new Date().toISOString()})}if(c.search!==""||c.hash!==""){let u="BACKUP_BUCKET_ENDPOINT must not include query parameters or fragments. Provide only the origin, e.g. https://<account_id>.eu.r2.cloudflarestorage.com";throw new v({message:u,code:h.INVALID_BACKUP_CONFIG,httpStatus:400,context:{reason:u},timestamp:new Date().toISOString()})}this.backupBucketEndpoint=c.origin}else this.backupBucketEndpoint=null;this.r2AccessKeyId&&this.r2SecretAccessKey&&(this.r2Client=new Ke({accessKeyId:this.r2AccessKeyId,secretAccessKey:this.r2SecretAccessKey})),this.controlCallback=new Jc(()=>this.tunnelExitHandler,this.logger),this.client=this.createClientForTransport(this.transport),this.codeInterpreter=new Ct(()=>this.client.interpreter),this.ctx.blockConcurrencyWhile(async()=>{this.sandboxName=await this.ctx.storage.get("sandboxName")??null,this.normalizeId=await this.ctx.storage.get("normalizeId")??!1,this.defaultSession=await this.ctx.storage.get("defaultSession")??null,this.keepAliveEnabled=await this.ctx.storage.get("keepAliveEnabled")??!1;let c=await this.ctx.storage.get("containerTimeouts");c&&(this.containerTimeouts={...this.containerTimeouts,...c},this.hasStoredContainerTimeouts=!0,this.client.setRetryTimeoutMs(this.computeRetryTimeoutMs()));let u=await this.ctx.storage.get("sleepAfter");u!==void 0&&(this.sleepAfter=u,this.renewActivityTimeout());let l=await this.ctx.storage.get("transport");if(l&&l!==this.transport){this.transport=l;let p=this.client;this.client=this.createClientForTransport(l),this.codeInterpreter=new Ct(()=>this.client.interpreter),this.tunnelsHandler=null,this.tunnelExitHandler=null,this.destroyAllTunnels=null,p.disconnect(this.buildDisconnectCause("runtime_replaced","The sandbox transport was switched while the operation was pending."))}l&&(this.hasStoredTransport=!0);let d=await this.ctx.storage.get("labels");d!=null&&(this.labels=Pt(d)),this.interceptHttps&&(this.envVars={...this.envVars,SANDBOX_INTERCEPT_HTTPS:"1"})})}async setSandboxName(e,r){if(this.sandboxName!==null)return;let n=r??!1;await Promise.all([this.ctx.storage.put("sandboxName",e),this.ctx.storage.put("normalizeId",n)]),this.sandboxName=e,this.normalizeId=n}async configure(e){e.sandboxName&&await this.setSandboxName(e.sandboxName.name,e.sandboxName.normalizeId),e.sleepAfter!==void 0&&await this.setSleepAfter(e.sleepAfter),e.keepAlive!==void 0&&await this.setKeepAlive(e.keepAlive),e.containerTimeouts!==void 0&&await this.setContainerTimeouts(e.containerTimeouts),e.transport!==void 0&&await this.setTransport(e.transport),e.labels!==void 0&&await this.setLabels(e.labels)}async setSleepAfter(e){this.sleepAfter!==e&&(await this.ctx.storage.put("sleepAfter",e),this.sleepAfter=e,this.renewActivityTimeout())}async setKeepAlive(e){this.keepAliveEnabled!==e&&(await this.ctx.storage.put("keepAliveEnabled",e),this.keepAliveEnabled=e,e||this.renewActivityTimeout())}async setEnvVars(e){let{toSet:r,toUnset:n}=Ft(e);for(let s of n)delete this.envVars[s];if(this.envVars={...this.envVars,...r},this.defaultSession){for(let s of n){let i=`unset ${s}`,o=await this.client.commands.execute(i,this.defaultSession,{origin:"internal"});if(o.exitCode!==0)throw new Error(`Failed to unset ${s}: ${o.stderr||"Unknown error"}`)}for(let[s,i]of Object.entries(r)){let o=`export ${s}=${S(i)}`,c=await this.client.commands.execute(o,this.defaultSession,{origin:"internal"});if(c.exitCode!==0)throw new Error(`Failed to set ${s}: ${c.stderr||"Unknown error"}`)}}}async setContainerTimeouts(e){let r={...this.containerTimeouts};e.instanceGetTimeoutMS!==void 0&&(r.instanceGetTimeoutMS=this.validateTimeout(e.instanceGetTimeoutMS,"instanceGetTimeoutMS",5e3,3e5)),e.portReadyTimeoutMS!==void 0&&(r.portReadyTimeoutMS=this.validateTimeout(e.portReadyTimeoutMS,"portReadyTimeoutMS",1e4,6e5)),e.waitIntervalMS!==void 0&&(r.waitIntervalMS=this.validateTimeout(e.waitIntervalMS,"waitIntervalMS",100,5e3)),!(this.hasStoredContainerTimeouts&&r.instanceGetTimeoutMS===this.containerTimeouts.instanceGetTimeoutMS&&r.portReadyTimeoutMS===this.containerTimeouts.portReadyTimeoutMS&&r.waitIntervalMS===this.containerTimeouts.waitIntervalMS)&&(await this.ctx.storage.put("containerTimeouts",r),this.containerTimeouts=r,this.hasStoredContainerTimeouts=!0,this.client.setRetryTimeoutMs(this.computeRetryTimeoutMs()),this.logger.debug("Container timeouts updated",this.containerTimeouts))}async setTransport(e){if(e!=="http"&&e!=="websocket"&&e!=="rpc"){this.logger.warn(`Invalid transport value: "${e}". Must be "http", "websocket", or "rpc". Ignoring.`);return}if(this.hasStoredTransport&&this.transport===e)return;await this.ctx.storage.put("transport",e);let r=this.client;this.transport=e,this.hasStoredTransport=!0,this.client=this.createClientForTransport(e),this.codeInterpreter=new Ct(()=>this.client.interpreter),this.tunnelsHandler=null,this.tunnelExitHandler=null,this.destroyAllTunnels=null,r.disconnect(this.buildDisconnectCause("runtime_replaced","The sandbox transport was switched while the operation was pending.")),this.renewActivityTimeout(),this.logger.debug("Transport updated",{transport:e})}async setLabels(e){let r=Pt(e);Gs(this.labels,r)||(await this.ctx.storage.put("labels",r),this.labels=r,this.ctx.container?.running===!0&&this.logger.warn("Container labels updated while container is running; new labels apply on the next container start"))}validateTimeout(e,r,n,s){if(typeof e!="number"||Number.isNaN(e)||!Number.isFinite(e))throw new Error(`${r} must be a valid finite number, got ${e}`);if(e<n||e>s)throw new Error(`${r} must be between ${n}-${s}ms, got ${e}ms`);return e}getDefaultTimeouts(e){let r=a((n,s,i,o)=>{let c=this.DEFAULT_CONTAINER_TIMEOUTS[s];if(n===void 0)return c;let u=parseInt(n,10);return Number.isNaN(u)?(this.logger.warn(`Invalid ${s}: "${n}" is not a number. Using default: ${c}ms`),c):u<i||u>o?(this.logger.warn(`Invalid ${s}: ${u}ms. Must be ${i}-${o}ms. Using default: ${c}ms`),c):u},"parseAndValidate");return{instanceGetTimeoutMS:r(D(e,"SANDBOX_INSTANCE_TIMEOUT_MS"),"instanceGetTimeoutMS",5e3,3e5),portReadyTimeoutMS:r(D(e,"SANDBOX_PORT_TIMEOUT_MS"),"portReadyTimeoutMS",1e4,6e5),waitIntervalMS:r(D(e,"SANDBOX_POLL_INTERVAL_MS"),"waitIntervalMS",100,5e3)}}async mountBucket(e,r,n){return this.runMountOperation(async()=>{await this.mountBucketUnlocked(e,r,n)})}async runMountOperation(e){let r=this.mountOperationQueue,n;this.mountOperationQueue=new Promise(s=>{n=s}),await r.catch(()=>{});try{await e()}finally{n()}}async mountBucketUnlocked(e,r,n){if(n.prefix!==void 0&&Os(n.prefix),"localBucket"in n&&n.localBucket){await this.mountBucketLocal(e,r,n);return}let s=n;if(s.endpoint===void 0){let i=this.env[e];if(Ae(i)){await this.mountBucketR2Egress(e,r,n);return}throw new _(`R2 binding "${e}" not found in Worker env. Ensure the binding name matches the bucket binding configured in wrangler.jsonc.`)}await this.mountBucketFuse(e,r,s)}async mountBucketLocal(e,r,n){let s=Date.now(),i="error",o;try{let c=this.env[e];if(!c||!Ae(c))throw new _(`R2 binding "${e}" not found in env or is not an R2Bucket. Make sure the binding name matches your wrangler.jsonc R2 binding.`);if(!r||!r.startsWith("/"))throw new _(`Invalid mount path: "${r}". Must be an absolute path starting with /`);if(this.activeMounts.has(r))throw new _(`Mount path already in use: ${r}`);let u=await this.ensureDefaultSession(),l=new Ka({bucket:c,mountPath:r,prefix:n.prefix,readOnly:n.readOnly??!1,client:this.client,sessionId:u,logger:this.logger}),d={mountId:crypto.randomUUID(),mountType:"local-sync",bucket:e,mountPath:r,syncManager:l,mounted:!1};this.activeMounts.set(r,d);try{await l.start(),d.mounted=!0}catch(p){throw await l.stop(),this.activeMounts.delete(r),p}i="success"}catch(c){throw o=c instanceof Error?c:new Error(String(c)),c}finally{N(this.logger,{event:"bucket.mount",outcome:i,durationMs:Date.now()-s,bucket:e,mountPath:r,provider:"local-sync",prefix:n.prefix,error:o})}}getR2EgressParams(){let e={};for(let[,r]of this.activeMounts)r.mountType==="r2-egress"&&(e[r.bucket]={prefix:r.prefix,readOnly:r.readOnly});return{buckets:e}}validateProtectedS3fsOptions(e,r,n=[]){if(!e)return;let s=new Set(["passwd_file","url",...n]);for(let i of e){let[o]=i.split("=");if(s.has(o))throw new _(`s3fs option "${o}" cannot be overridden for ${r} mounts`)}}getS3CredentialProxyParams(e){let r={};for(let[,n]of this.activeMounts)if(n.mountType==="fuse"&&n.credentialProxy){if(n.mountId===e?.excludeMountId)continue;r[n.mountId]={endpoint:n.credentialProxy.endpoint,bucket:n.credentialProxy.bucket,...n.credentialProxy.prefix!==void 0?{prefix:n.credentialProxy.prefix}:{},credentials:n.credentialProxy.credentials,readOnly:n.credentialProxy.readOnly,provider:n.credentialProxy.provider,authStrategy:n.credentialProxy.authStrategy}}return{mounts:r}}resolveCredentialProxyAuthStrategy(e){return e==="gcs"?"gcs":"s3-sigv4"}async mountBucketR2Egress(e,r,n){let s=Date.now(),i=n.prefix,o="error",c,u,l;try{Ba(e,r),this.validateMountPath(r),this.validateProtectedS3fsOptions(n.s3fsOptions,"R2 binding");for(let[y,E]of this.activeMounts){if(E.mountType==="r2-egress"&&E.bucket===e&&E.prefix!==i)throw new _(`R2 binding "${e}" is already mounted at ${y} with a different prefix. Mount the same binding only once, or use the same prefix for additional mounts.`);if(E.mountType==="r2-egress"&&E.bucket===e&&E.readOnly!==(n.readOnly??!1))throw new _(`R2 binding "${e}" is already mounted at ${y} with a different readOnly setting. Mount the same binding only once, or use the same readOnly value for additional mounts.`)}u=this.generatePasswordFilePath(),l=this.generateS3FSAdditionalHeaderFilePath(),await this.createPasswordFile(u,e,{accessKeyId:"x",secretAccessKey:"x"}),await this.createDisableExpectHeaderFile(l);let d={mountId:crypto.randomUUID(),mountType:"r2-egress",bucket:e,mountPath:r,passwordFilePath:u,additionalHeaderFilePath:l,mounted:!1,prefix:i,readOnly:n.readOnly??!1};this.activeMounts.set(r,d),await this.configureR2EgressOutbound(this.getR2EgressParams()),await this.execInternal(`mkdir -p ${S(r)}`);let p=e,g=S(Zn({passwd_file:u,...zs,...dr(Mn("r2",n.s3fsOptions)),use_path_request_style:!0,url:"http://r2.internal",ahbe_conf:l,...n.readOnly?{ro:!0}:{}})),m=`s3fs ${S(p)} ${S(r)} -o ${g}`;this.logger.debug("r2-egress: running s3fs",{mountCmd:m});let f=await this.execInternal(m);if(this.logger.debug("r2-egress: s3fs exited",{exitCode:f.exitCode,stdout:f.stdout,stderr:f.stderr}),f.exitCode!==0)throw new Ze(`S3FS mount failed: ${f.stderr||f.stdout||"Unknown error"}`);let w=await this.execInternal(`mountpoint -q ${S(r)} && echo \'FUSE_MOUNTED\' || echo \'NOT_FUSE_MOUNTED\'`);if(this.logger.debug("r2-egress: mountpoint check",{stdout:w.stdout.trim(),exitCode:w.exitCode}),w.stdout.trim()!=="FUSE_MOUNTED")throw new Ze(`s3fs exited 0 but mount was not established at ${r}`);d.mounted=!0,o="success"}catch(d){c=d instanceof Error?d:new Error(String(d));let p=this.activeMounts.get(r);this.activeMounts.delete(r),p?.mountType==="r2-egress"?(await this.deletePasswordFile(p.passwordFilePath).catch(()=>{}),p.additionalHeaderFilePath&&await this.deleteAdditionalHeaderFile(p.additionalHeaderFilePath).catch(()=>{})):(u&&await this.deletePasswordFile(u).catch(()=>{}),l&&await this.deleteAdditionalHeaderFile(l).catch(()=>{}));let g=this.getR2EgressParams();throw await this.configureR2EgressOutbound(g).catch(()=>{}),d}finally{N(this.logger,{event:"bucket.mount",outcome:o,durationMs:Date.now()-s,bucket:e,mountPath:r,provider:"r2",prefix:i,error:c})}}async mountBucketFuse(e,r,n){let s=Date.now(),i=n.prefix,o="error",c,u,l,d=null,p=!0;try{this.validateMountOptions(e,r,{...n,prefix:i});let g=$a(e,i);d=n.provider||Ma(n.endpoint),this.logger.debug(`Detected provider: ${d||"unknown"}`,{explicitProvider:n.provider,prefix:i});let m=this.env,f=La(n,{AWS_ACCESS_KEY_ID:D(m,"AWS_ACCESS_KEY_ID"),AWS_SECRET_ACCESS_KEY:D(m,"AWS_SECRET_ACCESS_KEY"),R2_ACCESS_KEY_ID:this.r2AccessKeyId||void 0,R2_SECRET_ACCESS_KEY:this.r2SecretAccessKey||void 0,...this.envVars}),w=n.credentialProxy===!0;w&&this.validateProtectedS3fsOptions(n.s3fsOptions,"credential proxy",["ahbe_conf","use_path_request_style"]),u=this.generatePasswordFilePath(),w&&(l=this.generateS3FSAdditionalHeaderFilePath());let y=crypto.randomUUID(),E={mountId:y,mountType:"fuse",bucket:g,mountPath:r,endpoint:n.endpoint,provider:d,passwordFilePath:u,...l?{additionalHeaderFilePath:l}:{},mounted:!1,...w?{credentialProxy:{endpoint:n.endpoint,bucket:e,...i!==void 0?{prefix:i}:{},credentials:f,readOnly:n.readOnly??!1,provider:d,authStrategy:this.resolveCredentialProxyAuthStrategy(d)}}:{}};this.activeMounts.set(r,E),await this.createPasswordFile(u,e,w?{accessKeyId:"x",secretAccessKey:"x"}:f),w&&(l&&await this.createDisableExpectHeaderFile(l),await this.configureS3CredentialProxyOutbound(this.getS3CredentialProxyParams())),p=(await this.execInternal(`test -d ${S(r)}`)).exitCode===0,await this.execInternal(`mkdir -p ${S(r)}`);let T=w?{...n,endpoint:`http://${lr}/${y}`,s3fsOptions:[...d==="r2"?yu:[],...n.s3fsOptions??[],...l?[`ahbe_conf=${l}`]:[],"use_path_request_style"]}:n;await this.executeS3FSMount(g,r,T,d,u),E.mounted=!0,o="success"}catch(g){c=g instanceof Error?g:new Error(String(g));try{await this.execInternal(`mountpoint -q ${S(r)} && fusermount -u ${S(r)}`)}catch{}if(u&&await this.deletePasswordFile(u),l&&await this.deleteAdditionalHeaderFile(l),!p)try{await this.execInternal(`rmdir ${S(r)} 2>/dev/null`)}catch{}let m=this.activeMounts.get(r);if(m?.mountType==="fuse"&&m.credentialProxy)try{await this.configureS3CredentialProxyOutbound(this.getS3CredentialProxyParams({excludeMountId:m.mountId})),this.activeMounts.delete(r),Ye(m.mountId),Je(m.mountId)}catch(f){this.logger.warn("credential proxy cleanup failed",{mountPath:r,error:f instanceof Error?f.message:String(f)}),this.activeMounts.delete(r),Ye(m.mountId),Je(m.mountId)}else this.activeMounts.delete(r);throw g}finally{N(this.logger,{event:"bucket.mount",outcome:o,durationMs:Date.now()-s,bucket:e,mountPath:r,provider:d||"unknown",prefix:i,error:c})}}async unmountBucket(e){return this.runMountOperation(async()=>{await this.unmountBucketUnlocked(e)})}async unmountBucketUnlocked(e){let r=Date.now(),n="error",s,i=this.activeMounts.get(e);try{if(!i)throw new _(`No active mount found at path: ${e}`);if(i.mountType==="local-sync")await i.syncManager.stop(),i.mounted=!1,this.activeMounts.delete(e);else if(i.mountType==="fuse"&&i.credentialProxy&&!i.mounted){try{await this.configureS3CredentialProxyOutbound(this.getS3CredentialProxyParams({excludeMountId:i.mountId}))}catch(o){this.logger.warn("credential proxy outbound reconfiguration failed on unmount",{mountPath:e,error:o instanceof Error?o.message:String(o)})}this.activeMounts.delete(e),Ye(i.mountId),Je(i.mountId)}else{let o=!1;try{let c=await this.execInternal(`fusermount -u ${S(e)}`);if(c.exitCode!==0){let u=c.stderr||"unknown error";throw new xs(`fusermount -u failed (exit ${c.exitCode}): ${u}`)}if(o=!0,i.mounted=!1,i.mountType==="r2-egress"){let u={};for(let[,l]of this.activeMounts)l.mountType==="r2-egress"&&l.mountId!==i.mountId&&(u[l.bucket]={prefix:l.prefix,readOnly:l.readOnly});try{await this.configureR2EgressOutbound({buckets:u})}catch(l){this.logger.warn("r2 egress outbound reconfiguration failed on unmount",{mountPath:e,error:l instanceof Error?l.message:String(l)})}this.activeMounts.delete(e)}else if(i.mountType==="fuse"&&i.credentialProxy){try{await this.configureS3CredentialProxyOutbound(this.getS3CredentialProxyParams({excludeMountId:i.mountId}))}catch(u){this.logger.warn("credential proxy outbound reconfiguration failed on unmount",{mountPath:e,error:u instanceof Error?u.message:String(u)})}this.activeMounts.delete(e),Ye(i.mountId),Je(i.mountId)}else this.activeMounts.delete(e);try{let u=await this.execInternal(`mountpoint -q ${S(e)} || rmdir ${S(e)}`);u.exitCode!==0&&this.logger.warn("mount directory removal failed",{mountPath:e,exitCode:u.exitCode,stderr:u.stderr})}catch(u){this.logger.warn("mount directory removal failed",{mountPath:e,error:u instanceof Error?u.message:String(u)})}}finally{o&&(await this.deletePasswordFile(i.passwordFilePath),i.additionalHeaderFilePath&&await this.deleteAdditionalHeaderFile(i.additionalHeaderFilePath))}}n="success"}catch(o){throw s=o instanceof Error?o:new Error(String(o)),o}finally{N(this.logger,{event:"bucket.unmount",outcome:n,durationMs:Date.now()-r,mountPath:e,bucket:i?.bucket,error:s})}}validateMountPath(e){if(!e.startsWith("/"))throw new _(`Mount path must be absolute (start with /): "${e}"`);if(this.activeMounts.has(e))throw new _(`Mount path "${e}" is already in use by bucket "${this.activeMounts.get(e)?.bucket}". Unmount the existing bucket first or use a different mount path.`)}validateMountOptions(e,r,n){try{new URL(n.endpoint)}catch{throw new _(`Invalid endpoint URL: "${n.endpoint}". Must be a valid HTTP(S) URL.`)}Fa(e,r),this.validateMountPath(r)}generatePasswordFilePath(){return`/tmp/.passwd-s3fs-${crypto.randomUUID()}`}generateS3FSAdditionalHeaderFilePath(){return`/tmp/.s3fs-ahbe-${crypto.randomUUID()}.conf`}async createDisableExpectHeaderFile(e){await this.client.files.writeFile(e,Eu,O),await this.execInternal(`chmod 0600 ${S(e)}`)}async createPasswordFile(e,r,n){let s=`${r}:${n.accessKeyId}:${n.secretAccessKey}`;await this.client.files.writeFile(e,s,O),await this.execInternal(`chmod 0600 ${S(e)}`)}async deletePasswordFile(e){try{await this.execInternal(`rm -f ${S(e)}`)}catch(r){this.logger.warn("password file cleanup failed",{passwordFilePath:e,error:r instanceof Error?r.message:String(r)})}}async deleteAdditionalHeaderFile(e){try{await this.execInternal(`rm -f ${S(e)}`)}catch(r){this.logger.warn("s3fs additional header file cleanup failed",{headerFilePath:e,error:r instanceof Error?r.message:String(r)})}}async executeS3FSMount(e,r,n,s,i,o){let c={logfile:`/tmp/.s3fs-log-${Pu(4)}`,...dr(Mn(s)),...dr(n.s3fsOptions??[]),passwd_file:i,url:n.endpoint,...n.readOnly?{ro:!0}:{}},u=c.logfile,l=Au`(\n s3fs ${e} ${r} -o ${Zn(c)} >${u} 2>&1\n rc=$?\n if [ "$rc" -ne 0 ]; then tail -n 20 ${u} 2>/dev/null || true; exit 2; fi\n for _ in $(seq 1 60); do\n if mountpoint -q ${r}; then exit 0; fi\n sleep 0.1\n done\n tail -n 20 ${u} 2>/dev/null || true\n exit 3\n )`,d=await(o?g=>this.execWithSession(g,o,{origin:"internal"}):g=>this.execInternal(g))(l);if(d.exitCode===0)return;let p=d.stdout?.trim()||d.stderr?.trim()||"";throw d.exitCode===2?new Ze(`S3FS mount failed: ${p||"Unknown error"}`):new Ze(`S3FS mount failed: FUSE filesystem never appeared at ${r}. ${p?`s3fs log: ${p}`:"No s3fs log output captured. The s3fs daemon may have exited before writing logs."}`)}async unmountTrackedFuseMount(e,r){if(!r.mounted)return;this.logger.debug(`Unmounting bucket ${r.bucket} from ${e}`);let n=await this.execInternal(`fusermount -u ${S(e)}`);if(n.exitCode!==0)throw new Error(`fusermount -u failed (exit ${n.exitCode}): ${n.stderr||"unknown error"}`);r.mounted=!1}inflightDestroy=null;async destroy(){if(this.inflightDestroy)return N(this.logger,{event:"sandbox.destroy.coalesced",outcome:"success",durationMs:0}),this.inflightDestroy;let e=this.doDestroy();this.inflightDestroy=e;try{await e}finally{this.inflightDestroy===e&&(this.inflightDestroy=null)}}async doDestroy(){let e=Date.now(),r=0,n=0,s="error",i;try{await this.ctx.storage.delete(Tt),await this.clearActivePreviewPorts(),await this.currentLifetime.rotate(),await this.currentRuntime.clear();for(let[o,c]of this.activeMounts.entries())if(r++,c.mountType==="local-sync")try{await c.syncManager.stop(),c.mounted=!1}catch(u){n++;let l=u instanceof Error?u.message:String(u);this.logger.warn(`Failed to stop local sync for ${o}: ${l}`)}else{try{await this.unmountTrackedFuseMount(o,c)}catch(u){n++;let l=u instanceof Error?u.message:String(u);this.logger.warn(`Failed to unmount bucket ${c.bucket} from ${o}: ${l}`)}await this.deletePasswordFile(c.passwordFilePath),c.additionalHeaderFilePath&&await this.deleteAdditionalHeaderFile(c.additionalHeaderFilePath)}try{this.ensureTunnelsBuilt(),await this.destroyAllTunnels?.()}catch(o){this.logger.warn("Failed to tear down tunnels during destroy()",{error:o instanceof Error?o.message:String(o)})}await this.ctx.storage.delete("tunnels"),await this.ctx.storage.delete("tunnels:meta"),this.client.disconnect(this.buildDisconnectCause("sandbox_lifetime_changed","The sandbox was destroyed while the operation was pending.")),s="success";try{await super.destroy()}catch(o){if(!this.isNoInstanceError(o))throw o;this.logger.debug("super.destroy() reported no container instance; treating as no-op")}}catch(o){throw i=o instanceof Error?o:new Error(String(o)),o}finally{N(this.logger,{event:"sandbox.destroy",outcome:s,durationMs:Date.now()-e,mountsProcessed:r,mountFailures:n,error:i})}}async onStart(){this.logger.debug("Sandbox started"),await this.currentRuntime.markStarted(),this.checkVersionCompatibility().catch(e=>{this.logger.error("Version compatibility check failed",e instanceof Error?e:new Error(String(e)))});try{await Vn(this.ctx.storage)}catch(e){this.logger.error("Failed to reconcile tunnel storage after container start",e instanceof Error?e:new Error(String(e)))}}async stop(e){await this.currentRuntime.clear(),await this.clearActivePreviewPorts(),await super.stop(e)}async readPortTokens(e=this.ctx.storage){let r=await e.get(Tt)??{},n={};for(let[s,i]of Object.entries(r))n[s]=typeof i=="string"?{token:i}:i;return n}async readActivePreviewPorts(e=this.ctx.storage){return await e.get(It)??{}}async writeActivePreviewPorts(e,r=this.ctx.storage){if(Object.keys(e).length===0){await r.delete(It);return}await r.put(It,e)}async readPreviewState(e=this.ctx.storage){let[r,n]=await Promise.all([this.readPortTokens(e),this.readActivePreviewPorts(e)]);return{tokens:r,activations:n}}async clearActivePreviewPorts(){await this.ctx.storage.delete(It)}async checkVersionCompatibility(){let e=gu,r,n;try{r=await this.client.utils.getVersion(),r==="unknown"?n="container_version_unknown":r!==e?n="version_mismatch":n="compatible"}catch{n="check_failed",r=void 0}let s=n==="compatible"?"debug":n==="container_version_unknown"?"info":"warn";N(this.logger,{event:"version.check",outcome:"success",durationMs:0,sdkVersion:e,containerVersion:r??"unknown",versionOutcome:n},{successLevel:s})}async onStop(e){this.logger.debug("Sandbox stopped",{exitCode:e?.exitCode,reason:e?.reason}),this.containerGeneration++,this.defaultSession=null,this.defaultSessionInit=null,await this.currentRuntime.clear(),await this.clearActivePreviewPorts();try{await Vn(this.ctx.storage)}catch(s){this.logger.error("Failed to reconcile tunnel storage after container stop",s instanceof Error?s:new Error(String(s)))}this.client.disconnect(this.buildDisconnectCause("runtime_replaced","The sandbox container stopped while the operation was pending.",e));let r=!1,n=!1;for(let[,s]of this.activeMounts)s.mountType==="local-sync"?await s.syncManager.stop().catch(()=>{}):s.mountType==="r2-egress"?r=!0:s.mountType==="fuse"&&s.credentialProxy&&(n=!0,Ye(s.mountId),Je(s.mountId));r&&await this.configureR2EgressOutbound({buckets:{}}).catch(()=>{}),n&&await this.configureS3CredentialProxyOutbound({mounts:{}}).catch(()=>{}),this.activeMounts.clear(),await this.ctx.storage.delete("defaultSession")}onError(e){this.logger.error("Sandbox error",e instanceof Error?e:new Error(String(e)))}async containerFetch(e,r,n){let{request:s,port:i}=this.parseContainerFetchArgs(e,r,n),o=await this.getState(),c=this.ctx.container?.running,u=o.status==="healthy"&&c===!1;if(o.status!=="healthy"||c===!1)try{await this.startAndWaitForPorts({ports:i,cancellationOptions:{instanceGetTimeoutMS:this.containerTimeouts.instanceGetTimeoutMS,portReadyTimeoutMS:this.containerTimeouts.portReadyTimeoutMS,waitInterval:this.containerTimeouts.waitIntervalMS,abort:s.signal}})}catch(l){let d=ke(l);if(d){let g=l instanceof Error?l.message:String(l),m={reason:d,retryable:!0,originalMessage:g},f={code:h.CONTAINER_UNAVAILABLE,message:g,context:m,httpStatus:503,timestamp:new Date().toISOString(),suggestion:W(h.CONTAINER_UNAVAILABLE,m)};return new Response(JSON.stringify(f),{status:503,headers:{"Content-Type":"application/json","Retry-After":"10"}})}if(this.isPermanentStartupError(l)){this.logger.error("Permanent container startup error, returning 500",l instanceof Error?l:new Error(String(l)));let g={code:h.INTERNAL_ERROR,message:"Container failed to start due to a permanent error. Check your container configuration.",context:{phase:"startup",error:l instanceof Error?l.message:String(l)},httpStatus:500,timestamp:new Date().toISOString(),suggestion:"This error will not resolve with retries. Check container logs, image name, and resource limits."};return new Response(JSON.stringify(g),{status:500,headers:{"Content-Type":"application/json"}})}if(this.isTransientStartupError(l)){u?(this.logger.warn("container.startup",{outcome:"stale_state_abort",staleStateDetected:!0,error:l instanceof Error?l.message:String(l)}),this.ctx.abort()):this.logger.debug("container.startup",{outcome:"transient_error",staleStateDetected:u,error:l instanceof Error?l.message:String(l)});let g={code:h.INTERNAL_ERROR,message:"Container is starting. Please retry in a moment.",context:{phase:"startup",error:l instanceof Error?l.message:String(l)},httpStatus:503,timestamp:new Date().toISOString(),suggestion:"The container is booting. The SDK will retry automatically."};return new Response(JSON.stringify(g),{status:503,headers:{"Content-Type":"application/json","Retry-After":"3"}})}this.logger.warn("container.startup",{outcome:"unrecognized_error",staleStateDetected:u,error:l instanceof Error?l.message:String(l)});let p={code:h.INTERNAL_ERROR,message:"Container is starting. Please retry in a moment.",context:{phase:"startup",error:l instanceof Error?l.message:String(l)},httpStatus:503,timestamp:new Date().toISOString(),suggestion:"The SDK will retry automatically. If this persists, the container may need redeployment."};return new Response(JSON.stringify(p),{status:503,headers:{"Content-Type":"application/json","Retry-After":"5"}})}return await super.containerFetch(e,r,n)}isNoInstanceError(e){return ke(e)!==null}async startContainerForRPC(){try{await this.startAndWaitForPorts({ports:3e3,cancellationOptions:{instanceGetTimeoutMS:Su,portReadyTimeoutMS:this.containerTimeouts.portReadyTimeoutMS,waitInterval:this.containerTimeouts.waitIntervalMS}})}catch(e){throw this.toContainerStartError(e)}}toContainerStartError(e){if(e instanceof R)return e;let r=e instanceof Error?e.message:String(e),n=ke(e);if(n){let i={reason:n,retryable:!0,originalMessage:r};return B({code:h.CONTAINER_UNAVAILABLE,message:r,context:i,httpStatus:F(h.CONTAINER_UNAVAILABLE),suggestion:W(h.CONTAINER_UNAVAILABLE,i),timestamp:new Date().toISOString()},{cause:e})}let s={phase:"startup",error:r};return B({code:h.INTERNAL_ERROR,message:`Container failed to start: ${r}`,context:s,httpStatus:F(h.INTERNAL_ERROR),timestamp:new Date().toISOString()},{cause:e})}buildDisconnectCause(e,r,n){let s={reason:e,operation:"rpc.connect",phase:"connection",admitted:"unknown",retryable:e==="runtime_replaced",...n?.exitCode!==void 0&&{containerExitCode:n.exitCode},...n?.reason!==void 0&&{stopReason:n.reason}};return new Q({code:h.OPERATION_INTERRUPTED,message:r,context:s,httpStatus:F(h.OPERATION_INTERRUPTED),suggestion:W(h.OPERATION_INTERRUPTED,s),timestamp:new Date().toISOString()})}isTransientStartupError(e){if(!(e instanceof Error))return!1;let r=e.message.toLowerCase();return["container port not found","connection refused: container port","the container is not listening","failed to verify port","container did not start","network connection lost","container suddenly disconnected","monitor failed to find container","container exited with unexpected exit code","container exited before we could determine","timed out","timeout","the operation was aborted"].some(n=>r.includes(n))}isPermanentStartupError(e){if(!(e instanceof Error))return!1;let r=e.message.toLowerCase();return["ran out of memory","too many subprocesses","no application that matches","no container application assigned","no such image","did not call start"].some(n=>r.includes(n))}parseContainerFetchArgs(e,r,n){let s,i;if(e instanceof Request)s=e,i=typeof r=="number"?r:void 0;else{let o=typeof e=="string"?e:e.toString(),c=typeof r=="number"?{}:r||{};i=typeof r=="number"?r:typeof n=="number"?n:void 0,s=new Request(o,c)}if(i??=this.defaultPort,i===void 0)throw new Error("No port specified for container fetch");return{request:s,port:i}}async onActivityExpired(){this.keepAliveEnabled?this.logger.debug("Activity expired but keepAlive is enabled - container will stay alive"):(this.logger.debug("Activity expired - stopping container"),await super.onActivityExpired())}isPreviewProxyRequest(e){return e.headers.get(Cr)==="1"}invalidPreviewTokenResponse(){return new Response(JSON.stringify({error:"Access denied: Invalid token or port not exposed",code:"INVALID_TOKEN"}),{status:404,headers:{"Content-Type":"application/json"}})}stalePreviewURLResponse(){return new Response(JSON.stringify({error:"Preview URL is stale because the sandbox runtime is not active",code:"STALE_PREVIEW_URL"}),{status:410,headers:{"Content-Type":"application/json"}})}getPreviewForwardingContainer(){return this.ctx.container}beginPreviewForward(){let e=this;e.inflightRequests=(e.inflightRequests??0)+1,this.renewActivityTimeout();let r=!1;return()=>{r||(r=!0,e.inflightRequests=Math.max(0,(e.inflightRequests??0)-1),e.inflightRequests===0&&this.renewActivityTimeout())}}async fetchPreviewIfRunning(e,r,n){let s=this.getPreviewForwardingContainer(),i=await this.getState();if(!s?.running||i.status!=="healthy")return this.stalePreviewURLResponse();if(!await this.currentRuntime.isActive(n))return this.stalePreviewURLResponse();let o=await Ga(s.getTcpPort(r),e,{beginForward:a(()=>this.beginPreviewForward(),"beginForward"),renewActivity:a(()=>this.renewActivityTimeout(),"renewActivity")});return o.status==="network-lost"?await this.currentRuntime.isActive(n)?new Response("Container suddenly disconnected, try again",{status:500}):this.stalePreviewURLResponse():o.response}buildPreviewProxyRequest(e,r,n){let s=new URL(e.url),i=`http://localhost:${r}${s.pathname}${s.search}`,o=new Headers(e.headers);for(let c of _s)o.delete(c);return o.set("X-Original-URL",e.url),o.set("X-Forwarded-Host",s.hostname),o.set("X-Forwarded-Proto",s.protocol.replace(":","")),o.set("X-Sandbox-Name",this.sandboxName??n),e.headers.get("Upgrade")?.toLowerCase()==="websocket"?new Request(e,{headers:o,redirect:"manual"}):new Request(i,{method:e.method,headers:o,body:e.body,duplex:"half",redirect:"manual"})}async proxyPreviewRequest(e){let r=e.headers.get(xr),n=e.headers.get(vr),s=e.headers.get(Or),i=r===null?NaN:Number.parseInt(r,10);if(!Number.isFinite(i)||!se(i)||!n||!s)return this.invalidPreviewTokenResponse();let o=this.buildPreviewProxyRequest(e,i,s),c=await this.validatePreviewURLForRuntime(i,n);return c.status==="invalid"?this.invalidPreviewTokenResponse():c.status==="stale"?(this.logger.warn("Stale preview URL blocked",{port:i,sandboxId:s,containerStatus:c.containerStatus,reason:c.reason,method:e.method}),this.stalePreviewURLResponse()):await this.fetchPreviewIfRunning(o,i,c.runtime)}async fetch(e){let r=Be.fromHeaders(e.headers)||Be.generate(),n=this.logger.child({traceId:r,operation:"fetch"}),s=new URL(e.url);if(this.isPreviewProxyRequest(e))return await this.proxyPreviewRequest(e);if(!this.sandboxName&&e.headers.has("X-Sandbox-Name")){let u=e.headers.get("X-Sandbox-Name");this.sandboxName=u,await this.ctx.storage.put("sandboxName",u)}let i=e.headers.get("Upgrade"),o=e.headers.get("Connection");if(i?.toLowerCase()==="websocket"&&o?.toLowerCase().includes("upgrade"))try{return n.debug("WebSocket upgrade requested",{path:s.pathname,port:this.determinePort(s)}),await super.fetch(e)}catch(u){throw n.error("WebSocket connection failed",u instanceof Error?u:new Error(String(u)),{path:s.pathname}),u}let c=this.determinePort(s);return await this.containerFetch(e,c)}wsConnect(e,r){throw new Error("wsConnect must be called on the stub returned by getSandbox()")}determinePort(e){let r=e.pathname.match(/^\\/proxy\\/(\\d+)/);return r?parseInt(r[1],10):3e3}async ensureDefaultSession(){let e=`sandbox-${this.sandboxName||"default"}`;if(this.defaultSession===e)return this.defaultSession;let r=this.containerGeneration,n=this.defaultSessionInit;if(n?.sessionId===e&&n.generation===r)return n.promise;let s=this.initializeDefaultSession(e,r),i={sessionId:e,generation:r,promise:s};this.defaultSessionInit=i;try{return await s}catch(o){if(Xa(o)){if(this.defaultSession===e)return this.defaultSession;let c=this.defaultSessionInit;return c!=null&&c!==i&&c.sessionId===e&&c.generation===this.containerGeneration?c.promise:await this.initializeDefaultSession(e,this.containerGeneration)}throw o}finally{this.defaultSessionInit===i&&(this.defaultSessionInit=null)}}async initializeDefaultSession(e,r){let n;try{n=(await this.client.utils.createSession({id:e,env:this.envVars||{},cwd:"/workspace"})).containerPlacementId}catch(s){if(!(s instanceof ss))throw s;n=s.containerPlacementId,this.logger.debug("Session exists in container but not in DO state, syncing",{sessionId:e})}if(r!==this.containerGeneration)throw new As;return await this.ctx.storage.put("defaultSession",e),await this.capturePlacementId(n),this.defaultSession=e,this.logger.debug("Default session initialized",{sessionId:e}),e}async capturePlacementId(e){e!==void 0&&await this.ctx.storage.put("containerPlacementId",e)}async resolveExecution(e){return e!==void 0?(this.validateExplicitSessionId(e),e===O?{kind:"sessionless"}:{kind:"session",sessionId:e}):{kind:"session",sessionId:await this.ensureDefaultSession()}}validateExplicitSessionId(e){if(e.trim().length===0)throw new Error("sessionId must not be empty or whitespace")}serializeExecutionContext(e){return e.kind==="sessionless"?O:e.sessionId}getPublicExecutionSessionId(e){return e===O?void 0:e}getProcessSessionBinding(e){return e!==void 0?(this.validateExplicitSessionId(e),e===O?void 0:e):this.defaultSession??void 0}resolveExecutionEnv(e,r){if(e===O){let s=lt({...this.envVars,...r??{}});return Object.keys(s).length>0?s:void 0}if(r===void 0)return;let n=lt(r);return Object.keys(n).length>0?n:void 0}buildExecutionRequestOptions(e,r){let n=this.resolveExecutionEnv(e,r?.env);if(!(r?.timeout===void 0&&n===void 0&&r?.cwd===void 0&&r?.origin===void 0))return{...r?.timeout!==void 0&&{timeoutMs:r.timeout},...n!==void 0&&{env:n},...r?.cwd!==void 0&&{cwd:r.cwd},...r?.origin!==void 0&&{origin:r.origin}}}async exec(e,r){let n=await this.resolveExecution(),s=this.serializeExecutionContext(n);return this.execWithSession(e,s,r)}async execWithSessionToken(e,r,n){return this.validateExplicitSessionId(r),this.execWithSession(e,r,n)}async execInternal(e){let r=await this.ensureDefaultSession();return this.execWithSession(e,r,{origin:"internal"})}async execWithSession(e,r,n){let s=Date.now(),i=new Date().toISOString(),o,c;try{if(n?.signal?.aborted)throw new Error("Operation was aborted");let u;if(n?.stream&&n?.onOutput)u=await this.executeWithStreaming(e,r,n,s,i);else{let l=this.buildExecutionRequestOptions(r,n),d=await this.client.commands.execute(e,r,l),p=Date.now()-s,g=this.getPublicExecutionSessionId(r);u=this.mapExecuteResponseToExecResult(d,p,g)}return o={exitCode:u.exitCode,success:u.success},n?.onComplete&&n.onComplete(u),u}catch(u){throw c=u instanceof Error?u:new Error(String(u)),n?.onError&&u instanceof Error&&n.onError(u),u}finally{N(this.logger,{event:"sandbox.exec",outcome:c?"error":"success",command:e,exitCode:o?.exitCode,durationMs:Date.now()-s,sessionId:this.getPublicExecutionSessionId(r),origin:n?.origin??"user",error:c??void 0,errorMessage:c?.message})}}async executeWithStreaming(e,r,n,s,i){let o="",c="";try{let u=this.buildExecutionRequestOptions(r,n),l=await this.client.commands.executeStream(e,r,u);for await(let d of Te(l)){if(n.signal?.aborted)throw new Error("Operation was aborted");switch(d.type){case"stdout":case"stderr":d.data&&(d.type==="stdout"&&(o+=d.data),d.type==="stderr"&&(c+=d.data),n.onOutput&&n.onOutput(d.type,d.data));break;case"complete":{let p=Date.now()-s;return{success:(d.exitCode??0)===0,exitCode:d.exitCode??0,stdout:o,stderr:c,command:e,duration:p,timestamp:i,sessionId:this.getPublicExecutionSessionId(r)}}case"error":throw new Error(d.data||"Command execution failed")}}throw new Error("Stream ended without completion event")}catch(u){throw n.signal?.aborted?new Error("Operation was aborted"):u}}mapExecuteResponseToExecResult(e,r,n){return{success:e.success,exitCode:e.exitCode,stdout:e.stdout,stderr:e.stderr,command:e.command,duration:r,timestamp:e.timestamp,sessionId:n}}createProcessFromDTO(e,r){return{id:e.id,pid:e.pid,command:e.command,status:e.status,startTime:typeof e.startTime=="string"?new Date(e.startTime):e.startTime,endTime:e.endTime?typeof e.endTime=="string"?new Date(e.endTime):e.endTime:void 0,exitCode:e.exitCode,sessionId:r,kill:a(async n=>{await this.killProcess(e.id,n)},"kill"),getStatus:a(async()=>(await this.getProcess(e.id))?.status||"error","getStatus"),getLogs:a(async()=>{let n=await this.getProcessLogs(e.id);return{stdout:n.stdout,stderr:n.stderr}},"getLogs"),waitForLog:a(async(n,s)=>this.waitForLogPattern(e.id,e.command,n,s),"waitForLog"),waitForPort:a(async(n,s)=>{await this.waitForPortReady(e.id,e.command,n,s)},"waitForPort"),waitForExit:a(async n=>this.waitForProcessExit(e.id,e.command,n),"waitForExit")}}async waitForLogPattern(e,r,n,s){let i=Date.now(),o=this.conditionToString(n),c="",u="";try{let g=await this.getProcessLogs(e);c=g.stdout,c&&!c.endsWith(`\n`)&&(c+=`\n`),u=g.stderr,u&&!u.endsWith(`\n`)&&(u+=`\n`);let m=this.matchPattern(g.stdout,n);if(m)return m;let f=this.matchPattern(g.stderr,n);if(f)return f}catch(g){this.logger.debug("Could not get existing logs, will stream",{processId:e,error:g instanceof Error?g.message:String(g)})}let l=await this.streamProcessLogs(e),d,p;if(s!==void 0){let g=s-(Date.now()-i);if(g<=0)throw this.createReadyTimeoutError(e,r,o,s);p=new Promise((m,f)=>{d=setTimeout(()=>{f(this.createReadyTimeoutError(e,r,o,s))},g)})}try{let g=a(async()=>{let m=a(()=>{let w=this.matchPattern(c,n);if(w)return w;let y=this.matchPattern(u,n);return y||null},"checkPattern");for await(let w of Te(l)){if(w.type==="stdout"||w.type==="stderr"){let y=w.data||"";w.type==="stdout"?c+=y:u+=y;let E=m();if(E)return E}if(w.type==="exit"){let y=m();if(y)return y;throw this.createExitedBeforeReadyError(e,r,o,w.exitCode??1)}}let f=m();if(f)return f;throw this.createExitedBeforeReadyError(e,r,o,0)},"streamProcessor");return p?await Promise.race([g(),p]):await g()}finally{d&&clearTimeout(d)}}async waitForPortReady(e,r,n,s){let{mode:i="http",path:o="/",status:c={min:200,max:399},timeout:u,interval:l=500}=s??{},d=i==="http"?`port ${n} (HTTP ${o})`:`port ${n} (TCP)`,p=typeof c=="number"?c:c.min,g=typeof c=="number"?c:c.max,m=await this.client.ports.watchPort({port:n,mode:i,path:o,statusMin:p,statusMax:g,processId:e,interval:l}),f,w;u!==void 0&&(w=new Promise((y,E)=>{f=setTimeout(()=>{E(this.createReadyTimeoutError(e,r,d,u))},u)}));try{let y=a(async()=>{for await(let E of Te(m))switch(E.type){case"ready":return;case"process_exited":throw this.createExitedBeforeReadyError(e,r,d,E.exitCode??1);case"error":throw new Error(E.error||"Port watch failed")}throw new Error("Port watch stream ended unexpectedly")},"streamProcessor");w?await Promise.race([y(),w]):await y()}finally{f&&clearTimeout(f);try{await m.cancel()}catch{}}}async waitForProcessExit(e,r,n){let s=await this.streamProcessLogs(e),i,o;n!==void 0&&(o=new Promise((c,u)=>{i=setTimeout(()=>{u(this.createReadyTimeoutError(e,r,"process exit",n))},n)}));try{let c=a(async()=>{for await(let u of Te(s))if(u.type==="exit")return{exitCode:u.exitCode??1};throw new Error(`Process ${e} stream ended unexpectedly without exit event`)},"streamProcessor");return o?await Promise.race([c(),o]):await c()}finally{i&&clearTimeout(i)}}matchPattern(e,r){if(typeof r=="string"){if(e.includes(r)){let n=e.split(`\n`);for(let s of n)if(s.includes(r))return{line:s};return{line:r}}}else{let n=new RegExp(r.source,r.flags.replace("g","")),s=e.match(n);if(s){let i=e.split(`\n`);for(let o of i){let c=o.match(n);if(c)return{line:o,match:c}}return{line:s[0],match:s}}}return null}conditionToString(e){return typeof e=="string"?`"${e}"`:e.toString()}createReadyTimeoutError(e,r,n,s){return new cs({code:h.PROCESS_READY_TIMEOUT,message:`Process did not become ready within ${s}ms. Waiting for: ${n}`,context:{processId:e,command:r,condition:n,timeout:s},httpStatus:408,timestamp:new Date().toISOString(),suggestion:`Check if your process outputs ${n}. You can increase the timeout parameter.`})}createExitedBeforeReadyError(e,r,n,s){return new us({code:h.PROCESS_EXITED_BEFORE_READY,message:`Process exited with code ${s} before becoming ready. Waiting for: ${n}`,context:{processId:e,command:r,condition:n,exitCode:s},httpStatus:500,timestamp:new Date().toISOString(),suggestion:"Check process logs with getLogs() for error messages"})}async startProcess(e,r,n){try{let s=await this.resolveExecution(n),i=this.serializeExecutionContext(s),o=this.getProcessSessionBinding(i),c={...this.buildExecutionRequestOptions(i,{timeout:r?.timeout,env:r?.env,cwd:r?.cwd}),...r?.processId!==void 0&&{processId:r.processId},...r?.encoding!==void 0&&{encoding:r.encoding},...r?.autoCleanup!==void 0&&{autoCleanup:r.autoCleanup}},u=await this.client.processes.startProcess(e,i,c),l=this.createProcessFromDTO({id:u.processId,pid:u.pid,command:u.command,status:"running",startTime:new Date,endTime:void 0,exitCode:void 0},o);return r?.onStart&&r.onStart(l),(r?.onOutput||r?.onExit)&&this.startProcessCallbackStream(u.processId,r).catch(()=>{}),l}catch(s){throw r?.onError&&s instanceof Error&&r.onError(s),s}}async startProcessCallbackStream(e,r){try{let n=await this.client.processes.streamProcessLogs(e);for await(let s of Te(n))switch(s.type){case"stdout":s.data&&r.onOutput&&r.onOutput("stdout",s.data);break;case"stderr":s.data&&r.onOutput&&r.onOutput("stderr",s.data);break;case"exit":case"complete":r.onExit&&r.onExit(s.exitCode??null);return}throw new Error("Stream ended without completion event")}catch(n){r.onError&&n instanceof Error&&r.onError(n),this.logger.error("Background process streaming failed",n instanceof Error?n:new Error(String(n)),{processId:e})}}async listProcesses(e){let r=this.getProcessSessionBinding(e);return(await this.client.processes.listProcesses()).processes.map(n=>this.createProcessFromDTO({id:n.id,pid:n.pid,command:n.command,status:n.status,startTime:n.startTime,endTime:n.endTime,exitCode:n.exitCode},r))}async getProcess(e,r){let n=this.getProcessSessionBinding(r);try{let s=await this.client.processes.getProcess(e);if(!s.process)return null;let i=s.process;return this.createProcessFromDTO({id:i.id,pid:i.pid,command:i.command,status:i.status,startTime:i.startTime,endTime:i.endTime,exitCode:i.exitCode},n)}catch(s){if(s instanceof ns)return null;throw s}}async killProcess(e,r,n){await this.client.processes.killProcess(e)}async killAllProcesses(e){return(await this.client.processes.killAllProcesses()).cleanedCount}async cleanupCompletedProcesses(e){return 0}async getProcessLogs(e,r){let n=await this.client.processes.getProcessLogs(e);return{stdout:n.stdout,stderr:n.stderr,processId:n.processId}}async execStream(e,r){if(r?.signal?.aborted)throw new Error("Operation was aborted");let n=await this.resolveExecution(r?.sessionId),s=this.serializeExecutionContext(n),i=this.buildExecutionRequestOptions(s,{timeout:r?.timeout,env:r?.env,cwd:r?.cwd});return this.client.commands.executeStream(e,s,i)}async execStreamWithSessionToken(e,r,n){return this.validateExplicitSessionId(r),this.execStreamWithSession(e,r,n)}async execStreamWithSession(e,r,n){if(n?.signal?.aborted)throw new Error("Operation was aborted");return this.client.commands.executeStream(e,r,this.buildExecutionRequestOptions(r,{timeout:n?.timeout,env:n?.env,cwd:n?.cwd}))}async streamProcessLogs(e,r){if(r?.signal?.aborted)throw new Error("Operation was aborted");return this.client.processes.streamProcessLogs(e)}async gitCheckout(e,r){let n=await this.resolveExecution(r?.sessionId),s=this.serializeExecutionContext(n);return this.client.git.checkout(e,s,{branch:r?.branch,targetDir:r?.targetDir,depth:r?.depth,timeoutMs:r?.cloneTimeoutMs})}async mkdir(e,r={}){let n=await this.resolveExecution(r.sessionId),s=this.serializeExecutionContext(n);return this.client.files.mkdir(e,s,{recursive:r.recursive})}async writeFile(e,r,n={}){let s=await this.resolveExecution(n.sessionId),i=this.serializeExecutionContext(s);return r instanceof ReadableStream?this.client.files.writeFileStream(e,r,i):this.client.files.writeFile(e,r,i,{encoding:n.encoding})}async deleteFile(e,r){let n=await this.resolveExecution(r),s=this.serializeExecutionContext(n);return this.client.files.deleteFile(e,s)}async renameFile(e,r,n){let s=await this.resolveExecution(n),i=this.serializeExecutionContext(s);return this.client.files.renameFile(e,r,i)}async moveFile(e,r,n){let s=await this.resolveExecution(n),i=this.serializeExecutionContext(s);return this.client.files.moveFile(e,r,i)}async readFile(e,r={}){let n=await this.resolveExecution(r.sessionId),s=this.serializeExecutionContext(n);return r.encoding==="none"?this.client.files.readFile(e,s,{encoding:"none"}):this.client.files.readFile(e,s,{encoding:r.encoding})}async readFileStream(e,r={}){let n=await this.resolveExecution(r.sessionId),s=this.serializeExecutionContext(n);return this.client.files.readFileStream(e,s)}async listFiles(e,r){let n=await this.resolveExecution(r?.sessionId),s=this.serializeExecutionContext(n);return this.client.files.listFiles(e,s,r)}async exists(e,r){let n=await this.resolveExecution(r),s=this.serializeExecutionContext(n);return this.client.files.exists(e,s)}async watch(e,r={}){let n=await this.resolveExecution(r.sessionId),s=this.serializeExecutionContext(n);return this.client.watch.watch({path:e,recursive:r.recursive,include:r.include,exclude:r.exclude,sessionId:s})}async checkChanges(e,r={}){let n=await this.resolveExecution(r.sessionId),s=this.serializeExecutionContext(n);return this.client.watch.checkChanges({path:e,recursive:r.recursive,include:r.include,exclude:r.exclude,since:r.since,sessionId:s})}async exposePort(e,r){let n=Date.now(),s="error",i;try{if(!se(e))throw new k(`Invalid port number: ${e}. Must be 1024-65535, excluding 3000 (sandbox control plane).`);if(r.hostname.endsWith(".workers.dev"))throw new os({code:h.CUSTOM_DOMAIN_REQUIRED,message:"Port exposure requires a custom domain. .workers.dev domains do not support wildcard subdomains required for port proxying.",context:{originalError:r.hostname},httpStatus:400,timestamp:new Date().toISOString()});if(!this.sandboxName)throw new Error("Sandbox name not available. Ensure sandbox is accessed through getSandbox()");r.token!==void 0&&this.validateCustomToken(r.token),await this.ensureDefaultSession();let o=await this.currentRuntime.get();o=o??await this.currentRuntime.markStarted(),await this.currentRuntime.assertActive(o);let c=await this.ctx.storage.transaction(async l=>{let d=await this.readPortTokens(l),p=d[e.toString()],g=r.token??p?.token??this.generatePortToken(),m=Object.entries(d).find(([w,y])=>y.token===g&&w!==e.toString());if(m)throw new k(`Token \'${g}\' is already in use by port ${m[0]}. Please use a different token.`);let f=await this.readActivePreviewPorts(l);return d[e.toString()]={token:g,name:r.name},f[e.toString()]=o.scope({token:g}),await Promise.all([l.put(Tt,d),this.writeActivePreviewPorts(f,l)]),g});await this.currentRuntime.assertActive(o);let u=this.constructPreviewUrl(e,this.sandboxName,r.hostname,c);return s="success",{url:u,port:e,name:r.name}}catch(o){throw i=o instanceof Error?o:new Error(String(o)),o}finally{N(this.logger,{event:"port.expose",outcome:s,port:e,durationMs:Date.now()-n,name:r.name,hostname:r.hostname,error:i})}}async unexposePort(e){let r=Date.now(),n="error",s;try{if(!se(e))throw new k(`Invalid port number: ${e}. Must be 1024-65535, excluding 3000 (sandbox control plane).`);await this.ctx.storage.transaction(async i=>{let o=await this.readPortTokens(i);o[e.toString()]&&(delete o[e.toString()],await i.put(Tt,o));let c=await this.readActivePreviewPorts(i);c[e.toString()]&&(delete c[e.toString()],await this.writeActivePreviewPorts(c,i))}),n="success"}catch(i){throw s=i instanceof Error?i:new Error(String(i)),i}finally{N(this.logger,{event:"port.unexpose",outcome:n,port:e,durationMs:Date.now()-r,error:s})}}async getExposedPorts(e){if(!this.sandboxName)throw new Error("Sandbox name not available. Ensure sandbox is accessed through getSandbox()");return(await this.getCurrentPreviewPorts()).map(({port:r,entry:n})=>({url:this.constructPreviewUrl(r,this.sandboxName,e,n.token),port:r,status:"active"}))}get tunnels(){return this.ensureTunnelsBuilt(),this.tunnelsHandler}ensureTunnelsBuilt(){if(this.tunnelsHandler)return;let e=mu({client:this.client,storage:this.ctx.storage,logger:this.logger,sandboxId:this.ctx.id.toString(),currentRuntime:this.currentRuntime,currentLifetime:this.currentLifetime,getNamedTunnelConfig:a(async()=>{let r=this.env,n=D(r,"CLOUDFLARE_API_TOKEN");if(!n)throw new Error("Named tunnels require CLOUDFLARE_API_TOKEN. Set it as a secret in your wrangler.jsonc.");let s=await this.getTunnelAccountId();return{token:n,accountId:s,zoneId:await this.getTunnelZoneId(n,s)}},"getNamedTunnelConfig")});this.tunnelsHandler=e.tunnels,this.tunnelExitHandler=e.handleTunnelExit,this.destroyAllTunnels=e.destroyAll}getTunnelAccountId(){if(!this.tunnelAccountIdPromise){let e=Vc(this.env,{overrideKey:"CLOUDFLARE_TUNNEL_ACCOUNT_ID"});this.tunnelAccountIdPromise=e,e.catch(()=>{this.tunnelAccountIdPromise===e&&(this.tunnelAccountIdPromise=null)})}return this.tunnelAccountIdPromise}getTunnelZoneId(e,r){if(!this.tunnelZoneIdPromise){let n=Yc(this.env,{token:e,accountId:r});this.tunnelZoneIdPromise=n,n.catch(()=>{this.tunnelZoneIdPromise===n&&(this.tunnelZoneIdPromise=null)})}return this.tunnelZoneIdPromise}async isPortExposed(e){return se(e)?(await this.getCurrentPreviewPorts()).some(r=>r.port===e):!1}async validatePortToken(e,r){let n=(await this.readPortTokens())[e.toString()];return n?this.previewTokensMatch(n.token,r):!1}async validatePreviewURLForRuntime(e,r){let n=await this.getState(),s=this.ctx.container?.running===!0,{tokens:i,activations:o,runtime:c}=await this.ctx.storage.transaction(async d=>{let[p,g]=await Promise.all([this.readPreviewState(d),this.currentRuntime.getStored(d)]);return{...p,runtime:g}}),u=i[e.toString()];if(!u)return{status:"invalid"};if(!this.previewTokensMatch(u.token,r))return{status:"invalid"};if(n.status!=="healthy")return{status:"stale",reason:"runtime-not-healthy",containerStatus:n.status};if(!s)return{status:"stale",reason:"runtime-not-running",containerStatus:n.status};if(!c)return{status:"stale",reason:"missing-runtime-id",containerStatus:n.status};let l=o[e.toString()];return l?c.owns(l)?this.previewTokensMatch(l.token,r)?{status:"active",runtime:c}:(this.logger.warn("Preview URL activation token mismatch",{port:e,runtimeIdentityID:c.id}),{status:"stale",reason:"token-mismatch",containerStatus:n.status}):{status:"stale",reason:"runtime-mismatch",containerStatus:n.status}:{status:"stale",reason:"missing-activation",containerStatus:n.status}}async getCurrentPreviewPorts(){let e=await this.getState(),r=this.ctx.container?.running===!0,{tokens:n,activations:s,runtime:i}=await this.ctx.storage.transaction(async c=>{let[u,l]=await Promise.all([this.readPreviewState(c),this.currentRuntime.getStored(c)]);return{...u,runtime:l}});if(e.status!=="healthy"||!r||!i)return[];let o=[];for(let[c,u]of Object.entries(s)){let l=Number.parseInt(c,10),d=n[c];!d||!Number.isInteger(l)||!se(l)||i.owns(u)&&this.previewTokensMatch(d.token,u.token)&&o.push({port:l,entry:d})}return o.sort((c,u)=>c.port-u.port)}previewTokensMatch(e,r){let n=new TextEncoder,s=n.encode(e),i=n.encode(r);try{return crypto.subtle.timingSafeEqual(s,i)}catch{return!1}}validateCustomToken(e){if(e.length===0)throw new k("Custom token cannot be empty.");if(e.length>16)throw new k(`Custom token too long. Maximum 16 characters allowed. Received: ${e.length} characters.`);if(!/^[a-z0-9_]+$/.test(e))throw new k("Custom token must contain only lowercase letters (a-z), numbers (0-9), and underscores (_). Invalid token provided.")}generatePortToken(){let e=new Uint8Array(12);return crypto.getRandomValues(e),btoa(String.fromCharCode(...e)).replace(/\\+/g,"_").replace(/\\//g,"_").replace(/=/g,"").toLowerCase()}constructPreviewUrl(e,r,n,s){if(!se(e))throw new k(`Invalid port number: ${e}. Must be 1024-65535, excluding 3000 (sandbox control plane).`);let i=this.sandboxName||r,o=/[A-Z]/.test(i);if(!this.normalizeId&&o)throw new k(`Preview URLs require lowercase sandbox IDs. Your ID "${i}" contains uppercase letters.\n\nTo fix this:\n1. Create a new sandbox with: getSandbox(ns, "${i}", { normalizeId: true })\n2. This will create a sandbox with ID: "${i.toLowerCase()}"\n\nNote: Due to DNS case-insensitivity, IDs with uppercase letters cannot be used with preview URLs.`);let c=Ir(r).toLowerCase();if(qa(n)){let[u,l]=n.split(":"),d=l||"80";try{let p=new URL(`http://${u}:${d}`);return p.hostname=`${e}-${c}-${s}.${u}`,p.toString()}catch(p){throw new k(`Failed to construct preview URL: ${p instanceof Error?p.message:"Unknown error"}`)}}try{let u=new URL(`https://${n}`);return u.hostname=`${e}-${c}-${s}.${n}`,u.toString()}catch(u){throw new k(`Failed to construct preview URL: ${u instanceof Error?u.message:"Unknown error"}`)}}async createSession(e){let r=e?.id||`session-${Date.now()}`;if(r===O)throw new Error(`Session ID \'${O}\' is reserved for internal use`);let n=lt({...this.envVars,...e?.env??{}}),s=Object.keys(n).length>0?n:void 0,i=await this.client.utils.createSession({id:r,...s&&{env:s},...e?.cwd&&{cwd:e.cwd},...e?.commandTimeoutMs!==void 0&&{commandTimeoutMs:e.commandTimeoutMs}});return await this.capturePlacementId(i.containerPlacementId),this.getSessionWrapper(r)}async getSession(e){return this.getSessionWrapper(e)}async deleteSession(e){if(this.defaultSession&&e===this.defaultSession)throw new Error(`Cannot delete default session \'${e}\'. Use sandbox.destroy() to terminate the sandbox.`);let r=await this.client.utils.deleteSession(e);return{success:r.success,sessionId:r.sessionId,timestamp:r.timestamp}}async getContainerPlacementId(){return this.ctx.storage.get("containerPlacementId")}getSessionWrapper(e){return{id:e,terminal:null,exec:a((r,n)=>this.execWithSession(r,e,n),"exec"),execStream:a((r,n)=>this.execStreamWithSession(r,e,n),"execStream"),startProcess:a((r,n)=>this.startProcess(r,n,e),"startProcess"),listProcesses:a(()=>this.listProcesses(e),"listProcesses"),getProcess:a(r=>this.getProcess(r,e),"getProcess"),killProcess:a((r,n)=>this.killProcess(r,n),"killProcess"),killAllProcesses:a(()=>this.killAllProcesses(),"killAllProcesses"),cleanupCompletedProcesses:a(()=>this.cleanupCompletedProcesses(),"cleanupCompletedProcesses"),getProcessLogs:a(r=>this.getProcessLogs(r),"getProcessLogs"),streamProcessLogs:a((r,n)=>this.streamProcessLogs(r,n),"streamProcessLogs"),writeFile:a((r,n,s)=>this.writeFile(r,n,{...s,sessionId:e}),"writeFile"),readFile:a(((r,n)=>{let s=n?.encoding;return s==="none"?this.readFile(r,{encoding:"none",sessionId:e}):this.readFile(r,{encoding:s,sessionId:e})}),"readFile"),readFileStream:a(r=>this.readFileStream(r,{sessionId:e}),"readFileStream"),watch:a((r,n)=>this.watch(r,{...n,sessionId:e}),"watch"),checkChanges:a((r,n)=>this.checkChanges(r,{...n,sessionId:e}),"checkChanges"),mkdir:a((r,n)=>this.mkdir(r,{...n,sessionId:e}),"mkdir"),deleteFile:a(r=>this.deleteFile(r,e),"deleteFile"),renameFile:a((r,n)=>this.renameFile(r,n,e),"renameFile"),moveFile:a((r,n)=>this.moveFile(r,n,e),"moveFile"),listFiles:a((r,n)=>this.client.files.listFiles(r,e,n),"listFiles"),exists:a(r=>this.exists(r,e),"exists"),gitCheckout:a((r,n)=>this.gitCheckout(r,{...n,sessionId:e}),"gitCheckout"),setEnvVars:a(async r=>{let{toSet:n,toUnset:s}=Ft(r);try{for(let i of s){let o=`unset ${i}`,c=await this.client.commands.execute(o,e,{origin:"internal"});if(c.exitCode!==0)throw new Error(`Failed to unset ${i}: ${c.stderr||"Unknown error"}`)}for(let[i,o]of Object.entries(n)){let c=`export ${i}=${S(o)}`,u=await this.client.commands.execute(c,e,{origin:"internal"});if(u.exitCode!==0)throw new Error(`Failed to set ${i}: ${u.stderr||"Unknown error"}`)}}catch(i){throw this.logger.error("Failed to set environment variables",i instanceof Error?i:new Error(String(i)),{sessionId:e}),i}},"setEnvVars"),createCodeContext:a(r=>this.codeInterpreter.createCodeContext(r),"createCodeContext"),runCode:a(async(r,n)=>(await this.codeInterpreter.runCode(r,n)).toJSON(),"runCode"),runCodeStream:a((r,n)=>this.codeInterpreter.runCodeStream(r,n),"runCodeStream"),listCodeContexts:a(()=>this.codeInterpreter.listCodeContexts(),"listCodeContexts"),deleteCodeContext:a(r=>this.codeInterpreter.deleteCodeContext(r),"deleteCodeContext"),mountBucket:a((r,n,s)=>this.mountBucket(r,n,s),"mountBucket"),unmountBucket:a(r=>this.unmountBucket(r),"unmountBucket"),createBackup:a(r=>this.createBackup(r),"createBackup"),restoreBackup:a(r=>this.restoreBackup(r),"restoreBackup")}}async createCodeContext(e){return this.codeInterpreter.createCodeContext(e)}async runCode(e,r){return(await this.codeInterpreter.runCode(e,r)).toJSON()}async runCodeStream(e,r){return this.codeInterpreter.runCodeStream(e,r)}async listCodeContexts(){return this.codeInterpreter.listCodeContexts()}async deleteCodeContext(e){return this.codeInterpreter.deleteCodeContext(e)}static UUID_REGEX=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;static validateBackupDir(e,r){if(!e||!e.startsWith("/"))throw new v({message:`${r} must be an absolute path`,code:h.INVALID_BACKUP_CONFIG,httpStatus:400,context:{reason:`${r} must be an absolute path`},timestamp:new Date().toISOString()});if(e.includes("\\0"))throw new v({message:`${r} must not contain null bytes`,code:h.INVALID_BACKUP_CONFIG,httpStatus:400,context:{reason:`${r} must not contain null bytes`},timestamp:new Date().toISOString()});if(e.split("/").includes(".."))throw new v({message:`${r} must not contain ".." path segments`,code:h.INVALID_BACKUP_CONFIG,httpStatus:400,context:{reason:`${r} must not contain ".." path segments`},timestamp:new Date().toISOString()});if(!vn.some(n=>e===n||e.startsWith(`${n}/`)))throw new v({message:`${r} must be inside one of the supported backup roots (${vn.join(", ")})`,code:h.INVALID_BACKUP_CONFIG,httpStatus:400,context:{reason:`${r} must be inside one of the supported backup roots`},timestamp:new Date().toISOString()})}requireBackupBucket(){if(!this.backupBucket)throw new v({message:"Backup not configured. Add a BACKUP_BUCKET R2 binding to your wrangler.jsonc.",code:h.INVALID_BACKUP_CONFIG,httpStatus:400,context:{reason:"Missing BACKUP_BUCKET R2 binding"},timestamp:new Date().toISOString()});return this.backupBucket}normalizeBackupExcludes(e){let r=[];for(let n of e){let s=ea(n);if(s===null){this.logger.warn("Exclude pattern reduced to empty after globstar normalization; skipping",{original:n});continue}s!==n&&this.logger.warn("Exclude pattern contained ** (globstar) which mksquashfs does not support; normalized automatically",{original:n,normalized:s}),r.push(s)}return r}resolveBackupCompression(e){if(e!==void 0&&(typeof e!="object"||e===null))throw new v({message:"BackupOptions.compression must be an object",code:h.INVALID_BACKUP_CONFIG,httpStatus:400,context:{reason:"compression must be an object"},timestamp:new Date().toISOString()});let r=e,n=r?.format??bu,s=r?.threads??Ru;if(typeof n!="string"||!["gzip","lz4","zstd"].includes(n))throw new v({message:"BackupOptions.compression.format must be one of: gzip, lz4, zstd",code:h.INVALID_BACKUP_CONFIG,httpStatus:400,context:{reason:"compression.format must be one of: gzip, lz4, zstd"},timestamp:new Date().toISOString()});if(typeof s!="number"||!Number.isInteger(s)||s<1)throw new v({message:"BackupOptions.compression.threads must be a positive integer",code:h.INVALID_BACKUP_CONFIG,httpStatus:400,context:{reason:"compression.threads must be a positive integer"},timestamp:new Date().toISOString()});return{format:n,threads:s}}static PRESIGNED_URL_EXPIRY_SECONDS=3600;async ensureBackupSession(){let e=`__sandbox_backup_${crypto.randomUUID()}`;return await this.client.utils.createSession({id:e,cwd:"/"}),e}requirePresignedURLSupport(){if(!this.r2Client||!this.r2AccountId||!this.backupBucketName){let e=[];throw this.r2AccountId||e.push("CLOUDFLARE_R2_ACCOUNT_ID or CLOUDFLARE_ACCOUNT_ID"),this.r2AccessKeyId||e.push("R2_ACCESS_KEY_ID"),this.r2SecretAccessKey||e.push("R2_SECRET_ACCESS_KEY"),this.backupBucketName||e.push("BACKUP_BUCKET_NAME"),new v({message:`Backup requires R2 presigned URL credentials. Missing: ${e.join(", ")}. Set these as environment variables or secrets in your wrangler.jsonc.`,code:h.INVALID_BACKUP_CONFIG,httpStatus:400,context:{reason:`Missing env vars: ${e.join(", ")}`},timestamp:new Date().toISOString()})}return{client:this.r2Client,accountId:this.r2AccountId,bucketName:this.backupBucketName}}getBackupBucketEndpoint(e){return this.backupBucketEndpoint??`https://${e}.r2.cloudflarestorage.com`}getBackupObjectURL(e,r,n){let s=encodeURIComponent(r),i=n.split("/").map(o=>encodeURIComponent(o)).join("/");return new URL(`${this.getBackupBucketEndpoint(e)}/${s}/${i}`)}async generatePresignedGetURL(e){let{client:r,accountId:n,bucketName:s}=this.requirePresignedURLSupport(),i=this.getBackupObjectURL(n,s,e);return i.searchParams.set("X-Amz-Expires",String(te.PRESIGNED_URL_EXPIRY_SECONDS)),(await r.sign(new Request(i),{aws:{signQuery:!0}})).url}async generatePresignedPutURL(e){let{client:r,accountId:n,bucketName:s}=this.requirePresignedURLSupport(),i=this.getBackupObjectURL(n,s,e);return i.searchParams.set("X-Amz-Expires",String(te.PRESIGNED_URL_EXPIRY_SECONDS)),(await r.sign(new Request(i,{method:"PUT"}),{aws:{signQuery:!0}})).url}async uploadBackupPresigned(e,r,n,s,i,o){let c=await this.generatePresignedPutURL(r),u=["curl -sSf","-X PUT","-H \'Content-Type: application/octet-stream\'","--connect-timeout 10","--max-time 1800","--retry 2","--retry-max-time 60",`-T ${S(e)}`,S(c)].join(" "),l=await this.execWithSession(u,o,{timeout:181e4,origin:"internal"});if(l.exitCode!==0)throw new G({message:`Presigned URL upload failed (exit code ${l.exitCode}): ${l.stderr}`,code:h.BACKUP_CREATE_FAILED,httpStatus:500,context:{dir:i,backupId:s},timestamp:new Date().toISOString()});let d=await this.requireBackupBucket().head(r);if(!d||d.size!==n){let p=d?.size??0;throw new G({message:`Upload verification failed: expected ${n} bytes, got ${p}.${l.exitCode===0&&p===0?\' This usually means the BACKUP_BUCKET R2 binding is using local storage while presigned URLs upload to remote R2. Add `"remote": true` to your BACKUP_BUCKET R2 binding in wrangler.jsonc to fix this.\':""}`,code:h.BACKUP_CREATE_FAILED,httpStatus:500,context:{dir:i,backupId:s},timestamp:new Date().toISOString()})}}async generatePresignedPartURL(e,r,n){let{client:s,accountId:i,bucketName:o}=this.requirePresignedURLSupport(),c=this.getBackupObjectURL(i,o,e);return c.searchParams.set("X-Amz-Expires",String(te.PRESIGNED_URL_EXPIRY_SECONDS)),c.searchParams.set("partNumber",String(n)),c.searchParams.set("uploadId",r),(await s.sign(new Request(c,{method:"PUT"}),{aws:{signQuery:!0}})).url}async uploadBackupMultipart(e,r,n,s,i,o){let c=Qn(n,Iu,xu),u=Math.min(c,Math.floor(n/Cu));if(u<=1)return this.uploadBackupPresigned(e,r,n,s,i,o);let{client:l,accountId:d,bucketName:p}=this.requirePresignedURLSupport(),g=this.getBackupObjectURL(d,p,r).toString(),m=await l.fetch(`${g}?uploads`,{method:"POST"});if(!m.ok)throw new G({message:`Failed to initiate multipart upload: HTTP ${m.status}`,code:h.BACKUP_CREATE_FAILED,httpStatus:500,context:{dir:i,backupId:s},timestamp:new Date().toISOString()});let f=(await m.text()).match(/<UploadId>([^<]+)<\\/UploadId>/)?.[1];if(!f)throw new G({message:"Multipart upload response did not contain an UploadId",code:h.BACKUP_CREATE_FAILED,httpStatus:500,context:{dir:i,backupId:s},timestamp:new Date().toISOString()});let w=a(async()=>{await l.fetch(`${g}?uploadId=${encodeURIComponent(f)}`,{method:"DELETE"}).catch(()=>{})},"abortMultipart");try{let y=Math.ceil(n/u),E=await Promise.all(Array.from({length:u},(C,P)=>({partNumber:P+1,url:"",offset:P*y,size:P===u-1?n-P*y:y})).map(async C=>({...C,url:await this.generatePresignedPartURL(r,f,C.partNumber)}))),T;try{T=await this.client.backup.uploadParts({archivePath:e,parts:E,sessionId:o})}catch(C){if(C instanceof R&&C.errorResponse.httpStatus===404)return await w(),this.uploadBackupPresigned(e,r,n,s,i,o);throw C}if(!T.success||T.parts.length!==u)throw new G({message:`Multipart upload returned ${T.parts.length} of ${u} parts`,code:h.BACKUP_CREATE_FAILED,httpStatus:500,context:{dir:i,backupId:s},timestamp:new Date().toISOString()});let x=["<CompleteMultipartUpload>",...T.parts.map(C=>`<Part><PartNumber>${C.partNumber}</PartNumber><ETag>${C.etag}</ETag></Part>`),"</CompleteMultipartUpload>"].join(""),b=await l.fetch(`${g}?uploadId=${encodeURIComponent(f)}`,{method:"POST",headers:{"Content-Type":"application/xml"},body:x});if(!b.ok){let C=await b.text().catch(()=>"");throw new G({message:`Multipart upload completion failed: HTTP ${b.status} ${C}`,code:h.BACKUP_CREATE_FAILED,httpStatus:500,context:{dir:i,backupId:s},timestamp:new Date().toISOString()})}let I=await this.requireBackupBucket().head(r);if(!I||I.size!==n)throw new G({message:`Multipart upload verification failed: expected ${n} bytes, got ${I?.size??0}`,code:h.BACKUP_CREATE_FAILED,httpStatus:500,context:{dir:i,backupId:s},timestamp:new Date().toISOString()})}catch(y){throw await w(),y}}async downloadBackupParallel(e,r,n,s,i,o){let c=await this.generatePresignedGetURL(r);await this.execWithSession(`mkdir -p ${Y}`,o,{origin:"internal"});let u=`${e}.tmp`;if(n<Ou){let g=["curl -sSf","--connect-timeout 10","--max-time 1800","--retry 2","--retry-max-time 60",`-o ${S(u)}`,S(c)].join(" "),m=await this.execWithSession(g,o,{timeout:181e4,origin:"internal"});if(m.exitCode!==0)throw await this.execWithSession(`rm -f ${S(u)}`,o,{origin:"internal"}).catch(()=>{}),new V({message:`Presigned URL download failed (exit code ${m.exitCode}): ${m.stderr}`,code:h.BACKUP_RESTORE_FAILED,httpStatus:500,context:{dir:i,backupId:s},timestamp:new Date().toISOString()})}else{let g=Qn(n,vu,_u),m=Math.floor(n/g),f=Array.from({length:g},(x,b)=>{let I=b*m;return{start:I,range:`${I}-${b<g-1?I+m-1:n-1}`}}).map(({start:x,range:b})=>["curl -sSf","--connect-timeout 10","--max-time 1800",`-H ${S(`Range: bytes=${b}`)}`,S(c),"|","dd",`of=${S(u)}`,"oflag=seek_bytes",`seek=${x}`,"conv=notrunc","2>/dev/null"].join(" ")).map((x,b)=>`(set -o pipefail; ${x}) & J${b}=$!`),w=Array.from({length:g},(x,b)=>`wait $J${b}; E${b}=$?`),y=Array.from({length:g},(x,b)=>`$E${b}`),E=[`rm -f ${S(u)}`,`truncate -s ${n} ${S(u)}`,...f,...w,`FAILED=$(( ${y.join(" + ")} ))`,`if [ "$FAILED" -ne 0 ]; then rm -f ${S(u)}; exit 1; fi`].join("; "),T=await this.execWithSession(E,o,{timeout:181e4,origin:"internal"});if(T.exitCode!==0)throw await this.execWithSession(`rm -f ${S(u)}`,o,{origin:"internal"}).catch(()=>{}),new V({message:`Parallel download failed (exit code ${T.exitCode}): ${T.stderr}`,code:h.BACKUP_RESTORE_FAILED,httpStatus:500,context:{dir:i,backupId:s},timestamp:new Date().toISOString()})}let l=await this.execWithSession(`stat -c %s ${S(u)}`,o,{origin:"internal"}),d=parseInt(l.stdout.trim(),10);if(d!==n)throw await this.execWithSession(`rm -f ${S(u)}`,o,{origin:"internal"}).catch(()=>{}),new V({message:`Downloaded archive size mismatch: expected ${n}, got ${d}`,code:h.BACKUP_RESTORE_FAILED,httpStatus:500,context:{dir:i,backupId:s},timestamp:new Date().toISOString()});let p=await this.execWithSession(`mv ${S(u)} ${S(e)}`,o,{origin:"internal"});if(p.exitCode!==0)throw await this.execWithSession(`rm -f ${S(u)}`,o,{origin:"internal"}).catch(()=>{}),new V({message:`Failed to finalize downloaded archive: ${p.stderr}`,code:h.BACKUP_RESTORE_FAILED,httpStatus:500,context:{dir:i,backupId:s},timestamp:new Date().toISOString()})}async enqueueBackupOp(e){try{await this.backupInProgress}catch{}let r=e();return this.backupInProgress=r.catch(()=>{}),await r}async createBackup(e){return e.localBucket?await this.enqueueBackupOp(()=>this.doCreateBackupLocal(e)):(this.requireBackupBucket(),await this.enqueueBackupOp(()=>this.doCreateBackup(e)))}async doCreateBackup(e){let r=this.requireBackupBucket();this.requirePresignedURLSupport();let{dir:n,name:s,ttl:i=Jn,gitignore:o=!1,excludes:c=[],compression:u,multipart:l=!0}=e,d=Date.now(),p,g,m="error",f,w;try{if(te.validateBackupDir(n,"BackupOptions.dir"),s!==void 0){if(typeof s!="string"||s.length>ve)throw new v({message:`BackupOptions.name must be a string of at most ${ve} characters`,code:h.INVALID_BACKUP_CONFIG,httpStatus:400,context:{reason:`name must be a string of at most ${ve} characters`},timestamp:new Date().toISOString()});if(/[\\u0000-\\u001f\\u007f]/.test(s))throw new v({message:"BackupOptions.name must not contain control characters",code:h.INVALID_BACKUP_CONFIG,httpStatus:400,context:{reason:"name must not contain control characters"},timestamp:new Date().toISOString()})}if(i<=0)throw new v({message:"BackupOptions.ttl must be a positive number of seconds",code:h.INVALID_BACKUP_CONFIG,httpStatus:400,context:{reason:"ttl must be a positive number of seconds"},timestamp:new Date().toISOString()});if(typeof o!="boolean")throw new v({message:"BackupOptions.gitignore must be a boolean",code:h.INVALID_BACKUP_CONFIG,httpStatus:400,context:{reason:"gitignore must be a boolean"},timestamp:new Date().toISOString()});if(!Array.isArray(c)||!c.every(P=>typeof P=="string"))throw new v({message:"BackupOptions.excludes must be an array of strings",code:h.INVALID_BACKUP_CONFIG,httpStatus:400,context:{reason:"excludes must be an array of strings"},timestamp:new Date().toISOString()});let y=this.resolveBackupCompression(u),E=this.normalizeBackupExcludes(c);w=await this.ensureBackupSession(),p=crypto.randomUUID();let T=`${Y}/${p}.sqsh`,x=await this.client.backup.createArchive(n,T,w,{gitignore:o,excludes:E,compression:y});if(!x.success)throw new G({message:"Container failed to create backup archive",code:h.BACKUP_CREATE_FAILED,httpStatus:500,context:{dir:n,backupId:p},timestamp:new Date().toISOString()});g=x.sizeBytes;let b=`${z}/${p}/${Oe}`,I=`${z}/${p}/${_e}`;l&&x.sizeBytes>=Tu?await this.uploadBackupMultipart(T,b,x.sizeBytes,p,n,w):await this.uploadBackupPresigned(T,b,x.sizeBytes,p,n,w);let C={id:p,dir:n,name:s||null,sizeBytes:x.sizeBytes,ttl:i,createdAt:new Date().toISOString()};return await r.put(I,JSON.stringify(C)),m="success",await this.execWithSession(`rm -f ${S(T)}`,w,{origin:"internal"}).catch(()=>{}),{id:p,dir:n}}catch(y){if(f=y instanceof Error?y:new Error(String(y)),p&&w){let E=`${Y}/${p}.sqsh`,T=`${z}/${p}/${Oe}`,x=`${z}/${p}/${_e}`;await this.execWithSession(`rm -f ${S(E)}`,w,{origin:"internal"}).catch(()=>{}),await r.delete(T).catch(()=>{}),await r.delete(x).catch(()=>{})}throw y}finally{w&&await this.client.utils.deleteSession(w).catch(()=>{}),N(this.logger,{event:"backup.create",outcome:m,durationMs:Date.now()-d,backupId:p,dir:n,name:s,sizeBytes:g,error:f})}}async doCreateBackupLocal(e){let{dir:r,name:n,ttl:s=Jn,gitignore:i=!1,excludes:o=[],compression:c}=e,u=Date.now(),l,d,p="error",g,m,f=this.env.BACKUP_BUCKET;if(!f||!Ae(f))throw new v({message:"BACKUP_BUCKET R2 binding not found in env. Add a BACKUP_BUCKET R2 binding to your wrangler.jsonc for local backup support.",code:h.INVALID_BACKUP_CONFIG,httpStatus:400,context:{reason:"Missing BACKUP_BUCKET R2 binding"},timestamp:new Date().toISOString()});try{if(te.validateBackupDir(r,"BackupOptions.dir"),n!==void 0){if(typeof n!="string"||n.length>ve)throw new v({message:`BackupOptions.name must be a string of at most ${ve} characters`,code:h.INVALID_BACKUP_CONFIG,httpStatus:400,context:{reason:`name must be a string of at most ${ve} characters`},timestamp:new Date().toISOString()});if(/[\\u0000-\\u001f\\u007f]/.test(n))throw new v({message:"BackupOptions.name must not contain control characters",code:h.INVALID_BACKUP_CONFIG,httpStatus:400,context:{reason:"name must not contain control characters"},timestamp:new Date().toISOString()})}if(s<=0)throw new v({message:"BackupOptions.ttl must be a positive number of seconds",code:h.INVALID_BACKUP_CONFIG,httpStatus:400,context:{reason:"ttl must be a positive number of seconds"},timestamp:new Date().toISOString()});if(typeof i!="boolean")throw new v({message:"BackupOptions.gitignore must be a boolean",code:h.INVALID_BACKUP_CONFIG,httpStatus:400,context:{reason:"gitignore must be a boolean"},timestamp:new Date().toISOString()});if(!Array.isArray(o)||!o.every(Ne=>typeof Ne=="string"))throw new v({message:"BackupOptions.excludes must be an array of strings",code:h.INVALID_BACKUP_CONFIG,httpStatus:400,context:{reason:"excludes must be an array of strings"},timestamp:new Date().toISOString()});let w=this.resolveBackupCompression(c),y=this.normalizeBackupExcludes(o);m=await this.ensureBackupSession(),l=crypto.randomUUID();let E=`${Y}/${l}.sqsh`,T=await this.client.backup.createArchive(r,E,m,{gitignore:i,excludes:y,compression:w});if(!T.success)throw new G({message:"Container failed to create backup archive",code:h.BACKUP_CREATE_FAILED,httpStatus:500,context:{dir:r,backupId:l},timestamp:new Date().toISOString()});d=T.sizeBytes;let x=`${z}/${l}/${Oe}`,b=`${z}/${l}/${_e}`,I=await this.client.files.readFileStream(E,m),C=new ReadableStream({async start(Ne){try{for await(let ot of Cs(I))ot instanceof Uint8Array&&Ne.enqueue(ot);Ne.close()}catch(ot){Ne.error(ot)}}}),P=new FixedLengthStream(T.sizeBytes);C.pipeTo(P.writable).catch(()=>{}),await f.put(x,P.readable);let H=await f.head(x);if(!H||H.size!==T.sizeBytes)throw new G({message:`Upload verification failed: expected ${T.sizeBytes} bytes, got ${H?.size??0}`,code:h.BACKUP_CREATE_FAILED,httpStatus:500,context:{dir:r,backupId:l},timestamp:new Date().toISOString()});let Qs={id:l,dir:r,name:n||null,sizeBytes:T.sizeBytes,ttl:s,createdAt:new Date().toISOString()};return await f.put(b,JSON.stringify(Qs)),p="success",await this.execWithSession(`rm -f ${S(E)}`,m,{origin:"internal"}).catch(()=>{}),{id:l,dir:r,localBucket:!0}}catch(w){if(g=w instanceof Error?w:new Error(String(w)),l&&m){let y=`${Y}/${l}.sqsh`,E=`${z}/${l}/${Oe}`,T=`${z}/${l}/${_e}`;await this.execWithSession(`rm -f ${S(y)}`,m,{origin:"internal"}).catch(()=>{}),await f.delete(E).catch(()=>{}),await f.delete(T).catch(()=>{})}throw w}finally{m&&await this.client.utils.deleteSession(m).catch(()=>{}),N(this.logger,{event:"backup.create",outcome:p,durationMs:Date.now()-u,backupId:l,dir:r,name:n,sizeBytes:d,provider:"local-binding",error:g})}}async restoreBackup(e){return e.localBucket||this.requireBackupBucket(),await this.enqueueBackupOp(()=>this.doRestoreBackupWithRecovery(e))}async doRestoreBackupWithRecovery(e){return await new aa({storage:this.ctx.storage,currentRuntime:this.currentRuntime,currentLifetime:this.currentLifetime}).execute({backupId:e.id,dir:e.dir,attempt:a(async r=>e.localBucket?await this.doRestoreBackupLocal(e,r):await this.doRestoreBackup(e,r),"attempt")})}async doRestoreBackup(e,r){let n=Date.now(),s=this.requireBackupBucket();this.requirePresignedURLSupport();let{id:i,dir:o}=e,c="error",u,l;try{if(!i||typeof i!="string")throw new v({message:"Invalid backup: missing or invalid id",code:h.INVALID_BACKUP_CONFIG,httpStatus:400,context:{reason:"missing or invalid id"},timestamp:new Date().toISOString()});if(!te.UUID_REGEX.test(i))throw new v({message:"Invalid backup: id must be a valid UUID (e.g. from createBackup)",code:h.INVALID_BACKUP_CONFIG,httpStatus:400,context:{reason:"id must be a valid UUID"},timestamp:new Date().toISOString()});te.validateBackupDir(o,"Invalid backup: dir");let d=`${z}/${i}/${_e}`,p=await s.get(d);if(!p)throw new Pe({message:`Backup not found: ${i}. Verify the backup ID is correct and the backup has not been deleted.`,code:h.BACKUP_NOT_FOUND,httpStatus:404,context:{backupId:i},timestamp:new Date().toISOString()});let g=await p.json(),m=60*1e3,f=new Date(g.createdAt).getTime();if(Number.isNaN(f))throw new V({message:`Backup metadata has invalid createdAt timestamp: ${g.createdAt}`,code:h.BACKUP_RESTORE_FAILED,httpStatus:500,context:{dir:o,backupId:i},timestamp:new Date().toISOString()});let w=f+g.ttl*1e3;if(Date.now()+m>w)throw new Ot({message:`Backup ${i} has expired (created: ${g.createdAt}, TTL: ${g.ttl}s). Create a new backup.`,code:h.BACKUP_EXPIRED,httpStatus:400,context:{backupId:i,expiredAt:new Date(w).toISOString()},timestamp:new Date().toISOString()});let y=`${z}/${i}/${Oe}`,E=await s.head(y);if(!E)throw new Pe({message:`Backup archive not found in R2: ${i}. The archive may have been deleted by R2 lifecycle rules.`,code:h.BACKUP_NOT_FOUND,httpStatus:404,context:{backupId:i},timestamp:new Date().toISOString()});l=await this.ensureBackupSession(),await r.runtimeReady();let T=`${Y}/${i}.sqsh`,x=`${Y}/mounts/${i}`;await this.execWithSession(`/usr/bin/fusermount3 -uz ${S(o)} 2>/dev/null || true`,l,{origin:"internal"}).catch(()=>{}),await this.execWithSession(`for d in ${S(x)}_*/lower ${S(x)}/lower; do [ -d "$d" ] && /usr/bin/fusermount3 -uz "$d" 2>/dev/null; done; true`,l,{origin:"internal"}).catch(()=>{});let b=await this.execWithSession(`stat -c %s ${S(T)} 2>/dev/null || echo 0`,l,{origin:"internal"}).catch(()=>({stdout:"0"}));if(Number.parseInt((b.stdout??"0").trim(),10)!==E.size&&await this.downloadBackupParallel(T,y,E.size,i,o,l),await r.archiveReady(E.size),!(await this.client.backup.restoreArchive(o,T,l)).success)throw new V({message:"Container failed to restore backup archive",code:h.BACKUP_RESTORE_FAILED,httpStatus:500,context:{dir:o,backupId:i},timestamp:new Date().toISOString()});let I={success:!0,dir:o,id:i};return await r.verify(I),c="success",I}catch(d){if(u=d instanceof Error?d:new Error(String(d)),i&&l){let p=`${Y}/${i}.sqsh`;await this.execWithSession(`rm -f ${S(p)}`,l,{origin:"internal"}).catch(()=>{})}throw d}finally{l&&await this.client.utils.deleteSession(l).catch(()=>{}),N(this.logger,{event:"backup.restore",outcome:c,durationMs:Date.now()-n,backupId:i,dir:o,error:u})}}async doRestoreBackupLocal(e,r){let n=Date.now(),{id:s,dir:i}=e,o="error",c,u,l=this.env.BACKUP_BUCKET;if(!l||!Ae(l))throw new v({message:"BACKUP_BUCKET R2 binding not found in env. Add a BACKUP_BUCKET R2 binding to your wrangler.jsonc for local backup support.",code:h.INVALID_BACKUP_CONFIG,httpStatus:400,context:{reason:"Missing BACKUP_BUCKET R2 binding"},timestamp:new Date().toISOString()});try{if(!s||typeof s!="string")throw new v({message:"Invalid backup: missing or invalid id",code:h.INVALID_BACKUP_CONFIG,httpStatus:400,context:{reason:"missing or invalid id"},timestamp:new Date().toISOString()});if(!te.UUID_REGEX.test(s))throw new v({message:"Invalid backup: id must be a valid UUID (e.g. from createBackup)",code:h.INVALID_BACKUP_CONFIG,httpStatus:400,context:{reason:"id must be a valid UUID"},timestamp:new Date().toISOString()});te.validateBackupDir(i,"Invalid backup: dir");let d=`${z}/${s}/${_e}`,p=await l.get(d);if(!p)throw new Pe({message:`Backup not found: ${s}. Verify the backup ID is correct and the backup has not been deleted.`,code:h.BACKUP_NOT_FOUND,httpStatus:404,context:{backupId:s},timestamp:new Date().toISOString()});let g=await p.json(),m=60*1e3,f=new Date(g.createdAt).getTime();if(Number.isNaN(f))throw new V({message:`Backup metadata has invalid createdAt timestamp: ${g.createdAt}`,code:h.BACKUP_RESTORE_FAILED,httpStatus:500,context:{dir:i,backupId:s},timestamp:new Date().toISOString()});let w=f+g.ttl*1e3;if(Date.now()+m>w)throw new Ot({message:`Backup ${s} has expired (created: ${g.createdAt}, TTL: ${g.ttl}s). Create a new backup.`,code:h.BACKUP_EXPIRED,httpStatus:400,context:{backupId:s,expiredAt:new Date(w).toISOString()},timestamp:new Date().toISOString()});let y=`${z}/${s}/${Oe}`,E=await l.get(y);if(!E)throw new Pe({message:`Backup archive not found in R2: ${s}. The archive may have been deleted by R2 lifecycle rules.`,code:h.BACKUP_NOT_FOUND,httpStatus:404,context:{backupId:s},timestamp:new Date().toISOString()});let T=g.sizeBytes;u=await this.ensureBackupSession(),await r.runtimeReady();let x=`${Y}/${s}.sqsh`;if(await this.execWithSession(`mkdir -p ${Y}`,u,{origin:"internal"}),this.transport==="rpc"){let C=E.body;if(!C)throw new V({message:`R2 archive object has no body stream for backup ${s}`,code:h.BACKUP_RESTORE_FAILED,httpStatus:500,context:{dir:i,backupId:s},timestamp:new Date().toISOString()});await this.client.files.writeFileStream(x,C,u)}else{let C=await E.arrayBuffer(),P=Buffer.from(C).toString("base64"),H=await this.client.files.writeFile(x,P,u,{encoding:"base64"});if(!H.success)throw new V({message:`Failed to write backup archive to ${x}: ${"error"in H&&typeof H.error=="object"&&H.error!==null&&"message"in H.error&&typeof H.error.message=="string"?H.error.message:`File write returned success: false for \'${x}\'`}`,code:h.BACKUP_RESTORE_FAILED,httpStatus:500,context:{dir:i,backupId:s},timestamp:new Date().toISOString()})}await r.archiveReady(T);let b=await this.execWithSession(`/usr/bin/unsquashfs -f -d ${S(i)} ${S(x)}`,u,{origin:"internal"});if(b.exitCode!==0)throw new V({message:`unsquashfs extraction failed (exit code ${b.exitCode}): ${b.stderr}`,code:h.BACKUP_RESTORE_FAILED,httpStatus:500,context:{dir:i,backupId:s},timestamp:new Date().toISOString()});let I={success:!0,dir:i,id:s};return await r.verify(I),await this.execWithSession(`rm -f ${S(x)}`,u,{origin:"internal"}).catch(()=>{}),o="success",I}catch(d){if(c=d instanceof Error?d:new Error(String(d)),s&&u){let p=`${Y}/${s}.sqsh`;await this.execWithSession(`rm -f ${S(p)}`,u,{origin:"internal"}).catch(()=>{})}throw d}finally{u&&await this.client.utils.deleteSession(u).catch(()=>{}),N(this.logger,{event:"backup.restore",outcome:o,durationMs:Date.now()-n,backupId:s,dir:i,provider:"local-binding",error:c})}}async configureR2EgressOutbound(e){let r=this.ctx;if(!r.container?.interceptOutboundHttp)throw new _("R2 binding mounts require container outbound interception support");if(!r.exports?.ContainerProxy)throw new _("R2 binding mounts require exporting ContainerProxy from the Worker entrypoint");this.constructor.outboundHandlers={r2EgressMount:Ar},Object.keys(e.buckets).length>0?await this.setOutboundByHost("r2.internal","r2EgressMount",e):await this.removeOutboundByHost("r2.internal"),this.logger.debug("r2 egress: registering host interception",{host:"r2.internal",method:"r2EgressMount",targetClassName:et});let n=r.exports.ContainerProxy({props:{enableInternet:this.enableInternet,containerId:this.ctx.id.toString(),className:et,outboundByHostOverrides:{"r2.internal":{method:"r2EgressMount",params:e}}}});if(!Xn(n))throw new _("R2 binding mounts require ContainerProxy to return a valid Fetcher");await r.container.interceptOutboundHttp("r2.internal",n)}async configureS3CredentialProxyOutbound(e){let r=this.ctx;if(!r.container?.interceptOutboundHttp)throw new _("Credential proxy bucket mounts require container outbound interception support");if(!r.exports?.ContainerProxy)throw new _("Credential proxy bucket mounts require exporting ContainerProxy from the Worker entrypoint");let n=[lr,wu];if(this.constructor.outboundHandlers={s3CredentialProxyMount:Pr},Object.keys(e.mounts).length>0)for(let o of n)await this.setOutboundByHost(o,"s3CredentialProxyMount",e);else for(let o of n)await this.removeOutboundByHost(o);let s={};for(let o of n)s[o]={method:"s3CredentialProxyMount",params:e};this.logger.debug("s3 credential proxy: registering host interception",{hosts:n,method:"s3CredentialProxyMount",targetClassName:et});let i=r.exports.ContainerProxy({props:{enableInternet:this.enableInternet,containerId:this.ctx.id.toString(),className:et,outboundByHostOverrides:s}});if(!Xn(i))throw new _("Credential proxy bucket mounts require ContainerProxy to return a valid Fetcher");try{let o=await i.fetch(new Request(`http://${lr}${Ds}`));await o.text(),this.logger.debug("s3 credential proxy: fetcher self-test complete",{status:o.status})}catch(o){this.logger.warn("s3 credential proxy: fetcher self-test failed",{error:o instanceof Error?o.message:String(o)})}for(let o of n)await r.container.interceptOutboundHttp(o,i)}};import{RpcTarget as Br,WorkerEntrypoint as $u}from"cloudflare:workers";var ae="__voidSandboxLease",Hu=30,Wu=5e3,Ku=new Set(["exec","execStream","startProcess","listProcesses","getProcess","killProcess","killAllProcesses","cleanupCompletedProcesses","getProcessLogs","streamProcessLogs","writeFile","readFile","readFileStream","watch","checkChanges","mkdir","deleteFile","renameFile","moveFile","listFiles","exists","gitCheckout","setEnvVars","mountBucket","unmountBucket","createSession","getSession","deleteSession","getContainerPlacementId","createCodeContext","runCode","runCodeStream","listCodeContexts","deleteCodeContext","createBackup","restoreBackup","exposePort","unexposePort","getExposedPorts","isPortExposed","validatePortToken","terminal","wsConnect","fetch","destroy","stop","getState","setSleepAfter","setKeepAlive","setContainerTimeouts","setTransport","setLabels"]),ju=new Set(["sleepAfter","keepAlive","enableDefaultSession","normalizeId","containerTimeouts","transport","labels"]),zu=new Set(["exec","execStream","startProcess","listProcesses","getProcess","killProcess","killAllProcesses","cleanupCompletedProcesses","getProcessLogs","streamProcessLogs","writeFile","readFile","readFileStream","watch","checkChanges","mkdir","deleteFile","renameFile","moveFile","listFiles","exists","gitCheckout","setEnvVars","mountBucket","unmountBucket","createCodeContext","runCode","runCodeStream","listCodeContexts","deleteCodeContext","createBackup","restoreBackup","terminal"]),Gu=new Set(["kill","getStatus","getLogs","waitForLog","waitForPort","waitForExit"]);function Xs(t){if(!t||typeof t!="object"||Array.isArray(t))throw new TypeError("Sandbox options must be an object.");for(let e of Object.keys(t))if(!ju.has(e))throw new TypeError(`Unsupported Sandbox option: ${e}`);for(let e of["keepAlive","enableDefaultSession","normalizeId"])if(t[e]!==void 0&&typeof t[e]!="boolean")throw new TypeError(`Sandbox ${e} must be a boolean.`);if(t.sleepAfter!==void 0&&!(typeof t.sleepAfter=="number"&&Number.isFinite(t.sleepAfter)&&t.sleepAfter>0||typeof t.sleepAfter=="string"&&/^\\d+(?:\\.\\d+)?[smh]$/.test(t.sleepAfter)))throw new TypeError("Sandbox sleepAfter must be a positive duration.");if(t.transport!==void 0&&!["http","websocket","rpc"].includes(t.transport))throw new TypeError("Invalid Sandbox transport.");if(t.containerTimeouts!==void 0){let e=t.containerTimeouts;if(!e||typeof e!="object"||Array.isArray(e))throw new TypeError("Sandbox containerTimeouts must be an object.");for(let[r,n]of Object.entries(e))if(!["instanceGetTimeoutMS","portReadyTimeoutMS","waitIntervalMS"].includes(r)||typeof n!="number"||!Number.isFinite(n)||n<=0||n>3e5)throw new TypeError(`Invalid Sandbox container timeout: ${r}`)}if(t.labels!==void 0&&(!t.labels||typeof t.labels!="object"||Array.isArray(t.labels)||Object.values(t.labels).some(e=>typeof e!="string")))throw new TypeError("Sandbox labels must be strings.")}a(Xs,"validateOptions");function Dt(t){return new Error(`VOID_SANDBOX_${t==="concurrency"||t==="runtime_budget"?t:"unavailable"}`)}a(Dt,"denied");async function Vs(t){let e;try{return await Promise.race([t,new Promise((r,n)=>{e=setTimeout(()=>n(Dt("unavailable")),Wu)})])}finally{clearTimeout(e)}}a(Vs,"bounded");var Dr=class extends Br{static{a(this,"SandboxCapability")}#e;constructor(e){super(),this.#e=e}async invoke(e,r){if(!Array.isArray(r))throw new TypeError("Sandbox arguments must be an array.");if(e==="tunnels"){let[o,...c]=r;if(typeof o!="string"||!["get","list","destroy"].includes(o))throw new TypeError("Unsupported Sandbox tunnel operation.");return this.#e.callTunnels(o,c)}if(!Ku.has(e))throw new TypeError(`Unsupported Sandbox operation: ${e}`);let n={setSleepAfter:"sleepAfter",setKeepAlive:"keepAlive",setContainerTimeouts:"containerTimeouts",setTransport:"transport",setLabels:"labels"}[e];n&&Xs({[n]:r[0]});let i=await this.#e[e](...Ys(r));return e==="createSession"||e==="getSession"?Vu(i):Js(i)}},Lr=class extends Br{static{a(this,"ProcessCapability")}#e;constructor(e){super(),this.#e=e}async invoke(e,r){if(!Array.isArray(r))throw new TypeError("Process arguments must be an array.");if(!Gu.has(e))throw new TypeError(`Unsupported Sandbox process operation: ${e}`);return this.#e[e](...r)}},Mr=class extends Br{static{a(this,"SessionCapability")}#e;constructor(e){super(),this.#e=e}async invoke(e,r){if(!Array.isArray(r))throw new TypeError("Session arguments must be an array.");if(!zu.has(e))throw new TypeError(`Unsupported Sandbox session operation: ${e}`);let n=this.#e;return Js(await n[e](...Ys(r)))}};function Ys(t){let[e,r,...n]=t;if(!r||typeof r!="object"||Array.isArray(r))return t;let s=r;return typeof s.onStart!="function"?t:[e,{...s,onStart:a(i=>s.onStart(Ur(i)),"onStart")},...n]}a(Ys,"prepareProcessCallbacks");function Ur(t){return{__voidSandboxType:"process",capability:new Lr(t),id:t.id,...t.pid===void 0?{}:{pid:t.pid},command:t.command,status:t.status,startTime:t.startTime,...t.endTime===void 0?{}:{endTime:t.endTime},...t.exitCode===void 0?{}:{exitCode:t.exitCode},...t.sessionId===void 0?{}:{sessionId:t.sessionId}}}a(Ur,"processWire");function Vu(t){return{__voidSandboxType:"session",capability:new Mr(t),id:t.id}}a(Vu,"sessionWire");function Js(t){return ht(t)?Ur(t):Array.isArray(t)&&t.every(ht)?t.map(Ur):t}a(Js,"transferableResult");var Fr=class extends $u{static{a(this,"SandboxService")}async getSandbox(e,r={}){if(typeof e!="string"||e.length===0||e.length>63)throw new TypeError("Sandbox id must contain between 1 and 63 characters.");Xs(r);let n=kr(this.env.SANDBOX,e,r);return await n.configure({sandboxName:{name:r.normalizeId?e.toLowerCase():e,normalizeId:r.normalizeId},sleepAfter:r.sleepAfter,keepAlive:r.keepAlive,containerTimeouts:r.containerTimeouts,transport:r.transport,labels:r.labels}),new Dr(n)}fetch(){return new Response("Not found",{status:404})}},qs=class extends Nr{static{a(this,"SandboxController")}#e;#t;async#r(){this.deleteSchedules("voidHeartbeat"),await this.schedule(Hu,"voidHeartbeat")}async#n(e,r){let n=await Vs(this.env.__VOID_SANDBOX_CONTROL[e](this.ctx.id.toString(),r.generation));if(!n.ok)throw Dt(n.reason)}async#o(){let e=await this.ctx.storage.get(ae);if(e?.phase==="running"&&this.ctx.container?.running){await this.#n("heartbeat",e);return}e&&await this.#a(),e={generation:crypto.randomUUID(),phase:"pending"},await this.ctx.storage.put(ae,e),await this.#r(),await this.#n("reserve",e)}#s(e){if(this.#e)return this.#e;let r=(async()=>{try{await this.#o(),await e()}catch(n){throw await this.#a().catch(()=>{}),n}})();return this.#e=r,r.finally(()=>{this.#e===r&&(this.#e=void 0)}).catch(()=>{}),r}start(...e){return this.#s(()=>super.start(...e))}startAndWaitForPorts(...e){return this.#s(()=>super.startAndWaitForPorts(...e))}async onStart(){let e=await this.ctx.storage.get(ae);if(!e||e.phase==="stopped"||!this.ctx.container?.running)throw Dt("unavailable");await this.#n("started",e),await this.ctx.storage.put(ae,{...e,phase:"running"}),await this.#r(),await super.onStart()}async#i(){if(this.#t)return this.#t;let e=(async()=>{if(this.ctx.container?.running)return;let r=await this.ctx.storage.get(ae);r&&(await this.ctx.storage.put(ae,{...r,phase:"stopped"}),await this.#r(),await Vs(this.env.__VOID_SANDBOX_CONTROL.stopped(this.ctx.id.toString(),r.generation)),await this.ctx.storage.delete(ae),this.deleteSchedules("voidHeartbeat"))})();this.#t=e;try{await e}finally{this.#t===e&&(this.#t=void 0)}}async#a(){if(this.ctx.container?.running&&await this.ctx.container.destroy(),this.ctx.container?.running)throw Dt("unavailable");await this.#i()}async onStop(...e){await this.#i(),await super.onStop(...e)}async voidHeartbeat(){try{let e=await this.ctx.storage.get(ae);if(!e)return;e.phase==="running"&&this.ctx.container?.running?await this.#n("heartbeat",e):(e.phase!=="pending"||!this.#e)&&await this.#a()}catch(e){await this.#a().catch(()=>{}),console.error("[void/sandbox] lifecycle check failed",e)}finally{await this.ctx.storage.get(ae)&&await this.#r()}}};export{js as ContainerProxy,qs as SandboxController,Fr as default};\n/*! Bundled license information:\n\naws4fetch/dist/aws4fetch.esm.mjs:\n (**\n * @license MIT <https://opensource.org/licenses/MIT>\n * @copyright Michael Hart 2024\n *)\n*/\n//# sourceMappingURL=sandbox-controller-runtime.js.map\n';
|
|
59790
|
+
|
|
59791
|
+
// ../../home/runner/work/void/void/platform/packages/api/src/sandbox-controller-source.ts
|
|
59792
|
+
function getSandboxControllerSource() {
|
|
59793
|
+
if (!sandbox_controller_source_default) {
|
|
59794
|
+
throw new Error("The platform runtime is missing its Sandbox controller bundle.");
|
|
59795
|
+
}
|
|
59796
|
+
return sandbox_controller_source_default;
|
|
59797
|
+
}
|
|
59798
|
+
__name(getSandboxControllerSource, "getSandboxControllerSource");
|
|
59799
|
+
|
|
59800
|
+
// ../../home/runner/work/void/void/platform/packages/api/src/provisioning/sandbox-controller.ts
|
|
59801
|
+
init_schema2();
|
|
59802
|
+
init_cloudflare_api();
|
|
59803
|
+
var CONTROLLER_CLASS = "SandboxController";
|
|
59804
|
+
var CONTROLLER_BINDING = "SANDBOX";
|
|
59805
|
+
var OWNER_BINDING = "__VOID_SANDBOX_OWNER";
|
|
59806
|
+
function sandboxControllerWorkerName(projectId, deploymentId) {
|
|
59807
|
+
return `void-sb-${projectId}-${deploymentId}`.toLowerCase().replaceAll("_", "-");
|
|
59808
|
+
}
|
|
59809
|
+
__name(sandboxControllerWorkerName, "sandboxControllerWorkerName");
|
|
59810
|
+
function isManagedSandbox(manifest) {
|
|
59811
|
+
return manifest?.sandbox?.runtime?.protocol === 1;
|
|
59812
|
+
}
|
|
59813
|
+
__name(isManagedSandbox, "isManagedSandbox");
|
|
59814
|
+
async function assertManagedSandboxEntitlement(accountId, apiToken) {
|
|
59815
|
+
try {
|
|
59816
|
+
await cfFetch(`${CF_API_BASE}/${accountId}/containers/applications`, apiToken);
|
|
59817
|
+
} catch {
|
|
59818
|
+
throw new Error(
|
|
59819
|
+
[
|
|
59820
|
+
"This app uses void/sandbox, but the platform could not verify Cloudflare Containers access.",
|
|
59821
|
+
"Cloudflare Containers require Workers Paid. Enable it for the platform account: https://dash.cloudflare.com/?to=/:account/workers/plans .",
|
|
59822
|
+
"The platform runtime API token needs Account / Containers: Edit and Account / Cloudchamber: Edit.",
|
|
59823
|
+
"An administrator can update the token and retry. No app resources were provisioned."
|
|
59824
|
+
].join(" ")
|
|
59825
|
+
);
|
|
59826
|
+
}
|
|
59827
|
+
}
|
|
59828
|
+
__name(assertManagedSandboxEntitlement, "assertManagedSandboxEntitlement");
|
|
59829
|
+
function workerUrl(accountId, workerName) {
|
|
59830
|
+
return `${CF_API_BASE}/${accountId}/workers/scripts/${workerName}`;
|
|
59831
|
+
}
|
|
59832
|
+
__name(workerUrl, "workerUrl");
|
|
59833
|
+
async function readSettings(accountId, apiToken, workerName) {
|
|
59834
|
+
try {
|
|
59835
|
+
return await cfFetch(`${workerUrl(accountId, workerName)}/settings`, apiToken);
|
|
59836
|
+
} catch (error) {
|
|
59837
|
+
if (error instanceof CloudflareApiError && error.status === 404) {
|
|
59838
|
+
return void 0;
|
|
59839
|
+
}
|
|
59840
|
+
throw error;
|
|
59841
|
+
}
|
|
59842
|
+
}
|
|
59843
|
+
__name(readSettings, "readSettings");
|
|
59844
|
+
function assertOwnership(settings, projectId, deploymentId) {
|
|
59845
|
+
const marker = settings.bindings.find(
|
|
59846
|
+
(binding) => binding.name === OWNER_BINDING && binding.type === "plain_text"
|
|
59847
|
+
);
|
|
59848
|
+
if (marker?.text !== JSON.stringify({ protocol: 1, projectId, deploymentId })) {
|
|
59849
|
+
throw new Error(
|
|
59850
|
+
"Sandbox controller ownership does not match this deployment; refusing to modify it."
|
|
59851
|
+
);
|
|
59852
|
+
}
|
|
59853
|
+
}
|
|
59854
|
+
__name(assertOwnership, "assertOwnership");
|
|
59855
|
+
function namespaceId(settings) {
|
|
59856
|
+
const binding = settings.bindings.find(
|
|
59857
|
+
(binding2) => binding2.type === "durable_object_namespace" && binding2.name === CONTROLLER_BINDING && binding2.class_name === CONTROLLER_CLASS
|
|
59858
|
+
);
|
|
59859
|
+
if (!binding?.namespace_id) {
|
|
59860
|
+
throw new Error("Sandbox controller Durable Object namespace is missing.");
|
|
59861
|
+
}
|
|
59862
|
+
return binding.namespace_id;
|
|
59863
|
+
}
|
|
59864
|
+
__name(namespaceId, "namespaceId");
|
|
59865
|
+
function plainTextBinding(settings, name) {
|
|
59866
|
+
const binding = settings.bindings.find(
|
|
59867
|
+
(candidate) => candidate.type === "plain_text" && candidate.name === name
|
|
59868
|
+
);
|
|
59869
|
+
return binding?.text;
|
|
59870
|
+
}
|
|
59871
|
+
__name(plainTextBinding, "plainTextBinding");
|
|
59872
|
+
function assertConfiguration(settings, identity, apiService, digest2) {
|
|
59873
|
+
assertOwnership(settings, identity.projectId, identity.deploymentId);
|
|
59874
|
+
const expectedText = {
|
|
59875
|
+
__VOID_SANDBOX_SOURCE: digest2,
|
|
59876
|
+
__VOID_USER_ID: identity.userId,
|
|
59877
|
+
__PROJECT_ID: identity.projectId,
|
|
59878
|
+
__VOID_PROJECT_SLUG: identity.slug,
|
|
59879
|
+
__VOID_DEPLOYMENT_ID: identity.deploymentId
|
|
59880
|
+
};
|
|
59881
|
+
for (const [name, value] of Object.entries(expectedText)) {
|
|
59882
|
+
if (plainTextBinding(settings, name) !== value) {
|
|
59883
|
+
throw new Error(`Sandbox controller binding ${name} differs from this deployment.`);
|
|
59884
|
+
}
|
|
59885
|
+
}
|
|
59886
|
+
const control = settings.bindings.find(
|
|
59887
|
+
(binding) => binding.type === "service" && binding.name === "__VOID_SANDBOX_CONTROL"
|
|
59888
|
+
);
|
|
59889
|
+
if (control?.service !== apiService || control.entrypoint !== "SandboxControl" || !control.props || control.props.projectId !== identity.projectId || control.props.deploymentId !== identity.deploymentId || control.props.userId !== identity.userId || control.props.slug !== identity.slug) {
|
|
59890
|
+
throw new Error("Sandbox controller authority binding differs from this deployment.");
|
|
59891
|
+
}
|
|
59892
|
+
namespaceId(settings);
|
|
59893
|
+
}
|
|
59894
|
+
__name(assertConfiguration, "assertConfiguration");
|
|
59895
|
+
async function provisionSandboxController(input2) {
|
|
59896
|
+
const { accountId, apiToken, apiService, identity, sandbox } = input2;
|
|
59897
|
+
const workerName = sandboxControllerWorkerName(identity.projectId, identity.deploymentId);
|
|
59898
|
+
const source = getSandboxControllerSource();
|
|
59899
|
+
const digest2 = Array.from(
|
|
59900
|
+
new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(source))),
|
|
59901
|
+
(byte) => byte.toString(16).padStart(2, "0")
|
|
59902
|
+
).join("");
|
|
59903
|
+
let settings = await readSettings(accountId, apiToken, workerName);
|
|
59904
|
+
if (settings) {
|
|
59905
|
+
assertConfiguration(settings, identity, apiService, digest2);
|
|
59906
|
+
} else {
|
|
59907
|
+
const form2 = new FormData();
|
|
59908
|
+
const metadata = {
|
|
59909
|
+
main_module: "index.js",
|
|
59910
|
+
compatibility_date: "2026-09-01",
|
|
59911
|
+
compatibility_flags: ["nodejs_compat"],
|
|
59912
|
+
bindings: [
|
|
59913
|
+
{
|
|
59914
|
+
type: "durable_object_namespace",
|
|
59915
|
+
name: CONTROLLER_BINDING,
|
|
59916
|
+
class_name: CONTROLLER_CLASS
|
|
59917
|
+
},
|
|
59918
|
+
{
|
|
59919
|
+
type: "service",
|
|
59920
|
+
name: "__VOID_SANDBOX_CONTROL",
|
|
59921
|
+
service: apiService,
|
|
59922
|
+
entrypoint: "SandboxControl",
|
|
59923
|
+
props: identity
|
|
59924
|
+
},
|
|
59925
|
+
...Object.entries({
|
|
59926
|
+
[OWNER_BINDING]: JSON.stringify({
|
|
59927
|
+
protocol: 1,
|
|
59928
|
+
projectId: identity.projectId,
|
|
59929
|
+
deploymentId: identity.deploymentId
|
|
59930
|
+
}),
|
|
59931
|
+
__VOID_SANDBOX_SOURCE: digest2,
|
|
59932
|
+
__VOID_USER_ID: identity.userId,
|
|
59933
|
+
__PROJECT_ID: identity.projectId,
|
|
59934
|
+
__VOID_PROJECT_SLUG: identity.slug,
|
|
59935
|
+
__VOID_DEPLOYMENT_ID: identity.deploymentId
|
|
59936
|
+
}).map(([name, text2]) => ({ type: "plain_text", name, text: text2 }))
|
|
59937
|
+
],
|
|
59938
|
+
migrations: { new_tag: "v1", steps: [{ new_sqlite_classes: [CONTROLLER_CLASS] }] },
|
|
59939
|
+
containers: [{ class_name: CONTROLLER_CLASS }]
|
|
59940
|
+
};
|
|
59941
|
+
form2.append("metadata", new Blob([JSON.stringify(metadata)], { type: "application/json" }));
|
|
59942
|
+
form2.append(
|
|
59943
|
+
"index.js",
|
|
59944
|
+
new Blob([source], { type: "application/javascript+module" }),
|
|
59945
|
+
"index.js"
|
|
59946
|
+
);
|
|
59947
|
+
const response = await fetch(workerUrl(accountId, workerName), {
|
|
59948
|
+
method: "PUT",
|
|
59949
|
+
headers: { Authorization: `Bearer ${apiToken}`, "If-None-Match": "*" },
|
|
59950
|
+
body: form2
|
|
59951
|
+
});
|
|
59952
|
+
if (!response.ok && response.status !== 409 && response.status !== 412) {
|
|
59953
|
+
throw new Error(
|
|
59954
|
+
`Sandbox controller upload failed (HTTP ${response.status}): ${await response.text()}`
|
|
59955
|
+
);
|
|
59956
|
+
}
|
|
59957
|
+
settings = await readSettings(accountId, apiToken, workerName);
|
|
59958
|
+
if (!settings) {
|
|
59959
|
+
throw new Error("Sandbox controller was not visible after upload. Retry the deployment.");
|
|
59744
59960
|
}
|
|
59961
|
+
assertConfiguration(settings, identity, apiService, digest2);
|
|
59962
|
+
}
|
|
59963
|
+
await cfFetch(`${workerUrl(accountId, workerName)}/subdomain`, apiToken, {
|
|
59964
|
+
method: "POST",
|
|
59965
|
+
body: JSON.stringify({ enabled: false, previews_enabled: false })
|
|
59966
|
+
});
|
|
59967
|
+
const namespace = namespaceId(settings);
|
|
59968
|
+
const applicationName = perDeployContainerApplicationName(
|
|
59969
|
+
identity.projectId,
|
|
59970
|
+
identity.deploymentId,
|
|
59971
|
+
sandbox.containerName ?? "void-sandbox"
|
|
59745
59972
|
);
|
|
59746
|
-
await assertSandboxContainerCreationAllowed(routing);
|
|
59747
59973
|
const created = await tryCreateContainerApplication(accountId, apiToken, {
|
|
59748
|
-
name:
|
|
59974
|
+
name: applicationName,
|
|
59975
|
+
namespaceId: namespace,
|
|
59749
59976
|
image: sandbox.image,
|
|
59750
|
-
namespaceId,
|
|
59751
59977
|
instanceType: sandbox.instanceType,
|
|
59752
59978
|
maxInstances: sandbox.maxInstances
|
|
59753
59979
|
});
|
|
59754
|
-
|
|
59755
|
-
|
|
59756
|
-
|
|
59980
|
+
const application = created ?? await findContainerApplication(accountId, apiToken, applicationName);
|
|
59981
|
+
if (!application || application.durable_objects?.namespace_id !== namespace) {
|
|
59982
|
+
throw new Error("Sandbox container application does not belong to this controller namespace.");
|
|
59983
|
+
}
|
|
59984
|
+
return { workerName, containerApplicationId: application.id };
|
|
59985
|
+
}
|
|
59986
|
+
__name(provisionSandboxController, "provisionSandboxController");
|
|
59987
|
+
async function verifySandboxController(accountId, apiToken, projectId, deploymentId, sandbox) {
|
|
59988
|
+
const settings = await readSettings(
|
|
59989
|
+
accountId,
|
|
59990
|
+
apiToken,
|
|
59991
|
+
sandboxControllerWorkerName(projectId, deploymentId)
|
|
59992
|
+
);
|
|
59993
|
+
if (!settings) {
|
|
59994
|
+
throw new Error("Sandbox controller is missing. Redeploy the app before rolling back.");
|
|
59995
|
+
}
|
|
59996
|
+
assertOwnership(settings, projectId, deploymentId);
|
|
59997
|
+
const application = await findContainerApplication(
|
|
59998
|
+
accountId,
|
|
59999
|
+
apiToken,
|
|
60000
|
+
perDeployContainerApplicationName(
|
|
60001
|
+
projectId,
|
|
60002
|
+
deploymentId,
|
|
60003
|
+
sandbox.containerName ?? "void-sandbox"
|
|
60004
|
+
)
|
|
60005
|
+
);
|
|
60006
|
+
if (!application || application.durable_objects?.namespace_id !== namespaceId(settings)) {
|
|
60007
|
+
throw new Error(
|
|
60008
|
+
"Sandbox container is missing or belongs to another controller. Redeploy the app before rolling back."
|
|
60009
|
+
);
|
|
60010
|
+
}
|
|
60011
|
+
}
|
|
60012
|
+
__name(verifySandboxController, "verifySandboxController");
|
|
60013
|
+
async function deleteSandboxController(accountId, apiToken, projectId, deploymentId, sandbox, counters, db) {
|
|
60014
|
+
const workerName = sandboxControllerWorkerName(projectId, deploymentId);
|
|
60015
|
+
const settings = await readSettings(accountId, apiToken, workerName);
|
|
60016
|
+
const application = await findContainerApplication(
|
|
60017
|
+
accountId,
|
|
60018
|
+
apiToken,
|
|
60019
|
+
perDeployContainerApplicationName(
|
|
60020
|
+
projectId,
|
|
60021
|
+
deploymentId,
|
|
60022
|
+
sandbox.containerName ?? "void-sandbox"
|
|
60023
|
+
)
|
|
60024
|
+
);
|
|
60025
|
+
if (!settings) {
|
|
60026
|
+
if (application) {
|
|
59757
60027
|
throw new Error(
|
|
59758
|
-
|
|
60028
|
+
"Cannot verify ownership of a Sandbox container whose controller is missing."
|
|
59759
60029
|
);
|
|
59760
60030
|
}
|
|
59761
|
-
|
|
59762
|
-
|
|
59763
|
-
|
|
59764
|
-
);
|
|
60031
|
+
await revokeDeploymentCapacity(counters, db, void 0, projectId, deploymentId);
|
|
60032
|
+
if (db) {
|
|
60033
|
+
await markCleanupComplete(db, deploymentId);
|
|
59765
60034
|
}
|
|
60035
|
+
return;
|
|
60036
|
+
}
|
|
60037
|
+
assertOwnership(settings, projectId, deploymentId);
|
|
60038
|
+
if (application) {
|
|
60039
|
+
if (application.durable_objects?.namespace_id !== namespaceId(settings)) {
|
|
60040
|
+
throw new Error("Refusing to delete a Sandbox container belonging to another namespace.");
|
|
60041
|
+
}
|
|
60042
|
+
await deleteContainerApplicationIdempotent(accountId, apiToken, application.id);
|
|
60043
|
+
}
|
|
60044
|
+
await revokeDeploymentCapacity(counters, db, settings, projectId, deploymentId);
|
|
60045
|
+
const response = await fetch(workerUrl(accountId, workerName), {
|
|
60046
|
+
method: "DELETE",
|
|
60047
|
+
headers: { Authorization: `Bearer ${apiToken}` }
|
|
60048
|
+
});
|
|
60049
|
+
if (!response.ok && response.status !== 404) {
|
|
60050
|
+
throw new Error(`Sandbox controller deletion failed (HTTP ${response.status}).`);
|
|
60051
|
+
}
|
|
60052
|
+
if (db) {
|
|
60053
|
+
await markCleanupComplete(db, deploymentId);
|
|
60054
|
+
}
|
|
60055
|
+
}
|
|
60056
|
+
__name(deleteSandboxController, "deleteSandboxController");
|
|
60057
|
+
async function revokeDeploymentCapacity(counters, db, settings, projectId, deploymentId) {
|
|
60058
|
+
let userId = settings ? plainTextBinding(settings, "__VOID_USER_ID") : void 0;
|
|
60059
|
+
let databaseUserId;
|
|
60060
|
+
if (db) {
|
|
60061
|
+
const [owner] = await db.select({ userId: projects.user_id }).from(deployments).innerJoin(projects, eq(projects.id, deployments.project_id)).where(and(eq(deployments.id, deploymentId), eq(deployments.project_id, projectId))).limit(1);
|
|
60062
|
+
databaseUserId = owner?.userId;
|
|
60063
|
+
}
|
|
60064
|
+
if (databaseUserId && userId && userId !== databaseUserId) {
|
|
60065
|
+
throw new Error("Sandbox controller owner binding differs from the deployment owner.");
|
|
60066
|
+
}
|
|
60067
|
+
userId ??= databaseUserId;
|
|
60068
|
+
if (!userId) {
|
|
60069
|
+
throw new Error("Cannot release Sandbox capacity without the deployment owner identity.");
|
|
60070
|
+
}
|
|
60071
|
+
const counter = counters.get(counters.idFromName(`account:${userId}`));
|
|
60072
|
+
await counter.revokeDeployment(projectId, deploymentId);
|
|
60073
|
+
}
|
|
60074
|
+
__name(revokeDeploymentCapacity, "revokeDeploymentCapacity");
|
|
60075
|
+
async function markCleanupComplete(db, deploymentId) {
|
|
60076
|
+
await db.update(deployments).set({
|
|
60077
|
+
manifest: sql`jsonb_set(${deployments.manifest}::jsonb, '{sandbox,runtime,cleanupComplete}', 'true'::jsonb)::text`
|
|
60078
|
+
}).where(eq(deployments.id, deploymentId));
|
|
60079
|
+
}
|
|
60080
|
+
__name(markCleanupComplete, "markCleanupComplete");
|
|
60081
|
+
async function retrySandboxControllerCleanup(db, env) {
|
|
60082
|
+
const rows = await db.select({
|
|
60083
|
+
id: deployments.id,
|
|
60084
|
+
projectId: deployments.project_id,
|
|
60085
|
+
manifest: deployments.manifest
|
|
60086
|
+
}).from(deployments).innerJoin(projects, eq(projects.id, deployments.project_id)).where(
|
|
60087
|
+
and(
|
|
60088
|
+
eq(deployments.retained, false),
|
|
60089
|
+
sql`${deployments.admission_protocol} >= 3`,
|
|
60090
|
+
sql`${deployments.status} IN ('live', 'failed', 'canceled')`,
|
|
60091
|
+
sql`${projects.active_deployment_id} IS DISTINCT FROM ${deployments.id}`,
|
|
60092
|
+
sql`${deployments.manifest}::jsonb #>> '{sandbox,runtime,protocol}' = '1'`,
|
|
60093
|
+
sql`COALESCE(${deployments.manifest}::jsonb #>> '{sandbox,runtime,cleanupComplete}', 'false') <> 'true'`
|
|
60094
|
+
)
|
|
60095
|
+
).orderBy(asc(deployments.updated_at), asc(deployments.id)).limit(16);
|
|
60096
|
+
for (const row of rows) {
|
|
60097
|
+
const manifest = JSON.parse(row.manifest);
|
|
59766
60098
|
try {
|
|
59767
|
-
await
|
|
60099
|
+
await deleteSandboxController(
|
|
60100
|
+
env.CF_ACCOUNT_ID,
|
|
60101
|
+
env.CF_API_TOKEN,
|
|
60102
|
+
row.projectId,
|
|
60103
|
+
row.id,
|
|
60104
|
+
manifest.sandbox,
|
|
60105
|
+
env.SANDBOX_CONCURRENCY_COUNTER,
|
|
60106
|
+
db
|
|
60107
|
+
);
|
|
59768
60108
|
} catch (error) {
|
|
59769
|
-
await
|
|
59770
|
-
|
|
60109
|
+
await db.update(deployments).set({ updated_at: sql`now()` }).where(eq(deployments.id, row.id));
|
|
60110
|
+
console.error("Sandbox controller cleanup failed", { deploymentId: row.id, error });
|
|
59771
60111
|
}
|
|
59772
|
-
return { namespaceId, containerApplicationId: existing.id };
|
|
59773
60112
|
}
|
|
59774
|
-
try {
|
|
59775
|
-
await assertSandboxContainerCreationAllowed(routing);
|
|
59776
|
-
} catch (error) {
|
|
59777
|
-
await deleteContainerApplicationIdempotent(accountId, apiToken, created.id);
|
|
59778
|
-
throw error;
|
|
59779
|
-
}
|
|
59780
|
-
return { namespaceId, containerApplicationId: created.id };
|
|
59781
60113
|
}
|
|
59782
|
-
__name(
|
|
60114
|
+
__name(retrySandboxControllerCleanup, "retrySandboxControllerCleanup");
|
|
59783
60115
|
|
|
59784
60116
|
// ../../home/runner/work/void/void/platform/packages/api/src/provisioning/cleanup.ts
|
|
59785
60117
|
function deleteCloudflareResource(accountId, apiToken, resource) {
|
|
@@ -59830,6 +60162,18 @@ async function sweepPerDeployContainerOrphans(context, projectId, alreadyDeleted
|
|
|
59830
60162
|
if (!manifest?.sandbox) {
|
|
59831
60163
|
continue;
|
|
59832
60164
|
}
|
|
60165
|
+
if (isManagedSandbox(manifest)) {
|
|
60166
|
+
await deleteSandboxController(
|
|
60167
|
+
context.env.CF_ACCOUNT_ID,
|
|
60168
|
+
context.env.CF_API_TOKEN,
|
|
60169
|
+
projectId,
|
|
60170
|
+
deployment.id,
|
|
60171
|
+
manifest.sandbox,
|
|
60172
|
+
context.env.SANDBOX_CONCURRENCY_COUNTER,
|
|
60173
|
+
context.get("db")
|
|
60174
|
+
);
|
|
60175
|
+
continue;
|
|
60176
|
+
}
|
|
59833
60177
|
const orphanName = perDeployContainerApplicationName(
|
|
59834
60178
|
projectId,
|
|
59835
60179
|
deployment.id,
|
|
@@ -60205,7 +60549,7 @@ async function requireProjectRouteCapability(context, projectId, capability, db
|
|
|
60205
60549
|
return await requireProjectCapability(db, projectId, context.get("user").id, capability);
|
|
60206
60550
|
} catch (error) {
|
|
60207
60551
|
if (error instanceof ProjectNotFoundError || error instanceof ProjectAccessDeniedError) {
|
|
60208
|
-
return context.json(
|
|
60552
|
+
return context.json(projectAccessErrorBody(error), error.status);
|
|
60209
60553
|
}
|
|
60210
60554
|
throw error;
|
|
60211
60555
|
}
|
|
@@ -61036,7 +61380,7 @@ function historicalAccountSummary(user, userId) {
|
|
|
61036
61380
|
}
|
|
61037
61381
|
__name(historicalAccountSummary, "historicalAccountSummary");
|
|
61038
61382
|
async function getOwnershipTransferBlockers(db, projectId) {
|
|
61039
|
-
const [activeDeployments, activeBuilds] = await Promise.all([
|
|
61383
|
+
const [activeDeployments, activeBuilds, sandboxControllers] = await Promise.all([
|
|
61040
61384
|
db.select({ id: deployments.id, status: deployments.status, source: deployments.source }).from(deployments).where(
|
|
61041
61385
|
and(
|
|
61042
61386
|
eq(deployments.project_id, projectId),
|
|
@@ -61048,7 +61392,17 @@ async function getOwnershipTransferBlockers(db, projectId) {
|
|
|
61048
61392
|
eq(builds.project_id, projectId),
|
|
61049
61393
|
inArray(builds.status, ["queued", ...ACTIVE_BUILD_STATUSES])
|
|
61050
61394
|
)
|
|
61051
|
-
).orderBy(asc(builds.created_at), asc(builds.id))
|
|
61395
|
+
).orderBy(asc(builds.created_at), asc(builds.id)),
|
|
61396
|
+
// Live/failed/canceled deployments no longer block as active work, but
|
|
61397
|
+
// their owner-bound Sandbox controllers still do until cleanup completes.
|
|
61398
|
+
db.select({ id: deployments.id, status: deployments.status }).from(deployments).where(
|
|
61399
|
+
and(
|
|
61400
|
+
eq(deployments.project_id, projectId),
|
|
61401
|
+
inArray(deployments.status, TERMINAL_DEPLOYMENT_STATUSES),
|
|
61402
|
+
sql`${deployments.manifest}::jsonb #>> '{sandbox,runtime,protocol}' = '1'`,
|
|
61403
|
+
sql`COALESCE(${deployments.manifest}::jsonb #>> '{sandbox,runtime,cleanupComplete}', 'false') <> 'true'`
|
|
61404
|
+
)
|
|
61405
|
+
).orderBy(asc(deployments.created_at), asc(deployments.id))
|
|
61052
61406
|
]);
|
|
61053
61407
|
return [
|
|
61054
61408
|
...activeDeployments.map((deployment) => ({
|
|
@@ -61060,6 +61414,11 @@ async function getOwnershipTransferBlockers(db, projectId) {
|
|
|
61060
61414
|
kind: "build",
|
|
61061
61415
|
id: build.id,
|
|
61062
61416
|
status: build.status
|
|
61417
|
+
})),
|
|
61418
|
+
...sandboxControllers.map((deployment) => ({
|
|
61419
|
+
kind: "sandbox_controller",
|
|
61420
|
+
id: deployment.id,
|
|
61421
|
+
status: deployment.status
|
|
61063
61422
|
}))
|
|
61064
61423
|
];
|
|
61065
61424
|
}
|
|
@@ -61177,7 +61536,7 @@ async function commitOwnershipTransfer(db, projectId, targetUserId, operatorUser
|
|
|
61177
61536
|
if (blockers.length > 0) {
|
|
61178
61537
|
throw new OperatorError(
|
|
61179
61538
|
409,
|
|
61180
|
-
"Project ownership cannot change while project work
|
|
61539
|
+
"Project ownership cannot change while project work or a managed Sandbox controller remains.",
|
|
61181
61540
|
"ownership_transfer_blocked",
|
|
61182
61541
|
{ blockers }
|
|
61183
61542
|
);
|
|
@@ -64655,7 +65014,7 @@ var import_headless = __toESM(require_xterm_headless(), 1);
|
|
|
64655
65014
|
// ../../home/runner/work/void/void/packages/void/package.json
|
|
64656
65015
|
var package_default = {
|
|
64657
65016
|
name: "void",
|
|
64658
|
-
version: "0.20.
|
|
65017
|
+
version: "0.20.3",
|
|
64659
65018
|
repository: {
|
|
64660
65019
|
type: "git",
|
|
64661
65020
|
url: "git+https://github.com/voidzero-dev/void.git",
|
|
@@ -68634,22 +68993,49 @@ var authMiddleware = /* @__PURE__ */ __name(async (context, next) => {
|
|
|
68634
68993
|
}
|
|
68635
68994
|
const header = context.req.header("Authorization");
|
|
68636
68995
|
if (!header?.startsWith("Bearer ")) {
|
|
68637
|
-
return context.json(
|
|
68996
|
+
return context.json(
|
|
68997
|
+
{ error: "unauthorized", message: "Sign in to this platform before continuing." },
|
|
68998
|
+
401
|
|
68999
|
+
);
|
|
68638
69000
|
}
|
|
68639
69001
|
const token = header.slice(7);
|
|
68640
69002
|
const payload = await verifyJwt(token, context.env.JWT_SECRET);
|
|
68641
69003
|
if (!payload || payload.aud !== "api" && payload.aud !== "deploy") {
|
|
68642
|
-
return context.json(
|
|
69004
|
+
return context.json(
|
|
69005
|
+
{
|
|
69006
|
+
error: "invalid or expired token",
|
|
69007
|
+
message: "Your sign-in or credential is invalid or has expired. Sign in again, or replace the credential used by your automation."
|
|
69008
|
+
},
|
|
69009
|
+
401
|
|
69010
|
+
);
|
|
68643
69011
|
}
|
|
68644
69012
|
if (payload.aud === "api" && !await validateHumanSession(context.get("db"), payload, context.get("companyIdentity"))) {
|
|
68645
|
-
return context.json(
|
|
69013
|
+
return context.json(
|
|
69014
|
+
{
|
|
69015
|
+
error: "session revoked; sign in again",
|
|
69016
|
+
message: "Your session is no longer active. Sign in to this platform again before continuing."
|
|
69017
|
+
},
|
|
69018
|
+
401
|
|
69019
|
+
);
|
|
68646
69020
|
}
|
|
68647
69021
|
const user = await getUser(context.get("db"), payload.sub);
|
|
68648
69022
|
if (!user) {
|
|
68649
|
-
return context.json(
|
|
69023
|
+
return context.json(
|
|
69024
|
+
{
|
|
69025
|
+
error: "user not found",
|
|
69026
|
+
message: "This account is no longer available. Sign in with an active account on this platform."
|
|
69027
|
+
},
|
|
69028
|
+
401
|
|
69029
|
+
);
|
|
68650
69030
|
}
|
|
68651
69031
|
if (isAdminSuspended(user.suspended_reason)) {
|
|
68652
|
-
return context.json(
|
|
69032
|
+
return context.json(
|
|
69033
|
+
{
|
|
69034
|
+
error: "account suspended",
|
|
69035
|
+
message: "Your account is suspended. Contact a platform administrator to restore access."
|
|
69036
|
+
},
|
|
69037
|
+
403
|
|
69038
|
+
);
|
|
68653
69039
|
}
|
|
68654
69040
|
context.set("user", user);
|
|
68655
69041
|
if (payload.aud === "api" && payload.sid) {
|
|
@@ -68657,7 +69043,13 @@ var authMiddleware = /* @__PURE__ */ __name(async (context, next) => {
|
|
|
68657
69043
|
}
|
|
68658
69044
|
if (payload.aud === "deploy") {
|
|
68659
69045
|
if (!payload.project) {
|
|
68660
|
-
return context.json(
|
|
69046
|
+
return context.json(
|
|
69047
|
+
{
|
|
69048
|
+
error: "invalid or expired token",
|
|
69049
|
+
message: "This deploy credential is invalid. Ask the project owner to issue a replacement."
|
|
69050
|
+
},
|
|
69051
|
+
401
|
|
69052
|
+
);
|
|
68661
69053
|
}
|
|
68662
69054
|
context.set("deployScope", payload.project);
|
|
68663
69055
|
context.set("deployBuild", payload.build);
|
|
@@ -68673,17 +69065,35 @@ var authMiddleware = /* @__PURE__ */ __name(async (context, next) => {
|
|
|
68673
69065
|
)
|
|
68674
69066
|
).limit(1).then((rows) => rows[0]);
|
|
68675
69067
|
if (!credential) {
|
|
68676
|
-
return context.json(
|
|
69068
|
+
return context.json(
|
|
69069
|
+
{
|
|
69070
|
+
error: "deploy credential revoked or expired",
|
|
69071
|
+
message: "This deploy credential has expired or been revoked. Ask the project owner to issue a new credential and update your deployment configuration."
|
|
69072
|
+
},
|
|
69073
|
+
401
|
|
69074
|
+
);
|
|
68677
69075
|
}
|
|
68678
69076
|
context.set("deployCredential", payload.credential);
|
|
68679
69077
|
}
|
|
68680
69078
|
if (!isDeployTokenAllowed(context.req.method, context.req.path, payload.project)) {
|
|
68681
|
-
return context.json(
|
|
69079
|
+
return context.json(
|
|
69080
|
+
{
|
|
69081
|
+
error: "forbidden",
|
|
69082
|
+
message: "This credential can only deploy to its assigned project. Use a credential issued for the selected project, or sign in with your account to manage project settings and members."
|
|
69083
|
+
},
|
|
69084
|
+
403
|
|
69085
|
+
);
|
|
68682
69086
|
}
|
|
68683
69087
|
if (payload.build) {
|
|
68684
69088
|
const boundBuild = await getBuild(context.get("db"), payload.build);
|
|
68685
69089
|
if (!boundBuild || !ACTIVE_BUILD_STATUSES.includes(boundBuild.status) || boundBuild.project_id !== payload.project) {
|
|
68686
|
-
return context.json(
|
|
69090
|
+
return context.json(
|
|
69091
|
+
{
|
|
69092
|
+
error: "deploy token build is no longer active",
|
|
69093
|
+
message: "This build is no longer active. Start a new build to obtain a valid deployment credential."
|
|
69094
|
+
},
|
|
69095
|
+
403
|
|
69096
|
+
);
|
|
68687
69097
|
}
|
|
68688
69098
|
}
|
|
68689
69099
|
}
|
|
@@ -70645,6 +71055,7 @@ __name(presignAssetPut, "presignAssetPut");
|
|
|
70645
71055
|
init_performance2();
|
|
70646
71056
|
var RESERVED_BINDING_NAMES = /* @__PURE__ */ new Set([
|
|
70647
71057
|
"__VOID_PROXY",
|
|
71058
|
+
"__VOID_SANDBOX",
|
|
70648
71059
|
"__PROJECT_ID",
|
|
70649
71060
|
"__VOID_PROXY_TOKEN",
|
|
70650
71061
|
"__VOID_USER_ID",
|
|
@@ -71018,15 +71429,23 @@ async function settleDeploymentForSandboxDrain(env, db, deploymentId) {
|
|
|
71018
71429
|
}
|
|
71019
71430
|
if (deployment.status !== "cutover" && deployment.status !== "compensating") {
|
|
71020
71431
|
if (deployment.status !== "canceling") {
|
|
71021
|
-
const requested = await cancelDeployment(
|
|
71432
|
+
const requested = await cancelDeployment(
|
|
71433
|
+
txDb,
|
|
71434
|
+
deployment.id,
|
|
71435
|
+
"legacy managed Sandbox drain"
|
|
71436
|
+
);
|
|
71022
71437
|
return { state: requested ? "cancel_requested" : "waiting" };
|
|
71023
71438
|
}
|
|
71024
71439
|
if (ageMs < DEPLOYMENT_CANCEL_STALE_MS) {
|
|
71025
71440
|
return { state: "waiting" };
|
|
71026
71441
|
}
|
|
71027
|
-
await updateDeploymentStatus(
|
|
71028
|
-
|
|
71029
|
-
|
|
71442
|
+
await updateDeploymentStatus(
|
|
71443
|
+
txDb,
|
|
71444
|
+
deployment.id,
|
|
71445
|
+
"canceled",
|
|
71446
|
+
"legacy managed Sandbox drain",
|
|
71447
|
+
{ force: true }
|
|
71448
|
+
);
|
|
71030
71449
|
return { state: "terminal" };
|
|
71031
71450
|
}
|
|
71032
71451
|
const project = await getProject(txDb, deployment.project_id);
|
|
@@ -71621,15 +72040,18 @@ function buildWebSocketUploadBindings(websocket) {
|
|
|
71621
72040
|
}));
|
|
71622
72041
|
}
|
|
71623
72042
|
__name(buildWebSocketUploadBindings, "buildWebSocketUploadBindings");
|
|
71624
|
-
function buildSandboxUploadBindings(sandbox) {
|
|
72043
|
+
function buildSandboxUploadBindings(sandbox, controllerWorkerName) {
|
|
71625
72044
|
if (!sandbox) {
|
|
71626
72045
|
return [];
|
|
71627
72046
|
}
|
|
72047
|
+
if (!controllerWorkerName) {
|
|
72048
|
+
throw new Error("Sandbox controller Worker name is required.");
|
|
72049
|
+
}
|
|
71628
72050
|
return [
|
|
71629
72051
|
{
|
|
71630
|
-
type: "
|
|
71631
|
-
name:
|
|
71632
|
-
|
|
72052
|
+
type: "service",
|
|
72053
|
+
name: "__VOID_SANDBOX",
|
|
72054
|
+
service: controllerWorkerName
|
|
71633
72055
|
}
|
|
71634
72056
|
];
|
|
71635
72057
|
}
|
|
@@ -71647,8 +72069,8 @@ function buildLiveUploadBindings(live) {
|
|
|
71647
72069
|
];
|
|
71648
72070
|
}
|
|
71649
72071
|
__name(buildLiveUploadBindings, "buildLiveUploadBindings");
|
|
71650
|
-
function buildSandboxUploadContainers(
|
|
71651
|
-
return
|
|
72072
|
+
function buildSandboxUploadContainers(_sandbox) {
|
|
72073
|
+
return void 0;
|
|
71652
72074
|
}
|
|
71653
72075
|
__name(buildSandboxUploadContainers, "buildSandboxUploadContainers");
|
|
71654
72076
|
function enrichWebSocketManifest(manifest, previousManifest, currentVersion) {
|
|
@@ -71967,10 +72389,7 @@ app12.post("/:id/deploy/upload-urls", async (context) => {
|
|
|
71967
72389
|
});
|
|
71968
72390
|
} catch (err) {
|
|
71969
72391
|
if (err instanceof ProjectAccessDeniedError) {
|
|
71970
|
-
return context.json(
|
|
71971
|
-
{ error: err instanceof ProjectOwnerSuspendedError ? err.message : "forbidden" },
|
|
71972
|
-
403
|
|
71973
|
-
);
|
|
72392
|
+
return context.json(projectAccessErrorBody(err), 403);
|
|
71974
72393
|
}
|
|
71975
72394
|
if (err instanceof Error && err.message === UPLOAD_URLS_PROJECT_DELETING) {
|
|
71976
72395
|
return context.json({ error: "project is being deleted" }, 410);
|
|
@@ -71999,13 +72418,25 @@ async function handleManifestOnlyDeploy(context) {
|
|
|
71999
72418
|
let project = access.project;
|
|
72000
72419
|
const deployScope = context.get("deployScope");
|
|
72001
72420
|
if (deployScope && deployScope !== projectId) {
|
|
72002
|
-
return context.json(
|
|
72421
|
+
return context.json(
|
|
72422
|
+
{
|
|
72423
|
+
error: "forbidden",
|
|
72424
|
+
message: "This deploy credential belongs to a different project. Use a credential issued for the project you want to deploy."
|
|
72425
|
+
},
|
|
72426
|
+
403
|
|
72427
|
+
);
|
|
72003
72428
|
}
|
|
72004
72429
|
const deployBuild = context.get("deployBuild");
|
|
72005
72430
|
if (deployBuild) {
|
|
72006
72431
|
const build = await getBuild(context.get("db"), deployBuild);
|
|
72007
72432
|
if (!build || !ACTIVE_BUILD_STATUSES.includes(build.status)) {
|
|
72008
|
-
return context.json(
|
|
72433
|
+
return context.json(
|
|
72434
|
+
{
|
|
72435
|
+
error: "forbidden",
|
|
72436
|
+
message: "This build is no longer active. Start a new build to deploy the current version."
|
|
72437
|
+
},
|
|
72438
|
+
403
|
|
72439
|
+
);
|
|
72009
72440
|
}
|
|
72010
72441
|
}
|
|
72011
72442
|
if (project.status === "deleting") {
|
|
@@ -72077,6 +72508,21 @@ async function handleManifestOnlyDeploy(context) {
|
|
|
72077
72508
|
return context.json({ event: "error", message: shapeError }, 400);
|
|
72078
72509
|
}
|
|
72079
72510
|
const incomingManifest = body.manifest;
|
|
72511
|
+
if (incomingManifest.sandbox && incomingManifest.sandbox.controllerProtocol !== 1) {
|
|
72512
|
+
return context.json(
|
|
72513
|
+
{
|
|
72514
|
+
event: "error",
|
|
72515
|
+
message: "Managed Sandboxes require an updated Void runtime. Upgrade void, rebuild the app, and deploy again."
|
|
72516
|
+
},
|
|
72517
|
+
400
|
|
72518
|
+
);
|
|
72519
|
+
}
|
|
72520
|
+
if (incomingManifest.sandbox && "runtime" in incomingManifest.sandbox) {
|
|
72521
|
+
return context.json(
|
|
72522
|
+
{ event: "error", message: "sandbox.runtime is reserved for the platform." },
|
|
72523
|
+
400
|
|
72524
|
+
);
|
|
72525
|
+
}
|
|
72080
72526
|
if (incomingManifest.sandbox && !getPlatformCapabilities(context.env).sandbox) {
|
|
72081
72527
|
return context.json(
|
|
72082
72528
|
{
|
|
@@ -72086,6 +72532,19 @@ async function handleManifestOnlyDeploy(context) {
|
|
|
72086
72532
|
501
|
|
72087
72533
|
);
|
|
72088
72534
|
}
|
|
72535
|
+
if (incomingManifest.sandbox) {
|
|
72536
|
+
try {
|
|
72537
|
+
await assertManagedSandboxEntitlement(context.env.CF_ACCOUNT_ID, context.env.CF_API_TOKEN);
|
|
72538
|
+
} catch (error) {
|
|
72539
|
+
return context.json(
|
|
72540
|
+
{
|
|
72541
|
+
event: "error",
|
|
72542
|
+
message: error instanceof Error ? error.message : "Cloudflare Containers access could not be verified."
|
|
72543
|
+
},
|
|
72544
|
+
403
|
|
72545
|
+
);
|
|
72546
|
+
}
|
|
72547
|
+
}
|
|
72089
72548
|
if (incomingManifest.version == null || !SUPPORTED_MANIFEST_VERSIONS.includes(incomingManifest.version)) {
|
|
72090
72549
|
return context.json(
|
|
72091
72550
|
{ event: "error", message: "Unsupported deploy manifest version. Please update void." },
|
|
@@ -72496,10 +72955,7 @@ async function handleManifestOnlyDeploy(context) {
|
|
|
72496
72955
|
});
|
|
72497
72956
|
} catch (err) {
|
|
72498
72957
|
if (err instanceof ProjectAccessDeniedError) {
|
|
72499
|
-
return context.json(
|
|
72500
|
-
{ error: err instanceof ProjectOwnerSuspendedError ? err.message : "forbidden" },
|
|
72501
|
-
403
|
|
72502
|
-
);
|
|
72958
|
+
return context.json(projectAccessErrorBody(err), 403);
|
|
72503
72959
|
}
|
|
72504
72960
|
if (err instanceof ConcurrentDeployError) {
|
|
72505
72961
|
return context.json({ error: "deploy in progress", deployment: err.deploymentId }, 409);
|
|
@@ -72806,6 +73262,7 @@ async function handleManifestOnlyDeploy(context) {
|
|
|
72806
73262
|
let workerUploadUrl;
|
|
72807
73263
|
let sandboxContainerAppId;
|
|
72808
73264
|
let sandboxContainerAppName;
|
|
73265
|
+
let sandboxControllerAttempted = false;
|
|
72809
73266
|
let manifest;
|
|
72810
73267
|
let workerName;
|
|
72811
73268
|
let dispatchNamespace;
|
|
@@ -72888,6 +73345,9 @@ async function handleManifestOnlyDeploy(context) {
|
|
|
72888
73345
|
);
|
|
72889
73346
|
const manifestVersionChanged = websocketManifestResult.changed || enrichedManifestResult.changed || liveManifestResult.changed;
|
|
72890
73347
|
manifest = liveManifestResult.manifest;
|
|
73348
|
+
if (manifest.sandbox) {
|
|
73349
|
+
manifest = { ...manifest, sandbox: { ...manifest.sandbox, runtime: { protocol: 1 } } };
|
|
73350
|
+
}
|
|
72891
73351
|
if (hasWorkerFiles && manifest.type === void 0) {
|
|
72892
73352
|
manifest = { ...manifest, type: manifest.framework ? "framework" : "void" };
|
|
72893
73353
|
}
|
|
@@ -73555,7 +74015,30 @@ ${Date.now()}
|
|
|
73555
74015
|
text: text2
|
|
73556
74016
|
}));
|
|
73557
74017
|
const websocketBindings = buildWebSocketUploadBindings(manifest2.websocket);
|
|
73558
|
-
|
|
74018
|
+
if (manifest2.sandbox) {
|
|
74019
|
+
currentStep = "sandbox_container";
|
|
74020
|
+
markPhase("sandbox_container");
|
|
74021
|
+
sandboxControllerAttempted = true;
|
|
74022
|
+
const controller = await provisionSandboxController({
|
|
74023
|
+
accountId: context.env.CF_ACCOUNT_ID,
|
|
74024
|
+
apiToken: context.env.CF_API_TOKEN,
|
|
74025
|
+
apiService: context.env.SANDBOX_CONTROL_SERVICE ?? "void-api",
|
|
74026
|
+
identity: {
|
|
74027
|
+
projectId,
|
|
74028
|
+
deploymentId: deployment2.id,
|
|
74029
|
+
userId: owner.id,
|
|
74030
|
+
slug: project.slug
|
|
74031
|
+
},
|
|
74032
|
+
sandbox: manifest2.sandbox
|
|
74033
|
+
});
|
|
74034
|
+
sandboxContainerAppId = controller.containerApplicationId;
|
|
74035
|
+
await assertDeploymentNotCanceled(context.get("db"), deployment2.id);
|
|
74036
|
+
await assertProjectNotDeleting(context.get("db"), projectId);
|
|
74037
|
+
}
|
|
74038
|
+
const sandboxBindings = buildSandboxUploadBindings(
|
|
74039
|
+
manifest2.sandbox,
|
|
74040
|
+
sandboxControllerWorkerName(projectId, deployment2.id)
|
|
74041
|
+
);
|
|
73559
74042
|
const liveBindings = buildLiveUploadBindings(manifest2.live);
|
|
73560
74043
|
const allBindings = [
|
|
73561
74044
|
...plainTextBindings,
|
|
@@ -73572,7 +74055,7 @@ ${Date.now()}
|
|
|
73572
74055
|
const assetConfig = manifest2.assetConfig ?? { not_found_handling: "none" };
|
|
73573
74056
|
const durableObjectMigrations = buildDurableObjectUploadMigrations(
|
|
73574
74057
|
manifest2.websocket?.migrations,
|
|
73575
|
-
|
|
74058
|
+
void 0,
|
|
73576
74059
|
manifest2.live?.migrations
|
|
73577
74060
|
);
|
|
73578
74061
|
const containers = buildSandboxUploadContainers(manifest2.sandbox);
|
|
@@ -73639,33 +74122,6 @@ ${Date.now()}
|
|
|
73639
74122
|
workerUploaded = true;
|
|
73640
74123
|
await assertDeploymentNotCanceled(context.get("db"), deployment2.id);
|
|
73641
74124
|
await assertProjectNotDeleting(context.get("db"), projectId);
|
|
73642
|
-
if (manifest2.sandbox && hasWorkerFiles) {
|
|
73643
|
-
currentStep = "sandbox_container";
|
|
73644
|
-
markPhase("sandbox_container");
|
|
73645
|
-
sandboxContainerAppName = perDeployContainerApplicationName(
|
|
73646
|
-
projectId,
|
|
73647
|
-
deployment2.id,
|
|
73648
|
-
manifest2.sandbox.containerName ?? "void-sandbox"
|
|
73649
|
-
);
|
|
73650
|
-
const { containerApplicationId } = await provisionPerDeployContainer(
|
|
73651
|
-
context.env.CF_ACCOUNT_ID,
|
|
73652
|
-
context.env.CF_API_TOKEN,
|
|
73653
|
-
dispatchNamespace2,
|
|
73654
|
-
workerName2,
|
|
73655
|
-
sandboxContainerAppName,
|
|
73656
|
-
manifest2.sandbox.bindingName,
|
|
73657
|
-
manifest2.sandbox.className,
|
|
73658
|
-
{
|
|
73659
|
-
image: manifest2.sandbox.image,
|
|
73660
|
-
instanceType: manifest2.sandbox.instanceType,
|
|
73661
|
-
maxInstances: manifest2.sandbox.maxInstances
|
|
73662
|
-
},
|
|
73663
|
-
context.env.ROUTING
|
|
73664
|
-
);
|
|
73665
|
-
sandboxContainerAppId = containerApplicationId;
|
|
73666
|
-
await assertDeploymentNotCanceled(context.get("db"), deployment2.id);
|
|
73667
|
-
await assertProjectNotDeleting(context.get("db"), projectId);
|
|
73668
|
-
}
|
|
73669
74125
|
emit2({ event: "worker_upload_done" });
|
|
73670
74126
|
let migrationsApplied = 0;
|
|
73671
74127
|
if (manifest2.migrations && manifest2.migrations.pending > 0) {
|
|
@@ -74319,22 +74775,34 @@ ${Date.now()}
|
|
|
74319
74775
|
try {
|
|
74320
74776
|
const oldManifest = JSON.parse(old.manifest);
|
|
74321
74777
|
if (oldManifest.sandbox) {
|
|
74322
|
-
|
|
74323
|
-
|
|
74324
|
-
|
|
74325
|
-
|
|
74326
|
-
|
|
74327
|
-
|
|
74328
|
-
|
|
74329
|
-
|
|
74330
|
-
|
|
74331
|
-
|
|
74332
|
-
|
|
74333
|
-
|
|
74778
|
+
if (isManagedSandbox(oldManifest)) {
|
|
74779
|
+
await deleteSandboxController(
|
|
74780
|
+
context.env.CF_ACCOUNT_ID,
|
|
74781
|
+
context.env.CF_API_TOKEN,
|
|
74782
|
+
projectId,
|
|
74783
|
+
old.id,
|
|
74784
|
+
oldManifest.sandbox,
|
|
74785
|
+
context.env.SANDBOX_CONCURRENCY_COUNTER,
|
|
74786
|
+
context.get("db")
|
|
74787
|
+
);
|
|
74788
|
+
} else {
|
|
74789
|
+
const oldContainerAppName = perDeployContainerApplicationName(
|
|
74790
|
+
projectId,
|
|
74791
|
+
old.id,
|
|
74792
|
+
oldManifest.sandbox.containerName ?? "void-sandbox"
|
|
74793
|
+
);
|
|
74794
|
+
const existing = await findContainerApplication(
|
|
74334
74795
|
context.env.CF_ACCOUNT_ID,
|
|
74335
74796
|
context.env.CF_API_TOKEN,
|
|
74336
|
-
|
|
74797
|
+
oldContainerAppName
|
|
74337
74798
|
);
|
|
74799
|
+
if (existing) {
|
|
74800
|
+
await deleteContainerApplicationIdempotent(
|
|
74801
|
+
context.env.CF_ACCOUNT_ID,
|
|
74802
|
+
context.env.CF_API_TOKEN,
|
|
74803
|
+
existing.id
|
|
74804
|
+
);
|
|
74805
|
+
}
|
|
74338
74806
|
}
|
|
74339
74807
|
}
|
|
74340
74808
|
} catch (e) {
|
|
@@ -74394,7 +74862,7 @@ ${Date.now()}
|
|
|
74394
74862
|
...migrationsApplied > 0 && { migrations: migrationsApplied }
|
|
74395
74863
|
});
|
|
74396
74864
|
} catch (err) {
|
|
74397
|
-
const raw2 = err instanceof Error ? err.message : String(err);
|
|
74865
|
+
const raw2 = err instanceof ProjectAccessDeniedError ? err.userMessage : err instanceof Error ? err.message : String(err);
|
|
74398
74866
|
const msg = sanitizeDeployErrorMessage(raw2);
|
|
74399
74867
|
if (msg !== raw2) {
|
|
74400
74868
|
logger.error("catch", "raw_error_before_sanitization", err, {
|
|
@@ -74560,7 +75028,21 @@ ${Date.now()}
|
|
|
74560
75028
|
})
|
|
74561
75029
|
);
|
|
74562
75030
|
}
|
|
74563
|
-
if (
|
|
75031
|
+
if (sandboxControllerAttempted && deployment && manifest?.sandbox) {
|
|
75032
|
+
await deleteSandboxController(
|
|
75033
|
+
context.env.CF_ACCOUNT_ID,
|
|
75034
|
+
context.env.CF_API_TOKEN,
|
|
75035
|
+
projectId,
|
|
75036
|
+
deployment.id,
|
|
75037
|
+
manifest.sandbox,
|
|
75038
|
+
context.env.SANDBOX_CONCURRENCY_COUNTER,
|
|
75039
|
+
context.get("db")
|
|
75040
|
+
).catch(
|
|
75041
|
+
(error) => logger.error("catch", "sandbox_controller_cleanup_failed", error, {
|
|
75042
|
+
deploymentId: deployment?.id
|
|
75043
|
+
})
|
|
75044
|
+
);
|
|
75045
|
+
} else if (sandboxContainerAppId) {
|
|
74564
75046
|
await deleteContainerApplicationWithRetry(
|
|
74565
75047
|
context.env.CF_ACCOUNT_ID,
|
|
74566
75048
|
context.env.CF_API_TOKEN,
|
|
@@ -74707,7 +75189,21 @@ ${Date.now()}
|
|
|
74707
75189
|
workerName: failedWorkerName
|
|
74708
75190
|
})
|
|
74709
75191
|
);
|
|
74710
|
-
if (
|
|
75192
|
+
if (sandboxControllerAttempted && deployment && manifest?.sandbox) {
|
|
75193
|
+
await deleteSandboxController(
|
|
75194
|
+
context.env.CF_ACCOUNT_ID,
|
|
75195
|
+
context.env.CF_API_TOKEN,
|
|
75196
|
+
projectId,
|
|
75197
|
+
deployment.id,
|
|
75198
|
+
manifest.sandbox,
|
|
75199
|
+
context.env.SANDBOX_CONCURRENCY_COUNTER,
|
|
75200
|
+
context.get("db")
|
|
75201
|
+
).catch(
|
|
75202
|
+
(error) => logger.error("catch", "sandbox_controller_cleanup_failed", error, {
|
|
75203
|
+
deploymentId: deployment?.id
|
|
75204
|
+
})
|
|
75205
|
+
);
|
|
75206
|
+
} else if (sandboxContainerAppId) {
|
|
74711
75207
|
await deleteContainerApplicationWithRetry(
|
|
74712
75208
|
context.env.CF_ACCOUNT_ID,
|
|
74713
75209
|
context.env.CF_API_TOKEN,
|
|
@@ -74875,10 +75371,16 @@ app12.post("/:id/deploy/preflight", async (context) => {
|
|
|
74875
75371
|
return context.json({ error: "project not found" }, 404);
|
|
74876
75372
|
}
|
|
74877
75373
|
if (resolution.kind === "forbidden") {
|
|
74878
|
-
return context.json({ error: "forbidden" }, 403);
|
|
75374
|
+
return context.json({ error: "forbidden", message: PROJECT_PERMISSION_MESSAGES.deploy }, 403);
|
|
74879
75375
|
}
|
|
74880
75376
|
if (resolution.kind === "owner-suspended") {
|
|
74881
|
-
return context.json(
|
|
75377
|
+
return context.json(
|
|
75378
|
+
{
|
|
75379
|
+
error: "project owner suspended",
|
|
75380
|
+
message: PROJECT_PERMISSION_MESSAGES["owner-suspended"]
|
|
75381
|
+
},
|
|
75382
|
+
403
|
|
75383
|
+
);
|
|
74882
75384
|
}
|
|
74883
75385
|
if (resolution.kind === "deleting") {
|
|
74884
75386
|
return context.json({ error: "project is being deleted" }, 410);
|
|
@@ -75042,10 +75544,13 @@ async function loadSandboxDeploymentPageProjection(db, cursor) {
|
|
|
75042
75544
|
)`,
|
|
75043
75545
|
createdAt: deployments.created_at
|
|
75044
75546
|
}).from(deployments).innerJoin(projects, eq(deployments.project_id, projects.id)).where(
|
|
75045
|
-
|
|
75046
|
-
|
|
75047
|
-
|
|
75048
|
-
|
|
75547
|
+
and(
|
|
75548
|
+
lt(deployments.admission_protocol, 3),
|
|
75549
|
+
createdAt && id ? or(
|
|
75550
|
+
gt(deployments.created_at, createdAt),
|
|
75551
|
+
and(eq(deployments.created_at, createdAt), gt(deployments.id, id))
|
|
75552
|
+
) : void 0
|
|
75553
|
+
)
|
|
75049
75554
|
).orderBy(asc(deployments.created_at), asc(deployments.id)).limit(PAGE_SIZE6 + 1);
|
|
75050
75555
|
}
|
|
75051
75556
|
__name(loadSandboxDeploymentPageProjection, "loadSandboxDeploymentPageProjection");
|
|
@@ -75061,7 +75566,7 @@ async function verifyApplication(env, application, target) {
|
|
|
75061
75566
|
};
|
|
75062
75567
|
}
|
|
75063
75568
|
try {
|
|
75064
|
-
const
|
|
75569
|
+
const namespaceId2 = await findDurableObjectNamespaceId(
|
|
75065
75570
|
env.CF_ACCOUNT_ID,
|
|
75066
75571
|
env.CF_API_TOKEN,
|
|
75067
75572
|
env.DISPATCH_NAMESPACE ?? DEFAULT_DISPATCH_NAMESPACE,
|
|
@@ -75069,7 +75574,7 @@ async function verifyApplication(env, application, target) {
|
|
|
75069
75574
|
target.bindingName,
|
|
75070
75575
|
target.className
|
|
75071
75576
|
);
|
|
75072
|
-
if (
|
|
75577
|
+
if (namespaceId2 !== application.durable_objects.namespace_id) {
|
|
75073
75578
|
return {
|
|
75074
75579
|
kind: "unverified_container",
|
|
75075
75580
|
projectId: target.projectId,
|
|
@@ -75339,7 +75844,7 @@ async function drainManagedSandboxes(db, env, dryRun2 = false, previewCursor) {
|
|
|
75339
75844
|
checkpoint: checkpoint2,
|
|
75340
75845
|
complete: true,
|
|
75341
75846
|
nextCursor: null,
|
|
75342
|
-
effect: "
|
|
75847
|
+
effect: "Legacy tenant-owned Sandbox containers are already drained."
|
|
75343
75848
|
});
|
|
75344
75849
|
}
|
|
75345
75850
|
const position = previewCursor ? parsePreviewCursor(previewCursor) : checkpoint2 ? {
|
|
@@ -75354,7 +75859,7 @@ async function drainManagedSandboxes(db, env, dryRun2 = false, previewCursor) {
|
|
|
75354
75859
|
...page2,
|
|
75355
75860
|
nextCursor: next2.complete ? null : JSON.stringify({ phase: next2.phase, cursor: next2.cursor }),
|
|
75356
75861
|
complete: false,
|
|
75357
|
-
effect: "Block
|
|
75862
|
+
effect: "Block legacy tenant-owned Sandbox activation, cancel active legacy deployments, delete verified container applications, and verify two bounded passes."
|
|
75358
75863
|
});
|
|
75359
75864
|
}
|
|
75360
75865
|
const lease = await acquireSandboxDrainLease(db);
|
|
@@ -75400,7 +75905,7 @@ async function drainManagedSandboxes(db, env, dryRun2 = false, previewCursor) {
|
|
|
75400
75905
|
complete: true,
|
|
75401
75906
|
checkpoint: checkpoint2,
|
|
75402
75907
|
...page,
|
|
75403
|
-
message: "
|
|
75908
|
+
message: "Legacy tenant-owned Sandbox container applications are drained."
|
|
75404
75909
|
};
|
|
75405
75910
|
}
|
|
75406
75911
|
const checkpoint = await checkpointSandboxDrain(db, leaseIdentity, next);
|
|
@@ -76266,6 +76771,7 @@ async function verifyGithubOidcToken(token, opts) {
|
|
|
76266
76771
|
__name(verifyGithubOidcToken, "verifyGithubOidcToken");
|
|
76267
76772
|
|
|
76268
76773
|
// ../../home/runner/work/void/void/platform/packages/api/src/routes/auth-oidc.ts
|
|
76774
|
+
init_project_access();
|
|
76269
76775
|
init_suspension();
|
|
76270
76776
|
init_tiers();
|
|
76271
76777
|
var app13 = new Hono2();
|
|
@@ -76352,7 +76858,10 @@ app13.post("/github-oidc", async (context) => {
|
|
|
76352
76858
|
return context.json({ error: "connection owner not found" }, 401);
|
|
76353
76859
|
}
|
|
76354
76860
|
if (isAdminSuspended(user.suspended_reason)) {
|
|
76355
|
-
return context.json(
|
|
76861
|
+
return context.json(
|
|
76862
|
+
{ error: "project owner suspended", message: PROJECT_PERMISSION_MESSAGES["owner-suspended"] },
|
|
76863
|
+
403
|
|
76864
|
+
);
|
|
76356
76865
|
}
|
|
76357
76866
|
if (typeof claims.ref !== "string" || claims.ref === "") {
|
|
76358
76867
|
return context.json({ error: "oidc token missing ref" }, 401);
|
|
@@ -76426,7 +76935,10 @@ app13.post("/github-oidc", async (context) => {
|
|
|
76426
76935
|
return context.json({ error: "project is being deleted" }, 409);
|
|
76427
76936
|
}
|
|
76428
76937
|
if (result.outcome === "owner-suspended") {
|
|
76429
|
-
return context.json(
|
|
76938
|
+
return context.json(
|
|
76939
|
+
{ error: "project owner suspended", message: PROJECT_PERMISSION_MESSAGES["owner-suspended"] },
|
|
76940
|
+
403
|
|
76941
|
+
);
|
|
76430
76942
|
}
|
|
76431
76943
|
const build = result.build;
|
|
76432
76944
|
const billingOwner = await getUser(db, build.user_id);
|
|
@@ -76911,7 +77423,7 @@ app15.delete("/:id", async (context) => {
|
|
|
76911
77423
|
}));
|
|
76912
77424
|
} catch (error) {
|
|
76913
77425
|
if (error instanceof ProjectNotFoundError || error instanceof ProjectAccessDeniedError) {
|
|
76914
|
-
return context.json(
|
|
77426
|
+
return context.json(projectAccessErrorBody(error), error.status);
|
|
76915
77427
|
}
|
|
76916
77428
|
if (error instanceof ProjectOperationInProgressError) {
|
|
76917
77429
|
return context.json({ error: error.message }, 409);
|
|
@@ -77894,7 +78406,7 @@ function serializeDestination(row) {
|
|
|
77894
78406
|
__name(serializeDestination, "serializeDestination");
|
|
77895
78407
|
function projectAccessErrorResponse(context, error) {
|
|
77896
78408
|
if (error instanceof ProjectNotFoundError || error instanceof ProjectAccessDeniedError) {
|
|
77897
|
-
return context.json(
|
|
78409
|
+
return context.json(projectAccessErrorBody(error), error.status);
|
|
77898
78410
|
}
|
|
77899
78411
|
return null;
|
|
77900
78412
|
}
|
|
@@ -81154,6 +81666,7 @@ var platform_bootstrap_default = app29;
|
|
|
81154
81666
|
// ../../home/runner/work/void/void/platform/packages/api/src/routes/project-team.ts
|
|
81155
81667
|
init_performance2();
|
|
81156
81668
|
init_db2();
|
|
81669
|
+
init_project_access();
|
|
81157
81670
|
var MEMBER_ROLES = /* @__PURE__ */ new Set(["reader", "collaborator", "admin"]);
|
|
81158
81671
|
var INVITATION_EMAILS_PER_MINUTE = 5;
|
|
81159
81672
|
var INVITATION_EMAILS_PER_DAY = 50;
|
|
@@ -81207,7 +81720,7 @@ function mutationErrorResponse(context, error) {
|
|
|
81207
81720
|
if (!(error instanceof ProjectTeamMutationError)) {
|
|
81208
81721
|
return null;
|
|
81209
81722
|
}
|
|
81210
|
-
const
|
|
81723
|
+
const errors = {
|
|
81211
81724
|
"project-not-found": "project not found",
|
|
81212
81725
|
"project-deleting": "project is being deleted",
|
|
81213
81726
|
"target-user-not-found": "registered user not found",
|
|
@@ -81222,7 +81735,25 @@ function mutationErrorResponse(context, error) {
|
|
|
81222
81735
|
"owner-suspended": "project owner suspended",
|
|
81223
81736
|
forbidden: "forbidden"
|
|
81224
81737
|
};
|
|
81225
|
-
|
|
81738
|
+
const messages = {
|
|
81739
|
+
"project-not-found": PROJECT_PERMISSION_MESSAGES["not-found"],
|
|
81740
|
+
"project-deleting": "This project is being deleted. Wait for deletion to finish and select another project.",
|
|
81741
|
+
"target-user-not-found": "No eligible registered account matches that email. Check the address and ask the person to sign in to this platform before inviting them.",
|
|
81742
|
+
"owner-conflict": "The project owner already has full access and cannot be managed as a team member. Manage other members instead.",
|
|
81743
|
+
"member-conflict": "This account is already a project member. Refresh the member list to review its access.",
|
|
81744
|
+
"member-not-found": "This project member could not be found. Refresh the member list and send a new invitation if access is still needed.",
|
|
81745
|
+
"invitation-not-found": "This invitation could not be found. Check your pending invitations or ask a project admin or owner to send a new one.",
|
|
81746
|
+
"invitation-not-pending": "This invitation is no longer pending. If you still need access, ask a project admin or owner to send a new invitation.",
|
|
81747
|
+
"invitation-not-target": "This invitation belongs to a different account. Sign in with the account that received it, or ask a project admin or owner to invite your current account.",
|
|
81748
|
+
"invitation-expired": "This invitation has expired. Ask a project admin or owner to resend it, then accept the renewed invitation.",
|
|
81749
|
+
"pending-invitation-limit": "This project has reached its pending invitation limit. Revoke unused invitations or wait for them to expire, then try again.",
|
|
81750
|
+
"owner-suspended": PROJECT_PERMISSION_MESSAGES["owner-suspended"],
|
|
81751
|
+
forbidden: PROJECT_PERMISSION_MESSAGES.members
|
|
81752
|
+
};
|
|
81753
|
+
return context.json(
|
|
81754
|
+
{ error: errors[error.reason], message: messages[error.reason] },
|
|
81755
|
+
error.status
|
|
81756
|
+
);
|
|
81226
81757
|
}
|
|
81227
81758
|
__name(mutationErrorResponse, "mutationErrorResponse");
|
|
81228
81759
|
async function deliverInvitation(context, invitation, target, projectSlug) {
|
|
@@ -81432,7 +81963,13 @@ var projectTeamRoutes = new Hono2().get("/:id/members", async (context) => {
|
|
|
81432
81963
|
);
|
|
81433
81964
|
const user = await getUser(context.get("db"), member.user_id);
|
|
81434
81965
|
if (!user) {
|
|
81435
|
-
return context.json(
|
|
81966
|
+
return context.json(
|
|
81967
|
+
{
|
|
81968
|
+
error: "project member not found",
|
|
81969
|
+
message: "This project member could not be found. Refresh the member list and send a new invitation if access is still needed."
|
|
81970
|
+
},
|
|
81971
|
+
404
|
|
81972
|
+
);
|
|
81436
81973
|
}
|
|
81437
81974
|
return context.json({ member: memberJson(member, user) });
|
|
81438
81975
|
} catch (error) {
|
|
@@ -81474,7 +82011,13 @@ var projectTeamRoutes = new Hono2().get("/:id/members", async (context) => {
|
|
|
81474
82011
|
return access;
|
|
81475
82012
|
}
|
|
81476
82013
|
if (access.role === "owner") {
|
|
81477
|
-
return context.json(
|
|
82014
|
+
return context.json(
|
|
82015
|
+
{
|
|
82016
|
+
error: "the project owner cannot leave the project",
|
|
82017
|
+
message: "The project owner cannot leave. Ask a platform administrator to transfer ownership before leaving the project."
|
|
82018
|
+
},
|
|
82019
|
+
409
|
|
82020
|
+
);
|
|
81478
82021
|
}
|
|
81479
82022
|
try {
|
|
81480
82023
|
const { cancelledBuilds } = await removeProjectMember(context.get("db"), {
|
|
@@ -81571,6 +82114,7 @@ var projectInvitationResponseRoutes = new Hono2().post("/:invitationId/accept",
|
|
|
81571
82114
|
init_performance2();
|
|
81572
82115
|
init_drizzle_orm();
|
|
81573
82116
|
init_db2();
|
|
82117
|
+
init_project_access();
|
|
81574
82118
|
init_schema2();
|
|
81575
82119
|
var app30 = new Hono2();
|
|
81576
82120
|
function parseExpiryDays(value) {
|
|
@@ -81628,10 +82172,13 @@ __name(publicCredential, "publicCredential");
|
|
|
81628
82172
|
app30.get("/:projectId/tokens", async (context) => {
|
|
81629
82173
|
const project = await ownedProject(context);
|
|
81630
82174
|
if (project === "forbidden") {
|
|
81631
|
-
return context.json({ error: "forbidden" }, 403);
|
|
82175
|
+
return context.json({ error: "forbidden", message: PROJECT_PERMISSION_MESSAGES.tokens }, 403);
|
|
81632
82176
|
}
|
|
81633
82177
|
if (!project) {
|
|
81634
|
-
return context.json(
|
|
82178
|
+
return context.json(
|
|
82179
|
+
{ error: "project not found", message: PROJECT_PERMISSION_MESSAGES["not-found"] },
|
|
82180
|
+
404
|
|
82181
|
+
);
|
|
81635
82182
|
}
|
|
81636
82183
|
const rows = await context.get("db").select().from(projectDeployCredentials).where(eq(projectDeployCredentials.project_id, project.id)).orderBy(desc(projectDeployCredentials.created_at)).limit(100);
|
|
81637
82184
|
return context.json(rows.map(publicCredential));
|
|
@@ -81639,7 +82186,10 @@ app30.get("/:projectId/tokens", async (context) => {
|
|
|
81639
82186
|
app30.post("/:projectId/tokens", async (context) => {
|
|
81640
82187
|
const projectId = context.req.param("projectId");
|
|
81641
82188
|
if (!projectId) {
|
|
81642
|
-
return context.json(
|
|
82189
|
+
return context.json(
|
|
82190
|
+
{ error: "project not found", message: PROJECT_PERMISSION_MESSAGES["not-found"] },
|
|
82191
|
+
404
|
|
82192
|
+
);
|
|
81643
82193
|
}
|
|
81644
82194
|
const body = await context.req.json().catch(() => ({}));
|
|
81645
82195
|
let name;
|
|
@@ -81675,20 +82225,32 @@ app30.post("/:projectId/tokens", async (context) => {
|
|
|
81675
82225
|
return created;
|
|
81676
82226
|
});
|
|
81677
82227
|
if (row === "forbidden") {
|
|
81678
|
-
return context.json({ error: "forbidden" }, 403);
|
|
82228
|
+
return context.json({ error: "forbidden", message: PROJECT_PERMISSION_MESSAGES.tokens }, 403);
|
|
81679
82229
|
}
|
|
81680
82230
|
if (row === "project-deleting") {
|
|
81681
|
-
return context.json(
|
|
82231
|
+
return context.json(
|
|
82232
|
+
{
|
|
82233
|
+
error: "project is being deleted",
|
|
82234
|
+
message: "This project is being deleted. Wait for deletion to finish and select another project."
|
|
82235
|
+
},
|
|
82236
|
+
409
|
|
82237
|
+
);
|
|
81682
82238
|
}
|
|
81683
82239
|
if (!row) {
|
|
81684
|
-
return context.json(
|
|
82240
|
+
return context.json(
|
|
82241
|
+
{ error: "project not found", message: PROJECT_PERMISSION_MESSAGES["not-found"] },
|
|
82242
|
+
404
|
|
82243
|
+
);
|
|
81685
82244
|
}
|
|
81686
82245
|
return context.json({ ...publicCredential(row), token }, 201);
|
|
81687
82246
|
});
|
|
81688
82247
|
app30.post("/:projectId/tokens/:credentialId/renew", async (context) => {
|
|
81689
82248
|
const projectId = context.req.param("projectId");
|
|
81690
82249
|
if (!projectId) {
|
|
81691
|
-
return context.json(
|
|
82250
|
+
return context.json(
|
|
82251
|
+
{ error: "project not found", message: PROJECT_PERMISSION_MESSAGES["not-found"] },
|
|
82252
|
+
404
|
|
82253
|
+
);
|
|
81692
82254
|
}
|
|
81693
82255
|
const body = await context.req.json().catch(() => ({}));
|
|
81694
82256
|
let days;
|
|
@@ -81742,23 +82304,41 @@ app30.post("/:projectId/tokens/:credentialId/renew", async (context) => {
|
|
|
81742
82304
|
return replacement;
|
|
81743
82305
|
});
|
|
81744
82306
|
if (result === "project-not-found") {
|
|
81745
|
-
return context.json(
|
|
82307
|
+
return context.json(
|
|
82308
|
+
{ error: "project not found", message: PROJECT_PERMISSION_MESSAGES["not-found"] },
|
|
82309
|
+
404
|
|
82310
|
+
);
|
|
81746
82311
|
}
|
|
81747
82312
|
if (result === "forbidden") {
|
|
81748
|
-
return context.json({ error: "forbidden" }, 403);
|
|
82313
|
+
return context.json({ error: "forbidden", message: PROJECT_PERMISSION_MESSAGES.tokens }, 403);
|
|
81749
82314
|
}
|
|
81750
82315
|
if (result === "project-deleting") {
|
|
81751
|
-
return context.json(
|
|
82316
|
+
return context.json(
|
|
82317
|
+
{
|
|
82318
|
+
error: "project is being deleted",
|
|
82319
|
+
message: "This project is being deleted. Wait for deletion to finish and select another project."
|
|
82320
|
+
},
|
|
82321
|
+
409
|
|
82322
|
+
);
|
|
81752
82323
|
}
|
|
81753
82324
|
if (!result) {
|
|
81754
|
-
return context.json(
|
|
82325
|
+
return context.json(
|
|
82326
|
+
{
|
|
82327
|
+
error: "active credential not found",
|
|
82328
|
+
message: "This active deploy token could not be found. Refresh the token list; it may have been revoked or renewed."
|
|
82329
|
+
},
|
|
82330
|
+
404
|
|
82331
|
+
);
|
|
81755
82332
|
}
|
|
81756
82333
|
return context.json({ ...publicCredential(result), token });
|
|
81757
82334
|
});
|
|
81758
82335
|
app30.delete("/:projectId/tokens/:credentialId", async (context) => {
|
|
81759
82336
|
const projectId = context.req.param("projectId");
|
|
81760
82337
|
if (!projectId) {
|
|
81761
|
-
return context.json(
|
|
82338
|
+
return context.json(
|
|
82339
|
+
{ error: "project not found", message: PROJECT_PERMISSION_MESSAGES["not-found"] },
|
|
82340
|
+
404
|
|
82341
|
+
);
|
|
81762
82342
|
}
|
|
81763
82343
|
const user = context.get("user");
|
|
81764
82344
|
const row = await context.get("db").transaction(async (tx) => {
|
|
@@ -81779,13 +82359,22 @@ app30.delete("/:projectId/tokens/:credentialId", async (context) => {
|
|
|
81779
82359
|
return revoked ?? null;
|
|
81780
82360
|
});
|
|
81781
82361
|
if (row === "project-not-found") {
|
|
81782
|
-
return context.json(
|
|
82362
|
+
return context.json(
|
|
82363
|
+
{ error: "project not found", message: PROJECT_PERMISSION_MESSAGES["not-found"] },
|
|
82364
|
+
404
|
|
82365
|
+
);
|
|
81783
82366
|
}
|
|
81784
82367
|
if (row === "forbidden") {
|
|
81785
|
-
return context.json({ error: "forbidden" }, 403);
|
|
82368
|
+
return context.json({ error: "forbidden", message: PROJECT_PERMISSION_MESSAGES.tokens }, 403);
|
|
81786
82369
|
}
|
|
81787
82370
|
if (!row) {
|
|
81788
|
-
return context.json(
|
|
82371
|
+
return context.json(
|
|
82372
|
+
{
|
|
82373
|
+
error: "active credential not found",
|
|
82374
|
+
message: "This active deploy token could not be found. Refresh the token list; it may have been revoked or renewed."
|
|
82375
|
+
},
|
|
82376
|
+
404
|
|
82377
|
+
);
|
|
81789
82378
|
}
|
|
81790
82379
|
return context.json({ ok: true, id: row.id });
|
|
81791
82380
|
});
|
|
@@ -82261,6 +82850,7 @@ async function queryD1(accountId, apiToken, databaseId, query, timeoutMs = D1_RE
|
|
|
82261
82850
|
__name(queryD1, "queryD1");
|
|
82262
82851
|
|
|
82263
82852
|
// ../../home/runner/work/void/void/platform/packages/api/src/routes/projects.ts
|
|
82853
|
+
init_project_access();
|
|
82264
82854
|
init_project_secrets();
|
|
82265
82855
|
init_cloudflare_api();
|
|
82266
82856
|
init_reserved_slugs();
|
|
@@ -82333,29 +82923,38 @@ var DESTRUCTIVE_PATTERNS = [
|
|
|
82333
82923
|
];
|
|
82334
82924
|
var DESTRUCTIVE_PRAGMA = "-- void:allow-destructive";
|
|
82335
82925
|
var RollbackError = class extends Error {
|
|
82336
|
-
constructor(status2, message2, destructiveMigrations) {
|
|
82926
|
+
constructor(status2, message2, destructiveMigrations, userMessage) {
|
|
82337
82927
|
super(message2);
|
|
82338
82928
|
this.status = status2;
|
|
82339
82929
|
this.destructiveMigrations = destructiveMigrations;
|
|
82930
|
+
this.userMessage = userMessage;
|
|
82340
82931
|
this.name = "RollbackError";
|
|
82341
82932
|
}
|
|
82342
82933
|
status;
|
|
82343
82934
|
destructiveMigrations;
|
|
82935
|
+
userMessage;
|
|
82344
82936
|
static {
|
|
82345
82937
|
__name(this, "RollbackError");
|
|
82346
82938
|
}
|
|
82347
82939
|
};
|
|
82348
|
-
async function
|
|
82940
|
+
async function getProjectAccessErrorBody(response) {
|
|
82941
|
+
const fallback = response.status === 404 ? { error: "project not found", message: PROJECT_PERMISSION_MESSAGES["not-found"] } : {
|
|
82942
|
+
error: "forbidden",
|
|
82943
|
+
message: "You do not have permission for this action. Ask a project admin or owner to check your access."
|
|
82944
|
+
};
|
|
82349
82945
|
try {
|
|
82350
82946
|
const body = await response.json();
|
|
82351
82947
|
if (typeof body === "object" && body !== null && "error" in body && typeof body.error === "string") {
|
|
82352
|
-
return
|
|
82948
|
+
return {
|
|
82949
|
+
error: body.error,
|
|
82950
|
+
message: "message" in body && typeof body.message === "string" && body.message.trim() ? body.message : fallback.message
|
|
82951
|
+
};
|
|
82353
82952
|
}
|
|
82354
82953
|
} catch {
|
|
82355
82954
|
}
|
|
82356
|
-
return
|
|
82955
|
+
return fallback;
|
|
82357
82956
|
}
|
|
82358
|
-
__name(
|
|
82957
|
+
__name(getProjectAccessErrorBody, "getProjectAccessErrorBody");
|
|
82359
82958
|
var DatabaseUrlPersistenceError = class extends Error {
|
|
82360
82959
|
static {
|
|
82361
82960
|
__name(this, "DatabaseUrlPersistenceError");
|
|
@@ -82705,7 +83304,13 @@ var app31 = new Hono2().get("/", async (context) => {
|
|
|
82705
83304
|
return minted;
|
|
82706
83305
|
}
|
|
82707
83306
|
if (!minted) {
|
|
82708
|
-
return context.json(
|
|
83307
|
+
return context.json(
|
|
83308
|
+
{
|
|
83309
|
+
error: "deploy token build is no longer active",
|
|
83310
|
+
message: "This build is no longer active. Start a new build to obtain a valid deployment credential."
|
|
83311
|
+
},
|
|
83312
|
+
403
|
|
83313
|
+
);
|
|
82709
83314
|
}
|
|
82710
83315
|
token = minted;
|
|
82711
83316
|
} else {
|
|
@@ -82786,6 +83391,17 @@ var app31 = new Hono2().get("/", async (context) => {
|
|
|
82786
83391
|
501
|
|
82787
83392
|
);
|
|
82788
83393
|
}
|
|
83394
|
+
if (preCheck.manifest) {
|
|
83395
|
+
const manifest = JSON.parse(preCheck.manifest);
|
|
83396
|
+
if (manifest.sandbox && (!isManagedSandbox(manifest) || preCheck.admission_protocol < 3)) {
|
|
83397
|
+
return context.json(
|
|
83398
|
+
{
|
|
83399
|
+
error: "This deployment predates managed Sandbox controllers. Redeploy the app before rolling back to it."
|
|
83400
|
+
},
|
|
83401
|
+
409
|
|
83402
|
+
);
|
|
83403
|
+
}
|
|
83404
|
+
}
|
|
82789
83405
|
let rollbackLeaseId;
|
|
82790
83406
|
const rollbackOwnerId = crypto.randomUUID();
|
|
82791
83407
|
const externalUndo = [];
|
|
@@ -82810,9 +83426,12 @@ var app31 = new Hono2().get("/", async (context) => {
|
|
|
82810
83426
|
txDb
|
|
82811
83427
|
);
|
|
82812
83428
|
if (lockedAccess instanceof Response) {
|
|
83429
|
+
const denied = await getProjectAccessErrorBody(lockedAccess);
|
|
82813
83430
|
throw new RollbackError(
|
|
82814
83431
|
lockedAccess.status,
|
|
82815
|
-
|
|
83432
|
+
denied.error,
|
|
83433
|
+
void 0,
|
|
83434
|
+
denied.message
|
|
82816
83435
|
);
|
|
82817
83436
|
}
|
|
82818
83437
|
const lockedProject = lockedAccess.project;
|
|
@@ -82887,9 +83506,12 @@ var app31 = new Hono2().get("/", async (context) => {
|
|
|
82887
83506
|
txDb
|
|
82888
83507
|
);
|
|
82889
83508
|
if (lockedAccess instanceof Response) {
|
|
83509
|
+
const denied = await getProjectAccessErrorBody(lockedAccess);
|
|
82890
83510
|
throw new RollbackError(
|
|
82891
83511
|
lockedAccess.status,
|
|
82892
|
-
|
|
83512
|
+
denied.error,
|
|
83513
|
+
void 0,
|
|
83514
|
+
denied.message
|
|
82893
83515
|
);
|
|
82894
83516
|
}
|
|
82895
83517
|
const target = await getDeployment(txDb, deploymentId);
|
|
@@ -82905,6 +83527,31 @@ var app31 = new Hono2().get("/", async (context) => {
|
|
|
82905
83527
|
"This Void platform does not enable rollback to Sandbox deployments."
|
|
82906
83528
|
);
|
|
82907
83529
|
}
|
|
83530
|
+
if (target.manifest) {
|
|
83531
|
+
const manifest2 = JSON.parse(target.manifest);
|
|
83532
|
+
if (manifest2.sandbox) {
|
|
83533
|
+
if (!isManagedSandbox(manifest2) || target.admission_protocol < 3) {
|
|
83534
|
+
throw new RollbackError(
|
|
83535
|
+
409,
|
|
83536
|
+
"This deployment predates managed Sandbox controllers. Redeploy the app before rolling back to it."
|
|
83537
|
+
);
|
|
83538
|
+
}
|
|
83539
|
+
try {
|
|
83540
|
+
await verifySandboxController(
|
|
83541
|
+
context.env.CF_ACCOUNT_ID,
|
|
83542
|
+
context.env.CF_API_TOKEN,
|
|
83543
|
+
projectId,
|
|
83544
|
+
deploymentId,
|
|
83545
|
+
manifest2.sandbox
|
|
83546
|
+
);
|
|
83547
|
+
} catch (error) {
|
|
83548
|
+
throw new RollbackError(
|
|
83549
|
+
409,
|
|
83550
|
+
error instanceof Error ? error.message : "Sandbox controller is unavailable."
|
|
83551
|
+
);
|
|
83552
|
+
}
|
|
83553
|
+
}
|
|
83554
|
+
}
|
|
82908
83555
|
const lockedProject = lockedAccess.project;
|
|
82909
83556
|
if (lockedProject.status === "deleting") {
|
|
82910
83557
|
throw new RollbackError(409, "project is being deleted");
|
|
@@ -83313,7 +83960,10 @@ var app31 = new Hono2().get("/", async (context) => {
|
|
|
83313
83960
|
err.status
|
|
83314
83961
|
);
|
|
83315
83962
|
} else {
|
|
83316
|
-
rollbackErrorResponse = context.json(
|
|
83963
|
+
rollbackErrorResponse = context.json(
|
|
83964
|
+
{ error: err.message, ...err.userMessage ? { message: err.userMessage } : {} },
|
|
83965
|
+
err.status
|
|
83966
|
+
);
|
|
83317
83967
|
}
|
|
83318
83968
|
} else if (!rollbackCommitted) {
|
|
83319
83969
|
rollbackErrorToThrow = err;
|
|
@@ -83472,9 +84122,7 @@ var app31 = new Hono2().get("/", async (context) => {
|
|
|
83472
84122
|
if (lockedAccess instanceof Response) {
|
|
83473
84123
|
return {
|
|
83474
84124
|
status: lockedAccess.status,
|
|
83475
|
-
body:
|
|
83476
|
-
error: await getProjectAccessErrorMessage(lockedAccess)
|
|
83477
|
-
}
|
|
84125
|
+
body: await getProjectAccessErrorBody(lockedAccess)
|
|
83478
84126
|
};
|
|
83479
84127
|
}
|
|
83480
84128
|
const resources2 = await getProjectResources(txDb, projectId);
|
|
@@ -83614,7 +84262,7 @@ var app31 = new Hono2().get("/", async (context) => {
|
|
|
83614
84262
|
status: lockedAccess.status,
|
|
83615
84263
|
body: {
|
|
83616
84264
|
ok: false,
|
|
83617
|
-
|
|
84265
|
+
...await getProjectAccessErrorBody(lockedAccess)
|
|
83618
84266
|
}
|
|
83619
84267
|
};
|
|
83620
84268
|
}
|
|
@@ -84331,7 +84979,10 @@ var app31 = new Hono2().get("/", async (context) => {
|
|
|
84331
84979
|
return access;
|
|
84332
84980
|
}
|
|
84333
84981
|
if (access.role !== "owner") {
|
|
84334
|
-
return context.json(
|
|
84982
|
+
return context.json(
|
|
84983
|
+
{ error: "forbidden", message: PROJECT_PERMISSION_MESSAGES["database-url"] },
|
|
84984
|
+
403
|
|
84985
|
+
);
|
|
84335
84986
|
}
|
|
84336
84987
|
const row = await getProjectDatabaseUrl(context.get("db"), projectId);
|
|
84337
84988
|
if (!row) {
|
|
@@ -84646,9 +85297,12 @@ var secrets_default = app33;
|
|
|
84646
85297
|
// ../../home/runner/work/void/void/platform/packages/api/src/sandbox-concurrency-counter.ts
|
|
84647
85298
|
init_performance2();
|
|
84648
85299
|
import { DurableObject as DurableObject5 } from "cloudflare:workers";
|
|
84649
|
-
var
|
|
84650
|
-
var
|
|
84651
|
-
var
|
|
85300
|
+
var RECONCILE_INTERVAL_MS = 6e4;
|
|
85301
|
+
var STORAGE_KEY = "controlled-entries-v1";
|
|
85302
|
+
var COMPLETIONS_KEY = "controlled-completions-v1";
|
|
85303
|
+
var COMPLETION_RETENTION_MS = 24 * 60 * 60 * 1e3;
|
|
85304
|
+
var MAX_COMPLETIONS = 4096;
|
|
85305
|
+
var unavailable = { ok: false, reason: "unavailable" };
|
|
84652
85306
|
var SandboxConcurrencyCounter = class extends DurableObject5 {
|
|
84653
85307
|
static {
|
|
84654
85308
|
__name(this, "SandboxConcurrencyCounter");
|
|
@@ -84667,45 +85321,59 @@ var SandboxConcurrencyCounter = class extends DurableObject5 {
|
|
|
84667
85321
|
}
|
|
84668
85322
|
async getEntries() {
|
|
84669
85323
|
if (!this.entries) {
|
|
84670
|
-
|
|
84671
|
-
this.entries = stored ?? {};
|
|
85324
|
+
this.entries = await this.ctx.storage.get(STORAGE_KEY) ?? {};
|
|
84672
85325
|
}
|
|
84673
85326
|
return { ...this.entries };
|
|
84674
85327
|
}
|
|
84675
85328
|
async saveEntries(entries) {
|
|
84676
85329
|
await this.ctx.storage.put(STORAGE_KEY, entries);
|
|
84677
|
-
this.entries = entries;
|
|
85330
|
+
this.entries = { ...entries };
|
|
84678
85331
|
}
|
|
84679
85332
|
async ensureAlarm() {
|
|
84680
|
-
|
|
84681
|
-
if (!current) {
|
|
85333
|
+
if (!await this.ctx.storage.getAlarm()) {
|
|
84682
85334
|
await this.ctx.storage.setAlarm(Date.now() + RECONCILE_INTERVAL_MS);
|
|
84683
85335
|
}
|
|
84684
85336
|
}
|
|
84685
|
-
|
|
84686
|
-
|
|
84687
|
-
return entry;
|
|
84688
|
-
}
|
|
84689
|
-
return { ...entry, attribution, meteringStart: entry.meteringStart ?? Date.now() };
|
|
85337
|
+
completionKey(id, generation) {
|
|
85338
|
+
return JSON.stringify([id, generation]);
|
|
84690
85339
|
}
|
|
84691
|
-
|
|
84692
|
-
|
|
84693
|
-
const
|
|
84694
|
-
|
|
85340
|
+
async completions() {
|
|
85341
|
+
const stored = await this.ctx.storage.get(COMPLETIONS_KEY) ?? {};
|
|
85342
|
+
const cutoff = Date.now() - COMPLETION_RETENTION_MS;
|
|
85343
|
+
return Object.fromEntries(
|
|
85344
|
+
Object.entries(stored).filter(([, completedAt]) => completedAt >= cutoff).sort((left, right) => left[1] - right[1]).slice(-MAX_COMPLETIONS)
|
|
85345
|
+
);
|
|
85346
|
+
}
|
|
85347
|
+
async hasCompletion(id, generation) {
|
|
85348
|
+
return this.completionKey(id, generation) in await this.completions();
|
|
85349
|
+
}
|
|
85350
|
+
async recordCompletion(id, generation) {
|
|
85351
|
+
const completions = await this.completions();
|
|
85352
|
+
completions[this.completionKey(id, generation)] = Date.now();
|
|
85353
|
+
const bounded = Object.fromEntries(
|
|
85354
|
+
Object.entries(completions).sort((left, right) => left[1] - right[1]).slice(-MAX_COMPLETIONS)
|
|
85355
|
+
);
|
|
85356
|
+
await this.ctx.storage.put(COMPLETIONS_KEY, bounded);
|
|
85357
|
+
}
|
|
85358
|
+
withinLimit(entries, id, limit) {
|
|
85359
|
+
return limit === 0 || Object.keys(entries).sort().indexOf(id) < limit;
|
|
85360
|
+
}
|
|
85361
|
+
async meterThrough(id, entry, through) {
|
|
85362
|
+
if (entry.startedAt === void 0) {
|
|
84695
85363
|
return entry;
|
|
84696
85364
|
}
|
|
84697
|
-
const from = entry.
|
|
85365
|
+
const from = entry.startedAt;
|
|
84698
85366
|
const seconds = Math.floor(Math.max(0, through - from) / 1e3);
|
|
84699
85367
|
const meteredThrough = from + seconds * 1e3;
|
|
84700
85368
|
if (meteredThrough <= (entry.meteredThrough ?? from)) {
|
|
84701
85369
|
return entry;
|
|
84702
85370
|
}
|
|
84703
|
-
const
|
|
85371
|
+
const instance = JSON.stringify([id, entry.generation]);
|
|
84704
85372
|
const event = {
|
|
84705
|
-
...attribution,
|
|
85373
|
+
...entry.attribution,
|
|
84706
85374
|
requests: 0,
|
|
84707
85375
|
responseBytes: 0,
|
|
84708
|
-
sandboxInstanceId:
|
|
85376
|
+
sandboxInstanceId: instance,
|
|
84709
85377
|
sandboxMeteredFrom: from,
|
|
84710
85378
|
sandboxMeteredThrough: meteredThrough
|
|
84711
85379
|
};
|
|
@@ -84714,140 +85382,241 @@ var SandboxConcurrencyCounter = class extends DurableObject5 {
|
|
|
84714
85382
|
}
|
|
84715
85383
|
const key = await ensureUsageSigningKey(this.env.ROUTING, this.env.JWT_SECRET);
|
|
84716
85384
|
await this.env.USAGE_EVENTS_QUEUE.send(
|
|
84717
|
-
await signUsageEvent(
|
|
85385
|
+
await signUsageEvent(
|
|
85386
|
+
key,
|
|
85387
|
+
"sandbox-counter",
|
|
85388
|
+
`sandbox:${instance}:${from}:${meteredThrough}`,
|
|
85389
|
+
event
|
|
85390
|
+
)
|
|
84718
85391
|
);
|
|
84719
85392
|
return { ...entry, meteredThrough };
|
|
84720
85393
|
}
|
|
84721
|
-
|
|
84722
|
-
|
|
84723
|
-
|
|
84724
|
-
|
|
84725
|
-
|
|
84726
|
-
|
|
84727
|
-
|
|
84728
|
-
|
|
84729
|
-
|
|
84730
|
-
|
|
84731
|
-
|
|
84732
|
-
|
|
84733
|
-
|
|
84734
|
-
(
|
|
84735
|
-
|
|
84736
|
-
|
|
84737
|
-
|
|
84738
|
-
const entries = await this.getEntries();
|
|
84739
|
-
const now = Date.now();
|
|
84740
|
-
if (entries[projectScopedSandboxInstanceId]) {
|
|
84741
|
-
const current = entries[projectScopedSandboxInstanceId];
|
|
84742
|
-
const withAttribution = this.attributeEntry(current, attribution);
|
|
84743
|
-
const metered = await this.meterThrough(projectScopedSandboxInstanceId, withAttribution, now);
|
|
84744
|
-
entries[projectScopedSandboxInstanceId] = {
|
|
84745
|
-
...metered,
|
|
84746
|
-
acquiredAt: now,
|
|
84747
|
-
...attribution ? { attribution } : {}
|
|
84748
|
-
};
|
|
85394
|
+
async reserve(id, generation, limit, attribution) {
|
|
85395
|
+
return this.serialize(async () => {
|
|
85396
|
+
const entries = await this.getEntries();
|
|
85397
|
+
const current = entries[id];
|
|
85398
|
+
if (current) {
|
|
85399
|
+
if (current.generation !== generation || current.stoppedAt !== void 0) {
|
|
85400
|
+
return unavailable;
|
|
85401
|
+
}
|
|
85402
|
+
return this.withinLimit(entries, id, limit) ? { ok: true } : { ok: false, reason: "concurrency" };
|
|
85403
|
+
}
|
|
85404
|
+
if (await this.hasCompletion(id, generation)) {
|
|
85405
|
+
return unavailable;
|
|
85406
|
+
}
|
|
85407
|
+
if (limit !== 0 && Object.keys(entries).length >= limit) {
|
|
85408
|
+
return { ok: false, reason: "concurrency" };
|
|
85409
|
+
}
|
|
85410
|
+
entries[id] = { generation, attribution };
|
|
84749
85411
|
await this.saveEntries(entries);
|
|
84750
|
-
await this.ensureAlarm();
|
|
84751
85412
|
return { ok: true };
|
|
84752
|
-
}
|
|
84753
|
-
const count2 = Object.keys(entries).length;
|
|
84754
|
-
if (planLimit !== 0 && count2 >= planLimit) {
|
|
84755
|
-
return { ok: false, reason: "concurrency" };
|
|
84756
|
-
}
|
|
84757
|
-
entries[projectScopedSandboxInstanceId] = {
|
|
84758
|
-
acquiredAt: now,
|
|
84759
|
-
meteringStart: now,
|
|
84760
|
-
meteredThrough: now,
|
|
84761
|
-
...attribution ? { attribution } : {}
|
|
84762
|
-
};
|
|
84763
|
-
await this.saveEntries(entries);
|
|
84764
|
-
await this.ensureAlarm();
|
|
84765
|
-
return { ok: true };
|
|
85413
|
+
});
|
|
84766
85414
|
}
|
|
84767
|
-
|
|
84768
|
-
|
|
84769
|
-
|
|
84770
|
-
|
|
84771
|
-
|
|
84772
|
-
|
|
84773
|
-
|
|
84774
|
-
|
|
84775
|
-
|
|
84776
|
-
|
|
84777
|
-
|
|
84778
|
-
|
|
84779
|
-
|
|
84780
|
-
|
|
84781
|
-
|
|
84782
|
-
|
|
84783
|
-
return this.serialize(() => this.handleRefresh(projectScopedSandboxInstanceId, attribution));
|
|
85415
|
+
async started(id, generation, limit) {
|
|
85416
|
+
return this.serialize(async () => {
|
|
85417
|
+
const entries = await this.getEntries();
|
|
85418
|
+
const current = entries[id];
|
|
85419
|
+
if (!current || current.generation !== generation || current.stoppedAt !== void 0) {
|
|
85420
|
+
return unavailable;
|
|
85421
|
+
}
|
|
85422
|
+
if (!this.withinLimit(entries, id, limit)) {
|
|
85423
|
+
return { ok: false, reason: "concurrency" };
|
|
85424
|
+
}
|
|
85425
|
+
if (current.startedAt === void 0) {
|
|
85426
|
+
entries[id] = { ...current, startedAt: Date.now() };
|
|
85427
|
+
await this.saveEntries(entries);
|
|
85428
|
+
}
|
|
85429
|
+
return { ok: true };
|
|
85430
|
+
});
|
|
84784
85431
|
}
|
|
84785
|
-
async
|
|
84786
|
-
|
|
84787
|
-
|
|
84788
|
-
|
|
84789
|
-
|
|
84790
|
-
|
|
84791
|
-
|
|
84792
|
-
|
|
84793
|
-
|
|
84794
|
-
|
|
84795
|
-
|
|
84796
|
-
|
|
84797
|
-
|
|
84798
|
-
};
|
|
84799
|
-
await this.saveEntries(entries);
|
|
84800
|
-
await this.ensureAlarm();
|
|
84801
|
-
return { ok: true };
|
|
85432
|
+
async heartbeat(id, generation, limit) {
|
|
85433
|
+
return this.serialize(async () => {
|
|
85434
|
+
const entries = await this.getEntries();
|
|
85435
|
+
const current = entries[id];
|
|
85436
|
+
if (!current || current.generation !== generation || current.stoppedAt !== void 0) {
|
|
85437
|
+
return unavailable;
|
|
85438
|
+
}
|
|
85439
|
+
if (!this.withinLimit(entries, id, limit)) {
|
|
85440
|
+
return { ok: false, reason: "concurrency" };
|
|
85441
|
+
}
|
|
85442
|
+
entries[id] = await this.meterThrough(id, current, Date.now());
|
|
85443
|
+
await this.saveEntries(entries);
|
|
85444
|
+
return { ok: true };
|
|
85445
|
+
});
|
|
84802
85446
|
}
|
|
84803
|
-
/**
|
|
84804
|
-
|
|
84805
|
-
|
|
84806
|
-
|
|
84807
|
-
|
|
84808
|
-
|
|
84809
|
-
|
|
85447
|
+
/** The trusted controller calls this only after confirming the container stopped. */
|
|
85448
|
+
async stopped(id, generation) {
|
|
85449
|
+
const stoppedAt = Date.now();
|
|
85450
|
+
return this.serialize(async () => {
|
|
85451
|
+
const entries = await this.getEntries();
|
|
85452
|
+
const current = entries[id];
|
|
85453
|
+
if (!current || current.generation !== generation) {
|
|
85454
|
+
await this.recordCompletion(id, generation);
|
|
85455
|
+
return;
|
|
85456
|
+
}
|
|
85457
|
+
if (current.stoppedAt === void 0) {
|
|
85458
|
+
entries[id] = { ...current, stoppedAt };
|
|
85459
|
+
await this.saveEntries(entries);
|
|
85460
|
+
}
|
|
85461
|
+
await this.ensureAlarm();
|
|
85462
|
+
await this.finishStopped(entries, id);
|
|
85463
|
+
});
|
|
84810
85464
|
}
|
|
84811
|
-
|
|
84812
|
-
|
|
84813
|
-
const
|
|
84814
|
-
|
|
84815
|
-
|
|
84816
|
-
|
|
84817
|
-
|
|
84818
|
-
|
|
84819
|
-
|
|
84820
|
-
|
|
84821
|
-
|
|
84822
|
-
|
|
85465
|
+
/** Called only after the API confirms every container for a deployment is gone. */
|
|
85466
|
+
async revokeDeployment(projectId, deploymentId) {
|
|
85467
|
+
const stoppedAt = Date.now();
|
|
85468
|
+
return this.serialize(async () => {
|
|
85469
|
+
const entries = await this.getEntries();
|
|
85470
|
+
const matching = Object.keys(entries).filter((id) => {
|
|
85471
|
+
try {
|
|
85472
|
+
const identity = JSON.parse(id);
|
|
85473
|
+
return Array.isArray(identity) && identity[0] === projectId && identity[1] === deploymentId;
|
|
85474
|
+
} catch {
|
|
85475
|
+
return false;
|
|
85476
|
+
}
|
|
85477
|
+
});
|
|
85478
|
+
if (matching.length === 0) {
|
|
85479
|
+
return;
|
|
85480
|
+
}
|
|
85481
|
+
for (const id of matching) {
|
|
85482
|
+
const entry = entries[id];
|
|
85483
|
+
if (entry.stoppedAt === void 0) {
|
|
85484
|
+
entries[id] = { ...entry, stoppedAt };
|
|
85485
|
+
}
|
|
85486
|
+
}
|
|
85487
|
+
await this.saveEntries(entries);
|
|
85488
|
+
await this.ensureAlarm();
|
|
85489
|
+
for (const id of matching) {
|
|
85490
|
+
await this.finishStopped(entries, id);
|
|
85491
|
+
}
|
|
85492
|
+
});
|
|
85493
|
+
}
|
|
85494
|
+
async finishStopped(entries, id) {
|
|
85495
|
+
const entry = entries[id];
|
|
85496
|
+
await this.meterThrough(id, entry, entry.stoppedAt);
|
|
85497
|
+
await this.recordCompletion(id, entry.generation);
|
|
85498
|
+
delete entries[id];
|
|
84823
85499
|
await this.saveEntries(entries);
|
|
84824
85500
|
}
|
|
84825
|
-
/**
|
|
84826
|
-
* Sweep stale entries — anything older than `STALE_MS` is assumed to be a
|
|
84827
|
-
* leaked slot (caller crashed without `release`). Re-arms itself so the
|
|
84828
|
-
* DO continues reconciling as long as it has live entries; once empty,
|
|
84829
|
-
* we let the alarm lapse to keep the DO cold.
|
|
84830
|
-
*/
|
|
84831
85501
|
async alarm() {
|
|
84832
|
-
return this.serialize(() =>
|
|
84833
|
-
|
|
84834
|
-
|
|
84835
|
-
|
|
84836
|
-
|
|
84837
|
-
|
|
84838
|
-
for (const [id, entry] of Object.entries(entries)) {
|
|
84839
|
-
if (entry.acquiredAt < now - STALE_MS) {
|
|
84840
|
-
await this.meterThrough(id, entry, entry.acquiredAt + STALE_MS);
|
|
84841
|
-
delete entries[id];
|
|
84842
|
-
changed = true;
|
|
85502
|
+
return this.serialize(async () => {
|
|
85503
|
+
const entries = await this.getEntries();
|
|
85504
|
+
for (const [id, entry] of Object.entries(entries)) {
|
|
85505
|
+
if (entry.stoppedAt !== void 0) {
|
|
85506
|
+
await this.finishStopped(entries, id);
|
|
85507
|
+
}
|
|
84843
85508
|
}
|
|
85509
|
+
});
|
|
85510
|
+
}
|
|
85511
|
+
};
|
|
85512
|
+
|
|
85513
|
+
// ../../home/runner/work/void/void/platform/packages/api/src/sandbox-control.ts
|
|
85514
|
+
init_performance2();
|
|
85515
|
+
init_dist();
|
|
85516
|
+
init_drizzle_orm();
|
|
85517
|
+
init_capabilities();
|
|
85518
|
+
init_db2();
|
|
85519
|
+
import { WorkerEntrypoint as WorkerEntrypoint2 } from "cloudflare:workers";
|
|
85520
|
+
init_schema2();
|
|
85521
|
+
init_suspension();
|
|
85522
|
+
init_tiers();
|
|
85523
|
+
var unavailable2 = { ok: false, reason: "unavailable" };
|
|
85524
|
+
var validIdentifier = /* @__PURE__ */ __name((value) => typeof value === "string" && value.length > 0 && value.length <= 128, "validIdentifier");
|
|
85525
|
+
var SandboxControl = class extends WorkerEntrypoint2 {
|
|
85526
|
+
static {
|
|
85527
|
+
__name(this, "SandboxControl");
|
|
85528
|
+
}
|
|
85529
|
+
identity() {
|
|
85530
|
+
const props = this.ctx.props;
|
|
85531
|
+
return props && validIdentifier(props.projectId) && validIdentifier(props.deploymentId) && validIdentifier(props.userId) && validIdentifier(props.slug) ? props : null;
|
|
85532
|
+
}
|
|
85533
|
+
instanceId(identity, instance) {
|
|
85534
|
+
return JSON.stringify([identity.projectId, identity.deploymentId, instance]);
|
|
85535
|
+
}
|
|
85536
|
+
counter(identity) {
|
|
85537
|
+
const namespace = this.env.SANDBOX_CONCURRENCY_COUNTER;
|
|
85538
|
+
return namespace.get(namespace.idFromName(`account:${identity.userId}`));
|
|
85539
|
+
}
|
|
85540
|
+
async authorize(identity) {
|
|
85541
|
+
if (!getPlatformCapabilities(this.env).sandbox || this.env.PLATFORM_TRAFFIC_STATE === "staging" || this.env.PLATFORM_TRAFFIC_STATE === "sandbox-drain" || await this.env.ROUTING.get(PLATFORM_DISABLED_KEY) === PLATFORM_DISABLED_VALUE) {
|
|
85542
|
+
return { ok: false, reason: "unavailable" };
|
|
84844
85543
|
}
|
|
84845
|
-
|
|
84846
|
-
|
|
85544
|
+
const db = createDb(this.env.HYPERDRIVE.connectionString);
|
|
85545
|
+
const checkpoint = await readSandboxDrainCheckpoint(db);
|
|
85546
|
+
if (!checkpoint || checkpoint.state !== "complete" || checkpoint.admission_protocol < 3) {
|
|
85547
|
+
return { ok: false, reason: "unavailable" };
|
|
85548
|
+
}
|
|
85549
|
+
const [authority] = await db.select({
|
|
85550
|
+
project: projects,
|
|
85551
|
+
deployment: deployments,
|
|
85552
|
+
owner: users,
|
|
85553
|
+
candidateFresh: sql`CASE
|
|
85554
|
+
WHEN ${deployments.status} = 'prerendering'
|
|
85555
|
+
THEN ${deployments.updated_at} > now() - interval '10 minutes'
|
|
85556
|
+
WHEN ${deployments.status} = 'cutover'
|
|
85557
|
+
THEN ${deployments.updated_at} > now() - interval '90 minutes'
|
|
85558
|
+
ELSE false END`
|
|
85559
|
+
}).from(projects).innerJoin(deployments, eq(deployments.project_id, projects.id)).innerJoin(users, eq(users.id, projects.user_id)).where(and(eq(projects.id, identity.projectId), eq(deployments.id, identity.deploymentId))).limit(1);
|
|
85560
|
+
if (!authority) {
|
|
85561
|
+
return { ok: false, reason: "unavailable" };
|
|
85562
|
+
}
|
|
85563
|
+
const { project, deployment, owner, candidateFresh } = authority;
|
|
85564
|
+
if (project.status !== "active" || project.user_id !== identity.userId || owner.id !== identity.userId || deployment.project_id !== project.id || deployment.admission_protocol < 3 || !(deployment.status === "live" && project.active_deployment_id === deployment.id || candidateFresh && (deployment.status === "prerendering" || deployment.status === "cutover"))) {
|
|
85565
|
+
return { ok: false, reason: "unavailable" };
|
|
85566
|
+
}
|
|
85567
|
+
let manifest;
|
|
85568
|
+
try {
|
|
85569
|
+
manifest = JSON.parse(deployment.manifest ?? "null");
|
|
85570
|
+
} catch {
|
|
85571
|
+
return { ok: false, reason: "unavailable" };
|
|
85572
|
+
}
|
|
85573
|
+
if (manifest?.sandbox?.runtime?.protocol !== 1) {
|
|
85574
|
+
return { ok: false, reason: "unavailable" };
|
|
85575
|
+
}
|
|
85576
|
+
if (owner.suspended_reason === REASON_SANDBOX_RUNTIME_EXCEEDED || await this.env.ROUTING.get(sandboxBlockKey(owner.id)) !== null) {
|
|
85577
|
+
return { ok: false, reason: "runtime_budget" };
|
|
85578
|
+
}
|
|
85579
|
+
if (owner.suspended_reason) {
|
|
85580
|
+
return { ok: false, reason: "unavailable" };
|
|
85581
|
+
}
|
|
85582
|
+
return {
|
|
85583
|
+
ok: true,
|
|
85584
|
+
limit: getPlanLimits(owner.plan).sandboxMaxConcurrentInstances,
|
|
85585
|
+
slug: project.slug
|
|
85586
|
+
};
|
|
85587
|
+
}
|
|
85588
|
+
async admit(action, instance, generation) {
|
|
85589
|
+
const identity = this.identity();
|
|
85590
|
+
if (!identity || !validIdentifier(instance) || !validIdentifier(generation)) {
|
|
85591
|
+
return unavailable2;
|
|
85592
|
+
}
|
|
85593
|
+
const authority = await this.authorize(identity);
|
|
85594
|
+
if (!authority.ok) {
|
|
85595
|
+
return authority;
|
|
84847
85596
|
}
|
|
84848
|
-
|
|
84849
|
-
|
|
85597
|
+
const counter = this.counter(identity);
|
|
85598
|
+
const id = this.instanceId(identity, instance);
|
|
85599
|
+
return action === "reserve" ? counter.reserve(id, generation, authority.limit, {
|
|
85600
|
+
projectId: identity.projectId,
|
|
85601
|
+
userId: identity.userId,
|
|
85602
|
+
slug: authority.slug
|
|
85603
|
+
}) : counter[action](id, generation, authority.limit);
|
|
85604
|
+
}
|
|
85605
|
+
reserve(instance, generation) {
|
|
85606
|
+
return this.admit("reserve", instance, generation);
|
|
85607
|
+
}
|
|
85608
|
+
started(instance, generation) {
|
|
85609
|
+
return this.admit("started", instance, generation);
|
|
85610
|
+
}
|
|
85611
|
+
heartbeat(instance, generation) {
|
|
85612
|
+
return this.admit("heartbeat", instance, generation);
|
|
85613
|
+
}
|
|
85614
|
+
async stopped(instance, generation) {
|
|
85615
|
+
const identity = this.identity();
|
|
85616
|
+
if (!identity || !validIdentifier(instance) || !validIdentifier(generation)) {
|
|
85617
|
+
throw new Error("Invalid Sandbox controller identity.");
|
|
84850
85618
|
}
|
|
85619
|
+
await this.counter(identity).stopped(this.instanceId(identity, instance), generation);
|
|
84851
85620
|
}
|
|
84852
85621
|
};
|
|
84853
85622
|
|
|
@@ -86184,6 +86953,11 @@ async function scheduled(controller, env, _ctx) {
|
|
|
86184
86953
|
);
|
|
86185
86954
|
return;
|
|
86186
86955
|
}
|
|
86956
|
+
if (capabilities.sandbox) {
|
|
86957
|
+
await retrySandboxControllerCleanup(db, env).catch(
|
|
86958
|
+
(error) => console.error("[scheduled] Sandbox controller cleanup failed:", error)
|
|
86959
|
+
);
|
|
86960
|
+
}
|
|
86187
86961
|
await failStaleDeployments(db).then((n) => {
|
|
86188
86962
|
if (n > 0) {
|
|
86189
86963
|
console.log(`[scheduled] auto-failed ${n} stale deployment(s)`);
|
|
@@ -86511,6 +87285,7 @@ export {
|
|
|
86511
87285
|
CronScheduler,
|
|
86512
87286
|
ErrorAlertMonitor,
|
|
86513
87287
|
SandboxConcurrencyCounter,
|
|
87288
|
+
SandboxControl,
|
|
86514
87289
|
UsageCounter,
|
|
86515
87290
|
index_default as default
|
|
86516
87291
|
};
|