void 0.7.2 → 0.7.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{better-auth-shared-APuDaPqW.mjs → better-auth-shared-BrfZ78iY.mjs} +55 -5
- package/dist/cli/cli.mjs +8 -8
- package/dist/{db-ClNu7vYQ.mjs → db-RqxhOT2E.mjs} +1 -1
- package/dist/{deploy-BkjqNk9U.mjs → deploy-CRIz77mw.mjs} +243 -56
- package/dist/index.mjs +56 -22
- package/dist/{init-CPny6w9D.mjs → init-FMZ29UZW.mjs} +2 -2
- package/dist/{plugin-inference-oZ6Ybu2_.mjs → plugin-inference-CCtRkt9O.mjs} +41 -12
- package/dist/{prepare-DKkx-2Kt.mjs → prepare-PqAbhLte.mjs} +2 -2
- package/dist/{preset-DFvePt0l.mjs → preset-jKn1hQwP.mjs} +1 -1
- package/dist/runtime/better-auth-pg.mjs +1 -1
- package/dist/runtime/better-auth.mjs +1 -1
- package/dist/runtime/live-client.d.mts +34 -0
- package/dist/runtime/live-client.mjs +283 -0
- package/dist/runtime/live-server.d.mts +13 -0
- package/dist/runtime/live-server.mjs +417 -0
- package/dist/runtime/live.d.mts +107 -0
- package/dist/runtime/live.mjs +409 -0
- package/dist/runtime/migration-handler.mjs +34 -1
- package/dist/runtime/sse-client.d.mts +22 -0
- package/dist/runtime/sse-client.mjs +36 -0
- package/dist/runtime/sse.d.mts +35 -0
- package/dist/runtime/sse.mjs +172 -0
- package/dist/{scan-C6HMEIdW.mjs → scan-QtRTdh94.mjs} +1 -1
- package/package.json +42 -17
- package/skills/void/docs/guide/live.md +230 -0
- package/skills/void/docs/guide/sse.md +187 -0
- package/skills/void/docs/index.md +12 -15
- package/skills/void/docs/reference/api.md +4 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
---
|
|
2
|
+
outline: deep
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Server-Sent Events
|
|
6
|
+
|
|
7
|
+
Void provides `void/sse` for producing and consuming Server-Sent Events from ordinary route handlers. It handles event formatting, response headers, keepalives, stream closure, request aborts, and browser `EventSource` parsing.
|
|
8
|
+
|
|
9
|
+
Use SSE when one HTTP request owns the producer: AI token streaming, progress updates, command output, deployment logs, or incremental status messages. Use `void/live` or an application-level Durable Object when multiple requests need shared fanout, replay, or subscription state.
|
|
10
|
+
|
|
11
|
+
## Server streams
|
|
12
|
+
|
|
13
|
+
Return `eventStream()` from a route handler:
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
// routes/api/events.ts
|
|
17
|
+
import { defineHandler } from 'void';
|
|
18
|
+
import { eventStream } from 'void/sse';
|
|
19
|
+
|
|
20
|
+
export const GET = defineHandler((c) => {
|
|
21
|
+
return eventStream(
|
|
22
|
+
async (stream) => {
|
|
23
|
+
await stream.comment('connected');
|
|
24
|
+
await stream.send({
|
|
25
|
+
event: 'ready',
|
|
26
|
+
data: { now: Date.now() },
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const timer = setInterval(() => {
|
|
30
|
+
void stream.send({ event: 'tick', data: { now: Date.now() } }).catch(() => stream.close());
|
|
31
|
+
}, 1000);
|
|
32
|
+
|
|
33
|
+
await stream.closed;
|
|
34
|
+
clearInterval(timer);
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
signal: c.req.raw.signal,
|
|
38
|
+
},
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
`eventStream()` returns a `Response` immediately with these default headers:
|
|
44
|
+
|
|
45
|
+
```http
|
|
46
|
+
Content-Type: text/event-stream; charset=utf-8
|
|
47
|
+
Cache-Control: no-cache, no-transform
|
|
48
|
+
X-Accel-Buffering: no
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
When the `start` callback returns, the stream closes. Long-lived streams should wait on `stream.closed`, a producer promise, or an application cancellation signal before returning.
|
|
52
|
+
|
|
53
|
+
## Sending events
|
|
54
|
+
|
|
55
|
+
Use `send()` for SSE messages and `comment()` for comments:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
await stream.send({
|
|
59
|
+
id: 'evt_1',
|
|
60
|
+
event: 'post.update',
|
|
61
|
+
retry: 1000,
|
|
62
|
+
data: { id: 'post_123', likes: 10 },
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
await stream.comment('still connected');
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`data` may be a string or JSON-serializable value. Strings are sent as-is; other values are serialized with `JSON.stringify()`. Multi-line strings are split into multiple `data:` lines. Binary data is rejected because SSE is text-only.
|
|
69
|
+
|
|
70
|
+
`event`, `id`, and `retry` are validated before writing so accidental frame injection is rejected. Writes after close reject with `SseStreamClosedError`.
|
|
71
|
+
|
|
72
|
+
If you already serialized the payload, use `formatSseText()` for lower-level formatting while keeping the same `id`, `event`, and `retry` validation:
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
import { formatSseText } from 'void/sse';
|
|
76
|
+
|
|
77
|
+
const frame = formatSseText({
|
|
78
|
+
event: 'post.update',
|
|
79
|
+
data: JSON.stringify({ id: 'post_123', likes: 10 }),
|
|
80
|
+
});
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Keepalives
|
|
84
|
+
|
|
85
|
+
Keepalives are enabled by default every 15 seconds:
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
return eventStream(start);
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Disable them or customize the interval and comment text:
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
return eventStream(start, { keepAlive: false });
|
|
95
|
+
|
|
96
|
+
return eventStream(start, {
|
|
97
|
+
keepAlive: { intervalMs: 5000, comment: 'ping' },
|
|
98
|
+
});
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The interval must be a positive finite number.
|
|
102
|
+
|
|
103
|
+
## Last Event ID
|
|
104
|
+
|
|
105
|
+
Browsers send `Last-Event-ID` when reconnecting after an event with an `id` field. Use `getLastEventId()` to resume from your own storage:
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
import { getLastEventId } from 'void/sse';
|
|
109
|
+
|
|
110
|
+
export const GET = defineHandler((c) => {
|
|
111
|
+
const lastId = getLastEventId(c.req.raw);
|
|
112
|
+
return eventStream(async (stream) => {
|
|
113
|
+
await stream.send({ id: nextId(lastId), data: await loadNextItem(lastId) });
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
`void/sse` does not store or replay events. Persist event offsets in your own database, queue, or Durable Object when replay matters.
|
|
119
|
+
|
|
120
|
+
## Client
|
|
121
|
+
|
|
122
|
+
Use `connectEventStream()` from the browser-only `void/sse/client` subpath:
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
import { connectEventStream } from 'void/sse/client';
|
|
126
|
+
|
|
127
|
+
const stream = connectEventStream<{
|
|
128
|
+
ready: { now: number };
|
|
129
|
+
tick: { now: number };
|
|
130
|
+
}>('/api/events', {
|
|
131
|
+
withCredentials: true,
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
const offReady = stream.on('ready', (event) => {
|
|
135
|
+
console.log(event.data.now);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
stream.on('tick', (event) => {
|
|
139
|
+
console.log(event.data.now);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
offReady();
|
|
143
|
+
stream.close();
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
The client wraps native `EventSource`. It supports cookie credentials and typed event handlers, but it does not support request bodies or arbitrary headers. Use cookie auth, signed URLs, or a fetch-based streaming route when you need custom headers.
|
|
147
|
+
|
|
148
|
+
JSON parsing is the default. Set `parse: 'text'` or pass a custom parser for non-JSON payloads:
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
const logs = connectEventStream('/api/logs', { parse: 'text' });
|
|
152
|
+
|
|
153
|
+
logs.on('line', (event) => {
|
|
154
|
+
console.log(event.data);
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Auth
|
|
159
|
+
|
|
160
|
+
SSE routes are ordinary route handlers, so use the same auth checks you use for JSON routes:
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
import { requireAuth } from 'void/auth';
|
|
164
|
+
|
|
165
|
+
export const GET = defineHandler(async (c) => {
|
|
166
|
+
const user = await requireAuth(c);
|
|
167
|
+
|
|
168
|
+
return eventStream(async (stream) => {
|
|
169
|
+
await stream.send({ event: 'ready', data: { userId: user.id } });
|
|
170
|
+
await stream.closed;
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Native `EventSource` can send cookies with `withCredentials: true`. For non-cookie auth, generate a short-lived signed URL and validate it in the route handler.
|
|
176
|
+
|
|
177
|
+
## When to use SSE
|
|
178
|
+
|
|
179
|
+
Plain SSE is enough when the producer belongs to the same request that opened the stream:
|
|
180
|
+
|
|
181
|
+
- AI token streaming
|
|
182
|
+
- One-off progress updates
|
|
183
|
+
- Command output
|
|
184
|
+
- Per-request deployment or build logs
|
|
185
|
+
- Incremental status for a long-running action
|
|
186
|
+
|
|
187
|
+
Use a higher-level realtime primitive when you need cross-request fanout, rooms, replay buffers, subscriptions, database change streams, or multi-region coordination.
|
|
@@ -4,40 +4,37 @@ theme: dark
|
|
|
4
4
|
|
|
5
5
|
hero:
|
|
6
6
|
name: Void.
|
|
7
|
-
text: Ship
|
|
8
|
-
tagline:
|
|
7
|
+
text: Ship Vite apps at warp speed
|
|
8
|
+
tagline: A deployment platform designed for Vite. A powerful backend SDK to make your Vite apps truly full-stack.
|
|
9
9
|
actions:
|
|
10
10
|
- theme: brand
|
|
11
11
|
text: Get Started
|
|
12
12
|
link: ./guide/
|
|
13
|
-
- theme: alt
|
|
14
|
-
text: Join Early Access
|
|
15
|
-
link: https://tally.so/r/D4VE85
|
|
16
13
|
image:
|
|
17
14
|
src: /hero.svg
|
|
18
15
|
alt: Void deployment platform
|
|
19
16
|
|
|
20
17
|
features:
|
|
18
|
+
- iconify: lucide:terminal
|
|
19
|
+
title: One Command to Production
|
|
20
|
+
details: '`void deploy` builds your app, runs migrations, provisions resources, and deploys it.'
|
|
21
21
|
- iconify: lucide:layers
|
|
22
22
|
title: Truly Full-Stack
|
|
23
|
-
details: Database, KV storage, object storage, AI inference, authentication, queues, and cron jobs
|
|
23
|
+
details: Database, KV storage, object storage, AI inference, authentication, queues, and cron jobs. All built-in. Import what you need, skip what you don't.
|
|
24
24
|
- iconify: lucide:wand-sparkles
|
|
25
25
|
title: Your Code is Your Infra
|
|
26
|
-
details: Void scans your source code, detects what you use, and provisions
|
|
26
|
+
details: Void scans your source code, detects what you use, and automatically provisions every resource. No config files. No dashboard clicks. Locally and in the cloud.
|
|
27
27
|
- iconify: lucide:shield-check
|
|
28
|
-
title:
|
|
29
|
-
details:
|
|
28
|
+
title: Performant and Reliable
|
|
29
|
+
details: Built on Cloudflare's battle tested, global network. Fast, secure, and always available from day one.
|
|
30
30
|
- iconify: lucide:blocks
|
|
31
|
-
title:
|
|
32
|
-
details: React, Vue, Svelte, Solid,
|
|
31
|
+
title: Your Framework, Your Rendering
|
|
32
|
+
details: React, Vue, Svelte, Solid, Vite-based meta-frameworks. SSR, SSG, ISR, islands with partial hydration, and markdown.
|
|
33
33
|
- iconify: lucide:bot
|
|
34
34
|
title: AI-Native
|
|
35
35
|
details: Built-in skills, MCP support, and reference prompts let coding agents scaffold and ship full-stack apps in a single prompt.
|
|
36
|
-
- iconify: lucide:terminal
|
|
37
|
-
title: One Command to Production
|
|
38
|
-
details: '`void deploy` builds your app, runs migrations, provisions resources, and deploys to Cloudflare Workers, without requiring a Cloudflare account or knowledge about the infra.'
|
|
39
36
|
|
|
40
|
-
footer_heading:
|
|
37
|
+
footer_heading: Deploy at Warp Speed
|
|
41
38
|
footer_subheading: Vite. Optimized. Isomorphic. Deploy.
|
|
42
39
|
---
|
|
43
40
|
|
|
@@ -902,6 +902,10 @@ Solid `Link` GET `data` is merged into the rendered `href` query string. Primiti
|
|
|
902
902
|
| `void/auth` | `defineAuth`, `getUser`, `getSession`, `requireAuth`, `AuthUser`, `AuthSession`, `AuthState` |
|
|
903
903
|
| `void/client` | `fetch`, `fetchStream`, `FetchError`, `auth`, `createAuthClient`, `AuthUser`, `AuthSession`, `AuthState` |
|
|
904
904
|
| `void/ws` | `defineRoom`, `defineWebSocket`, `connect`, WebSocket context and connection types |
|
|
905
|
+
| `void/sse` | `eventStream`, `formatSse`, `formatSseText`, `getLastEventId`, `SseStreamClosedError`, SSE message and stream types |
|
|
906
|
+
| `void/sse/client` | `connectEventStream`, browser `EventSource` wrapper types |
|
|
907
|
+
| `void/live` | `defineLiveStream`, SSE topic fanout runtime types. Server-only. |
|
|
908
|
+
| `void/live/client` | `connectLiveStream`, browser helper for one SSE connection plus POST subscribe/unsubscribe control. |
|
|
905
909
|
| `void/response` | `convertReturnValue` |
|
|
906
910
|
| `void/validator` | `runValidation`, `ValidatorSlots`, `HandlerInput` |
|
|
907
911
|
| `void/drizzle-zod` | Re-exports [`drizzle-zod`](https://orm.drizzle.team/docs/zod) for schema-derived Zod validators for Drizzle tables |
|