void 1.2.1 → 1.4.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 (200) hide show
  1. package/dist/{account-cmd-CdUll_35.mjs → account-cmd-HP8bixYo.mjs} +3 -3
  2. package/dist/{application-analysis-fEqoSeMp.mjs → application-analysis-DDOQwiXk.mjs} +18 -12
  3. package/dist/{application-routing-DAhNP4u3.mjs → application-routing-4719u_kf.mjs} +3 -1
  4. package/dist/auth-g2TQbDLD.d.mts +70 -0
  5. package/dist/{auth-link-C87vGXM-.mjs → auth-link-CedYpDCy.mjs} +3 -3
  6. package/dist/{auth-router-6I81r-ix.mjs → auth-router-vafo7x8w.mjs} +11 -6
  7. package/dist/{better-auth-shared-D-6z0q0f.mjs → better-auth-shared-7FM3Uk2N.mjs} +48 -2
  8. package/dist/{better-auth-shared-DVk2DkTW.d.mts → better-auth-shared-BHB8kiTE.d.mts} +1 -1
  9. package/dist/{build-cmd-ex1g-j_e.mjs → build-cmd-9vUAQ1_V.mjs} +1 -1
  10. package/dist/{cache-oHzrnY3z.mjs → cache-jvwLNb0h.mjs} +1 -1
  11. package/dist/{cancel-deploy-viAMD0Q_.mjs → cancel-deploy-Dw0UmWKO.mjs} +1 -1
  12. package/dist/{cf-build-output-BhVxldCw.mjs → cf-build-output-XpNR9zoh.mjs} +122 -5
  13. package/dist/cf-build-output-bd8Uwv1P.mjs +1 -0
  14. package/dist/{cf-worker-settings-BECvvTVd.mjs → cf-worker-settings-Dg27RzyT.mjs} +11 -5
  15. package/dist/cli/cli.mjs +41 -32
  16. package/dist/cli/cloudflare-operation-process.mjs +35 -8
  17. package/dist/cli/env-schema-probe.mjs +2 -2
  18. package/dist/{client-BEkdj1kx.mjs → client-B3LnB_bE.mjs} +8 -1
  19. package/dist/client-BZb9j66F.mjs +1 -0
  20. package/dist/{cloudflare-auth-Byo_0_N9.mjs → cloudflare-auth-DyD_kVFr.mjs} +1 -1
  21. package/dist/{cloudflare-cmd-DMzCv12s.mjs → cloudflare-cmd-D-b_u3T4.mjs} +2 -2
  22. package/dist/{cloudflare-config-DchHxPTo.mjs → cloudflare-config-CH1AylZT.mjs} +14 -3
  23. package/dist/{cloudflare-connect-CCRTVg-I.mjs → cloudflare-connect-zTJh8UnN.mjs} +2 -2
  24. package/dist/{cloudflare-operations-Dh9dEHJj.mjs → cloudflare-operations-Bc-7fN44.mjs} +4 -4
  25. package/dist/{cloudflare-operations-DsSaw2BT.mjs → cloudflare-operations-BtulCNOg.mjs} +1 -1
  26. package/dist/{config-BU6hMu1W.mjs → config-BV2ASlpn.mjs} +1 -1
  27. package/dist/{config-DQfHOKh9.d.mts → config-CAdZVTLN.d.mts} +4 -1
  28. package/dist/config-D-6q7EBH.mjs +87 -0
  29. package/dist/{config-DHgSEWT7.mjs → config-OFOAimzt.mjs} +5 -3
  30. package/dist/config-entry.d.mts +1 -1
  31. package/dist/{config-BIaXIkkv.mjs → config-tqMM6DwY.mjs} +1 -1
  32. package/dist/{connect-k7R2rPVA.mjs → connect-BOM6zvFX.mjs} +4 -4
  33. package/dist/{create-project-DV71ol5d.mjs → create-project-Bxd02EHN.mjs} +1 -1
  34. package/dist/{create-project-DTuy-l0z.mjs → create-project-C2K0DN2O.mjs} +1 -1
  35. package/dist/{db-DVOkLH5X.mjs → db-Cdvr3zwG.mjs} +18 -18
  36. package/dist/{db-types-NGxPwnlt.mjs → db-types-0eCiqYb1.mjs} +1 -1
  37. package/dist/{delete-BbP5eopu.mjs → delete-lETE6Tpt.mjs} +1 -1
  38. package/dist/deploy-CX94CmKa.mjs +2 -0
  39. package/dist/{deploy-7H32EnUs.mjs → deploy-CdM-LAxX.mjs} +473 -148
  40. package/dist/{deploy-managed-static-DlvcvnQT.mjs → deploy-managed-static-DjeBFG2c.mjs} +43 -20
  41. package/dist/{deploy-transport-BzGEj0Ge.mjs → deploy-transport-DIq_gFTP.mjs} +14 -13
  42. package/dist/deploy.d.mts +2 -0
  43. package/dist/deploy.mjs +8 -5
  44. package/dist/{dispatch-DoUnxTNo.mjs → dispatch-CLa2LThw.mjs} +76 -7
  45. package/dist/{domain-CA2wBgra.mjs → domain-DyhNtdYf.mjs} +2 -2
  46. package/dist/{email-DXpCc77w.mjs → email-DM2wDcBN.mjs} +59 -10
  47. package/dist/{email-cloudflare-D03g2TkS.mjs → email-cloudflare-PMbAev9Q.mjs} +124 -10
  48. package/dist/{env-DgOQ9_8S.mjs → env-78hbN-oI.mjs} +3 -3
  49. package/dist/{env-BJjULvL0.mjs → env-BaMz0j7H.mjs} +6 -1
  50. package/dist/{env-validation-Dwq3PJzK.mjs → env-validation-B3VobvXm.mjs} +2 -1
  51. package/dist/{env-validation-BmsdCZEk.mjs → env-validation-BUfFZ6bt.mjs} +1 -1
  52. package/dist/error-pages-CLIJ7aYq.mjs +37 -0
  53. package/dist/gen-BhWBT4iu.mjs +1 -0
  54. package/dist/{gen-BfmcIi2g.mjs → gen-CFmsUsW1.mjs} +3 -3
  55. package/dist/{github-cmd-CY9LUqLh.mjs → github-cmd-De-_IWbM.mjs} +1 -1
  56. package/dist/{handler-BbkSPzGF.d.mts → handler-BHktmuTL.d.mts} +4 -2
  57. package/dist/{headers-D522zd0A.mjs → headers--vaK_chu.mjs} +1 -1
  58. package/dist/{help-CxSlPpzJ.mjs → help-CKbrhZha.mjs} +16 -1
  59. package/dist/help-qOZr3wng.mjs +1 -0
  60. package/dist/index.d.mts +3 -5
  61. package/dist/index.mjs +370 -140
  62. package/dist/{info-7VDlhtyy.mjs → info-Yg0-V5Rs.mjs} +4 -4
  63. package/dist/{init-DxYyOs4-.mjs → init-CDiJQycf.mjs} +241 -206
  64. package/dist/{link-Ddmod1dZ.mjs → link-Dllip08S.mjs} +2 -2
  65. package/dist/{list-MogaugiO.mjs → list-BYRP6am0.mjs} +2 -2
  66. package/dist/{live-Bt8Y_0bg.d.mts → live-BllfDuzA.d.mts} +2 -2
  67. package/dist/{local-d1-BHBnKWRb.mjs → local-d1-CAwAs9GH.mjs} +1 -1
  68. package/dist/login-BAPmYnb7.mjs +1 -0
  69. package/dist/{login-Cttnagmm.mjs → login-PcFy5mlC.mjs} +2 -2
  70. package/dist/{logs-CAszUWZI.mjs → logs-DmJTBhed.mjs} +2 -2
  71. package/dist/{migrate-DyT2jJ8y.mjs → migrate-B8S2xTcb.mjs} +5 -66
  72. package/dist/migrate-BIYTPQE6.mjs +1 -0
  73. package/dist/nitro.mjs +4 -4
  74. package/dist/{node-WB7c2N4L.mjs → node-CDOPrGSl.mjs} +5 -5
  75. package/dist/{operator-args-UnE8Y2eK.mjs → operator-args-BsJIYXaT.mjs} +8 -1
  76. package/dist/operator-cmd-CjazwOyb.mjs +1 -0
  77. package/dist/{operator-cmd-skshjMGl.mjs → operator-cmd-DmkmS2wL.mjs} +4 -3
  78. package/dist/pages/client.d.mts +32 -4
  79. package/dist/pages/client.mjs +186 -29
  80. package/dist/pages/index.d.mts +34 -2
  81. package/dist/pages/index.mjs +96 -55
  82. package/dist/pages/islands-plugin.d.mts +1 -1
  83. package/dist/pages/islands-plugin.mjs +9 -3
  84. package/dist/pages/protocol.d.mts +2 -2
  85. package/dist/platform-args-BC8_hsDj.mjs +1 -0
  86. package/dist/{platform-args-DVbVClZl.mjs → platform-args-BMD2gjc_.mjs} +1 -1
  87. package/dist/{platform-auth-config-C-pm5Qzx.mjs → platform-auth-config-CImnfohz.mjs} +3 -3
  88. package/dist/{platform-auth-protection-SHhvim1L.mjs → platform-auth-protection-BogLhtHi.mjs} +2 -2
  89. package/dist/{platform-auth-recovery-DXVWs-wA.mjs → platform-auth-recovery-B-mEaWEi.mjs} +2 -2
  90. package/dist/{platform-cmd-PiNRkopU.mjs → platform-cmd-CV8NxIIn.mjs} +1 -1
  91. package/dist/{platform-cmd-D5I1beUX.mjs → platform-cmd-DZK2ixMl.mjs} +4 -4
  92. package/dist/{platform-domain-jpmBfZeb.mjs → platform-domain-CRvelPGE.mjs} +2 -2
  93. package/dist/{platform-lifecycle-DyKmuNY6.mjs → platform-lifecycle-CPYY7E9B.mjs} +103 -41
  94. package/dist/{platform-lifecycle-DH3Yr1qQ.mjs → platform-lifecycle-DwXq7kZt.mjs} +1 -1
  95. package/dist/{platform-management--vDwSn35.mjs → platform-management-BOnGbMSM.mjs} +1 -1
  96. package/dist/{platform-management-7m-PLaPJ.mjs → platform-management-lXdgGgAM.mjs} +1 -1
  97. package/dist/{platform-recovery-BiNpZZab.mjs → platform-recovery-noaALXnE.mjs} +2 -2
  98. package/dist/{plugin-inference-DUjCd55H.mjs → plugin-inference-CeiB6BG5.mjs} +53 -18
  99. package/dist/{prepare-BcAE5Sdj.mjs → prepare-BuOS18AM.mjs} +1 -1
  100. package/dist/{prepare-DA-17DhO.mjs → prepare-D604Yiyr.mjs} +12 -8
  101. package/dist/prepare-DU-tOpS5.mjs +1 -0
  102. package/dist/{prerender-render-Cijv7UFo.mjs → prerender-render-CaShbHJ3.mjs} +13 -1
  103. package/dist/prerender-render.d.mts +1 -0
  104. package/dist/prerender-render.mjs +1 -1
  105. package/dist/{project-cmd-DA4K5faU.mjs → project-cmd-DBYqAIbe.mjs} +15 -15
  106. package/dist/{project-team-CQBNveX3.mjs → project-team-BjCLgTRC.mjs} +1 -1
  107. package/dist/{project-token-CCalFyQf.mjs → project-token-BB6PwaA9.mjs} +1 -1
  108. package/dist/{project-tsconfig-Itv1f4WC.mjs → project-tsconfig-CVvk6Z_e.mjs} +24 -2
  109. package/dist/{project-zero-trust-DPnkiEuT.mjs → project-zero-trust-CWDh1P_t.mjs} +1 -1
  110. package/dist/{protocol-BBDpJz3G.d.mts → protocol-D5XDySYu.d.mts} +2 -2
  111. package/dist/{provision-BFLCrnUp.mjs → provision-DfxLCg-d.mjs} +1 -1
  112. package/dist/{provision-DtROpNNI.mjs → provision-DztLJ97X.mjs} +24 -8
  113. package/dist/{requests-BpH0kImL.mjs → requests-D_pbzDyz.mjs} +1 -1
  114. package/dist/{rollback-CXS1tAa-.mjs → rollback-CjfIYsJx.mjs} +2 -2
  115. package/dist/{route-types-BZi26DVS.mjs → route-types-DvEGmPif.mjs} +109 -30
  116. package/dist/routes-stub.d.mts +22 -13
  117. package/dist/runtime/auth.d.mts +2 -2
  118. package/dist/runtime/better-auth-mysql.d.mts +1 -1
  119. package/dist/runtime/better-auth-mysql.mjs +1 -1
  120. package/dist/runtime/better-auth-pg.d.mts +1 -1
  121. package/dist/runtime/better-auth-pg.mjs +1 -1
  122. package/dist/runtime/better-auth.d.mts +1 -1
  123. package/dist/runtime/better-auth.mjs +1 -1
  124. package/dist/runtime/client-react.d.mts +1 -1
  125. package/dist/runtime/client-solid.d.mts +1 -1
  126. package/dist/runtime/client-svelte.d.mts +1 -1
  127. package/dist/runtime/client-vue.d.mts +1 -1
  128. package/dist/runtime/client.d.mts +1 -1
  129. package/dist/runtime/handler.d.mts +1 -1
  130. package/dist/runtime/live-client.d.mts +1 -1
  131. package/dist/runtime/live.d.mts +1 -1
  132. package/dist/runtime/log.mjs +19 -1
  133. package/dist/runtime/routing.d.mts +5 -4
  134. package/dist/runtime/routing.mjs +14 -73
  135. package/dist/runtime/validator.d.mts +1 -1
  136. package/dist/runtime/ws-server.d.mts +3 -3
  137. package/dist/runtime/ws.d.mts +1 -1
  138. package/dist/runtime/ws.mjs +4 -2
  139. package/dist/{scan-8IzYXiU_.mjs → scan-N9WzdcAl.mjs} +302 -23
  140. package/dist/{secret-BbXHfLAt.mjs → secret-3X0PxmuX.mjs} +9 -12
  141. package/dist/static-asset-marker-Btf-6oCD.mjs +32 -0
  142. package/dist/{types-7AIz0OZu.d.mts → types-w72dljaA.d.mts} +6 -1
  143. package/dist/{version-metadata-tS39iW09.mjs → version-metadata-D2vfMQzv.mjs} +2 -1
  144. package/dist/worker-conditions-AWFRcFxR.mjs +11 -0
  145. package/dist/{wrangler-F96NnLyb.mjs → wrangler-I-scB_1t.mjs} +82 -13
  146. package/dist/wrangler-UnwdISay.mjs +1 -0
  147. package/dist/{wrapper-D3sZyh2C.mjs → wrapper-BBl1rC32.mjs} +8 -12
  148. package/dist/{ws-BH-im_tX.d.mts → ws-B3ClMVDh.d.mts} +3 -2
  149. package/docs/guide/auth.md +4 -2
  150. package/docs/guide/edge/redirects.md +22 -0
  151. package/docs/guide/edge/static-assets.md +10 -0
  152. package/docs/guide/email/domains.md +1 -1
  153. package/docs/guide/email/receiving.md +2 -0
  154. package/docs/guide/email/sending.md +1 -1
  155. package/docs/guide/pages-routing/actions-and-forms.md +43 -13
  156. package/docs/guide/pages-routing/markdown.md +2 -0
  157. package/docs/guide/pages-routing/overview.md +33 -2
  158. package/docs/guide/platform/administration/email.md +18 -0
  159. package/docs/guide/platform/installation/maintenance.md +3 -1
  160. package/docs/guide/platform/installation/prerequisites.md +9 -4
  161. package/docs/guide/platform/installation/uninstall.md +2 -0
  162. package/docs/guide/queues.md +13 -1
  163. package/docs/guide/server-routing.md +40 -2
  164. package/docs/guide/ssg.md +8 -0
  165. package/docs/guide/type-safety.md +7 -7
  166. package/docs/guide/websockets.md +4 -2
  167. package/docs/integrations/cloudflare.md +16 -7
  168. package/docs/reference/api/auth.md +6 -2
  169. package/docs/reference/api/deploy.md +9 -5
  170. package/docs/reference/api/pages.md +6 -4
  171. package/docs/reference/cli/deploy.md +10 -9
  172. package/docs/reference/cli/email.md +13 -0
  173. package/docs/reference/cli/platform-email.md +2 -2
  174. package/docs/reference/cli.md +1 -0
  175. package/docs/reference/config.md +11 -1
  176. package/docs/reference/structure.md +3 -1
  177. package/package.json +9 -7
  178. package/schema.json +4 -0
  179. package/skills/void/SKILL.md +1 -1
  180. package/templates/assets/icons.svg +49 -0
  181. package/templates/assets/react.svg +1 -0
  182. package/templates/assets/solid.svg +1 -0
  183. package/templates/assets/stack.svg +35 -0
  184. package/templates/assets/svelte.svg +1 -0
  185. package/templates/assets/void.svg +5 -0
  186. package/templates/assets/vue.svg +1 -0
  187. package/dist/auth-DkcFflXV.d.mts +0 -42
  188. package/dist/cf-build-output-BJHuSsVN.mjs +0 -1
  189. package/dist/client-BiRDZTSd.mjs +0 -1
  190. package/dist/config-CyUJzi3q.mjs +0 -32
  191. package/dist/deploy-CE0Ev0Ob.mjs +0 -2
  192. package/dist/gen-NrOlWZaG.mjs +0 -1
  193. package/dist/help-BeAFFE5C.mjs +0 -1
  194. package/dist/login-DgDwlKc_.mjs +0 -1
  195. package/dist/migrate-n49ZeS1X.mjs +0 -1
  196. package/dist/operator-cmd-d2MvJOrl.mjs +0 -1
  197. package/dist/parse-filename-DioPHiR9.mjs +0 -77
  198. package/dist/platform-args-kQrgxScY.mjs +0 -1
  199. package/dist/prepare-C4I0f--h.mjs +0 -1
  200. package/dist/wrangler-BLb3_luP.mjs +0 -1
