void 0.9.3 → 0.10.2

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 (104) hide show
  1. package/dist/{auth-cmd-CPkWrQR9.mjs → auth-cmd-DLvXvN-0.mjs} +2 -2
  2. package/dist/{better-auth-shared-CmEQZs1T.d.mts → better-auth-shared-a7H3wk9J.d.mts} +2 -2
  3. package/dist/{cache-1SVxZ7BK.mjs → cache-CHFZmqa5.mjs} +1 -1
  4. package/dist/{cancel-deploy-JaFClLr7.mjs → cancel-deploy-BwpT4U4a.mjs} +1 -1
  5. package/dist/cli/cli.mjs +273 -36
  6. package/dist/{client-DIfOFf1W.mjs → client-CTHvucDv.mjs} +166 -45
  7. package/dist/{create-project-DCUrFJxa.mjs → create-project-CruTH_TQ.mjs} +1 -1
  8. package/dist/{db-UW4IYQFw.mjs → db-BxnfKs7f.mjs} +14 -14
  9. package/dist/{delete-CYknzwXU.mjs → delete-IQe1O4Re.mjs} +1 -1
  10. package/dist/{deploy-RQXpVBL-.mjs → deploy-CuxXxVgz.mjs} +195 -89
  11. package/dist/{domain-B7RntQ1r.mjs → domain-Bq6kzr_T.mjs} +1 -1
  12. package/dist/{env-C_ZcxxED.mjs → env-BD3U_0Av.mjs} +1 -1
  13. package/dist/{env-helpers-Bd2wVdxz.d.mts → env-helpers-ZatKyjen.d.mts} +1 -1
  14. package/dist/{gen-O5mXZ76K.mjs → gen-Dgi4D7GC.mjs} +1 -1
  15. package/dist/git-metadata-Ce0AtSZL.mjs +82 -0
  16. package/dist/github-cmd-CD0Z8KCF.mjs +441 -0
  17. package/dist/{handler-hm9KldPP.d.mts → handler-DczZlaXR.d.mts} +3 -3
  18. package/dist/index.d.mts +3 -3
  19. package/dist/index.mjs +18 -18
  20. package/dist/{init-DGrLx2ls.mjs → init-CTe46nIr.mjs} +113 -77
  21. package/dist/{link-7MoXUMaI.mjs → link-BGFW4pHD.mjs} +2 -2
  22. package/dist/{list-N2mCHv8q.mjs → list-CbGxdbe7.mjs} +1 -1
  23. package/dist/{login-tt1OmNVg.mjs → login-v4wle1vn.mjs} +1 -1
  24. package/dist/{logs-Cl7q2CjZ.mjs → logs-BFgY5Vqc.mjs} +1 -1
  25. package/dist/{mcp-BXD35N2J.mjs → mcp-STKL-uWs.mjs} +1 -1
  26. package/dist/{node-Df8UjQ2H.mjs → node-B07cZs0d.mjs} +3 -3
  27. package/dist/pages/client.d.mts +1 -1
  28. package/dist/pages/client.mjs +1 -0
  29. package/dist/pages/head-client.d.mts +1 -1
  30. package/dist/pages/head.d.mts +1 -1
  31. package/dist/pages/index.d.mts +2 -2
  32. package/dist/pages/index.mjs +1 -1
  33. package/dist/pages/islands-plugin.d.mts +1 -1
  34. package/dist/pages/protocol.d.mts +2 -2
  35. package/dist/pages/protocol.mjs +1 -1
  36. package/dist/{plugin-inference--7geW5Z2.mjs → plugin-inference-C3fLzFvP.mjs} +2 -0
  37. package/dist/{prepare-DT-7QII_.mjs → prepare-DH2WnEpD.mjs} +3 -3
  38. package/dist/{preset-2aBxMfY1.mjs → preset-B7ZQZn0u.mjs} +2 -2
  39. package/dist/{project-cmd-CLrqSbqj.mjs → project-cmd-DZh-vbEL.mjs} +8 -8
  40. package/dist/{protocol-B9GZA4Bn.d.mts → protocol-63PHtCHS.d.mts} +3 -3
  41. package/dist/{rollback-CEbAwbHK.mjs → rollback-o0M0Qo_n.mjs} +1 -1
  42. package/dist/{runner-DLZ9E_cX.mjs → runner-BQyKUqAL.mjs} +1 -1
  43. package/dist/runtime/ai.mjs +1 -1
  44. package/dist/runtime/auth.d.mts +1 -1
  45. package/dist/runtime/better-auth-pg.d.mts +1 -1
  46. package/dist/runtime/better-auth-pg.mjs +3 -3
  47. package/dist/runtime/better-auth.d.mts +1 -1
  48. package/dist/runtime/better-auth.mjs +2 -2
  49. package/dist/runtime/client-react.d.mts +2 -2
  50. package/dist/runtime/client-react.mjs +1 -1
  51. package/dist/runtime/client-solid.d.mts +2 -2
  52. package/dist/runtime/client-solid.mjs +1 -1
  53. package/dist/runtime/client-svelte.d.mts +2 -2
  54. package/dist/runtime/client-svelte.mjs +1 -1
  55. package/dist/runtime/client-vue.d.mts +2 -2
  56. package/dist/runtime/client-vue.mjs +1 -1
  57. package/dist/runtime/client.d.mts +2 -2
  58. package/dist/runtime/client.mjs +1 -1
  59. package/dist/runtime/env-helpers.d.mts +1 -1
  60. package/dist/runtime/env-public-client.d.mts +1 -1
  61. package/dist/runtime/env-public.d.mts +2 -2
  62. package/dist/runtime/env-public.mjs +1 -1
  63. package/dist/runtime/env.mjs +1 -1
  64. package/dist/runtime/fetch-stream.d.mts +1 -1
  65. package/dist/runtime/fetch-stream.mjs +1 -1
  66. package/dist/runtime/fetch.d.mts +1 -1
  67. package/dist/runtime/fetch.mjs +1 -1
  68. package/dist/runtime/handler.d.mts +1 -1
  69. package/dist/runtime/handler.mjs +1 -1
  70. package/dist/runtime/isr.mjs +1 -1
  71. package/dist/runtime/live.d.mts +2 -2
  72. package/dist/runtime/live.mjs +1 -1
  73. package/dist/runtime/migration-handler-pg.mjs +1 -1
  74. package/dist/runtime/sandbox.mjs +1 -1
  75. package/dist/runtime/validator.d.mts +1 -1
  76. package/dist/runtime/ws-server.d.mts +2 -2
  77. package/dist/runtime/ws.d.mts +3 -3
  78. package/dist/{scan-B2H1Vo2C.mjs → scan-DGEp1-1Q.mjs} +17 -9
  79. package/dist/{secret-C_uTY7xx.mjs → secret-gs_yyGZL.mjs} +1 -1
  80. package/package.json +2 -2
  81. package/schema.json +3 -3
  82. package/skills/void/docs/guide/deployment.md +26 -11
  83. package/skills/void/docs/guide/edge/headers.md +10 -3
  84. package/skills/void/docs/guide/edge/rewrites.md +5 -5
  85. package/skills/void/docs/reference/cli.md +89 -2
  86. /package/dist/{auth-migrations-CuQkjjWE.mjs → auth-migrations-BP-hMzYl.mjs} +0 -0
  87. /package/dist/{auth-CDeb2XAl.d.mts → auth-nEUVHuFI.d.mts} +0 -0
  88. /package/dist/{better-auth-shared-QAfk8CAS.mjs → better-auth-shared-D0Mbmx5V.mjs} +0 -0
  89. /package/dist/{defer-CouVukrf.mjs → defer-C-bdSM_b.mjs} +0 -0
  90. /package/dist/{drizzle-DYstYz0j.mjs → drizzle-DqstQTGq.mjs} +0 -0
  91. /package/dist/{env-raw-RDkMnSTC.mjs → env-raw-Dtj1UAoK.mjs} +0 -0
  92. /package/dist/{fetch-error-CimrygMq.d.mts → fetch-error-BQMdPvge.d.mts} +0 -0
  93. /package/dist/{fetch-error-BFIoojjf.mjs → fetch-error-C6qffTl2.mjs} +0 -0
  94. /package/dist/{head-BsSTGnIe.d.mts → head-JAH2l3fg.d.mts} +0 -0
  95. /package/dist/{headers-VkAnACKX.mjs → headers-BNWymgnH.mjs} +0 -0
  96. /package/dist/{package-json-B2TD0JLu.mjs → package-json-Bg_GJdJB.mjs} +0 -0
  97. /package/dist/{pg-CMZ_5wsC.mjs → pg-CempqvEJ.mjs} +0 -0
  98. /package/dist/{providers-3Kkv63Ha.d.mts → providers-BkiAlEad.d.mts} +0 -0
  99. /package/dist/{runner-pg-Cv9V7ydr.mjs → runner-pg-BAheiT6v.mjs} +0 -0
  100. /package/dist/{skills-BRKc--As.mjs → skills--OMgLmXW.mjs} +0 -0
  101. /package/dist/{standard-schema-Dnsh2vnl.d.mts → standard-schema-BCBv-QaP.d.mts} +0 -0
  102. /package/dist/{subcommand-prompt-OD-x_Tsm.mjs → subcommand-prompt-ClwpLlKD.mjs} +0 -0
  103. /package/dist/{types-DEWCqHtl.d.mts → types-BnHMXezo.d.mts} +0 -0
  104. /package/dist/{yarn-pnp-0SwYgQxx.mjs → yarn-pnp-DhCHHLAz.mjs} +0 -0
