void 0.21.8 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/dist/{account-cmd-CQ2wi4Th.mjs → account-cmd-CjyxcGkM.mjs} +4 -4
  2. package/dist/{auth-link-B_lceSHK.mjs → auth-link-BLO4ptzo.mjs} +4 -4
  3. package/dist/{auth-router-cZq0HuWe.mjs → auth-router-ZUg9MF_U.mjs} +5 -5
  4. package/dist/{build-cmd-Dpt0jd-x.mjs → build-cmd-BxR5FROK.mjs} +3 -3
  5. package/dist/{cache-7_UeZdTk.mjs → cache-D0sWhgKI.mjs} +3 -3
  6. package/dist/{cancel-deploy-D23R1RXT.mjs → cancel-deploy-D4NUqFbi.mjs} +3 -3
  7. package/dist/{cf-build-output-CGT03qCD.mjs → cf-build-output-BJ6yGEIS.mjs} +139 -62
  8. package/dist/cli/cf-compat.mjs +164 -42
  9. package/dist/cli/cli.mjs +73 -44
  10. package/dist/cli/env-schema-probe.d.mts +1 -1
  11. package/dist/{client-QTl6ko_D.mjs → client-BTZ3XkrB.mjs} +25 -0
  12. package/dist/client-Czz8o5jP.mjs +2 -0
  13. package/dist/{cloudflare-auth-C4_GPZr0.mjs → cloudflare-auth-DQkqoMYa.mjs} +1 -6
  14. package/dist/{cloudflare-cmd-bSmZ1d5L.mjs → cloudflare-cmd-BKlfGHAy.mjs} +6 -7
  15. package/dist/{cloudflare-connect-jAwacxxP.mjs → cloudflare-connect-Ctmrw579.mjs} +3 -3
  16. package/dist/{cloudflare-operations-sMZXpk_S.mjs → cloudflare-operations-B9tzgjmf.mjs} +10 -39
  17. package/dist/{cloudflare-operations-BipGMJ5O.mjs → cloudflare-operations-BT6OWFBk.mjs} +1 -1
  18. package/dist/{config-CafTW6Cz.mjs → config-Br_JZD6u.mjs} +2 -7
  19. package/dist/{config-s7Xj7tPb.mjs → config-CyQ-wVd7.mjs} +1 -1
  20. package/dist/{config-CF69HgXc.d.mts → config-VavjpDnp.d.mts} +1 -2
  21. package/dist/config-entry.d.mts +1 -1
  22. package/dist/{config-write-BSduPMY8.mjs → config-write-B1f88wJA.mjs} +1 -1
  23. package/dist/{connect-BY38i-9E.mjs → connect-Dg-WkW-C.mjs} +5 -5
  24. package/dist/{create-project-BniEV0OW.mjs → create-project-DdoqwFLF.mjs} +1 -1
  25. package/dist/{create-project-DBfFSZKY.mjs → create-project-l9J7pbtm.mjs} +8 -4
  26. package/dist/{db-BIo37Y7H.mjs → db-gp2sCXyN.mjs} +14 -14
  27. package/dist/{delete-D6dZ9B6B.mjs → delete-TTedbH6B.mjs} +3 -3
  28. package/dist/{deploy-BM_LoBXC.mjs → deploy-B19L2Bra.mjs} +1 -1
  29. package/dist/{deploy-C0JaQSWS.mjs → deploy-CH-o2CaZ.mjs} +47 -36
  30. package/dist/{dist-BR1quN_w.mjs → dist-AoCzRTJE.mjs} +226 -60
  31. package/dist/{dist-C5fND3R0.mjs → dist-BuDuKZJv.mjs} +1 -1
  32. package/dist/{dist-Dn6nn2IU.mjs → dist-CTBk70IR.mjs} +42 -42
  33. package/dist/{domain-Dmhvb2oU.mjs → domain-JRF59P_r.mjs} +4 -4
  34. package/dist/{email-dMnE_Lat.mjs → email-Bo6G9LOZ.mjs} +6 -6
  35. package/dist/{env-Csi-tMbT.mjs → env-BYOrWQnv.mjs} +4 -4
  36. package/dist/{env-public-D_6u46fX.d.mts → env-public-BxU_0yTL.d.mts} +2 -1
  37. package/dist/gen-CNJ62MM7.mjs +2 -0
  38. package/dist/{gen-Dz3X1Qab.mjs → gen-sCtlCOdA.mjs} +3 -3
  39. package/dist/{github-cmd-BED3_9JD.mjs → github-cmd-0-7PexDq.mjs} +5 -7
  40. package/dist/{handler-BXJTXd02.d.mts → handler-HEcZsaij.d.mts} +2 -1
  41. package/dist/{headers-BOg_velo.mjs → headers-DWi2IXWx.mjs} +1 -1
  42. package/dist/help-CmZzxUba.mjs +2 -0
  43. package/dist/{help-DC7gdz7L.mjs → help-GKtwl07I.mjs} +124 -4
  44. package/dist/index.d.mts +1 -1
  45. package/dist/index.mjs +53 -24
  46. package/dist/{init-CJSnEcuj.mjs → init-FZx3Elvz.mjs} +13 -13
  47. package/dist/{link-CsHOinF7.mjs → link-BrQfb_CU.mjs} +4 -4
  48. package/dist/{list-CDb-4bZ1.mjs → list-D44jmIAM.mjs} +4 -4
  49. package/dist/{live-CKiJilLr.d.mts → live-CKJlvlNp.d.mts} +1 -1
  50. package/dist/{local-d1-CC8sKFGu.mjs → local-d1-Bg9OzEEO.mjs} +1 -1
  51. package/dist/{login-DZldyb8c.mjs → login-CAsAsQ-_.mjs} +4 -4
  52. package/dist/login-CGcRKEoi.mjs +2 -0
  53. package/dist/{logs-BdfiOezj.mjs → logs-BjKvFnVM.mjs} +4 -4
  54. package/dist/{migrate-B8KuoYsO.mjs → migrate-BPITvDJN.mjs} +4 -4
  55. package/dist/migrate-CYfbKkXh.mjs +2 -0
  56. package/dist/{node-BM43oz4G.mjs → node-Dt7z256D.mjs} +1 -1
  57. package/dist/{operator-cmd-B9dbG3Od.mjs → operator-cmd-BK5CCiT9.mjs} +4 -4
  58. package/dist/output-Dm_A4Tbv.mjs +81 -0
  59. package/dist/pages/client.d.mts +1 -1
  60. package/dist/pages/index.d.mts +1 -1
  61. package/dist/pages/index.mjs +2 -2
  62. package/dist/pages/islands-plugin.d.mts +16 -6
  63. package/dist/pages/islands-plugin.mjs +1 -1
  64. package/dist/pages/protocol.d.mts +2 -2
  65. package/dist/{output-CCH48AMM.mjs → picocolors-BTps1_gs.mjs} +2 -76
  66. package/dist/{platform-auth-config-Bex45lQt.mjs → platform-auth-config-BlN8xTdD.mjs} +3 -3
  67. package/dist/{platform-auth-protection-Dma02l6-.mjs → platform-auth-protection-7d5aV2Jg.mjs} +3 -3
  68. package/dist/{platform-auth-recovery-COOhMCvx.mjs → platform-auth-recovery-Dxij8ZbR.mjs} +3 -3
  69. package/dist/{platform-cmd-BtxZrT6w.mjs → platform-cmd-B3hwKrFK.mjs} +5 -5
  70. package/dist/{platform-cmd-CjNB09OF.mjs → platform-cmd-E0FuL212.mjs} +1 -1
  71. package/dist/{platform-domain-DppaTARe.mjs → platform-domain-D6Xcy9ZX.mjs} +36 -9
  72. package/dist/{platform-lifecycle-CYll-oKE.mjs → platform-lifecycle-DMh_qrry.mjs} +1 -1
  73. package/dist/{platform-lifecycle-BpDlxT3t.mjs → platform-lifecycle-k0E0xoxx.mjs} +769 -59
  74. package/dist/{platform-management-BKYenDlE.mjs → platform-management-Brz_BDiT.mjs} +72 -10
  75. package/dist/{platform-management-BS5r6Ao8.mjs → platform-management-DOtss0BN.mjs} +1 -1
  76. package/dist/{platform-recovery-dJ5Me-I0.mjs → platform-recovery-BvtcXON5.mjs} +2 -2
  77. package/dist/prepare-Bm3iq-u4.mjs +2 -0
  78. package/dist/{prepare-DyZ-Yok5.mjs → prepare-C-6YZyyg.mjs} +3 -3
  79. package/dist/{prepare-C3kt3Rst.mjs → prepare-CRhJbVrG.mjs} +1 -1
  80. package/dist/{project-cmd-B44I8J_W.mjs → project-cmd-BZLCqOqw.mjs} +29 -15
  81. package/dist/{project-team-BkbYIsXN.mjs → project-team-BvgM0WoX.mjs} +3 -3
  82. package/dist/{project-token-C8xEEQnB.mjs → project-token-l5DqK6Az.mjs} +3 -3
  83. package/dist/project-zero-trust-v6Mvpp8y.mjs +63 -0
  84. package/dist/{protocol-ZH3jP4a7.d.mts → protocol-BBa6cstI.d.mts} +1 -1
  85. package/dist/{provision-BhreDAOS.mjs → provision-C4IGqkBf.mjs} +24 -19
  86. package/dist/{provision-DNtrtaVD.mjs → provision-Fr9pRqce.mjs} +1 -1
  87. package/dist/{requests-DFyhBMaf.mjs → requests-DN-BbNiM.mjs} +3 -3
  88. package/dist/{rollback-DHHxXZiS.mjs → rollback-D7rzSaZM.mjs} +4 -4
  89. package/dist/runtime/env-public.d.mts +1 -1
  90. package/dist/runtime/handler.d.mts +1 -1
  91. package/dist/runtime/live-client.d.mts +1 -1
  92. package/dist/runtime/live.d.mts +1 -1
  93. package/dist/runtime/sandbox-container.d.mts +3 -0
  94. package/dist/runtime/sandbox-container.mjs +2 -0
  95. package/dist/runtime/sandbox.d.mts +4 -32
  96. package/dist/runtime/sandbox.mjs +118 -72
  97. package/dist/runtime/validator.d.mts +1 -1
  98. package/dist/runtime/ws-server.d.mts +1 -1
  99. package/dist/runtime/ws.d.mts +1 -1
  100. package/dist/sandbox-container-4fdqLnyb.mjs +279 -0
  101. package/dist/sandbox-container-DdNEBfCc.d.mts +72 -0
  102. package/dist/sandbox-qpNBT8a3.d.mts +49 -0
  103. package/dist/{secret-DN9sSNiV.mjs → secret-BOtOl_cb.mjs} +4 -4
  104. package/dist/{skills-O6FUaizK.mjs → skills-D1II1Juz.mjs} +1 -1
  105. package/dist/{subcommand-prompt-BuGYkAkC.mjs → subcommand-prompt-CY1C4fvl.mjs} +2 -2
  106. package/dist/{wrangler-BymcxrRa.mjs → wrangler-DQF1vKyf.mjs} +37 -27
  107. package/dist/{ws-BwcqizuH.d.mts → ws-BoY7vQML.d.mts} +1 -1
  108. package/package.json +40 -32
  109. package/sandbox.Dockerfile +4 -0
  110. package/schema.json +10 -22
  111. package/skills/void/SKILL.md +2 -0
  112. package/skills/void/docs/guide/deployment.md +1 -1
  113. package/skills/void/docs/guide/edge/revalidation.md +1 -1
  114. package/skills/void/docs/guide/edge/static-assets.md +1 -0
  115. package/skills/void/docs/guide/platform/administration/zero-trust.md +318 -0
  116. package/skills/void/docs/guide/platform/development/local.md +2 -2
  117. package/skills/void/docs/guide/platform/installation/domains.md +1 -1
  118. package/skills/void/docs/guide/platform/installation/first-deployment.md +4 -0
  119. package/skills/void/docs/guide/platform/installation/prerequisites.md +1 -1
  120. package/skills/void/docs/guide/platform/installation/uninstall.md +17 -2
  121. package/skills/void/docs/guide/platform-administration.md +1 -0
  122. package/skills/void/docs/guide/sandboxes.md +70 -41
  123. package/skills/void/docs/integrations/cloudflare.md +1 -1
  124. package/skills/void/docs/reference/api.md +35 -35
  125. package/skills/void/docs/reference/cli.md +68 -6
  126. package/skills/void/docs/reference/config.md +16 -16
  127. package/dist/client-4cDVv7BO.mjs +0 -2
  128. package/dist/gen-Vnv2f65C.mjs +0 -2
  129. package/dist/help-DQMfeKMz.mjs +0 -2
  130. package/dist/login-t6rndSRW.mjs +0 -2
  131. package/dist/migrate-TsHGBnDA.mjs +0 -2
  132. package/dist/prepare-BZXkjdNe.mjs +0 -2
