@lunora/replica 1.0.0-alpha.80 → 1.0.0-alpha.81
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/dist/index.d.mts +48 -10
- package/dist/index.d.ts +48 -10
- package/dist/index.mjs +1 -1
- package/dist/packem_shared/EventLogDO-BgUx2GGL.mjs +1 -0
- package/dist/packem_shared/{LocalMirror-ZmB8SJFe.mjs → LocalMirror-DP6flo3R.mjs} +1 -1
- package/dist/packem_shared/MaterializerRuntime-DdszLF-h.mjs +1 -0
- package/dist/packem_shared/applyDiff-BaUgblCl.mjs +1 -0
- package/dist/packem_shared/applyDiffToDb-DiSnjR45.mjs +1 -0
- package/dist/packem_shared/{local-mirror.d-CtQovAv_.d.mts → local-mirror.d-CHCqFAg9.d.mts} +11 -2
- package/dist/packem_shared/{local-mirror.d-CErKffFW.d.ts → local-mirror.d-CvNV3_gk.d.ts} +11 -2
- package/dist/packem_shared/subscribeToMirror-Cv24WiWj.mjs +1 -0
- package/dist/packem_shared/wire-key-CU8KEXPo.mjs +1 -0
- package/dist/react.d.mts +1 -1
- package/dist/react.d.ts +1 -1
- package/package.json +1 -1
- package/dist/packem_shared/EventLogDO-BF9ZWc6C.mjs +0 -1
- package/dist/packem_shared/MaterializerRuntime-S-Knx6BM.mjs +0 -1
- package/dist/packem_shared/applyDiff-DRJ1gap3.mjs +0 -1
- package/dist/packem_shared/applyDiffToDb-C6ek5Elp.mjs +0 -1
- package/dist/packem_shared/subscribeToMirror-BT4oOBng.mjs +0 -1
package/dist/index.d.mts
CHANGED
|
@@ -17,8 +17,8 @@ createBetterSqlite3Adapter } from "./adapters/better-sqlite3.mjs";
|
|
|
17
17
|
export { createSqliteWasmAdapter } from "./adapters/sqlite-wasm.mjs";
|
|
18
18
|
export { createSqlJsAdapter } from "./adapters/sqljs.mjs";
|
|
19
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-
|
|
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-
|
|
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-CHCqFAg9.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-CHCqFAg9.mjs";
|
|
22
22
|
/**
|
|
23
23
|
* Apply a single {@link TableDiff} to an in-memory row map and return
|
|
24
24
|
* the updated map.
|
|
@@ -223,6 +223,12 @@ declare class EventLogDOClient {
|
|
|
223
223
|
getSize(): Promise<number>;
|
|
224
224
|
/**
|
|
225
225
|
* Return the full log state — all entries plus the next seq number.
|
|
226
|
+
*
|
|
227
|
+
* Only for a log small enough to answer as one body: the DO refuses with a
|
|
228
|
+
* 413 past its page ceiling, since serialising an unbounded log into one
|
|
229
|
+
* response is what {@link EventLogDOClient.getSince} was bounded to avoid.
|
|
230
|
+
* A catch-up walks `getSince` instead.
|
|
231
|
+
* @throws Error when the log is too large to return in one body
|
|
226
232
|
*/
|
|
227
233
|
getState(): Promise<{
|
|
228
234
|
entries: EventLogEntry[];
|
|
@@ -487,9 +493,16 @@ declare class InMemorySnapshotStore implements SnapshotStore {
|
|
|
487
493
|
*
|
|
488
494
|
* Pure functions are strongly encouraged: given the same event and state,
|
|
489
495
|
* they must produce the same next state for deterministic replay.
|
|
496
|
+
*
|
|
497
|
+
* Return {@link UNHANDLED} for an event `type` the reducer does not recognise —
|
|
498
|
+
* that, and only that, is what {@link MaterializerRuntimeOptions.unknownEventHandling}
|
|
499
|
+
* reacts to. Returning the current `state` is a legitimate, idempotent no-op for
|
|
500
|
+
* a type the reducer DOES handle; reference equality cannot tell the two apart
|
|
501
|
+
* (REPLICA-07), and reading it as "unhandled" warned about — or, under `"fail"`,
|
|
502
|
+
* threw on — an event type the reducer explicitly recognised.
|
|
490
503
|
* @experimental
|
|
491
504
|
*/
|
|
492
|
-
type MaterializerReducer<S> = (state: S, entry: EventLogEntry) => S;
|
|
505
|
+
type MaterializerReducer<S> = (state: S, entry: EventLogEntry) => S | typeof UNHANDLED;
|
|
493
506
|
/**
|
|
494
507
|
* Options for defining a single materializer.
|
|
495
508
|
* @experimental
|
|
@@ -498,7 +511,8 @@ interface MaterializerDef<S> {
|
|
|
498
511
|
/**
|
|
499
512
|
* Reducer invoked for every event in the log.
|
|
500
513
|
*
|
|
501
|
-
* Return the current state unchanged
|
|
514
|
+
* Return the current state unchanged for a recognised event with nothing to
|
|
515
|
+
* do; return {@link UNHANDLED} for a `type` this reducer does not process.
|
|
502
516
|
*/
|
|
503
517
|
handle: MaterializerReducer<S>;
|
|
504
518
|
/** Factory for the initial (empty) state. */
|
|
@@ -511,8 +525,12 @@ interface MaterializerDef<S> {
|
|
|
511
525
|
* @experimental
|
|
512
526
|
*/
|
|
513
527
|
interface Materializer<S> {
|
|
514
|
-
/**
|
|
515
|
-
|
|
528
|
+
/**
|
|
529
|
+
* Apply a single event entry through the reducer.
|
|
530
|
+
* @returns `false` when the reducer returned {@link UNHANDLED} (state left
|
|
531
|
+
* untouched), `true` otherwise.
|
|
532
|
+
*/
|
|
533
|
+
apply: (entry: EventLogEntry) => boolean;
|
|
516
534
|
readonly def: MaterializerDef<S>;
|
|
517
535
|
/** Reset to the initial state. */
|
|
518
536
|
reset: () => void;
|
|
@@ -554,7 +572,21 @@ interface MaterializerRuntimeOptions {
|
|
|
554
572
|
/** Optional snapshot store for persisting/recovering materialized state. */
|
|
555
573
|
snapshotStore?: SnapshotStore;
|
|
556
574
|
/**
|
|
557
|
-
* How to handle
|
|
575
|
+
* How to handle an event that every materializer explicitly DECLINED — one
|
|
576
|
+
* for which each reducer returned {@link UNHANDLED}.
|
|
577
|
+
*
|
|
578
|
+
* A reducer that instead falls through to `return state` for a type it does
|
|
579
|
+
* not recognise has, as far as the runtime can tell, handled the event: it
|
|
580
|
+
* changed nothing, but it did not decline. `"fail"` and `"warn"` are inert
|
|
581
|
+
* for such a reducer, and no option here can make them otherwise — write the
|
|
582
|
+
* reducer's default branch as `return UNHANDLED` if you want to hear about
|
|
583
|
+
* unknown types.
|
|
584
|
+
*
|
|
585
|
+
* A materializer whose own watermark is already past the entry does not run
|
|
586
|
+
* for it, and does not count as declining it: an entry that was already
|
|
587
|
+
* applied has already been classified, so a catch-up replaying it for a
|
|
588
|
+
* LAGGING materializer alone never re-reports it. Without that, `"fail"`
|
|
589
|
+
* aborted a catch-up on events a snapshot-recovered sibling had processed.
|
|
558
590
|
* @default "warn"
|
|
559
591
|
*/
|
|
560
592
|
unknownEventHandling?: UnknownEventHandling;
|
|
@@ -814,9 +846,15 @@ interface SubscriptionClient {
|
|
|
814
846
|
* hooks subscribed to the mirror.
|
|
815
847
|
*
|
|
816
848
|
* Rows are keyed by the table's primary key (`id` unless the table was
|
|
817
|
-
* registered with another `primaryKey`)
|
|
818
|
-
*
|
|
819
|
-
*
|
|
849
|
+
* registered with another `primaryKey`). A row without one still lands — the
|
|
850
|
+
* apply path derives a key from the ROW's own content — but it cannot be
|
|
851
|
+
* diffed: it is re-emitted on every frame, and it is never reconciled on
|
|
852
|
+
* removal because only keyed rows are recorded for the delete pass. Repeating an
|
|
853
|
+
* identical frame is therefore a no-op upsert, but each distinct content the
|
|
854
|
+
* un-keyed row ever holds leaves a row behind for the life of the mirror.
|
|
855
|
+
* **Mirror a query that selects the primary key.** An un-keyed shape (an
|
|
856
|
+
* aggregate, or a projection that drops `id`) is supported only so that one such
|
|
857
|
+
* row cannot take the rest of the frame down with it.
|
|
820
858
|
*
|
|
821
859
|
* The mirror table name is derived from the function ref alone (not `args`), so
|
|
822
860
|
* do NOT mirror two subscriptions to the same function with different `args`
|
package/dist/index.d.ts
CHANGED
|
@@ -17,8 +17,8 @@ createBetterSqlite3Adapter } from "./adapters/better-sqlite3.js";
|
|
|
17
17
|
export { createSqliteWasmAdapter } from "./adapters/sqlite-wasm.js";
|
|
18
18
|
export { createSqlJsAdapter } from "./adapters/sqljs.js";
|
|
19
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-
|
|
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-
|
|
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-CvNV3_gk.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-CvNV3_gk.js";
|
|
22
22
|
/**
|
|
23
23
|
* Apply a single {@link TableDiff} to an in-memory row map and return
|
|
24
24
|
* the updated map.
|
|
@@ -223,6 +223,12 @@ declare class EventLogDOClient {
|
|
|
223
223
|
getSize(): Promise<number>;
|
|
224
224
|
/**
|
|
225
225
|
* Return the full log state — all entries plus the next seq number.
|
|
226
|
+
*
|
|
227
|
+
* Only for a log small enough to answer as one body: the DO refuses with a
|
|
228
|
+
* 413 past its page ceiling, since serialising an unbounded log into one
|
|
229
|
+
* response is what {@link EventLogDOClient.getSince} was bounded to avoid.
|
|
230
|
+
* A catch-up walks `getSince` instead.
|
|
231
|
+
* @throws Error when the log is too large to return in one body
|
|
226
232
|
*/
|
|
227
233
|
getState(): Promise<{
|
|
228
234
|
entries: EventLogEntry[];
|
|
@@ -487,9 +493,16 @@ declare class InMemorySnapshotStore implements SnapshotStore {
|
|
|
487
493
|
*
|
|
488
494
|
* Pure functions are strongly encouraged: given the same event and state,
|
|
489
495
|
* they must produce the same next state for deterministic replay.
|
|
496
|
+
*
|
|
497
|
+
* Return {@link UNHANDLED} for an event `type` the reducer does not recognise —
|
|
498
|
+
* that, and only that, is what {@link MaterializerRuntimeOptions.unknownEventHandling}
|
|
499
|
+
* reacts to. Returning the current `state` is a legitimate, idempotent no-op for
|
|
500
|
+
* a type the reducer DOES handle; reference equality cannot tell the two apart
|
|
501
|
+
* (REPLICA-07), and reading it as "unhandled" warned about — or, under `"fail"`,
|
|
502
|
+
* threw on — an event type the reducer explicitly recognised.
|
|
490
503
|
* @experimental
|
|
491
504
|
*/
|
|
492
|
-
type MaterializerReducer<S> = (state: S, entry: EventLogEntry) => S;
|
|
505
|
+
type MaterializerReducer<S> = (state: S, entry: EventLogEntry) => S | typeof UNHANDLED;
|
|
493
506
|
/**
|
|
494
507
|
* Options for defining a single materializer.
|
|
495
508
|
* @experimental
|
|
@@ -498,7 +511,8 @@ interface MaterializerDef<S> {
|
|
|
498
511
|
/**
|
|
499
512
|
* Reducer invoked for every event in the log.
|
|
500
513
|
*
|
|
501
|
-
* Return the current state unchanged
|
|
514
|
+
* Return the current state unchanged for a recognised event with nothing to
|
|
515
|
+
* do; return {@link UNHANDLED} for a `type` this reducer does not process.
|
|
502
516
|
*/
|
|
503
517
|
handle: MaterializerReducer<S>;
|
|
504
518
|
/** Factory for the initial (empty) state. */
|
|
@@ -511,8 +525,12 @@ interface MaterializerDef<S> {
|
|
|
511
525
|
* @experimental
|
|
512
526
|
*/
|
|
513
527
|
interface Materializer<S> {
|
|
514
|
-
/**
|
|
515
|
-
|
|
528
|
+
/**
|
|
529
|
+
* Apply a single event entry through the reducer.
|
|
530
|
+
* @returns `false` when the reducer returned {@link UNHANDLED} (state left
|
|
531
|
+
* untouched), `true` otherwise.
|
|
532
|
+
*/
|
|
533
|
+
apply: (entry: EventLogEntry) => boolean;
|
|
516
534
|
readonly def: MaterializerDef<S>;
|
|
517
535
|
/** Reset to the initial state. */
|
|
518
536
|
reset: () => void;
|
|
@@ -554,7 +572,21 @@ interface MaterializerRuntimeOptions {
|
|
|
554
572
|
/** Optional snapshot store for persisting/recovering materialized state. */
|
|
555
573
|
snapshotStore?: SnapshotStore;
|
|
556
574
|
/**
|
|
557
|
-
* How to handle
|
|
575
|
+
* How to handle an event that every materializer explicitly DECLINED — one
|
|
576
|
+
* for which each reducer returned {@link UNHANDLED}.
|
|
577
|
+
*
|
|
578
|
+
* A reducer that instead falls through to `return state` for a type it does
|
|
579
|
+
* not recognise has, as far as the runtime can tell, handled the event: it
|
|
580
|
+
* changed nothing, but it did not decline. `"fail"` and `"warn"` are inert
|
|
581
|
+
* for such a reducer, and no option here can make them otherwise — write the
|
|
582
|
+
* reducer's default branch as `return UNHANDLED` if you want to hear about
|
|
583
|
+
* unknown types.
|
|
584
|
+
*
|
|
585
|
+
* A materializer whose own watermark is already past the entry does not run
|
|
586
|
+
* for it, and does not count as declining it: an entry that was already
|
|
587
|
+
* applied has already been classified, so a catch-up replaying it for a
|
|
588
|
+
* LAGGING materializer alone never re-reports it. Without that, `"fail"`
|
|
589
|
+
* aborted a catch-up on events a snapshot-recovered sibling had processed.
|
|
558
590
|
* @default "warn"
|
|
559
591
|
*/
|
|
560
592
|
unknownEventHandling?: UnknownEventHandling;
|
|
@@ -814,9 +846,15 @@ interface SubscriptionClient {
|
|
|
814
846
|
* hooks subscribed to the mirror.
|
|
815
847
|
*
|
|
816
848
|
* Rows are keyed by the table's primary key (`id` unless the table was
|
|
817
|
-
* registered with another `primaryKey`)
|
|
818
|
-
*
|
|
819
|
-
*
|
|
849
|
+
* registered with another `primaryKey`). A row without one still lands — the
|
|
850
|
+
* apply path derives a key from the ROW's own content — but it cannot be
|
|
851
|
+
* diffed: it is re-emitted on every frame, and it is never reconciled on
|
|
852
|
+
* removal because only keyed rows are recorded for the delete pass. Repeating an
|
|
853
|
+
* identical frame is therefore a no-op upsert, but each distinct content the
|
|
854
|
+
* un-keyed row ever holds leaves a row behind for the life of the mirror.
|
|
855
|
+
* **Mirror a query that selects the primary key.** An un-keyed shape (an
|
|
856
|
+
* aggregate, or a projection that drops `id`) is supported only so that one such
|
|
857
|
+
* row cannot take the rest of the frame down with it.
|
|
820
858
|
*
|
|
821
859
|
* The mirror table name is derived from the function ref alone (not `args`), so
|
|
822
860
|
* do NOT mirror two subscriptions to the same function with different `args`
|
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-
|
|
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-BaUgblCl.mjs";import{defineEvents as l}from"./packem_shared/defineEvents-DHo-VK7G.mjs";import{MaterializerRuntime as S,defineMaterializer as E}from"./packem_shared/MaterializerRuntime-DdszLF-h.mjs";import{applyDiffToDb as v,applyDiffsToDb as y}from"./packem_shared/applyDiffToDb-DiSnjR45.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-BgUx2GGL.mjs";import{EventLogDOClient as T}from"./packem_shared/EventLogDOClient-DWerZ3_n.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-DP6flo3R.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-Cv24WiWj.mjs";import{SubscriptionManager as w}from"./packem_shared/SubscriptionManager-AhPw3lFc.mjs";import{EventsSync as K}from"./packem_shared/EventsSync-B3wzXm-b.mjs";import{classifyChanges as Q,createTableDiff as V,diffSize as X,isDiffEmpty as Y,mergeDiffs as Z}from"./packem_shared/classifyChanges-BBc0-770.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
|
+
const N=Symbol("lunora.replica.event-log-do.idempotency-conflict"),_=n=>{const t=new Error(n);return Object.defineProperty(t,N,{value:!0}),t},R=n=>n instanceof Error&&N in n,y=n=>{if(Array.isArray(n))return n.map(t=>y(t));if(n!==null&&typeof n=="object"){const t=n,e=Object.keys(t);e.sort();const s={};for(const r of e)s[r]=y(t[r]);return s}return n},O=async n=>{const t=JSON.stringify(y(n)),e=new TextEncoder().encode(t),s=await crypto.subtle.digest("SHA-256",e);return[...new Uint8Array(s)].map(r=>r.toString(16).padStart(2,"0")).join("")},v=500,m=1e3,g=32768,S=4194304,E=(n,t=200)=>Response.json(n,{status:t,headers:{"content-type":"application/json"}}),p=(n,t,e)=>E({error:{code:t,message:e}},n),l=n=>typeof n.toArray=="function"?n.toArray():typeof n[Symbol.iterator]=="function"?[...n]:[],T=n=>({seq:n.seq,type:n.type,payload:JSON.parse(n.payload),timestamp:n.timestamp,clientId:n.client_id??void 0,sessionId:n.session_id??void 0,parentSeqNum:n.parent_seq??void 0}),b=n=>l(n).map(t=>T(t)),L=n=>n.reduce((t,e)=>t+e.payload.length,0),C=(n,t)=>{const e=Math.min(n.length,t);let s=0;for(let r=0;r<e;r+=1)if(s+=n[r].payload.length,s>S&&r>0)return r;return e};class u{state;env;#t=!1;constructor(t,e){this.state=t,this.env=e}async fetch(t){this.#c();const e=new URL(t.url);try{if(t.method==="POST"&&e.pathname==="/append")return await this.#e(t);if(t.method==="GET"&&e.pathname==="/since")return this.#i(e);if(t.method==="GET"&&e.pathname==="/size")return this.#a();if(t.method==="GET"&&e.pathname==="/state")return this.#o()}catch(s){return console.error("[event-log-do] request failed:",s),p(500,"INTERNAL_ERROR","internal error")}return p(404,"NOT_FOUND","unknown route")}async#e(t){let e;try{e=await t.json()}catch{return p(400,"BAD_REQUEST","invalid JSON body")}const s=u.#s(e);if(s)return p(400,"BAD_REQUEST",s);const{sql:r}=this.state.storage,{batchId:a}=e,o=()=>u.#n(r,e,a),{transaction:i}=this.state.storage;let c;try{c=typeof i=="function"?await i(o):await o()}catch(f){if(R(f))return p(409,"CONFLICT",f.message);throw f}return E({entries:c})}static async#n(t,e,s){let r;if(typeof s=="string"){r=await O(e.events);const i=u.#p(t,s);if(i){if(i.fingerprint!==r)throw _(`batchId "${s}" was already used for a different event batch`);return i.entries}}const a=Date.now(),o=[];for(const i of e.events){const d={seq:u.#d(t),type:i.type,payload:i.payload,timestamp:i.timestamp??a,clientId:i.clientId,sessionId:i.sessionId,parentSeqNum:i.parentSeqNum};u.#l(t,d),o.push(d)}if(typeof s=="string"&&r!==void 0){const i=o[0]?.seq,c=o.at(-1)?.seq;i!==void 0&&c!==void 0&&u.#u(t,s,i,c,r)}return o}static#s(t){if(!Array.isArray(t.events)||t.events.length===0)return"events[] with a non-empty string `type` required";if(t.batchId!==void 0&&(typeof t.batchId!="string"||t.batchId.length===0))return"batchId must be a non-empty string";for(const e of t.events){const s=u.#r(e);if(s!==void 0)return s}}static#r(t){if(typeof t.type!="string"||t.type.length===0)return"events[] with a non-empty string `type` required";if(t.timestamp!==void 0&&!Number.isFinite(t.timestamp))return"events[].timestamp must be a finite number";if(t.clientId!==void 0&&typeof t.clientId!="string")return"events[].clientId must be a string";if(t.sessionId!==void 0&&typeof t.sessionId!="string")return"events[].sessionId must be a string";if(t.parentSeqNum!==void 0&&(typeof t.parentSeqNum!="number"||!Number.isInteger(t.parentSeqNum)||t.parentSeqNum<0))return"events[].parentSeqNum must be a non-negative integer";if(t.payload===void 0)return"events[].payload is required";if(JSON.stringify(t.payload).length>g)return`events[].payload must serialise to at most ${String(g)} characters`}#i(t){const e=t.searchParams.get("seq"),s=e===null?0:Number(e),r=t.searchParams.get("limit"),a=r===null?v:Number(r);if(!Number.isSafeInteger(s)||s<0)return p(400,"BAD_REQUEST","invalid seq");if(!Number.isSafeInteger(a)||a<1||a>m)return p(400,"BAD_REQUEST","invalid limit");const{sql:o}=this.state.storage,i=o.exec("SELECT seq, type, payload, timestamp, client_id, session_id, parent_seq FROM events WHERE seq >= ? ORDER BY seq ASC LIMIT ?",s,a+1),c=l(i),d=C(c,a),f=d<c.length,h=c.slice(0,d).map(I=>T(I)),q=h.at(-1),A=f&&q!==void 0?{entries:h,truncated:!0,cursor:q.seq+1}:{entries:h,truncated:!1};return E(A)}#a(){const{sql:t}=this.state.storage,e=t.exec("SELECT COUNT(*) AS count FROM events"),r=l(e)[0]?.count??0;return E({count:r})}#o(){const{sql:t}=this.state.storage,e=t.exec("SELECT seq, type, payload, timestamp, client_id, session_id, parent_seq FROM events ORDER BY seq ASC LIMIT ?",m+1),s=l(e);if(s.length>m||L(s)>S)return p(413,"PAYLOAD_TOO_LARGE",`the log is larger than /state can return in one body (over ${String(m)} entries, or over ${String(S)} characters of payload) — walk /since?seq=0 with its truncated/cursor pages instead`);const a=s.map(i=>T(i)),o=(a.at(-1)?.seq??-1)+1;return E({entries:a,nextSeq:o})}#c(){if(this.#t)return;const{sql:t}=this.state.storage;t.exec("CREATE TABLE IF NOT EXISTS events (seq INTEGER PRIMARY KEY AUTOINCREMENT, type TEXT NOT NULL, payload TEXT NOT NULL, timestamp INTEGER NOT NULL, client_id TEXT, session_id TEXT, parent_seq INTEGER)"),t.exec("CREATE TABLE IF NOT EXISTS event_batches (batch_id TEXT PRIMARY KEY, first_seq INTEGER NOT NULL, last_seq INTEGER NOT NULL, fingerprint TEXT NOT NULL)"),this.#t=!0}static#p(t,e){const s=t.exec("SELECT first_seq, last_seq, fingerprint FROM event_batches WHERE batch_id = ?",e),a=l(s)[0];if(!a)return;const o=t.exec("SELECT seq, type, payload, timestamp, client_id, session_id, parent_seq FROM events WHERE seq >= ? AND seq <= ? ORDER BY seq ASC",a.first_seq,a.last_seq);return{entries:b(o),fingerprint:a.fingerprint}}static#u(t,e,s,r,a){t.exec("INSERT INTO event_batches (batch_id, first_seq, last_seq, fingerprint) VALUES (?, ?, ?, ?)",e,s,r,a)}static#d(t){const e=t.exec("SELECT COALESCE(MAX(seq), -1) + 1 AS next_seq FROM events");return l(e)[0]?.next_seq??0}static#l(t,e){const s=typeof e.parentSeqNum=="number"?e.parentSeqNum:null;t.exec("INSERT INTO events (seq, type, payload, timestamp, client_id, session_id, parent_seq) VALUES (?, ?, ?, ?, ?, ?, ?)",e.seq,e.type,JSON.stringify(e.payload),e.timestamp,e.clientId??null,e.sessionId??null,s)}}export{u as EventLogDO};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{createSqlJsAdapter as y}from"../adapters/sqljs.mjs";import{applyDiffToDb as m,escapeIdentifier as a}from"./applyDiffToDb-
|
|
1
|
+
import{createSqlJsAdapter as y}from"../adapters/sqljs.mjs";import{applyDiffToDb as m,escapeIdentifier as a}from"./applyDiffToDb-DiSnjR45.mjs";import{EventLog as b}from"./EventLog-B1-yhArT.mjs";const A=1e3,l="__lunora_mirror_meta",R=o=>{o.exec(`CREATE TABLE IF NOT EXISTS ${l} (
|
|
2
2
|
key TEXT PRIMARY KEY NOT NULL,
|
|
3
3
|
value TEXT NOT NULL
|
|
4
4
|
)`)},u="schema_version",f=3,h=o=>typeof o=="bigint"||typeof o=="boolean"?"INTEGER":typeof o=="number"?Number.isInteger(o)?"INTEGER":"REAL":"TEXT";class E{#e;#t;#s;#n=new Set;#i=0;static create(e,s){const t=y(e);return new E({db:t,tables:s?.tables})}constructor(e){this.#e=e.db,this.#t={...e.tables},this.#s=new b({maxEntries:e.maxEventLogEntries??A}),R(this.#e),this.#o()}onChange(e){return this.#n.add(e),()=>{this.#n.delete(e)}}get eventLog(){return this.#s}get db(){return this.#e}get version(){return this.#i}applyDiff(e){e.changes.length!==0&&(this.#l(e),m(this.#e,e,this.primaryKeyOf(e.table)),this.#s.append("table-diff",e,[e]),this.#r())}query(e,s){return this.#e.query(e,s)}clearData(){const e=this.#a();this.#e.transaction(()=>{for(const{name:s}of e)this.#e.exec(`DELETE FROM ${a(s)}`)}),this.#r()}#r(){this.#i+=1;for(const e of this.#n)try{e()}catch{}}close(){this.#e.close(),this.#s.clear(),this.#n.clear()}registerTable(e,s){this.#t[e]={...this.#t[e],...s}}primaryKeyOf(e){return this.#t[e]?.primaryKey??"id"}get mirroredTables(){return Object.keys(this.#t)}#a(){return this.#e.query(String.raw`SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE '\_\_lunora\_%' ESCAPE '\' AND name NOT LIKE 'sqlite\_%' ESCAPE '\'`)}#o(){if(this.#e.query(`SELECT key, value FROM ${l}`).find(n=>n.key===u)?.value===String(f))return;const t=this.#a();this.#e.transaction(()=>{for(const{name:n}of t)this.#e.exec(`DROP TABLE IF EXISTS ${a(n)}`);this.#e.exec(`INSERT OR REPLACE INTO ${l} (key, value) VALUES (?, ?)`,[u,String(f)])})}static#c(e,s){const t=new Set;for(const n of e.changes)if(n.type!=="delete")for(const c of Object.keys(n.data))c!==s&&t.add(c);return t}static#E(e,s,t){const n=new Map;for(const c of e.changes)if(!(c.type==="delete"||n.size===t.size))for(const r of t){if(r===s||n.has(r))continue;const i=c.data[r];i!=null&&n.set(r,h(i))}return n}static#h(e,s){for(const t of e.changes){const n=t.type==="delete"?t.id:t.data[s];if(n!=null)return h(n);if(t.type==="update")return h(t.id)}return"TEXT"}#l(e){const s=this.primaryKeyOf(e.table),t=E.#c(e,s),n=E.#E(e,s,t);if(this.#e.query("SELECT name FROM sqlite_master WHERE type='table' AND name=?",[e.table]).length===0){const r=E.#h(e,s);let i=`${a(s)} ${r==="INTEGER"?"INT":r} PRIMARY KEY NOT NULL`;for(const T of t)i+=`, ${a(T)} ${n.get(T)??"TEXT"}`;this.#e.exec(`CREATE TABLE IF NOT EXISTS ${a(e.table)} (${i})`)}else if(t.size>0){const r=new Set(this.#e.query(`PRAGMA table_info(${a(e.table)})`).map(i=>i.name));for(const i of t)r.has(i)||this.#e.exec(`ALTER TABLE ${a(e.table)} ADD COLUMN ${a(i)} ${n.get(i)??"TEXT"}`)}}}export{E as LocalMirror};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{UNHANDLED as o}from"./EventSource-BC0hKJSA.mjs";const h=1e3,p=s=>{let e=s.initial();return{def:s,get state(){return Object.freeze(e)},setState(t){e=t},apply(t){const n=s.handle(e,t);return n===o?!1:(e=n,!0)},reset(){e=s.initial()}}};class c{#e;#n;#i;#r;#t;constructor(e,t={}){this.#e=[...e],this.#t=this.#e.map(()=>0),this.#n=t.snapshotStore,this.#i=t.doClient,this.#r=t.unknownEventHandling??"warn"}get appliedSeq(){return this.#t.length>0?Math.min(...this.#t):0}applyEntries(e){let t=0;for(const n of e){const{advancedIndices:r,anyHandled:i}=this.#a(n);if(r.length!==0){!i&&r.length===this.#e.length&&this.#o(n);for(const a of r)this.#t[a]=n.seq+1;t+=1}}return t}#a(e){const t=[];let n=!1;for(const[r,i]of this.#e.entries())e.seq<(this.#t[r]??0)||(i.apply(e)&&(n=!0),t.push(r));return{advancedIndices:t,anyHandled:n}}#o(e){const t=this.#r;if(typeof t=="function"){t(e);return}switch(t){case"ignore":return;case"fail":throw new Error(`MaterializerRuntime: unhandled event type "${e.type}" (seq ${String(e.seq)}). Configure \`unknownEventHandling\` to handle this event or change the strategy.`);default:console.warn(`[MaterializerRuntime] unhandled event type "${e.type}" (seq ${String(e.seq)}). The event was skipped. Configure \`unknownEventHandling\` if this is expected.`)}}async recoverFromSnapshots(){if(!this.#n)return 0;let e=0;for(const[t,n]of this.#e.entries()){const r=await this.#n.load(n.def.name);if(r!==null&&typeof r=="object"){const i=r;if(Number.isSafeInteger(i.appliedSeq)&&i.appliedSeq>=0&&i.state!==void 0){const a=i.appliedSeq;n.setState(i.state),this.#t[t]=a,a>e&&(e=a)}}}return e}async persistSnapshots(){if(this.#n)for(const[e,t]of this.#e.entries())await this.#n.save(t.def.name,{appliedSeq:this.#t[e]??0,state:t.state})}async initialize(){return this.#i?(await this.recoverFromSnapshots(),this.#s()):0}async#s(){const e=this.#i;if(!e)return 0;let t=this.appliedSeq,n=0;for(let r=0;r<h;r+=1){const i=await e.getSince(t);if(n+=this.applyEntries(i.entries),!i.truncated||i.cursor===void 0||i.cursor<=t)return n;t=i.cursor}return n}async appendEvent(e){if(!this.#i)throw new Error("MaterializerRuntime.appendEvent requires a doClient — pass one in the constructor options.");const n=(await this.#i.append([e]))[0];if(!n)throw new Error("MaterializerRuntime.appendEvent: DO returned empty result");return this.#e.length>0&&this.appliedSeq<n.seq&&(await this.#s(),this.appliedSeq<n.seq)||this.applyEntries([n]),n}reset(){for(const[e,t]of this.#e.entries())this.#t[e]=0,t.reset()}get materializers(){return this.#e}}export{c as MaterializerRuntime,p as defineMaterializer};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{f as r}from"./fnv1a-BNN96GYb.mjs";import{s as p}from"./wire-key-CU8KEXPo.mjs";const c=(e,n)=>`row-${r(`${e.table}::${p(n)}`)}`,o=(e,n)=>{for(const t of n.changes)switch(t.type){case"delete":{e.delete(t.id);break}case"insert":{const a=t.data.id,s=typeof a=="bigint"||typeof a=="number"||typeof a=="string"?String(a):c(n,t.data);e.set(s,{...t.data,id:s});break}case"update":{const a=e.get(t.id);a&&e.set(t.id,{...a,...t.data});break}}},i=(e,n)=>{const t=new Map(e);return o(t,n),t},l=(e,n)=>{const t=new Map(e);for(const a of n)o(t,a);return t},b=(e,n)=>{const t=new Map(e),a=t.get(n.table)??new Map;return t.set(n.table,i(a,n)),t};export{i as applyDiff,b as applyDiffToSnapshot,l as applyDiffs,c as deriveInsertId,r as fnv1a64Hex};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{deriveInsertId as $}from"./applyDiff-BaUgblCl.mjs";const p=t=>`\`${t.replaceAll("`","``")}\``,D=t=>t.map(n=>`${p(n)} = ?`).join(", "),h=t=>`(${t.map(n=>p(n)).join(", ")})`,T=t=>`(${Array.from({length:t}).fill("?").join(", ")})`,f=t=>t==null?null:typeof t=="number"||typeof t=="bigint"||typeof t=="string"?t:typeof t=="boolean"?t?1:0:t instanceof Uint8Array?t:typeof t=="object"?JSON.stringify(t):String(t),g=(t,n,o)=>{if(n.changes.length===0)return;const a=p(n.table),l=p(o);for(const i of n.changes)switch(i.type){case"delete":{t.exec(`DELETE FROM ${a} WHERE ${l} = ?`,[f(i.id)]);break}case"insert":{const{data:e}=i;if(Object.keys(e).length===0)continue;const s=e[o],c=typeof s=="bigint"||typeof s=="number"||typeof s=="string"?e:{...e,[o]:$(n,e)},r=Object.keys(c),y=`INSERT OR REPLACE INTO ${a} ${h(r)} VALUES ${T(r.length)}`,b=r.map(E=>f(c[E]));t.exec(y,b);break}case"update":{const{data:e}=i,s=Object.keys(e);if(s.length===0)continue;const c=`UPDATE ${a} SET ${D(s)} WHERE ${l} = ?`,r=[...s.map(y=>f(e[y])),f(i.id)];t.exec(c,r);break}}},d=(t,n,o)=>{t.transaction(()=>{g(t,n,o??"id")})},j=(t,n)=>{n.length!==0&&t.transaction(()=>{for(const o of n)g(t,o,"id")})};export{d as applyDiffToDb,j as applyDiffsToDb,p as escapeIdentifier,f as normalizeBindValue};
|
|
@@ -507,8 +507,17 @@ declare class LocalMirror {
|
|
|
507
507
|
*/
|
|
508
508
|
query<T = Record<string, unknown>>(sql: string, params?: ReadonlyArray<unknown>): T[];
|
|
509
509
|
/**
|
|
510
|
-
* Delete every row from
|
|
511
|
-
* and schema). Useful when re-syncing from scratch.
|
|
510
|
+
* Delete every row from every data table in the adapter's database
|
|
511
|
+
* (preserves the event log and schema). Useful when re-syncing from scratch.
|
|
512
|
+
*
|
|
513
|
+
* **The mirror owns its database.** The sweep is `sqlite_master` minus the
|
|
514
|
+
* reserved prefixes, NOT {@link LocalMirror.mirroredTables} — a table this
|
|
515
|
+
* mirror never registered is cleared too, and `#reconcileSchemaVersion`
|
|
516
|
+
* DROPs on the same list. It cannot be narrowed to the registered set: that
|
|
517
|
+
* runs from the constructor, before any `applyDiff` has re-registered the
|
|
518
|
+
* tables a previous session persisted, and those are exactly the
|
|
519
|
+
* stale-schema tables it exists to drop. So hand the adapter a database
|
|
520
|
+
* dedicated to the mirror, never one that also holds your own tables.
|
|
512
521
|
*
|
|
513
522
|
* Notifies `onChange` subscribers and bumps {@link LocalMirror.version}
|
|
514
523
|
* (REPLICA-09) even though nothing is appended to the event log — a
|
|
@@ -507,8 +507,17 @@ declare class LocalMirror {
|
|
|
507
507
|
*/
|
|
508
508
|
query<T = Record<string, unknown>>(sql: string, params?: ReadonlyArray<unknown>): T[];
|
|
509
509
|
/**
|
|
510
|
-
* Delete every row from
|
|
511
|
-
* and schema). Useful when re-syncing from scratch.
|
|
510
|
+
* Delete every row from every data table in the adapter's database
|
|
511
|
+
* (preserves the event log and schema). Useful when re-syncing from scratch.
|
|
512
|
+
*
|
|
513
|
+
* **The mirror owns its database.** The sweep is `sqlite_master` minus the
|
|
514
|
+
* reserved prefixes, NOT {@link LocalMirror.mirroredTables} — a table this
|
|
515
|
+
* mirror never registered is cleared too, and `#reconcileSchemaVersion`
|
|
516
|
+
* DROPs on the same list. It cannot be narrowed to the registered set: that
|
|
517
|
+
* runs from the constructor, before any `applyDiff` has re-registered the
|
|
518
|
+
* tables a previous session persisted, and those are exactly the
|
|
519
|
+
* stale-schema tables it exists to drop. So hand the adapter a database
|
|
520
|
+
* dedicated to the mirror, never one that also holds your own tables.
|
|
512
521
|
*
|
|
513
522
|
* Notifies `onChange` subscribers and bumps {@link LocalMirror.version}
|
|
514
523
|
* (REPLICA-09) even though nothing is appended to the event log — a
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{s as w}from"./wire-key-CU8KEXPo.mjs";const h=e=>`fn_${e.replaceAll(/[/:.]/g,"_")}`,m=e=>Array.isArray(e)?e:e!==null&&typeof e=="object"?[e]:[],M=(e,c,a,y,b)=>{const i=h(a.__lunoraRef);c.registerTable(i,{});const u=c.primaryKeyOf(i);let p=new Map;return e.subscribe(a,y,d=>{const r=new Map,f=new Map,o=[];for(const t of m(d)){const n=t,s=n[u];if(typeof s!="string"&&typeof s!="number"&&typeof s!="bigint"){o.push({type:"insert",data:n});continue}const l=String(s),g=w(n);r.set(l,g),f.set(l,n)}for(const[t,n]of r)p.get(t)!==n&&o.push({data:f.get(t),type:"insert"});for(const t of p.keys())r.has(t)||o.push({type:"delete",id:t});o.length>0&&c.applyDiff({table:i,changes:o,timestamp:Date.now()}),p=r},{shardKey:b})};export{M as subscribeToMirror};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const d=/["\\\u0000-\u001F\uD800-\uDFFF]/,p=r=>d.test(r)?JSON.stringify(r):`"${r}"`,b=r=>{if(r===void 0)return"null";if(typeof r=="bigint")throw new TypeError("stableStringify: cannot use a bigint in a stable JSON cache key — pass it as a string, or use stableWireKey");if(typeof r=="number"){if(Number.isNaN(r))return"nan";if(r===1/0)return"inf";if(r===-1/0)return"-inf";if(Object.is(r,-0))return"-0"}if(typeof r=="string")return p(r);if(r===null||typeof r!="object")return JSON.stringify(r);if(Array.isArray(r)){let n="[";for(let i=0;i<r.length;i++)i>0&&(n+=","),n+=b(r[i]);return n+"]"}const e=Object.getPrototypeOf(r);if(e!==null&&e!==Object.prototype){const n=r.constructor?.name??"value";throw new TypeError(`stableStringify: cannot use a ${n} in a stable JSON cache key — only plain objects, arrays, and JSON primitives are supported (wire-typed values key via stableWireKey)`)}const y=r,s=Object.keys(y).sort();let f="{",t=!0;for(const n of s){const i=y[n];i!==void 0&&(t?t=!1:f+=",",f+=p(n),f+=":",f+=b(i))}return f+"}"},u=r=>{let e="";for(let s=0;s<r.length;s+=32768)e+=String.fromCharCode(...r.subarray(s,s+32768));return btoa(e)},o="$lunora.wire$";const g="__proto__",m=r=>{if(r===null||typeof r!="object")return!1;const e=Object.getPrototypeOf(r);return e===null||e===Object.prototype},c=(r,e=0)=>{if(e>64)throw new RangeError("wire-codec: value nesting exceeds the 64-level limit");if(r===void 0)return[o,"undefined"];if(r===null)return null;const y=typeof r;if(y==="bigint")return[o,"bigint",r.toString()];if(y==="number"){const t=r;return Number.isNaN(t)?[o,"nan"]:t===1/0?[o,"inf"]:t===-1/0?[o,"-inf"]:t}if(y!=="object")return r;if(r instanceof Date)return[o,"date",c(r.getTime(),e+1)];if(r instanceof Error){const t=r,n={};for(const a of Object.keys(t))t[a]!==void 0&&(n[a]=c(t[a],e+1));const i=[o,"error",t.name,t.message,n];return t.cause!==void 0&&i.push(c(t.cause,e+1)),i}if(r instanceof URL)return[o,"url",r.href];if(r instanceof Map)return[o,"map",[...r.entries()].map(([t,n])=>[c(t,e+1),c(n,e+1)])];if(r instanceof Set)return[o,"set",[...r].map(t=>c(t,e+1))];if(r instanceof ArrayBuffer)return[o,"bytes",u(new Uint8Array(r)),"ArrayBuffer"];if(ArrayBuffer.isView(r)){const t=r,n=t.constructor.name,i=new Uint8Array(t.buffer,t.byteOffset,t.byteLength);return n==="Uint8Array"?[o,"bytes",u(i)]:[o,"bytes",u(i),n]}if(Array.isArray(r)){const t=r.map(n=>c(n,e+1));return t.length>0&&t[0]===o?[o,"arr",t]:t}if(!m(r)){const t=r.constructor?.name??"value";throw new TypeError(`wire-codec: cannot encode a ${t} over the Lunora wire — only plain objects, arrays, and the supported built-ins (Date, Error, URL, Map, Set, ArrayBuffer/typed arrays, bigint) round-trip`)}const s=r,f={};for(const t of Object.keys(s)){const n=s[t];if(n===void 0)continue;const i=c(n,e+1);t===g?Object.defineProperty(f,t,{configurable:!0,enumerable:!0,value:i,writable:!0}):f[t]=i}return f},w=r=>b(c(r));export{w as s};
|
package/dist/react.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { L as LocalMirror } from "./packem_shared/local-mirror.d-
|
|
1
|
+
import { L as LocalMirror } from "./packem_shared/local-mirror.d-CHCqFAg9.mjs";
|
|
2
2
|
import "./packem_shared/types.d-BuLTPLaQ.mjs";
|
|
3
3
|
/**
|
|
4
4
|
* Result of {@link useLocalQuery} — a discriminated union so callers get a
|
package/dist/react.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { L as LocalMirror } from "./packem_shared/local-mirror.d-
|
|
1
|
+
import { L as LocalMirror } from "./packem_shared/local-mirror.d-CvNV3_gk.js";
|
|
2
2
|
import "./packem_shared/types.d-BuLTPLaQ.js";
|
|
3
3
|
/**
|
|
4
4
|
* Result of {@link useLocalQuery} — a discriminated union so callers get a
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const y=Symbol("lunora.replica.event-log-do.idempotency-conflict"),q=n=>{const t=new Error(n);return Object.defineProperty(t,y,{value:!0}),t},N=n=>n instanceof Error&&y in n,T=n=>{if(Array.isArray(n))return n.map(t=>T(t));if(n!==null&&typeof n=="object"){const t=n,e=Object.keys(t);e.sort();const s={};for(const r of e)s[r]=T(t[r]);return s}return n},I=async n=>{const t=JSON.stringify(T(n)),e=new TextEncoder().encode(t),s=await crypto.subtle.digest("SHA-256",e);return[...new Uint8Array(s)].map(r=>r.toString(16).padStart(2,"0")).join("")},g=500,A=1e3,f=(n,t=200)=>Response.json(n,{status:t,headers:{"content-type":"application/json"}}),d=(n,t,e)=>f({error:{code:t,message:e}},n),m=n=>typeof n.toArray=="function"?n.toArray():typeof n[Symbol.iterator]=="function"?[...n]:[],E=n=>m(n).map(e=>({seq:e.seq,type:e.type,payload:JSON.parse(e.payload),timestamp:e.timestamp,clientId:e.client_id??void 0,sessionId:e.session_id??void 0,parentSeqNum:e.parent_seq??void 0}));class p{state;env;#t=!1;constructor(t,e){this.state=t,this.env=e}async fetch(t){this.#c();const e=new URL(t.url);try{if(t.method==="POST"&&e.pathname==="/append")return await this.#e(t);if(t.method==="GET"&&e.pathname==="/since")return this.#i(e);if(t.method==="GET"&&e.pathname==="/size")return this.#o();if(t.method==="GET"&&e.pathname==="/state")return this.#a()}catch(s){return console.error("[event-log-do] request failed:",s),d(500,"INTERNAL_ERROR","internal error")}return d(404,"NOT_FOUND","unknown route")}async#e(t){let e;try{e=await t.json()}catch{return d(400,"BAD_REQUEST","invalid JSON body")}const s=p.#n(e);if(s)return d(400,"BAD_REQUEST",s);const{sql:r}=this.state.storage,{batchId:o}=e,a=()=>p.#s(r,e,o),{transaction:i}=this.state.storage;let c;try{c=typeof i=="function"?await i(a):await a()}catch(u){if(N(u))return d(409,"CONFLICT",u.message);throw u}return f({entries:c})}static async#s(t,e,s){let r;if(typeof s=="string"){r=await I(e.events);const i=p.#p(t,s);if(i){if(i.fingerprint!==r)throw q(`batchId "${s}" was already used for a different event batch`);return i.entries}}const o=Date.now(),a=[];for(const i of e.events){const l={seq:p.#d(t),type:i.type,payload:i.payload,timestamp:i.timestamp??o,clientId:i.clientId,sessionId:i.sessionId,parentSeqNum:i.parentSeqNum};p.#l(t,l),a.push(l)}if(typeof s=="string"&&r!==void 0){const i=a[0]?.seq,c=a.at(-1)?.seq;i!==void 0&&c!==void 0&&p.#u(t,s,i,c,r)}return a}static#n(t){if(!Array.isArray(t.events)||t.events.length===0)return"events[] with a non-empty string `type` required";if(t.batchId!==void 0&&(typeof t.batchId!="string"||t.batchId.length===0))return"batchId must be a non-empty string";for(const e of t.events){const s=p.#r(e);if(s!==void 0)return s}}static#r(t){if(typeof t.type!="string"||t.type.length===0)return"events[] with a non-empty string `type` required";if(t.timestamp!==void 0&&!Number.isFinite(t.timestamp))return"events[].timestamp must be a finite number";if(t.clientId!==void 0&&typeof t.clientId!="string")return"events[].clientId must be a string";if(t.sessionId!==void 0&&typeof t.sessionId!="string")return"events[].sessionId must be a string";if(t.parentSeqNum!==void 0&&(typeof t.parentSeqNum!="number"||!Number.isInteger(t.parentSeqNum)||t.parentSeqNum<0))return"events[].parentSeqNum must be a non-negative integer"}#i(t){const e=t.searchParams.get("seq"),s=e===null?0:Number(e),r=t.searchParams.get("limit"),o=r===null?g:Number(r);if(!Number.isSafeInteger(s)||s<0)return d(400,"BAD_REQUEST","invalid seq");if(!Number.isSafeInteger(o)||o<1||o>A)return d(400,"BAD_REQUEST","invalid limit");const{sql:a}=this.state.storage,i=a.exec("SELECT seq, type, payload, timestamp, client_id, session_id, parent_seq FROM events WHERE seq >= ? ORDER BY seq ASC LIMIT ?",s,o+1),c=E(i),l=c.length>o,u=l?c.slice(0,o):c,h=u.at(-1),S=l&&h!==void 0?{entries:u,truncated:!0,cursor:h.seq+1}:{entries:u,truncated:!1};return f(S)}#o(){const{sql:t}=this.state.storage,e=t.exec("SELECT COUNT(*) AS count FROM events"),r=m(e)[0]?.count??0;return f({count:r})}#a(){const{sql:t}=this.state.storage,e=t.exec("SELECT seq, type, payload, timestamp, client_id, session_id, parent_seq FROM events ORDER BY seq ASC"),s=E(e),r=(s.at(-1)?.seq??-1)+1;return f({entries:s,nextSeq:r})}#c(){if(this.#t)return;const{sql:t}=this.state.storage;t.exec("CREATE TABLE IF NOT EXISTS events (seq INTEGER PRIMARY KEY AUTOINCREMENT, type TEXT NOT NULL, payload TEXT NOT NULL, timestamp INTEGER NOT NULL, client_id TEXT, session_id TEXT, parent_seq INTEGER)"),t.exec("CREATE TABLE IF NOT EXISTS event_batches (batch_id TEXT PRIMARY KEY, first_seq INTEGER NOT NULL, last_seq INTEGER NOT NULL, fingerprint TEXT NOT NULL)"),this.#t=!0}static#p(t,e){const s=t.exec("SELECT first_seq, last_seq, fingerprint FROM event_batches WHERE batch_id = ?",e),o=m(s)[0];if(!o)return;const a=t.exec("SELECT seq, type, payload, timestamp, client_id, session_id, parent_seq FROM events WHERE seq >= ? AND seq <= ? ORDER BY seq ASC",o.first_seq,o.last_seq);return{entries:E(a),fingerprint:o.fingerprint}}static#u(t,e,s,r,o){t.exec("INSERT INTO event_batches (batch_id, first_seq, last_seq, fingerprint) VALUES (?, ?, ?, ?)",e,s,r,o)}static#d(t){const e=t.exec("SELECT COALESCE(MAX(seq), -1) + 1 AS next_seq FROM events");return m(e)[0]?.next_seq??0}static#l(t,e){const s=typeof e.parentSeqNum=="number"?e.parentSeqNum:null;t.exec("INSERT INTO events (seq, type, payload, timestamp, client_id, session_id, parent_seq) VALUES (?, ?, ?, ?, ?, ?, ?)",e.seq,e.type,JSON.stringify(e.payload),e.timestamp,e.clientId??null,e.sessionId??null,s)}}export{p as EventLogDO};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const c=a=>{let e=a.initial();return{def:a,get state(){return Object.freeze(e)},setState(t){e=t},apply(t){e=a.handle(e,t)},reset(){e=a.initial()}}};class u{#e;#i;#n;#s;#t;constructor(e,t={}){this.#e=[...e],this.#t=this.#e.map(()=>0),this.#i=t.snapshotStore,this.#n=t.doClient,this.#s=t.unknownEventHandling??"warn"}get appliedSeq(){return this.#t.length>0?Math.min(...this.#t):0}applyEntries(e){let t=0;for(const i of e){let s=!1,n=!1;const r=[];for(const[o,p]of this.#e.entries()){const h=this.#t[o]??0;if(i.seq<h)continue;const l=p.state;p.apply(i),s=!0,p.state!==l&&(n=!0),r.push(o)}if(s){n||this.#a(i);for(const o of r)this.#t[o]=i.seq+1;t+=1}}return t}#a(e){const t=this.#s;if(typeof t=="function"){t(e);return}switch(t){case"ignore":return;case"fail":throw new Error(`MaterializerRuntime: unhandled event type "${e.type}" (seq ${String(e.seq)}). Configure \`unknownEventHandling\` to handle this event or change the strategy.`);default:console.warn(`[MaterializerRuntime] unhandled event type "${e.type}" (seq ${String(e.seq)}). The event was skipped. Configure \`unknownEventHandling\` if this is expected.`)}}async recoverFromSnapshots(){if(!this.#i)return 0;let e=0;for(const[t,i]of this.#e.entries()){const s=await this.#i.load(i.def.name);if(s!==null&&typeof s=="object"){const n=s;if(Number.isSafeInteger(n.appliedSeq)&&n.appliedSeq>=0&&n.state!==void 0){const r=n.appliedSeq;i.setState(n.state),this.#t[t]=r,r>e&&(e=r)}}}return e}async persistSnapshots(){if(this.#i)for(const[e,t]of this.#e.entries())await this.#i.save(t.def.name,{appliedSeq:this.#t[e]??0,state:t.state})}async initialize(){return this.#n?(await this.recoverFromSnapshots(),this.#r()):0}async#r(){const e=this.#n;if(!e)return 0;let t=this.appliedSeq,i=0;for(let s=0;s<1e3;s+=1){const n=await e.getSince(t);if(i+=this.applyEntries(n.entries),!n.truncated||n.cursor===void 0||n.cursor<=t)return i;t=n.cursor}return i}async appendEvent(e){if(!this.#n)throw new Error("MaterializerRuntime.appendEvent requires a doClient — pass one in the constructor options.");const i=(await this.#n.append([e]))[0];if(!i)throw new Error("MaterializerRuntime.appendEvent: DO returned empty result");return this.#e.length>0&&this.appliedSeq<i.seq&&(await this.#r(),this.appliedSeq<i.seq)||this.applyEntries([i]),i}reset(){for(const[e,t]of this.#e.entries())this.#t[e]=0,t.reset()}get materializers(){return this.#e}}export{u as MaterializerRuntime,c as defineMaterializer};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{f as i}from"./fnv1a-BNN96GYb.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};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const r=t=>`\`${t.replaceAll("`","``")}\``,E=t=>t.map(n=>`${r(n)} = ?`).join(", "),$=t=>`(${t.map(n=>r(n)).join(", ")})`,b=t=>`(${Array.from({length:t}).fill("?").join(", ")})`,c=t=>t==null?null:typeof t=="number"||typeof t=="bigint"||typeof t=="string"?t:typeof t=="boolean"?t?1:0:t instanceof Uint8Array?t:typeof t=="object"?JSON.stringify(t):String(t),g=(t,n,o)=>{if(n.changes.length===0)return;const f=r(n.table),y=r(o);for(const s of n.changes)switch(s.type){case"delete":{t.exec(`DELETE FROM ${f} WHERE ${y} = ?`,[c(s.id)]);break}case"insert":{const{data:i}=s,e=Object.keys(i);if(e.length===0)continue;const a=`INSERT OR REPLACE INTO ${f} ${$(e)} VALUES ${b(e.length)}`,p=e.map(l=>c(i[l]));t.exec(a,p);break}case"update":{const{data:i}=s,e=Object.keys(i);if(e.length===0)continue;const a=`UPDATE ${f} SET ${E(e)} WHERE ${y} = ?`,p=[...e.map(l=>c(i[l])),c(s.id)];t.exec(a,p);break}}},D=(t,n,o)=>{t.transaction(()=>{g(t,n,o??"id")})},h=(t,n)=>{n.length!==0&&t.transaction(()=>{for(const o of n)g(t,o,"id")})};export{D as applyDiffToDb,h as applyDiffsToDb,r as escapeIdentifier,c as normalizeBindValue};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const k=/["\\\u0000-\u001F\uD800-\uDFFF]/,O=r=>k.test(r)?JSON.stringify(r):`"${r}"`,w=r=>{if(r===void 0)return"null";if(typeof r=="bigint")throw new TypeError("stableStringify: cannot use a bigint in a stable JSON cache key — pass it as a string, or use stableWireKey");if(typeof r=="number"){if(Number.isNaN(r))return"nan";if(r===1/0)return"inf";if(r===-1/0)return"-inf";if(Object.is(r,-0))return"-0"}if(typeof r=="string")return O(r);if(r===null||typeof r!="object")return JSON.stringify(r);if(Array.isArray(r)){let e="[";for(let o=0;o<r.length;o++)o>0&&(e+=","),e+=w(r[o]);return e+"]"}const n=Object.getPrototypeOf(r);if(n!==null&&n!==Object.prototype){const e=r.constructor?.name??"value";throw new TypeError(`stableStringify: cannot use a ${e} in a stable JSON cache key — only plain objects, arrays, and JSON primitives are supported (wire-typed values key via stableWireKey)`)}const f=r,s=Object.keys(f).sort();let c="{",t=!0;for(const e of s){const o=f[e];o!==void 0&&(t?t=!1:c+=",",c+=O(e),c+=":",c+=w(o))}return c+"}"},l=r=>{let n="";for(let s=0;s<r.length;s+=32768)n+=String.fromCharCode(...r.subarray(s,s+32768));return btoa(n)},i="$lunora.wire$";const j="__proto__",E=r=>{if(r===null||typeof r!="object")return!1;const n=Object.getPrototypeOf(r);return n===null||n===Object.prototype},y=(r,n=0)=>{if(n>64)throw new RangeError("wire-codec: value nesting exceeds the 64-level limit");if(r===void 0)return[i,"undefined"];if(r===null)return null;const f=typeof r;if(f==="bigint")return[i,"bigint",r.toString()];if(f==="number"){const t=r;return Number.isNaN(t)?[i,"nan"]:t===1/0?[i,"inf"]:t===-1/0?[i,"-inf"]:t}if(f!=="object")return r;if(r instanceof Date)return[i,"date",y(r.getTime(),n+1)];if(r instanceof Error){const t=r,e={};for(const b of Object.keys(t))t[b]!==void 0&&(e[b]=y(t[b],n+1));const o=[i,"error",t.name,t.message,e];return t.cause!==void 0&&o.push(y(t.cause,n+1)),o}if(r instanceof URL)return[i,"url",r.href];if(r instanceof Map)return[i,"map",[...r.entries()].map(([t,e])=>[y(t,n+1),y(e,n+1)])];if(r instanceof Set)return[i,"set",[...r].map(t=>y(t,n+1))];if(r instanceof ArrayBuffer)return[i,"bytes",l(new Uint8Array(r)),"ArrayBuffer"];if(ArrayBuffer.isView(r)){const t=r,e=t.constructor.name,o=new Uint8Array(t.buffer,t.byteOffset,t.byteLength);return e==="Uint8Array"?[i,"bytes",l(o)]:[i,"bytes",l(o),e]}if(Array.isArray(r)){const t=r.map(e=>y(e,n+1));return t.length>0&&t[0]===i?[i,"arr",t]:t}if(!E(r)){const t=r.constructor?.name??"value";throw new TypeError(`wire-codec: cannot encode a ${t} over the Lunora wire — only plain objects, arrays, and the supported built-ins (Date, Error, URL, Map, Set, ArrayBuffer/typed arrays, bigint) round-trip`)}const s=r,c={};for(const t of Object.keys(s)){const e=s[t];if(e===void 0)continue;const o=y(e,n+1);t===j?Object.defineProperty(c,t,{configurable:!0,enumerable:!0,value:o,writable:!0}):c[t]=o}return c},N=r=>w(y(r)),S=r=>`fn_${r.replaceAll(/[/:.]/g,"_")}`,_=r=>Array.isArray(r)?r:r!==null&&typeof r=="object"?[r]:[],T=(r,n,f,s,c)=>{const t=S(f.__lunoraRef);n.registerTable(t,{});const e=n.primaryKeyOf(t);let o=new Map;return r.subscribe(f,s,b=>{const d=new Map,m=new Map,p=[];for(const a of _(b)){const u=a,g=u[e];if(typeof g!="string"&&typeof g!="number"&&typeof g!="bigint"){p.push({type:"insert",data:u});continue}const A=String(g),h=N(u);d.set(A,h),m.set(A,u)}for(const[a,u]of d)o.get(a)!==u&&p.push({data:m.get(a),type:"insert"});for(const a of o.keys())d.has(a)||p.push({type:"delete",id:a});p.length>0&&n.applyDiff({table:t,changes:p,timestamp:Date.now()}),o=d},{shardKey:c})};export{T as subscribeToMirror};
|