@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.
@@ -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(() => 2),
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, name === "sandbox" ? false : record2[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
- // Managed Sandbox is disabled while the beta lifecycle is drained. Keep
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, namespaceId) {
17862
- await cfFetch(`${CF_API_BASE}/${accountId}/storage/kv/namespaces/${namespaceId}`, apiToken, {
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("forbidden", 403);
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("forbidden", 403);
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("forbidden", 403);
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.json({ error: "cross-site request blocked" }, 403);
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" || isAdminSuspended(user.suspended_reason)) {
43024
- return context.html("<h1>403 Forbidden</h1><p>Admin access required.</p>", 403);
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.text("Forbidden: invalid request origin.", 403);
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.text("Forbidden: missing request origin.", 403);
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({ error: error.message }, error.status);
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(/* @__PURE__ */ jsxDEV("h1", { children: error.message }), error.status);
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" || isAdminSuspended(user.suspended_reason)) {
53962
- return context.html(
53963
- "<h1>403 Forbidden</h1><p>Admin access required. You must have an admin account to sign in.</p>",
53964
- 403
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
- async function provisionPerDeployContainer(accountId, apiToken, dispatchNamespace, workerScriptName, containerAppName, bindingName, className, sandbox, routing) {
59721
- const namespaceId = await retryWithBackoff(
59722
- async () => {
59723
- try {
59724
- return await findDurableObjectNamespaceId(
59725
- accountId,
59726
- apiToken,
59727
- dispatchNamespace,
59728
- workerScriptName,
59729
- bindingName,
59730
- className
59731
- );
59732
- } catch (err) {
59733
- const msg = err instanceof Error ? err.message : String(err);
59734
- console.warn(
59735
- `[per-deploy-container] namespace probe miss for ${workerScriptName} (will retry): ${msg}`
59736
- );
59737
- return void 0;
59738
- }
59739
- },
59740
- {
59741
- maxRetries: 8,
59742
- delayMs: 500,
59743
- errorMessage: `per-deploy DO namespace was not visible after worker PUT (script=${workerScriptName})`
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,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}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: containerAppName,
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
- if (!created) {
59755
- const existing = await findContainerApplication(accountId, apiToken, containerAppName);
59756
- if (!existing) {
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
- `per-deploy container application "${containerAppName}" POST returned 409 but a follow-up lookup found no application by that name`
60028
+ "Cannot verify ownership of a Sandbox container whose controller is missing."
59759
60029
  );
59760
60030
  }
59761
- if (existing.durable_objects?.namespace_id !== namespaceId) {
59762
- throw new Error(
59763
- `per-deploy container application "${containerAppName}" already exists but is bound to namespace_id=${existing.durable_objects?.namespace_id ?? "<none>"} instead of expected ${namespaceId}; refusing to reuse`
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 assertSandboxContainerCreationAllowed(routing);
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 deleteContainerApplicationIdempotent(accountId, apiToken, existing.id);
59770
- throw error;
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(provisionPerDeployContainer, "provisionPerDeployContainer");
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({ error: error.message }, error.status);
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 is active.",
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.2",
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({ error: "unauthorized" }, 401);
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({ error: "invalid or expired token" }, 401);
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({ error: "session revoked; sign in again" }, 401);
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({ error: "user not found" }, 401);
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({ error: "account suspended" }, 403);
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({ error: "invalid or expired token" }, 401);
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({ error: "deploy credential revoked or expired" }, 401);
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({ error: "forbidden" }, 403);
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({ error: "deploy token build is no longer active" }, 403);
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(txDb, deployment.id, "managed Sandbox disabled");
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(txDb, deployment.id, "canceled", "managed Sandbox disabled", {
71028
- force: true
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: "durable_object_namespace",
71631
- name: sandbox.bindingName,
71632
- class_name: sandbox.className
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(sandbox) {
71651
- return sandbox ? [{ class_name: sandbox.className }] : void 0;
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({ error: "forbidden" }, 403);
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({ error: "forbidden" }, 403);
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
- const sandboxBindings = buildSandboxUploadBindings(manifest2.sandbox);
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
- manifest2.sandbox?.migrations,
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
- const oldContainerAppName = perDeployContainerApplicationName(
74323
- projectId,
74324
- old.id,
74325
- oldManifest.sandbox.containerName ?? "void-sandbox"
74326
- );
74327
- const existing = await findContainerApplication(
74328
- context.env.CF_ACCOUNT_ID,
74329
- context.env.CF_API_TOKEN,
74330
- oldContainerAppName
74331
- );
74332
- if (existing) {
74333
- await deleteContainerApplicationIdempotent(
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
- existing.id
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 (sandboxContainerAppId) {
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 (sandboxContainerAppId) {
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({ error: "project owner suspended" }, 403);
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
- createdAt && id ? or(
75046
- gt(deployments.created_at, createdAt),
75047
- and(eq(deployments.created_at, createdAt), gt(deployments.id, id))
75048
- ) : void 0
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 namespaceId = await findDurableObjectNamespaceId(
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 (namespaceId !== application.durable_objects.namespace_id) {
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: "Managed Sandbox is already drained and remains disabled."
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 managed Sandbox activation, cancel active Sandbox deployments, delete verified container applications, and verify two bounded passes."
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: "Managed Sandbox container applications are drained and activation remains disabled."
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({ error: "project owner suspended" }, 403);
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({ error: "project owner suspended" }, 403);
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({ error: error.message }, error.status);
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({ error: error.message }, error.status);
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 messages = {
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
- return context.json({ error: messages[error.reason] }, error.status);
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({ error: "project member not found" }, 404);
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({ error: "the project owner cannot leave the project" }, 409);
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({ error: "project not found" }, 404);
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({ error: "project not found" }, 404);
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({ error: "project is being deleted" }, 409);
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({ error: "project not found" }, 404);
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({ error: "project not found" }, 404);
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({ error: "project not found" }, 404);
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({ error: "project is being deleted" }, 409);
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({ error: "active credential not found" }, 404);
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({ error: "project not found" }, 404);
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({ error: "project not found" }, 404);
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({ error: "active credential not found" }, 404);
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 getProjectAccessErrorMessage(response) {
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 body.error;
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 response.status === 404 ? "project not found" : "forbidden";
82955
+ return fallback;
82357
82956
  }
82358
- __name(getProjectAccessErrorMessage, "getProjectAccessErrorMessage");
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({ error: "deploy token build is no longer active" }, 403);
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
- await getProjectAccessErrorMessage(lockedAccess)
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
- await getProjectAccessErrorMessage(lockedAccess)
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({ error: err.message }, err.status);
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
- error: await getProjectAccessErrorMessage(lockedAccess)
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({ error: "forbidden" }, 403);
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 STALE_MS = 60 * 6e4;
84650
- var RECONCILE_INTERVAL_MS = 60 * 6e4;
84651
- var STORAGE_KEY = "entries";
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
- const stored = await this.ctx.storage.get(STORAGE_KEY);
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
- const current = await this.ctx.storage.getAlarm();
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
- attributeEntry(entry, attribution) {
84686
- if (!attribution) {
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
- /** Publish cumulative whole-second usage using only the DO's clock. */
84692
- async meterThrough(projectScopedSandboxInstanceId, entry, through) {
84693
- const attribution = entry.attribution;
84694
- if (!attribution || entry.meteringStart === void 0) {
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.meteringStart;
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 eventId = `sandbox:${projectScopedSandboxInstanceId}:${from}:${meteredThrough}`;
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: projectScopedSandboxInstanceId,
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(key, "sandbox-counter", eventId, event)
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
- * Try to claim a sandbox slot for `projectScopedSandboxInstanceId`.
84723
- *
84724
- * `planLimit` is the per-account cap (`PlanLimits.sandboxMaxConcurrentInstances`).
84725
- * A value of `0` follows the project's standard "0 means unlimited"
84726
- * convention used elsewhere in `tiers.ts` / `isWithinLimit`.
84727
- *
84728
- * Idempotent: if `projectScopedSandboxInstanceId` is already held, the call refreshes
84729
- * its `acquiredAt` timestamp (which keeps the alarm sweep from reaping a
84730
- * still-live session) and returns `{ ok: true }` without double-counting.
84731
- */
84732
- async acquire(projectScopedSandboxInstanceId, planLimit, attribution) {
84733
- return this.serialize(
84734
- () => this.handleAcquire(projectScopedSandboxInstanceId, planLimit, attribution)
84735
- );
84736
- }
84737
- async handleAcquire(projectScopedSandboxInstanceId, planLimit, attribution) {
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
- * Heartbeat refresh for a slot the caller still believes it holds. Touches
84769
- * `acquiredAt` to the current time so the `STALE_MS` alarm sweep doesn't
84770
- * reap a long-running but still-live session.
84771
- *
84772
- * Deliberately does NOT re-check `planLimit` — the user's plan may have
84773
- * changed since acquire, but in-flight sandboxes are not retroactively
84774
- * suspended; only new acquires see the updated cap.
84775
- *
84776
- * Returns `{ ok: false, reason: 'not_held' }` if the slot is unknown
84777
- * (already swept or never acquired). Refresh does NOT auto-acquire: the
84778
- * caller treats this as a heartbeat ping that won't recover the session,
84779
- * which keeps the DO's accounting simple (no surprise re-claim that
84780
- * bypasses the planLimit check on the acquire path).
84781
- */
84782
- async refresh(projectScopedSandboxInstanceId, attribution) {
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 handleRefresh(projectScopedSandboxInstanceId, attribution) {
84786
- const entries = await this.getEntries();
84787
- const current = entries[projectScopedSandboxInstanceId];
84788
- if (!current) {
84789
- return { ok: false, reason: "not_held" };
84790
- }
84791
- const now = Date.now();
84792
- const withAttribution = this.attributeEntry(current, attribution);
84793
- const metered = await this.meterThrough(projectScopedSandboxInstanceId, withAttribution, now);
84794
- entries[projectScopedSandboxInstanceId] = {
84795
- ...metered,
84796
- acquiredAt: now,
84797
- ...attribution ? { attribution } : {}
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
- * Release the slot held by `projectScopedSandboxInstanceId`. Idempotent: missing ids
84805
- * are a no-op so the proxy can call `release` from both happy-path and
84806
- * cleanup code paths without coordination.
84807
- */
84808
- async release(projectScopedSandboxInstanceId, attribution) {
84809
- return this.serialize(() => this.handleRelease(projectScopedSandboxInstanceId, attribution));
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
- async handleRelease(projectScopedSandboxInstanceId, attribution) {
84812
- const entries = await this.getEntries();
84813
- const current = entries[projectScopedSandboxInstanceId];
84814
- if (!current) {
84815
- return;
84816
- }
84817
- await this.meterThrough(
84818
- projectScopedSandboxInstanceId,
84819
- this.attributeEntry(current, attribution),
84820
- Date.now()
84821
- );
84822
- delete entries[projectScopedSandboxInstanceId];
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(() => this.handleAlarm());
84833
- }
84834
- async handleAlarm() {
84835
- const entries = await this.getEntries();
84836
- const now = Date.now();
84837
- let changed = false;
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
- if (changed) {
84846
- await this.saveEntries(entries);
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
- if (Object.keys(entries).length > 0) {
84849
- await this.ctx.storage.setAlarm(now + RECONCILE_INTERVAL_MS);
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
  };