@spooky-sync/client-solid2 0.0.1-canary.200
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/LICENSE +21 -0
- package/QUICK_START.md +126 -0
- package/README.md +19 -0
- package/dist/index.cjs +903 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +498 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.ts +498 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +884 -0
- package/dist/index.js.map +1 -0
- package/package.json +62 -0
- package/skills/sp00ky-solid2/SKILL.md +68 -0
- package/src/index.ts +365 -0
- package/src/lib/Sp00kyProvider.ts +104 -0
- package/src/lib/__tests__/conflate.test.ts +120 -0
- package/src/lib/__tests__/create-query.test.ts +284 -0
- package/src/lib/__tests__/rc-semantics.test.ts +389 -0
- package/src/lib/conflate.ts +74 -0
- package/src/lib/context.ts +28 -0
- package/src/lib/create-preload.ts +115 -0
- package/src/lib/create-query.ts +285 -0
- package/src/lib/create-submission.ts +57 -0
- package/src/lib/from-subscription.ts +32 -0
- package/src/lib/models.ts +8 -0
- package/src/lib/use-app-release.ts +89 -0
- package/src/lib/use-crdt-field.ts +57 -0
- package/src/lib/use-download-file.ts +181 -0
- package/src/lib/use-feature-flag.ts +43 -0
- package/src/lib/use-file-upload.ts +146 -0
- package/src/lib/use-storage-status.ts +44 -0
- package/src/lib/use-sync-status.ts +63 -0
- package/src/types/index.ts +83 -0
- package/tsconfig.json +27 -0
- package/tsdown.config.ts +18 -0
- package/vitest.config.ts +14 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Khadim Fall
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/QUICK_START.md
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# @spooky-sync/client-solid2 — Quick Start
|
|
2
|
+
|
|
3
|
+
Solid **2.0** native bindings for the Sp00ky reactive local-first SurrealDB framework. This is the Solid 2 counterpart of `@spooky-sync/client-solid` (which stays on Solid 1.x); the two packages coexist until Solid 2.0 is stable and apps migrate.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @spooky-sync/client-solid2 solid-js@2.0.0-rc.0 @solidjs/web@2.0.0-rc.0 @solidjs/signals@2.0.0-rc.0
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
> **Coordinated RC**: `solid-js`, `@solidjs/web`, and `@solidjs/signals` must be on matching `2.0.0-rc.x` versions. Pin exact versions; this package's semantics probes (`rc-semantics.test.ts`) catch drift on bumps. `jsxImportSource` is `@solidjs/web` in Solid 2.
|
|
12
|
+
|
|
13
|
+
## Provider
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
import { Sp00kyProvider } from '@spooky-sync/client-solid2';
|
|
17
|
+
import { schema } from './generated/schema';
|
|
18
|
+
import schemaSurql from './generated/schema.surql?raw';
|
|
19
|
+
|
|
20
|
+
function App() {
|
|
21
|
+
return (
|
|
22
|
+
<Sp00kyProvider
|
|
23
|
+
config={{
|
|
24
|
+
database: { endpoint: 'ws://localhost:8000', namespace: 'my_ns', database: 'my_db', store: 'indexeddb' },
|
|
25
|
+
schema,
|
|
26
|
+
schemaSurql,
|
|
27
|
+
}}
|
|
28
|
+
fallback={<div>Loading database…</div>}
|
|
29
|
+
preload={async (db) => { await db.preload(db.query('config').build()); }}
|
|
30
|
+
>
|
|
31
|
+
<MyApp />
|
|
32
|
+
</Sp00kyProvider>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Same props as client-solid's provider (`config`, `fallback`, `preload`, `onReady`, `onError`). A live mounted client is deliberately not closed on unmount (see source comment).
|
|
38
|
+
|
|
39
|
+
## createQuery
|
|
40
|
+
|
|
41
|
+
`createQuery` replaces `useQuery` (which remains as a deprecated alias). Same overloads: `(query, options?)` with context, or `(db, query, options?)`.
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
import { createQuery, useDb } from '@spooky-sync/client-solid2';
|
|
45
|
+
|
|
46
|
+
function PostList() {
|
|
47
|
+
const db = useDb();
|
|
48
|
+
const posts = createQuery(db.query('post').orderBy('createdAt', 'desc').limit(20).build());
|
|
49
|
+
|
|
50
|
+
// Accessor style — data() never suspends, born as [] and live thereafter:
|
|
51
|
+
return (
|
|
52
|
+
<Show when={!posts.isLoading()} fallback={<div>Loading…</div>}>
|
|
53
|
+
<For each={posts.data()}>{(post) => <PostRow post={post} />}</For>
|
|
54
|
+
</Show>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Reactive inputs: pass a thunk, read your signals inside it.
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
const post = createQuery(() => (postId() ? db.query('post').where({ id: postId() }).one().build() : null));
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Suspension style (`<Loading>`)
|
|
66
|
+
|
|
67
|
+
`q.ready()` reads the same data but participates in Solid 2's boundary protocol: it pends until the first real result.
|
|
68
|
+
|
|
69
|
+
```tsx
|
|
70
|
+
import { Loading } from 'solid-js';
|
|
71
|
+
|
|
72
|
+
<Loading fallback={<Skeleton />}>
|
|
73
|
+
<For each={posts.ready()}>{(post) => <PostRow post={post} />}</For>
|
|
74
|
+
</Loading>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Result surface
|
|
78
|
+
|
|
79
|
+
| Accessor | Meaning |
|
|
80
|
+
|---|---|
|
|
81
|
+
| `data()` | Rows (or row/`null` for `.one()`). Never suspends, never throws. Keyed-reconciled in place: unchanged rows keep identity, `<For>` is notified on add/remove/reorder. |
|
|
82
|
+
| `ready()` | Same data, suspends into the nearest `<Loading>` until first result or error. |
|
|
83
|
+
| `error()` | Registration/sync error (e.g. SSP 503 during bootstrap). Never thrown into the render tree; the sync scheduler retries underneath. |
|
|
84
|
+
| `isLoading()` | No result yet and no error. |
|
|
85
|
+
| `isFetching()` | Sync engine is pulling records for this query. |
|
|
86
|
+
| `isSettled()` | Delivered AND idle — windowed lists may trust a short result as the true end of the list. |
|
|
87
|
+
|
|
88
|
+
Options: `{ enabled?: () => boolean, deregisterOnCleanup?: boolean }` — both as in client-solid.
|
|
89
|
+
|
|
90
|
+
### Gotcha: rows are store proxies
|
|
91
|
+
|
|
92
|
+
Solid 2 stores wrap class instances too, and serve methods bound. A `RecordId` read out of a row works for display and for `db.delete('table', row.id)`, but if you pass whole row objects back into surrealdb APIs that check `instanceof`, unwrap first with `snapshot(row)` (exported by `solid-js`).
|
|
93
|
+
|
|
94
|
+
## Mutations
|
|
95
|
+
|
|
96
|
+
Engine writes are already optimistic local-first (local commit → live queries re-emit → outbox sync; `db.run()` is itself an outbox job row with `status: 'pending'`). Plain calls:
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
await db.create('post:xyz', { title: 'Hi' });
|
|
100
|
+
await db.update('post', 'post:xyz', { title: 'Edited' });
|
|
101
|
+
await db.delete('post', row.id);
|
|
102
|
+
await db.run('backend', 'sendMail', { to });
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
For button pending/error state, wrap with `createSubmission`:
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
const save = createSubmission((title: string) => db.create(`post:${crypto.randomUUID()}`, { title }));
|
|
109
|
+
<button disabled={save.pending()} onClick={() => save.submit(title())}>Save</button>
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Track a backend job's progress by querying its outbox row: `createQuery(() => db.query('job_outbox').where({ id: jobId() }).one().build())`.
|
|
113
|
+
|
|
114
|
+
## Status hooks
|
|
115
|
+
|
|
116
|
+
Same shapes as client-solid, rebuilt on async-iterable-backed memos: `useSyncStatus`, `useStorageStatus`, `usePendingMutations`, `useFeatureFlag`, `useAppRelease`, `useCrdtField`, `useFileUpload`, `useDownloadFile`, `createPreload`.
|
|
117
|
+
|
|
118
|
+
## Migrating from client-solid
|
|
119
|
+
|
|
120
|
+
| client-solid (Solid 1) | client-solid2 (Solid 2) |
|
|
121
|
+
|---|---|
|
|
122
|
+
| `useQuery(q)` | `createQuery(q)` (alias `useQuery` kept) |
|
|
123
|
+
| `data()` may be `undefined` pre-fetch | `data()` is `[]` / `null` pre-fetch |
|
|
124
|
+
| No suspension | `ready()` + `<Loading>` |
|
|
125
|
+
| `useDb()` throws custom error | same API (Solid 2 context throws on missing provider) |
|
|
126
|
+
| everything else | unchanged call signatures |
|
package/README.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# @spooky-sync/client-solid2
|
|
2
|
+
|
|
3
|
+
Solid **2.0** native bindings for the Sp00ky reactive local-first SurrealDB framework.
|
|
4
|
+
|
|
5
|
+
Counterpart of `@spooky-sync/client-solid` (Solid 1.x); the two coexist until Solid 2.0 is stable. Peer deps: `solid-js@^2.0.0-rc.0` + `@solidjs/signals@^2.0.0-rc.0` (coordinated RC — pin matching versions, apps also need `@solidjs/web`).
|
|
6
|
+
|
|
7
|
+
What "native" means here:
|
|
8
|
+
|
|
9
|
+
- Query results are a `createProjection` fed by an async generator over the engine's live subscription: keyed reconcile by `id`, row identity preserved, coarse `<For>` readers notified — no manual reconcile/version-signal plumbing.
|
|
10
|
+
- `createQuery` exposes both worlds: non-suspending accessors (`data`, `isLoading`, `isFetching`, `isSettled`, `error`) and a suspending `ready()` for `<Loading>` boundaries. Born committed (`seedLoadingValue`), so local-first cache paints never suspend.
|
|
11
|
+
- Status hooks (`useSyncStatus`, `useStorageStatus`, `usePendingMutations`, feature flags, app release) are async-iterable-backed memos with `loadingValue`.
|
|
12
|
+
- Mutations stay plain async calls — the engine is already optimistic local-first end to end (local commit → live re-emit → outbox sync). `createSubmission` adds button pending/error state.
|
|
13
|
+
|
|
14
|
+
See `QUICK_START.md` for usage and the migration table from client-solid, and `src/lib/__tests__/rc-semantics.test.ts` for the probed Solid 2 rc contracts this package depends on (run them after every Solid version bump).
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pnpm --filter @spooky-sync/client-solid2 test
|
|
18
|
+
pnpm --filter @spooky-sync/client-solid2 build
|
|
19
|
+
```
|