@@ -1,6 +1,6 @@
1
- import { n as AuthState, r as AuthUser, t as AuthSession } from "../auth-CDeb2XAl.mjs";
1
+ import { n as AuthState, r as AuthUser, t as AuthSession } from "../auth-nEUVHuFI.mjs";
2
2
  import { auth, createAuthClient } from "./auth-client-vue.mjs";
3
- import { t as FetchError } from "../fetch-error-CimrygMq.mjs";
3
+ import { t as FetchError } from "../fetch-error-BQMdPvge.mjs";
4
4
  import { fetch } from "./fetch.mjs";
5
5
  import { fetchStream } from "./fetch-stream.mjs";
6
6
  export { type AuthSession, type AuthState, type AuthUser, FetchError, FetchError as StreamError, auth, createAuthClient, fetch, fetchStream };
@@ -1,4 +1,4 @@
1
- import { t as FetchError } from "../fetch-error-BFIoojjf.mjs";
1
+ import { t as FetchError } from "../fetch-error-C6qffTl2.mjs";
2
2
  import { fetch } from "./fetch.mjs";
3
3
  import { fetchStream } from "./fetch-stream.mjs";
4
4
  import { auth, createAuthClient } from "./auth-client-vue.mjs";
@@ -1,6 +1,6 @@
1
- import { n as AuthState, r as AuthUser, t as AuthSession } from "../auth-CDeb2XAl.mjs";
1
+ import { n as AuthState, r as AuthUser, t as AuthSession } from "../auth-nEUVHuFI.mjs";
2
2
  import { auth, createAuthClient } from "./auth-client.mjs";
3
- import { t as FetchError } from "../fetch-error-CimrygMq.mjs";
3
+ import { t as FetchError } from "../fetch-error-BQMdPvge.mjs";
4
4
  import { fetch } from "./fetch.mjs";
5
5
  import { fetchStream } from "./fetch-stream.mjs";
6
6
  export { type AuthSession, type AuthState, type AuthUser, FetchError, FetchError as StreamError, auth, createAuthClient, fetch, fetchStream };
