void 0.9.0 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/dist/{auth-cmd-BSdoU6dB.mjs → auth-cmd-CPkWrQR9.mjs} +2 -2
  2. package/dist/{better-auth-shared-BxcgLiHN.d.mts → better-auth-shared-CmEQZs1T.d.mts} +2 -2
  3. package/dist/{cache-Cb4Vs95q.mjs → cache-1SVxZ7BK.mjs} +2 -2
  4. package/dist/{cancel-deploy-CLVkqGJB.mjs → cancel-deploy-JaFClLr7.mjs} +1 -1
  5. package/dist/cli/cli.mjs +77 -40
  6. package/dist/{client-CCOKwNUz.mjs → client-DIfOFf1W.mjs} +6 -1
  7. package/dist/{create-project-Dg5hiuDE.mjs → create-project-DCUrFJxa.mjs} +3 -3
  8. package/dist/{db-D7l4OGV1.mjs → db-DiddQC2v.mjs} +191 -19
  9. package/dist/{delete-Bi-gbEHT.mjs → delete-CYknzwXU.mjs} +2 -2
  10. package/dist/{deploy-iR7ug73w.mjs → deploy-CRU9fGjE.mjs} +8 -11
  11. package/dist/{domain-C_atK_X9.mjs → domain-B7RntQ1r.mjs} +13 -28
  12. package/dist/{env-Dc073Aip.mjs → env-Bvw0wMTI.mjs} +1 -1
  13. package/dist/{env-helpers-bupZjGHq.d.mts → env-helpers-Bd2wVdxz.d.mts} +1 -1
  14. package/dist/{gen-CsawhQZz.mjs → gen-CZdNWIaA.mjs} +1 -1
  15. package/dist/{handler-DMSGX5S6.d.mts → handler-xflsMwWM.d.mts} +3 -3
  16. package/dist/index.d.mts +3 -3
  17. package/dist/index.mjs +71 -52
  18. package/dist/{init-CD9yg4Xt.mjs → init-BHupO7Fm.mjs} +7 -7
  19. package/dist/{link-27a64clx.mjs → link-7MoXUMaI.mjs} +3 -3
  20. package/dist/{list-C3Xt_i8a.mjs → list-N2mCHv8q.mjs} +2 -2
  21. package/dist/{login-BZ1Yk9Xw.mjs → login-tt1OmNVg.mjs} +1 -1
  22. package/dist/{logs-CktUaLEr.mjs → logs-Cl7q2CjZ.mjs} +1 -1
  23. package/dist/{mcp-BU7CP6gX.mjs → mcp-BXD35N2J.mjs} +1 -1
  24. package/dist/{node-C2HhnBO_.mjs → node-CHWVVjO6.mjs} +3 -3
  25. package/dist/pages/client.d.mts +1 -1
  26. package/dist/pages/head-client.d.mts +1 -1
  27. package/dist/pages/head.d.mts +1 -1
  28. package/dist/pages/index.d.mts +2 -2
  29. package/dist/pages/index.mjs +1 -1
  30. package/dist/pages/islands-plugin.d.mts +1 -1
  31. package/dist/pages/protocol.d.mts +2 -2
  32. package/dist/pages/protocol.mjs +1 -1
  33. package/dist/{prepare-BNuC8Ds9.mjs → prepare-CrlAVbWS.mjs} +1 -1
  34. package/dist/{preset-Lvi0ORmO.mjs → preset-CIJG2O7a.mjs} +1 -1
  35. package/dist/{project-cmd-DUkWHooP.mjs → project-cmd-CLrqSbqj.mjs} +8 -8
  36. package/dist/{protocol-hjl3Nx5x.d.mts → protocol-DYca39yJ.d.mts} +3 -3
  37. package/dist/proxy-M3pxItg2.mjs +5 -0
  38. package/dist/{rollback-CEjAG9uQ.mjs → rollback-CEbAwbHK.mjs} +1 -1
  39. package/dist/{runner-Cioqe5b2.mjs → runner-DLZ9E_cX.mjs} +1 -1
  40. package/dist/runtime/ai.d.mts +20 -100
  41. package/dist/runtime/ai.mjs +102 -55
  42. package/dist/runtime/auth.d.mts +1 -1
  43. package/dist/runtime/better-auth-pg.d.mts +1 -1
  44. package/dist/runtime/better-auth-pg.mjs +3 -3
  45. package/dist/runtime/better-auth.d.mts +1 -1
  46. package/dist/runtime/better-auth.mjs +2 -2
  47. package/dist/runtime/client-react.d.mts +2 -2
  48. package/dist/runtime/client-react.mjs +1 -1
  49. package/dist/runtime/client-solid.d.mts +2 -2
  50. package/dist/runtime/client-solid.mjs +1 -1
  51. package/dist/runtime/client-svelte.d.mts +2 -2
  52. package/dist/runtime/client-svelte.mjs +1 -1
  53. package/dist/runtime/client-vue.d.mts +2 -2
  54. package/dist/runtime/client-vue.mjs +1 -1
  55. package/dist/runtime/client.d.mts +2 -2
  56. package/dist/runtime/client.mjs +1 -1
  57. package/dist/runtime/env-helpers.d.mts +1 -1
  58. package/dist/runtime/env-public-client.d.mts +1 -1
  59. package/dist/runtime/env-public.d.mts +2 -2
  60. package/dist/runtime/env-public.mjs +1 -1
  61. package/dist/runtime/env.mjs +1 -1
  62. package/dist/runtime/fetch-stream.d.mts +1 -1
  63. package/dist/runtime/fetch-stream.mjs +1 -1
  64. package/dist/runtime/fetch.d.mts +1 -1
  65. package/dist/runtime/fetch.mjs +1 -1
  66. package/dist/runtime/handler.d.mts +1 -1
  67. package/dist/runtime/handler.mjs +1 -1
  68. package/dist/runtime/isr.mjs +1 -1
  69. package/dist/runtime/live.d.mts +2 -2
  70. package/dist/runtime/live.mjs +1 -1
  71. package/dist/runtime/migration-handler-pg.mjs +1 -1
  72. package/dist/runtime/sandbox.mjs +1 -1
  73. package/dist/runtime/validator.d.mts +1 -1
  74. package/dist/runtime/ws-server.d.mts +2 -2
  75. package/dist/runtime/ws.d.mts +3 -3
  76. package/dist/{secret-Dab6XQdb.mjs → secret-C_uTY7xx.mjs} +2 -2
  77. package/dist/{skills-GPm5Kjev.mjs → skills-BRKc--As.mjs} +1 -1
  78. package/package.json +2 -2
  79. package/skills/void/docs/guide/ai.md +109 -51
  80. package/skills/void/docs/guide/auth.md +3 -3
  81. package/skills/void/docs/node_modules/void/AGENTS.md +1 -1
  82. package/skills/void/docs/reference/api.md +9 -2
  83. package/skills/void/docs/reference/cli.md +50 -30
  84. /package/dist/{agents-Dkgafwfr.mjs → agents-MhSzNMiC.mjs} +0 -0
  85. /package/dist/{auth-BL0cU_Sy.d.mts → auth-CDeb2XAl.d.mts} +0 -0
  86. /package/dist/{auth-migrations-DBoTUBvq.mjs → auth-migrations-CuQkjjWE.mjs} +0 -0
  87. /package/dist/{better-auth-shared-pR54mTD2.mjs → better-auth-shared-ChVbrq52.mjs} +0 -0
  88. /package/dist/{defer-BosTTQTi.mjs → defer-CouVukrf.mjs} +0 -0
  89. /package/dist/{drizzle-Bvhm-Uug.mjs → drizzle-2fs1qTgy.mjs} +0 -0
  90. /package/dist/{env-raw-DhK_myJu.mjs → env-raw-RDkMnSTC.mjs} +0 -0
  91. /package/dist/{fetch-error-B8GTcrQw.mjs → fetch-error-BFIoojjf.mjs} +0 -0
  92. /package/dist/{fetch-error-Dn-En6Wg.d.mts → fetch-error-CimrygMq.d.mts} +0 -0
  93. /package/dist/{head-BW_f2L_4.d.mts → head-BsSTGnIe.d.mts} +0 -0
  94. /package/dist/{headers-wAPJigtE.mjs → headers-Y0jshugF.mjs} +0 -0
  95. /package/dist/{package-json-BMdypFnO.mjs → package-json-B2TD0JLu.mjs} +0 -0
  96. /package/dist/{pg-C-ybKyFU.mjs → pg-CMZ_5wsC.mjs} +0 -0
  97. /package/dist/{project-slug-De4UjtD9.mjs → project-slug-rX3kTOfY.mjs} +0 -0
  98. /package/dist/{providers-BVUcW4Jo.d.mts → providers-3Kkv63Ha.d.mts} +0 -0
  99. /package/dist/{resolve-project-CNpUbUHd.mjs → resolve-project-D4O1_fZz.mjs} +0 -0
  100. /package/dist/{runner-pg-D8ciL41o.mjs → runner-pg-Cv9V7ydr.mjs} +0 -0
  101. /package/dist/{standard-schema-DCIm8cwQ.d.mts → standard-schema-Dnsh2vnl.d.mts} +0 -0
  102. /package/dist/{subcommand-prompt-DUaWltdH.mjs → subcommand-prompt-OD-x_Tsm.mjs} +0 -0
  103. /package/dist/{types-s2mK7ar_.d.mts → types-Dm9kep2X.d.mts} +0 -0
  104. /package/dist/{yarn-pnp-BdM0hoCa.mjs → yarn-pnp-0SwYgQxx.mjs} +0 -0
