void 1.3.0 → 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.
- package/dist/{account-cmd-B4i71m7k.mjs → account-cmd-HP8bixYo.mjs} +3 -3
- package/dist/{application-analysis-DYdVoMAY.mjs → application-analysis-DDOQwiXk.mjs} +11 -7
- package/dist/{application-routing-C8EqRDfv.mjs → application-routing-4719u_kf.mjs} +1 -1
- package/dist/auth-g2TQbDLD.d.mts +70 -0
- package/dist/{auth-link-BKwHPbdv.mjs → auth-link-CedYpDCy.mjs} +3 -3
- package/dist/{auth-router-DqLx8E0F.mjs → auth-router-vafo7x8w.mjs} +11 -6
- package/dist/{better-auth-shared-DVk2DkTW.d.mts → better-auth-shared-BHB8kiTE.d.mts} +1 -1
- package/dist/{build-cmd-Dy4psnt1.mjs → build-cmd-9vUAQ1_V.mjs} +1 -1
- package/dist/{cache-DV37S6dl.mjs → cache-jvwLNb0h.mjs} +1 -1
- package/dist/{cancel-deploy-DMPyu1Vt.mjs → cancel-deploy-Dw0UmWKO.mjs} +1 -1
- package/dist/{cf-build-output-Bapzc_8Z.mjs → cf-build-output-XpNR9zoh.mjs} +20 -4
- package/dist/cf-build-output-bd8Uwv1P.mjs +1 -0
- package/dist/{cf-worker-settings-BECvvTVd.mjs → cf-worker-settings-Dg27RzyT.mjs} +11 -5
- package/dist/cli/cli.mjs +25 -25
- package/dist/cli/cloudflare-operation-process.mjs +9 -3
- package/dist/cli/env-schema-probe.mjs +2 -2
- package/dist/{client-BEMtySaV.mjs → client-B3LnB_bE.mjs} +1 -1
- package/dist/client-BZb9j66F.mjs +1 -0
- package/dist/{cloudflare-auth-Byo_0_N9.mjs → cloudflare-auth-DyD_kVFr.mjs} +1 -1
- package/dist/{cloudflare-cmd-BaqIigwI.mjs → cloudflare-cmd-D-b_u3T4.mjs} +2 -2
- package/dist/{cloudflare-config-DchHxPTo.mjs → cloudflare-config-CH1AylZT.mjs} +14 -3
- package/dist/{cloudflare-connect-pNLQmr_e.mjs → cloudflare-connect-zTJh8UnN.mjs} +2 -2
- package/dist/{cloudflare-operations-vP3b5CQf.mjs → cloudflare-operations-Bc-7fN44.mjs} +4 -4
- package/dist/{cloudflare-operations-PCM4wucv.mjs → cloudflare-operations-BtulCNOg.mjs} +1 -1
- package/dist/{config-BU6hMu1W.mjs → config-BV2ASlpn.mjs} +1 -1
- package/dist/{config-Du88-7Y8.d.mts → config-CAdZVTLN.d.mts} +2 -0
- package/dist/config-D-6q7EBH.mjs +87 -0
- package/dist/{config-DHgSEWT7.mjs → config-OFOAimzt.mjs} +5 -3
- package/dist/config-entry.d.mts +1 -1
- package/dist/{config-BIaXIkkv.mjs → config-tqMM6DwY.mjs} +1 -1
- package/dist/{connect-DwVsBvVh.mjs → connect-BOM6zvFX.mjs} +4 -4
- package/dist/{create-project-CjzbBlTv.mjs → create-project-Bxd02EHN.mjs} +1 -1
- package/dist/{create-project-CgrnvzyA.mjs → create-project-C2K0DN2O.mjs} +1 -1
- package/dist/{db-rvo64snS.mjs → db-Cdvr3zwG.mjs} +16 -16
- package/dist/{db-types-NGxPwnlt.mjs → db-types-0eCiqYb1.mjs} +1 -1
- package/dist/{delete-DWX6dP4M.mjs → delete-lETE6Tpt.mjs} +1 -1
- package/dist/deploy-CX94CmKa.mjs +2 -0
- package/dist/{deploy-hRPvw8ci.mjs → deploy-CdM-LAxX.mjs} +260 -95
- package/dist/{deploy-managed-static-CDYA2p3L.mjs → deploy-managed-static-DjeBFG2c.mjs} +24 -17
- package/dist/{deploy-transport-JCxw7QDi.mjs → deploy-transport-DIq_gFTP.mjs} +13 -12
- package/dist/deploy.d.mts +2 -0
- package/dist/deploy.mjs +7 -5
- package/dist/{dispatch-OVLeWW8K.mjs → dispatch-CLa2LThw.mjs} +5 -5
- package/dist/{domain-CH5iBD9Y.mjs → domain-DyhNtdYf.mjs} +2 -2
- package/dist/{email-CbTO1l78.mjs → email-DM2wDcBN.mjs} +6 -6
- package/dist/{email-cloudflare-B8-pq_-W.mjs → email-cloudflare-PMbAev9Q.mjs} +20 -7
- package/dist/{env-BBdw236G.mjs → env-78hbN-oI.mjs} +3 -3
- package/dist/{env-validation-XcukUlFM.mjs → env-validation-B3VobvXm.mjs} +1 -0
- package/dist/{env-validation-BfBVvBNe.mjs → env-validation-BUfFZ6bt.mjs} +1 -1
- package/dist/error-pages-CLIJ7aYq.mjs +37 -0
- package/dist/gen-BhWBT4iu.mjs +1 -0
- package/dist/{gen-CCx3t2Ju.mjs → gen-CFmsUsW1.mjs} +3 -3
- package/dist/{github-cmd-BzkRLkbg.mjs → github-cmd-De-_IWbM.mjs} +1 -1
- package/dist/{handler-CQv5YDS0.d.mts → handler-BHktmuTL.d.mts} +3 -1
- package/dist/{headers-D522zd0A.mjs → headers--vaK_chu.mjs} +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +68 -33
- package/dist/{info-oBm8yK8J.mjs → info-Yg0-V5Rs.mjs} +3 -3
- package/dist/{init-CBp_uMve.mjs → init-CDiJQycf.mjs} +31 -16
- package/dist/{link-Dt_QXmM4.mjs → link-Dllip08S.mjs} +2 -2
- package/dist/{list-DF6asTdt.mjs → list-BYRP6am0.mjs} +2 -2
- package/dist/{live-CXJ9yC98.d.mts → live-BllfDuzA.d.mts} +2 -2
- package/dist/{local-d1-CUhH3qtj.mjs → local-d1-CAwAs9GH.mjs} +1 -1
- package/dist/login-BAPmYnb7.mjs +1 -0
- package/dist/{login-BjSyhXlT.mjs → login-PcFy5mlC.mjs} +2 -2
- package/dist/{logs-DmvBl6xA.mjs → logs-DmJTBhed.mjs} +2 -2
- package/dist/{migrate-BXRHpYwR.mjs → migrate-B8S2xTcb.mjs} +5 -66
- package/dist/migrate-BIYTPQE6.mjs +1 -0
- package/dist/nitro.mjs +4 -4
- package/dist/{node-DtD7ZiPf.mjs → node-CDOPrGSl.mjs} +3 -3
- package/dist/operator-cmd-CjazwOyb.mjs +1 -0
- package/dist/{operator-cmd-DjZKGGgN.mjs → operator-cmd-DmkmS2wL.mjs} +2 -2
- package/dist/pages/client.d.mts +17 -2
- package/dist/pages/client.mjs +26 -1
- package/dist/pages/index.d.mts +17 -1
- package/dist/pages/index.mjs +95 -4
- package/dist/pages/protocol.d.mts +2 -2
- package/dist/{platform-auth-config-BgnuMbml.mjs → platform-auth-config-CImnfohz.mjs} +3 -3
- package/dist/{platform-auth-protection-NjRejttU.mjs → platform-auth-protection-BogLhtHi.mjs} +2 -2
- package/dist/{platform-auth-recovery-Ug12d9W5.mjs → platform-auth-recovery-B-mEaWEi.mjs} +2 -2
- package/dist/{platform-cmd-BYKLMPCn.mjs → platform-cmd-CV8NxIIn.mjs} +1 -1
- package/dist/{platform-cmd-HByuZAO7.mjs → platform-cmd-DZK2ixMl.mjs} +3 -3
- package/dist/{platform-domain-DLSQ8GF8.mjs → platform-domain-CRvelPGE.mjs} +2 -2
- package/dist/{platform-lifecycle-3dwFJmnq.mjs → platform-lifecycle-CPYY7E9B.mjs} +8 -8
- package/dist/{platform-lifecycle-BRqcxerG.mjs → platform-lifecycle-DwXq7kZt.mjs} +1 -1
- package/dist/{platform-management-ZZ6bQM5j.mjs → platform-management-BOnGbMSM.mjs} +1 -1
- package/dist/{platform-management-ZK6XcbCo.mjs → platform-management-lXdgGgAM.mjs} +1 -1
- package/dist/{platform-recovery-8vNE5dNN.mjs → platform-recovery-noaALXnE.mjs} +2 -2
- package/dist/{prepare-5BR7Splm.mjs → prepare-BuOS18AM.mjs} +1 -1
- package/dist/{prepare-Dseww74N.mjs → prepare-D604Yiyr.mjs} +11 -7
- package/dist/prepare-DU-tOpS5.mjs +1 -0
- package/dist/{project-cmd-CjLNNxwe.mjs → project-cmd-DBYqAIbe.mjs} +13 -13
- package/dist/{project-team-DE5drjcl.mjs → project-team-BjCLgTRC.mjs} +1 -1
- package/dist/{project-token-XEYEXfiJ.mjs → project-token-BB6PwaA9.mjs} +1 -1
- package/dist/{project-tsconfig-Itv1f4WC.mjs → project-tsconfig-CVvk6Z_e.mjs} +24 -2
- package/dist/{project-zero-trust-6VPU8zmV.mjs → project-zero-trust-CWDh1P_t.mjs} +1 -1
- package/dist/{protocol-BekmFxCI.d.mts → protocol-D5XDySYu.d.mts} +1 -1
- package/dist/{provision-Chq0NRAV.mjs → provision-DfxLCg-d.mjs} +1 -1
- package/dist/{provision-B7UFrBH7.mjs → provision-DztLJ97X.mjs} +24 -8
- package/dist/{requests-CG-Pj8ze.mjs → requests-D_pbzDyz.mjs} +1 -1
- package/dist/{rollback-CIrm2txZ.mjs → rollback-CjfIYsJx.mjs} +2 -2
- package/dist/{route-types--PAOzHlH.mjs → route-types-DvEGmPif.mjs} +61 -3
- package/dist/runtime/auth.d.mts +2 -2
- package/dist/runtime/better-auth-mysql.d.mts +1 -1
- package/dist/runtime/better-auth-pg.d.mts +1 -1
- package/dist/runtime/better-auth.d.mts +1 -1
- package/dist/runtime/client-react.d.mts +1 -1
- package/dist/runtime/client-solid.d.mts +1 -1
- package/dist/runtime/client-svelte.d.mts +1 -1
- package/dist/runtime/client-vue.d.mts +1 -1
- package/dist/runtime/client.d.mts +1 -1
- package/dist/runtime/handler.d.mts +1 -1
- package/dist/runtime/live-client.d.mts +1 -1
- package/dist/runtime/live.d.mts +1 -1
- package/dist/runtime/routing.d.mts +5 -4
- package/dist/runtime/routing.mjs +10 -70
- package/dist/runtime/validator.d.mts +1 -1
- package/dist/runtime/ws-server.d.mts +3 -3
- package/dist/runtime/ws.d.mts +1 -1
- package/dist/runtime/ws.mjs +4 -2
- package/dist/{secret-BL6g7mF5.mjs → secret-3X0PxmuX.mjs} +9 -12
- package/dist/{version-metadata-DmaZNTYW.mjs → version-metadata-D2vfMQzv.mjs} +2 -1
- package/dist/{wrangler-CDiEBCdS.mjs → wrangler-I-scB_1t.mjs} +80 -12
- package/dist/wrangler-UnwdISay.mjs +1 -0
- package/dist/{wrapper-CEiDeCqD.mjs → wrapper-BBl1rC32.mjs} +3 -3
- package/dist/{ws-D1zWiB_P.d.mts → ws-B3ClMVDh.d.mts} +3 -2
- package/docs/guide/auth.md +1 -1
- package/docs/guide/edge/redirects.md +22 -0
- package/docs/guide/pages-routing/actions-and-forms.md +24 -0
- package/docs/guide/platform/installation/maintenance.md +3 -1
- package/docs/guide/server-routing.md +2 -0
- package/docs/guide/ssg.md +8 -0
- package/docs/integrations/cloudflare.md +16 -7
- package/docs/reference/api/auth.md +6 -2
- package/docs/reference/api/deploy.md +9 -5
- package/docs/reference/api/pages.md +2 -0
- package/docs/reference/cli/deploy.md +10 -9
- package/docs/reference/config.md +11 -1
- package/package.json +8 -7
- package/schema.json +4 -0
- package/skills/void/SKILL.md +1 -1
- package/dist/auth-DkcFflXV.d.mts +0 -42
- package/dist/cf-build-output-DlBkWdNU.mjs +0 -1
- package/dist/client-DyxPQnF_.mjs +0 -1
- package/dist/config-BTu1o3Dc.mjs +0 -49
- package/dist/deploy-CtHE2A3R.mjs +0 -2
- package/dist/gen-TgXy93Rr.mjs +0 -1
- package/dist/login-Cdo8Aco1.mjs +0 -1
- package/dist/migrate-COPncCGx.mjs +0 -1
- package/dist/operator-cmd-DDiX7Y3f.mjs +0 -1
- package/dist/prepare-B3VrSF1Z.mjs +0 -1
- package/dist/wrangler-DOPr4jyI.mjs +0 -1
|
@@ -1,12 +1,68 @@
|
|
|
1
1
|
import { a as join, c as resolve, n as dirname, o as normalize, t as basename } from "./dist-ipQi0Q8y.mjs";
|
|
2
|
-
import "./project-paths-DGu_QZ_Q.mjs";
|
|
3
|
-
import { p as readConfig } from "./config-
|
|
4
|
-
import {
|
|
2
|
+
import { o as TYPED_CONFIG_FILE, s as loadTypedVoidConfigFile } from "./project-paths-DGu_QZ_Q.mjs";
|
|
3
|
+
import { h as validateConfig, p as readConfig } from "./config-OFOAimzt.mjs";
|
|
4
|
+
import { a as persistCloudflareConfig, i as materializeCloudflareConfig, r as ignoreMaterializedCloudflareConfig } from "./cloudflare-config-CH1AylZT.mjs";
|
|
5
5
|
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
6
|
+
import { parseSync } from "vite";
|
|
6
7
|
import { appendSqliteClassMigration, isRecord } from "@void/deploy-core";
|
|
7
8
|
import { createHash } from "node:crypto";
|
|
8
9
|
import { isDeepStrictEqual } from "node:util";
|
|
9
10
|
import { SyntaxKind, applyEdits, createScanner, findNodeAtLocation, modify, parse, parseTree } from "jsonc-parser";
|
|
11
|
+
//#region src/config-write.ts
|
|
12
|
+
const GENERATED_MARKERS = [
|
|
13
|
+
"// Generated by void migrate.",
|
|
14
|
+
"// Generated from void.json by void migrate.",
|
|
15
|
+
"// Generated by void init."
|
|
16
|
+
];
|
|
17
|
+
function renderVoidConfig(config, marker = GENERATED_MARKERS[0]) {
|
|
18
|
+
return `${marker}\nimport { defineConfig } from 'void/config';\n\nexport default defineConfig(${JSON.stringify(config, null, 2)});\n`;
|
|
19
|
+
}
|
|
20
|
+
function isStaticValue(node) {
|
|
21
|
+
if (!node) return false;
|
|
22
|
+
if (node.type === "Literal") return node.value === null || [
|
|
23
|
+
"string",
|
|
24
|
+
"number",
|
|
25
|
+
"boolean"
|
|
26
|
+
].includes(typeof node.value);
|
|
27
|
+
if (node.type === "UnaryExpression") return node.operator === "-" && node.argument?.type === "Literal" && typeof node.argument.value === "number";
|
|
28
|
+
if (node.type === "ArrayExpression") return node.elements?.every(isStaticValue) ?? false;
|
|
29
|
+
if (node.type !== "ObjectExpression") return false;
|
|
30
|
+
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;
|
|
31
|
+
}
|
|
32
|
+
function isGeneratedStaticConfig(source) {
|
|
33
|
+
if (!GENERATED_MARKERS.some((marker) => source.startsWith(marker))) return false;
|
|
34
|
+
let program;
|
|
35
|
+
try {
|
|
36
|
+
const parsed = parseSync(TYPED_CONFIG_FILE, source, {
|
|
37
|
+
lang: "js",
|
|
38
|
+
sourceType: "module",
|
|
39
|
+
preserveParens: false,
|
|
40
|
+
showSemanticErrors: true
|
|
41
|
+
});
|
|
42
|
+
if (parsed.errors.length > 0 || parsed.comments.length !== 1 || !GENERATED_MARKERS.includes(`// ${parsed.comments[0]?.value.trim()}`)) return false;
|
|
43
|
+
program = parsed.program;
|
|
44
|
+
} catch {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
const [importDeclaration, exportDeclaration] = program.body ?? [];
|
|
48
|
+
const call = exportDeclaration?.declaration;
|
|
49
|
+
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]);
|
|
50
|
+
}
|
|
51
|
+
function canRewriteVoidProjectConfig(root) {
|
|
52
|
+
const path = join(root, TYPED_CONFIG_FILE);
|
|
53
|
+
return !existsSync(path) || isGeneratedStaticConfig(readFileSync(path, "utf8"));
|
|
54
|
+
}
|
|
55
|
+
/** Update CLI-owned static config without silently rewriting authored TypeScript. */
|
|
56
|
+
function writeVoidProjectConfig(root, config) {
|
|
57
|
+
validateConfig(config, TYPED_CONFIG_FILE);
|
|
58
|
+
const path = join(root, TYPED_CONFIG_FILE);
|
|
59
|
+
if (existsSync(path)) {
|
|
60
|
+
if (!isGeneratedStaticConfig(readFileSync(path, "utf8"))) throw new Error(`config: ${TYPED_CONFIG_FILE} contains authored TypeScript or comments. Update it directly and rerun the command.`);
|
|
61
|
+
validateConfig(loadTypedVoidConfigFile(path), TYPED_CONFIG_FILE);
|
|
62
|
+
}
|
|
63
|
+
writeFileSync(path, renderVoidConfig(config, "// Generated by void init."));
|
|
64
|
+
}
|
|
65
|
+
//#endregion
|
|
10
66
|
//#region src/cli/wrangler.ts
|
|
11
67
|
const COMPAT_DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
|
|
12
68
|
/** UTF-8 byte-order mark. Node's utf-8 read preserves a leading one. */
|
|
@@ -170,10 +226,15 @@ function resolveGeneratedName(base, used, kind) {
|
|
|
170
226
|
function readWranglerCompat(root, config, buildOutputDir) {
|
|
171
227
|
return resolveWranglerCompat(readWranglerCompatFields(root, config, buildOutputDir));
|
|
172
228
|
}
|
|
173
|
-
/**
|
|
174
|
-
|
|
229
|
+
/**
|
|
230
|
+
* Like `readWranglerCompat()`, but pins the default date when no source sets one.
|
|
231
|
+
* With `rootWrangler`, a project with no config gets the date in a root wrangler.jsonc
|
|
232
|
+
* instead of a new void.config.ts, so a framework adapter that reads the root file by
|
|
233
|
+
* default still finds it.
|
|
234
|
+
*/
|
|
235
|
+
function ensureWranglerCompat(root, config, buildOutputDir, options) {
|
|
175
236
|
const fields = readWranglerCompatFields(root, config, buildOutputDir);
|
|
176
|
-
const defaultDate = fields.voidDate ?? fields.wranglerDate ?? fields.buildDate ? void 0 : ensureVoidCompatibilityDate(root,
|
|
237
|
+
const defaultDate = fields.voidDate ?? fields.wranglerDate ?? fields.buildDate ? void 0 : ensureVoidCompatibilityDate(root, options?.rootWrangler === true);
|
|
177
238
|
return resolveWranglerCompat(fields, defaultDate ? { defaultDate } : void 0);
|
|
178
239
|
}
|
|
179
240
|
function readWranglerCompatFields(root, config, buildOutputDir) {
|
|
@@ -205,7 +266,6 @@ function readWranglerCompatFields(root, config, buildOutputDir) {
|
|
|
205
266
|
if (Array.isArray(buildParsed.compatibility_flags) && buildParsed.compatibility_flags.every((f) => typeof f === "string")) buildFlags = buildParsed.compatibility_flags;
|
|
206
267
|
} catch {}
|
|
207
268
|
return {
|
|
208
|
-
voidConfig,
|
|
209
269
|
voidDate: voidConfig?.worker?.compatibility_date,
|
|
210
270
|
voidFlags: voidConfig?.worker?.compatibility_flags,
|
|
211
271
|
wranglerDate,
|
|
@@ -226,14 +286,23 @@ function validateCompatDate(value, source) {
|
|
|
226
286
|
function readVoidConfigIfExists(root) {
|
|
227
287
|
return existsSync(join(root, VOID_CONFIG_FILE)) || existsSync(join(root, "void.config.ts")) ? readConfig(root) : void 0;
|
|
228
288
|
}
|
|
229
|
-
function ensureVoidCompatibilityDate(root,
|
|
289
|
+
function ensureVoidCompatibilityDate(root, rootWrangler) {
|
|
230
290
|
if (existsSync(join(root, "void.config.ts"))) {
|
|
231
291
|
writeProvisionedWranglerConfig(root, { compatibilityDate: LATEST_KNOWN_COMPAT_DATE });
|
|
232
292
|
return LATEST_KNOWN_COMPAT_DATE;
|
|
233
293
|
}
|
|
234
294
|
const filePath = join(root, VOID_CONFIG_FILE);
|
|
235
|
-
|
|
236
|
-
|
|
295
|
+
if (!existsSync(filePath)) {
|
|
296
|
+
if (existsSync(join(root, "wrangler.toml"))) writeFileSync(filePath, `${JSON.stringify({ worker: { compatibility_date: LATEST_KNOWN_COMPAT_DATE } }, null, 2)}\n`);
|
|
297
|
+
else if (rootWrangler || projectWranglerPaths(root).some((path) => existsSync(path))) writeProvisionedWranglerConfig(root, { compatibilityDate: LATEST_KNOWN_COMPAT_DATE });
|
|
298
|
+
else {
|
|
299
|
+
writeVoidProjectConfig(root, { worker: { compatibility_date: LATEST_KNOWN_COMPAT_DATE } });
|
|
300
|
+
ignoreMaterializedCloudflareConfig(root);
|
|
301
|
+
}
|
|
302
|
+
return LATEST_KNOWN_COMPAT_DATE;
|
|
303
|
+
}
|
|
304
|
+
let nextConfig;
|
|
305
|
+
try {
|
|
237
306
|
const parsed = JSON.parse(readFileSync(filePath, "utf-8"));
|
|
238
307
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) throw new Error(`config: ${VOID_CONFIG_FILE} must be a JSON object.`);
|
|
239
308
|
nextConfig = parsed;
|
|
@@ -241,7 +310,6 @@ function ensureVoidCompatibilityDate(root, config) {
|
|
|
241
310
|
if (error instanceof SyntaxError) throw new Error(`config: Invalid JSON in ${VOID_CONFIG_FILE}.`);
|
|
242
311
|
throw error;
|
|
243
312
|
}
|
|
244
|
-
else if (config) nextConfig = { ...config };
|
|
245
313
|
nextConfig.worker = {
|
|
246
314
|
...nextConfig.worker ?? {},
|
|
247
315
|
compatibility_date: LATEST_KNOWN_COMPAT_DATE
|
|
@@ -1400,4 +1468,4 @@ function normalizeMigrationsPath(p) {
|
|
|
1400
1468
|
return normalized.endsWith("/") ? normalized.slice(0, -1) : normalized;
|
|
1401
1469
|
}
|
|
1402
1470
|
//#endregion
|
|
1403
|
-
export { syncWranglerWebSockets as A, readWranglerManagedQueueCleanupCandidates as C, sameMigrationsDir as D, resolveLiveBindingConfig as E, writeProvisionedWranglerConfig as M, writeWranglerPublishedTrafficSnapshot as N, syncWranglerBindings as O, readWranglerCustomDomains as S, readWranglerWebSocketTombstones as T, persistMaterializedWranglerConfig as _, LIVE_MIGRATION_TAG as a, readRootWranglerConfig as b, bindingEntriesForField as c, ensureWranglerCompatibilityDate as d, ensureWranglerNodejsAlsFlag as f, normalizeWranglerCompatibilityFlags as g, nextDurableObjectMigrationTag as h, LATEST_KNOWN_COMPAT_DATE as i, updateWranglerCustomDomain as j, syncWranglerDurableObjects as k, bindingNamesForField as l, hasDurableObjectSqliteMigration as m, DEFAULT_LIVE_CLASS as n, acknowledgeWranglerManagedQueueRemovals as o, findBindingNameOwner as p, FRIENDLY_BINDING_NAMES as r, assertNoDuplicateMembers as s, DEFAULT_LIVE_BINDING as t, ensureWranglerCompat as u, readExistingLiveBindingConfig as v, readWranglerPublishedTrafficSnapshot as w, readWranglerCompat as x, readProvisionedBindingEntry as y };
|
|
1471
|
+
export { syncWranglerWebSockets as A, readWranglerManagedQueueCleanupCandidates as C, sameMigrationsDir as D, resolveLiveBindingConfig as E, canRewriteVoidProjectConfig as F, renderVoidConfig as I, writeVoidProjectConfig as L, writeProvisionedWranglerConfig as M, writeWranglerPublishedTrafficSnapshot as N, syncWranglerBindings as O, GENERATED_MARKERS as P, readWranglerCustomDomains as S, readWranglerWebSocketTombstones as T, persistMaterializedWranglerConfig as _, LIVE_MIGRATION_TAG as a, readRootWranglerConfig as b, bindingEntriesForField as c, ensureWranglerCompatibilityDate as d, ensureWranglerNodejsAlsFlag as f, normalizeWranglerCompatibilityFlags as g, nextDurableObjectMigrationTag as h, LATEST_KNOWN_COMPAT_DATE as i, updateWranglerCustomDomain as j, syncWranglerDurableObjects as k, bindingNamesForField as l, hasDurableObjectSqliteMigration as m, DEFAULT_LIVE_CLASS as n, acknowledgeWranglerManagedQueueRemovals as o, findBindingNameOwner as p, FRIENDLY_BINDING_NAMES as r, assertNoDuplicateMembers as s, DEFAULT_LIVE_BINDING as t, ensureWranglerCompat as u, readExistingLiveBindingConfig as v, readWranglerPublishedTrafficSnapshot as w, readWranglerCompat as x, readProvisionedBindingEntry as y };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { b as readRootWranglerConfig } from "./wrangler-I-scB_1t.mjs";
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { a as join, l as toSlash, n as dirname, r as extname } from "./dist-ipQi0Q8y.mjs";
|
|
2
2
|
import { n as readProjectPaths } from "./project-paths-DGu_QZ_Q.mjs";
|
|
3
|
-
import { l as getDatabaseDialect, p as readConfig } from "./config-
|
|
3
|
+
import { l as getDatabaseDialect, p as readConfig } from "./config-OFOAimzt.mjs";
|
|
4
4
|
import { n as isIdentifier, r as isLiteral } from "./ast-CsZ_q_gc.mjs";
|
|
5
5
|
import { t as MagicString } from "./dist-Cegxq8gs.mjs";
|
|
6
|
-
import { c as voidDbBundlerPlugin, r as cloudflareQueueName, t as generateQueueResolverSource } from "./dispatch-
|
|
6
|
+
import { c as voidDbBundlerPlugin, r as cloudflareQueueName, t as generateQueueResolverSource } from "./dispatch-CLa2LThw.mjs";
|
|
7
7
|
import { t as WORKER_CONDITIONS } from "./worker-conditions-AWFRcFxR.mjs";
|
|
8
8
|
import { createRequire } from "node:module";
|
|
9
9
|
import { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
10
|
-
import { fileURLToPath } from "node:url";
|
|
11
10
|
import { build, parseSync } from "vite";
|
|
11
|
+
import { fileURLToPath } from "node:url";
|
|
12
12
|
import { createHash } from "node:crypto";
|
|
13
13
|
//#region src/cli/worker-require-transform.ts
|
|
14
14
|
function nodes(root) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as StandardSchemaV1 } from "./standard-schema-Fo_vCAZh.mjs";
|
|
2
|
-
import { r as AuthUser } from "./auth-
|
|
3
|
-
import { a as CloudEnv } from "./handler-
|
|
2
|
+
import { r as AuthUser } from "./auth-g2TQbDLD.mjs";
|
|
3
|
+
import { a as CloudEnv } from "./handler-BHktmuTL.mjs";
|
|
4
4
|
import { WebSocketRouteMap } from "void/routes";
|
|
5
5
|
//#region src/runtime/ws.d.ts
|
|
6
6
|
type MaybePromise<T> = T | Promise<T>;
|
|
@@ -125,6 +125,7 @@ declare class VoidSocket<P extends keyof WebSocketRouteMap & string> {
|
|
|
125
125
|
private readonly buffer;
|
|
126
126
|
private reconnectAttempts;
|
|
127
127
|
private closedByUser;
|
|
128
|
+
private reconnectTimer;
|
|
128
129
|
constructor(url: string, options: ConnectCommonOptions);
|
|
129
130
|
private emit;
|
|
130
131
|
private connect;
|
package/docs/guide/auth.md
CHANGED
|
@@ -119,7 +119,7 @@ import { getSession, getUser, requireAuth } from 'void/auth';
|
|
|
119
119
|
- `getSession()` returns `{ user, session } | null`
|
|
120
120
|
- `requireAuth(c)` returns the authenticated user or throws `401`
|
|
121
121
|
|
|
122
|
-
Import `AuthUser` and `AuthSession` from `void/auth` for type annotations. See their fields in the [API reference](../reference/api/auth.md#authuser).
|
|
122
|
+
Import `AuthUser` and `AuthSession` from `void/auth` for type annotations. They include the fields your Better Auth plugins and `user.additionalFields` add, such as `role` from `admin()`. See their fields in the [API reference](../reference/api/auth.md#authuser).
|
|
123
123
|
|
|
124
124
|
## Behavior
|
|
125
125
|
|
|
@@ -51,6 +51,28 @@ Path-only sources apply to every domain on the project. Host-prefixed sources ap
|
|
|
51
51
|
|
|
52
52
|
The source must use `https://` and a literal hostname without wildcards or a port. Add the domain to your project with `void domain add` before deploying the rule. A domain awaiting certificate verification starts redirecting once it becomes active.
|
|
53
53
|
|
|
54
|
+
## HTTP to HTTPS
|
|
55
|
+
|
|
56
|
+
Set `routing.alwaysUseHttps` to redirect HTTP requests to HTTPS:
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
import { defineConfig } from 'void/config';
|
|
60
|
+
|
|
61
|
+
export default defineConfig({
|
|
62
|
+
routing: {
|
|
63
|
+
alwaysUseHttps: true,
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Void answers with a permanent `308` redirect to the same URL over HTTPS. The path, query string, and request method stay the same. Omitted or `false` means off. `localhost` and loopback addresses such as `127.0.0.1` stay on HTTP, so local development and `vite preview` are unchanged.
|
|
69
|
+
|
|
70
|
+
It works on the Void platform and for Void apps on `void deploy --platform cloudflare`. It needs the Cloudflare target: setting it with `target: 'node'`, `'bun'`, or `'deno'` is a config error.
|
|
71
|
+
|
|
72
|
+
On `void deploy --platform cloudflare`, built files with a content hash in their name, such as `/assets/index-abc123.js`, can be served by Cloudflare before Void runs, so they may still answer over HTTP. Pages always redirect, so browsers load these files over HTTPS. To redirect every request, also turn on [Always Use HTTPS](https://developers.cloudflare.com/ssl/edge-certificates/additional-options/always-use-https/) for your Cloudflare zone.
|
|
73
|
+
|
|
74
|
+
SvelteKit, Nuxt, Astro, Analog, TanStack Start, React Router, and vinext apps run their own Worker, so `void deploy --platform cloudflare` stops with an error when the option is on. Static builds of these frameworks, deployed with `--dir` or `inference.appType`, redirect as usual. For the others, redirect to HTTPS in the framework, or turn on [Always Use HTTPS](https://developers.cloudflare.com/ssl/edge-certificates/additional-options/always-use-https/) for your Cloudflare zone.
|
|
75
|
+
|
|
54
76
|
## Framework `_redirects` files
|
|
55
77
|
|
|
56
78
|
Void reads `_redirects` files produced by supported frameworks. You can also place one in Vite's `publicDir`:
|
|
@@ -177,6 +177,30 @@ const form = useForm('/users/:id', { name: '' }, { params: { id: '42' } });
|
|
|
177
177
|
|
|
178
178
|
Create forms often need empty fields again after a successful save. Either pass `resetOnSuccess: true` in the third argument, or call `form.reset({ initial: true })` when `form.wasSuccessful` becomes `true`.
|
|
179
179
|
|
|
180
|
+
### React submission callbacks
|
|
181
|
+
|
|
182
|
+
In React, pass `onSuccess` and `onError` to `useForm()` to respond to a submission:
|
|
183
|
+
|
|
184
|
+
```tsx
|
|
185
|
+
const form = useForm(
|
|
186
|
+
'/users',
|
|
187
|
+
{ name: '', email: '' },
|
|
188
|
+
{
|
|
189
|
+
onSuccess: () => setDialogOpen(false),
|
|
190
|
+
onError: (error) => {
|
|
191
|
+
// A field-error map or VoidActionError for a handled action failure.
|
|
192
|
+
console.error(error);
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
);
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Each submission uses the callbacks from when it was dispatched. Callbacks run inside the React Action, before the updated UI commits. Use an effect or ref callback to focus an element that appears after submission.
|
|
199
|
+
|
|
200
|
+
Callbacks can return `Promise<void>`. The Action awaits them, and `form.pending` stays true until they complete. Errors thrown or rejected by callbacks reach the nearest React error boundary. Aborted submissions invoke neither callback.
|
|
201
|
+
|
|
202
|
+
Vue, Svelte, and Solid submissions return a promise instead; use `await form.post()` to run work after a submission.
|
|
203
|
+
|
|
180
204
|
## Named Actions
|
|
181
205
|
|
|
182
206
|
When a page needs multiple mutations, such as updating and deleting a user on the same page, export `actions` (plural) instead of `action`:
|
|
@@ -100,7 +100,9 @@ Repair recreates missing infrastructure that the installer owns. It does not res
|
|
|
100
100
|
|
|
101
101
|
### Upgrade the platform
|
|
102
102
|
|
|
103
|
-
Keep the platform runtime current when updating the Void CLI.
|
|
103
|
+
Keep the platform runtime current when updating the Void CLI. Upgrade the platform before your team updates its CLI: a newer CLI refuses to work with an older platform and asks for `void platform upgrade`. Install the new CLI on the administrator's machine, run the upgrade below, then have the team update.
|
|
104
|
+
|
|
105
|
+
If the platform will deploy apps that use `void/sandbox`, its runtime token needs **Account → Containers → Edit** and **Account → Cloudchamber → Edit**. A token made from an older setup link may lack them, and an upgrade does not add them. Edit the token in the Cloudflare dashboard, or set `VOID_PLATFORM_RUNTIME_CLOUDFLARE_API_TOKEN` to a new token when you upgrade. See [Cloudflare API Tokens](/guide/platform/installation/credentials#runtime-token-permissions).
|
|
104
106
|
|
|
105
107
|
Use the installed CLI's packaged runtime to upgrade:
|
|
106
108
|
|
package/docs/guide/ssg.md
CHANGED
|
@@ -37,6 +37,14 @@ export async function getPrerenderPaths() {
|
|
|
37
37
|
}
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
+
## 404 pages
|
|
41
|
+
|
|
42
|
+
Static builds that prerender at least one page include a default `404.html` in `dist/client/`. To provide your own, add `public/404.html` or prerender a page at `/404`.
|
|
43
|
+
|
|
44
|
+
Fully static Void deployments serve this page for missing URLs with an HTTP 404 status by default. You can override this with [`routing.notFound`](../reference/config.md#routing-notfound). Hybrid deployments handle missing URLs in the Worker.
|
|
45
|
+
|
|
46
|
+
When hosting `dist/client/` yourself, configure your host to serve `404.html` with a 404 status for missing pages.
|
|
47
|
+
|
|
40
48
|
## Comparison with edge prerendering
|
|
41
49
|
|
|
42
50
|
| `output` value | Default prerender | Per-page override | Prerender timing |
|
|
@@ -133,13 +133,14 @@ Apps using email need `email.from` in `void.config.ts`. Void reviews the domain'
|
|
|
133
133
|
|
|
134
134
|
Set these CI secrets and variables as needed:
|
|
135
135
|
|
|
136
|
-
| Name | When needed
|
|
137
|
-
| ------------------------------------------------ |
|
|
138
|
-
| `CLOUDFLARE_API_TOKEN` | Required. Workers Scripts: Edit, read access to bound resources, and edit access to products Void provisions.
|
|
139
|
-
| `CLOUDFLARE_ACCOUNT_ID` | When the token can access several accounts.
|
|
140
|
-
| `DATABASE_URL` | PostgreSQL and MySQL provisioning and migrations.
|
|
141
|
-
| `CLOUDFLARE_WORKERS_SUBDOMAIN` | When the Worker has no version preview URL. Use `my-team` or `my-team.workers.dev`.
|
|
142
|
-
| `CF_ACCESS_CLIENT_ID`, `CF_ACCESS_CLIENT_SECRET` | When Cloudflare Access protects the readiness URL.
|
|
136
|
+
| Name | When needed |
|
|
137
|
+
| ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------ |
|
|
138
|
+
| `CLOUDFLARE_API_TOKEN` | Required. Workers Scripts: Edit, read access to bound resources, and edit access to products Void provisions. |
|
|
139
|
+
| `CLOUDFLARE_ACCOUNT_ID` | When the token can access several accounts. |
|
|
140
|
+
| `DATABASE_URL` | PostgreSQL and MySQL provisioning and migrations. |
|
|
141
|
+
| `CLOUDFLARE_WORKERS_SUBDOMAIN` | When the Worker has no version preview URL. Use `my-team` or `my-team.workers.dev`. |
|
|
142
|
+
| `CF_ACCESS_CLIENT_ID`, `CF_ACCESS_CLIENT_SECRET` | When Cloudflare Access protects the readiness URL. |
|
|
143
|
+
| `CF_ACCESS_READINESS_ORIGIN` | When Access protects a route or Custom Domain and `workers_dev` is `false`. See [Cloudflare Access](#cloudflare-access). |
|
|
143
144
|
|
|
144
145
|
For email, run `void email setup --platform cloudflare` locally, commit `void.lock.json`, and pass `--require-email` in CI. The token also needs Email Routing Edit and Email Sending Edit.
|
|
145
146
|
|
|
@@ -153,6 +154,14 @@ export CF_ACCESS_TOKEN="$(cloudflared access token --app=https://<worker>.<accou
|
|
|
153
154
|
|
|
154
155
|
Void uses Access credentials for readiness checks without saving them. If checks are denied, the deployment fails. A first-deploy bootstrap can already be active behind Access when this happens.
|
|
155
156
|
|
|
157
|
+
By default, Void sends Access credentials only to `workers.dev` URLs. If `workers_dev` is `false`, Void can check readiness through your first route or Custom Domain. To send the credentials there, set `CF_ACCESS_READINESS_ORIGIN` to that hostname's origin:
|
|
158
|
+
|
|
159
|
+
```sh
|
|
160
|
+
export CF_ACCESS_READINESS_ORIGIN="https://app.example.com"
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Use one exact `https:` origin, without a wildcard or a path. Set the variable in the shell or CI environment that runs `void deploy`. Void ignores a value that `void.config.ts` sets, for example through a dotenv import. Set it only for a hostname that you control and that serves this Worker, because Void sends your Access credentials to it.
|
|
164
|
+
|
|
156
165
|
### Databases and secrets
|
|
157
166
|
|
|
158
167
|
For PostgreSQL and MySQL, supply `DATABASE_URL` to the deploy process. Void uses it for Hyperdrive and migrations without writing it to config. MySQL schema changes can partially apply before an error; see [failed MySQL migrations](../guide/database/mysql.md#failed-migrations).
|
|
@@ -79,7 +79,7 @@ function requireAuth(c: CloudContext): AuthUser;
|
|
|
79
79
|
|
|
80
80
|
## `AuthUser` {#authuser}
|
|
81
81
|
|
|
82
|
-
Better Auth user shape re-exported by Void.
|
|
82
|
+
Better Auth user shape re-exported by Void. It also includes the fields that Better Auth plugins and `user.additionalFields` in `auth.ts` add, for example `role` from `admin()` or a custom `plan` field. Your tsconfig needs the generated Void types for this; see [Type Safety setup](../../guide/type-safety.md#setup).
|
|
83
83
|
|
|
84
84
|
```ts
|
|
85
85
|
interface AuthUser {
|
|
@@ -95,7 +95,7 @@ interface AuthUser {
|
|
|
95
95
|
|
|
96
96
|
## `AuthSession` {#authsession}
|
|
97
97
|
|
|
98
|
-
Better Auth session shape re-exported by Void.
|
|
98
|
+
Better Auth session shape re-exported by Void. It also includes the session fields that Better Auth plugins in `auth.ts` add, for example `impersonatedBy` from `admin()`.
|
|
99
99
|
|
|
100
100
|
```ts
|
|
101
101
|
interface AuthSession {
|
|
@@ -110,6 +110,10 @@ interface AuthSession {
|
|
|
110
110
|
}
|
|
111
111
|
```
|
|
112
112
|
|
|
113
|
+
::: tip Types inside `auth.ts`
|
|
114
|
+
`AuthUser` and `AuthSession` are built from `auth.ts`. Inside `auth.ts` and the files it imports, don't use them, or values from `getUser()`, `getSession()` and `requireAuth()`, to type a hook's parameters or returned data. TypeScript reports a circular reference and the extra fields are lost. Let Better Auth infer those types, or use its own `User` and `Session` types. Better Auth callbacks such as `sendResetPassword` pass its base `User`, without plugin fields.
|
|
115
|
+
:::
|
|
116
|
+
|
|
113
117
|
## `AuthState` {#authstate}
|
|
114
118
|
|
|
115
119
|
Combined authenticated request state:
|
|
@@ -33,7 +33,10 @@ Use `prepareCfBuildOutput` to convert an existing Cloudflare Worker build into a
|
|
|
33
33
|
```ts
|
|
34
34
|
import { prepareCfBuildOutput } from 'void/deploy';
|
|
35
35
|
|
|
36
|
-
const prepared = await prepareCfBuildOutput('/path/to/app/dist/server', {
|
|
36
|
+
const prepared = await prepareCfBuildOutput('/path/to/app/dist/server', {
|
|
37
|
+
projectRoot: '/path/to/app',
|
|
38
|
+
mode: 'staging',
|
|
39
|
+
});
|
|
37
40
|
if (!prepared) {
|
|
38
41
|
throw new Error('The Worker build could not be prepared.');
|
|
39
42
|
}
|
|
@@ -47,9 +50,10 @@ try {
|
|
|
47
50
|
|
|
48
51
|
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
52
|
|
|
50
|
-
| Option
|
|
51
|
-
|
|
|
52
|
-
| `accountId`
|
|
53
|
-
| `mode`
|
|
53
|
+
| Option | Description |
|
|
54
|
+
| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
55
|
+
| `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. |
|
|
56
|
+
| `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`. |
|
|
57
|
+
| `projectRoot` | App directory containing `package.json` and its installed dependencies. Defaults to the input directory. |
|
|
54
58
|
|
|
55
59
|
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.
|
|
@@ -109,6 +109,8 @@ Imported from `"@void/react"`.
|
|
|
109
109
|
|
|
110
110
|
React `Link` GET `data` is merged into the rendered `href` query string. Primitive values are serialized with `String(value)`, arrays become repeated keys, `null` and `undefined` are omitted, and nested objects throw. `prefetch` and `reloadDocument` are GET-only and throw for mutation links.
|
|
111
111
|
|
|
112
|
+
React `useForm()` options accept `onSuccess?: () => void | Promise<void>` and `onError?: (error: Record<string, string> | VoidActionError) => void | Promise<void>`. Each submission captures its callbacks, runs them before the updated UI commits, and awaits any returned promise. See [submission callbacks](../../guide/pages-routing/actions-and-forms.md#react-submission-callbacks).
|
|
113
|
+
|
|
112
114
|
React deferred props returned from `defer()` are Suspense resources. Read them
|
|
113
115
|
with React's `use()` inside a `<Suspense>` boundary. React Pages requires React
|
|
114
116
|
19 and uses streaming SSR for the initial deferred shell. Rejections throw from
|
|
@@ -86,15 +86,16 @@ void deploy --platform cloudflare --require-email # fail instead of deploying
|
|
|
86
86
|
|
|
87
87
|
Void signs you in through your browser when needed and saves the selected account. In CI, set `CLOUDFLARE_API_TOKEN` and, if the token can access several accounts, `CLOUDFLARE_ACCOUNT_ID`.
|
|
88
88
|
|
|
89
|
-
| Option or setting | Cloudflare behavior
|
|
90
|
-
| ------------------------------ |
|
|
91
|
-
| `--dir`, `--spa` | Deploy static output through a small Worker and Workers Assets
|
|
92
|
-
| `--skip-build` | Reuse existing static, SPA, or SSG output; unavailable for Worker apps
|
|
93
|
-
| `--project` | Unavailable; the Worker and account come from `void.config.ts` and `void.lock.json`
|
|
94
|
-
| Named environments | Unavailable; use the top-level `cloudflare` config
|
|
95
|
-
| `CLOUDFLARE_WORKERS_SUBDOMAIN` | Needed in fresh CI when versions have no preview URL; cached locally after a deploy
|
|
96
|
-
|
|
|
97
|
-
| `
|
|
89
|
+
| Option or setting | Cloudflare behavior |
|
|
90
|
+
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------- |
|
|
91
|
+
| `--dir`, `--spa` | Deploy static output through a small Worker and Workers Assets |
|
|
92
|
+
| `--skip-build` | Reuse existing static, SPA, or SSG output; unavailable for Worker apps |
|
|
93
|
+
| `--project` | Unavailable; the Worker and account come from `void.config.ts` and `void.lock.json` |
|
|
94
|
+
| Named environments | Unavailable; use the top-level `cloudflare` config |
|
|
95
|
+
| `CLOUDFLARE_WORKERS_SUBDOMAIN` | Needed in fresh CI when versions have no preview URL; cached locally after a deploy |
|
|
96
|
+
| `CF_ACCESS_READINESS_ORIGIN` | Lets Access credentials reach the readiness check on a route or Custom Domain, for example `https://app.example.com` |
|
|
97
|
+
| `--require-email` | Fail instead of deploying without email when the email step cannot run, as in CI |
|
|
98
|
+
| `DATABASE_URL` | Required in the deploy environment for PostgreSQL or MySQL provisioning and migrations |
|
|
98
99
|
|
|
99
100
|
The token needs Workers Scripts: Edit, read access to bound resources, and edit access to products Void provisions. Commit `void.lock.json` after the first deploy before using other machines or CI.
|
|
100
101
|
|
package/docs/reference/config.md
CHANGED
|
@@ -297,7 +297,7 @@ Void-managed WebSocket route files (`*.ws.ts`) are Cloudflare-only because they
|
|
|
297
297
|
|
|
298
298
|
### `worker`
|
|
299
299
|
|
|
300
|
-
Curated Cloudflare Workers configuration. `void init` pins `compatibility_date` here. Binding arrays such as `d1_databases`, `kv_namespaces`, and `r2_buckets` go in [`cloudflare`](#cloudflare), where Void preserves custom settings and resolved IDs during deployment.
|
|
300
|
+
Curated Cloudflare Workers configuration. `void init` pins `compatibility_date` here. If a project has no config file and no date, the first dev server or build creates `void.config.ts` with only this date and adds `.void-wrangler.jsonc` to `.gitignore`. Astro, SvelteKit, Nuxt, and Analog apps get the date in a root `wrangler.jsonc` instead, which their adapter reads by default. A project with a `wrangler.toml` gets it in `void.json`. Binding arrays such as `d1_databases`, `kv_namespaces`, and `r2_buckets` go in [`cloudflare`](#cloudflare), where Void preserves custom settings and resolved IDs during deployment.
|
|
301
301
|
|
|
302
302
|
| Field | Type | Description |
|
|
303
303
|
| --------------------- | ---------- | -------------------------------------- |
|
|
@@ -366,6 +366,16 @@ This choice applies to subsequent `void deploy` runs. Atomic deployment sends tr
|
|
|
366
366
|
|
|
367
367
|
Routing and edge configuration for headers, redirects, rewrites, and caching.
|
|
368
368
|
|
|
369
|
+
#### `routing.alwaysUseHttps`
|
|
370
|
+
|
|
371
|
+
Redirect HTTP requests to HTTPS with a permanent `308` redirect. Omitted or `false` means off. Requires the Cloudflare target. `localhost` stays on HTTP. See [HTTP to HTTPS](../guide/edge/redirects#http-to-https) for where it works.
|
|
372
|
+
|
|
373
|
+
```ts
|
|
374
|
+
routing: {
|
|
375
|
+
alwaysUseHttps: true,
|
|
376
|
+
}
|
|
377
|
+
```
|
|
378
|
+
|
|
369
379
|
#### `routing.headers`
|
|
370
380
|
|
|
371
381
|
Custom response headers. Keys are URL patterns, values are arrays of `"Name: value"` strings. See [Custom Headers](../guide/edge/headers) for details.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "void",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Full-stack framework and deployment CLI for Cloudflare Workers, powered by Vite.",
|
|
5
5
|
"homepage": "https://void.cloud",
|
|
6
6
|
"bugs": {
|
|
@@ -348,12 +348,13 @@
|
|
|
348
348
|
"@cloudflare/vite-plugin": "^1.64.0",
|
|
349
349
|
"@cloudflare/workers-auth": "^0.14.1",
|
|
350
350
|
"@cloudflare/workers-types": "^5.20261019.1",
|
|
351
|
+
"@cloudflare/workers-utils": "^0.47.3",
|
|
351
352
|
"@napi-rs/keyring": "^2.1.2",
|
|
352
|
-
"@void/deploy-cloudflare": "1.
|
|
353
|
-
"@void/deploy-core": "1.
|
|
354
|
-
"@void/edge": "1.
|
|
355
|
-
"@void/isr": "1.
|
|
356
|
-
"@void/platform": "1.
|
|
353
|
+
"@void/deploy-cloudflare": "1.4.0",
|
|
354
|
+
"@void/deploy-core": "1.4.0",
|
|
355
|
+
"@void/edge": "1.4.0",
|
|
356
|
+
"@void/isr": "1.4.0",
|
|
357
|
+
"@void/platform": "1.4.0",
|
|
357
358
|
"better-auth": "^1.7.11",
|
|
358
359
|
"better-sqlite3": "^13.0.3",
|
|
359
360
|
"blake3-jit": "^1.1.0",
|
|
@@ -402,7 +403,7 @@
|
|
|
402
403
|
"zod": "^4.6.7"
|
|
403
404
|
},
|
|
404
405
|
"peerDependencies": {
|
|
405
|
-
"@void/md": "1.
|
|
406
|
+
"@void/md": "1.4.0",
|
|
406
407
|
"arktype": ">=2.0.0",
|
|
407
408
|
"valibot": ">=1.0.0-beta.7",
|
|
408
409
|
"vite": "^8.0.0",
|
package/schema.json
CHANGED
|
@@ -144,6 +144,10 @@
|
|
|
144
144
|
"type": "object",
|
|
145
145
|
"description": "Routing configuration — headers, redirects, rewrites, fallbacks, revalidation, prerendering.",
|
|
146
146
|
"properties": {
|
|
147
|
+
"alwaysUseHttps": {
|
|
148
|
+
"type": "boolean",
|
|
149
|
+
"description": "Redirect HTTP requests to HTTPS with a permanent 308 redirect. Omitted or false means off. Requires the Cloudflare target; localhost stays on HTTP."
|
|
150
|
+
},
|
|
147
151
|
"isr": {
|
|
148
152
|
"type": "boolean",
|
|
149
153
|
"description": "Enable inferred ISR caching. Set false to disable ISR and edge prerendering, including per-page prerender and revalidate policies. Does not disable output: static build-time prerendering."
|
package/skills/void/SKILL.md
CHANGED
|
@@ -49,7 +49,7 @@ the app's existing saved destination, including when the target project is new.
|
|
|
49
49
|
| Email | `docs/guide/email.md`, then the matching guide under `docs/guide/email/` |
|
|
50
50
|
| KV / storage / queues / cron jobs | `docs/guide/kv.md`, `docs/guide/storage.md`, `docs/guide/queues.md`, `docs/guide/jobs.md` |
|
|
51
51
|
| SSR and caching | `docs/guide/ssr.md`, `docs/guide/edge/*.md` |
|
|
52
|
-
|
|
|
52
|
+
| HTTPS, rewrites, redirects, fallbacks | `docs/guide/edge/rewrites.md`, `docs/guide/edge/redirects.md`, `docs/reference/config.md` |
|
|
53
53
|
| Static site generation | `docs/guide/ssg.md` |
|
|
54
54
|
| Connected apps and artifact preparation | `docs/guide/platform/administration/connected-apps.md`, `docs/reference/api/deploy.md` |
|
|
55
55
|
| Deployment and CI | `docs/guide/deployment.md`, `docs/reference/cli/deploy.md` |
|
package/dist/auth-DkcFflXV.d.mts
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
-
import { BetterAuthOptions, Session, User } from "better-auth";
|
|
3
|
-
import { Context, Env } from "hono";
|
|
4
|
-
//#region src/runtime/auth.d.ts
|
|
5
|
-
type AuthUser = User;
|
|
6
|
-
type AuthSession = Session;
|
|
7
|
-
type AuthState = {
|
|
8
|
-
session: AuthSession;
|
|
9
|
-
user: AuthUser;
|
|
10
|
-
};
|
|
11
|
-
type VoidAuthConfigContext = {
|
|
12
|
-
defaults: BetterAuthOptions;
|
|
13
|
-
env: Record<string, unknown>;
|
|
14
|
-
dialect: "sqlite" | "postgresql" | "mysql";
|
|
15
|
-
request: Request;
|
|
16
|
-
};
|
|
17
|
-
type VoidAuthConfig = BetterAuthOptions | ((ctx: VoidAuthConfigContext) => BetterAuthOptions);
|
|
18
|
-
/**
|
|
19
|
-
* Shared AsyncLocalStorage that holds the authenticated Better Auth state for the
|
|
20
|
-
* current request.
|
|
21
|
-
*
|
|
22
|
-
* Stored on `globalThis` under a `Symbol.for` key so duplicate module loads
|
|
23
|
-
* (e.g. once by void's bundled runtime and once by Vite's SSR module runner
|
|
24
|
-
* when user code imports from `void/auth`) share a single ALS instance. Without
|
|
25
|
-
* this, the middleware writes to one instance and `getUser()` reads another,
|
|
26
|
-
* always returning null.
|
|
27
|
-
*/
|
|
28
|
-
type AuthContextStore = {
|
|
29
|
-
user: AuthUser | null;
|
|
30
|
-
state: AuthState | null;
|
|
31
|
-
};
|
|
32
|
-
declare const authContext: AsyncLocalStorage<AuthContextStore>;
|
|
33
|
-
declare function defineAuth<T extends VoidAuthConfig>(config: T): T;
|
|
34
|
-
declare function getUser(): AuthUser | null;
|
|
35
|
-
declare function getSession(): AuthState | null;
|
|
36
|
-
declare function requireAuth<E extends Env & {
|
|
37
|
-
Variables: {
|
|
38
|
-
user: AuthUser | null;
|
|
39
|
-
};
|
|
40
|
-
}>(c: Context<E>): AuthUser;
|
|
41
|
-
//#endregion
|
|
42
|
-
export { VoidAuthConfigContext as a, getSession as c, VoidAuthConfig as i, getUser as l, AuthState as n, authContext as o, AuthUser as r, defineAuth as s, AuthSession as t, requireAuth as u };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { t as prepareCfBuildOutput } from "./cf-build-output-Bapzc_8Z.mjs";
|
package/dist/client-DyxPQnF_.mjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { r as PlatformClient } from "./client-BEMtySaV.mjs";
|
package/dist/config-BTu1o3Dc.mjs
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { n as readProjectPaths } from "./project-paths-DGu_QZ_Q.mjs";
|
|
2
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
3
|
-
import { pathToFileURL } from "node:url";
|
|
4
|
-
import { isRunnableDevEnvironment, parseSync } from "vite";
|
|
5
|
-
//#region src/auth/config.ts
|
|
6
|
-
function isVoidAuthConfigSource(code, filename) {
|
|
7
|
-
if (!code.includes("void/auth")) return false;
|
|
8
|
-
let program;
|
|
9
|
-
try {
|
|
10
|
-
program = parseSync(filename, code).program;
|
|
11
|
-
} catch {
|
|
12
|
-
return false;
|
|
13
|
-
}
|
|
14
|
-
return (program.body ?? []).some((node) => {
|
|
15
|
-
if (node.type !== "ImportDeclaration" && node.type !== "ExportNamedDeclaration" && node.type !== "ExportAllDeclaration") return false;
|
|
16
|
-
return node.source?.value === "void/auth";
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
function findVoidAuthConfig(root, paths = readProjectPaths(root)) {
|
|
20
|
-
for (const absPath of paths.authConfigCandidates) {
|
|
21
|
-
if (!existsSync(absPath)) continue;
|
|
22
|
-
if (isVoidAuthConfigSource(readFileSync(absPath, "utf-8"), absPath)) return absPath;
|
|
23
|
-
}
|
|
24
|
-
return null;
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* The dev server evaluates the auth config in this Node environment. A native
|
|
28
|
-
* `import()` would keep the first evaluation for the life of the process; the
|
|
29
|
-
* module runner reads the config again once its files are invalidated, and the
|
|
30
|
-
* module graph lists the local files the config imports.
|
|
31
|
-
*/
|
|
32
|
-
const AUTH_CONFIG_ENVIRONMENT = "void_auth_config";
|
|
33
|
-
/** The dev server's importer for the auth config, when it has the environment. */
|
|
34
|
-
function devAuthConfigImporter(server) {
|
|
35
|
-
const environment = server.environments[AUTH_CONFIG_ENVIRONMENT];
|
|
36
|
-
return environment && isRunnableDevEnvironment(environment) ? (path) => environment.runner.import(path) : void 0;
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Evaluate the auth config. A native `import()` keeps its first evaluation for
|
|
40
|
-
* the life of the process, which suits one-off commands; the dev server passes
|
|
41
|
-
* its module runner.
|
|
42
|
-
*/
|
|
43
|
-
async function loadVoidAuthConfig(configPath, importModule = (path) => import(pathToFileURL(path).href)) {
|
|
44
|
-
if (!configPath) return;
|
|
45
|
-
const mod = await importModule(configPath);
|
|
46
|
-
return mod.default ?? mod.auth ?? mod.config;
|
|
47
|
-
}
|
|
48
|
-
//#endregion
|
|
49
|
-
export { loadVoidAuthConfig as i, devAuthConfigImporter as n, findVoidAuthConfig as r, AUTH_CONFIG_ENVIRONMENT as t };
|
package/dist/deploy-CtHE2A3R.mjs
DELETED
package/dist/gen-TgXy93Rr.mjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { r as runGenCommand } from "./gen-CCx3t2Ju.mjs";
|