@@ -1,6 +1,6 @@
1
1
  import { a as getApiUrl, c as getToken, f as removeToken, l as getTokenSource, m as savePlatformToken, p as runPlatformLogin } from "./auth-B6iOCjKI.mjs";
2
2
  import { H as outro, K as select, L as log, O as cancel, tt as isCancel } from "./dist-Cor9XGoz.mjs";
3
- import { a as isExpiredTokenError, r as PlatformClient } from "./client-BEkdj1kx.mjs";
3
+ import { a as isExpiredTokenError, r as PlatformClient } from "./client-B3LnB_bE.mjs";
4
4
  import { f as import_picocolors, l as formatUrl, m as printSuccess, r as createSpinner } from "./output-BpgYODYx.mjs";
5
5
  //#region src/cli/login.ts
6
6
  async function selectPlatformLoginMethod(platform, requestedId) {
@@ -30,7 +30,7 @@ async function selectPlatformLoginMethod(platform, requestedId) {
30
30
  }
31
31
  async function promptForLoginToken(root = process.cwd(), platform) {
32
32
  const apiUrl = platform?.apiUrl ?? getApiUrl(root);
33
- const { id: provider, label: providerName } = await selectPlatformLoginMethod(platform ?? await (await import("./platform-cmd-PiNRkopU.mjs")).discoverPlatform(apiUrl));
33
+ const { id: provider, label: providerName } = await selectPlatformLoginMethod(platform ?? await (await import("./platform-cmd-CV8NxIIn.mjs")).discoverPlatform(apiUrl));
34
34
  const s = createSpinner();
35
35
  s.start(`Opening browser for ${providerName} login...`);
36
36
  try {
@@ -1,7 +1,7 @@
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 { $ as wrapTextWithPrefix, H as outro, L as log } from "./dist-Cor9XGoz.mjs";
4
- import { r as PlatformClient } from "./client-BEkdj1kx.mjs";
4
+ import { r as PlatformClient } from "./client-B3LnB_bE.mjs";
5
5
  import { a as errorStackFrames, f as import_picocolors, i as dim, o as formatCount } from "./output-BpgYODYx.mjs";
6
6
  import { t as sanitizeTerminalLogText } from "./terminal-log-text-D9ACPOuG.mjs";
7
7
  //#region src/cli/logs.ts
@@ -9,7 +9,7 @@ async function runLogsCommand(root, filter, range, deployment, level) {
9
9
  console.log();
10
10
  const platform = readDeploymentPlatform(root);
11
11
  if (platform === "cloudflare") {
12
- const { resolveCloudflareOperationContext, tailCloudflareWorker } = await import("./cloudflare-operations-DsSaw2BT.mjs");
12
+ const { resolveCloudflareOperationContext, tailCloudflareWorker } = await import("./cloudflare-operations-BtulCNOg.mjs");
13
13
  if (range !== "1h") log.warn("Cloudflare tail streams live logs; --range does not select historical entries.");
14
14
  if (level && level !== "all" && level !== "error") log.warn("Cloudflare tail cannot filter individual console levels; showing all invocation logs.");
15
15
  await tailCloudflareWorker(resolveCloudflareOperationContext(root), {
@@ -1,9 +1,9 @@
1
1
  import { a as join, n as dirname } from "./dist-ipQi0Q8y.mjs";
2
2
  import { o as TYPED_CONFIG_FILE, s as loadTypedVoidConfigFile } from "./project-paths-DGu_QZ_Q.mjs";
3
- import { h as validateConfig } from "./config-DHgSEWT7.mjs";
3
+ import { h as validateConfig } from "./config-OFOAimzt.mjs";
4
4
  import { t as parseJsoncObject } from "./generated-wrangler-config-DeWj5F9Y.mjs";
5
- import { n as VOID_LOCK_FILE, o as seedCloudflareConfig, s as stashCloudflareDeployPointer } from "./cloudflare-config-DchHxPTo.mjs";
6
- import "./wrangler-F96NnLyb.mjs";
5
+ import { c as stashCloudflareDeployPointer, n as VOID_LOCK_FILE, r as ignoreMaterializedCloudflareConfig, s as seedCloudflareConfig } from "./cloudflare-config-CH1AylZT.mjs";
6
+ import { I as renderVoidConfig, P as GENERATED_MARKERS } from "./wrangler-I-scB_1t.mjs";
7
7
  import { L as log } from "./dist-Cor9XGoz.mjs";
8
8
  import { m as printSuccess } from "./output-BpgYODYx.mjs";
9
9
  import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, unlinkSync, writeFileSync } from "node:fs";
@@ -198,61 +198,6 @@ function migrateFrameworkAdapterPaths(root) {
198
198
  return applyFrameworkConfigMigration(root, planFrameworkConfigMigration(root));
199
199
  }
200
200
  //#endregion
201
- //#region src/config-write.ts
202
- const GENERATED_MARKERS = [
203
- "// Generated by void migrate.",
204
- "// Generated from void.json by void migrate.",
205
- "// Generated by void init."
206
- ];
207
- function renderVoidConfig(config, marker = GENERATED_MARKERS[0]) {
208
- return `${marker}\nimport { defineConfig } from 'void/config';\n\nexport default defineConfig(${JSON.stringify(config, null, 2)});\n`;
209
- }
210
- function isStaticValue(node) {
211
- if (!node) return false;
212
- if (node.type === "Literal") return node.value === null || [
213
- "string",
214
- "number",
215
- "boolean"
216
- ].includes(typeof node.value);
217
- if (node.type === "UnaryExpression") return node.operator === "-" && node.argument?.type === "Literal" && typeof node.argument.value === "number";
218
- if (node.type === "ArrayExpression") return node.elements?.every(isStaticValue) ?? false;
219
- if (node.type !== "ObjectExpression") return false;
220
- return node.properties?.every((property) => property.type === "Property" && property.kind === "init" && !property.computed && !property.method && (property.key?.type === "Identifier" || property.key?.type === "Literal") && isStaticValue(property.value)) ?? false;
221
- }
222
- function isGeneratedStaticConfig(source) {
223
- if (!GENERATED_MARKERS.some((marker) => source.startsWith(marker))) return false;
224
- let program;
225
- try {
226
- const parsed = parseSync(TYPED_CONFIG_FILE, source, {
227
- lang: "js",
228
- sourceType: "module",
229
- preserveParens: false,
230
- showSemanticErrors: true
231
- });
232
- if (parsed.errors.length > 0 || parsed.comments.length !== 1 || !GENERATED_MARKERS.includes(`// ${parsed.comments[0]?.value.trim()}`)) return false;
233
- program = parsed.program;
234
- } catch {
235
- return false;
236
- }
237
- const [importDeclaration, exportDeclaration] = program.body ?? [];
238
- const call = exportDeclaration?.declaration;
239
- return program.body?.length === 2 && importDeclaration?.type === "ImportDeclaration" && importDeclaration.source?.value === "void/config" && importDeclaration.specifiers?.length === 1 && importDeclaration.specifiers[0]?.imported?.name === "defineConfig" && importDeclaration.specifiers[0]?.local?.name === "defineConfig" && exportDeclaration?.type === "ExportDefaultDeclaration" && call?.type === "CallExpression" && call.callee?.name === "defineConfig" && call.arguments?.length === 1 && isStaticValue(call.arguments[0]);
240
- }
241
- function canRewriteVoidProjectConfig(root) {
242
- const path = join(root, TYPED_CONFIG_FILE);
243
- return !existsSync(path) || isGeneratedStaticConfig(readFileSync(path, "utf8"));
244
- }
245
- /** Update CLI-owned static config without silently rewriting authored TypeScript. */
246
- function writeVoidProjectConfig(root, config) {
247
- validateConfig(config, TYPED_CONFIG_FILE);
248
- const path = join(root, TYPED_CONFIG_FILE);
249
- if (existsSync(path)) {
250
- if (!isGeneratedStaticConfig(readFileSync(path, "utf8"))) throw new Error(`config: ${TYPED_CONFIG_FILE} contains authored TypeScript or comments. Update it directly and rerun the command.`);
251
- validateConfig(loadTypedVoidConfigFile(path), TYPED_CONFIG_FILE);
252
- }
253
- writeFileSync(path, renderVoidConfig(config, "// Generated by void init."));
254
- }
255
- //#endregion
256
201
  //#region src/cli/migrate.ts
257
202
  const LEGACY_FILE = "void.json";
258
203
  function parseWranglerJsonc(path, raw) {
@@ -291,12 +236,6 @@ function isOrphanedCompatibilityConfig(root, legacy, typed) {
291
236
  return false;
292
237
  }
293
238
  }
294
- function ignoreGeneratedCloudflareConfig(root) {
295
- const path = join(root, ".gitignore");
296
- const source = existsSync(path) ? readFileSync(path, "utf8") : "";
297
- if (source.split(/\r?\n/).some((line) => /^\/?\.void-wrangler\.jsonc$/.test(line.trim()))) return;
298
- writeFileSync(path, `${source}${source && !source.endsWith("\n") ? "\n" : ""}.void-wrangler.jsonc\n`);
299
- }
300
239
  /** Move Void and Cloudflare JSON/JSONC settings into a typed, checked-in project config. */
301
240
  function migrateLegacyVoidConfig(root) {
302
241
  const legacyPath = join(root, LEGACY_FILE);
@@ -353,7 +292,7 @@ function migrateLegacyVoidConfig(root) {
353
292
  applyFrameworkConfigMigration(root, frameworkPatches);
354
293
  if (raw !== void 0) unlinkSync(legacyPath);
355
294
  if (wranglerName) unlinkSync(join(root, wranglerName));
356
- ignoreGeneratedCloudflareConfig(root);
295
+ ignoreMaterializedCloudflareConfig(root);
357
296
  stashCloudflareDeployPointer(root);
358
297
  return true;
359
298
  } finally {
@@ -368,4 +307,4 @@ async function runMigrateCommand(root) {
368
307
  } else log.info("No legacy project configuration found.");
369
308
  }
370
309
  //#endregion
371
- export { discoverFrameworkWranglerFiles as a, writeVoidProjectConfig as i, runMigrateCommand as n, migrateFrameworkAdapterPaths as o, canRewriteVoidProjectConfig as r, migrateLegacyVoidConfig as t };
310
+ export { migrateFrameworkAdapterPaths as i, runMigrateCommand as n, discoverFrameworkWranglerFiles as r, migrateLegacyVoidConfig as t };
@@ -0,0 +1 @@
1
+ export { n as runMigrateCommand } from "./migrate-B8S2xTcb.mjs";
package/dist/nitro.mjs CHANGED
@@ -1,9 +1,9 @@
1
1
  import { a as join, n as dirname } from "./dist-ipQi0Q8y.mjs";
2
- import { l as getDatabaseDialect, p as readConfig } from "./config-DHgSEWT7.mjs";
3
- import { r as voidDbBundlerPlugin } from "./dispatch-DoUnxTNo.mjs";
4
- import { n as bundleWorkerSqlDriver } from "./wrapper-D3sZyh2C.mjs";
5
- import { fileURLToPath } from "node:url";
2
+ import { l as getDatabaseDialect, p as readConfig } from "./config-OFOAimzt.mjs";
3
+ import { c as voidDbBundlerPlugin } from "./dispatch-CLa2LThw.mjs";
4
+ import { n as bundleWorkerSqlDriver } from "./wrapper-BBl1rC32.mjs";
6
5
  import { normalizePath } from "vite";
6
+ import { fileURLToPath } from "node:url";
7
7
  import { resolve } from "node:path/win32";
8
8
  //#region src/nitro.ts
9
9
  const envModuleFile = fileURLToPath(import.meta.resolve("#self/_env"));
@@ -1,14 +1,14 @@
1
1
  import { n as dirname } from "./dist-ipQi0Q8y.mjs";
2
- import { n as loadVoidAuthConfig, t as findVoidAuthConfig } from "./config-CyUJzi3q.mjs";
3
- import { p as readConfig } from "./config-DHgSEWT7.mjs";
2
+ import { a as projectAuthConfigImporter, i as loadVoidAuthConfig, r as findVoidAuthConfig } from "./config-D-6q7EBH.mjs";
3
+ import { p as readConfig } from "./config-OFOAimzt.mjs";
4
4
  import { r as getMiniflareDatabasePath } from "./runner-3uGC-oLF.mjs";
5
- import { o as loadLocalEnv } from "./env-BJjULvL0.mjs";
5
+ import { s as loadLocalEnv } from "./env-BaMz0j7H.mjs";
6
6
  import { a as pgMigrationRunner, i as mysqlMigrationRunner, n as applyPgAuthMigrations, r as applySqliteAuthMigrations, t as applyMySqlAuthMigrations } from "./auth-migrations-BO27GDNr.mjs";
7
7
  import { r as resolveVoidAuthMigrationSchema } from "./drizzle-BQfyvQKX.mjs";
8
8
  import { mkdirSync } from "node:fs";
9
9
  //#region src/auth/node.ts
10
- async function runLocalVoidAuthMigrations(root, dialect, persistRoot, databaseId, configPath = findVoidAuthConfig(root), databaseUrl) {
11
- const authConfig = await loadVoidAuthConfig(configPath);
10
+ async function runLocalVoidAuthMigrations(root, dialect, persistRoot, databaseId, configPath = findVoidAuthConfig(root), databaseUrl, importModule) {
11
+ const authConfig = await loadVoidAuthConfig(configPath, importModule ?? projectAuthConfigImporter(root));
12
12
  const runtime = {
13
13
  dialect,
14
14
  providers: readConfig(root).auth?.providers ?? null,
@@ -488,7 +488,10 @@ const operatorCommands = [
488
488
  path: "/email/domains",
489
489
  positional: ["domain"],
490
490
  values: { project: "Project id or slug" },
491
- booleans: { "token-stdin": "Read a scoped Cloudflare API token from stdin" },
491
+ booleans: {
492
+ "token-stdin": "Read a scoped Cloudflare API token from stdin",
493
+ "outbound-only": "Send only; leave the MX records and inbound mail with the current provider"
494
+ },
492
495
  method: "POST"
493
496
  },
494
497
  {
@@ -701,6 +704,10 @@ function parseOperatorArgs(args) {
701
704
  if (flags.has("check")) parsed.query.check = "true";
702
705
  } else if (group === "zero-trust" && action === "project-protect") parsed.body.protected = true;
703
706
  else if (group === "zero-trust" && action === "project-public") parsed.body.protected = false;
707
+ else if (group === "email" && action === "domain-add" && flags.has("outbound-only")) {
708
+ delete parsed.body["outbound-only"];
709
+ parsed.body.outboundOnly = true;
710
+ }
704
711
  return parsed;
705
712
  }
706
713
  //#endregion
@@ -0,0 +1 @@
1
+ export { a as runOperatorCommand } from "./operator-cmd-DmkmS2wL.mjs";
@@ -163,8 +163,8 @@ async function runAuth(origin, args) {
163
163
  if (args.action === "login" || args.action === "token" && args.tokenStdin) {
164
164
  if (!args.tokenStdin && !process.stdin.isTTY) throw new OperatorClientError("Browser login requires an interactive terminal. Use --token-stdin to exchange an API session.", "interactive_login_required");
165
165
  const apiToken = args.tokenStdin ? await readOperatorApiTokenStdin() : await (async () => {
166
- const { discoverPlatform } = await import("./platform-cmd-PiNRkopU.mjs");
167
- const { selectPlatformLoginMethod } = await import("./login-DgDwlKc_.mjs");
166
+ const { discoverPlatform } = await import("./platform-cmd-CV8NxIIn.mjs");
167
+ const { selectPlatformLoginMethod } = await import("./login-BAPmYnb7.mjs");
168
168
  const { runPlatformLogin } = await import("./auth-Cbqi1iVX.mjs");
169
169
  return runPlatformLogin(origin, (await selectPlatformLoginMethod(await discoverPlatform(origin), args.provider)).id, (url) => process.stderr.write(`Sign in at ${url}\n`));
170
170
  })();
@@ -344,7 +344,7 @@ async function migrateDeploymentAssets(client, origin, args) {
344
344
  }
345
345
  async function runOperatorCommand(args) {
346
346
  if (!args.action) {
347
- const { printHelpPage } = await import("./help-BeAFFE5C.mjs");
347
+ const { printHelpPage } = await import("./help-qOZr3wng.mjs");
348
348
  printHelpPage(["platform", args.group]);
349
349
  return;
350
350
  }
@@ -376,6 +376,7 @@ async function runOperatorCommand(args) {
376
376
  if (!target || typeof target.recoveryFence !== "string" || !/^[a-f0-9]{64}$/.test(target.recoveryFence)) throw new OperatorClientError("The server did not return a valid shared recipient recovery fence. No change was requested.", "invalid_preview");
377
377
  recoveryFence = { recoveryFence: target.recoveryFence };
378
378
  }
379
+ if (args.group === "email" && args.action === "domain-add" && args.body.outboundOnly === true && preview.target?.inboundMode !== "none") throw new OperatorClientError("This platform does not support outbound-only email domains. Upgrade it first. No change was requested.", "unsupported");
379
380
  if (!await confirmOperatorMutation(origin, preview, args)) return;
380
381
  const body = {
381
382
  ...args.body,
@@ -1,5 +1,5 @@
1
1
  import { t as interpolateRouteParams } from "../route-url-BgPja1GS.mjs";
2
- import { t as PageObject } from "../protocol-BBDpJz3G.mjs";
2
+ import { t as PageObject } from "../protocol-D5XDySYu.mjs";
3
3
  import { n as CacheForInput, r as CacheForResult } from "../prefetch-Ce6la4EI.mjs";
4
4
  import { UsageLimitData } from "@void/edge";
5
5
  import { ActionUrl, ResolveActionBody, ResolveActionParams } from "void/routes";
@@ -71,7 +71,8 @@ type PageNavigationEngineConfig = {
71
71
  routeMeta: Record<string, {
72
72
  island?: boolean;
73
73
  }>;
74
- matchRoute(url: string): string | null;
74
+ /** Page id for a decoded pathname (see `decodePagePath`). */
75
+ matchRoute(path: string): string | null;
75
76
  staticPageData?: boolean;
76
77
  staticPageDataFastPath?: boolean;
77
78
  viewTransitions: boolean;
@@ -95,7 +96,8 @@ type PageNavigationResource = {
95
96
  immediate: boolean;
96
97
  shell: Promise<PageNavigationResult | undefined>;
97
98
  abort(): void;
98
- commit(): Promise<void>;
99
+ /** Resolves false when a newer visit has already set the URL, so nothing was committed. */
100
+ commit(): Promise<boolean>;
99
101
  dispose(): void;
100
102
  };
101
103
  type PageNavigationEngine = {
@@ -122,9 +124,35 @@ export declare function getValidationErrors(body: unknown): Record<string, strin
122
124
  export declare function mergeDataIntoHref(href: string, data?: Record<string, unknown>): string;
123
125
  export declare function isModifiedEvent(e: Pick<MouseEvent, "currentTarget" | "ctrlKey" | "metaKey" | "shiftKey" | "altKey" | "button">): boolean;
124
126
  //#endregion
127
+ //#region src/pages/island-action.d.ts
128
+ type IslandActionResult = {
129
+ kind: "redirect";
130
+ url: string;
131
+ } | {
132
+ kind: "success";
133
+ } | {
134
+ kind: "validation";
135
+ errors: Record<string, string>;
136
+ } | {
137
+ kind: "error";
138
+ error: VoidActionError;
139
+ };
140
+ export declare function submitIslandAction(url: string, method: string, data: Record<string, unknown>): Promise<IslandActionResult>;
141
+ //#endregion
125
142
  //#region src/pages/form-value-equality.d.ts
126
143
  export declare function isEqualFormValue(a: unknown, b: unknown): boolean;
127
144
  //#endregion
145
+ //#region src/pages/form-reset.d.ts
146
+ type FormResetOptions = {
147
+ initial?: boolean;
148
+ };
149
+ export declare function isFormResetOptions(value: unknown): value is FormResetOptions;
150
+ export declare function cloneFormValue<T>(value: T): T;
151
+ export declare function parseFormResetArgs(args: ReadonlyArray<string | FormResetOptions>): {
152
+ initial: boolean;
153
+ fields: ReadonlyArray<string>;
154
+ };
155
+ //#endregion
128
156
  //#region src/pages/form-presentation.d.ts
129
157
  type FormMethod = "post" | "put" | "patch" | "delete";
130
158
  type FormModel<Args extends Array<unknown> = []> = {
@@ -202,4 +230,4 @@ export declare function createVoidRouter(config: VoidRouterConfig): Promise<{
202
230
  export declare function scheduleHydration(el: Element, loader: () => Promise<unknown>, props: Record<string, unknown>, strategy: string, hydrateFn: (el: Element, mod: unknown, props: Record<string, unknown>) => void | Promise<void>): void;
203
231
  export declare function initIslands(islands: Record<string, () => Promise<unknown>>, hydrateFn: (el: Element, mod: unknown, props: Record<string, unknown>, frontmatter: Record<string, unknown>) => void | Promise<void>): void;
204
232
  //#endregion
205
- export { type ActionErrorHandlingScope, type ActionResult, type FormMethod, type FormModel, type PageNavigationEngine, type PageNavigationResource, type PageNavigationResult, type PrefetchOptions, type VisitOptions, interpolateRouteParams };
233
+ export { type ActionErrorHandlingScope, type ActionResult, type FormMethod, type FormModel, type FormResetOptions, type IslandActionResult, type PageNavigationEngine, type PageNavigationResource, type PageNavigationResult, type PrefetchOptions, type VisitOptions, interpolateRouteParams };
@@ -215,13 +215,14 @@ function createScrollRestoration() {
215
215
  },
216
216
  save,
217
217
  writeHistory(url, replace) {
218
- renderedKey = (replace ? readKey(history.state) : null) ?? newKey();
218
+ const key = (replace ? readKey(history.state) : null) ?? newKey();
219
219
  const state = {
220
220
  ...replace ? history.state : {},
221
- __voidScrollKey: renderedKey
221
+ __voidScrollKey: key
222
222
  };
223
223
  if (replace) history.replaceState(state, "", url);
224
224
  else history.pushState(state, "", url);
225
+ renderedKey = key;
225
226
  },
226
227
  commit() {
227
228
  renderedKey = readKey(history.state) ?? renderedKey;
@@ -255,11 +256,46 @@ function isSameOrigin(url, origin) {
255
256
  }
256
257
  return url.origin === origin;
257
258
  }
259
+ function isHexDigit(char) {
260
+ return char !== void 0 && (char >= "0" && char <= "9" || char >= "a" && char <= "f" || char >= "A" && char <= "F");
261
+ }
262
+ function tryDecodeURI(text) {
263
+ try {
264
+ return decodeURI(text);
265
+ } catch {
266
+ return text;
267
+ }
268
+ }
269
+ /**
270
+ * The path a page is matched on, decoded the way the server (Hono's getPath)
271
+ * decodes it: `/caf%C3%A9` becomes `/café`, while `%25`, reserved escapes such
272
+ * as `%2F` and malformed escapes stay encoded.
273
+ */
274
+ function decodePagePath(path) {
275
+ if (!path.includes("%")) return path;
276
+ const escaped = path.split("%25").join("%2525");
277
+ try {
278
+ return decodeURI(escaped);
279
+ } catch {}
280
+ let decoded = "";
281
+ let index = 0;
282
+ while (index < escaped.length) {
283
+ let end = index;
284
+ while (escaped[end] === "%" && isHexDigit(escaped[end + 1]) && isHexDigit(escaped[end + 2])) end += 3;
285
+ if (end === index) decoded += escaped[index++];
286
+ else {
287
+ decoded += tryDecodeURI(escaped.slice(index, end));
288
+ index = end;
289
+ }
290
+ }
291
+ return decoded;
292
+ }
258
293
  //#endregion
259
294
  //#region src/pages/navigation-engine.ts
260
295
  /**
261
296
  * The server leaves a named action's key out of the page URL. When the page URL
262
297
  * shows that, drop the key from the URL written to history as well.
298
+ * Otherwise keep the requested URL: the page URL may reflect a server rewrite.
263
299
  */
264
300
  function withoutActionKey(fetchUrl, pageUrl) {
265
301
  const q = fetchUrl.indexOf("?");
@@ -330,9 +366,11 @@ async function fetchPageResponse(fetchUrl, init) {
330
366
  }
331
367
  }
332
368
  async function createPageNavigationEngine(config) {
333
- const { adapter, components, layoutTree, routeMeta, matchRoute, staticPageData: STATIC_PAGE_DATA_ENABLED = false, staticPageDataFastPath: STATIC_PAGE_DATA_FAST_PATH = STATIC_PAGE_DATA_ENABLED, prefetchHoverDelay: PREFETCH_HOVER_DELAY, prefetchDefaultCacheFor: PREFETCH_DEFAULT_CACHE_FOR, cacheVisitedPageData: CACHE_VISITED_PAGE_DATA = false } = config;
369
+ const { adapter, components, layoutTree, routeMeta, staticPageData: STATIC_PAGE_DATA_ENABLED = false, staticPageDataFastPath: STATIC_PAGE_DATA_FAST_PATH = STATIC_PAGE_DATA_ENABLED, prefetchHoverDelay: PREFETCH_HOVER_DELAY, prefetchDefaultCacheFor: PREFETCH_DEFAULT_CACHE_FOR, cacheVisitedPageData: CACHE_VISITED_PAGE_DATA = false } = config;
370
+ const matchRoute = (url) => config.matchRoute(decodePagePath(new URL(url, "http://x").pathname));
334
371
  const _prefetchCache = new PrefetchCache();
335
372
  let _nextNavigationId = 0;
373
+ let _urlNavigationId = 0;
336
374
  let _pendingResource = null;
337
375
  let _committedResource = null;
338
376
  let _committedDeferredRegistry = null;
@@ -551,8 +589,8 @@ async function createPageNavigationEngine(config) {
551
589
  deferredWindow.__resolveDeferred = (group, data) => _htmlDeferredRegistry?.resolve(group, data, void 0);
552
590
  deferredWindow.__rejectDeferred = (group, error) => _htmlDeferredRegistry?.resolve(group, void 0, error);
553
591
  function commitHashNavigation(effectiveFetchUrl, hash, options, writeHistory) {
554
- _currentFetchUrl = effectiveFetchUrl;
555
592
  if (writeHistory) scrollRestoration.writeHistory(effectiveFetchUrl + hash, !!options.replace);
593
+ _currentFetchUrl = effectiveFetchUrl;
556
594
  scrollRestoration.commit();
557
595
  restoreScroll(options._scrollPosition, hash);
558
596
  }
@@ -617,14 +655,11 @@ async function createPageNavigationEngine(config) {
617
655
  window.location.href = method === "GET" ? url : response.url;
618
656
  return;
619
657
  }
620
- commitTarget.fetchUrl = redirectUrl.pathname + redirectUrl.search;
658
+ method = "GET";
659
+ fetchUrl = redirectUrl.pathname + redirectUrl.search;
660
+ url = fetchUrl + redirectUrl.hash;
661
+ commitTarget.fetchUrl = fetchUrl;
621
662
  commitTarget.hash = redirectUrl.hash;
622
- return loadNavigationShell(id, redirectUrl.pathname + redirectUrl.search + redirectUrl.hash, redirectUrl.pathname + redirectUrl.search, "GET", {
623
- preserveScroll: options.preserveScroll,
624
- preserveState: options.preserveState,
625
- replace: options.replace,
626
- viewTransition: options.viewTransition
627
- }, signal, commitTarget, deferredRegistry);
628
663
  }
629
664
  if (response && method !== "GET" && !response.ok) throw await createActionErrorFromResponse(response, fetchUrl);
630
665
  if (response && !response.headers.get("X-VoidPages")) {
@@ -704,10 +739,25 @@ async function createPageNavigationEngine(config) {
704
739
  function makeCommit(commitTarget, options, shell, deferredRegistry, resourceId, getResource) {
705
740
  let committed = false;
706
741
  return async () => {
707
- if (committed) return;
742
+ if (committed) return false;
708
743
  committed = true;
709
744
  const result = await shell;
710
- if (!result) return;
745
+ if (!result) return false;
746
+ if (resourceId < _urlNavigationId) return false;
747
+ if (!options._popstate) {
748
+ const historyUrl = commitTarget.fetchUrl + commitTarget.hash;
749
+ const resource = getResource();
750
+ const currentDocumentUrl = window.location.pathname + window.location.search;
751
+ const replaceHistory = !!options.replace || resource.method !== "GET" && historyUrl === currentDocumentUrl + commitTarget.hash;
752
+ try {
753
+ scrollRestoration.writeHistory(historyUrl, replaceHistory);
754
+ } catch (error) {
755
+ if (_pendingResource?.id === resourceId) _pendingResource = null;
756
+ resource.dispose();
757
+ throw error;
758
+ }
759
+ }
760
+ _urlNavigationId = resourceId;
711
761
  if (_pendingResource?.id === resourceId) _pendingResource = null;
712
762
  const previousResource = _committedResource;
713
763
  const previousDeferredRegistry = _committedDeferredRegistry;
@@ -726,14 +776,11 @@ async function createPageNavigationEngine(config) {
726
776
  if (preservedDeferredRegistry && preservedDeferredRegistry !== deferredRegistry) deferredRegistry.dispose();
727
777
  applyClientHead(result.pageData.head);
728
778
  _currentFetchUrl = commitTarget.fetchUrl;
729
- if (!options._popstate) {
730
- const historyUrl = commitTarget.fetchUrl + commitTarget.hash;
731
- scrollRestoration.writeHistory(historyUrl, !!options.replace);
732
- }
733
779
  scrollRestoration.commit();
734
780
  requestAnimationFrame(() => {
735
781
  if (!options.preserveScroll) restoreScroll(options._scrollPosition, commitTarget.hash);
736
782
  });
783
+ return true;
737
784
  };
738
785
  }
739
786
  const initialPageData = readInitialPageData();
@@ -761,7 +808,12 @@ async function createPageNavigationEngine(config) {
761
808
  _pendingResource?.abort();
762
809
  _pendingResource = null;
763
810
  if (!options._refresh && effectiveFetchUrl === hashNavigationBaseUrl && method === "GET" && !options.data && Boolean(hash || options._popstate)) {
764
- commitHashNavigation(effectiveFetchUrl, hash, options, !options._popstate);
811
+ let shell = Promise.resolve(void 0);
812
+ try {
813
+ commitHashNavigation(effectiveFetchUrl, hash, options, !options._popstate);
814
+ } catch (error) {
815
+ shell = Promise.reject(error);
816
+ }
765
817
  return {
766
818
  id,
767
819
  url,
@@ -770,12 +822,15 @@ async function createPageNavigationEngine(config) {
770
822
  method,
771
823
  options,
772
824
  immediate: true,
773
- shell: Promise.resolve(void 0),
825
+ shell,
774
826
  abort() {},
775
- async commit() {},
827
+ async commit() {
828
+ return true;
829
+ },
776
830
  dispose() {}
777
831
  };
778
832
  }
833
+ if (options._popstate) _urlNavigationId = id;
779
834
  const controller = new AbortController();
780
835
  const deferredRegistry = new DeferredRegistry();
781
836
  const commitTarget = {
@@ -783,7 +838,7 @@ async function createPageNavigationEngine(config) {
783
838
  hash
784
839
  };
785
840
  const shell = loadNavigationShell(id, url, effectiveFetchUrl, method, options, controller.signal, commitTarget, deferredRegistry);
786
- let commitResource = async () => {};
841
+ let commitResource = async () => false;
787
842
  const stop = () => {
788
843
  controller.abort(abortError());
789
844
  deferredRegistry.dispose();
@@ -918,6 +973,31 @@ function isModifiedEvent(e) {
918
973
  return target !== null && target !== "_self" || e.ctrlKey || e.metaKey || e.shiftKey || e.altKey || e.button !== 0;
919
974
  }
920
975
  //#endregion
976
+ //#region src/pages/island-action.ts
977
+ async function submitIslandAction(url, method, data) {
978
+ const response = await fetch(url, {
979
+ method,
980
+ headers: { "Content-Type": "application/json" },
981
+ body: JSON.stringify(data)
982
+ });
983
+ if (response.redirected) return {
984
+ kind: "redirect",
985
+ url: response.url
986
+ };
987
+ if (response.ok) return { kind: "success" };
988
+ const error = await createActionErrorFromResponse(response, url);
989
+ const errors = response.status === 422 ? getValidationErrors(error.body) : null;
990
+ if (errors) return {
991
+ kind: "validation",
992
+ errors
993
+ };
994
+ if (categorizeActionError(response.status) === "boundary") throw error;
995
+ return {
996
+ kind: "error",
997
+ error
998
+ };
999
+ }
1000
+ //#endregion
921
1001
  //#region src/pages/form-value-equality.ts
922
1002
  function isPlainObject(value) {
923
1003
  if (value === null || typeof value !== "object") return false;
@@ -940,6 +1020,39 @@ function isEqualFormValue(a, b) {
940
1020
  return false;
941
1021
  }
942
1022
  //#endregion
1023
+ //#region src/pages/form-reset.ts
1024
+ function isFormResetOptions(value) {
1025
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1026
+ }
1027
+ function cloneFormValue(value) {
1028
+ return clone(value, /* @__PURE__ */ new WeakMap());
1029
+ }
1030
+ function clone(value, seen) {
1031
+ if (value === null || typeof value !== "object") return value;
1032
+ const prototype = Object.getPrototypeOf(value);
1033
+ if (!Array.isArray(value) && prototype !== Object.prototype && prototype !== null) return value;
1034
+ if (seen.has(value)) return seen.get(value);
1035
+ const result = Array.isArray(value) ? new Array(value.length) : Object.create(prototype);
1036
+ seen.set(value, result);
1037
+ for (const key of Object.keys(value)) Object.defineProperty(result, key, {
1038
+ value: clone(value[key], seen),
1039
+ enumerable: true,
1040
+ configurable: true,
1041
+ writable: true
1042
+ });
1043
+ return result;
1044
+ }
1045
+ function parseFormResetArgs(args) {
1046
+ if (args.length > 0 && isFormResetOptions(args[0])) return {
1047
+ initial: args[0].initial === true,
1048
+ fields: args.slice(1)
1049
+ };
1050
+ return {
1051
+ initial: false,
1052
+ fields: args
1053
+ };
1054
+ }
1055
+ //#endregion
943
1056
  //#region src/pages/form-presentation.ts
944
1057
  function formErrorMessage(form) {
945
1058
  return form.error?.message ?? (Object.values(form.errors).filter(Boolean).join(". ") || null);
@@ -1133,6 +1246,13 @@ async function createVoidRouter(config) {
1133
1246
  let routeUrl = currentUrl();
1134
1247
  let routeParams = engine.initialPageData.params ?? {};
1135
1248
  let activeNavigationId = null;
1249
+ let committedPage = {
1250
+ pageData: engine.initialPageData,
1251
+ component: engine.initialComponent,
1252
+ layouts: engine.initialLayouts
1253
+ };
1254
+ let renderedPage = committedPage;
1255
+ let failedRender = null;
1136
1256
  const setRouteState = (url, params = routeParams) => {
1137
1257
  routeUrl = url;
1138
1258
  routeParams = params;
@@ -1148,20 +1268,57 @@ async function createVoidRouter(config) {
1148
1268
  const result = await resource.shell;
1149
1269
  if (!result) return;
1150
1270
  setRouteState(result.pageData.url || resource.fetchUrl + resource.hash, result.pageData.params ?? {});
1151
- const applyUpdate = () => config.adapter.applyUpdate(result.pageData, result.component, result.layouts, { preserveState: resource.options.preserveState ?? resource.method !== "GET" });
1152
- if ((resource.options.viewTransition ?? config.viewTransitions) && document.startViewTransition) await document.startViewTransition(() => applyUpdate()).updateCallbackDone;
1271
+ const preserveState = resource.options.preserveState ?? resource.method !== "GET";
1272
+ const applyUpdate = () => {
1273
+ renderedPage = result;
1274
+ failedRender = null;
1275
+ return config.adapter.applyUpdate(result.pageData, result.component, result.layouts, { preserveState });
1276
+ };
1277
+ let applied = true;
1278
+ if ((resource.options.viewTransition ?? config.viewTransitions) && document.startViewTransition) await document.startViewTransition(() => {
1279
+ if (activeNavigationId !== resource.id) {
1280
+ applied = false;
1281
+ return;
1282
+ }
1283
+ return applyUpdate();
1284
+ }).updateCallbackDone;
1153
1285
  else await applyUpdate();
1154
- await resource.commit();
1286
+ let committed = false;
1287
+ if (applied) try {
1288
+ committed = await resource.commit();
1289
+ } catch (error) {
1290
+ if (renderedPage === result) failedRender = { preserveState };
1291
+ throw error;
1292
+ }
1293
+ if (!committed) throw new DOMException("Navigation aborted", "AbortError");
1294
+ committedPage = result;
1295
+ if (renderedPage === result) failedRender = null;
1155
1296
  if (activeNavigationId === resource.id) setRouteState(currentUrl(), result.pageData.params ?? {});
1156
1297
  return result.pageData;
1157
1298
  } catch (error) {
1158
1299
  if (resource.method.toUpperCase() === "GET" && !resource.options._resolveOnShell && isAbortError(error)) return;
1159
1300
  throw error;
1160
1301
  } finally {
1161
- if (activeNavigationId === resource.id) {
1162
- activeNavigationId = null;
1163
- setRouteState(currentUrl());
1164
- setNavigation(idleNavigationState());
1302
+ const ownsNavigation = activeNavigationId === resource.id;
1303
+ if (ownsNavigation || activeNavigationId === null) {
1304
+ let restored = false;
1305
+ if (failedRender && renderedPage !== committedPage) {
1306
+ const { preserveState } = failedRender;
1307
+ failedRender = null;
1308
+ renderedPage = committedPage;
1309
+ restored = true;
1310
+ const page = committedPage;
1311
+ try {
1312
+ await config.adapter.applyUpdate(page.pageData, page.component, page.layouts, { preserveState });
1313
+ } catch (error) {
1314
+ reportError(error);
1315
+ }
1316
+ }
1317
+ if (ownsNavigation && activeNavigationId === resource.id) {
1318
+ activeNavigationId = null;
1319
+ setRouteState(currentUrl(), restored ? committedPage.pageData.params ?? {} : void 0);
1320
+ setNavigation(idleNavigationState());
1321
+ } else if (restored && activeNavigationId === null) setRouteState(currentUrl(), committedPage.pageData.params ?? {});
1165
1322
  }
1166
1323
  }
1167
1324
  }
@@ -1245,4 +1402,4 @@ function initIslands(islands, hydrateFn) {
1245
1402
  });
1246
1403
  }
1247
1404
  //#endregion
1248
- export { VoidActionError, categorizeActionError, createActionClient, createPageNavigationEngine, createRouterFacade, createSsrRouter, createVoidRouter, formErrorMessage, formRetryMessage, formSubmissionBlocked, getValidationErrors, hasFiles, idleNavigationState, initIslands, interpolateRouteParams, isAbortError, isCallSiteActionError, isEqualFormValue, isFile, isModifiedEvent, mergeDataIntoHref, objectToFormData, refreshPage, scheduleFormRetry, scheduleHydration, ssrProxy, submitAction };
1405
+ export { VoidActionError, categorizeActionError, cloneFormValue, createActionClient, createPageNavigationEngine, createRouterFacade, createSsrRouter, createVoidRouter, formErrorMessage, formRetryMessage, formSubmissionBlocked, getValidationErrors, hasFiles, idleNavigationState, initIslands, interpolateRouteParams, isAbortError, isCallSiteActionError, isEqualFormValue, isFile, isFormResetOptions, isModifiedEvent, mergeDataIntoHref, objectToFormData, parseFormResetArgs, refreshPage, scheduleFormRetry, scheduleHydration, ssrProxy, submitAction, submitIslandAction };