@lunora/cli 1.0.0-alpha.400 → 1.0.0-alpha.401

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/cli",
3
- "version": "1.0.0-alpha.400",
3
+ "version": "1.0.0-alpha.401",
4
4
  "description": "The Lunora CLI: init, dev, deploy, codegen, migrate, seed, doctor, insights, logs, registry, and the rest of the project commands",
5
5
  "keywords": [
6
6
  "agent-skills",
@@ -52,16 +52,16 @@
52
52
  },
53
53
  "dependencies": {
54
54
  "@bomb.sh/tab": "0.0.22",
55
- "@lunora/advisor": "1.0.0-alpha.235",
55
+ "@lunora/advisor": "1.0.0-alpha.236",
56
56
  "@lunora/bindings": "1.0.0-alpha.123",
57
- "@lunora/codegen": "1.0.0-alpha.326",
58
- "@lunora/config": "1.0.0-alpha.375",
57
+ "@lunora/codegen": "1.0.0-alpha.327",
58
+ "@lunora/config": "1.0.0-alpha.377",
59
59
  "@lunora/container": "1.0.0-alpha.82",
60
60
  "@lunora/d1": "1.0.0-alpha.190",
61
61
  "@lunora/errors": ">=1.0.0-alpha.51 <2.0.0-0",
62
- "@lunora/mcp": "1.0.0-alpha.242",
62
+ "@lunora/mcp": "1.0.0-alpha.243",
63
63
  "@lunora/runtime": "1.0.0-alpha.219",
64
- "@lunora/seed": "1.0.0-alpha.237",
64
+ "@lunora/seed": "1.0.0-alpha.238",
65
65
  "@visulima/cerebro": "3.1.2",
66
66
  "@visulima/error": "6.1.0",
67
67
  "@visulima/fs": "6.0.29",
@@ -42,7 +42,9 @@ Scaffolded projects gitignore `lunora/_generated/`; never hand-edit it.
42
42
  - New project, or adding Lunora to an existing app: `lunora-quickstart`
43
43
  - Writing or reviewing schema + functions (the core authoring rules):
44
44
  `lunora-functions`
45
- - Wiring live data into a client (hooks, optimistic updates): `lunora-realtime`
45
+ - Wiring live data into a client (hooks, optimistic updates), or choosing
46
+ between a live query, stream, live topic, whisper, room and socket (including
47
+ pushing a server event to the browser): `lunora-realtime`
46
48
  - Authentication (email/password, OAuth, magic link, OTP): `lunora-setup-auth`
47
49
  - Transactional email: `lunora-setup-mail`
48
50
  - R2 file storage (signed upload/download): `lunora-setup-storage`
@@ -285,6 +285,7 @@ first, then run `lunora codegen` to wire the binding and typed context:
285
285
  | `ctx.workflows` / `ctx.runStep` | `@lunora/workflow` |
286
286
  | `ctx.containers` | `@lunora/container` |
287
287
  | `ctx.browser` (action-only) | `@lunora/browser` |
288
+ | `ctx.live` (action-side only; see `lunora-realtime`) | `@lunora/server` |
288
289
  | `ctx.sql` (action-only) | `@lunora/hyperdrive` |
289
290
  | `ctx.kv` / `ctx.images` / `ctx.analytics` | `@lunora/bindings` subpaths |
290
291
  | `ctx.pipelines` / `ctx.vectors` / `ctx.r2sql` | `@lunora/bindings` subpaths |
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: lunora-realtime
3
- description: Wires Lunora's live data into a client app. Covers `LunoraClient` and the per-framework provider, reactive `useQuery`/`useSubscription`, `useMutation` with optimistic updates, `usePaginatedQuery`, `shardKey` routing, connection status, presence, the React/Vue/Solid/Svelte/Angular/React Native adapters, and the `@lunora/db` TanStack DB binding. Use when building UI that reads or writes Lunora functions, when asked to "show live data", "make this update in real time", "add optimistic updates", "add infinite scroll/pagination", or "show offline/reconnecting state", when editing components that import `@lunora/react`/`vue`/`solid`/`svelte`/`angular`/`react-native` or `lunorash/client`, or when a live query stays `undefined`, freezes, or doesn't update.
3
+ description: Wires Lunora's live data into a client app. Covers `LunoraClient` and the per-framework provider, reactive `useQuery`/`useSubscription`, `useMutation` with optimistic updates, `usePaginatedQuery`, `shardKey` routing, connection status, presence, the React/Vue/Solid/Svelte/Angular/React Native adapters, and the `@lunora/db` TanStack DB binding. Use when building UI that reads or writes Lunora functions, when asked to "show live data", "make this update in real time", "add optimistic updates", "add infinite scroll/pagination", or "show offline/reconnecting state", when editing components that import `@lunora/react`/`vue`/`solid`/`svelte`/`angular`/`react-native` or `lunorash/client`, when a live query stays `undefined`, freezes, or doesn't update, or when choosing between a live query, a stream, a live topic (`defineLiveStream`, `useLiveTopic`, `ctx.live.publish`, SSE), a whisper, a room and a socket, such as "push an event to the browser" or "notify the page when X happens".
4
4
  ---
5
5
 
6
6
  # Lunora Realtime
@@ -10,6 +10,27 @@ subscriptions over WebSocket — a `useQuery` re-renders as soon as a mutation
10
10
  changes the rows it reads — and mutations can paint optimistically with
11
11
  automatic rollback.
12
12
 
13
+ ## Choosing a Channel
14
+
15
+ Decide by what you are sending. If the client could get it by running a query,
16
+ use a live query: it is typed, runs under the caller's identity, and works across
17
+ shards. Reach past it only for the rest.
18
+
19
+ | You want | Use |
20
+ | -------------------------------------------------- | ------------------------------------------------------ |
21
+ | Rows that stay fresh | `useQuery` (WebSocket, typed through `api.*`) |
22
+ | A write / a side effect | `useMutation` / `useAction` |
23
+ | Chunks of one long call (model tokens) | `query.stream()` + `useStream` (`durable` to resume) |
24
+ | Chunks of one HTTP request | `httpRoute.get(path).stream()` + `useHttpStream` |
25
+ | A server-published event that is not a row | live topic: `defineLiveStream` + `useLiveTopic` |
26
+ | A client-to-clients ephemeral message (cursors) | whisper (`client.whisper`; authorize with `onWhisper`) |
27
+ | A room with server join / message / leave handlers | `defineRoom` + `client.connectRoom` |
28
+ | A dedicated socket at your own path | `defineWebSocket` + `client.connectWebSocket(path)` |
29
+ | Who is online | `usePresence` |
30
+
31
+ Live topics are the untyped one: the topic is a string and the payload is
32
+ `unknown`. Full guide: the "Choosing a data channel" docs page.
33
+
13
34
  ## When Not to Use
14
35
 
15
36
  - Writing the server functions themselves — that's `lunora-functions`.
@@ -170,6 +191,46 @@ TanStack-style alternative.
170
191
  - `useAuth` + `Authenticated` / `Unauthenticated` / `AuthLoading` — see
171
192
  `lunora-setup-auth`.
172
193
 
194
+ ## Live Topics
195
+
196
+ For an event with no query behind it ("a comment was posted"), the server
197
+ publishes to a named topic and the browser follows topics over one shared SSE
198
+ connection (shared when the connection options match). Declare the stream once, mount its two handlers on the HTTP router,
199
+ and follow topics with the adapter's hook (all return `{ lastEvent, error }`):
200
+
201
+ | Package | Primitive |
202
+ | ---------------------- | ------------------------- |
203
+ | `@lunora/react`, `vue` | `useLiveTopic` |
204
+ | `@lunora/solid` | `createLiveTopic` |
205
+ | `@lunora/svelte` | `liveTopic` (a store) |
206
+ | `@lunora/angular` | `liveTopic` (signals) |
207
+ | `@lunora/react-native` | re-exports `useLiveTopic` |
208
+
209
+ ```tsx
210
+ const { lastEvent, error } = useLiveTopic({ url: "/live/posts/connect", topic: `post:${postId}`, onEvent: (payload) => refresh(payload) });
211
+ ```
212
+
213
+ - Several hooks with the same URL, credentials, headers, `retryDelay`, `maxDelayMs` and
214
+ `sessionKey` share a single connection; the last to unmount closes it. On a
215
+ cookie-authenticated stream pass `sessionKey` (the user id), or the connection
216
+ outlives a sign-out and keeps the previous user's topics.
217
+ - Publish from server code with `ctx.live.publish(topic, payload, { stream })`.
218
+ `ctx.live` exists only on actions, HTTP actions, queue consumers and scheduled
219
+ actions, NOT on a query or mutation. It is always present on an HTTP action
220
+ but typed optional on an `action` and a queue consumer, so write
221
+ `ctx.live?.publish(...)` there. To tell a page about a write, have the
222
+ mutation `ctx.scheduler.runAfter(0, internal.x.publish, args)`: it is held until
223
+ the commit, so a rolled-back write sends nothing. If the page already has a
224
+ `useQuery` over those rows, skip the event.
225
+ - Without `onSubscribe` every subscribe is DENIED (unless `allowAnonymousControl`
226
+ admits anonymous callers). Only a literal `true` allows.
227
+ - Delivery is at least once (a retried action publishes again) and shard-local
228
+ (no fan-out across Durable Objects). Put an id in the payload to dedupe.
229
+ - React Native's stock `fetch` does not stream, so events never arrive; use a
230
+ streaming `fetch` such as `expo/fetch`.
231
+ - Live streams are native on Cloudflare and celld, emulated on Node. Codegen
232
+ refuses an app that reads `ctx.live` on a target that withholds them.
233
+
173
234
  ## `@lunora/db` — TanStack DB Collections
174
235
 
175
236
  For indexed local collections, cross-query joins, or a durable offline outbox,
@@ -216,3 +277,5 @@ hold stale ones, while `useLiveQuery` still looks correct.
216
277
  `optimisticUpdate` rows match the query's element shape.
217
278
  - [ ] Lists that grow use `usePaginatedQuery` over a `.paginate` query.
218
279
  - [ ] `@lunora/db`: one `defineCollections` instance; no parallel copy of rows.
280
+ - [ ] Events that are not rows use a live topic, published from an action (via
281
+ `ctx.scheduler` after a write); data a query could return stays a `useQuery`.