@lunora/replica 0.0.0 → 1.0.0-alpha.100
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.md +445 -0
- package/README.md +239 -29
- package/dist/adapters/better-sqlite3.d.mts +29 -0
- package/dist/adapters/better-sqlite3.d.ts +29 -0
- package/dist/adapters/better-sqlite3.mjs +1 -0
- package/dist/adapters/sqlite-wasm.d.mts +30 -0
- package/dist/adapters/sqlite-wasm.d.ts +30 -0
- package/dist/adapters/sqlite-wasm.mjs +1 -0
- package/dist/adapters/sqljs.d.mts +22 -0
- package/dist/adapters/sqljs.d.ts +22 -0
- package/dist/adapters/sqljs.mjs +1 -0
- package/dist/index.d.mts +1074 -0
- package/dist/index.d.ts +1074 -0
- package/dist/index.mjs +1 -0
- package/dist/packem_shared/EventEmitter-uo75adUL.mjs +1 -0
- package/dist/packem_shared/EventLog-SuC_BKwj.mjs +1 -0
- package/dist/packem_shared/EventLogDO-BgUx2GGL.mjs +1 -0
- package/dist/packem_shared/EventLogDOClient-DWerZ3_n.mjs +1 -0
- package/dist/packem_shared/EventSource-Bg6zNmRn.mjs +1 -0
- package/dist/packem_shared/EventsSync-B3wzXm-b.mjs +1 -0
- package/dist/packem_shared/InMemorySnapshotStore-C4taIG5K.mjs +1 -0
- package/dist/packem_shared/LocalMirror-Bn22hyEB.mjs +4 -0
- package/dist/packem_shared/MaterializerRuntime-DFXi-aqd.mjs +1 -0
- package/dist/packem_shared/SubscriptionManager-AhPw3lFc.mjs +1 -0
- package/dist/packem_shared/applyDiff-CZAqAC8Y.mjs +1 -0
- package/dist/packem_shared/applyDiffToDb-CK-Dcy17.mjs +1 -0
- package/dist/packem_shared/classifyChanges-BBc0-770.mjs +1 -0
- package/dist/packem_shared/defineEvents-DHo-VK7G.mjs +1 -0
- package/dist/packem_shared/eventsContext-Dxow9Y7S.mjs +1 -0
- package/dist/packem_shared/fnv1a-BNN96GYb.mjs +1 -0
- package/dist/packem_shared/int64-CCVxepl4.mjs +1 -0
- package/dist/packem_shared/isClientSeq-D2Xm0_lj.mjs +1 -0
- package/dist/packem_shared/local-mirror.d-DzREvGNM.d.mts +562 -0
- package/dist/packem_shared/local-mirror.d-wbGXkXaE.d.ts +562 -0
- package/dist/packem_shared/subscribeToMirror-DSn8n1IR.mjs +1 -0
- package/dist/packem_shared/types.d-BuLTPLaQ.d.mts +22 -0
- package/dist/packem_shared/types.d-BuLTPLaQ.d.ts +22 -0
- package/dist/packem_shared/wire-key-DfMHAtqH.mjs +1 -0
- package/dist/react.d.mts +77 -0
- package/dist/react.d.ts +77 -0
- package/dist/react.mjs +1 -0
- package/package.json +88 -7
package/dist/react.d.mts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { L as LocalMirror } from "./packem_shared/local-mirror.d-DzREvGNM.mjs";
|
|
2
|
+
import "./packem_shared/types.d-BuLTPLaQ.mjs";
|
|
3
|
+
/**
|
|
4
|
+
* Result of {@link useLocalQuery} — a discriminated union so callers get a
|
|
5
|
+
* typed error instead of a swallowed `undefined`.
|
|
6
|
+
* @experimental
|
|
7
|
+
*/
|
|
8
|
+
type LocalQueryResult<T> = {
|
|
9
|
+
readonly data: T[];
|
|
10
|
+
readonly error?: undefined;
|
|
11
|
+
} | {
|
|
12
|
+
readonly data?: undefined;
|
|
13
|
+
readonly error: Error;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* React hook that subscribes to a local SQLite query and returns
|
|
17
|
+
* live-updating results whenever the mirror applies a diff.
|
|
18
|
+
*
|
|
19
|
+
* Uses `useSyncExternalStore` with `getSnapshot` reading {@link LocalMirror.version}
|
|
20
|
+
* — a plain number, unconditionally `Object.is`-stable across calls with no
|
|
21
|
+
* mutation in between. The actual query runs in a `useMemo` keyed on
|
|
22
|
+
* `[mirror, version, sql, stableParamsKey(params)]`, so it only re-executes
|
|
23
|
+
* when the mirror actually advances (or `sql`/`params` change) — not on
|
|
24
|
+
* every unrelated re-render.
|
|
25
|
+
*
|
|
26
|
+
* This intentionally does NOT cache query results inside {@link LocalMirror}
|
|
27
|
+
* itself: an LRU-capped cache in the mirror core evicts still-mounted hooks'
|
|
28
|
+
* entries once more than the cap's worth of distinct live queries are open
|
|
29
|
+
* on one mirror, which makes `getSnapshot` return a fresh (non-identical)
|
|
30
|
+
* object on the next read — `useSyncExternalStore` then force-re-renders,
|
|
31
|
+
* re-inserts, evicts another entry, and so on without bound. Keying the
|
|
32
|
+
* external-store snapshot on the version primitive instead of a cached
|
|
33
|
+
* query result has no such cap, so it can't loop.
|
|
34
|
+
*
|
|
35
|
+
* The hook works with React 18+ concurrent features, Suspense, and
|
|
36
|
+
* server-side rendering. During SSR the same value is returned as on
|
|
37
|
+
* the client (the mirror's current state at render time).
|
|
38
|
+
* @param mirror The {@link LocalMirror} instance to query. Must have been
|
|
39
|
+
* constructed with an {@link import("./adapters/types").SqliteAdapter}.
|
|
40
|
+
* @param sql Parameterised SQL query string. Use `?` placeholders for
|
|
41
|
+
* bound parameters (the adapter forwards them to the underlying SQLite
|
|
42
|
+
* engine without rewriting).
|
|
43
|
+
* @param params Optional positional bound parameters matching `?`
|
|
44
|
+
* placeholders in `sql`.
|
|
45
|
+
* @returns `{ data }` with the result rows typed via the generic parameter
|
|
46
|
+
* `T`, or `{ error }` when the query fails (e.g. malformed SQL, or the
|
|
47
|
+
* target table doesn't exist yet because no matching diff has been applied
|
|
48
|
+
* — that specific case surfaces as a "no such table" `Error`). Never
|
|
49
|
+
* collapses a failure to `undefined` — check `error` explicitly rather than
|
|
50
|
+
* treating a missing `data` as "still loading".
|
|
51
|
+
* @example
|
|
52
|
+
* ```tsx
|
|
53
|
+
* import { useLocalQuery } from "@lunora/replica/react";
|
|
54
|
+
* import { mirror } from "./mirror";
|
|
55
|
+
*
|
|
56
|
+
* function UserList() {
|
|
57
|
+
* const { data: users, error } = useLocalQuery<{ id: string; name: string }>(
|
|
58
|
+
* mirror,
|
|
59
|
+
* "SELECT id, name FROM fn_todos_list WHERE name LIKE ?",
|
|
60
|
+
* ["%alice%"],
|
|
61
|
+
* );
|
|
62
|
+
*
|
|
63
|
+
* if (error) {
|
|
64
|
+
* return <p>Query failed: {error.message}</p>;
|
|
65
|
+
* }
|
|
66
|
+
*
|
|
67
|
+
* if (users === undefined) {
|
|
68
|
+
* return <p>Waiting for data…</p>;
|
|
69
|
+
* }
|
|
70
|
+
*
|
|
71
|
+
* return <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
|
|
72
|
+
* }
|
|
73
|
+
* ```
|
|
74
|
+
* @experimental
|
|
75
|
+
*/
|
|
76
|
+
declare const useLocalQuery: <T = Record<string, unknown>>(mirror: LocalMirror, sql: string, params?: ReadonlyArray<unknown>) => LocalQueryResult<T>;
|
|
77
|
+
export { type LocalQueryResult, useLocalQuery };
|
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { L as LocalMirror } from "./packem_shared/local-mirror.d-wbGXkXaE.js";
|
|
2
|
+
import "./packem_shared/types.d-BuLTPLaQ.js";
|
|
3
|
+
/**
|
|
4
|
+
* Result of {@link useLocalQuery} — a discriminated union so callers get a
|
|
5
|
+
* typed error instead of a swallowed `undefined`.
|
|
6
|
+
* @experimental
|
|
7
|
+
*/
|
|
8
|
+
type LocalQueryResult<T> = {
|
|
9
|
+
readonly data: T[];
|
|
10
|
+
readonly error?: undefined;
|
|
11
|
+
} | {
|
|
12
|
+
readonly data?: undefined;
|
|
13
|
+
readonly error: Error;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* React hook that subscribes to a local SQLite query and returns
|
|
17
|
+
* live-updating results whenever the mirror applies a diff.
|
|
18
|
+
*
|
|
19
|
+
* Uses `useSyncExternalStore` with `getSnapshot` reading {@link LocalMirror.version}
|
|
20
|
+
* — a plain number, unconditionally `Object.is`-stable across calls with no
|
|
21
|
+
* mutation in between. The actual query runs in a `useMemo` keyed on
|
|
22
|
+
* `[mirror, version, sql, stableParamsKey(params)]`, so it only re-executes
|
|
23
|
+
* when the mirror actually advances (or `sql`/`params` change) — not on
|
|
24
|
+
* every unrelated re-render.
|
|
25
|
+
*
|
|
26
|
+
* This intentionally does NOT cache query results inside {@link LocalMirror}
|
|
27
|
+
* itself: an LRU-capped cache in the mirror core evicts still-mounted hooks'
|
|
28
|
+
* entries once more than the cap's worth of distinct live queries are open
|
|
29
|
+
* on one mirror, which makes `getSnapshot` return a fresh (non-identical)
|
|
30
|
+
* object on the next read — `useSyncExternalStore` then force-re-renders,
|
|
31
|
+
* re-inserts, evicts another entry, and so on without bound. Keying the
|
|
32
|
+
* external-store snapshot on the version primitive instead of a cached
|
|
33
|
+
* query result has no such cap, so it can't loop.
|
|
34
|
+
*
|
|
35
|
+
* The hook works with React 18+ concurrent features, Suspense, and
|
|
36
|
+
* server-side rendering. During SSR the same value is returned as on
|
|
37
|
+
* the client (the mirror's current state at render time).
|
|
38
|
+
* @param mirror The {@link LocalMirror} instance to query. Must have been
|
|
39
|
+
* constructed with an {@link import("./adapters/types").SqliteAdapter}.
|
|
40
|
+
* @param sql Parameterised SQL query string. Use `?` placeholders for
|
|
41
|
+
* bound parameters (the adapter forwards them to the underlying SQLite
|
|
42
|
+
* engine without rewriting).
|
|
43
|
+
* @param params Optional positional bound parameters matching `?`
|
|
44
|
+
* placeholders in `sql`.
|
|
45
|
+
* @returns `{ data }` with the result rows typed via the generic parameter
|
|
46
|
+
* `T`, or `{ error }` when the query fails (e.g. malformed SQL, or the
|
|
47
|
+
* target table doesn't exist yet because no matching diff has been applied
|
|
48
|
+
* — that specific case surfaces as a "no such table" `Error`). Never
|
|
49
|
+
* collapses a failure to `undefined` — check `error` explicitly rather than
|
|
50
|
+
* treating a missing `data` as "still loading".
|
|
51
|
+
* @example
|
|
52
|
+
* ```tsx
|
|
53
|
+
* import { useLocalQuery } from "@lunora/replica/react";
|
|
54
|
+
* import { mirror } from "./mirror";
|
|
55
|
+
*
|
|
56
|
+
* function UserList() {
|
|
57
|
+
* const { data: users, error } = useLocalQuery<{ id: string; name: string }>(
|
|
58
|
+
* mirror,
|
|
59
|
+
* "SELECT id, name FROM fn_todos_list WHERE name LIKE ?",
|
|
60
|
+
* ["%alice%"],
|
|
61
|
+
* );
|
|
62
|
+
*
|
|
63
|
+
* if (error) {
|
|
64
|
+
* return <p>Query failed: {error.message}</p>;
|
|
65
|
+
* }
|
|
66
|
+
*
|
|
67
|
+
* if (users === undefined) {
|
|
68
|
+
* return <p>Waiting for data…</p>;
|
|
69
|
+
* }
|
|
70
|
+
*
|
|
71
|
+
* return <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
|
|
72
|
+
* }
|
|
73
|
+
* ```
|
|
74
|
+
* @experimental
|
|
75
|
+
*/
|
|
76
|
+
declare const useLocalQuery: <T = Record<string, unknown>>(mirror: LocalMirror, sql: string, params?: ReadonlyArray<unknown>) => LocalQueryResult<T>;
|
|
77
|
+
export { type LocalQueryResult, useLocalQuery };
|
package/dist/react.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{useSyncExternalStore as y,useMemo as i}from"react";const u=t=>JSON.stringify(t??[],(r,e)=>typeof e=="bigint"?`${e.toString()}n`:e),S=(t,r,e)=>{const s=n=>t.onChange(n),o=()=>t.version,c=y(s,o,o),a=u(e);return i(()=>{try{return{data:t.query(r,e)}}catch(n){return{error:n instanceof Error?n:new Error(String(n))}}},[t,c,r,a])};export{S as useLocalQuery};
|
package/package.json
CHANGED
|
@@ -1,10 +1,91 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lunora/replica",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.0.0-alpha.100",
|
|
4
|
+
"description": "Local-first replica runtime + local SQLite mirror for Lunora",
|
|
5
5
|
"keywords": [
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
"cloudflare",
|
|
7
|
+
"durable-objects",
|
|
8
|
+
"event-sourcing",
|
|
9
|
+
"local-first",
|
|
10
|
+
"lunora",
|
|
11
|
+
"replica",
|
|
12
|
+
"sqlite",
|
|
13
|
+
"sync",
|
|
14
|
+
"workers"
|
|
15
|
+
],
|
|
16
|
+
"homepage": "https://lunora.sh",
|
|
17
|
+
"bugs": "https://github.com/anolilab/lunora/issues",
|
|
18
|
+
"license": "FSL-1.1-Apache-2.0",
|
|
19
|
+
"author": {
|
|
20
|
+
"name": "Daniel Bannert",
|
|
21
|
+
"email": "d.bannert@anolilab.de"
|
|
22
|
+
},
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/anolilab/lunora.git",
|
|
26
|
+
"directory": "packages/replica"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist",
|
|
30
|
+
"README.md",
|
|
31
|
+
"LICENSE.md"
|
|
32
|
+
],
|
|
33
|
+
"type": "module",
|
|
34
|
+
"sideEffects": false,
|
|
35
|
+
"main": "./dist/index.mjs",
|
|
36
|
+
"module": "./dist/index.mjs",
|
|
37
|
+
"types": "./dist/index.d.ts",
|
|
38
|
+
"exports": {
|
|
39
|
+
".": {
|
|
40
|
+
"types": "./dist/index.d.ts",
|
|
41
|
+
"import": "./dist/index.mjs"
|
|
42
|
+
},
|
|
43
|
+
"./react": {
|
|
44
|
+
"types": "./dist/react.d.ts",
|
|
45
|
+
"import": "./dist/react.mjs"
|
|
46
|
+
},
|
|
47
|
+
"./adapters/sqljs": {
|
|
48
|
+
"types": "./dist/adapters/sqljs.d.ts",
|
|
49
|
+
"import": "./dist/adapters/sqljs.mjs"
|
|
50
|
+
},
|
|
51
|
+
"./adapters/better-sqlite3": {
|
|
52
|
+
"types": "./dist/adapters/better-sqlite3.d.ts",
|
|
53
|
+
"import": "./dist/adapters/better-sqlite3.mjs"
|
|
54
|
+
},
|
|
55
|
+
"./adapters/sqlite-wasm": {
|
|
56
|
+
"types": "./dist/adapters/sqlite-wasm.d.ts",
|
|
57
|
+
"import": "./dist/adapters/sqlite-wasm.mjs"
|
|
58
|
+
},
|
|
59
|
+
"./package.json": "./package.json"
|
|
60
|
+
},
|
|
61
|
+
"publishConfig": {
|
|
62
|
+
"access": "public"
|
|
63
|
+
},
|
|
64
|
+
"peerDependencies": {
|
|
65
|
+
"@lunora/server": ">=1.0.0-alpha.24 <2.0.0-0",
|
|
66
|
+
"@sqlite.org/sqlite-wasm": "*",
|
|
67
|
+
"better-sqlite3": "*",
|
|
68
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
69
|
+
"sql.js": "^1.0.0"
|
|
70
|
+
},
|
|
71
|
+
"peerDependenciesMeta": {
|
|
72
|
+
"@lunora/server": {
|
|
73
|
+
"optional": true
|
|
74
|
+
},
|
|
75
|
+
"@sqlite.org/sqlite-wasm": {
|
|
76
|
+
"optional": true
|
|
77
|
+
},
|
|
78
|
+
"better-sqlite3": {
|
|
79
|
+
"optional": true
|
|
80
|
+
},
|
|
81
|
+
"react": {
|
|
82
|
+
"optional": true
|
|
83
|
+
},
|
|
84
|
+
"sql.js": {
|
|
85
|
+
"optional": true
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
"engines": {
|
|
89
|
+
"node": "^22.15.0 || >=24.11.0"
|
|
90
|
+
}
|
|
91
|
+
}
|