@@ -1,4 +1,4 @@
1
- import { i as getRawRuntimeEnv, n as asEnv, r as envContext, t as INTERNAL_BINDING_PREFIXES } from "../env-raw-DhK_myJu.mjs";
1
+ import { i as getRawRuntimeEnv, n as asEnv, r as envContext, t as INTERNAL_BINDING_PREFIXES } from "../env-raw-RDkMnSTC.mjs";
2
2
  //#region src/runtime/env.ts
3
3
  /**
4
4
  * Public runtime env API — exposed via "void/_env".
@@ -1,4 +1,4 @@
1
- import { t as FetchError } from "../fetch-error-Dn-En6Wg.mjs";
1
+ import { t as FetchError } from "../fetch-error-CimrygMq.mjs";
2
2
  import { RouteMap } from "void/routes";
3
3
 
4
4
  //#region src/runtime/fetch-stream.d.ts
@@ -1,4 +1,4 @@
1
- import { n as ofetch, t as FetchError } from "../fetch-error-B8GTcrQw.mjs";
1
+ import { n as ofetch, t as FetchError } from "../fetch-error-BFIoojjf.mjs";
2
2
  //#region src/runtime/fetch-stream.ts
3
3
  /**
4
4
  * Consume an SSE endpoint as an async generator of text chunks.
@@ -1,4 +1,4 @@
1
- import { t as FetchError } from "../fetch-error-Dn-En6Wg.mjs";
1
+ import { t as FetchError } from "../fetch-error-CimrygMq.mjs";
2
2
  import { RouteMap } from "void/routes";
3
3
 
4
4
  //#region src/runtime/fetch.d.ts
@@ -1,4 +1,4 @@
1
- import { n as ofetch, t as FetchError } from "../fetch-error-B8GTcrQw.mjs";
1
+ import { n as ofetch, t as FetchError } from "../fetch-error-BFIoojjf.mjs";
2
2
  //#region src/runtime/fetch.ts
3
3
  async function fetch(path, options) {
4
4
  let url = path;
@@ -1,3 +1,3 @@
1
1
  /// <reference types="@cloudflare/workers-types" />
2
- import { C as HandlerInput, S as ValidationError, _ as defineScheduled, a as QueueBatch, b as InferProps, c as RenderAssetTags, d as VoidAssetRewriteError, f as defineHandler, g as defineRender, h as defineQueue, i as CloudEnv, l as TypedHandler, m as defineMiddleware, n as CloudContext, o as QueueMessage, p as defineHead, r as CloudContextVariables, s as QueueRetryOptions, t as CloudBindings, u as TypedQueueHandler, v as Deferred, w as ValidatorSlots, x as defer } from "../handler-DMSGX5S6.mjs";
2
+ import { C as HandlerInput, S as ValidationError, _ as defineScheduled, a as QueueBatch, b as InferProps, c as RenderAssetTags, d as VoidAssetRewriteError, f as defineHandler, g as defineRender, h as defineQueue, i as CloudEnv, l as TypedHandler, m as defineMiddleware, n as CloudContext, o as QueueMessage, p as defineHead, r as CloudContextVariables, s as QueueRetryOptions, t as CloudBindings, u as TypedQueueHandler, v as Deferred, w as ValidatorSlots, x as defer } from "../handler-xflsMwWM.mjs";
3
3
  export { CloudBindings, CloudContext, CloudContextVariables, CloudEnv, Deferred, HandlerInput, InferProps, QueueBatch, QueueMessage, QueueRetryOptions, RenderAssetTags, TypedHandler, TypedQueueHandler, ValidationError, ValidatorSlots, VoidAssetRewriteError, defer, defineHandler, defineHead, defineMiddleware, defineQueue, defineRender, defineScheduled };
@@ -1,6 +1,6 @@
1
1
  import { convertReturnValue } from "./response.mjs";
2
2
  import { runValidation } from "./validator.mjs";
3
- import { i as ValidationError, n as defer } from "../defer-BosTTQTi.mjs";
3
+ import { i as ValidationError, n as defer } from "../defer-CouVukrf.mjs";
4
4
  //#region src/runtime/handler.ts
5
5
  /**
6
6
  * Thrown when `c.rewrite()` is called with a destination whose final path
@@ -1,4 +1,4 @@
1
- import { i as getRawRuntimeEnv } from "../env-raw-DhK_myJu.mjs";
1
+ import { i as getRawRuntimeEnv } from "../env-raw-RDkMnSTC.mjs";
2
2
  //#region src/runtime/isr.ts
3
3
  /**
4
4
  * Revalidate ISR-cached pages on demand.
@@ -1,6 +1,6 @@
1
1
  /// <reference types="@cloudflare/workers-types" />
2
- import { r as AuthUser } from "../auth-BL0cU_Sy.mjs";
3
- import { i as CloudEnv, n as CloudContext } from "../handler-DMSGX5S6.mjs";
2
+ import { r as AuthUser } from "../auth-CDeb2XAl.mjs";
3
+ import { i as CloudEnv, n as CloudContext } from "../handler-xflsMwWM.mjs";
4
4
 
5
5
  //#region src/runtime/live.d.ts
6
6
  type MaybePromise<T> = T | Promise<T>;
@@ -1,4 +1,4 @@
1
- import { i as getRawRuntimeEnv } from "../env-raw-DhK_myJu.mjs";
1
+ import { i as getRawRuntimeEnv } from "../env-raw-RDkMnSTC.mjs";
2
2
  import { getUser } from "./auth.mjs";
3
3
  //#region src/runtime/live.ts
4
4
  let liveBindingName = "VOID_LIVE";
@@ -1,4 +1,4 @@
1
- import { t as disablePgPassFallback } from "../pg-C-ybKyFU.mjs";
1
+ import { t as disablePgPassFallback } from "../pg-CMZ_5wsC.mjs";
2
2
  //#region src/runtime/migration-handler-pg.ts
3
3
  function createMigrationHandler(env, migrations, _dialect, runAuthMigrations) {
4
4
  return async (request) => {
@@ -1,4 +1,4 @@
1
- import { i as getRawRuntimeEnv } from "../env-raw-DhK_myJu.mjs";
1
+ import { i as getRawRuntimeEnv } from "../env-raw-RDkMnSTC.mjs";
2
2
  import { requireRuntimeBinding } from "./env.mjs";
3
3
  import { Sandbox, getSandbox as getSandbox$1 } from "@cloudflare/sandbox";
4
4
  //#region src/runtime/sandbox.ts
@@ -1,2 +1,2 @@
1
- import { C as HandlerInput, T as runValidation, w as ValidatorSlots } from "../handler-DMSGX5S6.mjs";
1
+ import { C as HandlerInput, T as runValidation, w as ValidatorSlots } from "../handler-xflsMwWM.mjs";
2
2
  export { HandlerInput, ValidatorSlots, runValidation };
@@ -1,5 +1,5 @@
1
- import { n as AuthState } from "../auth-BL0cU_Sy.mjs";
2
- import { i as VoidAuthRuntimeOptions, n as VoidAuthEnv } from "../better-auth-shared-BxcgLiHN.mjs";
1
+ import { n as AuthState } from "../auth-CDeb2XAl.mjs";
2
+ import { i as VoidAuthRuntimeOptions, n as VoidAuthEnv } from "../better-auth-shared-CmEQZs1T.mjs";
3
3
  import { AnyWebSocketDefinition } from "./ws.mjs";
4
4
 
5
5
  //#region src/runtime/ws-server.d.ts
@@ -1,6 +1,6 @@
1
- import { r as AuthUser } from "../auth-BL0cU_Sy.mjs";
2
- import { t as StandardSchemaV1 } from "../standard-schema-DCIm8cwQ.mjs";
3
- import { i as CloudEnv } from "../handler-DMSGX5S6.mjs";
1
+ import { r as AuthUser } from "../auth-CDeb2XAl.mjs";
2
+ import { t as StandardSchemaV1 } from "../standard-schema-Dnsh2vnl.mjs";
3
+ import { i as CloudEnv } from "../handler-xflsMwWM.mjs";
4
4
  import { WebSocketRouteMap } from "void/routes";
5
5
 
6
6
  //#region src/runtime/ws.d.ts
@@ -1,8 +1,8 @@
1
1
  import { n as cliTitle } from "./output-DeiS4oEX.mjs";
2
- import { c as getToken, n as PlatformClient } from "./client-CCOKwNUz.mjs";
2
+ import { c as getToken, n as PlatformClient } from "./client-DIfOFf1W.mjs";
3
3
  import { _ as me, c as R, g as ge, n as Ce, u as Se, v as ue, x as q, y as ye } from "./dist-abzUneor.mjs";
4
4
  import { r as readProjectConfig } from "./project-CH9pdo16.mjs";
5
- import { r as resolveProjectBySlug, t as getRequestedProjectSlug } from "./resolve-project-CNpUbUHd.mjs";
5
+ import { r as resolveProjectBySlug, t as getRequestedProjectSlug } from "./resolve-project-D4O1_fZz.mjs";
6
6
  import { readFileSync } from "node:fs";
7
7
  //#region src/cli/secret.ts
8
8
  async function runSecretCommand(root, args) {
@@ -1,6 +1,6 @@
1
1
  import { a as join, s as relative } from "./pathe.M-eThtNZ-BrPhGF_K.mjs";
2
2
  import { c as R } from "./dist-abzUneor.mjs";
3
- import { r as getPackageDir } from "./agents-Dkgafwfr.mjs";
3
+ import { r as getPackageDir } from "./agents-MhSzNMiC.mjs";
4
4
  import { existsSync, mkdirSync, readFileSync, readdirSync, readlinkSync, symlinkSync } from "node:fs";
5
5
  //#region src/cli/skills.ts
6
6
  function parseSkills(skillsDir) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "void",
3
- "version": "0.9.0",
3
+ "version": "0.9.2",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/voidzero-dev/void.git",
@@ -353,7 +353,7 @@
353
353
  "valibot": ">=1.0.0-beta.7",
354
354
  "vite": "^8.0.0",
355
355
  "zod": "^3.25.0 || ^4.0.0",
356
- "@void/md": "0.9.0"
356
+ "@void/md": "0.9.2"
357
357
  },
358
358
  "peerDependenciesMeta": {
359
359
  "@void/md": {
@@ -4,7 +4,7 @@ outline: deep
4
4
 
5
5
  # AI
6
6
 
7
- Void provides a typed AI client powered by Cloudflare's [AI Gateway](https://developers.cloudflare.com/ai-gateway/). It supports both [Workers AI](https://developers.cloudflare.com/workers-ai/) models and third-party providers such as OpenAI, Anthropic, and Google through bring-your-own-key credentials. Import `ai` from `void/ai` and run inference directly from your route handlers. Usage is metered through Void.
7
+ Void provides a typed AI client powered by Cloudflare's [AI Gateway](https://developers.cloudflare.com/ai-gateway/). Import `ai` from `void/ai` and run inference directly from your route handlers. Usage is metered through Void.
8
8
 
9
9
  ```ts
10
10
  import { ai } from 'void/ai';
@@ -29,7 +29,7 @@ export const POST = defineHandler(async (c) => {
29
29
  });
30
30
  ```
31
31
 
32
- You can use any model available on [Workers AI](https://developers.cloudflare.com/workers-ai/models/), including text generation, image classification, image-to-text, text-to-image, embeddings, translation, and more. Models that return binary data, such as generated images, are returned as a `Blob` from `ai.run()`.
32
+ You can use any model available through Cloudflare's AI binding, including Workers AI models such as `@cf/meta/llama-3.1-8b-instruct` and Cloudflare Gateway models such as `google/gemini-2.5-flash` or `openai/gpt-4.1-mini`. The input object must match the selected Cloudflare model's schema. Models that return binary data, such as generated images, are returned as a `Blob` from `ai.run()`.
33
33
 
34
34
  ## Streaming
35
35
 
@@ -87,11 +87,52 @@ Workers AI usage is metered in [**neurons**](https://developers.cloudflare.com/w
87
87
 
88
88
  On the **free tier**, AI requests return a `429` error once the limit is reached. On **paid tiers**, usage beyond the included allowance is tracked as overage on your monthly bill.
89
89
 
90
- ## Third-Party Providers (BYOK)
90
+ ## Cloudflare Gateway Models
91
91
 
92
- You can use models from OpenAI, Anthropic, Google, and other providers by passing a `provider/model` identifier. Bring your own API key, add it as a project secret, and Void handles the rest. Third-party inference is billed directly by the provider, and Void does not mark up API calls. Requests still route through AI Gateway so usage shows up on the dashboard.
92
+ `ai.run()` mirrors Cloudflare's `env.AI.run()` model naming and input schemas. Third-party models use Cloudflare model IDs and Cloudflare-managed credentials.
93
93
 
94
- ### Usage
94
+ ```ts
95
+ const result = await ai.run('google/gemini-2.5-flash', {
96
+ contents: [
97
+ {
98
+ role: 'user',
99
+ parts: [{ text: 'Explain Durable Objects in one paragraph.' }],
100
+ },
101
+ ],
102
+ });
103
+ ```
104
+
105
+ OpenAI-compatible models use OpenAI-style `messages`:
106
+
107
+ ```ts
108
+ const result = await ai.run('openai/gpt-4.1-mini', {
109
+ messages: [{ role: 'user', content: 'Summarize this deploy.' }],
110
+ });
111
+ ```
112
+
113
+ Pass Cloudflare AI Gateway options as the third argument:
114
+
115
+ ```ts
116
+ const result = await ai.run(
117
+ 'openai/gpt-4.1-mini',
118
+ {
119
+ messages: [{ role: 'user', content: 'Summarize this deploy.' }],
120
+ },
121
+ {
122
+ gateway: {
123
+ skipCache: true,
124
+ },
125
+ },
126
+ );
127
+ ```
128
+
129
+ Void always injects the `void` gateway ID and project metadata for metering.
130
+
131
+ ## Provider-Native Requests
132
+
133
+ Use `ai.provider(provider).fetch(path, init)` when you want to call a provider-native API with your own provider key. The request still routes through Cloudflare AI Gateway and Void metering, but the request shape is the provider's native HTTP API.
134
+
135
+ ### OpenAI
95
136
 
96
137
  ```ts
97
138
  import { defineHandler } from 'void';
@@ -100,85 +141,99 @@ import { ai } from 'void/ai';
100
141
  export const POST = defineHandler(async (c) => {
101
142
  const { prompt } = await c.req.json();
102
143
 
103
- const result = await ai.run('openai/gpt-4o', {
104
- messages: [{ role: 'user', content: prompt }],
105
- max_tokens: 512,
144
+ const response = await ai.provider('openai').fetch('/chat/completions', {
145
+ body: {
146
+ model: 'gpt-4o',
147
+ messages: [{ role: 'user', content: prompt }],
148
+ max_tokens: 512,
149
+ },
106
150
  });
107
151
 
152
+ const result = await response.json();
108
153
  return c.json(result);
109
154
  });
110
155
  ```
111
156
 
112
- The same `ai.run()` and `ai.stream()` methods work for both Workers AI and third-party models. The framework detects the provider from the model string and routes the request through [AI Gateway](https://developers.cloudflare.com/ai-gateway/) automatically.
113
-
114
- The options follow each provider's conventions. All third-party providers use the OpenAI-compatible chat completions format, including `messages`, `max_tokens`, and `temperature`. TypeScript narrows the input and return types based on the model string: Workers AI models get per-model typed inputs from `@cloudflare/workers-types`, while third-party models such as `"provider/model"` get `ChatCompletionInputs` and `ChatCompletionResponse`.
115
-
116
- ### Vision
117
-
118
- Third-party chat models that accept image inputs can receive OpenAI-compatible multimodal message content:
157
+ ### Google AI Studio
119
158
 
120
159
  ```ts
121
- const result = await ai.run('openai/gpt-4o', {
122
- messages: [
123
- {
124
- role: 'user',
125
- content: [
126
- { type: 'text', text: 'What is in this image?' },
160
+ const response = await ai
161
+ .provider('google-ai-studio')
162
+ .fetch('/v1/models/gemini-2.5-flash:generateContent', {
163
+ body: {
164
+ contents: [
127
165
  {
128
- type: 'image_url',
129
- image_url: { url: 'data:image/png;base64,...', detail: 'high' },
166
+ role: 'user',
167
+ parts: [{ text: 'What is Cloudflare?' }],
130
168
  },
131
169
  ],
132
170
  },
133
- ],
134
- });
171
+ });
172
+
173
+ const result = await response.json();
174
+ ```
175
+
176
+ ### Custom Providers
177
+
178
+ For providers that are not in Void's default key map, pass the secret name and API-key header:
179
+
180
+ ```ts
181
+ const response = await ai
182
+ .provider('custom-provider', {
183
+ apiKeyEnv: 'CUSTOM_PROVIDER_API_KEY',
184
+ apiKeyHeader: 'x-api-key',
185
+ apiKeyPrefix: '',
186
+ })
187
+ .fetch('/v1/respond', {
188
+ body: { prompt: 'Hello' },
189
+ });
135
190
  ```
136
191
 
137
192
  ### Image Generation
138
193
 
139
- Use `ai.image()` for image-generation providers or Workers AI image models. It returns a `Response`, so route handlers can return it directly or parse it as JSON depending on the provider:
194
+ Use `ai.run()` or `ai.image()` for Cloudflare-native image models:
140
195
 
141
196
  ```ts
142
197
  export const POST = defineHandler(async (c) => {
143
198
  const { prompt } = await c.req.json();
144
-
145
- return ai.image('openai/gpt-image-1.5', {
146
- prompt,
147
- size: '1024x1024',
148
- response_format: 'b64_json',
149
- });
199
+ return ai.image('@cf/black-forest-labs/flux-1-schnell', { prompt });
150
200
  });
151
201
  ```
152
202
 
153
- For Workers AI text-to-image models, pass the model name and input shape from Cloudflare's model docs:
203
+ Use `ai.provider().fetch()` for provider-native image APIs:
154
204
 
155
205
  ```ts
156
206
  export const POST = defineHandler(async (c) => {
157
207
  const { prompt } = await c.req.json();
158
- return ai.image('@cf/black-forest-labs/flux-1-schnell', { prompt });
208
+
209
+ return ai.provider('openai').fetch('/images/generations', {
210
+ body: {
211
+ model: 'gpt-image-1.5',
212
+ prompt,
213
+ size: '1024x1024',
214
+ response_format: 'b64_json',
215
+ },
216
+ });
159
217
  });
160
218
  ```
161
219
 
162
- For image edits, pass the file-like input and select the edit endpoint. Void serializes the file through the proxy and forwards it to AI Gateway as multipart form data:
220
+ For multipart provider APIs, pass a `FormData` body. Void serializes the body through the proxy and reconstructs it before forwarding to AI Gateway:
163
221
 
164
222
  ```ts
165
223
  export const POST = defineHandler(async (c) => {
166
224
  const body = await c.req.parseBody();
225
+ const form = new FormData();
226
+ form.set('model', 'gpt-image-1.5');
227
+ form.set('prompt', String(body.prompt));
228
+ form.set('image', body.image as Blob, 'source.png');
167
229
 
168
- return ai.image(
169
- 'openai/gpt-image-1.5',
170
- {
171
- prompt: String(body.prompt),
172
- image: body.image as Blob,
173
- },
174
- { endpoint: 'images/edits' },
175
- );
230
+ return ai.provider('openai').fetch('/images/edits', { body: form });
176
231
  });
177
232
  ```
178
233
 
179
234
  ### Provider Key Convention
180
235
 
181
- Each provider requires an API key set as a project secret. The env var name is automatically derived from the provider prefix:
236
+ Provider-native requests require an API key set as a project secret. The env var name is automatically derived from the provider name:
182
237
 
183
238
  | Provider prefix | Env var |
184
239
  | ------------------ | --------------------- |
@@ -203,7 +258,7 @@ Each provider requires an API key set as a project secret. The env var name is a
203
258
  | `ideogram` | `IDEOGRAM_API_KEY` |
204
259
  | `parallel` | `PARALLEL_API_KEY` |
205
260
 
206
- All [AI Gateway providers](https://developers.cloudflare.com/ai-gateway/usage/providers/) that accept a Bearer API key are supported. Providers with non-standard auth (Amazon Bedrock, Azure OpenAI, Google Vertex) are not yet supported.
261
+ OpenAI-style providers use `Authorization: Bearer <key>`. Google AI Studio uses `x-goog-api-key`. Use `apiKeyHeader` and `apiKeyPrefix` for custom providers.
207
262
 
208
263
  For production, add your API key as a project secret:
209
264
 
@@ -217,19 +272,22 @@ For local development, add it to `.env.local` in your project root:
217
272
  OPENAI_API_KEY=sk-...
218
273
  ```
219
274
 
220
- If the key is missing at runtime, `ai.run()` throws a descriptive error telling you which env var to set.
275
+ If the key is missing at runtime, `ai.provider().fetch()` throws a descriptive error telling you which env var to set.
221
276
 
222
- ### Streaming with Third-Party Models
277
+ ### Streaming with Provider-Native APIs
223
278
 
224
- `ai.stream()` works the same way. The response is always SSE regardless of provider:
279
+ Provider-native streaming APIs return the provider response directly:
225
280
 
226
281
  ```ts
227
282
  export const POST = defineHandler(async (c) => {
228
283
  const { prompt } = await c.req.json();
229
284
 
230
- return ai.stream('anthropic/claude-sonnet-4-20250514', {
231
- messages: [{ role: 'user', content: prompt }],
232
- max_tokens: 512,
285
+ return ai.provider('openai').fetch('/chat/completions', {
286
+ body: {
287
+ model: 'gpt-4o',
288
+ messages: [{ role: 'user', content: prompt }],
289
+ stream: true,
290
+ },
233
291
  });
234
292
  });
235
293
  ```
@@ -229,12 +229,12 @@ Localhost dev uses a built-in fallback secret automatically. Outside the managed
229
229
  For advanced configuration, create `auth.ts` at the project root and export `defineAuth(...)`:
230
230
 
231
231
  ```ts
232
- import { defineAuth } from "void/auth";
232
+ import { defineAuth } from 'void/auth';
233
233
 
234
234
  export default defineAuth(({ defaults }) => ({
235
235
  ...defaults,
236
- trustedOrigins: ["https://example.com"],
237
- });
236
+ trustedOrigins: ['https://example.com'],
237
+ }));
238
238
  ```
239
239
 
240
240
  `defaults` already includes Void's conventions. Extend it explicitly instead of expecting a deep merge.
@@ -101,7 +101,7 @@ src/
101
101
  | `void/ws` | `defineRoom()`, `defineWebSocket()`, typed `connect()`, and WebSocket context types |
102
102
  | `void/db` | `db` Drizzle D1 instance (auto-wired with user schema) + `createDb()` for custom D1 bindings |
103
103
  | `void/queues` | `queues` typed proxy + `QueueMap` stub interface (augmented by generated `queues.d.ts`) |
104
- | `void/ai` | `ai` proxy — `ai.run()`, `ai.stream()`, `ai.models()` with auto-detected backend (service binding / HTTPS / direct) |
104
+ | `void/ai` | `ai` proxy — Cloudflare-native `ai.run()`/`ai.stream()`, provider-native `ai.provider().fetch()`, `ai.models()` |
105
105
  | `void/log` | `logger.error/warn/info(msg, fields?)` — emits stringified JSON to `console.*` so Cloudflare Tail captures level + msg |
106
106
  | `void/env` | `defineEnv()`, typed `env` proxy, built-in schema helpers (`string`, `number`, `oneOf`, …) + global Cloudflare types |
107
107
 
@@ -675,7 +675,7 @@ Imported from `"void/ai"`.
675
675
 
676
676
  ### `ai`
677
677
 
678
- Typed AI client for Workers AI models and AI Gateway-backed third-party providers.
678
+ Typed AI client for Cloudflare AI models and provider-native AI Gateway requests.
679
679
 
680
680
  ```ts
681
681
  import { ai } from 'void/ai';
@@ -683,9 +683,16 @@ import { ai } from 'void/ai';
683
683
  const result = await ai.run('@cf/meta/llama-3.1-8b-instruct', {
684
684
  messages: [{ role: 'user', content: 'Summarize this release note.' }],
685
685
  });
686
+
687
+ const response = await ai.provider('openai').fetch('/chat/completions', {
688
+ body: {
689
+ model: 'gpt-4o',
690
+ messages: [{ role: 'user', content: 'Summarize this release note.' }],
691
+ },
692
+ });
686
693
  ```
687
694
 
688
- **Key exports:** `ai`, `VoidAi`, model input/response types. See [AI](../guide/ai.md) for provider setup and streaming examples.
695
+ **Key exports:** `ai`, `VoidAi`, provider request types. See [AI](../guide/ai.md) for provider setup and streaming examples.
689
696
 
690
697
  ## ISR
691
698
 
@@ -10,32 +10,33 @@ Use this page as a command reference. If you are setting up a project for the fi
10
10
 
11
11
  ## Cheat Sheet
12
12
 
13
- | Command | Purpose |
14
- | --------------------------------- | ------------------------------------------------ |
15
- | `void deploy` | Build and deploy to Void |
16
- | `void prepare` | Generate `.void` artifacts without starting Vite |
17
- | `void gen model <name> [cols...]` | Scaffold migration + CRUD routes |
18
- | `void gen route <path>` | Create an API route |
19
- | `void db push` | Apply schema directly without migration files |
20
- | `void db generate` | Generate SQL migrations from schema changes |
21
- | `void db status` | Show local/remote migration status |
22
- | `void db reset` | Drop and re-apply all migrations |
23
- | `void db seed` | Reset + seed local database |
24
- | `void db studio` | Open Drizzle Studio for local database |
25
- | `void secret put <name=value>` | Set a production secret |
26
- | `void secret list` | List production secrets |
27
- | `void secret sync .env.local` | Bulk upload secrets from dotenv file |
28
- | `void env check [--remote]` | Validate env.ts schema |
29
- | `void env types` | Regenerate .void/env.d.ts from env.ts |
30
- | `void env example` | Refresh the void-managed block in .env.example |
31
- | `void auth login` | Authenticate with Void |
32
- | `void project link` | Link directory to a project |
33
- | `void project logs` | Show runtime logs from deployed project |
34
- | `void project rollback` | Roll back to a previous deployment |
35
- | `void project cancel` | Cancel an active deployment |
36
- | `void project purge-cache` | Purge all cached pages |
37
- | `void mcp` | Start the Void MCP server |
38
- | `void init` | Setup wizard for new or existing projects |
13
+ | Command | Purpose |
14
+ | --------------------------------- | ------------------------------------------------------------------- |
15
+ | `void deploy` | Build and deploy to Void |
16
+ | `void prepare` | Generate `.void` artifacts without starting Vite |
17
+ | `void gen model <name> [cols...]` | Scaffold migration + CRUD routes |
18
+ | `void gen route <path>` | Create an API route |
19
+ | `void db push` | Apply schema directly without migration files |
20
+ | `void db generate` | Generate SQL migrations from schema changes |
21
+ | `void db status` | Show local/remote migration status |
22
+ | `void db reset` | Drop and re-apply all migrations |
23
+ | `void db seed` | Reset + seed local database |
24
+ | `void db execute <sql>` | Run SQL against the database (--remote for deployed) |
25
+ | `void db studio` | Open Drizzle Studio (--remote for the deployed PostgreSQL database) |
26
+ | `void secret put <name=value>` | Set a production secret |
27
+ | `void secret list` | List production secrets |
28
+ | `void secret sync .env.local` | Bulk upload secrets from dotenv file |
29
+ | `void env check [--remote]` | Validate env.ts schema |
30
+ | `void env types` | Regenerate .void/env.d.ts from env.ts |
31
+ | `void env example` | Refresh the void-managed block in .env.example |
32
+ | `void auth login` | Authenticate with Void |
33
+ | `void project link` | Link directory to a project |
34
+ | `void project logs` | Show runtime logs from deployed project |
35
+ | `void project rollback` | Roll back to a previous deployment |
36
+ | `void project cancel` | Cancel an active deployment |
37
+ | `void project purge-cache` | Purge all cached pages |
38
+ | `void mcp` | Start the Void MCP server |
39
+ | `void init` | Setup wizard for new or existing projects |
39
40
 
40
41
  ## Binary Invocation
41
42
 
@@ -289,9 +290,17 @@ Programmatic seed modules must export either a default function or a named `seed
289
290
  ```
290
291
  void db execute <sql>
291
292
  void db execute --file <path>
293
+ void db execute --remote <sql>
292
294
  ```
293
295
 
294
- Run ad-hoc SQL against the local D1 database. Provide SQL inline or from a file. SELECT queries display results as a formatted table; other statements execute silently.
296
+ Run ad-hoc SQL against the database. Provide SQL inline or from a file. SELECT queries display results as a formatted table; other statements execute silently.
297
+
298
+ By default, targets the local database. Pass `--remote` to run against the deployed database:
299
+
300
+ - **D1 projects**: routes the query through the Void proxy (`proxy.void.cloud/d1/query`) using your auth token. No Cloudflare credentials needed.
301
+ - **PostgreSQL projects**: fetches the stored connection string from the platform and connects directly. Requires that `void db set-url` has been run at least once (the platform stores the URL encrypted). If the URL isn't stored yet, you will see: _"Run `void db set-url` once to populate it, then retry."_
302
+
303
+ For destructive statements (`DELETE`, `UPDATE`, `DROP`, etc.) when running in a TTY, you will be prompted to confirm before the query is sent to the deployed database. Non-TTY environments (CI) skip the prompt.
295
304
 
296
305
  ### `void db migrate`
297
306
 
@@ -305,7 +314,16 @@ Pass `--remote` to apply pending migrations to the remote database instead. Requ
305
314
 
306
315
  ### `void db studio`
307
316
 
308
- Open [Drizzle Studio](https://orm.drizzle.team/docs/drizzle-kit-studio) for the local database. Launches a web-based GUI for browsing and editing your data.
317
+ ```
318
+ void db studio [--remote]
319
+ ```
320
+
321
+ Open [Drizzle Studio](https://orm.drizzle.team/docs/drizzle-kit-studio) for the database. Launches a web-based GUI for browsing and editing your data.
322
+
323
+ By default, targets the local database. Pass `--remote` to open Studio against the deployed database:
324
+
325
+ - **PostgreSQL projects**: fetches the stored connection string from the platform and opens Studio against it. Requires being logged in (`void auth login`) with a linked project. If the URL isn't stored yet, run `void db set-url` first.
326
+ - **D1 projects**: remote Studio is not yet supported. Use `void db execute --remote` for ad-hoc queries against your deployed D1 database.
309
327
 
310
328
  ### `void db rename-migrations`
311
329
 
@@ -554,7 +572,9 @@ See [Environment Variables](../guide/env-vars.md) for the full guide.
554
572
  void domain add <hostname> [--project <name>]
555
573
  ```
556
574
 
557
- Add a custom domain to a project. Prints the CNAME target you need to add in your DNS provider.
575
+ Add a custom domain to a project. Prints the two DNS records to add at your DNS provider: a traffic **CNAME** pointing `<hostname>` at the CNAME target shown in the command output, and a non-rotating `_cf-custom-hostname` ownership **TXT**. Certificates are validated over HTTP at Cloudflare's edge and renew automatically — there are no `_acme-challenge` records to publish, at first issuance or ever. After adding the records the domain activates automatically (no polling required); run `void domain status <hostname>` to check progress.
576
+
577
+ > Wildcard custom hostnames (`*.example.com`) are not supported — register each subdomain individually.
558
578
 
559
579
  ### `void domain delete`
560
580
 
@@ -578,7 +598,7 @@ List all custom domains and their status (active/pending).
578
598
  void domain status <hostname> [--project <name>] [--verbose]
579
599
  ```
580
600
 
581
- Check verification and SSL status for a specific domain. Prints a rolled-up state (`awaiting_dns`, `verifying_dns`, `issuing_cert`, `deploying_cert`, `awaiting_deployment`, `active`, `error`, or `pending`) with a one-line diagnostic explaining what Cloudflare is doing and any user action required. When DNS records are still pending, the command also prints the exact TXT records to add at your DNS provider.
601
+ Check verification and SSL status for a specific domain. Prints a rolled-up state (`awaiting_dns`, `verifying_dns`, `issuing_cert`, `deploying_cert`, `awaiting_deployment`, `active`, `error`, or `pending`) with a one-line diagnostic explaining what Cloudflare is doing and any user action required. While the certificate is not yet active, the command also surfaces the records to configure — the traffic **CNAME** and the `_cf-custom-hostname` ownership **TXT** — so you can verify them. Activation is automatic: a background job reconciles pending domains (about every 2 minutes for the first 30 minutes after adding, then hourly), so this command is for instant feedback rather than required polling.
582
602
 
583
603
  Pass `--verbose` to additionally print the raw multi-line status breakdown (DB status, SSL status, ownership state, verification errors) underneath the rollup.
584
604
 
File without changes
File without changes