void 1.1.11 → 1.1.12

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 (152) hide show
  1. package/dist/{account-cmd-R35a4Oa8.mjs → account-cmd-Cj6sCMTk.mjs} +4 -4
  2. package/dist/{auth-link-VHmiKZmP.mjs → auth-link-Dj7lAC_K.mjs} +4 -4
  3. package/dist/{auth-router-O_Wrs5kg.mjs → auth-router-CNsMOFCa.mjs} +2 -2
  4. package/dist/{build-cmd-CMZiMn46.mjs → build-cmd-ByhegwRC.mjs} +2 -2
  5. package/dist/{cache-TZ5Ab3d7.mjs → cache-CEFb5ban.mjs} +2 -2
  6. package/dist/{cancel-deploy-DXoR6oC3.mjs → cancel-deploy-CaARY26n.mjs} +2 -2
  7. package/dist/{cf-build-output-Bc8i3dzE.mjs → cf-build-output-ChEKWan2.mjs} +71 -7
  8. package/dist/cf-build-output-Dcmxa-Zm.mjs +1 -0
  9. package/dist/{cf-user-agent-ChjQp2MU.mjs → cf-command-values-b8OqDoo9.mjs} +5 -16
  10. package/dist/cf-user-agent-BkEHPDLA.mjs +16 -0
  11. package/dist/cli/cli.mjs +135 -31
  12. package/dist/cli/cloudflare-operation-process.mjs +46 -9
  13. package/dist/{client-GuSO3v_x.mjs → client-BdzxubTS.mjs} +57 -12
  14. package/dist/client-DAnfyMe9.mjs +1 -0
  15. package/dist/{cloudflare-cmd-ZSErUl6Y.mjs → cloudflare-cmd-D_2-Q-_i.mjs} +1 -1
  16. package/dist/{cloudflare-operations-Cm8lVx7W.mjs → cloudflare-operations-BFLCpUCV.mjs} +1 -1
  17. package/dist/{cloudflare-operations-DH3GedbV.mjs → cloudflare-operations-D5PLrOqD.mjs} +14 -4
  18. package/dist/{connect-yQuLbuiJ.mjs → connect-C4_m2moF.mjs} +4 -4
  19. package/dist/{create-project-CGOo_OL_.mjs → create-project-CvuYDD-l.mjs} +1 -1
  20. package/dist/{create-project-DEEWJX_M.mjs → create-project-D8jQTwVQ.mjs} +2 -2
  21. package/dist/{db-COI-yTJE.mjs → db-BsiOAa0A.mjs} +58 -8
  22. package/dist/{delete-PgN6L_9N.mjs → delete-CAma7nFi.mjs} +2 -2
  23. package/dist/{deploy-DsW-PrRQ.mjs → deploy-D1gIPiAq.mjs} +118 -36
  24. package/dist/deploy-Dc0XsCQj.mjs +2 -0
  25. package/dist/{deploy-managed-static-Dqz06S2u.mjs → deploy-managed-static-B9KVxY3X.mjs} +64 -18
  26. package/dist/{deploy-transport-nY3vLXPL.mjs → deploy-transport-B3mtEi_q.mjs} +1 -1
  27. package/dist/deploy.d.mts +22 -1
  28. package/dist/deploy.mjs +45 -4
  29. package/dist/{domain-DKlNI0SR.mjs → domain-BAdwm-QS.mjs} +3 -3
  30. package/dist/{email-C0s3OvJk.mjs → email-MwjA7kaL.mjs} +4 -4
  31. package/dist/{env-BX2JFsgF.mjs → env-B163-G1s.mjs} +3 -3
  32. package/dist/{fetch-DHLOuPyk.d.mts → fetch-CUX0tB78.d.mts} +14 -1
  33. package/dist/fetch-CtESUYWd.mjs +26 -0
  34. package/dist/{fetch-error-Dj3crt0e.mjs → fetch-error-Bw0n-IY-.mjs} +1 -1
  35. package/dist/{fetch-stream-PGgz4uGz.mjs → fetch-stream-BspOeTAI.mjs} +1 -1
  36. package/dist/{fetch-stream-CNxOrBdP.d.mts → fetch-stream-DfkAzZf-.d.mts} +1 -1
  37. package/dist/{gen-Bj6ZkOcI.mjs → gen-CYN3wiov.mjs} +1 -1
  38. package/dist/gen-Cf-RBVg4.mjs +1 -0
  39. package/dist/{github-cmd-DQDryS-5.mjs → github-cmd-C8QsnJQs.mjs} +2 -2
  40. package/dist/{handler-_PqY82xe.d.mts → handler-D5K_yP6T.d.mts} +1 -1
  41. package/dist/{help-D49SL_lN.mjs → help-B2sFwn9b.mjs} +44 -3
  42. package/dist/help-w-xlx_kq.mjs +1 -0
  43. package/dist/index.d.mts +1 -1
  44. package/dist/index.mjs +38 -71
  45. package/dist/{init-DyTEY04s.mjs → init-DGFQMnbk.mjs} +6 -6
  46. package/dist/{link-CgOVn9EC.mjs → link-CwrfpjIM.mjs} +3 -3
  47. package/dist/{list-CUfD9RSb.mjs → list-hKoW5z-b.mjs} +3 -3
  48. package/dist/{live-DJONVlQK.d.mts → live-JheIDZKc.d.mts} +1 -1
  49. package/dist/login-08mBwZfI.mjs +1 -0
  50. package/dist/{login-BJvGW5Eu.mjs → login-f2eu2TQh.mjs} +3 -3
  51. package/dist/{logs-DeizBI4j.mjs → logs-CEWqD-_B.mjs} +3 -3
  52. package/dist/{migrate-8rk56vV8.mjs → migrate-DYfdWBXt.mjs} +1 -1
  53. package/dist/migrate-Di-4EuoE.mjs +1 -0
  54. package/dist/nitro.mjs +1 -1
  55. package/dist/operator-cmd-Bv20yLu2.mjs +1 -0
  56. package/dist/{operator-cmd-CA5QQyvE.mjs → operator-cmd-DCr_QGMH.mjs} +4 -4
  57. package/dist/{output-Ba6ZbrzY.mjs → output-CKguMgr7.mjs} +13 -1
  58. package/dist/pages/client.d.mts +2 -2
  59. package/dist/pages/client.mjs +18 -5
  60. package/dist/pages/index.d.mts +1 -1
  61. package/dist/pages/index.mjs +1 -1
  62. package/dist/pages/islands-plugin.d.mts +43 -5
  63. package/dist/pages/islands-plugin.mjs +98 -27
  64. package/dist/pages/protocol.d.mts +2 -2
  65. package/dist/pages/protocol.mjs +1 -1
  66. package/dist/pages/serialize.d.mts +2 -2
  67. package/dist/pages/serialize.mjs +1 -1
  68. package/dist/{platform-auth-config-CZaY812e.mjs → platform-auth-config-qGvEuns3.mjs} +5 -5
  69. package/dist/{platform-auth-protection-U9HCqoXv.mjs → platform-auth-protection-CyLcD6ot.mjs} +3 -3
  70. package/dist/{platform-auth-recovery-B0BV2hfV.mjs → platform-auth-recovery-B2LKI8V2.mjs} +3 -3
  71. package/dist/{platform-cmd-D9lwFpcl.mjs → platform-cmd-B2ec5eFg.mjs} +1 -1
  72. package/dist/{platform-cmd-CXrjk4fb.mjs → platform-cmd-CX7phm7V.mjs} +5 -5
  73. package/dist/{platform-domain-CXyq-68_.mjs → platform-domain-DDNK2y-4.mjs} +3 -3
  74. package/dist/{platform-lifecycle-D0TdyXbN.mjs → platform-lifecycle-3CR98Tg2.mjs} +386 -36
  75. package/dist/{platform-lifecycle-Dz2cJsLX.mjs → platform-lifecycle-CWc5gr6c.mjs} +1 -1
  76. package/dist/{platform-management-BvgbusqL.mjs → platform-management-DAE6g2QU.mjs} +1 -1
  77. package/dist/{platform-management-CnXhgxTM.mjs → platform-management-o3LCCeE4.mjs} +40 -2
  78. package/dist/{platform-plans-config-BWn1S2Rv.mjs → platform-plans-config-CBMZxCep.mjs} +1 -1
  79. package/dist/{platform-recovery-CH_fThW6.mjs → platform-recovery-Dmsg7lWA.mjs} +2 -2
  80. package/dist/{platform-setup-YvN9VQXV.mjs → platform-setup-hFbnWAVQ.mjs} +1 -1
  81. package/dist/{prepare-2XD6kh77.mjs → prepare-HKo7Rh5V.mjs} +1 -1
  82. package/dist/{project-cmd-CpLYflCH.mjs → project-cmd-8ylYGx-O.mjs} +17 -17
  83. package/dist/{project-team-CTSY7W7Q.mjs → project-team-Bvpl78we.mjs} +2 -2
  84. package/dist/{project-token-Cybtlfbl.mjs → project-token-QWHoJH2t.mjs} +2 -2
  85. package/dist/{project-zero-trust-DKOtqyvu.mjs → project-zero-trust-8tJ-RFvu.mjs} +2 -2
  86. package/dist/{protocol-B8sI8dRD.d.mts → protocol-Ssc_LhHj.d.mts} +1 -1
  87. package/dist/{protocol-RNP0u7UY.mjs → protocol-bAUUkx70.mjs} +1 -1
  88. package/dist/{provision-UcYjpTRh.mjs → provision-BgXFDv0d.mjs} +1 -1
  89. package/dist/{provision-BuifYvLc.mjs → provision-DZKYCEJg.mjs} +3 -2
  90. package/dist/{requests-Ryiazz9i.mjs → requests-Vk5Zyhcy.mjs} +2 -2
  91. package/dist/{rollback-Or0EV3rP.mjs → rollback-CH4yMQys.mjs} +9 -8
  92. package/dist/runtime/client-react.d.mts +2 -2
  93. package/dist/runtime/client-react.mjs +3 -3
  94. package/dist/runtime/client-solid.d.mts +2 -2
  95. package/dist/runtime/client-solid.mjs +3 -3
  96. package/dist/runtime/client-svelte.d.mts +2 -2
  97. package/dist/runtime/client-svelte.mjs +3 -3
  98. package/dist/runtime/client-vue.d.mts +2 -2
  99. package/dist/runtime/client-vue.mjs +3 -3
  100. package/dist/runtime/client.d.mts +2 -2
  101. package/dist/runtime/client.mjs +3 -3
  102. package/dist/runtime/fetch-server.d.mts +8 -0
  103. package/dist/runtime/fetch-server.mjs +30 -0
  104. package/dist/runtime/fetch-stream.d.mts +2 -2
  105. package/dist/runtime/fetch-stream.mjs +2 -2
  106. package/dist/runtime/fetch.d.mts +2 -2
  107. package/dist/runtime/fetch.mjs +3 -3
  108. package/dist/runtime/handler.d.mts +1 -1
  109. package/dist/runtime/live-client.d.mts +1 -1
  110. package/dist/runtime/live.d.mts +1 -1
  111. package/dist/runtime/routing.d.mts +1 -1
  112. package/dist/runtime/routing.mjs +1 -1
  113. package/dist/runtime/validator.d.mts +1 -1
  114. package/dist/runtime/ws-server.d.mts +1 -1
  115. package/dist/runtime/ws.d.mts +1 -1
  116. package/dist/{secret-CClHaFxm.mjs → secret-wr6Sn4Xa.mjs} +3 -3
  117. package/dist/serialize-DtR8Vwa_.d.mts +18 -0
  118. package/dist/serialize-YHvlcG3Q.mjs +31 -0
  119. package/dist/{subcommand-prompt-Bm3ZlYgA.mjs → subcommand-prompt-CNZc4XUd.mjs} +1 -1
  120. package/dist/{wrapper-BOigE1xJ.mjs → wrapper-DGsYwNi6.mjs} +2 -0
  121. package/dist/{ws-CsBNxv86.d.mts → ws-nnFnAyQb.d.mts} +1 -1
  122. package/docs/guide/deployment.md +2 -0
  123. package/docs/guide/edge/headers.md +1 -1
  124. package/docs/guide/email/receiving.md +1 -1
  125. package/docs/guide/email/sending.md +3 -3
  126. package/docs/guide/pages-routing/markdown.md +3 -1
  127. package/docs/guide/platform/administration/email.md +7 -1
  128. package/docs/guide/platform/installation/ci.md +2 -0
  129. package/docs/guide/platform/installation/credentials.md +23 -5
  130. package/docs/guide/platform/installation/maintenance.md +32 -2
  131. package/docs/guide/platform/installation/setup.md +1 -1
  132. package/docs/guide/typed-fetch.md +1 -1
  133. package/docs/integrations/cloudflare.md +1 -1
  134. package/docs/integrations/frameworks/tanstack-start.md +25 -0
  135. package/docs/reference/api/deploy.md +35 -3
  136. package/docs/reference/cli/database.md +15 -0
  137. package/docs/reference/cli/platform-installation.md +2 -0
  138. package/docs/reference/cli/project.md +4 -2
  139. package/docs/reference/cli.md +1 -0
  140. package/docs/reference/config.md +1 -1
  141. package/package.json +8 -7
  142. package/dist/cf-build-output-BU3hqdHu.mjs +0 -1
  143. package/dist/client-DrdeJgHR.mjs +0 -1
  144. package/dist/deploy-CxNgEYr4.mjs +0 -2
  145. package/dist/fetch-sAcwjzLO.mjs +0 -18
  146. package/dist/gen-DsCukhuw.mjs +0 -1
  147. package/dist/help-DOFygYi4.mjs +0 -1
  148. package/dist/login-alAlxw4S.mjs +0 -1
  149. package/dist/migrate-D2odrAmh.mjs +0 -1
  150. package/dist/operator-cmd-D7toMPJ9.mjs +0 -1
  151. package/dist/serialize-BtQyaYoC.mjs +0 -20
  152. package/dist/serialize-CfSwWfF2.d.mts +0 -10
