void 0.1.6 → 0.7.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/AGENT_PROMPT.md +15 -0
- package/README.md +62 -123
- package/dist/auth-BdsJ0Aff.d.mts +43 -0
- package/dist/auth-cmd-Dx8oPKZC.mjs +43 -0
- package/dist/auth-migrations-BAtAck2g.mjs +117 -0
- package/dist/better-auth-shared-C9_GHSkR.d.mts +71 -0
- package/dist/better-auth-shared-CdYmQGry.mjs +163 -0
- package/dist/cache-W82I8ihI.mjs +47 -0
- package/dist/cancel-deploy-BOBTqqh0.mjs +59 -0
- package/dist/cf-access-Dee5cXxL.mjs +22 -0
- package/dist/chunk-DJd-R1mw.mjs +34 -0
- package/dist/cli/cli.d.mts +1 -0
- package/dist/cli/cli.mjs +1807 -0
- package/dist/client-snXOjrp1.mjs +565 -0
- package/dist/collect-CjeZgz5D.mjs +55 -0
- package/dist/config-BIa9HwVX.mjs +573 -0
- package/dist/config-BzM9Dy7T.mjs +37 -0
- package/dist/config-CvHtTM0q.mjs +30 -0
- package/dist/create-project-BIA15W7z.mjs +90 -0
- package/dist/db-DsRoMcfN.mjs +895 -0
- package/dist/defer-DcxEsVH1.mjs +49 -0
- package/dist/delete-DAP6yDc7.mjs +64 -0
- package/dist/deploy-BPKblFx6.mjs +2424 -0
- package/dist/discover-B7FkXBLB.mjs +40 -0
- package/dist/dist-DUyXJLkq.mjs +2667 -0
- package/dist/dist-Dayj3gCK.mjs +1287 -0
- package/dist/domain-BGofcQ6I.mjs +79 -0
- package/dist/dotenv-DwO4ti0Z.mjs +173 -0
- package/dist/drizzle-NnudE_UN.mjs +232 -0
- package/dist/env-CyG3tvU0.mjs +301 -0
- package/dist/env-helpers-Dr9Y7RnE.d.mts +52 -0
- package/dist/env-raw-BDL4TvdN.mjs +32 -0
- package/dist/env-types-DknSA4SO.mjs +64 -0
- package/dist/env-validation-DJKjR_8q.mjs +163 -0
- package/dist/fetch-error-BQ8sZ5Nd.mjs +266 -0
- package/dist/fetch-error-CVZ5CGA-.d.mts +20 -0
- package/dist/gen-U0Ktr4Zd.mjs +761 -0
- package/dist/handler-B0ds0OHJ.d.mts +269 -0
- package/dist/head-P-egrtFE.d.mts +45 -0
- package/dist/headers-DCXc7mDs.mjs +279 -0
- package/dist/index.d.mts +32 -0
- package/dist/index.mjs +4695 -0
- package/dist/init-C7wS5iGP.mjs +2625 -0
- package/dist/link-p2R6NbgN.mjs +49 -0
- package/dist/list-Bfel-QLc.mjs +113 -0
- package/dist/log-DXdqnmhF.mjs +26 -0
- package/dist/login-CkcXUiIu.mjs +72 -0
- package/dist/logs-DmkrRvx6.mjs +98 -0
- package/dist/magic-string.es-D6g9UnIy.mjs +1011 -0
- package/dist/mcp-CaQzfeUi.mjs +373 -0
- package/dist/node-DDfXj10V.mjs +54 -0
- package/dist/output-BwlcIYSR.mjs +139 -0
- package/dist/pages/client.d.mts +198 -0
- package/dist/pages/client.mjs +980 -0
- package/dist/pages/head-client.d.mts +15 -0
- package/dist/pages/head-client.mjs +90 -0
- package/dist/pages/head.d.mts +2 -0
- package/dist/pages/head.mjs +112 -0
- package/dist/pages/index.d.mts +38 -0
- package/dist/pages/index.mjs +76 -0
- package/dist/pages/islands-plugin.d.mts +50 -0
- package/dist/pages/islands-plugin.mjs +195 -0
- package/dist/pages/prefetch.d.mts +31 -0
- package/dist/pages/prefetch.mjs +90 -0
- package/dist/pages/protocol.d.mts +3 -0
- package/dist/pages/protocol.mjs +193 -0
- package/dist/pages/serialize.d.mts +10 -0
- package/dist/pages/serialize.mjs +14 -0
- package/dist/pathe.M-eThtNZ-D-kmWkCS.mjs +150 -0
- package/dist/plugin-inference-oZ6Ybu2_.mjs +2447 -0
- package/dist/prepare-BAtWufvm.mjs +99 -0
- package/dist/preset-D4I73kT4.mjs +221 -0
- package/dist/project-TqORyHn8.mjs +72 -0
- package/dist/project-cmd-B7lQp3F3.mjs +67 -0
- package/dist/project-slug-CKam8lF9.mjs +11 -0
- package/dist/project-tsconfig-DfkESbDL.mjs +63 -0
- package/dist/protocol-BWzXs2A2.d.mts +34 -0
- package/dist/providers-B3aMxWzP.mjs +67 -0
- package/dist/resolve-project-Br5BR03U.mjs +29 -0
- package/dist/rollback-gyC59l7U.mjs +92 -0
- package/dist/route-types-DReF1gUY.mjs +255 -0
- package/dist/routes-stub.d.mts +55 -0
- package/dist/routes-stub.mjs +1 -0
- package/dist/runner-6Ep3fNQu.mjs +123 -0
- package/dist/runner-pg-D0wWHYnr.mjs +57 -0
- package/dist/runtime/ai.d.mts +127 -0
- package/dist/runtime/ai.mjs +348 -0
- package/dist/runtime/auth-client-react.d.mts +8 -0
- package/dist/runtime/auth-client-react.mjs +6 -0
- package/dist/runtime/auth-client-solid.d.mts +8 -0
- package/dist/runtime/auth-client-solid.mjs +6 -0
- package/dist/runtime/auth-client-svelte.d.mts +8 -0
- package/dist/runtime/auth-client-svelte.mjs +6 -0
- package/dist/runtime/auth-client-vue.d.mts +8 -0
- package/dist/runtime/auth-client-vue.mjs +6 -0
- package/dist/runtime/auth-client.d.mts +8 -0
- package/dist/runtime/auth-client.mjs +6 -0
- package/dist/runtime/auth.d.mts +2 -0
- package/dist/runtime/auth.mjs +22 -0
- package/dist/runtime/better-auth-pg.d.mts +11 -0
- package/dist/runtime/better-auth-pg.mjs +51 -0
- package/dist/runtime/better-auth.d.mts +11 -0
- package/dist/runtime/better-auth.mjs +33 -0
- package/dist/runtime/client.d.mts +6 -0
- package/dist/runtime/client.mjs +5 -0
- package/dist/runtime/db-pg.d.mts +2 -0
- package/dist/runtime/db-pg.mjs +1 -0
- package/dist/runtime/db.d.mts +17 -0
- package/dist/runtime/db.mjs +30 -0
- package/dist/runtime/drizzle-arktype.d.mts +1 -0
- package/dist/runtime/drizzle-arktype.mjs +2 -0
- package/dist/runtime/drizzle-valibot.d.mts +1 -0
- package/dist/runtime/drizzle-valibot.mjs +2 -0
- package/dist/runtime/drizzle-zod.d.mts +1 -0
- package/dist/runtime/drizzle-zod.mjs +2 -0
- package/dist/runtime/env-helpers.d.mts +2 -0
- package/dist/runtime/env-helpers.mjs +173 -0
- package/dist/runtime/env-public-client.d.mts +22 -0
- package/dist/runtime/env-public-client.mjs +54 -0
- package/dist/runtime/env-public.d.mts +143 -0
- package/dist/runtime/env-public.mjs +366 -0
- package/dist/runtime/env.d.mts +13 -0
- package/dist/runtime/env.mjs +51 -0
- package/dist/runtime/fetch-stream.d.mts +51 -0
- package/dist/runtime/fetch-stream.mjs +81 -0
- package/dist/runtime/fetch.d.mts +59 -0
- package/dist/runtime/fetch.mjs +18 -0
- package/dist/runtime/handler.d.mts +3 -0
- package/dist/runtime/handler.mjs +85 -0
- package/dist/runtime/isr.d.mts +26 -0
- package/dist/runtime/isr.mjs +43 -0
- package/dist/runtime/kv.d.mts +48 -0
- package/dist/runtime/kv.mjs +106 -0
- package/dist/runtime/log.d.mts +24 -0
- package/dist/runtime/log.mjs +31 -0
- package/dist/runtime/migration-handler-pg.d.mts +6 -0
- package/dist/runtime/migration-handler-pg.mjs +85 -0
- package/dist/runtime/migration-handler.d.mts +19 -0
- package/dist/runtime/migration-handler.mjs +92 -0
- package/dist/runtime/queues.d.mts +7 -0
- package/dist/runtime/queues.mjs +8 -0
- package/dist/runtime/remote/binding-handler.d.mts +15 -0
- package/dist/runtime/remote/binding-handler.mjs +208 -0
- package/dist/runtime/remote/index.d.mts +8 -0
- package/dist/runtime/remote/index.mjs +461 -0
- package/dist/runtime/response.d.mts +14 -0
- package/dist/runtime/response.mjs +30 -0
- package/dist/runtime/sandbox.d.mts +17 -0
- package/dist/runtime/sandbox.mjs +19 -0
- package/dist/runtime/schema-d1.d.mts +1 -0
- package/dist/runtime/schema-d1.mjs +2 -0
- package/dist/runtime/schema-pg.d.mts +1 -0
- package/dist/runtime/schema-pg.mjs +2 -0
- package/dist/runtime/seed.d.mts +30 -0
- package/dist/runtime/seed.mjs +6 -0
- package/dist/runtime/storage.d.mts +7 -0
- package/dist/runtime/storage.mjs +14 -0
- package/dist/runtime/validator.d.mts +2 -0
- package/dist/runtime/validator.mjs +72 -0
- package/dist/runtime/ws-server.d.mts +26 -0
- package/dist/runtime/ws-server.mjs +296 -0
- package/dist/runtime/ws.d.mts +123 -0
- package/dist/runtime/ws.mjs +103 -0
- package/dist/scan-Ba4hFwlH.mjs +324 -0
- package/dist/scan-C6HMEIdW.mjs +318 -0
- package/dist/secret-CeRSukgM.mjs +109 -0
- package/dist/skills-ipldjlKE.mjs +62 -0
- package/dist/standard-schema-9CRjx-uR.d.mts +42 -0
- package/dist/subcommand-prompt-BKjuNAPb.mjs +349 -0
- package/dist/sveltekit.d.mts +20 -0
- package/dist/sveltekit.mjs +61 -0
- package/dist/types-mHOEwpW4.d.mts +57 -0
- package/dist/validate-CaMavMxu.mjs +146 -0
- package/dist/yarn-pnp-BFqMV_bl.mjs +196 -0
- package/getting-started-prompt.txt +26 -0
- package/package.json +322 -30
- package/schema.json +364 -0
- package/skills/migrate-vite-cloudflare-to-void/SKILL.md +175 -0
- package/skills/void/SKILL.md +75 -0
- package/skills/void/command/void.md +7 -0
- package/skills/void/docs/guide/ai.md +235 -0
- package/skills/void/docs/guide/app-types.md +103 -0
- package/skills/void/docs/guide/auth.md +257 -0
- package/skills/void/docs/guide/database/d1.md +106 -0
- package/skills/void/docs/guide/database/postgresql.md +106 -0
- package/skills/void/docs/guide/database.md +418 -0
- package/skills/void/docs/guide/deployment.md +98 -0
- package/skills/void/docs/guide/edge/headers.md +79 -0
- package/skills/void/docs/guide/edge/prerendering.md +83 -0
- package/skills/void/docs/guide/edge/redirects.md +116 -0
- package/skills/void/docs/guide/edge/revalidation.md +131 -0
- package/skills/void/docs/guide/edge/rewrites.md +354 -0
- package/skills/void/docs/guide/edge/static-assets.md +72 -0
- package/skills/void/docs/guide/env-vars.md +298 -0
- package/skills/void/docs/guide/index.md +80 -0
- package/skills/void/docs/guide/jobs.md +91 -0
- package/skills/void/docs/guide/kv.md +107 -0
- package/skills/void/docs/guide/pages-routing/actions-and-forms.md +419 -0
- package/skills/void/docs/guide/pages-routing/head.md +130 -0
- package/skills/void/docs/guide/pages-routing/islands.md +405 -0
- package/skills/void/docs/guide/pages-routing/layouts.md +362 -0
- package/skills/void/docs/guide/pages-routing/loaders.md +267 -0
- package/skills/void/docs/guide/pages-routing/markdown.md +625 -0
- package/skills/void/docs/guide/pages-routing/overview.md +236 -0
- package/skills/void/docs/guide/pages-routing/view-transitions.md +140 -0
- package/skills/void/docs/guide/queues.md +140 -0
- package/skills/void/docs/guide/quickstart.md +233 -0
- package/skills/void/docs/guide/remote-dev.md +67 -0
- package/skills/void/docs/guide/sandboxes.md +82 -0
- package/skills/void/docs/guide/server-routing.md +246 -0
- package/skills/void/docs/guide/ssg.md +74 -0
- package/skills/void/docs/guide/ssr.md +105 -0
- package/skills/void/docs/guide/storage.md +67 -0
- package/skills/void/docs/guide/type-safety.md +179 -0
- package/skills/void/docs/guide/typed-fetch.md +113 -0
- package/skills/void/docs/guide/websockets.md +190 -0
- package/skills/void/docs/index.md +48 -0
- package/skills/void/docs/integrations/agents.md +84 -0
- package/skills/void/docs/integrations/cloudflare.md +284 -0
- package/skills/void/docs/integrations/frameworks/analog.md +182 -0
- package/skills/void/docs/integrations/frameworks/astro.md +197 -0
- package/skills/void/docs/integrations/frameworks/nuxt.md +164 -0
- package/skills/void/docs/integrations/frameworks/overview.md +136 -0
- package/skills/void/docs/integrations/frameworks/react-router.md +137 -0
- package/skills/void/docs/integrations/frameworks/sveltekit.md +191 -0
- package/skills/void/docs/integrations/frameworks/tanstack-start.md +140 -0
- package/skills/void/docs/integrations/hono.md +97 -0
- package/skills/void/docs/integrations/nodejs-bun-deno.md +210 -0
- package/skills/void/docs/node_modules/@iconify/vue/README.md +408 -0
- package/skills/void/docs/node_modules/@iconify/vue/offline/readme.md +5 -0
- package/skills/void/docs/node_modules/@voidzero-dev/vitepress-theme/README.md +103 -0
- package/skills/void/docs/node_modules/oxc-minify/README.md +78 -0
- package/skills/void/docs/node_modules/reka-ui/README.md +80 -0
- package/skills/void/docs/node_modules/vitepress/README.md +28 -0
- package/skills/void/docs/node_modules/vitepress/template/api-examples.md +49 -0
- package/skills/void/docs/node_modules/vitepress/template/index.md +28 -0
- package/skills/void/docs/node_modules/vitepress/template/markdown-examples.md +85 -0
- package/skills/void/docs/node_modules/vitepress-plugin-group-icons/README.md +101 -0
- package/skills/void/docs/node_modules/void/AGENTS.md +204 -0
- package/skills/void/docs/node_modules/void/AGENT_PROMPT.md +15 -0
- package/skills/void/docs/node_modules/void/README.md +89 -0
- package/skills/void/docs/node_modules/void/node_modules/@clack/prompts/CHANGELOG.md +591 -0
- package/skills/void/docs/node_modules/void/node_modules/@clack/prompts/README.md +375 -0
- package/skills/void/docs/node_modules/void/node_modules/@cloudflare/sandbox/README.md +174 -0
- package/skills/void/docs/node_modules/void/node_modules/@cloudflare/vite-plugin/README.md +37 -0
- package/skills/void/docs/node_modules/void/node_modules/@cloudflare/workers-types/README.md +135 -0
- package/skills/void/docs/node_modules/void/node_modules/@electric-sql/pglite/README.md +189 -0
- package/skills/void/docs/node_modules/void/node_modules/@hono/oauth-providers/CHANGELOG.md +143 -0
- package/skills/void/docs/node_modules/void/node_modules/@hono/oauth-providers/README.md +1272 -0
- package/skills/void/docs/node_modules/void/node_modules/@napi-rs/keyring/README.md +19 -0
- package/skills/void/docs/node_modules/void/node_modules/@types/better-sqlite3/README.md +15 -0
- package/skills/void/docs/node_modules/void/node_modules/@types/node/README.md +15 -0
- package/skills/void/docs/node_modules/void/node_modules/@types/pg/README.md +15 -0
- package/skills/void/docs/node_modules/void/node_modules/@typescript/native-preview/README.md +22 -0
- package/skills/void/docs/node_modules/void/node_modules/@typescript/native-preview/vendor/vscode-jsonrpc/README.md +69 -0
- package/skills/void/docs/node_modules/void/node_modules/@void/md/README.md +152 -0
- package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/@shikijs/engine-javascript/README.md +9 -0
- package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/@shikijs/transformers/README.md +9 -0
- package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/@types/node/README.md +15 -0
- package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/gray-matter/CHANGELOG.md +24 -0
- package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/gray-matter/README.md +565 -0
- package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/markdown-exit/README.md +124 -0
- package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/markdown-it-anchor/README.md +600 -0
- package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/markdown-it-attrs/README.md +386 -0
- package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/markdown-it-container/README.md +95 -0
- package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/markdown-it-emoji/README.md +101 -0
- package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/pathe/README.md +73 -0
- package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/shiki/README.md +15 -0
- package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/tinyglobby/README.md +25 -0
- package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/tsdown/README.md +55 -0
- package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite/LICENSE.md +2230 -0
- package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite/README.md +20 -0
- package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vue/README.md +58 -0
- package/skills/void/docs/node_modules/void/node_modules/arktype/README.md +165 -0
- package/skills/void/docs/node_modules/void/node_modules/better-auth/LICENSE.md +20 -0
- package/skills/void/docs/node_modules/void/node_modules/better-auth/README.md +32 -0
- package/skills/void/docs/node_modules/void/node_modules/better-sqlite3/README.md +99 -0
- package/skills/void/docs/node_modules/void/node_modules/blake3-jit/README.md +108 -0
- package/skills/void/docs/node_modules/void/node_modules/drizzle-arktype/README.md +51 -0
- package/skills/void/docs/node_modules/void/node_modules/drizzle-kit/README.md +79 -0
- package/skills/void/docs/node_modules/void/node_modules/drizzle-orm/README.md +44 -0
- package/skills/void/docs/node_modules/void/node_modules/drizzle-valibot/README.md +51 -0
- package/skills/void/docs/node_modules/void/node_modules/drizzle-zod/README.md +65 -0
- package/skills/void/docs/node_modules/void/node_modules/es-module-lexer/README.md +390 -0
- package/skills/void/docs/node_modules/void/node_modules/estree-walker/README.md +48 -0
- package/skills/void/docs/node_modules/void/node_modules/hono/README.md +85 -0
- package/skills/void/docs/node_modules/void/node_modules/ignore/README.md +452 -0
- package/skills/void/docs/node_modules/void/node_modules/jsonc-parser/CHANGELOG.md +76 -0
- package/{LICENSE → skills/void/docs/node_modules/void/node_modules/jsonc-parser/LICENSE.md} +21 -21
- package/skills/void/docs/node_modules/void/node_modules/jsonc-parser/README.md +364 -0
- package/skills/void/docs/node_modules/void/node_modules/jsonc-parser/SECURITY.md +41 -0
- package/skills/void/docs/node_modules/void/node_modules/magic-string/README.md +325 -0
- package/skills/void/docs/node_modules/void/node_modules/ofetch/README.md +398 -0
- package/skills/void/docs/node_modules/void/node_modules/pathe/README.md +73 -0
- package/skills/void/docs/node_modules/void/node_modules/pg/README.md +95 -0
- package/skills/void/docs/node_modules/void/node_modules/pglite-server/LICENSE.md +21 -0
- package/skills/void/docs/node_modules/void/node_modules/pglite-server/README.md +135 -0
- package/skills/void/docs/node_modules/void/node_modules/picocolors/README.md +21 -0
- package/skills/void/docs/node_modules/void/node_modules/tinyglobby/README.md +25 -0
- package/skills/void/docs/node_modules/void/node_modules/tsdown/README.md +55 -0
- package/skills/void/docs/node_modules/void/node_modules/valibot/LICENSE.md +9 -0
- package/skills/void/docs/node_modules/void/node_modules/valibot/README.md +94 -0
- package/skills/void/docs/node_modules/void/node_modules/vite/LICENSE.md +2230 -0
- package/skills/void/docs/node_modules/void/node_modules/vite/README.md +20 -0
- package/skills/void/docs/node_modules/void/node_modules/wrangler/README.md +63 -0
- package/skills/void/docs/node_modules/void/node_modules/zod/README.md +191 -0
- package/skills/void/docs/node_modules/void/skills/migrate-vite-cloudflare-to-void/SKILL.md +175 -0
- package/skills/void/docs/node_modules/void/skills/void/SKILL.md +75 -0
- package/skills/void/docs/node_modules/void/skills/void/command/void.md +7 -0
- package/skills/void/docs/reference/api.md +917 -0
- package/skills/void/docs/reference/cli.md +561 -0
- package/skills/void/docs/reference/config.md +408 -0
- package/skills/void/docs/reference/resource-inference.md +149 -0
- package/skills/void/docs/reference/structure.md +176 -0
- package/.npmignore +0 -29
- package/.travis.yml +0 -9
- package/favicon.ico +0 -0
- package/index.js +0 -14
- package/lib/Job.js +0 -150
- package/lib/Void.js +0 -99
- package/lib/scan.js +0 -19
- package/test/credentials.js +0 -20
- package/test/job.js +0 -64
- package/test/static/dir1/test6.html +0 -0
- package/test/static/dir2/test7.html +0 -0
- package/test/static/dir2/test8.html +0 -0
- package/test/static/dir2/test9.html +0 -0
- package/test/static/test1.html +0 -0
- package/test/static/test2.html +0 -0
- package/test/static/test3.html +0 -0
- package/test/void.js +0 -31
- /package/{test/static/dir1/test4.html → skills/void/docs/integrations/auth-providers.md} +0 -0
- /package/{test/static/dir1/test5.html → skills/void/docs/integrations/payment-processors.md} +0 -0
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import { a as join } from "./pathe.M-eThtNZ-D-kmWkCS.mjs";
|
|
2
|
+
import { n as cliTitle } from "./output-BwlcIYSR.mjs";
|
|
3
|
+
import { c as R, g as ge, u as Se, y as ye } from "./dist-Dayj3gCK.mjs";
|
|
4
|
+
import { r as readProjectConfig } from "./project-TqORyHn8.mjs";
|
|
5
|
+
import { n as PlatformClient, s as getToken } from "./client-snXOjrp1.mjs";
|
|
6
|
+
import { n as generateEnvTypes, t as findEnvFile } from "./env-types-DknSA4SO.mjs";
|
|
7
|
+
import { a as loadUserEnvFile, i as validateProdEnv, n as formatEnvReport, t as fetchRemoteSecretNames } from "./env-validation-DJKjR_8q.mjs";
|
|
8
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
9
|
+
//#region src/cli/env-example.ts
|
|
10
|
+
/**
|
|
11
|
+
* `void env example` — generate a `.env.example` block from the registered
|
|
12
|
+
* env schema, managed as a marker-delimited section so any user-managed
|
|
13
|
+
* entries (CI tokens, build flags, etc.) above or below the block survive
|
|
14
|
+
* a refresh.
|
|
15
|
+
*
|
|
16
|
+
* Marker convention mirrors the one used by `init.ts` for CLAUDE.md /
|
|
17
|
+
* AGENTS.md instructions: a literal start marker, a body, and a literal
|
|
18
|
+
* end marker. The markers are hash-prefixed so they remain valid dotenv
|
|
19
|
+
* comments and don't trip up tools that parse `.env` files.
|
|
20
|
+
*
|
|
21
|
+
* Schema introspection strategy:
|
|
22
|
+
* - Call `schema['~standard'].validate(undefined)`:
|
|
23
|
+
* • `{ value: undefined }` → optional (no default)
|
|
24
|
+
* • `{ value: <x> }` → has a default (value is `<x>`)
|
|
25
|
+
* • `{ issues: [...] }` → required
|
|
26
|
+
* - For enum hints, probe with a sentinel that is unlikely to match and
|
|
27
|
+
* parse the built-in `oneOf` error message ("Expected one of A, B, got ..."),
|
|
28
|
+
* yielding the valid values. This only works for Void's built-in
|
|
29
|
+
* `oneOf()` helper — third-party validators silently degrade to no hint,
|
|
30
|
+
* which is fine because `.env.example` is purely informational.
|
|
31
|
+
*
|
|
32
|
+
* This keeps the introspection layer Standard Schema-friendly (no private
|
|
33
|
+
* fields, no type-widening) while still giving a good DX for the common
|
|
34
|
+
* Void helpers.
|
|
35
|
+
*/
|
|
36
|
+
/** Load the user's env.ts so `defineEnv` registers the schema. */
|
|
37
|
+
async function loadRegisteredSchema(envFile) {
|
|
38
|
+
await loadUserEnvFile(envFile);
|
|
39
|
+
return (await import("./runtime/env-public.mjs"))._getRegisteredSchema();
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Introspect a single schema into an {@link EntryKind}.
|
|
43
|
+
*
|
|
44
|
+
* The probing logic is pure: it only calls the public `~standard.validate`
|
|
45
|
+
* contract, so it works for any Standard Schema-compliant validator.
|
|
46
|
+
*/
|
|
47
|
+
function classifySchema(schema) {
|
|
48
|
+
const enumValues = tryExtractEnumValues(schema);
|
|
49
|
+
const probe = schema["~standard"].validate(void 0);
|
|
50
|
+
if (probe instanceof Promise) return {
|
|
51
|
+
kind: "required",
|
|
52
|
+
enumValues
|
|
53
|
+
};
|
|
54
|
+
if ("issues" in probe && probe.issues) return {
|
|
55
|
+
kind: "required",
|
|
56
|
+
enumValues
|
|
57
|
+
};
|
|
58
|
+
if (probe.value === void 0) return {
|
|
59
|
+
kind: "optional",
|
|
60
|
+
enumValues
|
|
61
|
+
};
|
|
62
|
+
return {
|
|
63
|
+
kind: "default",
|
|
64
|
+
defaultValue: probe.value,
|
|
65
|
+
enumValues
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Attempt to pull enum values out of a Void `oneOf()` schema by probing with
|
|
70
|
+
* an invalid sentinel and parsing the error message. Returns undefined for
|
|
71
|
+
* any schema that isn't a built-in `oneOf`.
|
|
72
|
+
*/
|
|
73
|
+
function tryExtractEnumValues(schema) {
|
|
74
|
+
const result = schema["~standard"].validate("__void_env_example_probe__");
|
|
75
|
+
if (result instanceof Promise) return;
|
|
76
|
+
if (!("issues" in result) || !result.issues || result.issues.length === 0) return;
|
|
77
|
+
const message = result.issues[0].message;
|
|
78
|
+
const match = /^Expected one of (.+), got "/.exec(message);
|
|
79
|
+
if (!match) return;
|
|
80
|
+
return match[1].split(",").map((s) => s.trim());
|
|
81
|
+
}
|
|
82
|
+
/** Serialize a default value into a dotenv-friendly string. */
|
|
83
|
+
function serializeDefault(value) {
|
|
84
|
+
if (typeof value === "string") return value;
|
|
85
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
86
|
+
try {
|
|
87
|
+
return JSON.stringify(value);
|
|
88
|
+
} catch {
|
|
89
|
+
return "";
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Build the body of the managed env block (no markers) from a registered
|
|
94
|
+
* schema map.
|
|
95
|
+
*
|
|
96
|
+
* Grouped by:
|
|
97
|
+
* 1. required (no default, not optional)
|
|
98
|
+
* 2. required with default (prefilled value)
|
|
99
|
+
* 3. optional (empty value)
|
|
100
|
+
*
|
|
101
|
+
* Enum-valued keys get a leading `# enum: A | B | C` comment.
|
|
102
|
+
*/
|
|
103
|
+
function formatEnvExample(schema) {
|
|
104
|
+
const entries = Object.entries(schema).map(([key, s]) => ({
|
|
105
|
+
key,
|
|
106
|
+
classification: classifySchema(s)
|
|
107
|
+
}));
|
|
108
|
+
const required = entries.filter((e) => e.classification.kind === "required");
|
|
109
|
+
const withDefault = entries.filter((e) => e.classification.kind === "default");
|
|
110
|
+
const optional = entries.filter((e) => e.classification.kind === "optional");
|
|
111
|
+
const lines = [];
|
|
112
|
+
const writeGroup = (label, group) => {
|
|
113
|
+
if (group.length === 0) return;
|
|
114
|
+
if (lines.length > 0) lines.push("");
|
|
115
|
+
lines.push(`# ${label}`);
|
|
116
|
+
for (const entry of group) {
|
|
117
|
+
const enumValues = entry.classification.enumValues;
|
|
118
|
+
if (enumValues && enumValues.length > 0) lines.push(`# enum: ${enumValues.join(" | ")}`);
|
|
119
|
+
if (entry.classification.kind === "default") lines.push(`${entry.key}=${serializeDefault(entry.classification.defaultValue)}`);
|
|
120
|
+
else lines.push(`${entry.key}=`);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
writeGroup("required", required);
|
|
124
|
+
writeGroup("with defaults", withDefault);
|
|
125
|
+
writeGroup("optional", optional);
|
|
126
|
+
return lines.join("\n") + (lines.length > 0 ? "\n" : "");
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Literal start/end markers for the void-managed block. They are valid
|
|
130
|
+
* dotenv comments (hash-prefixed) so any tool that parses `.env.example`
|
|
131
|
+
* silently ignores them, and they are matched as whole lines (with
|
|
132
|
+
* defensive trailing-whitespace tolerance) when locating the block.
|
|
133
|
+
*/
|
|
134
|
+
const ENV_EXAMPLE_START_MARKER = "# >>> void env: managed block — do not edit between markers <<<";
|
|
135
|
+
const ENV_EXAMPLE_END_MARKER = "# >>> end void env <<<";
|
|
136
|
+
const ENV_EXAMPLE_MARKER_HINT = "# Run `void env example` to refresh.";
|
|
137
|
+
/** Regex matchers for the markers — full line, ignore trailing whitespace. */
|
|
138
|
+
const START_MARKER_RE = new RegExp(`^${ENV_EXAMPLE_START_MARKER.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\s*$`);
|
|
139
|
+
const END_MARKER_RE = new RegExp(`^${ENV_EXAMPLE_END_MARKER.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\s*$`);
|
|
140
|
+
function buildMarkerBlock(body) {
|
|
141
|
+
const trimmedBody = body.endsWith("\n") ? body.slice(0, -1) : body;
|
|
142
|
+
const parts = [ENV_EXAMPLE_START_MARKER, ENV_EXAMPLE_MARKER_HINT];
|
|
143
|
+
if (trimmedBody.length > 0) parts.push(trimmedBody);
|
|
144
|
+
parts.push(ENV_EXAMPLE_END_MARKER);
|
|
145
|
+
return parts.join("\n") + "\n";
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Pure helper that produces the new `.env.example` content given the
|
|
149
|
+
* existing file contents (or `null` when the file does not exist) and the
|
|
150
|
+
* formatted env body (without marker lines).
|
|
151
|
+
*
|
|
152
|
+
* Behavior matrix:
|
|
153
|
+
* - existing == null → `create` a fresh marker-only file
|
|
154
|
+
* - both markers present → `replace` the lines between them
|
|
155
|
+
* - no markers present → `append` the block at the end
|
|
156
|
+
* - exactly one marker present → `error` (mismatched markers)
|
|
157
|
+
*/
|
|
158
|
+
function applyMarkerBlock(existing, body) {
|
|
159
|
+
const block = buildMarkerBlock(body);
|
|
160
|
+
if (existing === null) return {
|
|
161
|
+
content: block,
|
|
162
|
+
action: "create"
|
|
163
|
+
};
|
|
164
|
+
const lines = existing.split("\n");
|
|
165
|
+
let startIdx = -1;
|
|
166
|
+
let endIdx = -1;
|
|
167
|
+
for (let i = 0; i < lines.length; i++) {
|
|
168
|
+
if (startIdx === -1 && START_MARKER_RE.test(lines[i])) {
|
|
169
|
+
startIdx = i;
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
if (startIdx !== -1 && END_MARKER_RE.test(lines[i])) {
|
|
173
|
+
endIdx = i;
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const hasStart = lines.some((l) => START_MARKER_RE.test(l));
|
|
178
|
+
const hasEnd = lines.some((l) => END_MARKER_RE.test(l));
|
|
179
|
+
if (hasStart && !hasEnd) return {
|
|
180
|
+
content: existing,
|
|
181
|
+
action: "error",
|
|
182
|
+
reason: "Found start marker but no matching end marker in .env.example. Restore `# >>> end void env <<<` or delete the file and re-run `void env example`."
|
|
183
|
+
};
|
|
184
|
+
if (!hasStart && hasEnd) return {
|
|
185
|
+
content: existing,
|
|
186
|
+
action: "error",
|
|
187
|
+
reason: "Found end marker but no matching start marker in .env.example. Restore `# >>> void env: ... <<<` or delete the file and re-run `void env example`."
|
|
188
|
+
};
|
|
189
|
+
if (startIdx !== -1 && endIdx !== -1) {
|
|
190
|
+
const before = lines.slice(0, startIdx);
|
|
191
|
+
const after = lines.slice(endIdx + 1);
|
|
192
|
+
const beforeText = before.length > 0 ? before.join("\n") + "\n" : "";
|
|
193
|
+
const afterText = after.join("\n");
|
|
194
|
+
return {
|
|
195
|
+
content: beforeText + block + afterText,
|
|
196
|
+
action: "replace"
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
const trimmed = existing.replace(/\s+$/, "");
|
|
200
|
+
return {
|
|
201
|
+
content: trimmed + (trimmed.length > 0 ? "\n\n" : "") + block,
|
|
202
|
+
action: "append"
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
/** CLI entrypoint: load schema, manage marker block, write `.env.example`. */
|
|
206
|
+
async function runEnvExample(root, options) {
|
|
207
|
+
const envFile = findEnvFile(root);
|
|
208
|
+
if (!envFile) {
|
|
209
|
+
ye("No env.ts found at project root — nothing to generate.");
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
const schema = await loadRegisteredSchema(envFile);
|
|
213
|
+
if (!schema || Object.keys(schema).length === 0) {
|
|
214
|
+
ye("env.ts registered no keys — nothing to generate.");
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
const outPath = join(root, ".env.example");
|
|
218
|
+
const existing = existsSync(outPath) ? readFileSync(outPath, "utf-8") : null;
|
|
219
|
+
const result = applyMarkerBlock(existing, formatEnvExample(schema));
|
|
220
|
+
if (result.action === "error") {
|
|
221
|
+
R.error(result.reason ?? "Failed to update .env.example.");
|
|
222
|
+
process.exit(1);
|
|
223
|
+
}
|
|
224
|
+
if (existing !== null && existing === result.content) {
|
|
225
|
+
ye(".env.example is already up to date.");
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
writeFileSync(outPath, result.content);
|
|
229
|
+
const count = Object.keys(schema).length;
|
|
230
|
+
const keyCount = `${count} key${count === 1 ? "" : "s"}`;
|
|
231
|
+
if (result.action === "create") R.success(`Wrote .env.example (${keyCount}).`);
|
|
232
|
+
else if (result.action === "replace") R.success(`Refreshed void env block in .env.example (${keyCount}).`);
|
|
233
|
+
else if (result.action === "append") {
|
|
234
|
+
R.success(`Refreshed void env block in .env.example (${keyCount}).`);
|
|
235
|
+
if (!options.force) R.info("appended void env block to existing .env.example");
|
|
236
|
+
}
|
|
237
|
+
ye("Done.");
|
|
238
|
+
}
|
|
239
|
+
//#endregion
|
|
240
|
+
//#region src/cli/env.ts
|
|
241
|
+
async function runEnvCommand(root, args) {
|
|
242
|
+
console.log();
|
|
243
|
+
ge(cliTitle(`env ${args.subcommand}`));
|
|
244
|
+
if (args.subcommand === "check") {
|
|
245
|
+
await runCheck(root, args.useRemoteSecrets);
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
if (args.subcommand === "types") {
|
|
249
|
+
runTypes(root);
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
if (args.subcommand === "example") {
|
|
253
|
+
await runEnvExample(root, { force: args.force });
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
async function runCheck(root, useRemoteSecrets) {
|
|
258
|
+
let remoteSecrets;
|
|
259
|
+
if (useRemoteSecrets) {
|
|
260
|
+
const token = getToken(root);
|
|
261
|
+
if (!token) {
|
|
262
|
+
R.error("--remote requires authentication. Run `void auth login` first.");
|
|
263
|
+
process.exit(1);
|
|
264
|
+
}
|
|
265
|
+
const config = readProjectConfig(root);
|
|
266
|
+
if (!config) {
|
|
267
|
+
R.error("--remote requires a linked project. Run `void project link` first.");
|
|
268
|
+
process.exit(1);
|
|
269
|
+
}
|
|
270
|
+
remoteSecrets = await fetchRemoteSecretNames(new PlatformClient(token, { root }), config.projectId);
|
|
271
|
+
}
|
|
272
|
+
const { hasSchema, report } = await validateProdEnv(root, {
|
|
273
|
+
productionOnly: true,
|
|
274
|
+
remoteSecrets
|
|
275
|
+
});
|
|
276
|
+
if (!hasSchema) {
|
|
277
|
+
ye("No env.ts found — nothing to validate.");
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
if (report.valid) {
|
|
281
|
+
ye("All required env vars are present and valid.");
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
Se(formatEnvReport(report), "Env validation failed");
|
|
285
|
+
if (report.missing.length > 0) R.info(`Set missing values via .env / .env.production, or upload as secrets with \`void secret put <NAME>\`.`);
|
|
286
|
+
process.exit(1);
|
|
287
|
+
}
|
|
288
|
+
function runTypes(root) {
|
|
289
|
+
const envFile = findEnvFile(root);
|
|
290
|
+
if (!envFile) {
|
|
291
|
+
ye("No env.ts found at project root — nothing to generate.");
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
const outDir = join(root, ".void");
|
|
295
|
+
mkdirSync(outDir, { recursive: true });
|
|
296
|
+
const { dts } = generateEnvTypes(envFile, outDir);
|
|
297
|
+
writeFileSync(join(outDir, "env.d.ts"), dts);
|
|
298
|
+
ye(`Wrote ${join(".void", "env.d.ts")}.`);
|
|
299
|
+
}
|
|
300
|
+
//#endregion
|
|
301
|
+
export { runEnvCommand };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { t as StandardSchemaV1 } from "./standard-schema-9CRjx-uR.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/shared/env-mask.d.ts
|
|
4
|
+
/** Per-key override set by `.secret()` / `.public()` on built-in helpers. */
|
|
5
|
+
type SecretOverride = "secret" | "public" | undefined;
|
|
6
|
+
//#endregion
|
|
7
|
+
//#region src/runtime/env-helpers.d.ts
|
|
8
|
+
/**
|
|
9
|
+
* Marker property read by the mask helpers. Present only on built-in
|
|
10
|
+
* schema builders; third-party Standard Schema validators fall back to the
|
|
11
|
+
* name/value heuristic (documented in `docs/guide/env-vars.md`).
|
|
12
|
+
*/
|
|
13
|
+
declare const SECRET_OVERRIDE_SYMBOL: unique symbol;
|
|
14
|
+
/**
|
|
15
|
+
* Pull the explicit `.secret()` / `.public()` flag off a Standard Schema
|
|
16
|
+
* validator, if it was authored through our built-in helpers. Returns
|
|
17
|
+
* `undefined` for third-party validators (valibot, zod, arktype, …) —
|
|
18
|
+
* they are redacted purely via the heuristic.
|
|
19
|
+
*/
|
|
20
|
+
declare function getSecretOverride(validator: {
|
|
21
|
+
[SECRET_OVERRIDE_SYMBOL]?: SecretOverride;
|
|
22
|
+
} | unknown): SecretOverride;
|
|
23
|
+
interface EnvSchema<T> extends StandardSchemaV1<unknown, T> {
|
|
24
|
+
optional(): EnvSchema<T | undefined>;
|
|
25
|
+
default(value: NonNullable<T>): EnvSchema<NonNullable<T>>;
|
|
26
|
+
/**
|
|
27
|
+
* Force redaction of this key's value in every validation/error surface,
|
|
28
|
+
* regardless of the key-name / value-content heuristics.
|
|
29
|
+
*/
|
|
30
|
+
secret(): EnvSchema<T>;
|
|
31
|
+
/**
|
|
32
|
+
* Opt this key out of redaction — useful for public config (URLs, app
|
|
33
|
+
* titles) that happens to match the heuristic (`PUBLIC_KEY`, `…_TOKEN_URL`).
|
|
34
|
+
*/
|
|
35
|
+
public(): EnvSchema<T>;
|
|
36
|
+
}
|
|
37
|
+
/** Required string env value. */
|
|
38
|
+
declare function string(): EnvSchema<string>;
|
|
39
|
+
/** Numeric env value. Parses with `Number(raw)`; rejects NaN. */
|
|
40
|
+
declare function number(): EnvSchema<number>;
|
|
41
|
+
/** Boolean env value. Accepts "true"/"false"/"1"/"0" (case-insensitive). */
|
|
42
|
+
declare function boolean(): EnvSchema<boolean>;
|
|
43
|
+
/** URL string — validated via `new URL(raw)`. */
|
|
44
|
+
declare function url(): EnvSchema<string>;
|
|
45
|
+
/** Email string — basic shape validation. */
|
|
46
|
+
declare function email(): EnvSchema<string>;
|
|
47
|
+
/** One of a fixed set of literal string values. */
|
|
48
|
+
declare function oneOf<const Values extends ReadonlyArray<string>>(values: Values): EnvSchema<Values[number]>;
|
|
49
|
+
/** JSON-parsed env value. Specify `T` to type the parsed result. */
|
|
50
|
+
declare function json<T = unknown>(): EnvSchema<T>;
|
|
51
|
+
//#endregion
|
|
52
|
+
export { getSecretOverride as a, oneOf as c, email as i, string as l, SECRET_OVERRIDE_SYMBOL as n, json as o, boolean as r, number as s, EnvSchema as t, url as u };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
//#region src/runtime/env-raw.ts
|
|
3
|
+
/**
|
|
4
|
+
* Raw runtime env resolution — framework-internal only.
|
|
5
|
+
*
|
|
6
|
+
* This module is NOT exported in package.json, so it cannot be imported
|
|
7
|
+
* via "void/..." subpaths. Only framework modules using relative imports
|
|
8
|
+
* (isr.ts, ai.ts, env.ts) can access it.
|
|
9
|
+
*/
|
|
10
|
+
/** Prefixes for platform-internal bindings that must be hidden from user code. */
|
|
11
|
+
const INTERNAL_BINDING_PREFIXES = ["__VOID_", "__PROJECT_"];
|
|
12
|
+
const envContext = new AsyncLocalStorage();
|
|
13
|
+
let cloudflareEnv;
|
|
14
|
+
if (typeof navigator !== "undefined" && navigator.userAgent === "Cloudflare-Workers") import("cloudflare:workers").then((mod) => {
|
|
15
|
+
cloudflareEnv = asEnv(mod.env) ?? void 0;
|
|
16
|
+
}).catch(() => {});
|
|
17
|
+
function asEnv(value) {
|
|
18
|
+
if (typeof value !== "object" || value === null) return null;
|
|
19
|
+
if ("then" in value && typeof value.then === "function") return null;
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
function getNuxtEnv() {
|
|
23
|
+
return asEnv(globalThis.__env__);
|
|
24
|
+
}
|
|
25
|
+
/** Resolve raw env from AsyncLocalStorage, Nuxt globals, or CF module env. */
|
|
26
|
+
function getRawRuntimeEnv() {
|
|
27
|
+
return envContext.getStore() ?? getNuxtEnv() ?? cloudflareEnv ?? (() => {
|
|
28
|
+
throw new Error("env: Cloudflare env is unavailable. Use void runtime bindings inside Nuxt/SvelteKit/Analog server request handlers or Worker handlers.");
|
|
29
|
+
})();
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
export { getRawRuntimeEnv as i, asEnv as n, envContext as r, INTERNAL_BINDING_PREFIXES as t };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { a as join, o as relative } from "./pathe.M-eThtNZ-D-kmWkCS.mjs";
|
|
2
|
+
import { i as voidWarn } from "./log-DXdqnmhF.mjs";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
//#region src/codegen/env-types.ts
|
|
5
|
+
/** Possible source locations for the user env schema, in priority order.
|
|
6
|
+
* Root-level files win over `src/`-nested ones. */
|
|
7
|
+
const ENV_FILE_CANDIDATES = [
|
|
8
|
+
"env.ts",
|
|
9
|
+
"env.mts",
|
|
10
|
+
"env.js",
|
|
11
|
+
"env.mjs",
|
|
12
|
+
"src/env.ts",
|
|
13
|
+
"src/env.mts",
|
|
14
|
+
"src/env.js",
|
|
15
|
+
"src/env.mjs"
|
|
16
|
+
];
|
|
17
|
+
/** Roots already warned about duplicate env.ts files — dedupes noisy repeat calls. */
|
|
18
|
+
const warnedRoots = /* @__PURE__ */ new Set();
|
|
19
|
+
/** Find the user's env schema file, if any. Warns once per root when multiple candidates exist. */
|
|
20
|
+
function findEnvFile(root) {
|
|
21
|
+
const matches = [];
|
|
22
|
+
for (const candidate of ENV_FILE_CANDIDATES) {
|
|
23
|
+
const abs = join(root, candidate);
|
|
24
|
+
if (existsSync(abs)) matches.push(abs);
|
|
25
|
+
}
|
|
26
|
+
if (matches.length > 1 && !warnedRoots.has(root)) {
|
|
27
|
+
warnedRoots.add(root);
|
|
28
|
+
const rel = matches.map((m) => relative(root, m));
|
|
29
|
+
voidWarn(`Multiple env schema files found — using "${rel[0]}" and ignoring ${rel.slice(1).map((r) => `"${r}"`).join(", ")}. Keep just one.`);
|
|
30
|
+
}
|
|
31
|
+
return matches[0] ?? null;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Generate `.void/env.d.ts` content. Augments:
|
|
35
|
+
* - `void/env`'s `ValidatedEnv` so `env.X` is typed
|
|
36
|
+
* - `void/handler`'s `CloudBindings` so `c.env.X` is typed
|
|
37
|
+
*
|
|
38
|
+
* Uses `typeof import("../env.ts").default` so TypeScript handles the
|
|
39
|
+
* inference — codegen never analyses types itself.
|
|
40
|
+
*
|
|
41
|
+
* @param envFileAbs Absolute path to the user's env schema file.
|
|
42
|
+
* @param outDir Absolute path to the project's `.void/` directory.
|
|
43
|
+
*/
|
|
44
|
+
function generateEnvTypes(envFileAbs, outDir) {
|
|
45
|
+
const importPath = relative(outDir, envFileAbs).replace(/\\/g, "/");
|
|
46
|
+
const lines = [];
|
|
47
|
+
lines.push("// Auto-generated by void — do not edit");
|
|
48
|
+
lines.push("export {}");
|
|
49
|
+
lines.push("");
|
|
50
|
+
lines.push(`type _VoidEnvSchema = typeof import("${importPath}");`);
|
|
51
|
+
lines.push("type _VoidEnvShape = _VoidEnvSchema extends { default: infer D } ? D : _VoidEnvSchema extends { env: infer E } ? E : {};");
|
|
52
|
+
lines.push("");
|
|
53
|
+
lines.push("declare module \"void/env\" {");
|
|
54
|
+
lines.push(" interface ValidatedEnv extends _VoidEnvShape {}");
|
|
55
|
+
lines.push("}");
|
|
56
|
+
lines.push("");
|
|
57
|
+
lines.push("declare module \"void/handler\" {");
|
|
58
|
+
lines.push(" interface CloudBindings extends _VoidEnvShape {}");
|
|
59
|
+
lines.push("}");
|
|
60
|
+
lines.push("");
|
|
61
|
+
return { dts: lines.join("\n") };
|
|
62
|
+
}
|
|
63
|
+
//#endregion
|
|
64
|
+
export { generateEnvTypes as n, findEnvFile as t };
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { a as join } from "./pathe.M-eThtNZ-D-kmWkCS.mjs";
|
|
2
|
+
import { i as voidWarn } from "./log-DXdqnmhF.mjs";
|
|
3
|
+
import { n as mergeAndExpand, r as parseDotenvFile } from "./dotenv-DwO4ti0Z.mjs";
|
|
4
|
+
import { t as findEnvFile } from "./env-types-DknSA4SO.mjs";
|
|
5
|
+
import { pathToFileURL } from "node:url";
|
|
6
|
+
//#region src/host/load-user-env.ts
|
|
7
|
+
/**
|
|
8
|
+
* Loader for the user's `env.ts`.
|
|
9
|
+
*
|
|
10
|
+
* Uses Node's native `import()` (type-stripping is on by default in the
|
|
11
|
+
* supported Node version), so only relative imports and bare package
|
|
12
|
+
* specifiers resolve. tsconfig path aliases (`@/foo`, `~/foo`) are NOT
|
|
13
|
+
* supported — if the user writes one, we detect the resulting resolution
|
|
14
|
+
* error and re-throw with guidance pointing at the offending specifier.
|
|
15
|
+
*
|
|
16
|
+
* Used by:
|
|
17
|
+
* - `plugin-env-schema.ts` (dev plugin, HMR re-imports)
|
|
18
|
+
* - `cli/env-validation.ts` (deploy + `void env check`)
|
|
19
|
+
*
|
|
20
|
+
* Side-effect contract: loading the file evaluates the user's `defineEnv`
|
|
21
|
+
* call, which registers the schema in the singleton state in
|
|
22
|
+
* `runtime/env-public.ts`. Callers read the result from there.
|
|
23
|
+
*
|
|
24
|
+
* Node-only (lives under `host/`). Must not be imported from anything
|
|
25
|
+
* that ships in worker bundles.
|
|
26
|
+
*/
|
|
27
|
+
let loadCounter = 0;
|
|
28
|
+
/**
|
|
29
|
+
* Returns the specifier from a Node resolution error if the error looks
|
|
30
|
+
* like one — otherwise `null`. Both `ERR_MODULE_NOT_FOUND` and
|
|
31
|
+
* `ERR_UNSUPPORTED_DIR_IMPORT` have the specifier embedded in the message.
|
|
32
|
+
*/
|
|
33
|
+
function extractFailedSpecifier(err) {
|
|
34
|
+
if (!(err instanceof Error)) return null;
|
|
35
|
+
const code = err.code;
|
|
36
|
+
if (code !== "ERR_MODULE_NOT_FOUND" && code !== "ERR_PACKAGE_PATH_NOT_EXPORTED") return null;
|
|
37
|
+
const match = /Cannot find (?:package|module) '([^']+)'/.exec(err.message);
|
|
38
|
+
return match ? match[1] ?? null : null;
|
|
39
|
+
}
|
|
40
|
+
/** A specifier is alias-shaped if it isn't relative, absolute, a node: URL, or a valid bare package name. */
|
|
41
|
+
function looksLikeAlias(specifier) {
|
|
42
|
+
if (specifier.startsWith("./") || specifier.startsWith("../") || specifier.startsWith("/") || specifier.startsWith("node:") || specifier.startsWith("file:")) return false;
|
|
43
|
+
if (specifier.startsWith("@")) return !/^@[^/]+\/[^/]+/.test(specifier);
|
|
44
|
+
return specifier.startsWith("~") || specifier.startsWith("#");
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Load the user's env.ts via native `import()`. The URL gets a cache-busting
|
|
48
|
+
* query param so HMR re-imports re-evaluate the file.
|
|
49
|
+
*
|
|
50
|
+
* On resolution failures, wraps the error with the source file path, and if
|
|
51
|
+
* the failed specifier looks like a tsconfig path alias, appends guidance
|
|
52
|
+
* explaining that env.ts doesn't resolve aliases.
|
|
53
|
+
*/
|
|
54
|
+
async function loadUserEnvFile(envFile) {
|
|
55
|
+
const url = pathToFileURL(envFile).href + `?t=${Date.now()}-${++loadCounter}`;
|
|
56
|
+
try {
|
|
57
|
+
await import(
|
|
58
|
+
/* @vite-ignore */
|
|
59
|
+
url
|
|
60
|
+
);
|
|
61
|
+
} catch (err) {
|
|
62
|
+
const specifier = extractFailedSpecifier(err);
|
|
63
|
+
const base = `env: Failed to load '${envFile}': '${err.message}'.`;
|
|
64
|
+
if (specifier && looksLikeAlias(specifier)) throw new Error(`${base}\n\nHint: '${specifier}' looks like a tsconfig path alias. env.ts is loaded directly by Node and does not resolve tsconfig "paths" — use a relative import (e.g. "./shared/...") instead.`);
|
|
65
|
+
throw new Error(base);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
//#endregion
|
|
69
|
+
//#region src/cli/env-validation.ts
|
|
70
|
+
/**
|
|
71
|
+
* Shared env-schema validation for CLI commands.
|
|
72
|
+
*
|
|
73
|
+
* Loads the user's `env.ts` (which calls `defineEnv` as a side effect),
|
|
74
|
+
* collects sources of env values (`.env*` files, remote secrets), and
|
|
75
|
+
* validates each declared key against the registered schema.
|
|
76
|
+
*
|
|
77
|
+
* Used by both `void deploy` (hard error on missing prod env) and
|
|
78
|
+
* `void env check` (CI/pre-push validation).
|
|
79
|
+
*/
|
|
80
|
+
/**
|
|
81
|
+
* After the user's env.ts has been imported (via `validateProdEnv` or
|
|
82
|
+
* `loadSchema`), read the registered schema's `.default(value)` entries.
|
|
83
|
+
* Returns `{}` if no schema was registered.
|
|
84
|
+
*/
|
|
85
|
+
async function getDeployEnvDefaults(root) {
|
|
86
|
+
const envFile = findEnvFile(root);
|
|
87
|
+
if (!envFile) return {};
|
|
88
|
+
const mod = await loadSchema(envFile);
|
|
89
|
+
if (!mod) return {};
|
|
90
|
+
return mod._getSchemaDefaults();
|
|
91
|
+
}
|
|
92
|
+
/** Load the registered schema by importing the user's env.ts. */
|
|
93
|
+
async function loadSchema(envFile) {
|
|
94
|
+
await loadUserEnvFile(envFile);
|
|
95
|
+
const mod = await import("./runtime/env-public.mjs");
|
|
96
|
+
if (!mod._hasRegisteredSchema()) return null;
|
|
97
|
+
return mod;
|
|
98
|
+
}
|
|
99
|
+
function emptyReport() {
|
|
100
|
+
return {
|
|
101
|
+
valid: true,
|
|
102
|
+
missing: [],
|
|
103
|
+
invalid: [],
|
|
104
|
+
values: /* @__PURE__ */ new Map()
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Validate the user's env schema against the union of .env files and
|
|
109
|
+
* remote secret names. Remote secrets are treated as "present" (we can't
|
|
110
|
+
* fetch their values), which is sufficient for the missing-key check.
|
|
111
|
+
*/
|
|
112
|
+
async function validateProdEnv(root, options) {
|
|
113
|
+
const envFile = findEnvFile(root);
|
|
114
|
+
if (!envFile) return {
|
|
115
|
+
hasSchema: false,
|
|
116
|
+
report: emptyReport()
|
|
117
|
+
};
|
|
118
|
+
const mod = await loadSchema(envFile);
|
|
119
|
+
if (!mod) return {
|
|
120
|
+
hasSchema: false,
|
|
121
|
+
report: emptyReport()
|
|
122
|
+
};
|
|
123
|
+
const merged = mergeAndExpand((options.productionOnly ? [".env", ".env.production"] : [
|
|
124
|
+
".env",
|
|
125
|
+
".env.local",
|
|
126
|
+
".env.production",
|
|
127
|
+
".env.production.local"
|
|
128
|
+
]).map((file) => parseDotenvFile(join(root, file), { expand: false })), { onWarn: (msg) => voidWarn(msg) });
|
|
129
|
+
const report = await mod.validateAllEnv(merged);
|
|
130
|
+
const remoteSet = new Set(options.remoteSecrets ?? []);
|
|
131
|
+
if (remoteSet.size > 0 && report.missing.length > 0) {
|
|
132
|
+
report.missing = report.missing.filter((key) => !remoteSet.has(key));
|
|
133
|
+
if (report.missing.length === 0 && report.invalid.length === 0) report.valid = true;
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
hasSchema: true,
|
|
137
|
+
report
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
/** Format an EnvValidationReport into a human-readable multi-line string. */
|
|
141
|
+
function formatEnvReport(report) {
|
|
142
|
+
const lines = [];
|
|
143
|
+
if (report.missing.length > 0) {
|
|
144
|
+
lines.push("Missing required env vars:");
|
|
145
|
+
for (const key of report.missing) lines.push(` • ${key}`);
|
|
146
|
+
}
|
|
147
|
+
if (report.invalid.length > 0) {
|
|
148
|
+
if (lines.length > 0) lines.push("");
|
|
149
|
+
lines.push("Invalid env vars:");
|
|
150
|
+
for (const { key, messages } of report.invalid) lines.push(` • ${key}: ${messages.join("; ")}`);
|
|
151
|
+
}
|
|
152
|
+
return lines.join("\n");
|
|
153
|
+
}
|
|
154
|
+
/** Convenience: fetch remote secret names from the platform. */
|
|
155
|
+
async function fetchRemoteSecretNames(client, projectId) {
|
|
156
|
+
try {
|
|
157
|
+
return (await client.listSecrets(projectId)).map((s) => s.name);
|
|
158
|
+
} catch {
|
|
159
|
+
return [];
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
//#endregion
|
|
163
|
+
export { loadUserEnvFile as a, validateProdEnv as i, formatEnvReport as n, getDeployEnvDefaults as r, fetchRemoteSecretNames as t };
|