@@ -1,4 +1,4 @@
1
- import { t as FetchError } from "../fetch-error-BFIoojjf.mjs";
1
+ import { t as FetchError } from "../fetch-error-C6qffTl2.mjs";
2
2
  import { fetch } from "./fetch.mjs";
3
3
  import { fetchStream } from "./fetch-stream.mjs";
4
4
  import { auth, createAuthClient } from "./auth-client.mjs";
@@ -1,2 +1,2 @@
1
- import { a as getSecretOverride, c as oneOf, i as email, l as string, n as SECRET_OVERRIDE_SYMBOL, o as json, r as boolean, s as number, t as EnvSchema, u as url } from "../env-helpers-Bd2wVdxz.mjs";
1
+ import { a as getSecretOverride, c as oneOf, i as email, l as string, n as SECRET_OVERRIDE_SYMBOL, o as json, r as boolean, s as number, t as EnvSchema, u as url } from "../env-helpers-ZatKyjen.mjs";
2
2
  export { EnvSchema, SECRET_OVERRIDE_SYMBOL, boolean, email, getSecretOverride, json, number, oneOf, string, url };
@@ -1,4 +1,4 @@
1
- import { c as oneOf, i as email, l as string, o as json, r as boolean, s as number, t as EnvSchema, u as url } from "../env-helpers-Bd2wVdxz.mjs";
1
+ import { c as oneOf, i as email, l as string, o as json, r as boolean, s as number, t as EnvSchema, u as url } from "../env-helpers-ZatKyjen.mjs";
2
2
 
3
3
  //#region src/runtime/env-public-client.d.ts
4
4
  declare const env: Record<string, unknown>;
@@ -1,6 +1,6 @@
1
1
  /// <reference types="@cloudflare/workers-types" />
2
- import { t as StandardSchemaV1 } from "../standard-schema-Dnsh2vnl.mjs";
3
- import { c as oneOf, i as email, l as string, o as json, r as boolean, s as number, t as EnvSchema, u as url } from "../env-helpers-Bd2wVdxz.mjs";
2
+ import { t as StandardSchemaV1 } from "../standard-schema-BCBv-QaP.mjs";
3
+ import { c as oneOf, i as email, l as string, o as json, r as boolean, s as number, t as EnvSchema, u as url } from "../env-helpers-ZatKyjen.mjs";
4
4
  import * as _$_cloudflare_sandbox0 from "@cloudflare/sandbox";
5
5
 
6
6
  //#region src/runtime/env-public.d.ts
@@ -1,4 +1,4 @@
1
- import { i as getRawRuntimeEnv } from "../env-raw-RDkMnSTC.mjs";
1
+ import { i as getRawRuntimeEnv } from "../env-raw-Dtj1UAoK.mjs";
2
2
  import { getRuntimeEnv } from "./env.mjs";
3
3
  import { boolean, email, getSecretOverride, json, number, oneOf, string, url } from "./env-helpers.mjs";
4
4
  //#region src/shared/env-mask.ts
@@ -1,4 +1,4 @@
1
- import { i as getRawRuntimeEnv, n as asEnv, r as envContext, t as INTERNAL_BINDING_PREFIXES } from "../env-raw-RDkMnSTC.mjs";
1
+ import { i as getRawRuntimeEnv, n as asEnv, r as envContext, t as INTERNAL_BINDING_PREFIXES } from "../env-raw-Dtj1UAoK.mjs";
2
2
  //#region src/runtime/env.ts