@@ -1,2 +1,2 @@
1
- import { D as runValidation, E as ValidatorSlots, T as HandlerInput } from "../handler-_PqY82xe.mjs";
1
+ import { D as runValidation, E as ValidatorSlots, T as HandlerInput } from "../handler-D5K_yP6T.mjs";
2
2
  export { HandlerInput, ValidatorSlots, runValidation };
@@ -1,6 +1,6 @@
1
1
  import { n as AuthState } from "../auth-DkcFflXV.mjs";
2
2
  import { r as VoidAuthRuntimeOptions, t as VoidAuthEnv } from "../better-auth-shared-Bv18bB-l.mjs";
3
- import { f as WebSocketInstanceKey, t as AnyWebSocketDefinition } from "../ws-CsBNxv86.mjs";
3
+ import { f as WebSocketInstanceKey, t as AnyWebSocketDefinition } from "../ws-nnFnAyQb.mjs";
4
4
  //#region src/runtime/ws-server.d.ts
5
5
  export type WebSocketRouteMeta = {
6
6
  name?: string;
@@ -1,2 +1,2 @@
1
- import { a as RoomDefinition, c as VoidSocket, d as WebSocketConnection, f as WebSocketInstanceKey, h as defineWebSocket, i as RoomController, l as VoidSocketCloseEvent, m as defineRoom, n as ConnectCommonOptions, o as SocketContext, p as connect, r as RoomContext, s as SocketDefinition, t as AnyWebSocketDefinition, u as WebSocketBaseContext } from "../ws-CsBNxv86.mjs";
1
+ import { a as RoomDefinition, c as VoidSocket, d as WebSocketConnection, f as WebSocketInstanceKey, h as defineWebSocket, i as RoomController, l as VoidSocketCloseEvent, m as defineRoom, n as ConnectCommonOptions, o as SocketContext, p as connect, r as RoomContext, s as SocketDefinition, t as AnyWebSocketDefinition, u as WebSocketBaseContext } from "../ws-nnFnAyQb.mjs";
2
2
  export { AnyWebSocketDefinition, ConnectCommonOptions, RoomContext, RoomController, RoomDefinition, SocketContext, SocketDefinition, VoidSocket, VoidSocketCloseEvent, WebSocketBaseContext, WebSocketConnection, WebSocketInstanceKey, connect, defineRoom, defineWebSocket };
@@ -1,8 +1,8 @@
1
1
  import { n as readDeploymentPlatform, r as readProjectConfig } from "./project-rqDnVsJN.mjs";
2
2
  import { c as getToken } from "./auth-B6iOCjKI.mjs";
3
3
  import { A as confirm, H as outro, L as log, O as cancel, U as password, tt as isCancel } from "./dist-BVdsO7Py.mjs";
4
- import { m as printSuccess, o as formatCount, p as note } from "./output-Ba6ZbrzY.mjs";
5
- import { r as PlatformClient } from "./client-GuSO3v_x.mjs";
4
+ import { m as printSuccess, o as formatCount, p as note } from "./output-CKguMgr7.mjs";
5
+ import { r as PlatformClient } from "./client-BdzxubTS.mjs";
6
6
  import { a as resolveProjectBySlug, t as getRequestedProjectSlug } from "./resolve-project-WpwkCB_c.mjs";
7
7
  import { _ as validateSecretValues } from "./env-validation-D_KyMdab.mjs";
8
8
  import { readFileSync } from "node:fs";
@@ -93,7 +93,7 @@ async function resolveSecretBackend(root, args) {
93
93
  }
94
94
  async function resolveCloudflareSecretBackend(root, args) {
95
95
  if (args.projectName) throw new Error("secret: --project selects a Void platform project and is not used for direct Cloudflare apps.");
96
- const { deleteCloudflareSecret, listCloudflareSecrets, putCloudflareSecret, resolveCloudflareOperationContext, syncCloudflareSecrets } = await import("./cloudflare-operations-Cm8lVx7W.mjs");
96
+ const { deleteCloudflareSecret, listCloudflareSecrets, putCloudflareSecret, resolveCloudflareOperationContext, syncCloudflareSecrets } = await import("./cloudflare-operations-BFLCpUCV.mjs");
97
97
  const context = resolveCloudflareOperationContext(root);
98
98
  return {
99
99
  target: "Cloudflare Worker",
@@ -0,0 +1,18 @@
1
+ //#region src/pages/serialize.d.ts
2
+ /**
3
+ * Escape JSON for embedding inside an inline `<script type="application/json">`
4
+ * tag. Replaces `<`, `>`, `&`, U+2028, U+2029 with their `\uXXXX` JSON escape
5
+ * sequences so the script tag cannot be closed early and the payload survives
6
+ * `JSON.parse` on hydration.
7
+ */
8
+ declare function serializePageData(pageObj: unknown): string;
9
+ /** Element id of the Markdown page frontmatter that islands read when they hydrate. */
10
+ declare const ISLAND_FRONTMATTER_ID = "__void_frontmatter";
11
+ /**
12
+ * Script tag that carries a Markdown page's frontmatter to its islands, so
13
+ * `useFrontmatter()` returns the same value in the browser as on the server.
14
+ * Empty when the page has no frontmatter.
15
+ */
16
+ declare function islandFrontmatterScript(frontmatter: Record<string, unknown> | undefined): string;
17
+ //#endregion
18
+ export { islandFrontmatterScript as n, serializePageData as r, ISLAND_FRONTMATTER_ID as t };
@@ -0,0 +1,31 @@
1
+ //#region src/pages/script-json.ts
2
+ const UNSAFE_SCRIPT_CHARS = /[<>&\u2028\u2029]/g;
3
+ function escapeScriptJson(json) {
4
+ return json.replace(UNSAFE_SCRIPT_CHARS, (c) => {
5
+ return `\\u${c.charCodeAt(0).toString(16).padStart(4, "0")}`;
6
+ });
7
+ }
8
+ //#endregion
9
+ //#region src/pages/serialize.ts
10
+ /**
11
+ * Escape JSON for embedding inside an inline `<script type="application/json">`
12
+ * tag. Replaces `<`, `>`, `&`, U+2028, U+2029 with their `\uXXXX` JSON escape
13
+ * sequences so the script tag cannot be closed early and the payload survives
14
+ * `JSON.parse` on hydration.
15
+ */
16
+ function serializePageData(pageObj) {
17
+ return escapeScriptJson(JSON.stringify(pageObj));
18
+ }
19
+ /** Element id of the Markdown page frontmatter that islands read when they hydrate. */
20
+ const ISLAND_FRONTMATTER_ID = "__void_frontmatter";
21
+ /**
22
+ * Script tag that carries a Markdown page's frontmatter to its islands, so
23
+ * `useFrontmatter()` returns the same value in the browser as on the server.
24
+ * Empty when the page has no frontmatter.
25
+ */
26
+ function islandFrontmatterScript(frontmatter) {
27
+ if (!frontmatter || Object.keys(frontmatter).length === 0) return "";
28
+ return `<script type="application/json" id="${ISLAND_FRONTMATTER_ID}">${serializePageData(frontmatter)}<\/script>`;
29
+ }
30
+ //#endregion
31
+ export { escapeScriptJson as i, islandFrontmatterScript as n, serializePageData as r, ISLAND_FRONTMATTER_ID as t };
@@ -1,5 +1,5 @@
1
1
  import { $ as wrapTextWithPrefix, G as promptTitle, M as getGuide, V as optionText, b as S_RADIO_ACTIVE, d as S_CHECKBOX_SELECTED, i as S_BAR_END, it as wrapAnsi, j as formatInstructionFooter, n as SELECT_INSTRUCTIONS, r as S_BAR, t as MULTISELECT_INSTRUCTIONS, u as S_CHECKBOX_INACTIVE, w as S_STEP_SUBMIT } from "./dist-BVdsO7Py.mjs";
2
- import { f as import_picocolors } from "./output-Ba6ZbrzY.mjs";
2
+ import { f as import_picocolors } from "./output-CKguMgr7.mjs";
3
3
  //#region src/cli/subcommand-prompt.ts
4
4
  const isUpKey = (key) => key === "\x1B[A" || key === "\x1BOA";
5
5
  const isDownKey = (key) => key === "\x1B[B" || key === "\x1BOB";
@@ -459,6 +459,7 @@ function generateWrapperSource(renamedEntry, handlersModule, features, migration
459
459
  const lines = [];
460
460
  lines.push(WRAPPER_MARKER);
461
461
  lines.push(`import original from "./${renamedEntry}";`);
462
+ lines.push(`export * from "./${renamedEntry}";`);
462
463
  if (features.isr) {
463
464
  lines.push("import { handleFrameworkIsr } from \"./__void_isr.mjs\";");
464
465
  lines.push(`const __voidIsrDeploymentId = ${JSON.stringify(crypto.randomUUID())};`);
@@ -558,6 +559,7 @@ function generateWrapperSource(renamedEntry, handlersModule, features, migration
558
559
  lines.push("");
559
560
  }
560
561
  lines.push("export default {");
562
+ lines.push(" ...original,");
561
563
  if (needsFetchWrap) lines.push(" fetch: wrappedFetch,");
562
564
  else lines.push(" fetch: original.fetch,");
563
565
  if (features.crons.length > 0) lines.push(features.isr ? " scheduled(controller, env, ctx) { env.__VOID_ISR_DEPLOYMENT_ID ??= __voidIsrDeploymentId; return handleScheduled(controller, env, ctx); }," : " scheduled: handleScheduled,");
@@ -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-_PqY82xe.mjs";
3
+ import { a as CloudEnv } from "./handler-D5K_yP6T.mjs";
4
4
  import { WebSocketRouteMap } from "void/routes";
5
5
  //#region src/runtime/ws.d.ts
6
6
  type MaybePromise<T> = T | Promise<T>;
@@ -35,6 +35,8 @@ void db generate
35
35
 
36
36
  Review and commit the SQL, then deploy again. Rollback does not reverse database migrations. See [Database](./database.md) for the local workflow.
37
37
 
38
+ On your own Cloudflare account, deploy saves a D1 [Time Travel](https://developers.cloudflare.com/d1/reference/time-travel/) restore point before it applies pending migrations and prints the [`void db restore`](../reference/cli/database.md#void-db-restore) command for it. If no restore point can be saved, deploy stops before it migrates. If deploy fails after it applied the migrations, for example when the upload fails, it prints the command again. Usually you fix the error and deploy again; restore only if the live version cannot run against the new schema. To recover from a bad migration, roll back the code with `void project rollback` if the new version is live, restore the database, then fix or remove the migration before you deploy again. After a one-off `void deploy --platform cloudflare`, add `--platform cloudflare` to each of these commands. Restoring discards every write made after the restore point. Restore points expire after 7 days on Workers Free and 30 days on Workers Paid; after that, undo a migration with a new one.
39
+
38
40
  ### Environment variables
39
41
 
40
42
  Declare values in `env.ts` and set production server secrets with `void secret put`. Deploy never uploads your local `.env`. Supply public `VITE_*` values through the build environment. See [Environment Variables](./env-vars.md).
@@ -43,7 +43,7 @@ On a [Void platform](../deployment.md#deploy-to-a-team-platform), apps usually s
43
43
 
44
44
  This stops a header rule from setting or clearing cookies for other apps on the same domain. These limits apply only to header rules. Your app's own response can set cookies and send `Clear-Site-Data`, and on a shared domain those can affect other apps. See [Domains and Resources](../platform/installation/domains.md#adding-a-domain).
45
45
 
46
- In `void dev`, with `void deploy --platform cloudflare`, and on [other runtimes](../deployment.md#other-runtimes), header rules apply both headers as written.
46
+ During local development, with `void deploy --platform cloudflare`, and on [other runtimes](../deployment.md#other-runtimes), header rules apply both headers as written.
47
47
 
48
48
  ## Framework `_headers` files
49
49
 
@@ -96,7 +96,7 @@ to check current provider routing and any remaining setup steps.
96
96
 
97
97
  For direct deployments, follow [Your own Cloudflare account](./domains.md#your-own-cloudflare-account) to configure inbound addresses.
98
98
 
99
- `void dev` has no local inbound trigger. It serves only the outbound dev inbox. Test inbound handlers with `createInboundTestHarness` below.
99
+ The local dev server provides the outbound email inbox but has no inbound email trigger. Test inbound handlers with `createInboundTestHarness` below.
100
100
 
101
101
  ## Testing inbound handlers {#testing-inbound-handlers}
102
102
 
@@ -34,7 +34,7 @@ Check both failure shapes: `result.error` reports a request failure, while `resu
34
34
 
35
35
  ## Setup {#setup}
36
36
 
37
- On a platform with email enabled, deploy without additional email configuration. Ask your administrator for its shared mail domain. Administrators [enable email during installation or upgrade](/guide/platform/installation/credentials#runtime-token-permissions).
37
+ On a platform with email enabled, deploy without additional email configuration. Ask your administrator for its shared mail domain. Administrators [enable email during installation or upgrade](/guide/platform/installation/credentials#enable-email).
38
38
 
39
39
  Each project on an email-enabled platform has:
40
40
 
@@ -171,7 +171,7 @@ The default platform allowance is 200 recipient attempts per UTC month and 10 pe
171
171
 
172
172
  ## Local development {#local-development}
173
173
 
174
- During `void dev`, sends are captured to an in-memory inbox instead of going to Cloudflare. The dev server prints the inbox URL when it starts:
174
+ During local development, sends are captured to an in-memory inbox instead of going to Cloudflare. The dev server prints the inbox URL when it starts:
175
175
 
176
176
  ```
177
177
  [void] Email inbox: http://localhost:5173/__void/inbox?token=<printed-token>
@@ -195,7 +195,7 @@ The inbox keeps the most recent 100 messages through HMR and clears on a full se
195
195
 
196
196
  The dev inbox works in native Void apps, TanStack Start, and React Router. It is unavailable in SvelteKit, Nuxt, Analog, and Astro; sends from those apps return `BINDING_MISSING`. Use `createEmailTestHarness` from `void/email/testing` to capture sends in tests. If a configured inbox cannot be reached, `sendEmail` returns `UPSTREAM_ERROR` without sending.
197
197
 
198
- `sendInDev` is deprecated. During `void dev` it skips the inbox and returns `BINDING_MISSING`, so it never delivers. Remove it, and deploy the app to test real delivery.
198
+ `sendInDev` is deprecated. During local development it skips the inbox and returns `BINDING_MISSING`, so it never delivers. Remove it, and deploy the app to test real delivery.
199
199
 
200
200
  ## Testing {#testing}
201
201
 
@@ -137,7 +137,7 @@ Welcome to Void. Here's an interactive demo:
137
137
  ```
138
138
 
139
139
  - **`<script>` block:** extracted before markdown compilation. Island imports use `with { island: "..." }` syntax (see [islands](./islands)). Any other code in the block becomes a [client script](#client-scripts) that runs in the browser.
140
- - **Frontmatter:** YAML metadata between `---` fences. Layouts can read it through [`useFrontmatter()`](#frontmatter-access).
140
+ - **Frontmatter:** YAML metadata between `---` fences. Layouts and islands can read it through [`useFrontmatter()`](#frontmatter-access).
141
141
  - **Body:** standard markdown plus GFM. Uppercase tags such as `<Counter />` reference imported components and render as islands.
142
142
 
143
143
  ## Client Scripts
@@ -230,6 +230,8 @@ export default function DocsLayout(props) {
230
230
 
231
231
  :::
232
232
 
233
+ Island components on a Markdown page can call `useFrontmatter()` too. A page with islands includes its frontmatter in the HTML for them to read in the browser. Keep private values out of the frontmatter of those pages.
234
+
233
235
  ## Pages Virtual Module
234
236
 
235
237
  Import `@void/md/pages` to get metadata for all markdown pages at build time. Use it to build sidebars, navigation, or search indexes:
@@ -27,6 +27,12 @@ reconciliation verifies delivery afterward; a deleting project stays closed
27
27
  and its deletion can be retried. See [operator email commands](../../../reference/cli/platform-email.md#operator-email)
28
28
  for the recovery requirements.
29
29
 
30
+ ### Mail that the platform sends {#platform-sender}
31
+
32
+ The platform sends its own mail, for example invitations, welcome mail, failed-deploy notices, and error alerts. This mail comes from `noreply@<mail domain>`, and the sender name is the platform's display name. Void sets this sender, so you do not need to configure one. Do not set a different sender on the platform Workers in the Cloudflare dashboard. That change stops the next `upgrade`, `repair`, `enable`, or `rollback` until you let Void replace it. See [Platform Workers changed outside Void](/guide/platform/installation/maintenance#workers-changed-outside-void).
33
+
34
+ Mail to an address that is not verified needs Cloudflare Email Sending onboarding and [Workers Paid](https://dash.cloudflare.com/?to=/:account/workers/plans).
35
+
30
36
  ### Deciding who mail may reach
31
37
 
32
38
  By default, mail from the shared sender reaches only the recipients each project has verified. For a team whose applications mainly mail colleagues, widen that once for the whole installation:
@@ -114,7 +120,7 @@ Use the apex of the selected Cloudflare zone. Platform-managed custom inbound em
114
120
  void platform email domain-add other.example --project hr-portal --token-stdin --yes < token.txt
115
121
  ```
116
122
 
117
- Project owners see administrator-registered domains in `void email domain list` and `status`; `status` names the `void platform email` command for any step they cannot take themselves, and `sync` and `remove` point them at `domain-sync` and `domain-remove`. A domain an owner registered before you switched to `admin` stays theirs to renew, sync and remove. The runtime token needs the email permissions listed in the [self-hosting guide](/guide/platform/installation/credentials#runtime-token-permissions) for this to work.
123
+ Project owners see administrator-registered domains in `void email domain list` and `status`; `status` names the `void platform email` command for any step they cannot take themselves, and `sync` and `remove` point them at `domain-sync` and `domain-remove`. A domain an owner registered before you switched to `admin` stays theirs to renew, sync and remove. The runtime token needs the [email permissions](/guide/platform/installation/credentials#enable-email) for this to work.
118
124
 
119
125
  A permission refusal leaves setup blocked. After correcting it, run `domain-sync`
120
126
  to resume that same setup operation; repeat `domain-rotate-secret` to resume a
@@ -51,6 +51,8 @@ void platform install \
51
51
 
52
52
  Mutations require `--yes` in CI; a read-only `--plan` does not. Custom runtimes also require `--runtime <directory>`. For a new installation, run `--plan` with the same account, name, and domain options as the unattended install. If you use `--auth-config`, pass the same file to both commands. Register `<platform-api-url>/auth/callback` when creating a login provider's OAuth or OIDC client manually; automatic Access setup manages its own application. A custom API hostname is optional.
53
53
 
54
+ In CI, `upgrade`, `repair`, `enable`, `rollback`, and `install --resume` stop before they change a platform Worker or pause traffic when a platform Worker was changed in the Cloudflare dashboard or with the Cloudflare API, or has an active version without a Void deployment record. See [Platform Workers changed outside Void](/guide/platform/installation/maintenance#workers-changed-outside-void).
55
+
54
56
  :::
55
57
 
56
58
  ## Customize the Platform
@@ -68,7 +68,25 @@ Void checks access before provisioning. If it reports a missing permission, upda
68
68
 
69
69
  ## Enable Email {#enable-email}
70
70
 
71
- Choose a shared sender domain and its Cloudflare zone ID. The mail zone may differ from the application zone, but it must belong to the platform's Cloudflare account. To enable email on an existing installation, run:
71
+ Choose a shared sender domain and its Cloudflare zone ID. The mail zone may differ from the application zone, but it must belong to the platform's Cloudflare account.
72
+
73
+ Before you enable email, enable [Cloudflare Email Routing](https://developers.cloudflare.com/email-service/get-started/route-emails/) for the exact shared sender domain and confirm that its MX records point to Cloudflare. For a subdomain, add that name under the zone's **Email Routing → Settings → Subdomains**. Cloudflare adds the required MX and SPF records. The installer's shared-mail bootstrap verifies those records; it does not add them. Keep existing mail-provider records on other domain names in place.
74
+
75
+ Enabling email lets administrators [register email domains for projects](/guide/platform/administration/email#registering-email-domains-for-projects) and lets projects register destination addresses through the runtime token. The runtime token needs these permissions:
76
+
77
+ | Scope | Permission | Access |
78
+ | ------- | ----------------------- | ------ |
79
+ | Account | Email Routing Addresses | Edit |
80
+ | Account | Email Sending | Edit |
81
+ | Zone | Zone | Read |
82
+ | Zone | Zone Settings | Edit |
83
+ | Zone | Email Routing Rules | Edit |
84
+
85
+ The zone permissions must include each zone that will carry mail, including the mail zone. Email Sending onboarding for arbitrary recipients needs Workers Paid.
86
+
87
+ For a new installation, set `VOID_EMAIL_SENDER_DOMAIN` and `VOID_EMAIL_SHARED_ZONE_ID` before `void platform install`. The runtime-token link then preselects these permissions.
88
+
89
+ For an existing installation, add the permissions to its runtime token first. Edit the token in the Cloudflare dashboard. The token value stays the same. Or set `VOID_PLATFORM_RUNTIME_CLOUDFLARE_API_TOKEN` to a new token that has all runtime permissions. Then run:
72
90
 
73
91
  ```sh
74
92
  VOID_EMAIL_SENDER_DOMAIN=mail.example.com \
@@ -76,13 +94,13 @@ VOID_EMAIL_SHARED_ZONE_ID=your-zone-id \
76
94
  void platform upgrade your-installation-id
77
95
  ```
78
96
 
79
- Set the same two variables before `void platform install` to enable email during a new installation. Void records the pair for later upgrades; an ordinary upgrade cannot replace it.
97
+ Void records the domain and zone for later upgrades; an ordinary upgrade cannot replace them.
80
98
 
81
- Before installing, enable [Cloudflare Email Routing](https://developers.cloudflare.com/email-service/get-started/route-emails/) for the exact shared sender domain and confirm that its MX records point to Cloudflare. For a subdomain, add that name under the zone's **Email Routing → Settings → Subdomains**. Cloudflare adds the required MX and SPF records. The installer's shared-mail bootstrap verifies those records; it does not add them. Keep existing mail-provider records on other domain names in place.
99
+ Before the CLI changes anything or pauses traffic, it checks that the runtime token can read the mail zone and its Email Routing settings, rules, and addresses. If Cloudflare denies a request, the command stops and names each missing permission. Void keeps a saved runtime token, so you can add the permission to the same token and run the command again. The check cannot confirm Edit access or Email Sending, so select those permissions as the table shows.
82
100
 
83
- Enabling email lets administrators [register email domains for projects](/guide/platform/administration/email#registering-email-domains-for-projects) and lets projects register destination addresses through the runtime token. That needs **Email Routing Addresses: Edit** and **Email Sending: Edit** on the account, plus **Zone: Read**, **Zone Settings: Edit** and **Email Routing Rules: Edit** on the zones that will carry mail. The runtime-token link preselects them when email is enabled. Email Sending onboarding for arbitrary recipients needs Workers Paid.
101
+ Without `VOID_PLATFORM_RUNTIME_CLOUDFLARE_API_TOKEN`, `upgrade`, `repair`, `enable`, and `rollback` check the runtime token saved on this machine. The platform can use a newer token, for example one set from another machine. If Cloudflare does not accept the saved token, the CLI shows a warning and continues without the check. To check the token that the platform uses, set `VOID_PLATFORM_RUNTIME_CLOUDFLARE_API_TOKEN` to it.
84
102
 
85
- The installer deploys the email gateway, prepares the shared mail route, and verifies inbound readiness before opening platform traffic. If setup fails, correct the reported permission, exact-domain MX records, or routing conflict, then rerun the same install or upgrade command. A fresh install resumes with `void platform install --resume --name <installation-id>`; it continues the recorded email operation after the configuration is corrected.
103
+ The installer deploys the email gateway, prepares the shared mail route, and verifies inbound readiness before opening platform traffic. If setup fails, fix the problem that the error names, for example a missing permission, the exact-domain MX records, or a routing conflict. Then run the same install or upgrade command again. A fresh install resumes with `void platform install --resume --name <installation-id>`; it continues the recorded email operation after the configuration is corrected.
86
104
 
87
105
  ## R2 Upload Credentials
88
106
 
@@ -113,9 +113,13 @@ An upgrade validates the runtime, applies supported pending migrations, deploys
113
113
 
114
114
  Before starting, Void checks access to the installation's Cloudflare account, Workers, and existing R2 buckets. If credentials are rejected, set `CLOUDFLARE_API_TOKEN` to a management token scoped to that account and retry. This overrides the installation's saved management token.
115
115
 
116
- ::: details Migration safety, credential rotation, and interrupted upgrades
116
+ Some upgrades pause application traffic during the cutover to the new version. Traffic resumes after the new version passes its health checks. If an upgrade or another lifecycle command fails after it paused traffic, traffic stays paused until a later run succeeds. To resume:
117
117
 
118
- Some upgrades briefly put the platform into maintenance mode. Traffic resumes after the new version passes health checks. If an upgrade is interrupted during maintenance, rerun the same command to complete it.
118
+ 1. Run `void platform status <id>` to see the saved progress.
119
+ 2. Fix the problem that the error names.
120
+ 3. Run the resume command that the CLI printed. It is the same command, with the same runtime.
121
+
122
+ ::: details Migration safety, credential rotation, and rollback
119
123
 
120
124
  To update the runtime Cloudflare token, GitHub OAuth credentials when GitHub login is enabled, or R2 credentials,
121
125
  provide their `VOID_PLATFORM_*` environment variables when running the upgrade.
@@ -141,6 +145,32 @@ Let running rotations finish before you roll back. If an older proxy runs next t
141
145
 
142
146
  :::
143
147
 
148
+ ### Platform Workers changed outside Void {#workers-changed-outside-void}
149
+
150
+ Void manages the platform's own Workers. Do not change them in the Cloudflare dashboard or with the Cloudflare API. To change the platform, use the Void commands on this page.
151
+
152
+ `upgrade`, `repair`, `enable`, `rollback`, and `install --resume` deploy the platform Workers again. Before they change a platform Worker or pause traffic, Void finds each platform Worker that:
153
+
154
+ - was changed in the Cloudflare dashboard or with the Cloudflare API.
155
+ - has an active version without a Void deployment record. This can occur when an earlier run replaced a change made outside Void, and then stopped or failed. If that run stopped during the cutover to the new version, the command first makes the earlier versions active again. Void checks those earlier versions too. A version that an older Void release deployed can also have no record.
156
+
157
+ The `--plan` preview of `upgrade`, `repair`, `enable`, and `rollback` shows the same list as a warning.
158
+
159
+ In a terminal, Void lists these Workers and asks **Replace the configuration of these Workers?** The default answer is No.
160
+
161
+ - If you answer No, the command stops. No platform Worker changed, and the command did not pause traffic.
162
+ - If you answer Yes, the command continues. First, Void prepares the platform resources and the database. Then, before it pauses traffic or deploys a Worker, the Cloudflare CLI asks you again for each Worker changed in the dashboard or with the API. For a dashboard change, it shows the differences. Void uploads a new version of each of these Workers and does not deploy it yet. For a Worker that has an active version without a Void deployment record, the Cloudflare CLI does not ask again.
163
+
164
+ If you refuse in the Cloudflare CLI, the command stops. Void does not undo the resource and database changes. No deployment changed, and the command did not pause traffic.
165
+
166
+ The replacement removes values that Void does not set, for example an `EMAIL_FROM` variable that you added. It also resets values that Void sets, for example `AUTH_REDIRECT_URI`.
167
+
168
+ Without a terminal, for example in CI, or with `--yes`, the command stops before it changes a platform Worker, and it does not pause traffic. Run the command that Void prints once in a terminal, and answer the questions there. After that run completes, the command works in CI again.
169
+
170
+ If Void cannot read a platform Worker, the command also stops before it changes a platform Worker or pauses traffic. Run the command again. If a platform Worker has no single version that gets 100% of traffic, for example after a gradual deployment, deploy one version of it to 100% of traffic in the Cloudflare dashboard. Then run the command once in a terminal, so that you can approve the dashboard change.
171
+
172
+ If an earlier run failed after it paused traffic, traffic stays paused after these stops. To resume traffic, see [Upgrade the platform](#upgrade-the-platform).
173
+
144
174
  ### Follow upgrade and rollback progress
145
175
 
146
176
  Watching progress is optional: a running upgrade or rollback proceeds through
@@ -260,6 +260,6 @@ You can also rerun `void platform install` and choose **Continue setup** for an
260
260
 
261
261
  Resume restores your selected Hyperdrive. If that selection is missing from the saved checkpoint, add `--hyperdrive <existing-id>` when resuming, using the same configuration you originally selected.
262
262
 
263
- If Cloudflare rejects a saved runtime token during continued credential setup, Void opens the token page and asks for a replacement in the same run. Network or service failures do not discard saved tokens. Tokens supplied through the environment must be corrected there instead.
263
+ If Cloudflare rejects a saved runtime token during continued credential setup, Void opens the token page and asks for a replacement in the same run. A missing [email permission](/guide/platform/installation/credentials#enable-email) does not discard the saved token: add the permission to the same token, then resume. Network or service failures do not discard saved tokens. Tokens supplied through the environment must be corrected there instead.
264
264
 
265
265
  :::
@@ -106,4 +106,4 @@ export default defineRender(async (c, assetTags) => {
106
106
  });
107
107
  ```
108
108
 
109
- Server-side calls forward the incoming request's `cookie` and `authorization` headers. Explicit headers take precedence.
109
+ Server-side calls to your app forward the incoming request's `cookie` and `authorization` headers. Explicit headers take precedence. Calls to an external `baseURL` use HTTP and do not inherit these headers.
@@ -183,7 +183,7 @@ void project status
183
183
  void project rollback [version]
184
184
  ```
185
185
 
186
- Void restores recorded triggers along with the code. Versions without a complete trigger snapshot keep current routes and schedules. Rollback does not reverse database migrations.
186
+ Void restores recorded triggers along with the code. Versions without a complete trigger snapshot keep current routes and schedules. Rollback does not reverse database migrations. To undo D1 migrations, run [`void db restore`](../reference/cli/database.md#void-db-restore) with the restore point that deploy printed before it applied them, within 7 days on Workers Free or 30 days on Workers Paid.
187
187
 
188
188
  #### Scope and limitations
189
189
 
@@ -71,6 +71,31 @@ Use [KV](../../guide/kv.md), [object storage](../../guide/storage.md), and [AI](
71
71
 
72
72
  Declare variables in `env.ts` and read them with `import { env } from "void/env"`. See [Environment Variables](../../guide/env-vars.md) for local values, production secrets, and public `VITE_*` values.
73
73
 
74
+ ## Custom Worker Entry
75
+
76
+ Set `cloudflare.main` in `void.config.ts` when your Worker needs its own entry module, for example to export a Durable Object class:
77
+
78
+ ```ts
79
+ import { defineConfig } from 'void/config';
80
+
81
+ export default defineConfig({
82
+ cloudflare: { main: './server.ts' },
83
+ });
84
+ ```
85
+
86
+ The path is relative to your app root. Default-export the TanStack request handler and add your named exports in that module:
87
+
88
+ ```ts
89
+ import handler from '@tanstack/react-start/server-entry';
90
+
91
+ export { Counter } from './counter';
92
+ export default handler;
93
+ ```
94
+
95
+ Void preserves these named exports in development, production builds, and deploys. Without `cloudflare.main`, Void uses TanStack's default server entry. A package entry such as `@tanstack/react-start/server-entry` is resolved as a module.
96
+
97
+ Bind an exported Durable Object or Workflow class under `cloudflare` as well, for example in `cloudflare.durable_objects`. These settings apply when you deploy with `void deploy --platform cloudflare`. On a Void platform, use [Durable State](../../guide/durable-state.md) instead.
98
+
74
99
  ## Accessing Bindings Directly
75
100
 
76
101
  You can also access Cloudflare bindings via the `cloudflare:workers` module:
@@ -1,6 +1,6 @@
1
1
  # Deployment artifacts
2
2
 
3
- Use `void/deploy` from Node.js to prepare a built Void app for a managed platform deployment without platform credentials.
3
+ Use `void/deploy` from Node.js to prepare a built Void app, SPA, or static site for a managed platform deployment without platform credentials.
4
4
 
5
5
  Build the app in managed mode inside its isolated environment:
6
6
 
@@ -16,8 +16,40 @@ import { prepareDeployArtifact } from 'void/deploy';
16
16
  const { artifact, assets } = await prepareDeployArtifact('/path/to/app');
17
17
  ```
18
18
 
19
- `artifact` contains the deployment manifest, content-addressed asset metadata, and base64 Worker modules. `assets` maps asset URL paths to base64 bytes. Keep this result immutable while requesting [publish approval](/guide/platform/administration/connected-apps).
19
+ `artifact` contains the deployment manifest, content-addressed asset metadata, and base64 Worker modules when the app needs a Worker. SPAs and static sites contain only assets, using the same app detection, output directory and routing configuration as `void deploy`. `assets` maps asset URL paths to base64 bytes. Keep this result immutable while requesting [publish approval](/guide/platform/administration/connected-apps).
20
20
 
21
- Preparation packages existing build output; it does not build, contact a platform, provision resources, or deploy. It supports Void Cloudflare Worker builds. Node targets, static output, remote data, deploy-time prerendering, Sandbox, and Live resources require the normal `void deploy` workflow instead.
21
+ Preparation packages existing build output; it does not build, contact a platform, provision resources, or deploy. It supports Void Cloudflare Worker builds, SPAs, and static sites. Node targets, Pages `output: 'static'`, remote data, deploy-time prerendering, Sandbox, and Live resources require the normal `void deploy` workflow instead.
22
22
 
23
23
  Run preparation inside the same isolated environment as the app build. App configuration and build plugins execute project code; keep platform credentials on the publishing server.
24
+
25
+ ## Cloudflare Build Output
26
+
27
+ ::: warning Experimental
28
+ `prepareCfBuildOutput` follows Cloudflare's draft Build Output format. Its options and the prepared directory can change between Void releases.
29
+ :::
30
+
31
+ Use `prepareCfBuildOutput` to convert an existing Cloudflare Worker build into a disposable Cloudflare Build Output directory:
32
+
33
+ ```ts
34
+ import { prepareCfBuildOutput } from 'void/deploy';
35
+
36
+ const prepared = await prepareCfBuildOutput('/path/to/app/dist/server', { mode: 'staging' });
37
+ if (!prepared) {
38
+ throw new Error('The Worker build could not be prepared.');
39
+ }
40
+
41
+ try {
42
+ // Inspect or pass prepared.directory to your Cloudflare publication workflow.
43
+ } finally {
44
+ await prepared.dispose();
45
+ }
46
+ ```
47
+
48
+ Pass the Worker output directory that contains a generated `wrangler.json`, such as `dist/ssr`, `dist/rsc`, or `dist/server`. When Cloudflare's build tooling built the app, pass the project root that contains its native Build Output at `.cloudflare/output/v0` instead. Preparation copies modules and assets without changing that input. Native output keeps its module types, auxiliary Workers, Container declarations, and build metadata. Preparation does not provision resources, upload a Worker, or activate a deployment. Container images built from a local Dockerfile exist only in the Docker environment that built them, so publish from that environment.
49
+
50
+ | Option | Description |
51
+ | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
52
+ | `accountId` | Cloudflare account the build must target. A different account in the build returns `null`. When omitted, the build's account is kept or left unset. |
53
+ | `mode` | Vite build mode. Native output keeps the mode it was built with, and a different value returns `null`. For other output it defaults to `production`. |
54
+
55
+ The result contains `directory`, an optional `assetsDirectory` pointing to the input assets, and an asynchronous `dispose()` method. Always dispose the result after use. Unsupported build configuration returns `null`. A directory without a Worker build, a missing or invalid Worker module, or an asset symlink outside the asset directory throws an error.
@@ -89,6 +89,21 @@ By default, targets the local database. Pass `--remote` to open Studio against t
89
89
  - **Direct Cloudflare PostgreSQL and MySQL projects**: use `DATABASE_URL` from the current shell.
90
90
  - **D1 projects**: remote Studio is not available. Use `void db execute --remote` to query your deployed D1 database.
91
91
 
92
+ ## `void db restore` {#void-db-restore}
93
+
94
+ ```
95
+ void db restore --bookmark <bookmark> [--platform cloudflare] [--yes]
96
+ void db restore --timestamp <iso-time> [--platform cloudflare] [--yes]
97
+ ```
98
+
99
+ Restore the deployed D1 database of a direct Cloudflare deploy with D1 [Time Travel](https://developers.cloudflare.com/d1/reference/time-travel/). Before `void deploy --platform cloudflare` applies migrations, it prints the `--bookmark` that undoes them. `--timestamp` restores the state at an ISO 8601 time with `Z` or an offset instead, such as `2026-10-16T09:30:00Z`, with at most millisecond precision. Time Travel keeps 7 days of history on Workers Free and 30 days on Workers Paid. An older bookmark or time can no longer be restored: Cloudflare rejects it and the database stays unchanged. To undo an older migration, write a new migration that reverses it.
100
+
101
+ If the project's saved destination is not Cloudflare and you deployed once with `void deploy --platform cloudflare`, pass `--platform cloudflare`; deploy prints the command with it.
102
+
103
+ Restoring replaces the whole database and discards every write made after that point. Void names the database and asks before it restores. Pass `--yes` to skip the prompt in scripts and CI; without a terminal, the command stops unless `--yes` is set. Afterwards Void prints the `void db restore` command that undoes the restore.
104
+
105
+ A restore also rewinds the record of applied migrations. Void lists the migration files the database no longer has applied; the next deploy applies them, so fix or remove the one that caused the problem first. Restoring does not change the deployed code: use [`void project rollback`](./project.md#void-project-rollback-deployid) if the live version needs the newer schema. After a one-off Cloudflare deploy, pass `--platform cloudflare` to `void project rollback` and `void deploy` as well.
106
+
92
107
  ## `void db rename-migrations` {#void-db-rename-migrations}
93
108
 
94
109
  Rename existing migrations from the old numeric prefix format (`0001_name.sql`) to timestamp-based format (`20260410161500_name.sql`). Updates local tracking table and remote records if logged in with a linked project. A project that deploys to Void must be linked first with `void project link`; otherwise the command stops without changes.
@@ -137,6 +137,8 @@ After discovery on another machine, set `VOID_PLATFORM_DATABASE_URL`. See [Manag
137
137
 
138
138
  Repair and upgrade preserve disabled state. New, resumed, and previously disabled installations block user traffic until all target Workers pass verification; the installer's health probes can still run. Routes and custom domains remain attached.
139
139
 
140
+ If a platform Worker was changed outside Void, or has an active version without a Void deployment record, a command that deploys the platform Workers stops before it changes a platform Worker or pauses traffic, unless you agree in a terminal to replace the changes. See [Platform Workers changed outside Void](../../guide/platform/installation/maintenance.md#workers-changed-outside-void).
141
+
140
142
  `--runtime` selects a custom platform build. Relative paths resolve from your current directory. Void verifies the build before making changes; see [Platform Development](../../guide/platform/development/runtime.md#deploying-your-runtime) for creating one.
141
143
 
142
144
  Without `--runtime`, the CLI uses its packaged platform version.
@@ -169,7 +169,7 @@ void project requests --range 24h
169
169
  ## `void project rollback [deployId]` {#void-project-rollback-deployid}
170
170
 
171
171
  ```
172
- void project rollback [deployId]
172
+ void project rollback [deployId] [--platform cloudflare]
173
173
  ```
174
174
 
175
175
  Roll back to a previous deployment or Worker Version.
@@ -179,7 +179,9 @@ Roll back to a previous deployment or Worker Version.
179
179
 
180
180
  On a Void platform, you can select a retained deployment. On Cloudflare, use a complete Worker Version ID or an unambiguous prefix. Void activates that version at 100%. When both versions have complete trigger snapshots, it also restores the selected version's schedules, queues, workflows, routes, and custom domains. Otherwise, rollback keeps the current triggers and restores the code, including versions originally deployed outside Void.
181
181
 
182
- Rollback doesn't reverse database migrations. If older code may run against a newer schema, or migration metadata is missing, Void explains the risk and asks for confirmation.
182
+ If the project's saved destination is not Cloudflare and you deployed once with `void deploy --platform cloudflare`, pass `--platform cloudflare` to roll back that Worker.
183
+
184
+ Rollback doesn't reverse database migrations. If older code may run against a newer schema, or migration metadata is missing, Void explains the risk and asks for confirmation. On Cloudflare, undo D1 migrations with [`void db restore`](./database.md#void-db-restore) and the restore point that deploy printed before it applied them, within 7 days on Workers Free or 30 days on Workers Paid.
183
185
 
184
186
  ## `void project cancel [deployId]` {#void-project-cancel-deployid}
185
187
 
@@ -47,6 +47,7 @@ Use this page as a command reference. If you are setting up a project for the fi
47
47
  | `void db seed` | Reset + seed local database |
48
48
  | `void db execute <sql>` | Run SQL against the database (--remote for deployed) |
49
49
  | `void db studio` | Open Drizzle Studio (--remote for a deployed external database) |
50
+ | `void db restore --bookmark <b>` | Restore the deployed D1 database to a restore point (direct Cloudflare) |
50
51
  | `void secret put <name=value>` | Set a production secret |
51
52
  | `void secret list` | List production secrets |
52
53
  | `void secret sync <file>` | Bulk upload secrets from dotenv file |
@@ -512,7 +512,7 @@ Each binding accepts `true` (use default name), `false` (disable), or a string (
512
512
 
513
513
  Custom binding names work with `void/db`, `void/kv`, and `void/storage` during development and deployment. Custom AI names also work with `void/ai` on direct Cloudflare deploys; managed Workers AI uses the platform's proxy.
514
514
 
515
- `email` is a boolean feature switch. Set it to `true` to enable [email](../guide/email.md) and the `void dev` inbox without an import from `void/email`, or `false` to disable them. On a Void platform, sending uses the platform proxy. Direct Cloudflare setup records a `SEND_EMAIL` binding in `void.lock.json`; see [`email.from`](#email).
515
+ `email` is a boolean feature switch. Set it to `true` to enable [email](../guide/email.md) and the local email inbox without an import from `void/email`, or `false` to disable them. On a Void platform, sending uses the platform proxy. Direct Cloudflare setup records a `SEND_EMAIL` binding in `void.lock.json`; see [`email.from`](#email).
516
516
 
517
517
  #### `inference.build`
518
518
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "void",
3
- "version": "1.1.11",
3
+ "version": "1.1.12",
4
4
  "description": "Full-stack framework and deployment CLI for Cloudflare Workers, powered by Vite.",
5
5
  "homepage": "https://void.cloud",
6
6
  "bugs": {
@@ -37,6 +37,7 @@
37
37
  "#self/sandbox": "./dist/runtime/sandbox.mjs",
38
38
  "#self/runtime/live-server": "./dist/runtime/live-server.mjs",
39
39
  "#self/runtime/fetch": "./dist/runtime/fetch.mjs",
40
+ "#self/runtime/fetch-server": "./dist/runtime/fetch-server.mjs",
40
41
  "#self/runtime/fetch-stream": "./dist/runtime/fetch-stream.mjs",
41
42
  "#self/runtime/route-url": "./dist/runtime/route-url.mjs",
42
43
  "#self/runtime/migration-handler": "./dist/runtime/migration-handler.mjs",
@@ -347,11 +348,11 @@
347
348
  "@cloudflare/workers-auth": "^0.14.0",
348
349
  "@cloudflare/workers-types": "^5.20261014.1",
349
350
  "@napi-rs/keyring": "^2.1.1",
350
- "@void/deploy-cloudflare": "1.1.11",
351
- "@void/deploy-core": "1.1.11",
352
- "@void/edge": "1.1.11",
353
- "@void/isr": "1.1.11",
354
- "@void/platform": "1.1.11",
351
+ "@void/deploy-cloudflare": "1.1.12",
352
+ "@void/deploy-core": "1.1.12",
353
+ "@void/edge": "1.1.12",
354
+ "@void/isr": "1.1.12",
355
+ "@void/platform": "1.1.12",
355
356
  "better-auth": "^1.7.7",
356
357
  "better-sqlite3": "^13.0.3",
357
358
  "blake3-jit": "^1.1.0",
@@ -400,7 +401,7 @@
400
401
  "zod": "^4.6.7"
401
402
  },
402
403
  "peerDependencies": {
403
- "@void/md": "1.1.11",
404
+ "@void/md": "1.1.12",
404
405
  "arktype": ">=2.0.0",
405
406
  "valibot": ">=1.0.0-beta.7",
406
407
  "vite": "^8.0.0",
@@ -1 +0,0 @@
1
- export { t as prepareCfBuildOutput } from "./cf-build-output-Bc8i3dzE.mjs";
@@ -1 +0,0 @@
1
- export { r as PlatformClient } from "./client-GuSO3v_x.mjs";
@@ -1,2 +0,0 @@
1
- import "./deploy-transport-nY3vLXPL.mjs";
2
- export { i as checkWranglerMigrationApplySet, t as parseRootWranglerConfig, r as runDeploy } from "./deploy-DsW-PrRQ.mjs";