@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.
Files changed (42) hide show
  1. package/LICENSE.md +445 -0
  2. package/README.md +239 -29
  3. package/dist/adapters/better-sqlite3.d.mts +29 -0
  4. package/dist/adapters/better-sqlite3.d.ts +29 -0
  5. package/dist/adapters/better-sqlite3.mjs +1 -0
  6. package/dist/adapters/sqlite-wasm.d.mts +30 -0
  7. package/dist/adapters/sqlite-wasm.d.ts +30 -0
  8. package/dist/adapters/sqlite-wasm.mjs +1 -0
  9. package/dist/adapters/sqljs.d.mts +22 -0
  10. package/dist/adapters/sqljs.d.ts +22 -0
  11. package/dist/adapters/sqljs.mjs +1 -0
  12. package/dist/index.d.mts +1074 -0
  13. package/dist/index.d.ts +1074 -0
  14. package/dist/index.mjs +1 -0
  15. package/dist/packem_shared/EventEmitter-uo75adUL.mjs +1 -0
  16. package/dist/packem_shared/EventLog-SuC_BKwj.mjs +1 -0
  17. package/dist/packem_shared/EventLogDO-BgUx2GGL.mjs +1 -0
  18. package/dist/packem_shared/EventLogDOClient-DWerZ3_n.mjs +1 -0
  19. package/dist/packem_shared/EventSource-Bg6zNmRn.mjs +1 -0
  20. package/dist/packem_shared/EventsSync-B3wzXm-b.mjs +1 -0
  21. package/dist/packem_shared/InMemorySnapshotStore-C4taIG5K.mjs +1 -0
  22. package/dist/packem_shared/LocalMirror-Bn22hyEB.mjs +4 -0
  23. package/dist/packem_shared/MaterializerRuntime-DFXi-aqd.mjs +1 -0
  24. package/dist/packem_shared/SubscriptionManager-AhPw3lFc.mjs +1 -0
  25. package/dist/packem_shared/applyDiff-CZAqAC8Y.mjs +1 -0
  26. package/dist/packem_shared/applyDiffToDb-CK-Dcy17.mjs +1 -0
  27. package/dist/packem_shared/classifyChanges-BBc0-770.mjs +1 -0
  28. package/dist/packem_shared/defineEvents-DHo-VK7G.mjs +1 -0
  29. package/dist/packem_shared/eventsContext-Dxow9Y7S.mjs +1 -0
  30. package/dist/packem_shared/fnv1a-BNN96GYb.mjs +1 -0
  31. package/dist/packem_shared/int64-CCVxepl4.mjs +1 -0
  32. package/dist/packem_shared/isClientSeq-D2Xm0_lj.mjs +1 -0
  33. package/dist/packem_shared/local-mirror.d-DzREvGNM.d.mts +562 -0
  34. package/dist/packem_shared/local-mirror.d-wbGXkXaE.d.ts +562 -0
  35. package/dist/packem_shared/subscribeToMirror-DSn8n1IR.mjs +1 -0
  36. package/dist/packem_shared/types.d-BuLTPLaQ.d.mts +22 -0
  37. package/dist/packem_shared/types.d-BuLTPLaQ.d.ts +22 -0
  38. package/dist/packem_shared/wire-key-DfMHAtqH.mjs +1 -0
  39. package/dist/react.d.mts +77 -0
  40. package/dist/react.d.ts +77 -0
  41. package/dist/react.mjs +1 -0
  42. package/package.json +88 -7
@@ -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 };
@@ -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.0",
4
- "description": "OIDC trusted publishing setup package for @lunora/replica",
3
+ "version": "1.0.0-alpha.100",
4
+ "description": "Local-first replica runtime + local SQLite mirror for Lunora",
5
5
  "keywords": [
6
- "oidc",
7
- "trusted-publishing",
8
- "setup"
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
+ }