@spooky-sync/client-solid 0.0.1-canary.33 → 0.0.1-canary.330

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/AGENTS.md ADDED
@@ -0,0 +1,70 @@
1
+ # `@spooky-sync/client-solid` — agent guide
2
+
3
+ ## What this package is
4
+
5
+ The SolidJS binding for sp00ky. Exposes a `Sp00kyProvider` that initializes a `Sp00kyClient` and a set of reactive hooks (`useDb`, `useQuery`, `useCrdtField`, `useFileUpload`, `useDownloadFile`). All hooks expect to be called inside a `<Sp00kyProvider>` boundary.
6
+
7
+ ## Setup pattern
8
+
9
+ ```ts
10
+ // db.ts
11
+ import type { SyncedDbConfig } from '@spooky-sync/client-solid';
12
+ import { schema, SURQL_SCHEMA } from './schema.gen'; // generated by `spky generate`
13
+
14
+ export const dbConfig: SyncedDbConfig<typeof schema> = {
15
+ schema,
16
+ schemaSurql: SURQL_SCHEMA,
17
+ database: {
18
+ namespace: 'main',
19
+ database: 'app',
20
+ endpoint: 'ws://localhost:8666/rpc',
21
+ store: 'memory', // or 'indexeddb' for persistence
22
+ persistenceClient: 'localstorage',
23
+ },
24
+ };
25
+ ```
26
+
27
+ ```tsx
28
+ // App.tsx
29
+ <Sp00kyProvider config={dbConfig}>{/* app */}</Sp00kyProvider>
30
+ ```
31
+
32
+ ## Key hooks
33
+
34
+ - **`useDb<typeof schema>()`** — returns the `SyncedDb<S>` instance. Methods:
35
+ - `db.create(id, payload)` — `id` is a full record ID like `'thread:abc'`.
36
+ - `db.update(table, id, payload, options?)` — `options.debounced` coalesces updates; with `flushOnHide` (default `true`) a pending patch survives a reload or closed tab.
37
+ - `db.delete(table, idOrSelector)`.
38
+ - `db.query(table)` — returns a `QueryBuilder`. Chain `.related()`, `.orderBy()`, `.limit()`, etc., end with `.build()`.
39
+ - `db.preload(query, options?)` — registers the query without subscribing. Resolved before on this device: returns instantly. Never resolved: awaits the server's membership and every record. Signed out without `enableAnonymousLiveQueries`: returns instantly (no membership is ever sent to that session). `options.signal` aborts a cold wait; `refresh`/`staleTime` are ignored. Evicted a ttl after registration unless a view mounts the same query.
40
+ - `db.run(backend, route, payload)` — call a backend RPC route.
41
+ - `db.bucket(name)` — get a `BucketHandle` for file storage.
42
+ - `db.remoteQuery(sql, vars?)` — one-shot remote read through the client's queued, connect-gated path (skips cache).
43
+ - `db.useRemote(fn)` — escape hatch to the raw `Surreal` client (skips cache AND the connect gate).
44
+ - `db.authenticate(token)`, `db.signOut()`, `db.auth`.
45
+ - `db.pendingMutationCount`, `db.subscribeToPendingMutations(cb)`.
46
+ - **`useQuery(() => db.query(...).build())`** — reactive query. Returns `{ data, status, error, ... }` accessors. The factory function is tracked, so passing reactive params (signals) re-runs the query.
47
+ - **`createPreload(() => db.query(...).build(), options?)`** — reactive, fire-and-forget prewarm (same overloads/`enabled` as `useQuery`, plus `signal`). Registers a query the user is likely to open next (e.g. a list row's detail). For blocking first-load, use the `Sp00kyProvider` `preload` prop instead.
48
+ - **`useCrdtField(table, () => recordId, field)`**: opens a `@crdt` field and returns an accessor that is `null` until it is open, then a `CrdtField`. Bind the editor to `field()?.getDoc()` (a `LoroDoc`: `loro-prosemirror` plugins for `@crdt prosemirror`, `doc.getText(field)` for `@crdt text`); edits sync themselves, so there is no `db.update` for them. Reopens when the id changes, closes on cleanup. To give a not-yet-created record content, use `db.getSp00ky().createCrdtDraft(table, field)`, then after `db.create` call `openCrdtField(table, id, field, draft)` and `await closeCrdtField(...)`. Only the record id is an accessor.
49
+ - **`useImpersonation()`**: `{ impersonation, isImpersonating, stop }` for admin impersonation started from the DevTools (`impersonation.enabled` in sp00ky.yml). The client already renders its own warning bar with a Stop button; use the hook only for extras, such as hiding destructive actions while impersonating, or pass `{ rendersBanner: true }` when the app draws its own banner under `impersonationBanner: { mode: 'custom' }`. See `/docs/client/impersonation`.
50
+ - **`useFileUpload()`** / **`useDownloadFile()`** — bucket helpers; the upload result includes the storage path you write into a record column. `useDownloadFile` reads through the durable OPFS blob cache (options `{ cache, persist, pin, revalidate }`), so images survive a reload and paint offline; `refetch()` bypasses every layer.
51
+
52
+ ## Re-exports for convenience
53
+
54
+ - `RecordId`, `Uuid` from `surrealdb`.
55
+ - Query-builder types: `TableModel`, `TableNames`, `GetTable`, `QueryResult`, etc. (see `@spooky-sync/query-builder/AGENTS.md`).
56
+ - `Model<S, T>`, `GenericModel`, `ModelPayload` — typed row shapes.
57
+
58
+ ## Common gotchas
59
+
60
+ - **`useDb()` requires `<typeof schema>`.** Without the generic, all calls fall back to `unknown` and you lose type safety.
61
+ - **A `@crdt` column is the server-written plain text of its document.** Read it with `useQuery` for previews, search and filters (it trails live edits until the server folds, a few seconds); edit it only through `useCrdtField`. Set it only in the `db.create` that makes the record (its initial text, so lists show it before the first fold); a later `db.update` keeps the old value.
62
+ - **Generate IDs explicitly.** `const id = new Uuid().toString()`, then `db.create(\`thread:\${id}\`, ...)`. SurrealDB's auto-id only fires on direct DB writes, not through the sync queue.
63
+ - **`useQuery` factories must call `.build()` (or `.all()`, `.first()`, etc.).** A bare `db.query('thread')` is a builder, not a query — `useQuery` will throw or return forever-loading.
64
+ - **Provider is mandatory.** Calling any hook outside `<Sp00kyProvider>` throws.
65
+
66
+ ## Pointers
67
+
68
+ - Sync engine: `node_modules/@spooky-sync/core/AGENTS.md`
69
+ - Query builder DSL: `node_modules/@spooky-sync/query-builder/AGENTS.md`
70
+ - Schema authoring + codegen: `node_modules/@spooky-sync/cli/AGENTS.md`
package/README.md CHANGED
@@ -11,6 +11,7 @@ A SurrealDB client for Solid.js with automatic cache synchronization and live qu
11
11
  - **Type-Safe**: Full TypeScript support with generated schema types
12
12
  - **Reactive**: Seamless integration with Solid.js reactivity
13
13
  - **Offline Support**: Local cache works even when remote is temporarily unavailable
14
+ - **Preload / Prewarm**: Warm data into the local cache ahead of time so screens open instantly — awaitable to gate first load, reactive to prefetch what's next
14
15
 
15
16
  ## Quick Start
16
17
 
@@ -215,6 +216,25 @@ const liveQuery = await db.query.thread
215
216
  .orderBy('created_at', 'desc'); // ✅ Field names autocompleted
216
217
  ```
217
218
 
219
+ ### Preload / Prewarm
220
+
221
+ Warm a query's results into the local cache before they're needed, so a later `useQuery` paints
222
+ instantly instead of waiting on the network. Preload is a one-shot snapshot — it does not register
223
+ a live view; the data freshens on use when the real `useQuery` mounts.
224
+
225
+ ```typescript
226
+ // Awaitable + cache-aware: blocks on the FIRST load (nothing cached), returns
227
+ // instantly on later loads (already cached). Great for gating the UI on config.
228
+ await db.preload(db.query('config').build());
229
+
230
+ // Opt into a one-time background refresh when the cache is stale:
231
+ await db.preload(db.query('config').build(), { refresh: 'stale', staleTime: '1d' });
232
+ ```
233
+
234
+ Block first-load UI on essential data via the `Sp00kyProvider` `preload` prop, or reactively
235
+ prefetch what the user is likely to open next with `createPreload(() => …build())`. Full details
236
+ in the [SKILL guide](./skills/sp00ky-solid/SKILL.md#preload).
237
+
218
238
  ## Documentation
219
239
 
220
240
  - **[Quick Start Guide](./QUICK_START.md)**: Get up and running quickly