@@ -0,0 +1,49 @@
1
+ import { i as SandboxExecOptions, r as SandboxContainer, s as SandboxOptions } from "./sandbox-container-DdNEBfCc.mjs";
2
+ import { Files } from "@cloudflare/sandbox";
3
+ //#region src/runtime/sandbox.d.ts
4
+ declare const DEFAULT_SANDBOX_ID = "default";
5
+ declare const DEFAULT_SANDBOX_BINDING = "SANDBOX";
6
+ declare const SANDBOX_SERVICE_BINDING = "__VOID_SANDBOX";
7
+ type VoidSandboxOptions = SandboxOptions & {
8
+ binding?: string;
9
+ normalizeId?: boolean;
10
+ };
11
+ type SandboxProcess = {
12
+ pid: number;
13
+ isPty: boolean;
14
+ stdin: WritableStream | null;
15
+ stdout: ReadableStream | null;
16
+ stderr: ReadableStream | null;
17
+ readonly exitCode: Promise<number>;
18
+ output(): Promise<ExecOutput>;
19
+ kill(signal?: number): Promise<void>;
20
+ resize(cols: number, rows: number): Promise<void>;
21
+ };
22
+ type SandboxClient = {
23
+ exec(argv: Array<string>, options?: SandboxExecOptions): Promise<SandboxProcess>;
24
+ files: Files;
25
+ fetch(port: number, request: Request): Promise<Response>;
26
+ running(): Promise<boolean>;
27
+ destroy(): Promise<void>;
28
+ };
29
+ declare class SandboxLimitError extends Error {
30
+ override readonly name = "SandboxLimitError";
31
+ readonly reason: "concurrency" | "runtime_budget";
32
+ constructor(reason: "concurrency" | "runtime_budget", message?: string);
33
+ }
34
+ declare class SandboxUnavailableError extends Error {
35
+ override readonly name = "SandboxUnavailableError";
36
+ constructor(message?: string);
37
+ }
38
+ declare function __setSandboxBindingName(bindingName: string): void;
39
+ /** Generated local/native DO. Managed execution uses the trusted controller. */
40
+ declare class VoidPlatformSandbox<Env = unknown> extends SandboxContainer<Env> {
41
+ protected override beforeStart(): Promise<void>;
42
+ }
43
+ /** Resolve a container by name. Starts on the first command, file or port operation. */
44
+ declare function getSandbox(id?: string, options?: VoidSandboxOptions): Promise<SandboxClient>;
45
+ declare const sandbox: {
46
+ get: typeof getSandbox;
47
+ };
48
+ //#endregion
49
+ export { SandboxLimitError as a, VoidPlatformSandbox as c, getSandbox as d, sandbox as f, SandboxClient as i, VoidSandboxOptions as l, DEFAULT_SANDBOX_ID as n, SandboxProcess as o, SANDBOX_SERVICE_BINDING as r, SandboxUnavailableError as s, DEFAULT_SANDBOX_BINDING as t, __setSandboxBindingName as u };
@@ -1,9 +1,9 @@
1
- import { r as cliTitle } from "./output-CCH48AMM.mjs";
2
1
  import { c as getToken } from "./auth-DLNN0D3Z.mjs";
