void 0.1.6 → 0.7.1
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-DVKi6dzh.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-B0BgSTZi.mjs +47 -0
- package/dist/cancel-deploy-D9OFt5gA.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 +1814 -0
- package/dist/client-BUdfE3QJ.mjs +622 -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-CN1pF-OQ.mjs +90 -0
- package/dist/db-BIP2kuEt.mjs +895 -0
- package/dist/defer-DcxEsVH1.mjs +49 -0
- package/dist/delete-DJTvwbr-.mjs +64 -0
- package/dist/deploy-BqXz1ycW.mjs +2723 -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-B-fIU3VE.mjs +79 -0
- package/dist/dotenv-DwO4ti0Z.mjs +173 -0
- package/dist/drizzle-NnudE_UN.mjs +232 -0
- package/dist/env-BwbZJd2x.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-Bb_Qsdq6.mjs +2625 -0
- package/dist/link-D4d26PCm.mjs +49 -0
- package/dist/list-bQc1eQCZ.mjs +113 -0
- package/dist/log-DXdqnmhF.mjs +26 -0
- package/dist/login-RWUDCfdx.mjs +72 -0
- package/dist/logs-DrkTklop.mjs +98 -0
- package/dist/magic-string.es-D6g9UnIy.mjs +1011 -0
- package/dist/mcp-kZ4zg13a.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-ATFi3kRm.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-BSyita3C.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-DmjBDxB1.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 +564 -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,233 @@
|
|
|
1
|
+
---
|
|
2
|
+
outline: deep
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Quickstart
|
|
6
|
+
|
|
7
|
+
## Start in an Empty Directory
|
|
8
|
+
|
|
9
|
+
Install the Void CLI from npm:
|
|
10
|
+
|
|
11
|
+
`npm`
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
npm install -D void
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
`pnpm`
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
pnpm add -D void
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
`yarn`
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
yarn add -D void
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`bun`
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
bun add -D void
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
In an empty directory, `void init` adds the matching Pages adapter and starter dependencies after you choose a framework.
|
|
36
|
+
|
|
37
|
+
As part of `void init`, you'll choose a Pages framework (React, Vue, Svelte, or Solid) and a starter type. D1 is the default top option and scaffolds a DB-backed page loader, schema, generated migration, `db/seed.ts`, and API route. PostgreSQL scaffolds the same starter and writes `"database": "pg"` to `void.json`. Static Pages skips the database and server starter files so you can start with static content and add Void features later.
|
|
38
|
+
|
|
39
|
+
After installation, run the setup flow:
|
|
40
|
+
|
|
41
|
+
::: code-group
|
|
42
|
+
|
|
43
|
+
```sh [npm]
|
|
44
|
+
npx void init
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
```sh [pnpm]
|
|
48
|
+
pnpm void init
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
```sh [yarn]
|
|
52
|
+
yarn void init
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
```sh [bun]
|
|
56
|
+
bunx void init
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
:::
|
|
60
|
+
|
|
61
|
+
At the end of the full interactive flow, `void init` can also handle Void project setup by logging you in and linking or creating your Void project. That means the default first-time path is install packages, run `void init`, then `void deploy`.
|
|
62
|
+
|
|
63
|
+
For the database-backed starters, D1 is the zero-config default for prototyping and read-heavy apps, while PostgreSQL is better when you already have Postgres infrastructure or need heavier writes and more complex queries.
|
|
64
|
+
|
|
65
|
+
<details>
|
|
66
|
+
<summary style="cursor:pointer">
|
|
67
|
+
💡 <b>Notes on <code>void</code> binary usage</b>
|
|
68
|
+
</summary>
|
|
69
|
+
|
|
70
|
+
`void` is a local binary from the installed `void` package, so outside of npm scripts, you will have to invoke it with `npx`, `pnpm`, `yarn`, or `bunx`. For brevity, you will sometimes see unprefixed `void` usage throughout the docs. Just remember it needs to be invoked through a binary runner.
|
|
71
|
+
|
|
72
|
+
Alternatively, you can add `./node_modules/.bin` to your `PATH` so that you can invoke `void` directly when you are in the root directory of your app.
|
|
73
|
+
|
|
74
|
+
:::warning ⚠️ Prefer local install
|
|
75
|
+
We do not recommend installing `void` globally, because the CLI needs to be in sync with same version of the runtime framework. Always install `void` locally as a dev dependency of your project.
|
|
76
|
+
:::
|
|
77
|
+
|
|
78
|
+
</details>
|
|
79
|
+
|
|
80
|
+
## Using with Coding Agents
|
|
81
|
+
|
|
82
|
+
`void init` detects your agent once and reuses that choice for instructions, skills linking, and MCP config.
|
|
83
|
+
|
|
84
|
+
If auto-detection fails, `void init` asks you to choose from a short list (Claude, Cursor, Codex, Gemini CLI, Generic).
|
|
85
|
+
|
|
86
|
+
In supported agents such as Claude Code, you can invoke the `/void` skill to turn your agent into a Void export. Then, simply ask the agent to build an app with Void. See the [Coding Agents](../integrations/agents) guide for more details.
|
|
87
|
+
|
|
88
|
+
## Meta Frameworks
|
|
89
|
+
|
|
90
|
+
Void as a platform supports Vite-based meta frameworks, but the Void SDK itself is also a powerful and flexible meta framework via its [Pages routing](./pages-routing/overview) feature. If you only want to use an existing meta framework and deploy to Void, check out the [Framework Integration Guides](../integrations/frameworks/overview).
|
|
91
|
+
|
|
92
|
+
## Adding to an Existing Vite App
|
|
93
|
+
|
|
94
|
+
::: code-group
|
|
95
|
+
|
|
96
|
+
```sh [npm]
|
|
97
|
+
npm install -D void
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
```sh [pnpm]
|
|
101
|
+
pnpm add -D void
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
```sh [yarn]
|
|
105
|
+
yarn add -D void
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
```sh [bun]
|
|
109
|
+
bun add -D void
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
:::
|
|
113
|
+
|
|
114
|
+
Enable the plugin in `vite.config.ts`
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
import { defineConfig } from 'vite';
|
|
118
|
+
import { voidPlugin } from 'void';
|
|
119
|
+
|
|
120
|
+
export default defineConfig({
|
|
121
|
+
plugins: [voidPlugin()],
|
|
122
|
+
});
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Then run the setup guide via `void` (Void CLI):
|
|
126
|
+
|
|
127
|
+
::: code-group
|
|
128
|
+
|
|
129
|
+
```sh [npm]
|
|
130
|
+
npx void init
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
```sh [pnpm]
|
|
134
|
+
pnpm void init
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
```sh [yarn]
|
|
138
|
+
yarn void init
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
```sh [bun]
|
|
142
|
+
bunx void init
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
:::
|
|
146
|
+
|
|
147
|
+
## Once You Have a Working App
|
|
148
|
+
|
|
149
|
+
### 1. Edit the generated API route
|
|
150
|
+
|
|
151
|
+
Your starter already includes `routes/api/hello.ts` with a named `GET` export:
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
import { defineHandler } from 'void';
|
|
155
|
+
|
|
156
|
+
export const GET = defineHandler(() => {
|
|
157
|
+
return { message: 'Hello from Void' };
|
|
158
|
+
});
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### 2. Run locally
|
|
162
|
+
|
|
163
|
+
```sh
|
|
164
|
+
npm run dev
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Then visit:
|
|
168
|
+
|
|
169
|
+
- App: `http://localhost:5173`
|
|
170
|
+
- API route: `http://localhost:5173/api/hello`
|
|
171
|
+
|
|
172
|
+
### 3. Finish Void project setup if you skipped it during `void init`
|
|
173
|
+
|
|
174
|
+
```sh
|
|
175
|
+
void auth login
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
If you already logged in and linked a project during `void init`, you can skip this step.
|
|
179
|
+
|
|
180
|
+
### 4. Deploy
|
|
181
|
+
|
|
182
|
+
Set secrets once before deploying, if any:
|
|
183
|
+
|
|
184
|
+
```sh
|
|
185
|
+
void secret put KEY=value
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Then run:
|
|
189
|
+
|
|
190
|
+
```sh
|
|
191
|
+
void deploy
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
```sh
|
|
195
|
+
┌ void deploy
|
|
196
|
+
│
|
|
197
|
+
◇ Building...
|
|
198
|
+
│ (vite build output)
|
|
199
|
+
│
|
|
200
|
+
ℹ Found N migration(s)
|
|
201
|
+
│
|
|
202
|
+
◇ Checking assets...
|
|
203
|
+
◇ Uploading X/Y assets (Z cached)
|
|
204
|
+
◇ Packaging...
|
|
205
|
+
◇ Deploying...
|
|
206
|
+
◇ Deployed!
|
|
207
|
+
│
|
|
208
|
+
│ ╭─────────────────────────────────────────╮
|
|
209
|
+
│ │ https://my-app.void.app │
|
|
210
|
+
│ │ │
|
|
211
|
+
│ │ 2 worker module(s), 5 static asset(s) │
|
|
212
|
+
│ │ 1 migration(s) applied │
|
|
213
|
+
│ │ SSR enabled │
|
|
214
|
+
│ ╰─────────────────────────────────────────╯
|
|
215
|
+
│
|
|
216
|
+
└ Done!
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
On first deploy, Void will:
|
|
220
|
+
|
|
221
|
+
- build your app
|
|
222
|
+
- create or link a project if you did not already do that during `void init`
|
|
223
|
+
- provision required resources (for example D1/KV/R2 when inferred)
|
|
224
|
+
- deploy to `https://<slug>.void.app`
|
|
225
|
+
|
|
226
|
+
Right now, only deploys via the CLI is supported. To setup push-to-deploy GitHub, run `void init --github`.
|
|
227
|
+
|
|
228
|
+
## Next steps
|
|
229
|
+
|
|
230
|
+
- To understand what kind of apps are supported: [Supported App Types](./app-types)
|
|
231
|
+
- [Server Routing](./server-routing): dynamic params, middleware, and validation
|
|
232
|
+
- [Database](./database): queries, migrations, and generated types
|
|
233
|
+
- [Type Safety](./type-safety): end-to-end typed fetch client
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
outline: deep
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Remote Development
|
|
6
|
+
|
|
7
|
+
During local development, Void uses local emulations of D1, KV, and R2 through [Miniflare](https://miniflare.dev/). That covers most work, but sometimes you need real data for debugging a production issue, testing against a populated database, or validating R2 uploads end to end.
|
|
8
|
+
|
|
9
|
+
Remote development mode connects your local dev server to the **real bindings** from your deployed project. Your code does not change. `db.select()`, `env.KV.get()`, and `env.STORAGE.get()` work the same way, but they hit remote resources instead of local emulations.
|
|
10
|
+
|
|
11
|
+
## Prerequisites
|
|
12
|
+
|
|
13
|
+
Before enabling remote mode, you need:
|
|
14
|
+
|
|
15
|
+
1. **Logged in:** run `void auth login` if you have not already
|
|
16
|
+
2. **Project linked:** run `void deploy` at least once to create and link a project
|
|
17
|
+
|
|
18
|
+
## Enabling Remote Mode
|
|
19
|
+
|
|
20
|
+
### In `void.json` (persistent)
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{
|
|
24
|
+
"remote": true
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Via environment variable (one-off)
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
VOID_REMOTE=1 vite dev
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`VOID_REMOTE=0` disables remote mode even if `void.json` has `"remote": true`.
|
|
35
|
+
|
|
36
|
+
## Supported Bindings
|
|
37
|
+
|
|
38
|
+
| Binding | Local (default) | Remote |
|
|
39
|
+
| ------- | -------------------------- | ------------------- |
|
|
40
|
+
| D1 | Local SQLite via Miniflare | Remote D1 database |
|
|
41
|
+
| KV | Local file-backed KV | Remote KV namespace |
|
|
42
|
+
| R2 | Local file-backed R2 | Remote R2 bucket |
|
|
43
|
+
| AI | Always proxied | Always proxied |
|
|
44
|
+
|
|
45
|
+
AI inference is always routed through the proxy regardless of remote mode. There is no local AI emulation.
|
|
46
|
+
|
|
47
|
+
## How It Works
|
|
48
|
+
|
|
49
|
+
When remote mode is active, the dev server replaces local Miniflare bindings with proxy-backed versions at runtime. Every binding call is forwarded to your deployed resources via Void's proxy service, authenticated with your login token. The proxy resolves which D1 database, KV namespace, or R2 bucket to use based on your project's binding configuration.
|
|
50
|
+
|
|
51
|
+
You don't need to change any code. Imports like `import { db } from "void/db"` and direct binding access via `c.env.KV` both work transparently.
|
|
52
|
+
|
|
53
|
+
When the dev server starts with remote mode active, it prints:
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
⚡ Remote bindings active (my-project.void.app)
|
|
57
|
+
DB → remote D1
|
|
58
|
+
KV → remote KV
|
|
59
|
+
STORAGE → remote R2
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Limitations
|
|
63
|
+
|
|
64
|
+
- **Network latency:** every binding call goes over the network, so local dev is slower than local emulation. This is expected.
|
|
65
|
+
- **R2 multipart uploads:** `createMultipartUpload()` and `resumeMultipartUpload()` are not supported in remote mode.
|
|
66
|
+
- **D1 dump:** `db.dump()` is not supported in remote mode.
|
|
67
|
+
- **Writes affect real data:** remote mode connects to your actual deployed resources. Inserts, updates, and deletes are real, so use it carefully or point it at a staging project.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
---
|
|
2
|
+
outline: deep
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Sandboxes
|
|
6
|
+
|
|
7
|
+
Void can wire Cloudflare Sandboxes into Void apps. A sandbox gives each session an isolated container for running commands, working with files, and exposing ports from server-side code.
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { defineHandler } from 'void';
|
|
11
|
+
import { getSandbox } from 'void/sandbox';
|
|
12
|
+
|
|
13
|
+
export const POST = defineHandler(async (c) => {
|
|
14
|
+
const { command } = await c.req.json<{ command: string }>();
|
|
15
|
+
const sandbox = getSandbox('default');
|
|
16
|
+
const result = await sandbox.exec(command);
|
|
17
|
+
|
|
18
|
+
return c.json(result);
|
|
19
|
+
});
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Importing from `void/sandbox` enables the `SANDBOX` Durable Object binding, exports the SDK's `Sandbox` class from the generated Worker entry, and adds the matching `containers` and migration metadata to the Cloudflare worker config.
|
|
23
|
+
|
|
24
|
+
## Configuration
|
|
25
|
+
|
|
26
|
+
Most apps do not need config. The default binding is `SANDBOX`, the Durable Object class is `Sandbox`, local development uses the Dockerfile bundled with `@cloudflare/sandbox`, and `void deploy` uses the matching published sandbox image.
|
|
27
|
+
|
|
28
|
+
Use `void.json` when you need a custom image or container size:
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"sandbox": {
|
|
33
|
+
"image": "./Dockerfile.sandbox",
|
|
34
|
+
"platformImage": "registry.example.com/acme/sandbox:latest",
|
|
35
|
+
"instanceType": "lite",
|
|
36
|
+
"maxInstances": 2
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Available fields:
|
|
42
|
+
|
|
43
|
+
| Field | Default | Description |
|
|
44
|
+
| ------------------- | ------------------------------ | -------------------------------------------------------- |
|
|
45
|
+
| `binding` | `SANDBOX` | Worker binding name |
|
|
46
|
+
| `className` | `Sandbox` | Durable Object class exported by the Worker |
|
|
47
|
+
| `containerName` | `void-sandbox` | Cloudflare container app name |
|
|
48
|
+
| `image` | Bundled sandbox SDK Dockerfile | Dockerfile path or registry image used by Wrangler/local |
|
|
49
|
+
| `imageBuildContext` | Directory of `image` | Docker build context for Wrangler/local |
|
|
50
|
+
| `platformImage` | Matching sandbox SDK image | Registry image used by `void deploy` |
|
|
51
|
+
| `instanceType` | `lite` on Void deploy | Container size, such as `lite`, `basic`, `standard-1` |
|
|
52
|
+
| `maxInstances` | `20` on Void deploy | Maximum number of container instances |
|
|
53
|
+
|
|
54
|
+
## Runtime API
|
|
55
|
+
|
|
56
|
+
`getSandbox(id, options)` returns the SDK sandbox stub for a session id. IDs are normalized by default so user-provided session ids can safely map to Durable Object names.
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
import { getSandbox } from 'void/sandbox';
|
|
60
|
+
|
|
61
|
+
const sandbox = getSandbox(`user-${user.id}`);
|
|
62
|
+
await sandbox.writeFile('/tmp/input.txt', 'hello');
|
|
63
|
+
const result = await sandbox.exec('cat /tmp/input.txt');
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
You can also use the namespace directly from `c.env.SANDBOX` when you need lower-level Durable Object control.
|
|
67
|
+
|
|
68
|
+
## State persistence
|
|
69
|
+
|
|
70
|
+
There are two distinct layers to think about: stable Durable Object identity, and ephemeral container state.
|
|
71
|
+
|
|
72
|
+
`getSandbox(id)` always resolves to the same Durable Object instance for a given `id`, regardless of how many times the project has been deployed or rolled back. Anything written through the DO's persistent storage (`ctx.storage`, the embedded SQLite database) survives deploys, rollbacks, and container restarts. That layer is the durable home for sandbox metadata, session ids, and any data you need to outlive the container.
|
|
73
|
+
|
|
74
|
+
The container itself — filesystem, running processes, exposed ports, in-memory shell sessions — is tied to a single container lifetime and is **not** durable. Cloudflare Containers idle out after inactivity (the SDK default is `sleepAfter: "10m"`), and a container can also restart on a process crash or a platform-side reschedule. When that happens, files in the container filesystem, background processes, and previously exposed ports are lost. Setting `keepAlive: true` disables the idle timer but does not protect against crashes or infrastructure restarts.
|
|
75
|
+
|
|
76
|
+
Treat the sandbox container as a working environment, not a source of truth. Persist anything you cannot afford to lose to DO storage, your database, KV, or R2 (the SDK also offers backup/restore helpers for snapshotting a directory to R2). Project deletion destroys both layers, but plenty of routine events destroy only the container layer.
|
|
77
|
+
|
|
78
|
+
## Deployment
|
|
79
|
+
|
|
80
|
+
`void deploy` provisions the `SANDBOX` Durable Object namespace, attaches the Cloudflare Container metadata to the Worker upload, and creates or updates the matching container application in the Void platform account.
|
|
81
|
+
|
|
82
|
+
Platform deploys require a registry image reference. The default sandbox works without extra config. If `sandbox.image` points at a custom local Dockerfile, also set `sandbox.platformImage` to an image you have already pushed to a registry.
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
---
|
|
2
|
+
outline: deep
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Server Routing
|
|
6
|
+
|
|
7
|
+
Full-stack Void apps uses file-based routing powered by [Hono](https://hono.dev). Drop files in `routes/` and they become endpoints. Add global middleware in `middleware/`.
|
|
8
|
+
|
|
9
|
+
## Route Files
|
|
10
|
+
|
|
11
|
+
Create route handlers in `routes/**/*.ts`. Each file maps to a URL path based on its location in the filesystem:
|
|
12
|
+
|
|
13
|
+
<RoutesFileTree />
|
|
14
|
+
|
|
15
|
+
Dynamic segments use brackets: `[id]` becomes a route parameter and `[...slug]` becomes a catch-all. Files or directories starting with `_` are ignored. Directories wrapped in parentheses like `(admin)` are route groups. They help organize files without changing the URL.
|
|
16
|
+
|
|
17
|
+
You can add a `.dev` or `.prod` suffix before the extension (e.g. `debug.dev.ts`) to include a route only in that environment.
|
|
18
|
+
|
|
19
|
+
Each file exports named HTTP method constants to handle specific methods:
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
// routes/api/hello.ts → GET /api/hello
|
|
23
|
+
import { defineHandler } from 'void';
|
|
24
|
+
|
|
25
|
+
export const GET = defineHandler((c) => {
|
|
26
|
+
return { message: 'Hello!', timestamp: Date.now() };
|
|
27
|
+
});
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
A file can export multiple methods:
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
// routes/api/users/index.ts → GET + POST /api/users
|
|
34
|
+
import { defineHandler } from 'void';
|
|
35
|
+
import { db } from 'void/db';
|
|
36
|
+
import { users } from '@schema';
|
|
37
|
+
|
|
38
|
+
export const GET = defineHandler(async () => {
|
|
39
|
+
return await db.select().from(users);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
export const POST = defineHandler(async (c) => {
|
|
43
|
+
const body = await c.req.json();
|
|
44
|
+
await db.insert(users).values({ name: body.name });
|
|
45
|
+
return { created: true };
|
|
46
|
+
});
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The `db` helper provides a typed query API over D1. See [Database](./database.md) for the full API.
|
|
50
|
+
|
|
51
|
+
## `defineHandler`
|
|
52
|
+
|
|
53
|
+
`defineHandler` wraps a route handler function:
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import { defineHandler } from 'void';
|
|
57
|
+
|
|
58
|
+
export const GET = defineHandler((c) => {
|
|
59
|
+
return { data: 'hello' };
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The handler receives a Hono `Context` with typed Cloudflare bindings on `c.env` (see [Cloudflare](../integrations/cloudflare.md)). You can use the full Hono API (`c.json()`, `c.text()`, `c.header()`, etc.).
|
|
64
|
+
|
|
65
|
+
Return values are automatically converted:
|
|
66
|
+
|
|
67
|
+
- **object/array/number/boolean** → JSON response
|
|
68
|
+
- **`string`** → `text/html; charset=utf-8`
|
|
69
|
+
- **`null`/`undefined`** → `204 No Content`
|
|
70
|
+
- **`Response`** → returned as-is
|
|
71
|
+
|
|
72
|
+
## Validation
|
|
73
|
+
|
|
74
|
+
`defineHandler.withValidator()` adds input validation for `body`, `query`, and `params`. The recommended approach is to derive validators from your [Drizzle schema](./database.md#schema-derived-validators), which keeps validation in sync with the database.
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
// routes/api/users/index.ts
|
|
78
|
+
import { defineHandler } from 'void';
|
|
79
|
+
import { db } from 'void/db';
|
|
80
|
+
import { users, insertUserSchema } from '@schema';
|
|
81
|
+
|
|
82
|
+
export const POST = defineHandler.withValidator({
|
|
83
|
+
body: insertUserSchema,
|
|
84
|
+
})(async (c, { body }) => {
|
|
85
|
+
const [created] = await db.insert(users).values(body).returning();
|
|
86
|
+
return created;
|
|
87
|
+
});
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
See [Database: Schema-Derived Validators](./database.md#schema-derived-validators) for how to set up `createInsertSchema` with column refinements.
|
|
91
|
+
|
|
92
|
+
You can validate multiple slots at once:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
// routes/api/users/[id].ts
|
|
96
|
+
import { defineHandler } from 'void';
|
|
97
|
+
import { db, eq } from 'void/db';
|
|
98
|
+
import { users, updateUserSchema } from '@schema';
|
|
99
|
+
|
|
100
|
+
export const PUT = defineHandler.withValidator({
|
|
101
|
+
body: updateUserSchema,
|
|
102
|
+
})(async (c, { body }) => {
|
|
103
|
+
const id = Number(c.req.param('id'));
|
|
104
|
+
const [updated] = await db.update(users).set(body).where(eq(users.id, id)).returning();
|
|
105
|
+
return updated;
|
|
106
|
+
});
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Manual validators
|
|
110
|
+
|
|
111
|
+
For endpoints that don't map to a database table, you can write validators by hand using any [Standard Schema](https://standardschema.dev/)-compatible library (Valibot, Zod, ArkType, etc.):
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
import * as v from 'valibot';
|
|
115
|
+
import { defineHandler } from 'void';
|
|
116
|
+
|
|
117
|
+
export const POST = defineHandler.withValidator({
|
|
118
|
+
body: v.object({
|
|
119
|
+
query: v.pipe(v.string(), v.minLength(1)),
|
|
120
|
+
limit: v.optional(v.pipe(v.number(), v.maxValue(100)), 10),
|
|
121
|
+
}),
|
|
122
|
+
})(async (c, { body }) => {
|
|
123
|
+
// body is typed as { query: string; limit: number }
|
|
124
|
+
return search(body.query, body.limit);
|
|
125
|
+
});
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Validation errors
|
|
129
|
+
|
|
130
|
+
When validation fails, a `400` response is returned with structured error details:
|
|
131
|
+
|
|
132
|
+
```json
|
|
133
|
+
{
|
|
134
|
+
"error": "Validation failed",
|
|
135
|
+
"issues": [
|
|
136
|
+
{
|
|
137
|
+
"slot": "body",
|
|
138
|
+
"issues": [{ "message": "Invalid email", "path": "email" }]
|
|
139
|
+
}
|
|
140
|
+
]
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
No extra dependencies are required. Void inlines the Standard Schema types, so you only need your chosen schema library.
|
|
145
|
+
|
|
146
|
+
Validator schemas also power the [typed fetch client](./typed-fetch.md), so `body`, `query`, and `params` types are enforced at the call site.
|
|
147
|
+
|
|
148
|
+
## Middleware
|
|
149
|
+
|
|
150
|
+
Void middlewares are just Hono middlewares. `defineMiddleware()` is a thin typing helper around the standard Hono `(c, next)` shape, and `defineHandler()` also accepts raw Hono middleware directly.
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
import { defineMiddleware } from 'void';
|
|
154
|
+
|
|
155
|
+
export const addServerTiming = defineMiddleware(async (c, next) => {
|
|
156
|
+
const start = performance.now();
|
|
157
|
+
await next();
|
|
158
|
+
c.header('Server-Timing', `app;dur=${Math.round(performance.now() - start)}`);
|
|
159
|
+
});
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Any `hono/*` built-in middleware, response helpers, or third-party Hono ecosystem packages can be used in Void apps. If you want to import from `hono/*` in your app, make sure to install `hono` in your app first:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
npm install hono
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
import { cors } from 'hono/cors';
|
|
170
|
+
|
|
171
|
+
const allowDashboard = cors({ origin: 'https://app.example.com' });
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
You can apply middleware globally or per-route.
|
|
175
|
+
|
|
176
|
+
### Global middleware
|
|
177
|
+
|
|
178
|
+
Global middleware runs on every request. Place files in `middleware/` and use numeric prefixes for ordering:
|
|
179
|
+
|
|
180
|
+
- `middleware/01.logger.ts`
|
|
181
|
+
- `middleware/02.auth.ts`
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
import { defineMiddleware } from 'void';
|
|
185
|
+
|
|
186
|
+
export default defineMiddleware(async (c, next) => {
|
|
187
|
+
console.log(c.req.method, c.req.path);
|
|
188
|
+
await next();
|
|
189
|
+
});
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
`defineMiddleware` uses Hono middleware semantics: `(c, next) => Promise<void> | void`.
|
|
193
|
+
|
|
194
|
+
Middleware can set typed context variables using `c.set()`. Augment the `CloudContextVariables` interface so downstream handlers get full type safety:
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
// middleware/01.request-id.ts
|
|
198
|
+
import { defineMiddleware } from 'void';
|
|
199
|
+
|
|
200
|
+
declare module 'void' {
|
|
201
|
+
interface CloudContextVariables {
|
|
202
|
+
requestId: string;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export default defineMiddleware(async (c, next) => {
|
|
207
|
+
c.set('requestId', crypto.randomUUID());
|
|
208
|
+
await next();
|
|
209
|
+
});
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Now every route handler can call `c.get("requestId")` and get `string` back, with no type assertion needed. See [Type Safety](./type-safety.md#context-variables) for more details.
|
|
213
|
+
|
|
214
|
+
### Per-route middleware
|
|
215
|
+
|
|
216
|
+
Pass one or more middleware to `defineHandler` before the final handler:
|
|
217
|
+
|
|
218
|
+
```ts
|
|
219
|
+
defineHandler(middleware1, middleware2, handler);
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Middleware runs in order. Each can short-circuit (return a response without calling `next()`) or post-process (modify the response after `await next()`). Both `defineMiddleware`-wrapped functions and raw Hono `MiddlewareHandler` functions are accepted.
|
|
223
|
+
|
|
224
|
+
```ts
|
|
225
|
+
// routes/api/stats.ts
|
|
226
|
+
import { defineHandler } from 'void';
|
|
227
|
+
import { cors } from 'hono/cors';
|
|
228
|
+
|
|
229
|
+
const addServerTiming = async (c, next) => {
|
|
230
|
+
const start = performance.now();
|
|
231
|
+
await next();
|
|
232
|
+
c.header('Server-Timing', `app;dur=${Math.round(performance.now() - start)}`);
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
export const GET = defineHandler(
|
|
236
|
+
cors({ origin: 'https://app.example.com' }),
|
|
237
|
+
addServerTiming,
|
|
238
|
+
(c) => {
|
|
239
|
+
return { stats: '...' };
|
|
240
|
+
},
|
|
241
|
+
);
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
Up to 5 middleware can be passed before the handler, with full type inference for each position.
|
|
245
|
+
|
|
246
|
+
See the [Hono integration guide](../integrations/hono.md) for more examples.
|