3
3
  /**
4
4
  * Public runtime env API — exposed via "void/_env".
@@ -1,4 +1,4 @@
1
- import { t as FetchError } from "../fetch-error-CimrygMq.mjs";
1
+ import { t as FetchError } from "../fetch-error-BQMdPvge.mjs";
2
2
  import { RouteMap } from "void/routes";
3
3
 
4
4
  //#region src/runtime/fetch-stream.d.ts
@@ -1,4 +1,4 @@
1
- import { n as ofetch, t as FetchError } from "../fetch-error-BFIoojjf.mjs";
1
+ import { n as ofetch, t as FetchError } from "../fetch-error-C6qffTl2.mjs";
2
2
  //#region src/runtime/fetch-stream.ts
3
3
  /**
4
4
  * Consume an SSE endpoint as an async generator of text chunks.
@@ -1,4 +1,4 @@
1
- import { t as FetchError } from "../fetch-error-CimrygMq.mjs";
1
+ import { t as FetchError } from "../fetch-error-BQMdPvge.mjs";
2
2
  import { RouteMap } from "void/routes";
3
3
 
4
4
  //#region src/runtime/fetch.d.ts
@@ -1,4 +1,4 @@
1
- import { n as ofetch, t as FetchError } from "../fetch-error-BFIoojjf.mjs";
1
+ import { n as ofetch, t as FetchError } from "../fetch-error-C6qffTl2.mjs";
2
2
  //#region src/runtime/fetch.ts
3
3
  async function fetch(path, options) {
4
4
  let url = path;
@@ -1,3 +1,3 @@
1
1
  /// <reference types="@cloudflare/workers-types" />
2
- import { C as defer, E as ValidatorSlots, S as InferProps, T as HandlerInput, _ as defineQueue, a as CloudEnv, b as Deferred, c as QueueRetryOptions, d as TypedQueueHandler, f as VoidAssetRewriteError, g as defineMiddleware, h as defineHead, i as CloudContextVariables, l as RenderAssetTags, m as defineHandler, n as CloudBindings, o as QueueBatch, p as basicAuth, r as CloudContext, s as QueueMessage, t as BasicAuthOptions, u as TypedHandler, v as defineRender, w as ValidationError, y as defineScheduled } from "../handler-hm9KldPP.mjs";
2
+ import { C as defer, E as ValidatorSlots, S as InferProps, T as HandlerInput, _ as defineQueue, a as CloudEnv, b as Deferred, c as QueueRetryOptions, d as TypedQueueHandler, f as VoidAssetRewriteError, g as defineMiddleware, h as defineHead, i as CloudContextVariables, l as RenderAssetTags, m as defineHandler, n as CloudBindings, o as QueueBatch, p as basicAuth, r as CloudContext, s as QueueMessage, t as BasicAuthOptions, u as TypedHandler, v as defineRender, w as ValidationError, y as defineScheduled } from "../handler-DczZlaXR.mjs";
3
3
  export { BasicAuthOptions, CloudBindings, CloudContext, CloudContextVariables, CloudEnv, Deferred, HandlerInput, InferProps, QueueBatch, QueueMessage, QueueRetryOptions, RenderAssetTags, TypedHandler, TypedQueueHandler, ValidationError, ValidatorSlots, VoidAssetRewriteError, basicAuth, defer, defineHandler, defineHead, defineMiddleware, defineQueue, defineRender, defineScheduled };
@@ -1,6 +1,6 @@
1
1
  import { convertReturnValue } from "./response.mjs";
2
2
  import { runValidation } from "./validator.mjs";
3
- import { i as ValidationError, n as defer } from "../defer-CouVukrf.mjs";
3
+ import { i as ValidationError, n as defer } from "../defer-C-bdSM_b.mjs";
4
4
  //#region src/runtime/handler.ts
5
5
  /**
6
6
  * Thrown when `c.rewrite()` is called with a destination whose final path
@@ -1,4 +1,4 @@
1
- import { i as getRawRuntimeEnv } from "../env-raw-RDkMnSTC.mjs";
1
+ import { i as getRawRuntimeEnv } from "../env-raw-Dtj1UAoK.mjs";
2
2
  //#region src/runtime/isr.ts
3
3
  /**
4
4
  * Revalidate ISR-cached pages on demand.
@@ -1,6 +1,6 @@
1
1
  /// <reference types="@cloudflare/workers-types" />
2
- import { r as AuthUser } from "../auth-CDeb2XAl.mjs";
3
- import { a as CloudEnv, r as CloudContext } from "../handler-hm9KldPP.mjs";
2
+ import { r as AuthUser } from "../auth-nEUVHuFI.mjs";
3
+ import { a as CloudEnv, r as CloudContext } from "../handler-DczZlaXR.mjs";
4
4
 
5
5
  //#region src/runtime/live.d.ts
6
6
  type MaybePromise<T> = T | Promise<T>;
@@ -1,4 +1,4 @@
1
- import { i as getRawRuntimeEnv } from "../env-raw-RDkMnSTC.mjs";
1
+ import { i as getRawRuntimeEnv } from "../env-raw-Dtj1UAoK.mjs";
2
2
  import { getUser } from "./auth.mjs";
3
3
  //#region src/runtime/live.ts
4
4
  let liveBindingName = "VOID_LIVE";
@@ -1,4 +1,4 @@
1
- import { t as disablePgPassFallback } from "../pg-CMZ_5wsC.mjs";
1
+ import { t as disablePgPassFallback } from "../pg-CempqvEJ.mjs";
2
2
  //#region src/runtime/migration-handler-pg.ts
3
3
  function createMigrationHandler(env, migrations, _dialect, runAuthMigrations) {
4
4
  return async (request) => {
@@ -1,4 +1,4 @@
1
- import { i as getRawRuntimeEnv } from "../env-raw-RDkMnSTC.mjs";
1
+ import { i as getRawRuntimeEnv } from "../env-raw-Dtj1UAoK.mjs";
2
2
  import { requireRuntimeBinding } from "./env.mjs";
3
3
  import { Sandbox, getSandbox as getSandbox$1 } from "@cloudflare/sandbox";
4
4
  //#region src/runtime/sandbox.ts
@@ -1,2 +1,2 @@
1
- import { D as runValidation, E as ValidatorSlots, T as HandlerInput } from "../handler-hm9KldPP.mjs";
1
+ import { D as runValidation, E as ValidatorSlots, T as HandlerInput } from "../handler-DczZlaXR.mjs";
2
2
  export { HandlerInput, ValidatorSlots, runValidation };
@@ -1,5 +1,5 @@
1
- import { n as AuthState } from "../auth-CDeb2XAl.mjs";
2
- import { i as VoidAuthRuntimeOptions, n as VoidAuthEnv } from "../better-auth-shared-CmEQZs1T.mjs";
1
+ import { n as AuthState } from "../auth-nEUVHuFI.mjs";
2
+ import { i as VoidAuthRuntimeOptions, n as VoidAuthEnv } from "../better-auth-shared-a7H3wk9J.mjs";
3
3
  import { AnyWebSocketDefinition } from "./ws.mjs";
4
4
 
5
5
  //#region src/runtime/ws-server.d.ts
@@ -1,6 +1,6 @@
1
- import { r as AuthUser } from "../auth-CDeb2XAl.mjs";
2
- import { t as StandardSchemaV1 } from "../standard-schema-Dnsh2vnl.mjs";
3
- import { a as CloudEnv } from "../handler-hm9KldPP.mjs";
1
+ import { r as AuthUser } from "../auth-nEUVHuFI.mjs";
2
+ import { t as StandardSchemaV1 } from "../standard-schema-BCBv-QaP.mjs";
3
+ import { a as CloudEnv } from "../handler-DczZlaXR.mjs";
4
4
  import { WebSocketRouteMap } from "void/routes";
5
5
 
6
6
  //#region src/runtime/ws.d.ts
@@ -1,7 +1,7 @@
1
1
  import { a as join, i as isAbsolute, t as basename } from "./pathe.M-eThtNZ-BrPhGF_K.mjs";
2
2
  import { n as readProjectPaths } from "./project-paths-CCMrHYQm.mjs";
3
3
  import { n as globSync, t as glob } from "./dist-5cGIJHQQ.mjs";
4
- import { d as isCallExpression, f as isIdentifier, h as isObjectExpression, p as isLiteral } from "./plugin-inference--7geW5Z2.mjs";
4
+ import { d as isCallExpression, f as isIdentifier, h as isObjectExpression, p as isLiteral } from "./plugin-inference-C3fLzFvP.mjs";
5
5
  import { o as parseRouteFilename, s as parseWebSocketFilename, t as scanPages } from "./scan-VCAM1oh3.mjs";
6
6
  import { readFileSync } from "node:fs";
7
7
  import { parseSync } from "vite";
@@ -147,6 +147,7 @@ function detectHttpExports(absPath) {
147
147
  const program = parsed.program;
148
148
  for (const node of program.body ?? []) if (node.type === "ExportNamedDeclaration") {
149
149
  const declarationNode = node;
150
+ if (declarationNode.exportKind === "type") continue;
150
151
  const decl = declarationNode.declaration;
151
152
  if (decl) {
152
153
  if (decl.type === "VariableDeclaration") {
@@ -157,6 +158,7 @@ function detectHttpExports(absPath) {
157
158
  }
158
159
  }
159
160
  if (declarationNode.specifiers) for (const spec of declarationNode.specifiers) {
161
+ if (spec.exportKind === "type") continue;
160
162
  const exported = isIdentifier(spec.exported) ? spec.exported.name : isIdentifier(spec.local) ? spec.local.name : void 0;
161
163
  if (exported && HTTP_METHODS.has(exported)) methods.push(exported);
162
164
  }
@@ -286,6 +288,18 @@ function parseMiddlewareDefinitions(files) {
286
288
  };
287
289
  }).sort((a, b) => a.order - b.order);
288
290
  }
291
+ function compareRouteSpecificity(a, b) {
292
+ if (a.catchAll !== b.catchAll) return a.catchAll ? 1 : -1;
293
+ const aSegments = a.pattern.split("/");
294
+ const bSegments = b.pattern.split("/");
295
+ const shared = Math.min(aSegments.length, bSegments.length);
296
+ for (let i = 0; i < shared; i++) {
297
+ const aDynamic = aSegments[i].startsWith(":") || aSegments[i] === "*";
298
+ if (aDynamic !== (bSegments[i].startsWith(":") || bSegments[i] === "*")) return aDynamic ? 1 : -1;
299
+ if (aSegments[i] !== bSegments[i]) return aSegments[i].localeCompare(bSegments[i]);
300
+ }
301
+ return aSegments.length - bSegments.length;
302
+ }
289
303
  /**
290
304
  * Scan routes/ and middleware/ directories and return a structured manifest.
291
305
  * Files starting with _ are ignored.
@@ -315,10 +329,7 @@ async function scanRoutes(root, options) {
315
329
  const route = parseRouteFilename(f);
316
330
  route.methods = detectHttpExports(join(routesDir, f));
317
331
  return route;
318
- }).sort((a, b) => {
319
- if (a.catchAll !== b.catchAll) return a.catchAll ? 1 : -1;
320
- return a.pattern.localeCompare(b.pattern);
321
- }),
332
+ }).sort(compareRouteSpecificity),
322
333
  websockets,
323
334
  middleware: parseMiddlewareDefinitions(middlewareFiles),
324
335
  jobs,
@@ -348,10 +359,7 @@ function scanRoutePatternsSync(root, paths = readProjectPaths(root)) {
348
359
  } catch {
349
360
  routeFiles = [];
350
361
  }
351
- return routeFiles.filter((f) => !isWebSocketPatternFile(f)).filter((f) => !f.split("/").some((s) => s.startsWith("_"))).map((f) => parseRouteFilename(f)).sort((a, b) => {
352
- if (a.catchAll !== b.catchAll) return a.catchAll ? 1 : -1;
353
- return a.pattern.localeCompare(b.pattern);
354
- });
362
+ return routeFiles.filter((f) => !isWebSocketPatternFile(f)).filter((f) => !f.split("/").some((s) => s.startsWith("_"))).map((f) => parseRouteFilename(f)).sort(compareRouteSpecificity);
355
363
  }
356
364
  //#endregion
357
365
  export { scanQueuesSync as a, scanWebSocketRoutesSync as i, scanRoutePatternsSync as n, scanJobsSync as o, scanRoutes as r, scanMiddlewareSync as t };
@@ -1,5 +1,5 @@
1
1
  import { n as cliTitle } from "./output-DeiS4oEX.mjs";
2
- import { c as getToken, n as PlatformClient } from "./client-DIfOFf1W.mjs";
2
+ import { f as getToken, n as PlatformClient } from "./client-CTHvucDv.mjs";
3
3
  import { _ as me, c as R, g as ge, n as Ce, u as Se, v as ue, x as q, y as ye } from "./dist-abzUneor.mjs";
4
4
  import { r as readProjectConfig } from "./project-CH9pdo16.mjs";
5
5
  import { r as resolveProjectBySlug, t as getRequestedProjectSlug } from "./resolve-project-D4O1_fZz.mjs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "void",
3
- "version": "0.9.3",
3
+ "version": "0.10.2",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/voidzero-dev/void.git",
@@ -353,7 +353,7 @@
353
353
  "valibot": ">=1.0.0-beta.7",
354
354
  "vite": "^8.0.0",
355
355
  "zod": "^3.25.0 || ^4.0.0",
356
- "@void/md": "0.9.3"
356
+ "@void/md": "0.10.2"
357
357
  },
358
358
  "peerDependenciesMeta": {
359
359
  "@void/md": {
package/schema.json CHANGED
@@ -154,7 +154,7 @@
154
154
  {
155
155
  "type": "object",
156
156
  "patternProperties": {
157
- "^(/|\\*)": {
157
+ "^(\\/|\\*$)": {
158
158
  "type": "number",
159
159
  "minimum": 0
160
160
  }
@@ -216,7 +216,7 @@
216
216
  "type": "object",
217
217
  "description": "URL rewrites. Keys are source URL patterns (path-only `/path` or host-scoped `https://host/path`); values are destination paths. Serves content from the destination without changing the browser URL. Destinations must start with \"/\" and must not contain \"?\" — the incoming request's query string is preserved automatically.",
218
218
  "patternProperties": {
219
- "^(/|https://)": { "type": "string", "pattern": "^/[^?]*$" }
219
+ "^(/|https://)": { "type": "string", "pattern": "^/(?!/)[^?]*$" }
220
220
  },
221
221
  "additionalProperties": false
222
222
  },
@@ -224,7 +224,7 @@
224
224
  "type": "object",
225
225
  "description": "Fallback rewrites. Same shape as `rewrites`, but only fire when no static asset matched the request. Useful for SPA shells or default-locale catch-alls without pre-empting real routes. Destinations must start with \"/\" and must not contain \"?\".",
226
226
  "patternProperties": {
227
- "^(/|https://)": { "type": "string", "pattern": "^/[^?]*$" }
227
+ "^(/|https://)": { "type": "string", "pattern": "^/(?!/)[^?]*$" }
228
228
  },
229
229
  "additionalProperties": false
230
230
  }
@@ -64,30 +64,45 @@ If your CI pipeline runs typechecking or other static analysis before deploy, ru
64
64
 
65
65
  ## GitHub Actions
66
66
 
67
- You can deploy from a GitHub repo with a simple GitHub Actions workflow. Running `void init --github` will generate this as `.github/workflows/deploy.yml` in your project:
67
+ You can deploy from a GitHub repo on every push to `main`. Running `void init --github` generates `.github/workflows/void-deploy.yml` in your project.
68
+
69
+ The workflow authenticates with [GitHub OIDC](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect) — there is **no long-lived `VOID_TOKEN` secret to store or rotate**. `void deploy` detects GitHub Actions and does the exchange itself: it requests a short-lived OIDC token from GitHub (audience `void`), exchanges it at `POST $VOID_API_URL/auth/github-oidc` for a short-lived project-scoped deploy token (about 15 minutes on the free tier; longer on higher plans, capped at ~60 minutes), and deploys — so the workflow is a single `void deploy` step. `permissions: id-token: write` is still required: it is what lets the job (and the CLI) mint the OIDC token.
68
70
 
69
71
  ```yaml
70
- name: Deploy
72
+ name: Deploy to Void
71
73
  on:
72
74
  push:
73
75
  branches: [main]
74
76
 
77
+ # Latest push wins: a newer commit cancels an in-flight deploy for the same
78
+ # repo + branch, so an older commit can never overtake a newer one.
79
+ concurrency:
80
+ group: void-deploy-${{ github.repository }}-${{ github.ref }}
81
+ cancel-in-progress: true
82
+
83
+ permissions:
84
+ id-token: write
85
+ contents: read
86
+
87
+ env:
88
+ VOID_API_URL: ${{ vars.VOID_API_URL || 'https://api.void.cloud' }}
89
+ VOID_PROJECT: my-app
90
+
75
91
  jobs:
76
92
  deploy:
77
93
  runs-on: ubuntu-latest
78
94
  steps:
79
- - uses: actions/checkout@v4
80
- - uses: voidzero-dev/setup-vp@v1
95
+ - uses: actions/checkout@v6
96
+ - uses: actions/setup-node@v6
81
97
  with:
82
- node-version: '22'
83
- cache: true
84
- - run: vp exec void deploy
85
- env:
86
- VOID_TOKEN: ${{ secrets.VOID_TOKEN }}
87
- VOID_PROJECT: my-app
98
+ node-version: lts/*
99
+ cache: npm
100
+ - run: npm ci
101
+ - name: Deploy
102
+ run: npx void deploy --project "$VOID_PROJECT"
88
103
  ```
89
104
 
90
- To get a deploy token, run `void auth token` to copy it to your clipboard, then add it as a GitHub Actions secret.
105
+ Connect the repository to your project once with `void github connect <project> --repo <owner/repo> --executor github_actions` to authorize it. This GitHub Actions path requires the `github_actions` build executor — the default `container` executor will not work with this workflow. The exact steps vary by package manager (the scaffold detects pnpm, yarn, bun, or npm). The `VOID_PROJECT` value is baked in from your linked project when known; otherwise the workflow reads a `VOID_PROJECT` repository variable. To target staging, set a `VOID_API_URL` repository variable to `https://api.staging.void.cloud`.
91
106
 
92
107
  ## Other Targets
93
108
 
@@ -56,11 +56,18 @@ Define custom response headers in [`void.json`](../../reference/config) using th
56
56
 
57
57
  ## Scope
58
58
 
59
- Header rules apply to **all responses** served through the dispatch worker, including static assets, SSR pages, and API routes. They do not apply to:
59
+ Header rules apply to **all responses** served through the dispatch worker, including static assets, SSR pages, API routes, and hashed asset responses (which browsers fetch over `GET` from the immutable edge cache). Serving headers on hashed assets is what lets a cross-origin-isolated app attach `Cross-Origin-Embedder-Policy` and `Cross-Origin-Resource-Policy` to its hashed worker and wasm files — without them, a module worker spawned from a `require-corp` document is blocked.
60
+
61
+ On hashed (content-addressed, immutable) assets, rules are **additive**. You can add headers such as COOP/COEP/CORP or other security headers, but the platform-managed caching, representation, and framing headers are preserved so an immutable asset cannot be mis-cached or corrupted: `Cache-Control`, `Content-Type`, `Content-Encoding`, `Content-Length`, `Content-Range`, `Accept-Ranges`, and `Transfer-Encoding` keep their platform values even if a broad rule tries to overwrite them. (This is the one case where a user `Cache-Control` does not override the default.)
62
+
63
+ Header rules do not apply to:
60
64
 
61
- - Hashed asset cache hits (these use immutable caching set by the dispatch worker itself)
62
65
  - ISR cache responses (these have their own cache-control headers)
63
66
 
67
+ ### Blocked headers
68
+
69
+ Two headers can never be set through rules: `Set-Cookie` and `Clear-Site-Data`. On the shared `*.void.app` domain, `void.app` is the registrable domain, so a cookie operation from one project would reach every project's subdomain. Both are dropped from rule output to keep that tenant boundary intact.
70
+
64
71
  ## Framework `_headers` files
65
72
 
66
73
  Meta-frameworks like SvelteKit, Nuxt, and Astro generate a `_headers` file with cache rules for their hashed asset directories. Void automatically parses this file during deploy and merges the rules into the deploy manifest.
@@ -74,6 +81,6 @@ No configuration is needed. If the framework generates a `_headers` file, it is
74
81
 
75
82
  1. `void deploy` reads header rules from the framework `_headers` file (if present) and `routing.headers` in `void.json`, then includes them in the deploy manifest.
76
83
  2. The platform stores the rules in the KV routing entry for your project.
77
- 3. The dispatch worker applies matching rules to matching responses before returning them. Cacheable responses are cached with the final headers.
84
+ 3. The dispatch worker applies matching rules to matching responses before returning them. Most cacheable responses are cached with the final headers; hashed assets are the exception — their rules are applied on every serve (including cache hits), so a later header-rule change takes effect even when the content hash, and thus the cache entry, is unchanged.
78
85
 
79
86
  Because rules are evaluated at the edge, there is no extra latency cost. Headers are applied inline before the response is returned and cached.
@@ -332,14 +332,14 @@ If you use [`routing.revalidate`](./revalidation) on a dispatch rewrite (`routin
332
332
  During `vite dev`, every response carries an `X-Void-Routing` header that traces how the request was resolved. Open the Network tab in devtools and inspect the response headers:
333
333
 
334
334
  ```
335
- X-Void-Routing: redirect[/old] → /new 301 (_redirects:12)
336
- X-Void-Routing: rewrite[/api/*] → /backend/:splat (void.json#routing.rewrites)
337
- X-Void-Routing: fallback[/docs/*] → /docs.html (void.json#routing.fallbacks)
338
- X-Void-Routing: c.rewrite → /new-path (middleware)
335
+ X-Void-Routing: redirect[/old] -> /new 301 (_redirects:12)
336
+ X-Void-Routing: rewrite[/api/*] -> /backend/:splat (void.json#routing.rewrites)
337
+ X-Void-Routing: fallback[/docs/*] -> /docs.html (void.json#routing.fallbacks)
338
+ X-Void-Routing: c.rewrite -> /new-path (middleware)
339
339
  X-Void-Routing: pass-through
340
340
  ```
341
341
 
342
- Phases are separated by `→`. The parenthesised source hint points at the exact declaration — a line number for `_redirects`, a config path for `void.json`, or `spa-default` for the synthetic SPA catch-all. The header is **only emitted in dev** — production builds strip both the trace code and the per-rule `origin` metadata from the bundle and manifest.
342
+ Phases are separated by `->` so the diagnostic value stays valid as an HTTP header. The parenthesised source hint points at the exact declaration — a line number for `_redirects`, a config path for `void.json`, or `spa-default` for the synthetic SPA catch-all. The header is **only emitted in dev** — production builds strip both the trace code and the per-rule `origin` metadata from the bundle and manifest.
343
343
 
344
344
  ::: info What fires in `vite dev`
345
345
  `vite dev` applies the full static routing pipeline on every target — `node`, `bun`, `deno`, and the default target alike. `void.json` rules (`routing.redirects` / `routing.rewrites` / `routing.fallbacks` / `routing.headers`) and file-based rules (`public/_redirects`, `public/_headers`) are merged at plugin load and compiled into the Hono middleware your worker runs behind. Editing `_redirects` or `_headers` during a dev session re-runs the merge and reloads the page — no restart needed. `c.rewrite()` calls in middleware work everywhere because they live inside the worker itself, and the `X-Void-Routing` dev header reports every decision on every target.
@@ -86,7 +86,7 @@ After that, the full interactive flow walks through:
86
86
  4. **Skills:** links Void skills using the same detected or selected agent context.
87
87
  5. **MCP config:** writes MCP server config using that same agent context.
88
88
  6. **Demo code:** for existing non-Pages projects, optionally scaffolds a `db/migrations/` directory plus an API route and typed fetch example.
89
- 7. **GitHub Actions:** optionally creates `.github/workflows/deploy.yml` with the right package manager commands.
89
+ 7. **GitHub Actions:** optionally creates `.github/workflows/void-deploy.yml`. The workflow deploys on pushes to `main` and authenticates via [GitHub OIDC](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect) — no long-lived `VOID_TOKEN` secret is stored in the repo. The workflow is a single `void deploy` step: when it runs in GitHub Actions, `void deploy` mints an OIDC token (audience `void`), exchanges it at `POST $VOID_API_URL/auth/github-oidc` for a short-lived project-scoped deploy token, and deploys. `permissions: id-token: write` is retained so the CLI can mint that token. The project slug is baked in from your linked project (`.void/project.json`) when known; otherwise the workflow reads a `VOID_PROJECT` repository variable.
90
90
  8. **`env.ts` scaffold:** if the project has no `env.ts` but has `.env` / `.env.example` / `.env.local` / `.env.development*` files on disk, generates an `env.ts` pre-populated with their keys. Values get conservative type inference (`boolean`/`url`/`number`/`string`) — the file carries a banner nudging you to tighten anything the heuristic got wrong.
91
91
  9. **Project setup:** optionally logs you in, lets you select or create a project, and writes `.void/project.json` so your first deploy can just be `void deploy`.
92
92
 
@@ -98,10 +98,12 @@ Use flags to run individual steps without prompts:
98
98
  | ------------ | ------------------------------------------------- |
99
99
  | `--tsconfig` | Only update `tsconfig.json` |
100
100
  | `--agents` | Set up agent instructions, skills, and MCP config |
101
- | `--github` | Only create GitHub Actions workflow |
101
+ | `--github` | Only create the GitHub Actions deploy workflow |
102
102
 
103
103
  Flags can be combined. When any flag is provided, only the specified steps run and interactive prompts are skipped.
104
104
 
105
+ The `--github` workflow uses GitHub OIDC: you connect the repository to your Void project once with `void github connect <project> --repo <owner/repo> --executor github_actions` (see the GitHub section below), and pushes to `main` deploy automatically. There is no `VOID_TOKEN` secret to create or rotate. To target staging, set a `VOID_API_URL` repository variable to `https://api.staging.void.cloud`.
106
+
105
107
  For projects that already have `"extends"`, `void init --tsconfig` preserves the existing config and adds `./.void/tsconfig.json`. If the existing config defines `files` or `compilerOptions.paths`, Void also merges its generated declaration files and aliases into the root config because TypeScript replaces those fields across `extends` instead of deeply merging them.
106
108
 
107
109
  ### `void prepare`
@@ -564,6 +566,91 @@ PORT=3000
564
566
 
565
567
  See [Environment Variables](../guide/env-vars.md) for the full guide.
566
568
 
569
+ ## GitHub
570
+
571
+ Deploy-on-GitHub works from **any** Void login — Google, GitHub, or other SSO. The first time you connect GitHub, Void links your GitHub identity to your current account (a one-time step, independent of how you logged in); it never creates a second account.
572
+
573
+ ### `void github link`
574
+
575
+ ```
576
+ void github link
577
+ ```
578
+
579
+ Link your current Void account to a GitHub identity. Opens your browser to authorize Void on GitHub (a localhost + PKCE handshake, the same mechanics as `void auth login`), then binds that GitHub identity to the logged-in account. Requires an authenticated CLI (`void auth login` first).
580
+
581
+ You normally don't need to run this directly — `void github install` runs the link automatically when your account has no GitHub identity yet. Run it on its own to link ahead of time, or to link a GitHub identity without installing the App. If that GitHub account is already linked to a different Void account, the command fails and asks you to use a different GitHub account.
582
+
583
+ ### `void github install`
584
+
585
+ ```
586
+ void github install
587
+ ```
588
+
589
+ Open the GitHub App install page in your browser. If your account has no linked GitHub identity yet, `void github install` first runs the GitHub link automatically (browser authorize), then continues. After installing, run `void github connect` to link a repository to your project.
590
+
591
+ ### `void github installations`
592
+
593
+ ```
594
+ void github installations
595
+ ```
596
+
597
+ List all GitHub App installations linked to your account. Each entry includes the `[id: <installation_id>]` needed for `--installation` in non-interactive use.
598
+
599
+ ### `void github connect`
600
+
601
+ ```
602
+ void github connect [project] [options]
603
+ ```
604
+
605
+ Connect a GitHub repository to a Void project for automatic deploys. On every push to the configured branch, Void builds and deploys your project automatically.
606
+
607
+ **Options**
608
+
609
+ | Flag | Description |
610
+ | --------------------- | ------------------------------------------------------------------------------- |
611
+ | `--project <name>` | Project name (alias for the positional argument) |
612
+ | `--installation <id>` | GitHub App installation ID (required when you have multiple installations) |
613
+ | `--repo <owner/repo>` | Repository full name — required unless the installation grants exactly one repo |
614
+ | `--branch <name>` | Branch to deploy from — **required in non-interactive mode** |
615
+ | `--executor <type>` | Build executor: `container` (default) or `github_actions` |
616
+
617
+ **Non-interactive use (CI)**
618
+
619
+ When stdin is not a TTY, `void github connect` never prompts — it fails closed and names any flag it needs. `--branch` is always required. `--project` must be resolvable (positional / `--project` / `VOID_PROJECT` / linked `.void/project.json`). `--installation` is required only when your account has more than one installation; otherwise the sole installation is used. `--repo` is required when the installation grants access to all repos or to more than one selected repo; when it grants exactly one repo that repo is used automatically. Use `void github installations` to discover the `installation_id`.
620
+
621
+ ```
622
+ void github connect my-app \
623
+ --installation 42 \
624
+ --repo owner/my-app \
625
+ --branch main
626
+ ```
627
+
628
+ **Project resolution** follows the same order as deploy: positional / `--project`, `VOID_PROJECT`, linked project (`.void/project.json`).
629
+
630
+ ### `void github update`
631
+
632
+ ```
633
+ void github update [project] [options]
634
+ ```
635
+
636
+ Update an existing connection's deploy **branch** and/or **build executor**. Use this to change settings on a project that is already connected — for example, flipping the executor from `container` to `github_actions` for a monorepo whose Void app lives in a subdirectory, or moving the deploy branch. The project must already be connected (run `void github connect` first); the repository and installation are not changed.
637
+
638
+ **Options**
639
+
640
+ | Flag | Description |
641
+ | ------------------- | --------------------------------------------------- |
642
+ | `--project <name>` | Project name (alias for the positional argument) |
643
+ | `--branch <name>` | New branch to deploy from |
644
+ | `--executor <type>` | New build executor: `container` or `github_actions` |
645
+
646
+ Interactively (TTY), `void github update` shows the current branch and executor and prompts for new values, defaulting each to the current setting. When stdin is not a TTY, it never prompts: pass at least one of `--branch` / `--executor`, or it fails closed. If nothing actually changes, the command reports "no changes" and does not call the API.
647
+
648
+ ```
649
+ void github update my-app --executor github_actions
650
+ ```
651
+
652
+ **Project resolution** follows the same order as deploy: positional / `--project`, `VOID_PROJECT`, linked project (`.void/project.json`).
653
+
567
654
  ## Custom Domains
568
655
 
569
656
  ### `void domain add`
File without changes
File without changes