3
2
  import { i as readDeploymentPlatform, o as readProjectConfig } from "./project-C0Fqu05O.mjs";
4
3
  import { _ as validateSecretValues } from "./env-validation-BB4GkLxn.mjs";
5
- import { E as confirm, F as password, N as note, O as intro, P as outro, T as cancel, W as isCancel, j as log } from "./dist-Dn6nn2IU.mjs";
6
- import { n as PlatformClient } from "./client-QTl6ko_D.mjs";
4
+ import { E as confirm, F as password, N as note, O as intro, P as outro, T as cancel, W as isCancel, j as log } from "./dist-CTBk70IR.mjs";
5
+ import { n as PlatformClient } from "./client-BTZ3XkrB.mjs";
6
+ import { r as cliTitle } from "./output-Dm_A4Tbv.mjs";
7
7
  import { r as resolveProjectBySlug, t as getRequestedProjectSlug } from "./resolve-project-BG5ORGID.mjs";
8
8
  import { readFileSync } from "node:fs";
9
9
  //#region src/cli/secret.ts
@@ -78,7 +78,7 @@ async function runSecretCommand(root, args) {
78
78
  }
79
79
  async function runCloudflareSecretCommand(root, args) {
80
80
  if (args.projectName) throw new Error("secret: --project selects a Void platform project and is not used for direct Cloudflare apps.");
81
- const { deleteCloudflareSecret, listCloudflareSecrets, putCloudflareSecret, resolveCloudflareOperationContext, syncCloudflareSecrets } = await import("./cloudflare-operations-BipGMJ5O.mjs");
81
+ const { deleteCloudflareSecret, listCloudflareSecrets, putCloudflareSecret, resolveCloudflareOperationContext, syncCloudflareSecrets } = await import("./cloudflare-operations-BT6OWFBk.mjs");
82
82
  const context = resolveCloudflareOperationContext(root);
83
83
  if (args.action === "list") {
84
84
  const secrets = await listCloudflareSecrets(context);
@@ -1,5 +1,5 @@
1
1
  import { a as join, l as relative } from "./dist-BVqXeR_h.mjs";
2
- import { j as log } from "./dist-Dn6nn2IU.mjs";
2
+ import { j as log } from "./dist-CTBk70IR.mjs";
3
3
  import { n as getPackageDir } from "./agents-B_pX_HmQ.mjs";
4
4
  import { existsSync, mkdirSync, readFileSync, readdirSync, readlinkSync, symlinkSync } from "node:fs";
5
5
  //#region src/cli/skills.ts
@@ -1,5 +1,5 @@
1
- import { c as import_picocolors } from "./output-CCH48AMM.mjs";
2
- import { S as S_STEP_SUBMIT, _ as S_RADIO_ACTIVE, c as S_CHECKBOX_INACTIVE, i as S_BAR_END, q as wrapAnsi, r as S_BAR, s as S_CHECKBOX_ACTIVE, v as S_RADIO_INACTIVE, y as S_STEP_ACTIVE } from "./dist-Dn6nn2IU.mjs";
1
+ import { S as S_STEP_SUBMIT, _ as S_RADIO_ACTIVE, c as S_CHECKBOX_INACTIVE, i as S_BAR_END, q as wrapAnsi, r as S_BAR, s as S_CHECKBOX_ACTIVE, v as S_RADIO_INACTIVE, y as S_STEP_ACTIVE } from "./dist-CTBk70IR.mjs";
2
+ import { c as import_picocolors } from "./output-Dm_A4Tbv.mjs";
3
3
  //#region src/cli/subcommand-prompt.ts
4
4
  function promptSubcommand(command, subcommands) {
5
5
  return new Promise((resolve) => {
@@ -1,9 +1,9 @@
1
1
  import { a as join, i as isAbsolute, n as dirname, o as normalize, t as basename } from "./dist-BVqXeR_h.mjs";
2
2
  import "./project-paths-GgcMozYz.mjs";
3
- import { m as readConfig } from "./config-CafTW6Cz.mjs";
4
- import { createRequire } from "node:module";
3
+ import { m as readConfig } from "./config-Br_JZD6u.mjs";
5
4
  import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
6
- import { appendSqliteClassMigration } from "@void/deploy-core";
5
+ import { fileURLToPath } from "node:url";
6
+ import { appendSqliteClassMigration, isSandboxRegistryImage } from "@void/deploy-core";
7
7
  import { createHash, randomUUID } from "node:crypto";
8
8
  import { SyntaxKind, applyEdits, createScanner, findNodeAtLocation, modify, parse, parseTree } from "jsonc-parser";
9
9
  import { isDeepStrictEqual } from "node:util";
@@ -180,16 +180,16 @@ function seedCloudflareConfig(root, source, text) {
180
180
  text
181
181
  });
182
182
  }
183
- const SANDBOX_MIGRATION_TAG = "void-sandbox-v1";
184
- const require = createRequire(import.meta.url);
183
+ const DEFAULT_SANDBOX_CLASS_NAME = "SandboxV1";
184
+ const SANDBOX_MIGRATION_TAG = "void-sandbox-v2";
185
185
  function isSandboxEnabled(config) {
186
186
  return config.sandbox !== void 0 && config.sandbox !== false;
187
187
  }
188
188
  function getDefaultSandboxImage() {
189
- return getDefaultSandboxPlatformImage();
189
+ return fileURLToPath(new URL("../../sandbox.Dockerfile", import.meta.resolve("void/sandbox")));
190
190
  }
191
191
  function getDefaultSandboxPlatformImage() {
192
- return `docker.io/cloudflare/sandbox:${JSON.parse(readFileSync(join(getSandboxPackageRoot(), "package.json"), "utf-8")).version ?? "latest"}`;
192
+ return "cloudflare/debian-trixie";
193
193
  }
194
194
  function isLocalSandboxImage(image) {
195
195
  const lowerImage = image.toLowerCase();
@@ -204,24 +204,39 @@ function resolveSandboxConfig(config, root = process.cwd()) {
204
204
  const image = raw.image ?? getDefaultSandboxImage();
205
205
  const imageBuildContext = raw.imageBuildContext;
206
206
  const platformImage = raw.platformImage ?? (raw.image && !isLocalSandboxImage(raw.image) ? raw.image : getDefaultSandboxPlatformImage());
207
+ if (!isLocalSandboxImage(image) && !isSandboxRegistryImage(image)) throw new Error("sandbox.image must be a Dockerfile or a digest-pinned Cloudflare registry image (registry.cloudflare.com/<account>/<image>@sha256:<digest>).");
208
+ if (platformImage !== getDefaultSandboxPlatformImage() && !isSandboxRegistryImage(platformImage)) throw new Error("sandbox.platformImage must be a digest-pinned Cloudflare registry image (registry.cloudflare.com/<account>/<image>@sha256:<digest>).");
207
209
  return {
208
210
  binding: raw.binding ?? "SANDBOX",
209
- className: raw.className ?? "Sandbox",
210
- containerName: raw.containerName ?? "void-sandbox",
211
+ className: raw.className ?? "SandboxV1",
212
+ containerName: raw.containerName ?? "void-sandbox-v1",
211
213
  image: resolveSandboxImage(image, root),
212
214
  platformImage,
213
215
  ...imageBuildContext && { imageBuildContext: isAbsolute(imageBuildContext) ? imageBuildContext : join(root, imageBuildContext) },
214
- ...raw.instanceType && { instanceType: raw.instanceType },
215
- ...raw.maxInstances != null && { maxInstances: raw.maxInstances }
216
+ ...raw.instanceType && { instanceType: raw.instanceType }
216
217
  };
217
218
  }
218
- function getSandboxPackageRoot() {
219
- return join(dirname(require.resolve("@cloudflare/sandbox")), "..");
220
- }
221
219
  function resolveSandboxImage(image, root) {
222
220
  if (!isLocalSandboxImage(image) || isAbsolute(image)) return image;
223
221
  return join(root, image);
224
222
  }
223
+ function sandboxContainerConfig(sandbox) {
224
+ return {
225
+ name: sandbox.containerName,
226
+ class_name: sandbox.className,
227
+ scheduling_policy: "durable_object",
228
+ images: { default: isLocalSandboxImage(sandbox.image) ? {
229
+ dockerfile: sandbox.image,
230
+ ...sandbox.imageBuildContext && { build_context: sandbox.imageBuildContext }
231
+ } : { image: sandbox.image } }
232
+ };
233
+ }
234
+ /** Refuse namespace reuse before either uploader can change a live Worker. */
235
+ function assertSandboxNamespaceConfig(config, sandbox) {
236
+ const containers = Array.isArray(config.containers) ? config.containers : [];
237
+ const durable = config.durable_objects;
238
+ if (containers.some((container) => container.class_name === sandbox.className && container.scheduling_policy !== "durable_object") || durable?.bindings?.some((binding) => binding.name === sandbox.binding && binding.class_name !== sandbox.className)) throw new Error("Sandbox SDK 1.0 needs a new Durable Object namespace. Back up existing Sandbox data and deploy to a fresh Worker name with the new Sandbox configuration; remove legacy Sandbox bindings, containers, and migrations from that new Worker configuration. See https://developers.cloudflare.com/containers/guides/migrate-to-durable-object-scheduling-policy/.");
239
+ }
225
240
  //#endregion
226
241
  //#region src/cli/wrangler.ts
227
242
  const COMPAT_DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
@@ -588,7 +603,8 @@ function syncWranglerBindings(root, bindings, options) {
588
603
  if (bindings.needsSandbox) {
589
604
  const sandbox = options?.sandbox ?? resolveSandboxConfig({ sandbox: true }, root);
590
605
  const bindingName = options?.bindingNames?.sandbox ?? sandbox?.binding ?? "SANDBOX";
591
- const className = sandbox?.className ?? "Sandbox";
606
+ const className = sandbox.className;
607
+ assertSandboxNamespaceConfig(parsed, sandbox);
592
608
  const existingDurableObjectBindings = parsed.durable_objects?.bindings ?? [];
593
609
  if (!existingDurableObjectBindings.some((binding) => binding.name === bindingName)) {
594
610
  parsed.durable_objects = { bindings: [...existingDurableObjectBindings, {
@@ -598,19 +614,13 @@ function syncWranglerBindings(root, bindings, options) {
598
614
  modified = true;
599
615
  }
600
616
  const existingContainers = parsed.containers ?? [];
601
- if (!existingContainers.some((container) => container.class_name === className)) {
602
- parsed.containers = [...existingContainers, {
603
- name: sandbox?.containerName ?? "void-sandbox",
604
- class_name: className,
605
- image: sandbox?.image,
606
- ...sandbox?.imageBuildContext && { image_build_context: sandbox.imageBuildContext },
607
- ...sandbox?.instanceType && { instance_type: sandbox.instanceType },
608
- ...sandbox?.maxInstances != null && { max_instances: sandbox.maxInstances }
609
- }];
617
+ const containers = [...existingContainers.filter((container) => container.class_name !== className), sandboxContainerConfig(sandbox)];
618
+ if (JSON.stringify(containers) !== JSON.stringify(existingContainers)) {
619
+ parsed.containers = containers;
610
620
  modified = true;
611
621
  }
612
622
  const migrations = Array.isArray(parsed.migrations) ? parsed.migrations : [];
613
- if (!migrations.some((migration) => migration.tag === "void-sandbox-v1" || migration.new_sqlite_classes?.includes(className))) {
623
+ if (!migrations.some((migration) => migration.tag === "void-sandbox-v2" || migration.new_sqlite_classes?.includes(className))) {
614
624
  parsed.migrations = [...migrations, {
615
625
  tag: SANDBOX_MIGRATION_TAG,
616
626
  new_sqlite_classes: [className]
@@ -675,7 +685,7 @@ function readWranglerWebSocketTombstones(root, websockets) {
675
685
  if (!configPath) return [];
676
686
  const parsed = parseJsonc(readFileSync(configPath, "utf-8"));
677
687
  const migrations = Array.isArray(parsed.migrations) ? parsed.migrations : [];
678
- const historicalClasses = new Set(migrations.filter((migration) => /^void-ws-v1(?:-\d+)?$/.test(migration.tag ?? "")).flatMap((migration) => [...migration.new_classes ?? [], ...migration.new_sqlite_classes ?? []]));
688
+ const historicalClasses = new Set(migrations.flatMap((migration) => /^void-ws-v1(?:-\d+)?$/.test(migration.tag ?? "") ? [...migration.new_classes ?? [], ...migration.new_sqlite_classes ?? []] : []));
679
689
  const currentClasses = new Set(websockets.map((route) => route.className));
680
690
  const bindings = parsed.durable_objects?.bindings;
681
691
  return [...new Set((Array.isArray(bindings) ? bindings : []).flatMap((binding) => typeof binding.class_name === "string" && historicalClasses.has(binding.class_name) && !currentClasses.has(binding.class_name) ? [binding.class_name] : []))].sort();
@@ -1981,4 +1991,4 @@ function canonicalize(value) {
1981
1991
  return value;
1982
1992
  }
1983
1993
  //#endregion
1984
- export { writeWranglerPublishedTrafficSnapshot as A, seedCloudflareConfig as B, readWranglerWebSocketTombstones as C, syncWranglerWebSockets as D, syncWranglerDurableObjects as E, MATERIALIZED_CLOUDFLARE_FILE as F, VOID_LOCK_FILE as I, materializeCloudflareConfig as L, isSandboxEnabled as M, requiresSandboxPlatformImage as N, updateWranglerCustomDomain as O, resolveSandboxConfig as P, persistCloudflareConfig as R, readWranglerPublishedTrafficSnapshot as S, syncWranglerBindings as T, stashCloudflareDeployPointer as V, readProvisionedBindingEntry as _, LIVE_MIGRATION_TAG as a, readWranglerCustomDomains as b, bindingEntriesForField as c, ensureWranglerNodejsAlsFlag as d, findBindingNameOwner as f, readExistingLiveBindingConfig as g, normalizeWranglerCompatibilityFlags as h, LATEST_KNOWN_COMPAT_DATE as i, SANDBOX_MIGRATION_TAG as j, writeProvisionedWranglerConfig as k, ensureWranglerCompat as l, nextDurableObjectMigrationTag as m, DEFAULT_LIVE_CLASS as n, acknowledgeWranglerManagedQueueRemovals as o, hasDurableObjectSqliteMigration as p, FRIENDLY_BINDING_NAMES as r, assertNoDuplicateMembers as s, DEFAULT_LIVE_BINDING as t, ensureWranglerCompatibilityDate as u, readRootWranglerConfig as v, resolveLiveBindingConfig as w, readWranglerManagedQueueCleanupCandidates as x, readWranglerCompat as y, restoreCloudflarePreviewPointer as z };
1994
+ export { writeWranglerPublishedTrafficSnapshot as A, materializeCloudflareConfig as B, readWranglerWebSocketTombstones as C, syncWranglerWebSockets as D, syncWranglerDurableObjects as E, requiresSandboxPlatformImage as F, restoreCloudflarePreviewPointer as H, resolveSandboxConfig as I, sandboxContainerConfig as L, SANDBOX_MIGRATION_TAG as M, assertSandboxNamespaceConfig as N, updateWranglerCustomDomain as O, isSandboxEnabled as P, MATERIALIZED_CLOUDFLARE_FILE as R, readWranglerPublishedTrafficSnapshot as S, syncWranglerBindings as T, seedCloudflareConfig as U, persistCloudflareConfig as V, stashCloudflareDeployPointer as W, readProvisionedBindingEntry as _, LIVE_MIGRATION_TAG as a, readWranglerCustomDomains as b, bindingEntriesForField as c, ensureWranglerNodejsAlsFlag as d, findBindingNameOwner as f, readExistingLiveBindingConfig as g, normalizeWranglerCompatibilityFlags as h, LATEST_KNOWN_COMPAT_DATE as i, DEFAULT_SANDBOX_CLASS_NAME as j, writeProvisionedWranglerConfig as k, ensureWranglerCompat as l, nextDurableObjectMigrationTag as m, DEFAULT_LIVE_CLASS as n, acknowledgeWranglerManagedQueueRemovals as o, hasDurableObjectSqliteMigration as p, FRIENDLY_BINDING_NAMES as r, assertNoDuplicateMembers as s, DEFAULT_LIVE_BINDING as t, ensureWranglerCompatibilityDate as u, readRootWranglerConfig as v, resolveLiveBindingConfig as w, readWranglerManagedQueueCleanupCandidates as x, readWranglerCompat as y, VOID_LOCK_FILE as z };
@@ -1,6 +1,6 @@
1
1
  import { t as StandardSchemaV1 } from "./standard-schema-Fo_vCAZh.mjs";
2
2
  import { r as AuthUser } from "./auth-DkcFflXV.mjs";
3
- import { a as CloudEnv } from "./handler-BXJTXd02.mjs";
3
+ import { a as CloudEnv } from "./handler-HEcZsaij.mjs";
4
4
  import { WebSocketRouteMap } from "void/routes";
5
5
  //#region src/runtime/ws.d.ts
6
6
  type MaybePromise<T> = T | Promise<T>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "void",
3
- "version": "0.21.8",
3
+ "version": "0.22.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/voidzero-dev/void.git",
@@ -14,7 +14,8 @@
14
14
  "schema.json",
15
15
  "skills",
16
16
  "AGENTS_TEMPLATE.md",
17
- "README.md"
17
+ "README.md",
18
+ "sandbox.Dockerfile"
18
19
  ],
19
20
  "type": "module",
20
21
  "imports": {
@@ -316,57 +317,64 @@
316
317
  "types": "./dist/runtime/db-mysql.d.mts",
317
318
  "import": "./dist/runtime/db-mysql.mjs",
318
319
  "require": "./dist/runtime/db-mysql.mjs"
320
+ },
321
+ "./_sandbox-container": {
322
+ "types": "./dist/runtime/sandbox-container.d.mts",
323
+ "import": "./dist/runtime/sandbox-container.mjs"
319
324
  }
320
325
  },
321
326
  "dependencies": {
322
- "@cloudflare/build-output-utils": "0.8.2",
323
- "@cloudflare/config": "0.20.0",
324
- "@cloudflare/sandbox": "^0.12.9",
325
- "@cloudflare/vite-plugin": "1.54.7",
327
+ "@cloudflare/build-output-utils": "0.8.4",
328
+ "@cloudflare/codemods": "0.3.0",
329
+ "@cloudflare/config": "0.22.0",
330
+ "@cloudflare/sandbox": "1.0.0",
331
+ "@cloudflare/vite-plugin": "1.62.2",
332
+ "@cloudflare/workers-auth": "0.9.5",
326
333
  "@cloudflare/workers-types": "^4.20260702.1",
327
- "@napi-rs/keyring": "2.0.0",
328
- "@void/deploy-cloudflare": "0.21.8",
329
- "@void/deploy-core": "0.21.8",
330
- "@void/edge": "0.21.8",
331
- "@void/isr": "0.21.8",
332
- "@void/platform": "0.21.8",
333
- "acorn": "^8.15.0",
334
- "better-auth": "^1.7.3",
334
+ "@napi-rs/keyring": "2.1.0",
335
+ "@void/deploy-cloudflare": "0.22.0",
336
+ "@void/deploy-core": "0.22.0",
337
+ "@void/edge": "0.22.0",
338
+ "@void/isr": "0.22.0",
339
+ "@void/platform": "0.22.0",
340
+ "acorn": "^8.18.0",
341
+ "better-auth": "^1.7.6",
335
342
  "better-sqlite3": "^13.0.3",
336
343
  "blake3-jit": "^1.1.0",
337
- "cf": "1.0.0-beta.5",
344
+ "cf": "1.0.0-beta.9",
338
345
  "drizzle-arktype": "^0.1.3",
339
- "drizzle-kit": "^0.31.10",
340
- "drizzle-orm": "^0.45.2",
346
+ "drizzle-kit": "^0.31.11",
347
+ "drizzle-orm": "^0.45.3",
341
348
  "drizzle-valibot": "^0.4.2",
342
349
  "drizzle-zod": "^0.8.3",
343
350
  "email-validator": "^2.0.4",
344
351
  "es-module-lexer": "^3.0.2",
345
- "hono": "^4.13.7",
346
- "ignore": "^7.0.9",
352
+ "hono": "^4.13.11",
353
+ "ignore": "^7.0.10",
347
354
  "jiti": "^2.7.0",
348
355
  "jsonc-parser": "3.3.1",
349
- "miniflare": "5.20260926.0-alpha",
356
+ "mime": "4.1.0",
357
+ "miniflare": "5.20260926.1-alpha",
350
358
  "minimatch": "^10.2.6",
351
- "mysql2": "3.24.4",
359
+ "mysql2": "3.24.5",
352
360
  "pg": "8.23.0",
353
- "postal-mime": "^2.7.4",
361
+ "postal-mime": "^4.0.0",
354
362
  "proper-lockfile": "^4.1.2",
355
- "undici": "7.29.0"
363
+ "undici": "8.11.2"
356
364
  },
357
365
  "devDependencies": {
358
- "@clack/core": "1.5.0",
359
- "@clack/prompts": "^1.8.0",
366
+ "@clack/core": "^1.5.1",
367
+ "@clack/prompts": "^1.8.1",
360
368
  "@electric-sql/pglite": "0.5.8",
361
369
  "@types/better-sqlite3": "^9.6.0",
362
- "@types/node": "^26.5.1",
370
+ "@types/node": "^26.6.3",
363
371
  "@types/pg": "^8.23.1",
364
372
  "@types/proper-lockfile": "^4.1.4",
365
- "arktype": "^2.2.3",
373
+ "arktype": "^2.2.5",
366
374
  "ci-info": "^4.4.0",
367
375
  "estree-walker": "^3.0.3",
368
376
  "fast-wrap-ansi": "^0.2.2",
369
- "magic-string": "^1.3.1",
377
+ "magic-string": "^1.4.2",
370
378
  "ofetch": "2.0.0-alpha.3",
371
379
  "pathslash": "^0.1.0",
372
380
  "pglite-server": "0.1.5",
@@ -374,12 +382,12 @@
374
382
  "tinyglobby": "^0.2.17",
375
383
  "typescript": "7.0.2",
376
384
  "valibot": "^1.5.0",
377
- "vite": "npm:@voidzero-dev/vite-plus-core@0.3.1",
378
- "vite-plus": "0.3.1",
379
- "zod": "^4.6.1"
385
+ "vite": "npm:@voidzero-dev/vite-plus-core@1.0.0",
386
+ "vite-plus": "1.0.0",
387
+ "zod": "^4.6.5"
380
388
  },
381
389
  "peerDependencies": {
382
- "@void/md": "0.21.8",
390
+ "@void/md": "0.22.0",
383
391
  "arktype": ">=2.0.0",
384
392
  "valibot": ">=1.0.0-beta.7",
385
393
  "vite": "^8.0.0",
@@ -0,0 +1,4 @@
1
+ FROM node:24.21.0-trixie-slim
2
+ COPY --from=docker.io/cloudflare/sandbox:1.0.0 /usr/local/bin/sandbox-shim /usr/local/bin/sandbox-shim
3
+ WORKDIR /workspace
4
+ CMD ["sleep", "infinity"]
package/schema.json CHANGED
@@ -297,9 +297,11 @@
297
297
  "description": "Connect to remote D1/KV/R2 bindings during local development. Can also be set via VOID_REMOTE=1 environment variable."
298
298
  },
299
299
  "sandbox": {
300
- "description": "Enable Cloudflare Sandboxes. `true` uses the default SANDBOX binding and Cloudflare sandbox image; an object customizes the Durable Object binding, container image, and scaling.",
300
+ "description": "Enable Cloudflare Sandboxes. `true` uses the default SANDBOX binding and Node.js environment; an object customizes the Durable Object binding, container image, and instance size.",
301
301
  "oneOf": [
302
- { "type": "boolean" },
302
+ {
303
+ "type": "boolean"
304
+ },
303
305
  {
304
306
  "type": "object",
305
307
  "properties": {
@@ -309,42 +311,28 @@
309
311
  },
310
312
  "className": {
311
313
  "type": "string",
312
- "description": "Durable Object class name. Defaults to Sandbox."
314
+ "description": "Durable Object class name. Defaults to SandboxV1."
313
315
  },
314
316
  "containerName": {
315
317
  "type": "string",
316
- "description": "Cloudflare Container application name. Defaults to void-sandbox."
318
+ "description": "Cloudflare Container application name. Defaults to void-sandbox-v1."
317
319
  },
318
320
  "image": {
319
321
  "type": "string",
320
- "description": "Container image or Dockerfile path used by local Wrangler development."
322
+ "description": "Dockerfile path or digest-pinned Cloudflare managed registry image for local and native Cloudflare use."
321
323
  },
322
324
  "imageBuildContext": {
323
325
  "type": "string",
324
- "description": "Optional Docker build context path for local Wrangler development."
326
+ "description": "Optional Docker build context path for local development and native Cloudflare deploys."
325
327
  },
326
328
  "platformImage": {
327
329
  "type": "string",
328
- "description": "Registry image reference used by `void deploy`. Required when `image` is a custom local Dockerfile path."
330
+ "description": "Cloudflare managed registry image pinned by digest, containing the SDK 1.0 sandbox-shim. Defaults to Cloudflare’s managed Node.js image."
329
331
  },
330
332
  "instanceType": {
331
333
  "type": "string",
332
- "enum": [
333
- "dev",
334
- "lite",
335
- "basic",
336
- "standard",
337
- "standard-1",
338
- "standard-2",
339
- "standard-3",
340
- "standard-4"
341
- ],
334
+ "enum": ["lite", "standard-1", "standard-2", "standard-3", "standard-4"],
342
335
  "description": "Cloudflare Container instance type."
343
- },
344
- "maxInstances": {
345
- "type": "integer",
346
- "minimum": 1,
347
- "description": "Maximum number of sandbox container instances."
348
336
  }
349
337
  },
350
338
  "additionalProperties": false
@@ -77,6 +77,8 @@ Use `void connect` for deployment onboarding: no arguments offers Cloudflare or
77
77
 
78
78
  For Void platform project access, use `void project team`: invite only an email already registered on that platform and assign `reader`, `collaborator`, or `admin`. The invited account uses `void connect <url>` followed by pending/accept/decline on that active connection, regardless of the current directory's project link or deploy target. `VOID_API_URL` overrides the connection; an unscoped `VOID_TOKEN` selects Void Cloud. Acceptance preserves directory links; run `void project link` in an unlinked checkout of the invited application. Project-scoped team management does not apply to direct Cloudflare deployments. Installation administrators transfer ownership with `void platform project owner <project-id> <user-id> --plan` and apply the reviewed transfer with `--yes`.
79
79
 
80
+ For a self-hosted platform's project Zero Trust policy, installation administrators use `void platform zero-trust`; pass the Access management token only through `--token-stdin`. Project owners and project administrators use `void project zero-trust status|protect|public|reconcile`; these commands do not apply to direct Cloudflare deployments. When a deploy or rollback is refused because protection is not settled, check `void project zero-trust status`; an owner or project administrator can run `void project zero-trust reconcile` before retrying.
81
+
80
82
  Use Void commands for every user-facing workflow. Never ask the user to install, authenticate, or run Wrangler directly. Say Cloudflare or Void instead, except when naming literal `wrangler.jsonc` / `wrangler.json` files or `WRANGLER_*` environment variables the user must inspect.
81
83
 
82
84
  `void auth login|status|logout` follows the saved deploy destination or asks the user to choose; `void account` explicitly manages a Void platform account.
@@ -150,7 +150,7 @@ void github join
150
150
  void github connect --executor container
151
151
  ```
152
152
 
153
- Organization installations always require a browser proof for the specific repository, including for the person who installed the App. Void does not reveal the installation's full private repository list. If an upgraded platform marks an older organization connection as requiring reconnection, run the same `void github connect` command again to renew that repository-scoped authorization before builds resume.
153
+ Organization installations always require a browser proof for the specific repository, including for the person who installed the App. Void does not reveal the installation's full private repository list.
154
154
 
155
155
  4. Verify the connection
156
156
 
@@ -105,7 +105,7 @@ revalidation, Void removes its HTML, Pages JSON, and KV cache entries.
105
105
 
106
106
  ## Cache bypass
107
107
 
108
- Requests with `Cookie` or `Authorization` headers bypass the ISR cache entirely and always dispatch to the worker. This ensures personalized or authenticated pages are never served from a shared cache.
108
+ Requests with `Cookie`, `Authorization`, or Cloudflare Access's `Cf-Access-Jwt-Assertion` header bypass the ISR cache entirely and always dispatch to the worker. Authenticated responses are not shared between users, including when Access authentication supplies no cookie.
109
109
 
110
110
  ## Cache keys and rewrites
111
111
 
@@ -51,6 +51,7 @@ Cached at the edge until the next deploy. Browsers always revalidate on the next
51
51
  - `/api/*` routes, which always hit the worker
52
52
  - SSR-rendered pages (paths without file extensions in SSR projects)
53
53
  - Non-GET requests
54
+ - Requests carrying `Cookie`, `Authorization`, or `Cf-Access-Jwt-Assertion` credentials
54
55
  - Responses other than a complete `200`
55
56
 
56
57
  ### Opting out