@lunora/replica 1.0.0-alpha.73 → 1.0.0-alpha.75

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/README.md CHANGED
@@ -112,9 +112,11 @@ const SQL = await initSqlJs();
112
112
  const adapter = createSqlJsAdapter(new SQL.Database());
113
113
  const mirror = new LocalMirror({ db: adapter });
114
114
 
115
+ // A diff is `{ table, timestamp, changes }` (plus an optional stable `id`).
116
+ // `createTableDiff("todos", changes)` fills the timestamp and id for you.
115
117
  mirror.applyDiff({
116
118
  table: "todos",
117
- schema: "1.0",
119
+ timestamp: Date.now(),
118
120
  changes: [{ type: "insert", data: { id: "1", title: "hello", done: false } }],
119
121
  });
120
122
 
@@ -160,15 +162,23 @@ See the [EventsSync JSDoc](src/sync-events.ts) for full API details.
160
162
 
161
163
  ### useLocalQuery (React)
162
164
 
163
- Live-updating hook that re-queries the mirror whenever a diff is applied.
164
- Returns `undefined` when the query fails (e.g. table doesn't exist yet),
165
- and the result rows otherwise.
165
+ Live-updating hook that re-queries the mirror whenever a diff is applied. It
166
+ returns a discriminated union — `{ data }` on success, `{ error }` when the
167
+ query fails (malformed SQL, or the table doesn't exist yet because no matching
168
+ diff has been applied). A failure is never collapsed to `undefined`, so check
169
+ `error` explicitly rather than reading a missing `data` as "still loading".
166
170
 
167
171
  ```tsx
168
172
  import { useLocalQuery } from "@lunora/replica/react";
169
173
 
170
174
  function TodoList() {
171
- const todos = useLocalQuery<{ id: string; title: string; done: boolean }>(mirror, "SELECT id, title, done FROM todos WHERE done = ?", [false]);
175
+ const { data: todos, error } = useLocalQuery<{ id: string; title: string; done: boolean }>(mirror, "SELECT id, title, done FROM todos WHERE done = ?", [
176
+ false,
177
+ ]);
178
+
179
+ if (error) {
180
+ return <p>Query failed: {error.message}</p>;
181
+ }
172
182
 
173
183
  if (todos === undefined) {
174
184
  return <p>Waiting for data…</p>;
@@ -189,14 +199,46 @@ React 18+ concurrent features and Suspense-based frameworks (Next.js, Remix).
189
199
 
190
200
  ## EventLogDO
191
201
 
192
- A Durable Object that persists the event log to DO SQLite storage:
202
+ A Durable Object that persists the event log to DO SQLite storage.
203
+
204
+ Re-export the class from your worker entry so Wrangler can find it:
193
205
 
194
206
  ```ts
207
+ // src/worker.ts
195
208
  export { EventLogDO } from "@lunora/replica";
209
+ ```
210
+
211
+ Then declare the binding in `wrangler.jsonc`. The DO uses `state.storage.sql`,
212
+ so its migration **must** use `new_sqlite_classes` — `new_classes` gives the
213
+ instance a key-value store with no `.sql`, and every request fails at the first
214
+ statement:
215
+
216
+ ```jsonc
217
+ {
218
+ "durable_objects": {
219
+ "bindings": [{ "name": "EVENT_LOG_DO", "class_name": "EventLogDO" }],
220
+ },
221
+ "migrations": [{ "tag": "v1", "new_sqlite_classes": ["EventLogDO"] }],
222
+ }
223
+ ```
224
+
225
+ `EventLogDOClient` wraps the DO's `fetch()` RPC surface. Its only option is
226
+ `fetch` — a function that dispatches a request to the instance you want, which
227
+ is where the namespace and instance id are chosen:
228
+
229
+ ```ts
230
+ const client = new EventLogDOClient({
231
+ fetch: (request) => env.EVENT_LOG_DO.get(env.EVENT_LOG_DO.idFromName("my-app")).fetch(request),
232
+ });
233
+
234
+ // Append takes an ARRAY of events and returns them with their assigned `seq`s.
235
+ const [entry] = await client.append([{ type: "order:placed", payload: { orderId: "123" } }]);
196
236
 
197
- const client = new EventLogDOClient({ namespace: "my-app" });
198
- await client.append({ type: "order:placed", payload: { orderId: "123" } });
199
- const events = await client.query({ type: "order:placed", limit: 10 });
237
+ // Read back by sequence number — the log is append-only and ordered, so
238
+ // there is no filter-by-type query. `getSince(0)` is the whole log.
239
+ const events = await client.getSince(entry.seq);
240
+ const { entries, hasMore } = await client.getRange(0, 50);
241
+ const size = await client.getSize();
200
242
  ```
201
243
 
202
244
  ## Custom adapters
@@ -1,4 +1,4 @@
1
- import { S as SqliteAdapter } from "../packem_shared/types.d-CkMkSwLJ.mjs";
1
+ import { S as SqliteAdapter } from "../packem_shared/types.d-BuLTPLaQ.mjs";
2
2
  /**
3
3
  * Create a {@link SqliteAdapter} backed by [better-sqlite3](https://github.com/WiseLibs/better-sqlite3)
4
4
  * (a synchronous SQLite3 binding for Node.js).
@@ -1,4 +1,4 @@
1
- import { S as SqliteAdapter } from "../packem_shared/types.d-CkMkSwLJ.js";
1
+ import { S as SqliteAdapter } from "../packem_shared/types.d-BuLTPLaQ.js";
2
2
  /**
3
3
  * Create a {@link SqliteAdapter} backed by [better-sqlite3](https://github.com/WiseLibs/better-sqlite3)
4
4
  * (a synchronous SQLite3 binding for Node.js).
@@ -1 +1 @@
1
- const c=t=>({exec(e,r){r&&r.length>0?t.prepare(e).run([...r]):t.exec(e)},query(e,r){const n=t.prepare(e);return r&&r.length>0?n.all([...r]):n.all()},transaction(e){t.transaction(e)()},lastInsertRowId(){const e=t.prepare("SELECT last_insert_rowid() AS id").get();return Number(e?.id??-1)},close(){t.close()}});export{c as createBetterSqlite3Adapter};
1
+ const o=t=>({exec(r,e){e&&e.length>0?t.prepare(r).run([...e]):t.exec(r)},query(r,e){const n=t.prepare(r);return e&&e.length>0?n.all([...e]):n.all()},transaction(r){t.transaction(r)()},close(){t.close()}});export{o as createBetterSqlite3Adapter};
@@ -1,4 +1,4 @@
1
- import { S as SqliteAdapter } from "../packem_shared/types.d-CkMkSwLJ.mjs";
1
+ import { S as SqliteAdapter } from "../packem_shared/types.d-BuLTPLaQ.mjs";
2
2
  /**
3
3
  * Create a {@link SqliteAdapter} backed by the [official SQLite Wasm](https://www.npmjs.com/package/@sqlite.org/sqlite-wasm)
4
4
  * (a WebAssembly build of SQLite that runs in browsers and Node.js).
@@ -10,18 +10,13 @@ import { S as SqliteAdapter } from "../packem_shared/types.d-CkMkSwLJ.mjs";
10
10
  * IMPORTANT (REPLICA-01): the real `oo1.DB.exec()` does NOT return sql.js's
11
11
  * `{ columns, values }[]` result shape — with `rowMode: "object"` and
12
12
  * `returnValue: "resultRows"` it returns the rows directly, as
13
- * `Record<string, unknown>[]`. This adapter is written against that real
14
- * shape; `lastInsertRowId` uses the driver's `selectValue()` convenience
15
- * method (a single-scalar query helper) rather than parsing a result-row
16
- * array.
13
+ * `Record<string, unknown>[]`. This adapter is written against that real shape.
17
14
  * @param database An already-initialised `sqlite3.oo1.DB` instance.
18
15
  * @param database.close Tear down the database connection.
19
16
  * @param database.exec Execute SQL with optional bind params. With
20
17
  * `{ returnValue: "resultRows", rowMode: "object" }` it returns the matched
21
18
  * rows directly (`Record<string, unknown>[]`); otherwise (DDL/DML/BEGIN/
22
19
  * COMMIT/ROLLBACK) its return value is unused here.
23
- * @param database.selectValue Run a query and return the first column of the
24
- * first row as a single scalar — used for `SELECT last_insert_rowid()`.
25
20
  * @experimental
26
21
  */
27
22
  declare const createSqliteWasmAdapter: (database: {
@@ -31,6 +26,5 @@ declare const createSqliteWasmAdapter: (database: {
31
26
  returnValue?: "resultRows";
32
27
  rowMode?: "object";
33
28
  }) => Record<string, unknown>[] | undefined;
34
- selectValue: (sql: string, bind?: unknown[]) => unknown;
35
29
  }) => SqliteAdapter;
36
30
  export { createSqliteWasmAdapter };
@@ -1,4 +1,4 @@
1
- import { S as SqliteAdapter } from "../packem_shared/types.d-CkMkSwLJ.js";
1
+ import { S as SqliteAdapter } from "../packem_shared/types.d-BuLTPLaQ.js";
2
2
  /**
3
3
  * Create a {@link SqliteAdapter} backed by the [official SQLite Wasm](https://www.npmjs.com/package/@sqlite.org/sqlite-wasm)
4
4
  * (a WebAssembly build of SQLite that runs in browsers and Node.js).
@@ -10,18 +10,13 @@ import { S as SqliteAdapter } from "../packem_shared/types.d-CkMkSwLJ.js";
10
10
  * IMPORTANT (REPLICA-01): the real `oo1.DB.exec()` does NOT return sql.js's
11
11
  * `{ columns, values }[]` result shape — with `rowMode: "object"` and
12
12
  * `returnValue: "resultRows"` it returns the rows directly, as
13
- * `Record<string, unknown>[]`. This adapter is written against that real
14
- * shape; `lastInsertRowId` uses the driver's `selectValue()` convenience
15
- * method (a single-scalar query helper) rather than parsing a result-row
16
- * array.
13
+ * `Record<string, unknown>[]`. This adapter is written against that real shape.
17
14
  * @param database An already-initialised `sqlite3.oo1.DB` instance.
18
15
  * @param database.close Tear down the database connection.
19
16
  * @param database.exec Execute SQL with optional bind params. With
20
17
  * `{ returnValue: "resultRows", rowMode: "object" }` it returns the matched
21
18
  * rows directly (`Record<string, unknown>[]`); otherwise (DDL/DML/BEGIN/
22
19
  * COMMIT/ROLLBACK) its return value is unused here.
23
- * @param database.selectValue Run a query and return the first column of the
24
- * first row as a single scalar — used for `SELECT last_insert_rowid()`.
25
20
  * @experimental
26
21
  */
27
22
  declare const createSqliteWasmAdapter: (database: {
@@ -31,6 +26,5 @@ declare const createSqliteWasmAdapter: (database: {
31
26
  returnValue?: "resultRows";
32
27
  rowMode?: "object";
33
28
  }) => Record<string, unknown>[] | undefined;
34
- selectValue: (sql: string, bind?: unknown[]) => unknown;
35
29
  }) => SqliteAdapter;
36
30
  export { createSqliteWasmAdapter };
@@ -1 +1 @@
1
- const n=t=>({exec(e,r){r&&r.length>0?t.exec(e,{bind:[...r]}):t.exec(e)},query(e,r){return t.exec(e,{bind:r&&r.length>0?[...r]:void 0,returnValue:"resultRows",rowMode:"object"})??[]},transaction(e){t.exec("BEGIN");try{e(),t.exec("COMMIT")}catch(r){throw t.exec("ROLLBACK"),r}},lastInsertRowId(){const e=t.selectValue("SELECT last_insert_rowid()");return typeof e=="number"?e:typeof e=="bigint"?Number(e):-1},close(){t.close()}});export{n as createSqliteWasmAdapter};
1
+ const t=c=>({exec(r,e){e&&e.length>0?c.exec(r,{bind:[...e]}):c.exec(r)},query(r,e){return c.exec(r,{bind:e&&e.length>0?[...e]:void 0,returnValue:"resultRows",rowMode:"object"})??[]},transaction(r){c.exec("BEGIN");try{r(),c.exec("COMMIT")}catch(e){throw c.exec("ROLLBACK"),e}},close(){c.close()}});export{t as createSqliteWasmAdapter};
@@ -1,4 +1,4 @@
1
- import { S as SqliteAdapter } from "../packem_shared/types.d-CkMkSwLJ.mjs";
1
+ import { S as SqliteAdapter } from "../packem_shared/types.d-BuLTPLaQ.mjs";
2
2
  /**
3
3
  * Create a {@link SqliteAdapter} backed by [sql.js](https://sql.js.org)
4
4
  * (a WebAssembly build of SQLite that runs in browsers, Node, and
@@ -1,4 +1,4 @@
1
- import { S as SqliteAdapter } from "../packem_shared/types.d-CkMkSwLJ.js";
1
+ import { S as SqliteAdapter } from "../packem_shared/types.d-BuLTPLaQ.js";
2
2
  /**
3
3
  * Create a {@link SqliteAdapter} backed by [sql.js](https://sql.js.org)
4
4
  * (a WebAssembly build of SQLite that runs in browsers, Node, and
@@ -1 +1 @@
1
- const h=n=>({exec(r,e){e&&e.length>0?n.run(r,[...e]):n.exec(r)},query(r,e){const o=(e&&e.length>0?n.exec(r,[...e]):n.exec(r))[0];if(!o)return[];const l=o.columns,c=[];for(const s of o.values){const u={};for(const[i,f]of l.entries())u[f]=s[i];c.push(u)}return c},transaction(r){n.run("BEGIN");try{r(),n.run("COMMIT")}catch(e){throw n.run("ROLLBACK"),e}},lastInsertRowId(){const r=n.exec("SELECT last_insert_rowid() AS id"),e=r[0];if(r.length===0||!e||e.values.length===0)return-1;const t=e.values[0];return!t||t.length===0?-1:Number(t[0])},close(){n.close()}});export{h as createSqlJsAdapter};
1
+ const h=r=>({exec(e,o){o&&o.length>0?r.run(e,[...o]):r.exec(e)},query(e,o){const c=(o&&o.length>0?r.exec(e,[...o]):r.exec(e))[0];if(!c)return[];const u=c.columns,n=[];for(const l of c.values){const t={};for(const[s,f]of u.entries())t[f]=l[s];n.push(t)}return n},transaction(e){r.run("BEGIN");try{e(),r.run("COMMIT")}catch(o){throw r.run("ROLLBACK"),o}},close(){r.close()}});export{h as createSqlJsAdapter};
package/dist/index.d.mts CHANGED
@@ -16,9 +16,9 @@ export {
16
16
  createBetterSqlite3Adapter } from "./adapters/better-sqlite3.mjs";
17
17
  export { createSqliteWasmAdapter } from "./adapters/sqlite-wasm.mjs";
18
18
  export { createSqlJsAdapter } from "./adapters/sqljs.mjs";
19
- import { S as SqliteAdapter } from "./packem_shared/types.d-CkMkSwLJ.mjs";
20
- import { T as TableDiff, I as InputEvent, S as Seq, E as EventLogEntry, a as EventLog, A as AppendOptions, L as LocalMirror } from "./packem_shared/local-mirror.d-Cip3QuMf.mjs";
21
- export { type C as ClientSeq, type b as EventLogOptions, type c as EventLogSnapshot, type G as GlobalSeq, type d as LocalMirrorOptions, type M as MirrorTableDef, type R as RowChange, e as classifyChanges, f as createTableDiff, g as diffSize, i as isClientSeq, h as isDiffEmpty, j as isGlobalSeq, k as isInputEvent, m as mergeDiffs } from "./packem_shared/local-mirror.d-Cip3QuMf.mjs";
19
+ import { S as SqliteAdapter } from "./packem_shared/types.d-BuLTPLaQ.mjs";
20
+ import { T as TableDiff, I as InputEvent, S as Seq, E as EventLogEntry, a as EventLog, A as AppendOptions, L as LocalMirror } from "./packem_shared/local-mirror.d-N1dkxd9A.mjs";
21
+ export { type C as ClientSeq, type b as EventLogOptions, type c as EventLogSnapshot, type G as GlobalSeq, type d as LocalMirrorOptions, type M as MirrorTableDef, type R as RowChange, e as classifyChanges, f as createTableDiff, g as diffSize, i as isClientSeq, h as isDiffEmpty, j as isGlobalSeq, k as isInputEvent, m as mergeDiffs } from "./packem_shared/local-mirror.d-N1dkxd9A.mjs";
22
22
  /**
23
23
  * Apply a single {@link TableDiff} to an in-memory row map and return
24
24
  * the updated map.
package/dist/index.d.ts CHANGED
@@ -16,9 +16,9 @@ export {
16
16
  createBetterSqlite3Adapter } from "./adapters/better-sqlite3.js";
17
17
  export { createSqliteWasmAdapter } from "./adapters/sqlite-wasm.js";
18
18
  export { createSqlJsAdapter } from "./adapters/sqljs.js";
19
- import { S as SqliteAdapter } from "./packem_shared/types.d-CkMkSwLJ.js";
20
- import { T as TableDiff, I as InputEvent, S as Seq, E as EventLogEntry, a as EventLog, A as AppendOptions, L as LocalMirror } from "./packem_shared/local-mirror.d-ByrYTq4z.js";
21
- export { type C as ClientSeq, type b as EventLogOptions, type c as EventLogSnapshot, type G as GlobalSeq, type d as LocalMirrorOptions, type M as MirrorTableDef, type R as RowChange, e as classifyChanges, f as createTableDiff, g as diffSize, i as isClientSeq, h as isDiffEmpty, j as isGlobalSeq, k as isInputEvent, m as mergeDiffs } from "./packem_shared/local-mirror.d-ByrYTq4z.js";
19
+ import { S as SqliteAdapter } from "./packem_shared/types.d-BuLTPLaQ.js";
20
+ import { T as TableDiff, I as InputEvent, S as Seq, E as EventLogEntry, a as EventLog, A as AppendOptions, L as LocalMirror } from "./packem_shared/local-mirror.d-C1pwwvwS.js";
21
+ export { type C as ClientSeq, type b as EventLogOptions, type c as EventLogSnapshot, type G as GlobalSeq, type d as LocalMirrorOptions, type M as MirrorTableDef, type R as RowChange, e as classifyChanges, f as createTableDiff, g as diffSize, i as isClientSeq, h as isDiffEmpty, j as isGlobalSeq, k as isInputEvent, m as mergeDiffs } from "./packem_shared/local-mirror.d-C1pwwvwS.js";
22
22
  /**
23
23
  * Apply a single {@link TableDiff} to an in-memory row map and return
24
24
  * the updated map.
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{createBetterSqlite3Adapter as o}from"./adapters/better-sqlite3.mjs";import{createSqliteWasmAdapter as f}from"./adapters/sqlite-wasm.mjs";import{createSqlJsAdapter as i}from"./adapters/sqljs.mjs";import{applyDiff as m,applyDiffToSnapshot as n,applyDiffs as x}from"./packem_shared/applyDiff-Da160K7_.mjs";import{defineEvents as l}from"./packem_shared/defineEvents-DHo-VK7G.mjs";import{MaterializerRuntime as S,defineMaterializer as E}from"./packem_shared/MaterializerRuntime-D0HOAe24.mjs";import{applyDiffToDb as v,applyDiffsToDb as y}from"./packem_shared/applyDiffToDb-C6ek5Elp.mjs";import{EventEmitter as d}from"./packem_shared/EventEmitter-uo75adUL.mjs";import{EventLog as M}from"./packem_shared/EventLog-B1-yhArT.mjs";import{EventLogDO as u}from"./packem_shared/EventLogDO-CaZvpgJN.mjs";import{EventLogDOClient as T}from"./packem_shared/EventLogDOClient-DGDMj5L5.mjs";import{EventSource as C,UNHANDLED as h}from"./packem_shared/EventSource-BC0hKJSA.mjs";import{eventsContext as I}from"./packem_shared/eventsContext-Dxow9Y7S.mjs";import{LocalMirror as O}from"./packem_shared/LocalMirror-BIURA-He.mjs";import{isClientSeq as G,isGlobalSeq as H,isInputEvent as J}from"./packem_shared/isClientSeq-D2Xm0_lj.mjs";import{InMemorySnapshotStore as U}from"./packem_shared/InMemorySnapshotStore-C4taIG5K.mjs";import{subscribeToMirror as j}from"./packem_shared/subscribeToMirror-CX10AaP3.mjs";import{SubscriptionManager as w}from"./packem_shared/SubscriptionManager-AhPw3lFc.mjs";import{EventsSync as K}from"./packem_shared/EventsSync-DWyGGZQZ.mjs";import{classifyChanges as Q,createTableDiff as V,diffSize as X,isDiffEmpty as Y,mergeDiffs as Z}from"./packem_shared/classifyChanges-ioMfjjbU.mjs";export{d as EventEmitter,M as EventLog,u as EventLogDO,T as EventLogDOClient,C as EventSource,K as EventsSync,U as InMemorySnapshotStore,O as LocalMirror,S as MaterializerRuntime,w as SubscriptionManager,h as UNHANDLED,m as applyDiff,v as applyDiffToDb,n as applyDiffToSnapshot,x as applyDiffs,y as applyDiffsToDb,Q as classifyChanges,o as createBetterSqlite3Adapter,i as createSqlJsAdapter,f as createSqliteWasmAdapter,V as createTableDiff,l as defineEvents,E as defineMaterializer,X as diffSize,I as eventsContext,G as isClientSeq,Y as isDiffEmpty,H as isGlobalSeq,J as isInputEvent,Z as mergeDiffs,j as subscribeToMirror};
1
+ import{createBetterSqlite3Adapter as o}from"./adapters/better-sqlite3.mjs";import{createSqliteWasmAdapter as f}from"./adapters/sqlite-wasm.mjs";import{createSqlJsAdapter as i}from"./adapters/sqljs.mjs";import{applyDiff as m,applyDiffToSnapshot as n,applyDiffs as x}from"./packem_shared/applyDiff-C6A5aCk4.mjs";import{defineEvents as l}from"./packem_shared/defineEvents-DHo-VK7G.mjs";import{MaterializerRuntime as S,defineMaterializer as E}from"./packem_shared/MaterializerRuntime-D0HOAe24.mjs";import{applyDiffToDb as v,applyDiffsToDb as y}from"./packem_shared/applyDiffToDb-C6ek5Elp.mjs";import{EventEmitter as d}from"./packem_shared/EventEmitter-uo75adUL.mjs";import{EventLog as M}from"./packem_shared/EventLog-B1-yhArT.mjs";import{EventLogDO as u}from"./packem_shared/EventLogDO-CaZvpgJN.mjs";import{EventLogDOClient as T}from"./packem_shared/EventLogDOClient-DGDMj5L5.mjs";import{EventSource as C,UNHANDLED as h}from"./packem_shared/EventSource-BC0hKJSA.mjs";import{eventsContext as I}from"./packem_shared/eventsContext-Dxow9Y7S.mjs";import{LocalMirror as O}from"./packem_shared/LocalMirror-BIURA-He.mjs";import{isClientSeq as G,isGlobalSeq as H,isInputEvent as J}from"./packem_shared/isClientSeq-D2Xm0_lj.mjs";import{InMemorySnapshotStore as U}from"./packem_shared/InMemorySnapshotStore-C4taIG5K.mjs";import{subscribeToMirror as j}from"./packem_shared/subscribeToMirror-Rq100MXf.mjs";import{SubscriptionManager as w}from"./packem_shared/SubscriptionManager-AhPw3lFc.mjs";import{EventsSync as K}from"./packem_shared/EventsSync-DWyGGZQZ.mjs";import{classifyChanges as Q,createTableDiff as V,diffSize as X,isDiffEmpty as Y,mergeDiffs as Z}from"./packem_shared/classifyChanges-BDEt9_BL.mjs";export{d as EventEmitter,M as EventLog,u as EventLogDO,T as EventLogDOClient,C as EventSource,K as EventsSync,U as InMemorySnapshotStore,O as LocalMirror,S as MaterializerRuntime,w as SubscriptionManager,h as UNHANDLED,m as applyDiff,v as applyDiffToDb,n as applyDiffToSnapshot,x as applyDiffs,y as applyDiffsToDb,Q as classifyChanges,o as createBetterSqlite3Adapter,i as createSqlJsAdapter,f as createSqliteWasmAdapter,V as createTableDiff,l as defineEvents,E as defineMaterializer,X as diffSize,I as eventsContext,G as isClientSeq,Y as isDiffEmpty,H as isGlobalSeq,J as isInputEvent,Z as mergeDiffs,j as subscribeToMirror};
@@ -0,0 +1 @@
1
+ import{f as i}from"./fnv1a-SzTD85qB.mjs";const r=t=>{if(Array.isArray(t))return t.map(e=>r(e));if(t!==null&&typeof t=="object"){const e=t,s=Object.keys(e);s.sort();const n={};for(const o of s)n[o]=r(e[o]);return n}return t},p=(t,e,s)=>{const n=t.id??String(t.timestamp),o=`${t.table}::${n}::${String(e)}::${JSON.stringify(r(s))}`;return`row-${i(o)}`},c=(t,e)=>{for(const[s,n]of e.changes.entries())switch(n.type){case"delete":{t.delete(n.id);break}case"insert":{const o=n.data.id,a=typeof o=="string"||typeof o=="number"?String(o):p(e,s,n.data);t.set(a,{...n.data,id:a});break}case"update":{const o=t.get(n.id);o&&t.set(n.id,{...o,...n.data});break}}},f=(t,e)=>{const s=new Map(t);return c(s,e),s},y=(t,e)=>{const s=new Map(t);for(const n of e)c(s,n);return s},b=(t,e)=>{const s=new Map(t),n=s.get(e.table)??new Map;return s.set(e.table,f(n,e)),s};export{f as applyDiff,b as applyDiffToSnapshot,y as applyDiffs,r as canonicalizeForHash,p as deriveInsertId,i as fnv1a64Hex};
@@ -0,0 +1 @@
1
+ import{f as a}from"./fnv1a-SzTD85qB.mjs";let s=0;const c=()=>{if(typeof crypto<"u"&&typeof crypto.randomUUID=="function")return crypto.randomUUID();s+=1;const t=typeof crypto<"u"&&typeof crypto.getRandomValues=="function"?Array.from(crypto.getRandomValues(new Uint8Array(8)),n=>n.toString(16).padStart(2,"0")).join(""):Math.random().toString(16).slice(2,12);return`id_${Date.now().toString(36)}_${s.toString(36)}_${t}`},i=(t,n,o,r)=>({table:t,changes:n,timestamp:o??Date.now(),id:r??c()}),g=t=>t.changes.length===0,m=t=>t.changes.length,f=t=>{const n=[],o=[],r=[];for(const e of t.changes)e.type==="insert"?n.push(e):e.type==="update"?o.push(e):r.push(e);return{inserts:n,updates:o,deletes:r}},u=t=>{if(t.length===0)return null;const n=t[0],o=t[t.length-1],r=`merge:${a(t.map(e=>e.id??String(e.timestamp)).join("|"))}`;return i(n.table,t.flatMap(e=>e.changes),o.timestamp,r)};export{f as classifyChanges,i as createTableDiff,m as diffSize,g as isDiffEmpty,u as mergeDiffs};
@@ -0,0 +1 @@
1
+ const c=o=>o.toString(16).padStart(4,"0"),g=o=>{let t=8997,n=33826,e=40164,s=52210;for(let h=0;h<o.length;h+=1){const l=o.codePointAt(h)??0;t^=l&65535,n^=l>>>16&65535;const p=t*435,x=n*435,d=e*435+t*256,f=s*435+n*256,r=x+(p>>>16),a=d+(r>>>16),i=f+(a>>>16);t=p&65535,n=r&65535,e=a&65535,s=i&65535}return c(s)+c(e)+c(n)+c(t)};export{g as f};
@@ -1,4 +1,4 @@
1
- import { S as SqliteAdapter } from "./types.d-CkMkSwLJ.js";
1
+ import { S as SqliteAdapter } from "./types.d-BuLTPLaQ.js";
2
2
  /**
3
3
  * Row-level change kind within a TableDiff.
4
4
  *
@@ -1,4 +1,4 @@
1
- import { S as SqliteAdapter } from "./types.d-CkMkSwLJ.mjs";
1
+ import { S as SqliteAdapter } from "./types.d-BuLTPLaQ.mjs";
2
2
  /**
3
3
  * Row-level change kind within a TableDiff.
4
4
  *
@@ -0,0 +1 @@
1
+ const y=e=>`fn_${e.replaceAll(/[/:.]/g,"_")}`,w=e=>Array.isArray(e)?e:e!==null&&typeof e=="object"?[e]:[],d=(e,c,i,a,p)=>{const f=y(i.__lunoraRef);c.registerTable(f,{});let s=new Set;return e.subscribe(i,a,u=>{const b=w(u),r=new Set,t=[];for(const n of b){const l=n,o=l.id;(typeof o=="string"||typeof o=="number")&&r.add(String(o)),t.push({type:"insert",data:l})}for(const n of s)r.has(n)||t.push({type:"delete",id:n});if(t.length===0){s=r;return}c.applyDiff({table:f,changes:t,timestamp:Date.now()}),s=r},{shardKey:p})};export{d as subscribeToMirror};
@@ -11,8 +11,6 @@ interface SqliteAdapter {
11
11
  close: () => void;
12
12
  /** Execute a SQL statement (with optional bound params). */
13
13
  exec: (sql: string, params?: ReadonlyArray<unknown>) => void;
14
- /** Return the id of the last inserted row. */
15
- lastInsertRowId: () => number;
16
14
  /**
17
15
  * Execute a SQL statement and return the result rows.
18
16
  * Columns can be accessed by index or by name.
@@ -11,8 +11,6 @@ interface SqliteAdapter {
11
11
  close: () => void;
12
12
  /** Execute a SQL statement (with optional bound params). */
13
13
  exec: (sql: string, params?: ReadonlyArray<unknown>) => void;
14
- /** Return the id of the last inserted row. */
15
- lastInsertRowId: () => number;
16
14
  /**
17
15
  * Execute a SQL statement and return the result rows.
18
16
  * Columns can be accessed by index or by name.
package/dist/react.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { L as LocalMirror } from "./packem_shared/local-mirror.d-Cip3QuMf.mjs";
2
- import "./packem_shared/types.d-CkMkSwLJ.mjs";
1
+ import { L as LocalMirror } from "./packem_shared/local-mirror.d-N1dkxd9A.mjs";
2
+ import "./packem_shared/types.d-BuLTPLaQ.mjs";
3
3
  /**
4
4
  * Result of {@link useLocalQuery} — a discriminated union so callers get a
5
5
  * typed error instead of a swallowed `undefined`.
@@ -12,21 +12,6 @@ type LocalQueryResult<T> = {
12
12
  readonly data?: undefined;
13
13
  readonly error: Error;
14
14
  };
15
- /**
16
- * Options for the {@link useLocalQuery} hook.
17
- * @experimental
18
- */
19
- interface UseLocalQueryOptions {
20
- /**
21
- * Optional shard key (reserved for future use; currently unused).
22
- *
23
- * Intended for multi-mirror setups where a single app maintains multiple
24
- * SQLite databases sharded by a key (e.g. user id, tenant id). Currently
25
- * has no effect — the hook always queries the mirror passed as the first
26
- * argument.
27
- */
28
- shardKey?: string;
29
- }
30
15
  /**
31
16
  * React hook that subscribes to a local SQLite query and returns
32
17
  * live-updating results whenever the mirror applies a diff.
@@ -57,8 +42,6 @@ interface UseLocalQueryOptions {
57
42
  * engine without rewriting).
58
43
  * @param params Optional positional bound parameters matching `?`
59
44
  * placeholders in `sql`.
60
- * @param _options Optional configuration (currently unused; reserved for
61
- * future features like shard key routing).
62
45
  * @returns `{ data }` with the result rows typed via the generic parameter
63
46
  * `T`, or `{ error }` when the query fails (e.g. malformed SQL, or the
64
47
  * target table doesn't exist yet because no matching diff has been applied
@@ -90,5 +73,5 @@ interface UseLocalQueryOptions {
90
73
  * ```
91
74
  * @experimental
92
75
  */
93
- declare const useLocalQuery: <T = Record<string, unknown>>(mirror: LocalMirror, sql: string, params?: ReadonlyArray<unknown>, _options?: UseLocalQueryOptions) => LocalQueryResult<T>;
94
- export { type LocalQueryResult, type UseLocalQueryOptions, useLocalQuery };
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 CHANGED
@@ -1,5 +1,5 @@
1
- import { L as LocalMirror } from "./packem_shared/local-mirror.d-ByrYTq4z.js";
2
- import "./packem_shared/types.d-CkMkSwLJ.js";
1
+ import { L as LocalMirror } from "./packem_shared/local-mirror.d-C1pwwvwS.js";
2
+ import "./packem_shared/types.d-BuLTPLaQ.js";
3
3
  /**
4
4
  * Result of {@link useLocalQuery} — a discriminated union so callers get a
5
5
  * typed error instead of a swallowed `undefined`.
@@ -12,21 +12,6 @@ type LocalQueryResult<T> = {
12
12
  readonly data?: undefined;
13
13
  readonly error: Error;
14
14
  };
15
- /**
16
- * Options for the {@link useLocalQuery} hook.
17
- * @experimental
18
- */
19
- interface UseLocalQueryOptions {
20
- /**
21
- * Optional shard key (reserved for future use; currently unused).
22
- *
23
- * Intended for multi-mirror setups where a single app maintains multiple
24
- * SQLite databases sharded by a key (e.g. user id, tenant id). Currently
25
- * has no effect — the hook always queries the mirror passed as the first
26
- * argument.
27
- */
28
- shardKey?: string;
29
- }
30
15
  /**
31
16
  * React hook that subscribes to a local SQLite query and returns
32
17
  * live-updating results whenever the mirror applies a diff.
@@ -57,8 +42,6 @@ interface UseLocalQueryOptions {
57
42
  * engine without rewriting).
58
43
  * @param params Optional positional bound parameters matching `?`
59
44
  * placeholders in `sql`.
60
- * @param _options Optional configuration (currently unused; reserved for
61
- * future features like shard key routing).
62
45
  * @returns `{ data }` with the result rows typed via the generic parameter
63
46
  * `T`, or `{ error }` when the query fails (e.g. malformed SQL, or the
64
47
  * target table doesn't exist yet because no matching diff has been applied
@@ -90,5 +73,5 @@ interface UseLocalQueryOptions {
90
73
  * ```
91
74
  * @experimental
92
75
  */
93
- declare const useLocalQuery: <T = Record<string, unknown>>(mirror: LocalMirror, sql: string, params?: ReadonlyArray<unknown>, _options?: UseLocalQueryOptions) => LocalQueryResult<T>;
94
- export { type LocalQueryResult, type UseLocalQueryOptions, useLocalQuery };
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 CHANGED
@@ -1 +1 @@
1
- import{useSyncExternalStore as i,useMemo as y}from"react";const u=t=>JSON.stringify(t??[],(r,n)=>typeof n=="bigint"?`${n.toString()}n`:n),p=(t,r,n,g)=>{const s=e=>t.onChange(e),o=()=>t.version,c=i(s,o,o),a=u(n);return y(()=>{try{return{data:t.query(r,n)}}catch(e){return{error:e instanceof Error?e:new Error(String(e))}}},[t,c,r,a])};export{p as useLocalQuery};
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/replica",
3
- "version": "1.0.0-alpha.73",
3
+ "version": "1.0.0-alpha.75",
4
4
  "description": "Local-first replica runtime + local SQLite mirror for Lunora",
5
5
  "keywords": [
6
6
  "cloudflare",
@@ -1 +0,0 @@
1
- const a=t=>{if(Array.isArray(t))return t.map(n=>a(n));if(t!==null&&typeof t=="object"){const n=t,e=Object.keys(n);e.sort();const o={};for(const s of e)o[s]=a(n[s]);return o}return t},r=t=>t.toString(16).padStart(4,"0"),u=t=>{let n=8997,e=33826,o=40164,s=52210;for(let c=0;c<t.length;c+=1){const i=t.codePointAt(c)??0;n^=i&65535,e^=i>>>16&65535;const p=n*435,y=e*435,h=o*435+n*256,b=s*435+e*256,d=y+(p>>>16),f=h+(d>>>16),g=b+(f>>>16);n=p&65535,e=d&65535,o=f&65535,s=g&65535}return r(s)+r(o)+r(e)+r(n)},x=(t,n,e)=>{const o=t.id??String(t.timestamp),s=`${t.table}::${o}::${String(n)}::${JSON.stringify(a(e))}`;return`row-${u(s)}`},l=(t,n)=>{for(const[e,o]of n.changes.entries())switch(o.type){case"delete":{t.delete(o.id);break}case"insert":{const s=o.data.id,c=typeof s=="string"||typeof s=="number"?String(s):x(n,e,o.data);t.set(c,{...o.data,id:c});break}case"update":{const s=t.get(o.id);s&&t.set(o.id,{...s,...o.data});break}}},w=(t,n)=>{const e=new Map(t);return l(e,n),e},S=(t,n)=>{const e=new Map(t);for(const o of n)l(e,o);return e},I=(t,n)=>{const e=new Map(t),o=e.get(n.table)??new Map;return e.set(n.table,w(o,n)),e};export{w as applyDiff,I as applyDiffToSnapshot,S as applyDiffs,a as canonicalizeForHash,x as deriveInsertId,u as fnv1a64Hex};
@@ -1 +0,0 @@
1
- import{fnv1a64Hex as a}from"./applyDiff-Da160K7_.mjs";let s=0;const c=()=>{if(typeof crypto<"u"&&typeof crypto.randomUUID=="function")return crypto.randomUUID();s+=1;const t=typeof crypto<"u"&&typeof crypto.getRandomValues=="function"?Array.from(crypto.getRandomValues(new Uint8Array(8)),n=>n.toString(16).padStart(2,"0")).join(""):Math.random().toString(16).slice(2,12);return`id_${Date.now().toString(36)}_${s.toString(36)}_${t}`},i=(t,n,o,r)=>({table:t,changes:n,timestamp:o??Date.now(),id:r??c()}),g=t=>t.changes.length===0,m=t=>t.changes.length,u=t=>{const n=[],o=[],r=[];for(const e of t.changes)e.type==="insert"?n.push(e):e.type==="update"?o.push(e):r.push(e);return{inserts:n,updates:o,deletes:r}},f=t=>{if(t.length===0)return null;const n=t[0],o=t[t.length-1],r=`merge:${a(t.map(e=>e.id??String(e.timestamp)).join("|"))}`;return i(n.table,t.flatMap(e=>e.changes),o.timestamp,r)};export{u as classifyChanges,i as createTableDiff,m as diffSize,g as isDiffEmpty,f as mergeDiffs};
@@ -1 +0,0 @@
1
- const y=e=>`fn_${e.replaceAll(/[/:.]/g,"_")}`,w=e=>Array.isArray(e)?e:e!==null&&typeof e=="object"?[e]:[],d=(e,o,c,a,p)=>{const i=y(c.__lunoraRef);o.registerTable(i,{});let f=new Set;return e.subscribe(c,a,u=>{const b=w(u),n=new Set,r=[];for(const t of b){const l=t,s=l.id;(typeof s=="string"||typeof s=="number")&&n.add(String(s)),r.push({type:"insert",data:l})}for(const t of f)n.has(t)||r.push({type:"delete",id:t});f=n,r.length!==0&&o.applyDiff({table:i,changes:r,timestamp:Date.now()})},{shardKey:p})};export{d as subscribeToMirror};