@lunora/replica 1.0.0-alpha.12 → 1.0.0-alpha.121
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 +55 -10
- package/dist/adapters/better-sqlite3.d.mts +2 -1
- package/dist/adapters/better-sqlite3.d.ts +2 -1
- package/dist/adapters/better-sqlite3.mjs +1 -1
- package/dist/adapters/sqlite-wasm.d.mts +3 -9
- package/dist/adapters/sqlite-wasm.d.ts +3 -9
- package/dist/adapters/sqlite-wasm.mjs +1 -1
- package/dist/adapters/sqljs.d.mts +4 -2
- package/dist/adapters/sqljs.d.ts +4 -2
- package/dist/adapters/sqljs.mjs +1 -1
- package/dist/index.d.mts +171 -67
- package/dist/index.d.ts +171 -67
- package/dist/index.mjs +1 -1
- package/dist/packem_shared/{EventEmitter-ovTsLeAj.mjs → EventEmitter-uo75adUL.mjs} +1 -1
- 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/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/fnv1a-BNN96GYb.mjs +1 -0
- package/dist/packem_shared/int64-CCVxepl4.mjs +1 -0
- package/dist/packem_shared/{isClientSeq-DSXBJskD.mjs → isClientSeq-D2Xm0_lj.mjs} +1 -1
- package/dist/packem_shared/{local-mirror.d-DTavX_y0.d.mts → local-mirror.d-DzREvGNM.d.mts} +54 -22
- package/dist/packem_shared/{local-mirror.d-CyGOpUES.d.ts → local-mirror.d-wbGXkXaE.d.ts} +54 -22
- package/dist/packem_shared/subscribeToMirror-DSn8n1IR.mjs +1 -0
- package/dist/packem_shared/{types.d-CkMkSwLJ.d.mts → types.d-BuLTPLaQ.d.mts} +0 -2
- package/dist/packem_shared/{types.d-CkMkSwLJ.d.ts → types.d-BuLTPLaQ.d.ts} +0 -2
- package/dist/packem_shared/wire-key-DfMHAtqH.mjs +1 -0
- package/dist/react.d.mts +39 -29
- package/dist/react.d.ts +39 -29
- package/dist/react.mjs +1 -1
- package/package.json +1 -1
- package/dist/packem_shared/EventLog-DmlRY_4Z.mjs +0 -1
- package/dist/packem_shared/EventLogDO-Cb-7iN9w.mjs +0 -1
- package/dist/packem_shared/EventLogDOClient-C6gA3b3u.mjs +0 -1
- package/dist/packem_shared/EventSource-B5UTlkl9.mjs +0 -1
- package/dist/packem_shared/EventsSync-pK_hg9KP.mjs +0 -1
- package/dist/packem_shared/LocalMirror-Q7cPH_rX.mjs +0 -4
- package/dist/packem_shared/MaterializerRuntime-B-I9jKDe.mjs +0 -1
- package/dist/packem_shared/SubscriptionManager-CbSjG_GA.mjs +0 -1
- package/dist/packem_shared/applyDiff-BUzddc6r.mjs +0 -1
- package/dist/packem_shared/applyDiffToDb-1M2I3BHi.mjs +0 -1
- package/dist/packem_shared/classifyChanges-BnOMcDGj.mjs +0 -1
- package/dist/packem_shared/defineEvents-CJZV8Bgi.mjs +0 -1
- package/dist/packem_shared/subscribeToMirror-Dru_AYBu.mjs +0 -1
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
|
-
|
|
119
|
+
timestamp: Date.now(),
|
|
118
120
|
changes: [{ type: "insert", data: { id: "1", title: "hello", done: false } }],
|
|
119
121
|
});
|
|
120
122
|
|
|
@@ -140,7 +142,9 @@ machine, and pushes the resulting diffs to the mirror:
|
|
|
140
142
|
import { EventsSync } from "@lunora/replica";
|
|
141
143
|
|
|
142
144
|
const sync = new EventsSync({
|
|
143
|
-
|
|
145
|
+
// `getSince` answers ONE bounded page; EventsSync keeps calling with the
|
|
146
|
+
// advanced watermark until the log is exhausted.
|
|
147
|
+
fetchEventsSince: async (seq) => (await eventLogClient.getSince(seq)).entries,
|
|
144
148
|
applyEvents: (events) => {
|
|
145
149
|
/* feed events into your state machine */
|
|
146
150
|
},
|
|
@@ -160,15 +164,23 @@ See the [EventsSync JSDoc](src/sync-events.ts) for full API details.
|
|
|
160
164
|
|
|
161
165
|
### useLocalQuery (React)
|
|
162
166
|
|
|
163
|
-
Live-updating hook that re-queries the mirror whenever a diff is applied.
|
|
164
|
-
|
|
165
|
-
|
|
167
|
+
Live-updating hook that re-queries the mirror whenever a diff is applied. It
|
|
168
|
+
returns a discriminated union — `{ data }` on success, `{ error }` when the
|
|
169
|
+
query fails (malformed SQL, or the table doesn't exist yet because no matching
|
|
170
|
+
diff has been applied). A failure is never collapsed to `undefined`, so check
|
|
171
|
+
`error` explicitly rather than reading a missing `data` as "still loading".
|
|
166
172
|
|
|
167
173
|
```tsx
|
|
168
174
|
import { useLocalQuery } from "@lunora/replica/react";
|
|
169
175
|
|
|
170
176
|
function TodoList() {
|
|
171
|
-
const todos = useLocalQuery<{ id: string; title: string; done: boolean }>(mirror, "SELECT id, title, done FROM todos WHERE done = ?", [
|
|
177
|
+
const { data: todos, error } = useLocalQuery<{ id: string; title: string; done: boolean }>(mirror, "SELECT id, title, done FROM todos WHERE done = ?", [
|
|
178
|
+
false,
|
|
179
|
+
]);
|
|
180
|
+
|
|
181
|
+
if (error) {
|
|
182
|
+
return <p>Query failed: {error.message}</p>;
|
|
183
|
+
}
|
|
172
184
|
|
|
173
185
|
if (todos === undefined) {
|
|
174
186
|
return <p>Waiting for data…</p>;
|
|
@@ -189,14 +201,47 @@ React 18+ concurrent features and Suspense-based frameworks (Next.js, Remix).
|
|
|
189
201
|
|
|
190
202
|
## EventLogDO
|
|
191
203
|
|
|
192
|
-
A Durable Object that persists the event log to DO SQLite storage
|
|
204
|
+
A Durable Object that persists the event log to DO SQLite storage.
|
|
205
|
+
|
|
206
|
+
Re-export the class from your worker entry so Wrangler can find it:
|
|
193
207
|
|
|
194
208
|
```ts
|
|
209
|
+
// src/worker.ts
|
|
195
210
|
export { EventLogDO } from "@lunora/replica";
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Then declare the binding in `wrangler.jsonc`. The DO uses `state.storage.sql`,
|
|
214
|
+
so its migration **must** use `new_sqlite_classes` — `new_classes` gives the
|
|
215
|
+
instance a key-value store with no `.sql`, and every request fails at the first
|
|
216
|
+
statement:
|
|
217
|
+
|
|
218
|
+
```jsonc
|
|
219
|
+
{
|
|
220
|
+
"durable_objects": {
|
|
221
|
+
"bindings": [{ "name": "EVENT_LOG_DO", "class_name": "EventLogDO" }],
|
|
222
|
+
},
|
|
223
|
+
"migrations": [{ "tag": "v1", "new_sqlite_classes": ["EventLogDO"] }],
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
`EventLogDOClient` wraps the DO's `fetch()` RPC surface. Its only option is
|
|
228
|
+
`fetch` — a function that dispatches a request to the instance you want, which
|
|
229
|
+
is where the namespace and instance id are chosen:
|
|
230
|
+
|
|
231
|
+
```ts
|
|
232
|
+
const client = new EventLogDOClient({
|
|
233
|
+
fetch: (request) => env.EVENT_LOG_DO.get(env.EVENT_LOG_DO.idFromName("my-app")).fetch(request),
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
// Append takes an ARRAY of events and returns them with their assigned `seq`s.
|
|
237
|
+
const [entry] = await client.append([{ type: "order:placed", payload: { orderId: "123" } }]);
|
|
196
238
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
239
|
+
// Read back by sequence number — the log is append-only and ordered, so
|
|
240
|
+
// there is no filter-by-type query. Every read is ONE bounded page (500
|
|
241
|
+
// entries by default, 1000 max): walk `cursor` while `truncated` is true.
|
|
242
|
+
const { entries, truncated, cursor } = await client.getSince(entry.seq);
|
|
243
|
+
const page = await client.getSince(0, 50);
|
|
244
|
+
const size = await client.getSize();
|
|
200
245
|
```
|
|
201
246
|
|
|
202
247
|
## Custom adapters
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { S as SqliteAdapter } from "../packem_shared/types.d-
|
|
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).
|
|
@@ -22,6 +22,7 @@ declare const createBetterSqlite3Adapter: (database: {
|
|
|
22
22
|
run: (params?: unknown[]) => {
|
|
23
23
|
lastInsertRowid: number | bigint;
|
|
24
24
|
};
|
|
25
|
+
safeIntegers: (toggle?: boolean) => unknown;
|
|
25
26
|
};
|
|
26
27
|
transaction: (function_: () => void) => () => void;
|
|
27
28
|
}) => SqliteAdapter;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { S as SqliteAdapter } from "../packem_shared/types.d-
|
|
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).
|
|
@@ -22,6 +22,7 @@ declare const createBetterSqlite3Adapter: (database: {
|
|
|
22
22
|
run: (params?: unknown[]) => {
|
|
23
23
|
lastInsertRowid: number | bigint;
|
|
24
24
|
};
|
|
25
|
+
safeIntegers: (toggle?: boolean) => unknown;
|
|
25
26
|
};
|
|
26
27
|
transaction: (function_: () => void) => () => void;
|
|
27
28
|
}) => SqliteAdapter;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const
|
|
1
|
+
import{n as c}from"../packem_shared/int64-CCVxepl4.mjs";const p=t=>({exec(r,e){e&&e.length>0?t.prepare(r).run([...e]):t.exec(r)},query(r,e){const n=t.prepare(r);n.safeIntegers(!0);const o=e&&e.length>0?n.all([...e]):n.all();return c(o)},transaction(r){t.transaction(r)()},close(){t.close()}});export{p as createBetterSqlite3Adapter};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { S as SqliteAdapter } from "../packem_shared/types.d-
|
|
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
|
|
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
|
-
* rows directly (`Record
|
|
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-
|
|
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
|
|
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
|
-
* rows directly (`Record
|
|
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
|
|
1
|
+
import{n}from"../packem_shared/int64-CCVxepl4.mjs";const x=r=>({exec(o,e){e&&e.length>0?r.exec(o,{bind:[...e]}):r.exec(o)},query(o,e){const c=r.exec(o,{bind:e&&e.length>0?[...e]:void 0,returnValue:"resultRows",rowMode:"object"});return n(c??[])},transaction(o){r.exec("BEGIN");try{o(),r.exec("COMMIT")}catch(e){throw r.exec("ROLLBACK"),e}},close(){r.close()}});export{x as createSqliteWasmAdapter};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { S as SqliteAdapter } from "../packem_shared/types.d-
|
|
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
|
|
@@ -11,7 +11,9 @@ import { S as SqliteAdapter } from "../packem_shared/types.d-CkMkSwLJ.mjs";
|
|
|
11
11
|
*/
|
|
12
12
|
declare const createSqlJsAdapter: (database: {
|
|
13
13
|
close: () => void;
|
|
14
|
-
exec: (sql: string, params?: unknown[]
|
|
14
|
+
exec: (sql: string, params?: unknown[], config?: {
|
|
15
|
+
useBigInt?: boolean;
|
|
16
|
+
}) => {
|
|
15
17
|
columns: string[];
|
|
16
18
|
values: unknown[][];
|
|
17
19
|
}[];
|
package/dist/adapters/sqljs.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { S as SqliteAdapter } from "../packem_shared/types.d-
|
|
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
|
|
@@ -11,7 +11,9 @@ import { S as SqliteAdapter } from "../packem_shared/types.d-CkMkSwLJ.js";
|
|
|
11
11
|
*/
|
|
12
12
|
declare const createSqlJsAdapter: (database: {
|
|
13
13
|
close: () => void;
|
|
14
|
-
exec: (sql: string, params?: unknown[]
|
|
14
|
+
exec: (sql: string, params?: unknown[], config?: {
|
|
15
|
+
useBigInt?: boolean;
|
|
16
|
+
}) => {
|
|
15
17
|
columns: string[];
|
|
16
18
|
values: unknown[][];
|
|
17
19
|
}[];
|
package/dist/adapters/sqljs.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const
|
|
1
|
+
import{n as i}from"../packem_shared/int64-CCVxepl4.mjs";const w=o=>({exec(e,r){r&&r.length>0?o.run(e,[...r]):o.exec(e)},query(e,r){const n=o.exec(e,r&&r.length>0?[...r]:void 0,{useBigInt:!0})[0];if(!n)return[];const u=n.columns,t=[];for(const s of n.values){const c={};for(const[l,f]of u.entries())c[f]=s[l];t.push(c)}return i(t)},transaction(e){o.run("BEGIN");try{e(),o.run("COMMIT")}catch(r){throw o.run("ROLLBACK"),r}},close(){o.close()}});export{w as createSqlJsAdapter};
|