@iadev93/zuno 0.0.12 → 0.0.13

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
@@ -120,6 +120,41 @@ SSE is ideal for:
120
120
  * CDN/proxy friendly infra
121
121
  * avoiding WebSocket lock-in
122
122
 
123
+ On reconnect, the client sends its last observed event ID. The server replays retained events after that ID. If the requested range is no longer complete, the server sends an authoritative snapshot with the current event ID instead. Calling `stop()` permanently cancels the active connection, scheduled reconnects, queue flush timers, and browser online listener.
124
+
125
+ Client recovery is bounded by default:
126
+
127
+ * `maxQueueSize` limits mutations retained while offline (default: `100`)
128
+ * `maxConflictRetries` limits automatic retries for one conflict (default: `3`)
129
+ * retryable HTTP 5xx mutations remain queued instead of being silently discarded
130
+
131
+ By default the offline queue is held in memory. To preserve queued mutations across
132
+ page reloads, provide the IndexedDB adapter with a queue key unique to the current
133
+ application namespace or signed-in user:
134
+
135
+ ```ts
136
+ import { createIndexedDBOfflineQueue, createZuno } from "@iadev93/zuno";
137
+
138
+ const zuno = createZuno({
139
+ sseUrl: "/zuno/events",
140
+ syncUrl: "/zuno/sync",
141
+ offlineQueue: createIndexedDBOfflineQueue({
142
+ databaseName: "my-app",
143
+ queueKey: "tenant-a:user-123",
144
+ }),
145
+ });
146
+ ```
147
+
148
+ Custom persistence providers can implement the exported `ZunoOfflineQueue`
149
+ `load()`/`save()` contract. A failed durable write returns
150
+ `QUEUE_STORAGE_ERROR` rather than claiming that the mutation was safely queued.
151
+
152
+ Before flushing, queued state snapshots are coalesced by `storeKey`: Zuno keeps
153
+ the first mutation's `baseVersion` and sends only the latest state for that store.
154
+ For example, offline counter states `1 → 2 → 3` produce one sync request carrying
155
+ state `3`. Different store keys remain separate. This preserves final-state
156
+ convergence while avoiding redundant requests and repeated version conflicts.
157
+
123
158
  ---
124
159
 
125
160
  ## Adapter Contract (UI / Frameworks)
@@ -177,6 +212,8 @@ For multi-tenant routing, use `createZunoServerRegistry()` and select a namespac
177
212
 
178
213
  The original module-level helpers remain available and use `defaultZunoServerState` for backward compatibility. New applications should prefer explicit instances.
179
214
 
215
+ `maxSubscriberBuffer` bounds pending messages per SSE subscriber. A slow subscriber that exhausts its buffer is disconnected and can recover through replay or snapshot fallback on reconnect.
216
+
180
217
  ### Snapshot handler
181
218
 
182
219
  The snapshot handler returns the current universe/store snapshot for new clients.
@@ -1,3 +1,23 @@
1
+ /** Storage contract used by the SSE client to persist queued mutations. */
2
+ interface ZunoOfflineQueue {
3
+ load(): Promise<ZunoStateEvent[]>;
4
+ save(events: readonly ZunoStateEvent[]): Promise<void>;
5
+ }
6
+ /** In-memory queue storage. Useful as the default and for custom integrations/tests. */
7
+ declare function createMemoryOfflineQueue(initialEvents?: readonly ZunoStateEvent[]): ZunoOfflineQueue;
8
+ type IndexedDBOfflineQueueOptions = {
9
+ /** IndexedDB database name (default: "zuno"). */
10
+ databaseName?: string;
11
+ /** Object-store name (default: "offline-queues"). */
12
+ storeName?: string;
13
+ /** Key used for this client/namespace queue (default: "default"). */
14
+ queueKey?: string;
15
+ /** IndexedDB schema version (default: 1). */
16
+ version?: number;
17
+ };
18
+ /** Creates durable browser queue storage backed by IndexedDB. */
19
+ declare function createIndexedDBOfflineQueue(options?: IndexedDBOfflineQueueOptions): ZunoOfflineQueue;
20
+
1
21
  type ConflictResolver<T = unknown> = (localState: T, serverState: T, storeKey: string) => T;
2
22
  /**
3
23
  * Authoritative state event.
@@ -52,6 +72,8 @@ type SSEOptions = {
52
72
  maxQueueSize?: number;
53
73
  /** Maximum automatic retries for a single conflict (default: 3). */
54
74
  maxConflictRetries?: number;
75
+ /** Queue persistence provider (default: an in-memory provider). */
76
+ offlineQueue?: ZunoOfflineQueue;
55
77
  onOpen?: () => void;
56
78
  onClose?: () => void;
57
79
  onEvent?: (event: ZunoStateEvent) => void;
@@ -141,6 +163,8 @@ type CreateZunoOptions = {
141
163
  maxQueueSize?: number;
142
164
  /** Maximum automatic retries for a single conflict (default: 3). */
143
165
  maxConflictRetries?: number;
166
+ /** Optional durable queue used for offline/server-error mutations. */
167
+ offlineQueue?: ZunoOfflineQueue;
144
168
  };
145
169
  /**
146
170
  * An extended interface for a Zuno store that includes methods for setting state
@@ -184,4 +208,4 @@ declare const createZuno: (opts?: CreateZunoOptions) => {
184
208
  setLastEventId: (id: number) => void;
185
209
  };
186
210
 
187
- export { type BoundStore as B, type CreateZunoOptions as C, type Dispatch as D, type Middleware as M, type Store as S, type TransportStatus as T, type Universe as U, type ZunoSnapshot as Z, type MiddlewareAPI as a, createUniverse as b, createStore as c, createZuno as d, type ConflictResolver as e, type ZunoStateEvent as f, type ZunoTransport as g, applyIncomingEvent as h, startSSE as i, type SSEOptions as j, type BCOptions as k, startBroadcastChannel as s };
211
+ export { type BoundStore as B, type CreateZunoOptions as C, type Dispatch as D, type IndexedDBOfflineQueueOptions as I, type Middleware as M, type Store as S, type TransportStatus as T, type Universe as U, type ZunoSnapshot as Z, type MiddlewareAPI as a, createUniverse as b, createStore as c, createZuno as d, type ConflictResolver as e, type ZunoStateEvent as f, type ZunoTransport as g, applyIncomingEvent as h, startSSE as i, type SSEOptions as j, type BCOptions as k, type ZunoOfflineQueue as l, createIndexedDBOfflineQueue as m, createMemoryOfflineQueue as n, startBroadcastChannel as s };
@@ -1,3 +1,23 @@
1
+ /** Storage contract used by the SSE client to persist queued mutations. */
2
+ interface ZunoOfflineQueue {
3
+ load(): Promise<ZunoStateEvent[]>;
4
+ save(events: readonly ZunoStateEvent[]): Promise<void>;
5
+ }
6
+ /** In-memory queue storage. Useful as the default and for custom integrations/tests. */
7
+ declare function createMemoryOfflineQueue(initialEvents?: readonly ZunoStateEvent[]): ZunoOfflineQueue;
8
+ type IndexedDBOfflineQueueOptions = {
9
+ /** IndexedDB database name (default: "zuno"). */
10
+ databaseName?: string;
11
+ /** Object-store name (default: "offline-queues"). */
12
+ storeName?: string;
13
+ /** Key used for this client/namespace queue (default: "default"). */
14
+ queueKey?: string;
15
+ /** IndexedDB schema version (default: 1). */
16
+ version?: number;
17
+ };
18
+ /** Creates durable browser queue storage backed by IndexedDB. */
19
+ declare function createIndexedDBOfflineQueue(options?: IndexedDBOfflineQueueOptions): ZunoOfflineQueue;
20
+
1
21
  type ConflictResolver<T = unknown> = (localState: T, serverState: T, storeKey: string) => T;
2
22
  /**
3
23
  * Authoritative state event.
@@ -52,6 +72,8 @@ type SSEOptions = {
52
72
  maxQueueSize?: number;
53
73
  /** Maximum automatic retries for a single conflict (default: 3). */
54
74
  maxConflictRetries?: number;
75
+ /** Queue persistence provider (default: an in-memory provider). */
76
+ offlineQueue?: ZunoOfflineQueue;
55
77
  onOpen?: () => void;
56
78
  onClose?: () => void;
57
79
  onEvent?: (event: ZunoStateEvent) => void;
@@ -141,6 +163,8 @@ type CreateZunoOptions = {
141
163
  maxQueueSize?: number;
142
164
  /** Maximum automatic retries for a single conflict (default: 3). */
143
165
  maxConflictRetries?: number;
166
+ /** Optional durable queue used for offline/server-error mutations. */
167
+ offlineQueue?: ZunoOfflineQueue;
144
168
  };
145
169
  /**
146
170
  * An extended interface for a Zuno store that includes methods for setting state
@@ -184,4 +208,4 @@ declare const createZuno: (opts?: CreateZunoOptions) => {
184
208
  setLastEventId: (id: number) => void;
185
209
  };
186
210
 
187
- export { type BoundStore as B, type CreateZunoOptions as C, type Dispatch as D, type Middleware as M, type Store as S, type TransportStatus as T, type Universe as U, type ZunoSnapshot as Z, type MiddlewareAPI as a, createUniverse as b, createStore as c, createZuno as d, type ConflictResolver as e, type ZunoStateEvent as f, type ZunoTransport as g, applyIncomingEvent as h, startSSE as i, type SSEOptions as j, type BCOptions as k, startBroadcastChannel as s };
211
+ export { type BoundStore as B, type CreateZunoOptions as C, type Dispatch as D, type IndexedDBOfflineQueueOptions as I, type Middleware as M, type Store as S, type TransportStatus as T, type Universe as U, type ZunoSnapshot as Z, type MiddlewareAPI as a, createUniverse as b, createStore as c, createZuno as d, type ConflictResolver as e, type ZunoStateEvent as f, type ZunoTransport as g, applyIncomingEvent as h, startSSE as i, type SSEOptions as j, type BCOptions as k, type ZunoOfflineQueue as l, createIndexedDBOfflineQueue as m, createMemoryOfflineQueue as n, startBroadcastChannel as s };
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- 'use strict';function L(t,n,p){let{clientId:a,versions:r}=p,l=n.origin==="server"||n.origin==="conflict-resolution",o=r.get(n.storeKey)??0;if(typeof n.version=="number"){if(!l&&n.version<=o)return;r.set(n.storeKey,n.version);}else if(n.origin===a)return;let d=t.getStore(n.storeKey,()=>n.state);n.intent&&(typeof n.version=="number"&&n.version<=o&&l||d.apply(n.intent)),n.state!==void 0&&(l||typeof n.version=="number"&&n.version>o)&&d.set(n.state);}function M(t){let{url:n,syncUrl:p,universe:a,clientId:r,versions:l,getLastEventId:o,setLastEventId:d,onEvent:g,resolveConflict:b}=t,I=t.maxQueueSize??100,x=t.maxConflictRetries??3;if(!Number.isInteger(I)||I<1)throw new TypeError("maxQueueSize must be a positive integer");if(!Number.isInteger(x)||x<0)throw new TypeError("maxConflictRetries must be a non-negative integer");let k=null,j=0,R=false,h=null,U=null,e=u=>{if(g)g(u);else {if(typeof u.version=="number"){let i=l.get(u.storeKey)??0;if(u.version<=i)return;l.set(u.storeKey,u.version);}let S=a.getStore(u.storeKey,()=>u.state);u.intent?S.apply(u.intent):S.set(u.state);}},s=[],f=new Map,v=false,m=u=>s.length>=I?false:(s.push(u),true),T=()=>{R||U||(U=setTimeout(()=>{U=null,Z();},1e3));};async function Z(){if(R||v||s.length===0||typeof navigator<"u"&&!navigator.onLine)return;v=true;let u=new Map,S=[];for(let i of s)if(u.has(i.storeKey)){let c=u.get(i.storeKey),y=S[c];S[c]={...i,baseVersion:y.baseVersion};}else u.set(i.storeKey,S.length),S.push(i);s.length=0,s.push(...S);try{for(;s.length>0;){let i=s[0];try{let c=await fetch(p,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)});if(!c.ok&&c.status!==409){if(c.status>=400&&c.status<500){s.shift();continue}T();break}if(c.status===409){let y=await c.json();if(y.current){let{state:w,version:O}=y.current,E=w;if(b){let C=a.getStore(i.storeKey,()=>null).get();E=b(C,w,i.storeKey);}if(e({storeKey:i.storeKey,state:E,version:O,origin:"conflict-resolution"}),JSON.stringify(E)!==JSON.stringify(w)){let C=(f.get(i.storeKey)??0)+1;if(C>x){f.delete(i.storeKey),s.shift();continue}f.set(i.storeKey,C),s.unshift({...i,state:E,baseVersion:O});continue}}s.shift();}else if(c.ok){f.delete(i.storeKey);let y=await c.json();y.event&&typeof y.event.version=="number"&&l.set(i.storeKey,y.event.version),s.shift();}else s.shift();}catch(c){console.error("[Zuno] Flush failed, retrying later",c),T();break}}}finally{v=false;}}function K(){if(R)return;let u=o(),S=new URL(n,globalThis.location?.href);u>0&&S.searchParams.set("lastEventId",String(u)),k=new EventSource(S.toString()),k.addEventListener("snapshot",i=>{try{let c=Number.parseInt(i.lastEventId||"0",10);c>=0&&d?.(c);let y=JSON.parse(i.data);for(let[w,O]of Object.entries(y)){let E=O;e({storeKey:w,state:E.state,version:E.version,origin:"server"});}}catch(c){console.error("[Zuno] Failed to parse snapshot",c);}}),k.addEventListener("state",i=>{try{let c=JSON.parse(i.data);if(c.origin||(c.origin="server"),c.origin===r)return;e(c);}catch(c){console.error("[Zuno] Failed to parse SSE event",c);}}),k.onopen=()=>{R||(j=0,t.onOpen?.(),Z());},k.onerror=()=>{if(k?.close(),R)return;t.onClose?.();let i=Math.min(1e3*2**j,3e4);j++,h=setTimeout(()=>{h=null,K();},i);};}typeof window<"u"&&window.addEventListener("online",Z),K();let Q=async(u,S=0)=>{try{if(t.optimistic!==!1&&!u.origin&&e(u),typeof navigator<"u"&&!navigator.onLine)return {ok:!1,status:0,json:null,reason:m(u)?"OFFLINE_QUEUED":"QUEUE_FULL"};let i=await fetch(p,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(u)});if(i.status===409){let y=await i.json();if(y.current){let{state:w,version:O}=y.current,E=w;if(b){let C=a.getStore(u.storeKey,()=>null).get();E=b(C,w,u.storeKey);}if(e({storeKey:u.storeKey,state:E,version:O,origin:"conflict-resolution"}),JSON.stringify(E)!==JSON.stringify(w))return S>=x?{ok:!1,status:409,json:y,reason:"CONFLICT_RETRY_LIMIT"}:await Q({...u,state:E,baseVersion:O},S+1)}return {ok:!1,status:409,json:y,reason:"CONFLICT"}}if(!i.ok){let y=await i.json();if(i.status>=500){let w=m(u);return w&&T(),{ok:!1,status:i.status,json:y,reason:w?"SERVER_ERROR_QUEUED":"QUEUE_FULL"}}return {ok:!1,status:i.status,json:y}}let c=await i.json();if(c.event){let{version:y}=c.event;typeof y=="number"&&l.set(u.storeKey,y);}return {ok:!0,status:200,json:c}}catch(i){let c=m(u);return c&&T(),{ok:false,status:500,json:i,reason:c?"NETWORK_ERROR_QUEUED":"QUEUE_FULL"}}};return {dispatch:Q,unsubscribe:()=>{R=true,k?.close(),h&&clearTimeout(h),U&&clearTimeout(U),typeof window<"u"&&window.removeEventListener("online",Z);}}}function N(t){let{channelName:n,clientId:p,onEvent:a,getSnapshot:r,onSnapshot:l}=t,o=new BroadcastChannel(n);return o.onmessage=d=>{let g=d.data;g.origin!==p&&(g.type==="event"&&a(g.event),g.type==="hello"&&o.postMessage({type:"snapshot",snapshot:r(),origin:p}),g.type==="snapshot"&&l(g.snapshot));},{publish:d=>o.postMessage({type:"event",event:d,origin:p}),hello:()=>o.postMessage({type:"hello",origin:p}),stop:()=>o.close()}}var P=(t,n,p=Object.is)=>{let a=t,r=new Set,l=()=>{r.forEach(o=>{o(a);});};return {get:()=>a,equals:p,set:o=>{let d=typeof o=="function"?o(a):o;p(d,a)||(a=d,l());},apply:o=>{let d=o;if(d.type==="SET"){let b=d.payload;if(p(b,a))return;a=b,l();return}if(!n){console.warn(`[Zuno] apply() called for intent "${d.type}" on a store without a reducer. Intent ignored.`);return}let g=n(a,d);p(g,a)||(a=g,l());},subscribe:o=>(r.add(o),()=>r.delete(o))}},B=()=>{let t=new Map,n=null,p=r=>(r.subscribe(()=>{n=null;}),r);return {getStore(r,l,o,d){let g=t.get(r);return g||(g=p(P(l(),o,d)),t.set(r,g),n=null),g},snapshot(){if(n)return n;let r={};for(let[l,o]of t.entries())r[l]=o.get();return n=r,r},restore(r){for(let[l,o]of Object.entries(r)){let d=t.get(l);d?d.set(o):(t.set(l,p(P(o))),n=null);}},delete(r){t.delete(r),n=null;},clear(){t.clear(),n=null;},hydrateSnapshot(r){let l={};for(let[o,d]of Object.entries(r.state))l[o]=d.state;this.restore(l);}}},F=(t={})=>{let p=new Map,a=t.universe??B(),r=t.clientId??globalThis.crypto?.randomUUID?.()??String(Math.random()),o=0;function d(e){let s={};for(let[f,v]of Object.entries(e.state))s[f]=v.state,p.set(f,v.version);a.restore(s),o=e.lastEventId;}let g=e=>{typeof e.eventId=="number"&&(o=Math.max(o,e.eventId)),L(a,e,{clientId:r,versions:p});},b=t.sseUrl&&t.syncUrl?M({universe:a,url:t.sseUrl,syncUrl:t.syncUrl,optimistic:t.optimistic??true,clientId:r,versions:p,getLastEventId:()=>o,setLastEventId:e=>{o=e;},maxQueueSize:t.maxQueueSize,maxConflictRetries:t.maxConflictRetries,onOpen:()=>{},onClose:()=>{},onEvent:e=>h(e),resolveConflict:t.resolveConflict}):null,I=t.channelName?N({channelName:t.channelName,clientId:r,onEvent:e=>h(e),getSnapshot:()=>{let e=a.snapshot(),s={};for(let[f,v]of Object.entries(e))s[f]={state:v,version:p.get(f)??0};return s},onSnapshot:e=>{for(let[s,f]of Object.entries(e))g({storeKey:s,state:f.state,version:f.version});}}):null;setTimeout(()=>I?.hello(),100);let x=new Map,k=null,j=async()=>{let e=Array.from(x.values());x.clear(),k=null;for(let s of e)b&&b.dispatch(s).catch(f=>{console.error("[Zuno] Batch sync failed",f);});},R=async e=>{if(e.origin&&(g(e),e.origin!==r))return {ok:true,status:200,json:null};if(!e.origin){e.origin=r;let s=a.getStore(e.storeKey,()=>{});if(e.state===void 0&&e.intent)if(t.optimistic!==false)s.apply(e.intent),e.state=s.get();else {let v=e.intent;v.type==="SET"&&(e.state=v.payload);}else e.state!==void 0&&t.optimistic!==false&&s.set(e.state);let f=p.get(e.storeKey)??0;if(e.baseVersion??(e.baseVersion=f),t.optimistic!==false){let v=f+1;p.set(e.storeKey,v),e.version=v;}I&&I.publish(e);}if(b){if(t.batchSync){let s=x.get(e.storeKey);return x.set(e.storeKey,{...e,baseVersion:s?.baseVersion??e.baseVersion}),k||(k=Promise.resolve().then(j)),{ok:true,status:202,json:{batched:true}}}return await b.dispatch(e)}return {ok:true,status:200,json:null}},h=R;if(t.middleware&&t.middleware.length>0){let e={universe:a,clientId:r,versions:p};h=t.middleware.map(f=>f(e)).reduceRight((f,v)=>v(f),R);}return {universe:a,clientId:r,store:(e,s,f,v)=>{let m=a.getStore(e,s,f,v);return {key:e,raw:()=>m,get:()=>m.get(),subscribe:T=>m.subscribe(T),equals:(T,Z)=>m.equals(T,Z),set:T=>{let Z=m.get(),K=typeof T=="function"?T(Z):T;return h({storeKey:e,state:K,intent:{type:"SET",payload:K}})}}},getStore:a.getStore.bind(a),get:(e,s)=>a.getStore(e,s??(()=>{})).get(),set:async(e,s,f)=>{let v=a.getStore(e,f??(()=>{})),m=typeof s=="function"?s(v.get()):s;return h({storeKey:e,state:m,intent:{type:"SET",payload:m}})},mutate:async(e,s)=>h({storeKey:e,state:void 0,intent:s}),subscribe:(e,s,f)=>a.getStore(e,s).subscribe(f),dispatch:h,stop:()=>{b?.unsubscribe?.(),I?.stop?.();},hydrateSnapshot:d,getLastEventId:()=>o,setLastEventId:e=>{o=e;}}};function V(t){return {getSnapshot:()=>t.get(),subscribe:n=>t.subscribe(()=>n())}}function q(t,n){if(Object.is(t,n))return true;if(typeof t!="object"||t===null||typeof n!="object"||n===null)return false;let p=Object.keys(t),a=Object.keys(n);if(p.length!==a.length)return false;let r=t,l=n;for(let o of p)if(!Object.hasOwn(l,o)||!Object.is(r[o],l[o]))return false;return true}exports.applyIncomingEvent=L;exports.createStore=P;exports.createUniverse=B;exports.createZuno=F;exports.shallowEqual=q;exports.startBroadcastChannel=N;exports.startSSE=M;exports.toReadable=V;//# sourceMappingURL=index.cjs.map
1
+ 'use strict';function B(t=[]){let n=structuredClone([...t]);return {async load(){return structuredClone(n)},async save(u){n=structuredClone([...u]);}}}function J(t={}){let n=t.databaseName??"zuno",u=t.storeName??"offline-queues",a=t.queueKey??"default",i=t.version??1;if(!Number.isInteger(i)||i<1)throw new TypeError("version must be a positive integer");let l,r=()=>typeof indexedDB>"u"?Promise.reject(new Error("IndexedDB is not available in this environment")):(l||(l=new Promise((p,y)=>{let g=indexedDB.open(n,i);g.onupgradeneeded=()=>{g.result.objectStoreNames.contains(u)||g.result.createObjectStore(u);},g.onsuccess=()=>p(g.result),g.onerror=()=>y(g.error),g.onblocked=()=>y(new Error(`IndexedDB database "${n}" is blocked`));})),l);return {async load(){let p=await r();return await new Promise((y,g)=>{let S=p.transaction(u,"readonly").objectStore(u).get(a);S.onsuccess=()=>y(Array.isArray(S.result)?S.result:[]),S.onerror=()=>g(S.error);})},async save(p){let y=await r();await new Promise((g,S)=>{let h=y.transaction(u,"readwrite");h.objectStore(u).put([...p],a),h.oncomplete=()=>g(),h.onerror=()=>S(h.error),h.onabort=()=>S(h.error);});}}}function D(t,n,u){let{clientId:a,versions:i}=u,l=n.origin==="server"||n.origin==="conflict-resolution",r=i.get(n.storeKey)??0;if(typeof n.version=="number"){if(!l&&n.version<=r)return;i.set(n.storeKey,n.version);}else if(n.origin===a)return;let p=t.getStore(n.storeKey,()=>n.state);n.intent&&(typeof n.version=="number"&&n.version<=r&&l||p.apply(n.intent)),n.state!==void 0&&(l||typeof n.version=="number"&&n.version>r)&&p.set(n.state);}function L(t){let{url:n,syncUrl:u,universe:a,clientId:i,versions:l,getLastEventId:r,setLastEventId:p,onEvent:y,resolveConflict:g}=t,S=t.maxQueueSize??100,h=t.maxConflictRetries??3,I=t.offlineQueue??B();if(!Number.isInteger(S)||S<1)throw new TypeError("maxQueueSize must be a positive integer");if(!Number.isInteger(h)||h<0)throw new TypeError("maxConflictRetries must be a non-negative integer");let O=null,j=0,w=false,U=null,e=null,f=s=>{if(y)y(s);else {if(typeof s.version=="number"){let c=l.get(s.storeKey)??0;if(s.version<=c)return;l.set(s.storeKey,s.version);}let m=a.getStore(s.storeKey,()=>s.state);s.intent?m.apply(s.intent):m.set(s.state);}},o=[],b=true,T=s=>{b=false,console.error("[Zuno] Offline queue storage failed",s);},x=I.load().then(async s=>{if(o.push(...s.slice(0,S)),s.length>S)try{await I.save(o);}catch(m){T(m);}}).catch(T),Z=new Map,Q=false,R=async()=>{try{return await I.save(o),b=!0,!0}catch(s){return T(s),false}},q=async s=>(await x,b?o.length>=S?"full":(o.push(s),await R()?"queued":(o.pop(),"storage-error")):"storage-error"),P=(s,m)=>s==="queued"?m:s==="full"?"QUEUE_FULL":"QUEUE_STORAGE_ERROR",N=()=>{w||e||(e=setTimeout(()=>{e=null,M();},1e3));};async function M(){if(w||(await x,Q||o.length===0)||typeof navigator<"u"&&!navigator.onLine)return;Q=true;let s=new Map,m=[];for(let c of o)if(s.has(c.storeKey)){let d=s.get(c.storeKey),v=m[d];m[d]={...c,baseVersion:v.baseVersion};}else s.set(c.storeKey,m.length),m.push(c);o.length=0,o.push(...m),await R();try{for(;o.length>0;){let c=o[0];try{let d=await fetch(u,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(c)});if(!d.ok&&d.status!==409){if(d.status>=400&&d.status<500){o.shift(),await R();continue}N();break}if(d.status===409){let v=await d.json();if(v.current){let{state:E,version:C}=v.current,k=E;if(g){let K=a.getStore(c.storeKey,()=>null).get();k=g(K,E,c.storeKey);}if(f({storeKey:c.storeKey,state:k,version:C,origin:"conflict-resolution"}),JSON.stringify(k)!==JSON.stringify(E)){let K=(Z.get(c.storeKey)??0)+1;if(K>h){Z.delete(c.storeKey),o.shift(),await R();continue}Z.set(c.storeKey,K),o.unshift({...c,state:k,baseVersion:C});continue}}o.shift(),await R();}else if(d.ok){Z.delete(c.storeKey);let v=await d.json();v.event&&typeof v.event.version=="number"&&l.set(c.storeKey,v.event.version),o.shift(),await R();}else o.shift(),await R();}catch(d){console.error("[Zuno] Flush failed, retrying later",d),N();break}}}finally{Q=false;}}function F(){if(w)return;let s=r(),m=new URL(n,globalThis.location?.href);s>0&&m.searchParams.set("lastEventId",String(s)),O=new EventSource(m.toString()),O.addEventListener("snapshot",c=>{try{let d=Number.parseInt(c.lastEventId||"0",10);d>=0&&p?.(d);let v=JSON.parse(c.data);for(let[E,C]of Object.entries(v)){let k=C;f({storeKey:E,state:k.state,version:k.version,origin:"server"});}}catch(d){console.error("[Zuno] Failed to parse snapshot",d);}}),O.addEventListener("state",c=>{try{let d=JSON.parse(c.data);if(d.origin||(d.origin="server"),d.origin===i)return;f(d);}catch(d){console.error("[Zuno] Failed to parse SSE event",d);}}),O.onopen=()=>{w||(j=0,t.onOpen?.(),M());},O.onerror=()=>{if(O?.close(),w)return;t.onClose?.();let c=Math.min(1e3*2**j,3e4);j++,U=setTimeout(()=>{U=null,F();},c);};}typeof window<"u"&&window.addEventListener("online",M),F();let _=async(s,m=0)=>{try{if(t.optimistic!==!1&&!s.origin&&f(s),typeof navigator<"u"&&!navigator.onLine){let v=await q(s);return {ok:!1,status:0,json:null,reason:P(v,"OFFLINE_QUEUED")}}let c=await fetch(u,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)});if(c.status===409){let v=await c.json();if(v.current){let{state:E,version:C}=v.current,k=E;if(g){let K=a.getStore(s.storeKey,()=>null).get();k=g(K,E,s.storeKey);}if(f({storeKey:s.storeKey,state:k,version:C,origin:"conflict-resolution"}),JSON.stringify(k)!==JSON.stringify(E))return m>=h?{ok:!1,status:409,json:v,reason:"CONFLICT_RETRY_LIMIT"}:await _({...s,state:k,baseVersion:C},m+1)}return {ok:!1,status:409,json:v,reason:"CONFLICT"}}if(!c.ok){let v=await c.json();if(c.status>=500){let E=await q(s);return E==="queued"&&N(),{ok:!1,status:c.status,json:v,reason:P(E,"SERVER_ERROR_QUEUED")}}return {ok:!1,status:c.status,json:v}}let d=await c.json();if(d.event){let{version:v}=d.event;typeof v=="number"&&l.set(s.storeKey,v);}return {ok:!0,status:200,json:d}}catch(c){let d=await q(s);return d==="queued"&&N(),{ok:false,status:500,json:c,reason:P(d,"NETWORK_ERROR_QUEUED")}}};return {dispatch:_,unsubscribe:()=>{w=true,O?.close(),U&&clearTimeout(U),e&&clearTimeout(e),typeof window<"u"&&window.removeEventListener("online",M);}}}function V(t){let{channelName:n,clientId:u,onEvent:a,getSnapshot:i,onSnapshot:l}=t,r=new BroadcastChannel(n);return r.onmessage=p=>{let y=p.data;y.origin!==u&&(y.type==="event"&&a(y.event),y.type==="hello"&&r.postMessage({type:"snapshot",snapshot:i(),origin:u}),y.type==="snapshot"&&l(y.snapshot));},{publish:p=>r.postMessage({type:"event",event:p,origin:u}),hello:()=>r.postMessage({type:"hello",origin:u}),stop:()=>r.close()}}var A=(t,n,u=Object.is)=>{let a=t,i=new Set,l=()=>{i.forEach(r=>{r(a);});};return {get:()=>a,equals:u,set:r=>{let p=typeof r=="function"?r(a):r;u(p,a)||(a=p,l());},apply:r=>{let p=r;if(p.type==="SET"){let g=p.payload;if(u(g,a))return;a=g,l();return}if(!n){console.warn(`[Zuno] apply() called for intent "${p.type}" on a store without a reducer. Intent ignored.`);return}let y=n(a,p);u(y,a)||(a=y,l());},subscribe:r=>(i.add(r),()=>i.delete(r))}},z=()=>{let t=new Map,n=null,u=i=>(i.subscribe(()=>{n=null;}),i);return {getStore(i,l,r,p){let y=t.get(i);return y||(y=u(A(l(),r,p)),t.set(i,y),n=null),y},snapshot(){if(n)return n;let i={};for(let[l,r]of t.entries())i[l]=r.get();return n=i,i},restore(i){for(let[l,r]of Object.entries(i)){let p=t.get(l);p?p.set(r):(t.set(l,u(A(r))),n=null);}},delete(i){t.delete(i),n=null;},clear(){t.clear(),n=null;},hydrateSnapshot(i){let l={};for(let[r,p]of Object.entries(i.state))l[r]=p.state;this.restore(l);}}},$=(t={})=>{let u=new Map,a=t.universe??z(),i=t.clientId??globalThis.crypto?.randomUUID?.()??String(Math.random()),r=0;function p(e){let f={};for(let[o,b]of Object.entries(e.state))f[o]=b.state,u.set(o,b.version);a.restore(f),r=e.lastEventId;}let y=e=>{typeof e.eventId=="number"&&(r=Math.max(r,e.eventId)),D(a,e,{clientId:i,versions:u});},g=t.sseUrl&&t.syncUrl?L({universe:a,url:t.sseUrl,syncUrl:t.syncUrl,optimistic:t.optimistic??true,clientId:i,versions:u,getLastEventId:()=>r,setLastEventId:e=>{r=e;},maxQueueSize:t.maxQueueSize,maxConflictRetries:t.maxConflictRetries,offlineQueue:t.offlineQueue,onOpen:()=>{},onClose:()=>{},onEvent:e=>w(e),resolveConflict:t.resolveConflict}):null,S=t.channelName?V({channelName:t.channelName,clientId:i,onEvent:e=>w(e),getSnapshot:()=>{let e=a.snapshot(),f={};for(let[o,b]of Object.entries(e))f[o]={state:b,version:u.get(o)??0};return f},onSnapshot:e=>{for(let[f,o]of Object.entries(e))y({storeKey:f,state:o.state,version:o.version});}}):null;setTimeout(()=>S?.hello(),100);let h=new Map,I=null,O=async()=>{let e=Array.from(h.values());h.clear(),I=null;for(let f of e)g&&g.dispatch(f).catch(o=>{console.error("[Zuno] Batch sync failed",o);});},j=async e=>{if(e.origin&&(y(e),e.origin!==i))return {ok:true,status:200,json:null};if(!e.origin){e.origin=i;let f=a.getStore(e.storeKey,()=>{});if(e.state===void 0&&e.intent)if(t.optimistic!==false)f.apply(e.intent),e.state=f.get();else {let b=e.intent;b.type==="SET"&&(e.state=b.payload);}else e.state!==void 0&&t.optimistic!==false&&f.set(e.state);let o=u.get(e.storeKey)??0;if(e.baseVersion??(e.baseVersion=o),t.optimistic!==false){let b=o+1;u.set(e.storeKey,b),e.version=b;}S&&S.publish(e);}if(g){if(t.batchSync){let f=h.get(e.storeKey);return h.set(e.storeKey,{...e,baseVersion:f?.baseVersion??e.baseVersion}),I||(I=Promise.resolve().then(O)),{ok:true,status:202,json:{batched:true}}}return await g.dispatch(e)}return {ok:true,status:200,json:null}},w=j;if(t.middleware&&t.middleware.length>0){let e={universe:a,clientId:i,versions:u};w=t.middleware.map(o=>o(e)).reduceRight((o,b)=>b(o),j);}return {universe:a,clientId:i,store:(e,f,o,b)=>{let T=a.getStore(e,f,o,b);return {key:e,raw:()=>T,get:()=>T.get(),subscribe:x=>T.subscribe(x),equals:(x,Z)=>T.equals(x,Z),set:x=>{let Z=T.get(),Q=typeof x=="function"?x(Z):x;return w({storeKey:e,state:Q,intent:{type:"SET",payload:Q}})}}},getStore:a.getStore.bind(a),get:(e,f)=>a.getStore(e,f??(()=>{})).get(),set:async(e,f,o)=>{let b=a.getStore(e,o??(()=>{})),T=typeof f=="function"?f(b.get()):f;return w({storeKey:e,state:T,intent:{type:"SET",payload:T}})},mutate:async(e,f)=>w({storeKey:e,state:void 0,intent:f}),subscribe:(e,f,o)=>a.getStore(e,f).subscribe(o),dispatch:w,stop:()=>{g?.unsubscribe?.(),S?.stop?.();},hydrateSnapshot:p,getLastEventId:()=>r,setLastEventId:e=>{r=e;}}};function G(t){return {getSnapshot:()=>t.get(),subscribe:n=>t.subscribe(()=>n())}}function H(t,n){if(Object.is(t,n))return true;if(typeof t!="object"||t===null||typeof n!="object"||n===null)return false;let u=Object.keys(t),a=Object.keys(n);if(u.length!==a.length)return false;let i=t,l=n;for(let r of u)if(!Object.hasOwn(l,r)||!Object.is(i[r],l[r]))return false;return true}exports.applyIncomingEvent=D;exports.createIndexedDBOfflineQueue=J;exports.createMemoryOfflineQueue=B;exports.createStore=A;exports.createUniverse=z;exports.createZuno=$;exports.shallowEqual=H;exports.startBroadcastChannel=V;exports.startSSE=L;exports.toReadable=G;//# sourceMappingURL=index.cjs.map
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/sync/index.ts","../src/core/index.ts","../src/shared/readable.ts","../src/utils.ts"],"names":["applyIncomingEvent","universe","event","context","clientId","versions","isAuthoritative","current","store","startSSE","opts","url","syncUrl","getLastEventId","setLastEventId","onEvent","resolveConflict","maxQueueSize","maxConflictRetries","es","retryCount","stopped","reconnectTimer","flushTimer","applyState","queue","conflictRetries","isFlushing","enqueue","scheduleFlush","flushQueue","keyIndex","reducedQueue","idx","prev","res","data","serverState","serverVersion","nextState","localState","attempts","json","err","connect","lastId","connectUrl","e","snapshotEventId","snap","key","rec","r","delay","dispatchFn","conflictAttempt","queued","version","startBroadcastChannel","channelName","getSnapshot","onSnapshot","channel","msg","createStore","initial","reducer","equals","state","listeners","notify","l","next","value","intent","i","listener","createUniverse","stores","cachedSnapshot","trackStore","init","s","out","existing","snapshot","plain","k","createZuno","lastEventId","hydrateSnapshot","apply","sse","id","dispatch","bc","storeKey","pendingSyncs","batchPromise","flushBatch","syncs","coreDispatch","nextVersion","pending","middlewareAPI","middleware","rawStore","cb","v1","v2","toReadable","onChange","shallowEqual","a","b","keysA","keysB","objA","objB"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { Universe } from \"../core\";\n\n// --- Types ---\n\nexport type ConflictResolver<T = unknown> = (\n\tlocalState: T,\n\tserverState: T,\n\tstoreKey: string,\n) => T;\n\n/**\n * Authoritative state event.\n */\nexport type ZunoStateEvent = {\n\tstoreKey: string;\n\tstate: unknown; // Was 'any', now strictly 'unknown'\n\tintent?: { type: string; payload?: unknown };\n\tversion?: number;\n\tbaseVersion?: number;\n\torigin?: string;\n\tts?: number;\n\teventId?: number;\n};\n\n/**\n * Generic transport status.\n */\nexport type TransportStatus = {\n\tok: boolean;\n\tstatus: number;\n\t// biome-ignore lint/suspicious/noExplicitAny: generic JSON response\n\tjson: any;\n\treason?: string;\n};\n\n/**\n * Client transport interface.\n */\nexport interface ZunoTransport {\n\tdispatch(event: ZunoStateEvent): Promise<TransportStatus>;\n\tunsubscribe?(): void;\n}\n\n/**\n * Apply incoming event to the universe and local bookkeeping.\n */\nexport function applyIncomingEvent(\n\tuniverse: Universe,\n\tevent: ZunoStateEvent,\n\tcontext: {\n\t\tclientId: string;\n\t\tlocalState: Map<string, unknown>;\n\t\tversions: Map<string, number>;\n\t},\n) {\n\tconst { clientId, versions } = context;\n\n\t// 1. Determine if this event is Authoritative (from Server) or Optimistic (from Peer/Local)\n\tconst isAuthoritative =\n\t\tevent.origin === \"server\" || event.origin === \"conflict-resolution\";\n\tconst current = versions.get(event.storeKey) ?? 0;\n\n\t// 2. Version check\n\tif (typeof event.version === \"number\") {\n\t\t// If it's not authoritative, we strictly enforce incrementing versions\n\t\tif (!isAuthoritative && event.version <= current) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Update version tracker\n\t\tversions.set(event.storeKey, event.version);\n\t} else if (event.origin === clientId) {\n\t\t// Suppress versionless loopback\n\t\treturn;\n\t}\n\n\t// 3. Apply to universe\n\tconst store = universe.getStore(event.storeKey, () => event.state);\n\n\t// If we have an intent, try to apply it first for side effects (but only if it's forward progress or authoritative)\n\tif (event.intent) {\n\t\t// If it's a version match/stale authoritative event, we might want to SKIP the intent\n\t\t// to avoid double-application (since we likely already did it optimistically).\n\t\t// However, snapping state (below) is always safe.\n\t\tif (\n\t\t\ttypeof event.version === \"number\" &&\n\t\t\tevent.version <= current &&\n\t\t\tisAuthoritative\n\t\t) {\n\t\t\t// Skip intent, but snap state anyway below.\n\t\t} else {\n\t\t\tstore.apply(event.intent);\n\t\t}\n\t}\n\n\t// 4. Authoritative State Snap\n\t// ALWAYS apply the state if provided and it's authoritative or has a higher version.\n\tif (event.state !== undefined) {\n\t\tif (\n\t\t\tisAuthoritative ||\n\t\t\t(typeof event.version === \"number\" && event.version > current)\n\t\t) {\n\t\t\tstore.set(event.state);\n\t\t}\n\t}\n}\n\n// --- SSE Client ---\n\nexport type SSEOptions = {\n\tuniverse: Universe;\n\turl: string;\n\tsyncUrl: string;\n\toptimistic: boolean;\n\tclientId: string;\n\tversions: Map<string, number>;\n\tgetLastEventId: () => number;\n\tsetLastEventId?: (id: number) => void;\n\t/** Maximum number of mutations retained while offline (default: 100). */\n\tmaxQueueSize?: number;\n\t/** Maximum automatic retries for a single conflict (default: 3). */\n\tmaxConflictRetries?: number;\n\tonOpen?: () => void;\n\tonClose?: () => void;\n\tonEvent?: (event: ZunoStateEvent) => void;\n\tresolveConflict?: ConflictResolver;\n};\n\nexport function startSSE(opts: SSEOptions): ZunoTransport {\n\tconst {\n\t\turl,\n\t\tsyncUrl,\n\t\tuniverse,\n\t\tclientId,\n\t\tversions,\n\t\tgetLastEventId,\n\t\tsetLastEventId,\n\t\tonEvent,\n\t\tresolveConflict,\n\t} = opts;\n\tconst maxQueueSize = opts.maxQueueSize ?? 100;\n\tconst maxConflictRetries = opts.maxConflictRetries ?? 3;\n\tif (!Number.isInteger(maxQueueSize) || maxQueueSize < 1) {\n\t\tthrow new TypeError(\"maxQueueSize must be a positive integer\");\n\t}\n\tif (!Number.isInteger(maxConflictRetries) || maxConflictRetries < 0) {\n\t\tthrow new TypeError(\"maxConflictRetries must be a non-negative integer\");\n\t}\n\tlet es: EventSource | null = null;\n\tlet retryCount = 0;\n\tlet stopped = false;\n\tlet reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n\tlet flushTimer: ReturnType<typeof setTimeout> | null = null;\n\n\t// Helper to apply state changes\n\tconst applyState = (event: ZunoStateEvent) => {\n\t\tif (onEvent) {\n\t\t\tonEvent(event);\n\t\t} else {\n\t\t\t// Fallback default implementation\n\t\t\tif (typeof event.version === \"number\") {\n\t\t\t\tconst current = versions.get(event.storeKey) ?? 0;\n\t\t\t\tif (event.version <= current) return;\n\t\t\t\tversions.set(event.storeKey, event.version);\n\t\t\t}\n\t\t\tconst store = universe.getStore(event.storeKey, () => event.state);\n\t\t\tif (event.intent) {\n\t\t\t\tstore.apply(event.intent);\n\t\t\t} else {\n\t\t\t\tstore.set(event.state);\n\t\t\t}\n\t\t}\n\t};\n\n\t// --- Offline Support ---\n\tconst queue: ZunoStateEvent[] = [];\n\tconst conflictRetries = new Map<string, number>();\n\tlet isFlushing = false;\n\tconst enqueue = (event: ZunoStateEvent) => {\n\t\tif (queue.length >= maxQueueSize) return false;\n\t\tqueue.push(event);\n\t\treturn true;\n\t};\n\tconst scheduleFlush = () => {\n\t\tif (stopped || flushTimer) return;\n\t\tflushTimer = setTimeout(() => {\n\t\t\tflushTimer = null;\n\t\t\tvoid flushQueue();\n\t\t}, 1000);\n\t};\n\n\tasync function flushQueue() {\n\t\tif (stopped) return;\n\t\tif (isFlushing || queue.length === 0) return;\n\t\tif (typeof navigator !== \"undefined\" && !navigator.onLine) return;\n\n\t\tisFlushing = true;\n\n\t\t// --- Coalesce / Deduplicate Logic ---\n\t\t// 1. Map index of first occurrence of each storeKey\n\t\tconst keyIndex = new Map<string, number>();\n\t\t// 2. Reduced queue construction\n\t\tconst reducedQueue: ZunoStateEvent[] = [];\n\n\t\tfor (const event of queue) {\n\t\t\tif (keyIndex.has(event.storeKey)) {\n\t\t\t\t// We've seen this key before. We want to update the existing entry in reducedQueue.\n\t\t\t\t// biome-ignore lint/style/noNonNullAssertion: key exists per has check\n\t\t\t\tconst idx = keyIndex.get(event.storeKey)!;\n\t\t\t\tconst prev = reducedQueue[idx];\n\t\t\t\t// Merge: keep original baseVersion (from the start of the chain) but use NEW state.\n\t\t\t\t// Note: We also likely want to keep the original 'ts' if strictly ordering,\n\t\t\t\t// but state is what matters.\n\t\t\t\t// The 'version' in the event is the *optimistic* version.\n\t\t\t\t// We can keep the *latest* optimistic version (e.g. v10) in the event,\n\t\t\t\t// but server will likely only verify baseVersion.\n\t\t\t\treducedQueue[idx] = { ...event, baseVersion: prev.baseVersion };\n\t\t\t} else {\n\t\t\t\tkeyIndex.set(event.storeKey, reducedQueue.length);\n\t\t\t\treducedQueue.push(event);\n\t\t\t}\n\t\t}\n\n\t\t// Replace original queue with reduced one.\n\t\t// We modify 'queue' in place or reset it.\n\t\t// Since 'queue' is const binding to array, we can't reassign variable,\n\t\t// but we can clear and push.\n\t\tqueue.length = 0;\n\t\tqueue.push(...reducedQueue);\n\n\t\ttry {\n\t\t\twhile (queue.length > 0) {\n\t\t\t\tconst event = queue[0];\n\t\t\t\ttry {\n\t\t\t\t\tconst res = await fetch(syncUrl, {\n\t\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\t\t\t\tbody: JSON.stringify(event),\n\t\t\t\t\t});\n\n\t\t\t\t\tif (!res.ok && res.status !== 409) {\n\t\t\t\t\t\tif (res.status >= 400 && res.status < 500) {\n\t\t\t\t\t\t\tqueue.shift();\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Preserve retryable server failures at the front of the queue.\n\t\t\t\t\t\tscheduleFlush();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (res.status === 409) {\n\t\t\t\t\t\tconst data = await res.json();\n\t\t\t\t\t\tif (data.current) {\n\t\t\t\t\t\t\tconst { state: serverState, version: serverVersion } =\n\t\t\t\t\t\t\t\tdata.current;\n\n\t\t\t\t\t\t\tlet nextState = serverState;\n\t\t\t\t\t\t\tif (resolveConflict) {\n\t\t\t\t\t\t\t\tconst localState = universe\n\t\t\t\t\t\t\t\t\t.getStore(event.storeKey, () => null)\n\t\t\t\t\t\t\t\t\t.get();\n\t\t\t\t\t\t\t\tnextState = resolveConflict(\n\t\t\t\t\t\t\t\t\tlocalState,\n\t\t\t\t\t\t\t\t\tserverState,\n\t\t\t\t\t\t\t\t\tevent.storeKey,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// versions.set(event.storeKey, serverVersion); // REMOVE THIS\n\n\t\t\t\t\t\t\t// 2. Apply resolved state locally\n\t\t\t\t\t\t\tapplyState({\n\t\t\t\t\t\t\t\tstoreKey: event.storeKey,\n\t\t\t\t\t\t\t\tstate: nextState,\n\t\t\t\t\t\t\t\tversion: serverVersion,\n\t\t\t\t\t\t\t\torigin: \"conflict-resolution\",\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t// 3. If resolved state differs from server, auto-sync back\n\t\t\t\t\t\t\tif (JSON.stringify(nextState) !== JSON.stringify(serverState)) {\n\t\t\t\t\t\t\t\tconst attempts = (conflictRetries.get(event.storeKey) ?? 0) + 1;\n\t\t\t\t\t\t\t\tif (attempts > maxConflictRetries) {\n\t\t\t\t\t\t\t\t\tconflictRetries.delete(event.storeKey);\n\t\t\t\t\t\t\t\t\tqueue.shift();\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tconflictRetries.set(event.storeKey, attempts);\n\t\t\t\t\t\t\t\tqueue.unshift({\n\t\t\t\t\t\t\t\t\t...event,\n\t\t\t\t\t\t\t\t\tstate: nextState,\n\t\t\t\t\t\t\t\t\tbaseVersion: serverVersion,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tqueue.shift();\n\t\t\t\t\t} else if (res.ok) {\n\t\t\t\t\t\tconflictRetries.delete(event.storeKey);\n\t\t\t\t\t\tconst json = await res.json();\n\t\t\t\t\t\tif (json.event && typeof json.event.version === \"number\") {\n\t\t\t\t\t\t\t// Just update version map\n\t\t\t\t\t\t\tversions.set(event.storeKey, json.event.version);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tqueue.shift();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tqueue.shift();\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconsole.error(\"[Zuno] Flush failed, retrying later\", err);\n\t\t\t\t\tscheduleFlush();\n\t\t\t\t\tbreak; // Network error, stop flushing\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\tisFlushing = false;\n\t\t}\n\t}\n\tfunction connect() {\n\t\tif (stopped) return;\n\t\tconst lastId = getLastEventId();\n\t\tconst connectUrl = new URL(url, globalThis.location?.href);\n\t\tif (lastId > 0) connectUrl.searchParams.set(\"lastEventId\", String(lastId));\n\n\t\tes = new EventSource(connectUrl.toString());\n\n\t\t// biome-ignore lint/suspicious/noExplicitAny: EventSource data is string, rec is parsed JSON\n\t\tes.addEventListener(\"snapshot\", (e: any) => {\n\t\t\ttry {\n\t\t\t\tconst snapshotEventId = Number.parseInt(e.lastEventId || \"0\", 10);\n\t\t\t\tif (snapshotEventId >= 0) setLastEventId?.(snapshotEventId);\n\t\t\t\tconst snap = JSON.parse(e.data);\n\t\t\t\tfor (const [key, rec] of Object.entries(snap)) {\n\t\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: rec state can be anything\n\t\t\t\t\tconst r = rec as { state: any; version: number };\n\t\t\t\t\tapplyState({\n\t\t\t\t\t\tstoreKey: key,\n\t\t\t\t\t\tstate: r.state,\n\t\t\t\t\t\tversion: r.version,\n\t\t\t\t\t\torigin: \"server\",\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(\"[Zuno] Failed to parse snapshot\", err);\n\t\t\t}\n\t\t});\n\n\t\t// biome-ignore lint/suspicious/noExplicitAny: EventSource event data\n\t\tes.addEventListener(\"state\", (e: any) => {\n\t\t\ttry {\n\t\t\t\tconst event = JSON.parse(e.data) as ZunoStateEvent;\n\t\t\t\t// If server didn't provide an origin (e.g. manual server-side trigger),\n\t\t\t\t// we treat it as authoritative \"server\" origin.\n\t\t\t\tif (!event.origin) {\n\t\t\t\t\tevent.origin = \"server\";\n\t\t\t\t}\n\n\t\t\t\tif (event.origin === clientId) return;\n\n\t\t\t\tapplyState(event);\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(\"[Zuno] Failed to parse SSE event\", err);\n\t\t\t}\n\t\t});\n\n\t\tes.onopen = () => {\n\t\t\tif (stopped) return;\n\t\t\tretryCount = 0;\n\t\t\topts.onOpen?.();\n\t\t\tflushQueue();\n\t\t};\n\n\t\tes.onerror = () => {\n\t\t\tes?.close();\n\t\t\tif (stopped) return;\n\t\t\topts.onClose?.();\n\t\t\tconst delay = Math.min(1000 * 2 ** retryCount, 30000);\n\t\t\tretryCount++;\n\t\t\treconnectTimer = setTimeout(() => {\n\t\t\t\treconnectTimer = null;\n\t\t\t\tconnect();\n\t\t\t}, delay);\n\t\t};\n\t}\n\n\tif (typeof window !== \"undefined\") {\n\t\twindow.addEventListener(\"online\", flushQueue);\n\t}\n\n\tconnect();\n\n\tconst dispatchFn = async (\n\t\tevent: ZunoStateEvent,\n\t\tconflictAttempt = 0,\n\t): Promise<TransportStatus> => {\n\t\ttry {\n\t\t\t// Removed local application here. Local application is handled by coreDispatch\n\t\t\t// to avoid double-update when intents are used.\n\n\t\t\t// 1. Optimistic Local Apply\n\t\t\t// This is needed for direct transport usage (like in tests)\n\t\t\tif (opts.optimistic !== false && !event.origin) {\n\t\t\t\tapplyState(event);\n\t\t\t}\n\n\t\t\t// Check online status first\n\t\t\tif (typeof navigator !== \"undefined\" && !navigator.onLine) {\n\t\t\t\tconst queued = enqueue(event);\n\t\t\t\treturn {\n\t\t\t\t\tok: false,\n\t\t\t\t\tstatus: 0,\n\t\t\t\t\tjson: null,\n\t\t\t\t\treason: queued ? \"OFFLINE_QUEUED\" : \"QUEUE_FULL\",\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst res = await fetch(syncUrl, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\t\tbody: JSON.stringify(event),\n\t\t\t});\n\n\t\t\tif (res.status === 409) {\n\t\t\t\tconst data = await res.json();\n\t\t\t\tif (data.current) {\n\t\t\t\t\tconst { state: serverState, version: serverVersion } = data.current;\n\n\t\t\t\t\tlet nextState = serverState;\n\t\t\t\t\tif (resolveConflict) {\n\t\t\t\t\t\tconst localState = universe\n\t\t\t\t\t\t\t.getStore(event.storeKey, () => null)\n\t\t\t\t\t\t\t.get();\n\t\t\t\t\t\tnextState = resolveConflict(\n\t\t\t\t\t\t\tlocalState,\n\t\t\t\t\t\t\tserverState,\n\t\t\t\t\t\t\tevent.storeKey,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tapplyState({\n\t\t\t\t\t\tstoreKey: event.storeKey,\n\t\t\t\t\t\tstate: nextState,\n\t\t\t\t\t\tversion: serverVersion,\n\t\t\t\t\t\torigin: \"conflict-resolution\",\n\t\t\t\t\t});\n\n\t\t\t\t\tif (JSON.stringify(nextState) !== JSON.stringify(serverState)) {\n\t\t\t\t\t\tif (conflictAttempt >= maxConflictRetries) {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tok: false,\n\t\t\t\t\t\t\t\tstatus: 409,\n\t\t\t\t\t\t\t\tjson: data,\n\t\t\t\t\t\t\t\treason: \"CONFLICT_RETRY_LIMIT\",\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn await dispatchFn(\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t...event,\n\t\t\t\t\t\t\t\tstate: nextState,\n\t\t\t\t\t\t\t\tbaseVersion: serverVersion,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tconflictAttempt + 1,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn { ok: false, status: 409, json: data, reason: \"CONFLICT\" };\n\t\t\t}\n\n\t\t\tif (!res.ok) {\n\t\t\t\tconst json = await res.json();\n\t\t\t\tif (res.status >= 500) {\n\t\t\t\t\tconst queued = enqueue(event);\n\t\t\t\t\tif (queued) scheduleFlush();\n\t\t\t\t\treturn {\n\t\t\t\t\t\tok: false,\n\t\t\t\t\t\tstatus: res.status,\n\t\t\t\t\t\tjson,\n\t\t\t\t\t\treason: queued ? \"SERVER_ERROR_QUEUED\" : \"QUEUE_FULL\",\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn { ok: false, status: res.status, json };\n\t\t\t}\n\n\t\t\tconst json = await res.json();\n\t\t\tif (json.event) {\n\t\t\t\tconst { version } = json.event;\n\t\t\t\tif (typeof version === \"number\") {\n\t\t\t\t\tversions.set(event.storeKey, version);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn { ok: true, status: 200, json };\n\t\t} catch (err) {\n\t\t\t// Network failure catch\n\t\t\tconst queued = enqueue(event);\n\t\t\tif (queued) scheduleFlush();\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\tstatus: 500,\n\t\t\t\tjson: err,\n\t\t\t\treason: queued ? \"NETWORK_ERROR_QUEUED\" : \"QUEUE_FULL\",\n\t\t\t};\n\t\t}\n\t};\n\n\treturn {\n\t\tdispatch: dispatchFn,\n\t\tunsubscribe: () => {\n\t\t\tstopped = true;\n\t\t\tes?.close();\n\t\t\tif (reconnectTimer) clearTimeout(reconnectTimer);\n\t\t\tif (flushTimer) clearTimeout(flushTimer);\n\t\t\tif (typeof window !== \"undefined\") {\n\t\t\t\twindow.removeEventListener(\"online\", flushQueue);\n\t\t\t}\n\t\t},\n\t};\n}\n\n// --- BroadcastChannel ---\n\nexport type BCOptions = {\n\tchannelName: string;\n\tclientId: string;\n\tonEvent: (event: ZunoStateEvent) => void;\n\tgetSnapshot: () => Record<string, { state: unknown; version: number }>;\n\tonSnapshot: (\n\t\tsnap: Record<string, { state: unknown; version: number }>,\n\t) => void;\n};\n\nexport function startBroadcastChannel(opts: BCOptions) {\n\tconst { channelName, clientId, onEvent, getSnapshot, onSnapshot } = opts;\n\tconst channel = new BroadcastChannel(channelName);\n\n\tchannel.onmessage = (e) => {\n\t\tconst msg = e.data;\n\t\tif (msg.origin === clientId) return;\n\n\t\tif (msg.type === \"event\") onEvent(msg.event);\n\t\tif (msg.type === \"hello\")\n\t\t\tchannel.postMessage({\n\t\t\t\ttype: \"snapshot\",\n\t\t\t\tsnapshot: getSnapshot(),\n\t\t\t\torigin: clientId,\n\t\t\t});\n\t\tif (msg.type === \"snapshot\") onSnapshot(msg.snapshot);\n\t};\n\n\treturn {\n\t\tpublish: (event: ZunoStateEvent) =>\n\t\t\tchannel.postMessage({ type: \"event\", event, origin: clientId }),\n\t\thello: () => channel.postMessage({ type: \"hello\", origin: clientId }),\n\t\tstop: () => channel.close(),\n\t};\n}\n","import type {\n\tConflictResolver,\n\tTransportStatus,\n\tZunoStateEvent,\n} from \"../sync\";\nimport { applyIncomingEvent, startBroadcastChannel, startSSE } from \"../sync\";\n\n// --- Types ---\n\n/**\n * Authoritative snapshot of the entire universe.\n */\nexport type ZunoSnapshot = {\n\tstate: Record<string, { state: unknown; version: number }>;\n\tlastEventId: number;\n};\n\n/**\n * A simple state container for a single keyed value.\n */\nexport interface Store<T> {\n\tget(): T;\n\tset(next: T | ((prev: T) => T)): void;\n\tapply(intent: unknown): void;\n\tsubscribe(listener: (state: T) => void): () => void;\n\tequals(val1: unknown, val2: unknown): boolean;\n}\n\n/**\n * A Universe manages many stores.\n */\nexport interface Universe {\n\tgetStore<T>(\n\t\tkey: string,\n\t\tinit: () => T,\n\t\treducer?: (prev: T, intent: unknown) => T,\n\t\tequals?: (v1: unknown, v2: unknown) => boolean,\n\t): Store<T>;\n\tsnapshot(): Record<string, unknown>;\n\trestore(data: Record<string, unknown>): void;\n\tdelete(key: string): void;\n\tclear(): void;\n\thydrateSnapshot(snapshot: ZunoSnapshot): void;\n}\n\n// --- Middleware Types ---\n\nexport type Dispatch = (event: ZunoStateEvent) => Promise<TransportStatus>;\n\nexport type MiddlewareAPI = {\n\tuniverse: Universe;\n\tclientId: string;\n\tversions: Map<string, number>;\n};\n\nexport type Middleware = (api: MiddlewareAPI) => (next: Dispatch) => Dispatch;\n\n/**\n * Options for creating a Zuno instance.\n */\nexport type CreateZunoOptions = {\n\t/** Optional pre-existing universe. */\n\tuniverse?: Universe;\n\t/** BroadcastChannel name for local tab sync. */\n\tchannelName?: string;\n\t/** SSE endpoint URL. */\n\tsseUrl?: string;\n\t/** Sync endpoint URL (required if sseUrl is provided). */\n\tsyncUrl?: string;\n\t/** Apply updates locally before server confirmation (default: true). */\n\toptimistic?: boolean;\n\t/** Batch multiple updates in the same microtask (default: false). */\n\tbatchSync?: boolean;\n\t/** Unique client identifier (default: random UUID). */\n\tclientId?: string;\n\t/** Middleware chain. */\n\tmiddleware?: Middleware[];\n\t/** Optional function to resolve 409 conflicts. */\n\tresolveConflict?: ConflictResolver;\n\t/** Maximum mutations retained while offline (default: 100). */\n\tmaxQueueSize?: number;\n\t/** Maximum automatic retries for a single conflict (default: 3). */\n\tmaxConflictRetries?: number;\n};\n\n/**\n * An extended interface for a Zuno store that includes methods for setting state\n * and a unique key identifier. This represents a store that has been \"bound\" or registered.\n */\nexport type BoundStore<T> = {\n\tkey: string;\n\tget: () => T;\n\tset: (next: T | ((prev: T) => T)) => Promise<unknown>;\n\tsubscribe: (cb: (state: T) => void) => () => void;\n\tequals: (v1: unknown, v2: unknown) => boolean;\n\traw: () => Store<T>;\n};\n\n// --- Store Implementation ---\n\n/**\n * Creates a raw ZUNO state management store.\n */\nexport const createStore = <T>(\n\tinitial: T,\n\treducer?: (prev: T, intent: unknown) => T,\n\tequals: (v1: unknown, v2: unknown) => boolean = Object.is,\n): Store<T> => {\n\tlet state = initial;\n\tconst listeners = new Set<(state: T) => void>();\n\n\tconst notify = () => {\n\t\tlisteners.forEach((l) => {\n\t\t\tl(state);\n\t\t});\n\t};\n\n\treturn {\n\t\tget: () => state,\n\t\tequals,\n\t\tset: (next) => {\n\t\t\tconst value =\n\t\t\t\ttypeof next === \"function\" ? (next as (prev: T) => T)(state) : next;\n\t\t\tif (equals(value, state)) return;\n\t\t\tstate = value;\n\t\t\tnotify();\n\t\t},\n\t\tapply: (intent) => {\n\t\t\tconst i = intent as { type: string; payload?: unknown };\n\t\t\tif (i.type === \"SET\") {\n\t\t\t\tconst value = i.payload as T;\n\t\t\t\tif (equals(value, state)) return;\n\t\t\t\tstate = value;\n\t\t\t\tnotify();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!reducer) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`[Zuno] apply() called for intent \"${i.type}\" on a store without a reducer. Intent ignored.`,\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst nextState = reducer(state, i);\n\t\t\tif (equals(nextState, state)) return;\n\t\t\tstate = nextState;\n\t\t\tnotify();\n\t\t},\n\t\tsubscribe: (listener) => {\n\t\t\tlisteners.add(listener);\n\t\t\treturn () => listeners.delete(listener);\n\t\t},\n\t};\n};\n\n// --- Universe Implementation ---\n\n/**\n * Creates a ZUNO Universe to manage multiple stores.\n */\nexport const createUniverse = (): Universe => {\n\t// biome-ignore lint/suspicious/noExplicitAny: internal registry of heterogeneous stores\n\tconst stores = new Map<string, Store<any>>();\n\tlet cachedSnapshot: Record<string, unknown> | null = null;\n\tconst trackStore = <T>(store: Store<T>) => {\n\t\tstore.subscribe(() => {\n\t\t\tcachedSnapshot = null;\n\t\t});\n\t\treturn store;\n\t};\n\n\tconst universe: Universe = {\n\t\tgetStore<T>(\n\t\t\tkey: string,\n\t\t\tinit: () => T,\n\t\t\treducer?: (prev: T, intent: unknown) => T,\n\t\t\tequals?: (v1: unknown, v2: unknown) => boolean,\n\t\t): Store<T> {\n\t\t\tlet s = stores.get(key);\n\t\t\tif (!s) {\n\t\t\t\ts = trackStore(createStore(init(), reducer, equals));\n\t\t\t\tstores.set(key, s);\n\t\t\t\tcachedSnapshot = null;\n\t\t\t}\n\t\t\treturn s as Store<T>;\n\t\t},\n\t\tsnapshot(): Record<string, unknown> {\n\t\t\tif (cachedSnapshot) return cachedSnapshot;\n\n\t\t\tconst out: Record<string, unknown> = {};\n\t\t\tfor (const [key, store] of stores.entries()) {\n\t\t\t\tout[key] = store.get();\n\t\t\t}\n\t\t\tcachedSnapshot = out;\n\t\t\treturn out;\n\t\t},\n\t\trestore(data: Record<string, unknown>): void {\n\t\t\tfor (const [key, value] of Object.entries(data)) {\n\t\t\t\tconst existing = stores.get(key);\n\t\t\t\tif (existing) {\n\t\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: external data needs to be cast to store type\n\t\t\t\t\texisting.set(value as any);\n\t\t\t\t} else {\n\t\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: external data needs to be cast to store type\n\t\t\t\t\tstores.set(key, trackStore(createStore(value as any)));\n\t\t\t\t\tcachedSnapshot = null;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tdelete(key: string): void {\n\t\t\tstores.delete(key);\n\t\t\tcachedSnapshot = null;\n\t\t},\n\t\tclear(): void {\n\t\t\tstores.clear();\n\t\t\tcachedSnapshot = null;\n\t\t},\n\t\thydrateSnapshot(snapshot: ZunoSnapshot) {\n\t\t\tconst plain: Record<string, unknown> = {};\n\t\t\tfor (const [k, rec] of Object.entries(snapshot.state)) {\n\t\t\t\tplain[k] = rec.state;\n\t\t\t}\n\t\t\tthis.restore(plain);\n\t\t},\n\t};\n\n\treturn universe;\n};\n\n// --- Main Zuno Factory ---\n\n/**\n * Creates a Zuno instance for distributed state synchronization.\n */\nexport const createZuno = (opts: CreateZunoOptions = {}) => {\n\tconst localState = new Map<string, unknown>();\n\tconst versions = new Map<string, number>();\n\tconst universe = opts.universe ?? createUniverse();\n\tconst clientId =\n\t\topts.clientId ?? globalThis.crypto?.randomUUID?.() ?? String(Math.random());\n\tlet _sseReady = false;\n\tlet lastEventId = 0;\n\n\tfunction hydrateSnapshot(snapshot: ZunoSnapshot) {\n\t\tconst plain: Record<string, unknown> = {};\n\t\tfor (const [k, rec] of Object.entries(snapshot.state)) {\n\t\t\tplain[k] = rec.state;\n\t\t\tversions.set(k, rec.version);\n\t\t}\n\t\tuniverse.restore(plain);\n\t\tlastEventId = snapshot.lastEventId;\n\t}\n\n\tconst apply = (event: ZunoStateEvent) => {\n\t\tif (typeof event.eventId === \"number\") {\n\t\t\tlastEventId = Math.max(lastEventId, event.eventId);\n\t\t}\n\t\tapplyIncomingEvent(universe, event, { clientId, localState, versions });\n\t};\n\n\tconst sse =\n\t\topts.sseUrl && opts.syncUrl\n\t\t\t? startSSE({\n\t\t\t\t\tuniverse,\n\t\t\t\t\turl: opts.sseUrl,\n\t\t\t\t\tsyncUrl: opts.syncUrl,\n\t\t\t\t\toptimistic: opts.optimistic ?? true,\n\t\t\t\t\tclientId,\n\t\t\t\t\tversions,\n\t\t\t\t\tgetLastEventId: () => lastEventId,\n\t\t\t\t\tsetLastEventId: (id) => {\n\t\t\t\t\t\tlastEventId = id;\n\t\t\t\t\t},\n\t\t\t\t\tmaxQueueSize: opts.maxQueueSize,\n\t\t\t\t\tmaxConflictRetries: opts.maxConflictRetries,\n\t\t\t\t\tonOpen: () => {\n\t\t\t\t\t\t_sseReady = true;\n\t\t\t\t\t},\n\t\t\t\t\tonClose: () => {\n\t\t\t\t\t\t_sseReady = false;\n\t\t\t\t\t},\n\t\t\t\t\tonEvent: (e) => dispatch(e), // Route incoming SSE events through middleware\n\t\t\t\t\tresolveConflict: opts.resolveConflict,\n\t\t\t\t})\n\t\t\t: null;\n\n\tconst bc = opts.channelName\n\t\t? startBroadcastChannel({\n\t\t\t\tchannelName: opts.channelName,\n\t\t\t\tclientId,\n\t\t\t\tonEvent: (e) => dispatch(e), // Route incoming BC events through middleware\n\t\t\t\tgetSnapshot: () => {\n\t\t\t\t\tconst snap = universe.snapshot();\n\t\t\t\t\tconst out: Record<string, { state: unknown; version: number }> = {};\n\t\t\t\t\tfor (const [storeKey, state] of Object.entries(snap)) {\n\t\t\t\t\t\tout[storeKey] = { state, version: versions.get(storeKey) ?? 0 };\n\t\t\t\t\t}\n\t\t\t\t\treturn out;\n\t\t\t\t},\n\t\t\t\tonSnapshot: (snap) => {\n\t\t\t\t\tfor (const [storeKey, rec] of Object.entries(snap)) {\n\t\t\t\t\t\tapply({ storeKey, state: rec.state, version: rec.version });\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t})\n\t\t: null;\n\n\tsetTimeout(() => bc?.hello(), 100);\n\n\t// --- Sync Batching ---\n\tconst pendingSyncs = new Map<string, ZunoStateEvent>();\n\tlet batchPromise: Promise<void> | null = null;\n\n\tconst flushBatch = async () => {\n\t\tconst syncs = Array.from(pendingSyncs.values());\n\t\tpendingSyncs.clear();\n\t\tbatchPromise = null;\n\n\t\tfor (const event of syncs) {\n\t\t\tif (sse) {\n\t\t\t\tsse.dispatch(event).catch((err) => {\n\t\t\t\t\tconsole.error(\"[Zuno] Batch sync failed\", err);\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t};\n\n\tconst coreDispatch = async (\n\t\tevent: ZunoStateEvent,\n\t): Promise<TransportStatus> => {\n\t\t// 1. Incoming/Reflected Event Logic (events WITH origin)\n\t\tif (event.origin) {\n\t\t\t// Always call apply to let applyIncomingEvent handle version checks and application\n\t\t\tapply(event);\n\n\t\t\t// If it's from another client, we are done\n\t\t\tif (event.origin !== clientId) {\n\t\t\t\treturn { ok: true, status: 200, json: null };\n\t\t\t}\n\t\t\t// If it's a reflected local event, we still need to broadcast it (fall through)\n\t\t}\n\n\t\t// 2. Outgoing Event Logic (events WITHOUT origin)\n\t\tif (!event.origin) {\n\t\t\tevent.origin = clientId;\n\n\t\t\t// Resolve state if needed (e.g. from mutate)\n\t\t\tconst store = universe.getStore(event.storeKey, () => undefined);\n\n\t\t\tif (event.state === undefined && event.intent) {\n\t\t\t\t// We need the state to send to server.\n\t\t\t\t// If optimistic, we apply it. If not, we only compute if it's a simple SET.\n\t\t\t\tif (opts.optimistic !== false) {\n\t\t\t\t\tstore.apply(event.intent);\n\t\t\t\t\tevent.state = store.get();\n\t\t\t\t} else {\n\t\t\t\t\tconst i = event.intent as { type: string; payload?: unknown };\n\t\t\t\t\tif (i.type === \"SET\") {\n\t\t\t\t\t\tevent.state = i.payload;\n\t\t\t\t\t}\n\t\t\t\t\t// For other intents with optimistic: false, we might send undefined state\n\t\t\t\t\t// and rely on the server to compute it authoritativeley.\n\t\t\t\t}\n\t\t\t} else if (event.state !== undefined) {\n\t\t\t\tif (opts.optimistic !== false) {\n\t\t\t\t\tstore.set(event.state as never);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Always send the authoritative version this mutation was based on.\n\t\t\tconst current = versions.get(event.storeKey) ?? 0;\n\t\t\tevent.baseVersion ??= current;\n\n\t\t\t// Local bookkeeping and optimistic versioning\n\t\t\tif (opts.optimistic !== false) {\n\t\t\t\tconst nextVersion = current + 1;\n\t\t\t\tversions.set(event.storeKey, nextVersion);\n\t\t\t\tevent.version = nextVersion;\n\t\t\t}\n\n\t\t\t// BROADCAST IMMEDIATELY to local tabs via BC\n\t\t\t// This ensures instant sync across tabs even if SSE is slow or down.\n\t\t\tif (bc) {\n\t\t\t\tbc.publish(event);\n\t\t\t}\n\t\t}\n\n\t\t// 3. Remote Sync (SSE/HTTP) with Optional Batching\n\t\tif (sse) {\n\t\t\tif (opts.batchSync) {\n\t\t\t\t// Coalesce outgoing syncs for the same storeKey within the same microtask\n\t\t\t\tconst pending = pendingSyncs.get(event.storeKey);\n\t\t\t\tpendingSyncs.set(event.storeKey, {\n\t\t\t\t\t...event,\n\t\t\t\t\tbaseVersion: pending?.baseVersion ?? event.baseVersion,\n\t\t\t\t});\n\n\t\t\t\tif (!batchPromise) {\n\t\t\t\t\tbatchPromise = Promise.resolve().then(flushBatch);\n\t\t\t\t}\n\n\t\t\t\t// Note: Batched dispatch currently returns a \"fake\" OK immediately\n\t\t\t\t// to avoid blocking the UI. Error handling is handled via console.error in flushBatch.\n\t\t\t\t// Real conflict resolution still happens via SSE's internal queue/retry.\n\t\t\t\treturn { ok: true, status: 202, json: { batched: true } };\n\t\t\t}\n\n\t\t\treturn await sse.dispatch(event);\n\t\t}\n\n\t\treturn { ok: true, status: 200, json: null };\n\t};\n\n\t// --- Middleware Composition ---\n\tlet dispatch: Dispatch = coreDispatch;\n\n\tif (opts.middleware && opts.middleware.length > 0) {\n\t\tconst middlewareAPI: MiddlewareAPI = {\n\t\t\tuniverse,\n\t\t\tclientId,\n\t\t\tversions,\n\t\t};\n\t\tconst chain = opts.middleware.map((middleware) =>\n\t\t\tmiddleware(middlewareAPI),\n\t\t);\n\t\tdispatch = chain.reduceRight(\n\t\t\t(next, middleware) => middleware(next),\n\t\t\tcoreDispatch,\n\t\t);\n\t}\n\n\tconst store = <T>(\n\t\tstoreKey: string,\n\t\tinit: () => T,\n\t\treducer?: (prev: T, intent: unknown) => T,\n\t\tequals?: (v1: unknown, v2: unknown) => boolean,\n\t): BoundStore<T> => {\n\t\tconst rawStore = universe.getStore<T>(storeKey, init, reducer, equals);\n\t\treturn {\n\t\t\tkey: storeKey,\n\t\t\traw: () => rawStore,\n\t\t\tget: () => rawStore.get(),\n\t\t\tsubscribe: (cb) => rawStore.subscribe(cb),\n\t\t\tequals: (v1, v2) => rawStore.equals(v1, v2),\n\t\t\tset: (next) => {\n\t\t\t\tconst prev = rawStore.get();\n\t\t\t\tconst state =\n\t\t\t\t\ttypeof next === \"function\" ? (next as (prev: T) => T)(prev) : next;\n\t\t\t\treturn dispatch({\n\t\t\t\t\tstoreKey,\n\t\t\t\t\tstate,\n\t\t\t\t\tintent: { type: \"SET\", payload: state },\n\t\t\t\t});\n\t\t\t},\n\t\t};\n\t};\n\n\treturn {\n\t\tuniverse,\n\t\tclientId,\n\t\tstore,\n\t\tgetStore: universe.getStore.bind(universe),\n\t\tget: <T>(key: string, init?: () => T) =>\n\t\t\tuniverse\n\t\t\t\t.getStore<T>(\n\t\t\t\t\tkey,\n\t\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: default init for convenience\n\t\t\t\t\tinit ?? (() => undefined as any),\n\t\t\t\t)\n\t\t\t\t.get(),\n\t\tset: async <T>(key: string, next: T | ((prev: T) => T), init?: () => T) => {\n\t\t\tconst s = universe.getStore<T>(\n\t\t\t\tkey,\n\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: default init for convenience\n\t\t\t\tinit ?? (() => undefined as any),\n\t\t\t);\n\t\t\tconst state =\n\t\t\t\ttypeof next === \"function\" ? (next as (prev: T) => T)(s.get()) : next;\n\n\t\t\t// Don't set origin or version here, let coreDispatch handle it\n\t\t\treturn dispatch({\n\t\t\t\tstoreKey: key,\n\t\t\t\tstate,\n\t\t\t\tintent: { type: \"SET\", payload: state },\n\t\t\t});\n\t\t},\n\t\tmutate: async (\n\t\t\tkey: string,\n\t\t\tintent: { type: string; payload?: unknown },\n\t\t) => {\n\t\t\treturn dispatch({\n\t\t\t\tstoreKey: key,\n\t\t\t\t// coreDispatch will calculate state from intent\n\t\t\t\tstate: undefined as unknown,\n\t\t\t\tintent,\n\t\t\t});\n\t\t},\n\t\tsubscribe: <T>(key: string, init: () => T, cb: (state: T) => void) =>\n\t\t\tuniverse.getStore<T>(key, init).subscribe(cb),\n\t\tdispatch,\n\t\tstop: () => {\n\t\t\tsse?.unsubscribe?.();\n\t\t\tbc?.stop?.();\n\t\t},\n\t\thydrateSnapshot,\n\t\tgetLastEventId: () => lastEventId,\n\t\tsetLastEventId: (id: number) => {\n\t\t\tlastEventId = id;\n\t\t},\n\t};\n};\n","/** Universal UI adapter contract */\nexport type ZunoReadable<T> = {\n\t/** Read current value (sync) */\n\tgetSnapshot(): T;\n\n\t/**\n\t * Subscribe to changes.\n\t * Call `onChange()` whenever snapshot may have changed.\n\t * Return unsubscribe.\n\t */\n\tsubscribe(onChange: () => void): () => void;\n\n\t/** Optional: React SSR (server snapshot) */\n\tgetServerSnapshot?: () => T;\n};\n\n/** Minimal store shape that can be adapted into a readable */\nexport type ZunoSubscribableStore<T> = {\n\tget(): T;\n\tsubscribe(cb: (state: T) => void): () => void;\n\tequals(v1: unknown, v2: unknown): boolean;\n};\n\n/** Adapter helper: convert store => readable */\nexport function toReadable<T>(\n\tstore: ZunoSubscribableStore<T>,\n): ZunoReadable<T> {\n\treturn {\n\t\tgetSnapshot: () => store.get(),\n\t\tsubscribe: (onChange) => store.subscribe(() => onChange()),\n\t};\n}\n","/**\n * Performs a shallow equality check between two values.\n */\nexport function shallowEqual(a: unknown, b: unknown): boolean {\n\tif (Object.is(a, b)) return true;\n\n\tif (\n\t\ttypeof a !== \"object\" ||\n\t\ta === null ||\n\t\ttypeof b !== \"object\" ||\n\t\tb === null\n\t) {\n\t\treturn false;\n\t}\n\n\tconst keysA = Object.keys(a as object);\n\tconst keysB = Object.keys(b as object);\n\n\tif (keysA.length !== keysB.length) return false;\n\n\tconst objA = a as Record<string, unknown>;\n\tconst objB = b as Record<string, unknown>;\n\n\tfor (const key of keysA) {\n\t\tif (!Object.hasOwn(objB, key) || !Object.is(objA[key], objB[key])) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\n}\n"]}
1
+ {"version":3,"sources":["../src/sync/offline-queue.ts","../src/sync/index.ts","../src/core/index.ts","../src/shared/readable.ts","../src/utils.ts"],"names":["createMemoryOfflineQueue","initialEvents","events","nextEvents","createIndexedDBOfflineQueue","options","databaseName","storeName","queueKey","version","databasePromise","getDatabase","resolve","reject","request","database","transaction","applyIncomingEvent","universe","event","context","clientId","versions","isAuthoritative","current","store","startSSE","opts","url","syncUrl","getLastEventId","setLastEventId","onEvent","resolveConflict","maxQueueSize","maxConflictRetries","offlineQueue","es","retryCount","stopped","reconnectTimer","flushTimer","applyState","queue","queueStorageHealthy","reportQueueStorageError","error","queueReady","storedEvents","conflictRetries","isFlushing","persistQueue","enqueue","queueReason","result","queuedReason","scheduleFlush","flushQueue","keyIndex","reducedQueue","idx","prev","res","data","serverState","serverVersion","nextState","localState","attempts","json","err","connect","lastId","connectUrl","e","snapshotEventId","snap","key","rec","r","delay","dispatchFn","conflictAttempt","queued","startBroadcastChannel","channelName","getSnapshot","onSnapshot","channel","msg","createStore","initial","reducer","equals","state","listeners","notify","l","next","value","intent","i","listener","createUniverse","stores","cachedSnapshot","trackStore","init","s","out","existing","snapshot","plain","k","createZuno","lastEventId","hydrateSnapshot","apply","sse","id","dispatch","bc","storeKey","pendingSyncs","batchPromise","flushBatch","syncs","coreDispatch","nextVersion","pending","middlewareAPI","middleware","rawStore","cb","v1","v2","toReadable","onChange","shallowEqual","a","b","keysA","keysB","objA","objB"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { ZunoStateEvent } from \"./index\";\n\n/** Storage contract used by the SSE client to persist queued mutations. */\nexport interface ZunoOfflineQueue {\n\tload(): Promise<ZunoStateEvent[]>;\n\tsave(events: readonly ZunoStateEvent[]): Promise<void>;\n}\n\n/** In-memory queue storage. Useful as the default and for custom integrations/tests. */\nexport function createMemoryOfflineQueue(\n\tinitialEvents: readonly ZunoStateEvent[] = [],\n): ZunoOfflineQueue {\n\tlet events: ZunoStateEvent[] = structuredClone([...initialEvents]);\n\treturn {\n\t\tasync load() {\n\t\t\treturn structuredClone(events);\n\t\t},\n\t\tasync save(nextEvents) {\n\t\t\tevents = structuredClone([...nextEvents]);\n\t\t},\n\t};\n}\n\nexport type IndexedDBOfflineQueueOptions = {\n\t/** IndexedDB database name (default: \"zuno\"). */\n\tdatabaseName?: string;\n\t/** Object-store name (default: \"offline-queues\"). */\n\tstoreName?: string;\n\t/** Key used for this client/namespace queue (default: \"default\"). */\n\tqueueKey?: string;\n\t/** IndexedDB schema version (default: 1). */\n\tversion?: number;\n};\n\n/** Creates durable browser queue storage backed by IndexedDB. */\nexport function createIndexedDBOfflineQueue(\n\toptions: IndexedDBOfflineQueueOptions = {},\n): ZunoOfflineQueue {\n\tconst databaseName = options.databaseName ?? \"zuno\";\n\tconst storeName = options.storeName ?? \"offline-queues\";\n\tconst queueKey = options.queueKey ?? \"default\";\n\tconst version = options.version ?? 1;\n\tif (!Number.isInteger(version) || version < 1) {\n\t\tthrow new TypeError(\"version must be a positive integer\");\n\t}\n\n\tlet databasePromise: Promise<IDBDatabase> | undefined;\n\tconst getDatabase = () => {\n\t\tif (typeof indexedDB === \"undefined\") {\n\t\t\treturn Promise.reject(\n\t\t\t\tnew Error(\"IndexedDB is not available in this environment\"),\n\t\t\t);\n\t\t}\n\t\tif (!databasePromise) {\n\t\t\tdatabasePromise = new Promise((resolve, reject) => {\n\t\t\t\tconst request = indexedDB.open(databaseName, version);\n\t\t\t\trequest.onupgradeneeded = () => {\n\t\t\t\t\tif (!request.result.objectStoreNames.contains(storeName)) {\n\t\t\t\t\t\trequest.result.createObjectStore(storeName);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\trequest.onsuccess = () => resolve(request.result);\n\t\t\t\trequest.onerror = () => reject(request.error);\n\t\t\t\trequest.onblocked = () =>\n\t\t\t\t\treject(new Error(`IndexedDB database \"${databaseName}\" is blocked`));\n\t\t\t});\n\t\t}\n\t\treturn databasePromise;\n\t};\n\n\treturn {\n\t\tasync load() {\n\t\t\tconst database = await getDatabase();\n\t\t\treturn await new Promise<ZunoStateEvent[]>((resolve, reject) => {\n\t\t\t\tconst request = database\n\t\t\t\t\t.transaction(storeName, \"readonly\")\n\t\t\t\t\t.objectStore(storeName)\n\t\t\t\t\t.get(queueKey);\n\t\t\t\trequest.onsuccess = () =>\n\t\t\t\t\tresolve(Array.isArray(request.result) ? request.result : []);\n\t\t\t\trequest.onerror = () => reject(request.error);\n\t\t\t});\n\t\t},\n\t\tasync save(events) {\n\t\t\tconst database = await getDatabase();\n\t\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\t\tconst transaction = database.transaction(storeName, \"readwrite\");\n\t\t\t\ttransaction.objectStore(storeName).put([...events], queueKey);\n\t\t\t\ttransaction.oncomplete = () => resolve();\n\t\t\t\ttransaction.onerror = () => reject(transaction.error);\n\t\t\t\ttransaction.onabort = () => reject(transaction.error);\n\t\t\t});\n\t\t},\n\t};\n}\n","import type { Universe } from \"../core\";\nimport {\n\tcreateMemoryOfflineQueue,\n\ttype ZunoOfflineQueue,\n} from \"./offline-queue\";\n\nexport type {\n\tIndexedDBOfflineQueueOptions,\n\tZunoOfflineQueue,\n} from \"./offline-queue\";\nexport {\n\tcreateIndexedDBOfflineQueue,\n\tcreateMemoryOfflineQueue,\n} from \"./offline-queue\";\n\n// --- Types ---\n\nexport type ConflictResolver<T = unknown> = (\n\tlocalState: T,\n\tserverState: T,\n\tstoreKey: string,\n) => T;\n\n/**\n * Authoritative state event.\n */\nexport type ZunoStateEvent = {\n\tstoreKey: string;\n\tstate: unknown; // Was 'any', now strictly 'unknown'\n\tintent?: { type: string; payload?: unknown };\n\tversion?: number;\n\tbaseVersion?: number;\n\torigin?: string;\n\tts?: number;\n\teventId?: number;\n};\n\n/**\n * Generic transport status.\n */\nexport type TransportStatus = {\n\tok: boolean;\n\tstatus: number;\n\t// biome-ignore lint/suspicious/noExplicitAny: generic JSON response\n\tjson: any;\n\treason?: string;\n};\n\n/**\n * Client transport interface.\n */\nexport interface ZunoTransport {\n\tdispatch(event: ZunoStateEvent): Promise<TransportStatus>;\n\tunsubscribe?(): void;\n}\n\n/**\n * Apply incoming event to the universe and local bookkeeping.\n */\nexport function applyIncomingEvent(\n\tuniverse: Universe,\n\tevent: ZunoStateEvent,\n\tcontext: {\n\t\tclientId: string;\n\t\tlocalState: Map<string, unknown>;\n\t\tversions: Map<string, number>;\n\t},\n) {\n\tconst { clientId, versions } = context;\n\n\t// 1. Determine if this event is Authoritative (from Server) or Optimistic (from Peer/Local)\n\tconst isAuthoritative =\n\t\tevent.origin === \"server\" || event.origin === \"conflict-resolution\";\n\tconst current = versions.get(event.storeKey) ?? 0;\n\n\t// 2. Version check\n\tif (typeof event.version === \"number\") {\n\t\t// If it's not authoritative, we strictly enforce incrementing versions\n\t\tif (!isAuthoritative && event.version <= current) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Update version tracker\n\t\tversions.set(event.storeKey, event.version);\n\t} else if (event.origin === clientId) {\n\t\t// Suppress versionless loopback\n\t\treturn;\n\t}\n\n\t// 3. Apply to universe\n\tconst store = universe.getStore(event.storeKey, () => event.state);\n\n\t// If we have an intent, try to apply it first for side effects (but only if it's forward progress or authoritative)\n\tif (event.intent) {\n\t\t// If it's a version match/stale authoritative event, we might want to SKIP the intent\n\t\t// to avoid double-application (since we likely already did it optimistically).\n\t\t// However, snapping state (below) is always safe.\n\t\tif (\n\t\t\ttypeof event.version === \"number\" &&\n\t\t\tevent.version <= current &&\n\t\t\tisAuthoritative\n\t\t) {\n\t\t\t// Skip intent, but snap state anyway below.\n\t\t} else {\n\t\t\tstore.apply(event.intent);\n\t\t}\n\t}\n\n\t// 4. Authoritative State Snap\n\t// ALWAYS apply the state if provided and it's authoritative or has a higher version.\n\tif (event.state !== undefined) {\n\t\tif (\n\t\t\tisAuthoritative ||\n\t\t\t(typeof event.version === \"number\" && event.version > current)\n\t\t) {\n\t\t\tstore.set(event.state);\n\t\t}\n\t}\n}\n\n// --- SSE Client ---\n\nexport type SSEOptions = {\n\tuniverse: Universe;\n\turl: string;\n\tsyncUrl: string;\n\toptimistic: boolean;\n\tclientId: string;\n\tversions: Map<string, number>;\n\tgetLastEventId: () => number;\n\tsetLastEventId?: (id: number) => void;\n\t/** Maximum number of mutations retained while offline (default: 100). */\n\tmaxQueueSize?: number;\n\t/** Maximum automatic retries for a single conflict (default: 3). */\n\tmaxConflictRetries?: number;\n\t/** Queue persistence provider (default: an in-memory provider). */\n\tofflineQueue?: ZunoOfflineQueue;\n\tonOpen?: () => void;\n\tonClose?: () => void;\n\tonEvent?: (event: ZunoStateEvent) => void;\n\tresolveConflict?: ConflictResolver;\n};\n\nexport function startSSE(opts: SSEOptions): ZunoTransport {\n\tconst {\n\t\turl,\n\t\tsyncUrl,\n\t\tuniverse,\n\t\tclientId,\n\t\tversions,\n\t\tgetLastEventId,\n\t\tsetLastEventId,\n\t\tonEvent,\n\t\tresolveConflict,\n\t} = opts;\n\tconst maxQueueSize = opts.maxQueueSize ?? 100;\n\tconst maxConflictRetries = opts.maxConflictRetries ?? 3;\n\tconst offlineQueue = opts.offlineQueue ?? createMemoryOfflineQueue();\n\tif (!Number.isInteger(maxQueueSize) || maxQueueSize < 1) {\n\t\tthrow new TypeError(\"maxQueueSize must be a positive integer\");\n\t}\n\tif (!Number.isInteger(maxConflictRetries) || maxConflictRetries < 0) {\n\t\tthrow new TypeError(\"maxConflictRetries must be a non-negative integer\");\n\t}\n\tlet es: EventSource | null = null;\n\tlet retryCount = 0;\n\tlet stopped = false;\n\tlet reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n\tlet flushTimer: ReturnType<typeof setTimeout> | null = null;\n\n\t// Helper to apply state changes\n\tconst applyState = (event: ZunoStateEvent) => {\n\t\tif (onEvent) {\n\t\t\tonEvent(event);\n\t\t} else {\n\t\t\t// Fallback default implementation\n\t\t\tif (typeof event.version === \"number\") {\n\t\t\t\tconst current = versions.get(event.storeKey) ?? 0;\n\t\t\t\tif (event.version <= current) return;\n\t\t\t\tversions.set(event.storeKey, event.version);\n\t\t\t}\n\t\t\tconst store = universe.getStore(event.storeKey, () => event.state);\n\t\t\tif (event.intent) {\n\t\t\t\tstore.apply(event.intent);\n\t\t\t} else {\n\t\t\t\tstore.set(event.state);\n\t\t\t}\n\t\t}\n\t};\n\n\t// --- Offline Support ---\n\tconst queue: ZunoStateEvent[] = [];\n\tlet queueStorageHealthy = true;\n\tconst reportQueueStorageError = (error: unknown) => {\n\t\tqueueStorageHealthy = false;\n\t\tconsole.error(\"[Zuno] Offline queue storage failed\", error);\n\t};\n\tconst queueReady = offlineQueue\n\t\t.load()\n\t\t.then(async (storedEvents) => {\n\t\t\tqueue.push(...storedEvents.slice(0, maxQueueSize));\n\t\t\tif (storedEvents.length > maxQueueSize) {\n\t\t\t\ttry {\n\t\t\t\t\tawait offlineQueue.save(queue);\n\t\t\t\t} catch (error) {\n\t\t\t\t\treportQueueStorageError(error);\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t\t.catch(reportQueueStorageError);\n\tconst conflictRetries = new Map<string, number>();\n\tlet isFlushing = false;\n\tconst persistQueue = async () => {\n\t\ttry {\n\t\t\tawait offlineQueue.save(queue);\n\t\t\tqueueStorageHealthy = true;\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\treportQueueStorageError(error);\n\t\t\treturn false;\n\t\t}\n\t};\n\tconst enqueue = async (event: ZunoStateEvent) => {\n\t\tawait queueReady;\n\t\tif (!queueStorageHealthy) return \"storage-error\" as const;\n\t\tif (queue.length >= maxQueueSize) return \"full\" as const;\n\t\tqueue.push(event);\n\t\tif (!(await persistQueue())) {\n\t\t\tqueue.pop();\n\t\t\treturn \"storage-error\" as const;\n\t\t}\n\t\treturn \"queued\" as const;\n\t};\n\tconst queueReason = (\n\t\tresult: \"queued\" | \"full\" | \"storage-error\",\n\t\tqueuedReason: string,\n\t) => {\n\t\tif (result === \"queued\") return queuedReason;\n\t\tif (result === \"full\") return \"QUEUE_FULL\";\n\t\treturn \"QUEUE_STORAGE_ERROR\";\n\t};\n\tconst scheduleFlush = () => {\n\t\tif (stopped || flushTimer) return;\n\t\tflushTimer = setTimeout(() => {\n\t\t\tflushTimer = null;\n\t\t\tvoid flushQueue();\n\t\t}, 1000);\n\t};\n\n\tasync function flushQueue() {\n\t\tif (stopped) return;\n\t\tawait queueReady;\n\t\tif (isFlushing || queue.length === 0) return;\n\t\tif (typeof navigator !== \"undefined\" && !navigator.onLine) return;\n\n\t\tisFlushing = true;\n\n\t\t// --- Coalesce / Deduplicate Logic ---\n\t\t// 1. Map index of first occurrence of each storeKey\n\t\tconst keyIndex = new Map<string, number>();\n\t\t// 2. Reduced queue construction\n\t\tconst reducedQueue: ZunoStateEvent[] = [];\n\n\t\tfor (const event of queue) {\n\t\t\tif (keyIndex.has(event.storeKey)) {\n\t\t\t\t// We've seen this key before. We want to update the existing entry in reducedQueue.\n\t\t\t\t// biome-ignore lint/style/noNonNullAssertion: key exists per has check\n\t\t\t\tconst idx = keyIndex.get(event.storeKey)!;\n\t\t\t\tconst prev = reducedQueue[idx];\n\t\t\t\t// Merge: keep original baseVersion (from the start of the chain) but use NEW state.\n\t\t\t\t// Note: We also likely want to keep the original 'ts' if strictly ordering,\n\t\t\t\t// but state is what matters.\n\t\t\t\t// The 'version' in the event is the *optimistic* version.\n\t\t\t\t// We can keep the *latest* optimistic version (e.g. v10) in the event,\n\t\t\t\t// but server will likely only verify baseVersion.\n\t\t\t\treducedQueue[idx] = { ...event, baseVersion: prev.baseVersion };\n\t\t\t} else {\n\t\t\t\tkeyIndex.set(event.storeKey, reducedQueue.length);\n\t\t\t\treducedQueue.push(event);\n\t\t\t}\n\t\t}\n\n\t\t// Replace original queue with reduced one.\n\t\t// We modify 'queue' in place or reset it.\n\t\t// Since 'queue' is const binding to array, we can't reassign variable,\n\t\t// but we can clear and push.\n\t\tqueue.length = 0;\n\t\tqueue.push(...reducedQueue);\n\t\tawait persistQueue();\n\n\t\ttry {\n\t\t\twhile (queue.length > 0) {\n\t\t\t\tconst event = queue[0];\n\t\t\t\ttry {\n\t\t\t\t\tconst res = await fetch(syncUrl, {\n\t\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\t\t\t\tbody: JSON.stringify(event),\n\t\t\t\t\t});\n\n\t\t\t\t\tif (!res.ok && res.status !== 409) {\n\t\t\t\t\t\tif (res.status >= 400 && res.status < 500) {\n\t\t\t\t\t\t\tqueue.shift();\n\t\t\t\t\t\t\tawait persistQueue();\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Preserve retryable server failures at the front of the queue.\n\t\t\t\t\t\tscheduleFlush();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (res.status === 409) {\n\t\t\t\t\t\tconst data = await res.json();\n\t\t\t\t\t\tif (data.current) {\n\t\t\t\t\t\t\tconst { state: serverState, version: serverVersion } =\n\t\t\t\t\t\t\t\tdata.current;\n\n\t\t\t\t\t\t\tlet nextState = serverState;\n\t\t\t\t\t\t\tif (resolveConflict) {\n\t\t\t\t\t\t\t\tconst localState = universe\n\t\t\t\t\t\t\t\t\t.getStore(event.storeKey, () => null)\n\t\t\t\t\t\t\t\t\t.get();\n\t\t\t\t\t\t\t\tnextState = resolveConflict(\n\t\t\t\t\t\t\t\t\tlocalState,\n\t\t\t\t\t\t\t\t\tserverState,\n\t\t\t\t\t\t\t\t\tevent.storeKey,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// versions.set(event.storeKey, serverVersion); // REMOVE THIS\n\n\t\t\t\t\t\t\t// 2. Apply resolved state locally\n\t\t\t\t\t\t\tapplyState({\n\t\t\t\t\t\t\t\tstoreKey: event.storeKey,\n\t\t\t\t\t\t\t\tstate: nextState,\n\t\t\t\t\t\t\t\tversion: serverVersion,\n\t\t\t\t\t\t\t\torigin: \"conflict-resolution\",\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t// 3. If resolved state differs from server, auto-sync back\n\t\t\t\t\t\t\tif (JSON.stringify(nextState) !== JSON.stringify(serverState)) {\n\t\t\t\t\t\t\t\tconst attempts = (conflictRetries.get(event.storeKey) ?? 0) + 1;\n\t\t\t\t\t\t\t\tif (attempts > maxConflictRetries) {\n\t\t\t\t\t\t\t\t\tconflictRetries.delete(event.storeKey);\n\t\t\t\t\t\t\t\t\tqueue.shift();\n\t\t\t\t\t\t\t\t\tawait persistQueue();\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tconflictRetries.set(event.storeKey, attempts);\n\t\t\t\t\t\t\t\tqueue.unshift({\n\t\t\t\t\t\t\t\t\t...event,\n\t\t\t\t\t\t\t\t\tstate: nextState,\n\t\t\t\t\t\t\t\t\tbaseVersion: serverVersion,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tqueue.shift();\n\t\t\t\t\t\tawait persistQueue();\n\t\t\t\t\t} else if (res.ok) {\n\t\t\t\t\t\tconflictRetries.delete(event.storeKey);\n\t\t\t\t\t\tconst json = await res.json();\n\t\t\t\t\t\tif (json.event && typeof json.event.version === \"number\") {\n\t\t\t\t\t\t\t// Just update version map\n\t\t\t\t\t\t\tversions.set(event.storeKey, json.event.version);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tqueue.shift();\n\t\t\t\t\t\tawait persistQueue();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tqueue.shift();\n\t\t\t\t\t\tawait persistQueue();\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconsole.error(\"[Zuno] Flush failed, retrying later\", err);\n\t\t\t\t\tscheduleFlush();\n\t\t\t\t\tbreak; // Network error, stop flushing\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\tisFlushing = false;\n\t\t}\n\t}\n\tfunction connect() {\n\t\tif (stopped) return;\n\t\tconst lastId = getLastEventId();\n\t\tconst connectUrl = new URL(url, globalThis.location?.href);\n\t\tif (lastId > 0) connectUrl.searchParams.set(\"lastEventId\", String(lastId));\n\n\t\tes = new EventSource(connectUrl.toString());\n\n\t\t// biome-ignore lint/suspicious/noExplicitAny: EventSource data is string, rec is parsed JSON\n\t\tes.addEventListener(\"snapshot\", (e: any) => {\n\t\t\ttry {\n\t\t\t\tconst snapshotEventId = Number.parseInt(e.lastEventId || \"0\", 10);\n\t\t\t\tif (snapshotEventId >= 0) setLastEventId?.(snapshotEventId);\n\t\t\t\tconst snap = JSON.parse(e.data);\n\t\t\t\tfor (const [key, rec] of Object.entries(snap)) {\n\t\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: rec state can be anything\n\t\t\t\t\tconst r = rec as { state: any; version: number };\n\t\t\t\t\tapplyState({\n\t\t\t\t\t\tstoreKey: key,\n\t\t\t\t\t\tstate: r.state,\n\t\t\t\t\t\tversion: r.version,\n\t\t\t\t\t\torigin: \"server\",\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(\"[Zuno] Failed to parse snapshot\", err);\n\t\t\t}\n\t\t});\n\n\t\t// biome-ignore lint/suspicious/noExplicitAny: EventSource event data\n\t\tes.addEventListener(\"state\", (e: any) => {\n\t\t\ttry {\n\t\t\t\tconst event = JSON.parse(e.data) as ZunoStateEvent;\n\t\t\t\t// If server didn't provide an origin (e.g. manual server-side trigger),\n\t\t\t\t// we treat it as authoritative \"server\" origin.\n\t\t\t\tif (!event.origin) {\n\t\t\t\t\tevent.origin = \"server\";\n\t\t\t\t}\n\n\t\t\t\tif (event.origin === clientId) return;\n\n\t\t\t\tapplyState(event);\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(\"[Zuno] Failed to parse SSE event\", err);\n\t\t\t}\n\t\t});\n\n\t\tes.onopen = () => {\n\t\t\tif (stopped) return;\n\t\t\tretryCount = 0;\n\t\t\topts.onOpen?.();\n\t\t\tflushQueue();\n\t\t};\n\n\t\tes.onerror = () => {\n\t\t\tes?.close();\n\t\t\tif (stopped) return;\n\t\t\topts.onClose?.();\n\t\t\tconst delay = Math.min(1000 * 2 ** retryCount, 30000);\n\t\t\tretryCount++;\n\t\t\treconnectTimer = setTimeout(() => {\n\t\t\t\treconnectTimer = null;\n\t\t\t\tconnect();\n\t\t\t}, delay);\n\t\t};\n\t}\n\n\tif (typeof window !== \"undefined\") {\n\t\twindow.addEventListener(\"online\", flushQueue);\n\t}\n\n\tconnect();\n\n\tconst dispatchFn = async (\n\t\tevent: ZunoStateEvent,\n\t\tconflictAttempt = 0,\n\t): Promise<TransportStatus> => {\n\t\ttry {\n\t\t\t// Removed local application here. Local application is handled by coreDispatch\n\t\t\t// to avoid double-update when intents are used.\n\n\t\t\t// 1. Optimistic Local Apply\n\t\t\t// This is needed for direct transport usage (like in tests)\n\t\t\tif (opts.optimistic !== false && !event.origin) {\n\t\t\t\tapplyState(event);\n\t\t\t}\n\n\t\t\t// Check online status first\n\t\t\tif (typeof navigator !== \"undefined\" && !navigator.onLine) {\n\t\t\t\tconst queued = await enqueue(event);\n\t\t\t\treturn {\n\t\t\t\t\tok: false,\n\t\t\t\t\tstatus: 0,\n\t\t\t\t\tjson: null,\n\t\t\t\t\treason: queueReason(queued, \"OFFLINE_QUEUED\"),\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst res = await fetch(syncUrl, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\t\tbody: JSON.stringify(event),\n\t\t\t});\n\n\t\t\tif (res.status === 409) {\n\t\t\t\tconst data = await res.json();\n\t\t\t\tif (data.current) {\n\t\t\t\t\tconst { state: serverState, version: serverVersion } = data.current;\n\n\t\t\t\t\tlet nextState = serverState;\n\t\t\t\t\tif (resolveConflict) {\n\t\t\t\t\t\tconst localState = universe\n\t\t\t\t\t\t\t.getStore(event.storeKey, () => null)\n\t\t\t\t\t\t\t.get();\n\t\t\t\t\t\tnextState = resolveConflict(\n\t\t\t\t\t\t\tlocalState,\n\t\t\t\t\t\t\tserverState,\n\t\t\t\t\t\t\tevent.storeKey,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tapplyState({\n\t\t\t\t\t\tstoreKey: event.storeKey,\n\t\t\t\t\t\tstate: nextState,\n\t\t\t\t\t\tversion: serverVersion,\n\t\t\t\t\t\torigin: \"conflict-resolution\",\n\t\t\t\t\t});\n\n\t\t\t\t\tif (JSON.stringify(nextState) !== JSON.stringify(serverState)) {\n\t\t\t\t\t\tif (conflictAttempt >= maxConflictRetries) {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tok: false,\n\t\t\t\t\t\t\t\tstatus: 409,\n\t\t\t\t\t\t\t\tjson: data,\n\t\t\t\t\t\t\t\treason: \"CONFLICT_RETRY_LIMIT\",\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn await dispatchFn(\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t...event,\n\t\t\t\t\t\t\t\tstate: nextState,\n\t\t\t\t\t\t\t\tbaseVersion: serverVersion,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tconflictAttempt + 1,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn { ok: false, status: 409, json: data, reason: \"CONFLICT\" };\n\t\t\t}\n\n\t\t\tif (!res.ok) {\n\t\t\t\tconst json = await res.json();\n\t\t\t\tif (res.status >= 500) {\n\t\t\t\t\tconst queued = await enqueue(event);\n\t\t\t\t\tif (queued === \"queued\") scheduleFlush();\n\t\t\t\t\treturn {\n\t\t\t\t\t\tok: false,\n\t\t\t\t\t\tstatus: res.status,\n\t\t\t\t\t\tjson,\n\t\t\t\t\t\treason: queueReason(queued, \"SERVER_ERROR_QUEUED\"),\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn { ok: false, status: res.status, json };\n\t\t\t}\n\n\t\t\tconst json = await res.json();\n\t\t\tif (json.event) {\n\t\t\t\tconst { version } = json.event;\n\t\t\t\tif (typeof version === \"number\") {\n\t\t\t\t\tversions.set(event.storeKey, version);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn { ok: true, status: 200, json };\n\t\t} catch (err) {\n\t\t\t// Network failure catch\n\t\t\tconst queued = await enqueue(event);\n\t\t\tif (queued === \"queued\") scheduleFlush();\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\tstatus: 500,\n\t\t\t\tjson: err,\n\t\t\t\treason: queueReason(queued, \"NETWORK_ERROR_QUEUED\"),\n\t\t\t};\n\t\t}\n\t};\n\n\treturn {\n\t\tdispatch: dispatchFn,\n\t\tunsubscribe: () => {\n\t\t\tstopped = true;\n\t\t\tes?.close();\n\t\t\tif (reconnectTimer) clearTimeout(reconnectTimer);\n\t\t\tif (flushTimer) clearTimeout(flushTimer);\n\t\t\tif (typeof window !== \"undefined\") {\n\t\t\t\twindow.removeEventListener(\"online\", flushQueue);\n\t\t\t}\n\t\t},\n\t};\n}\n\n// --- BroadcastChannel ---\n\nexport type BCOptions = {\n\tchannelName: string;\n\tclientId: string;\n\tonEvent: (event: ZunoStateEvent) => void;\n\tgetSnapshot: () => Record<string, { state: unknown; version: number }>;\n\tonSnapshot: (\n\t\tsnap: Record<string, { state: unknown; version: number }>,\n\t) => void;\n};\n\nexport function startBroadcastChannel(opts: BCOptions) {\n\tconst { channelName, clientId, onEvent, getSnapshot, onSnapshot } = opts;\n\tconst channel = new BroadcastChannel(channelName);\n\n\tchannel.onmessage = (e) => {\n\t\tconst msg = e.data;\n\t\tif (msg.origin === clientId) return;\n\n\t\tif (msg.type === \"event\") onEvent(msg.event);\n\t\tif (msg.type === \"hello\")\n\t\t\tchannel.postMessage({\n\t\t\t\ttype: \"snapshot\",\n\t\t\t\tsnapshot: getSnapshot(),\n\t\t\t\torigin: clientId,\n\t\t\t});\n\t\tif (msg.type === \"snapshot\") onSnapshot(msg.snapshot);\n\t};\n\n\treturn {\n\t\tpublish: (event: ZunoStateEvent) =>\n\t\t\tchannel.postMessage({ type: \"event\", event, origin: clientId }),\n\t\thello: () => channel.postMessage({ type: \"hello\", origin: clientId }),\n\t\tstop: () => channel.close(),\n\t};\n}\n","import type {\n\tConflictResolver,\n\tTransportStatus,\n\tZunoOfflineQueue,\n\tZunoStateEvent,\n} from \"../sync\";\nimport { applyIncomingEvent, startBroadcastChannel, startSSE } from \"../sync\";\n\n// --- Types ---\n\n/**\n * Authoritative snapshot of the entire universe.\n */\nexport type ZunoSnapshot = {\n\tstate: Record<string, { state: unknown; version: number }>;\n\tlastEventId: number;\n};\n\n/**\n * A simple state container for a single keyed value.\n */\nexport interface Store<T> {\n\tget(): T;\n\tset(next: T | ((prev: T) => T)): void;\n\tapply(intent: unknown): void;\n\tsubscribe(listener: (state: T) => void): () => void;\n\tequals(val1: unknown, val2: unknown): boolean;\n}\n\n/**\n * A Universe manages many stores.\n */\nexport interface Universe {\n\tgetStore<T>(\n\t\tkey: string,\n\t\tinit: () => T,\n\t\treducer?: (prev: T, intent: unknown) => T,\n\t\tequals?: (v1: unknown, v2: unknown) => boolean,\n\t): Store<T>;\n\tsnapshot(): Record<string, unknown>;\n\trestore(data: Record<string, unknown>): void;\n\tdelete(key: string): void;\n\tclear(): void;\n\thydrateSnapshot(snapshot: ZunoSnapshot): void;\n}\n\n// --- Middleware Types ---\n\nexport type Dispatch = (event: ZunoStateEvent) => Promise<TransportStatus>;\n\nexport type MiddlewareAPI = {\n\tuniverse: Universe;\n\tclientId: string;\n\tversions: Map<string, number>;\n};\n\nexport type Middleware = (api: MiddlewareAPI) => (next: Dispatch) => Dispatch;\n\n/**\n * Options for creating a Zuno instance.\n */\nexport type CreateZunoOptions = {\n\t/** Optional pre-existing universe. */\n\tuniverse?: Universe;\n\t/** BroadcastChannel name for local tab sync. */\n\tchannelName?: string;\n\t/** SSE endpoint URL. */\n\tsseUrl?: string;\n\t/** Sync endpoint URL (required if sseUrl is provided). */\n\tsyncUrl?: string;\n\t/** Apply updates locally before server confirmation (default: true). */\n\toptimistic?: boolean;\n\t/** Batch multiple updates in the same microtask (default: false). */\n\tbatchSync?: boolean;\n\t/** Unique client identifier (default: random UUID). */\n\tclientId?: string;\n\t/** Middleware chain. */\n\tmiddleware?: Middleware[];\n\t/** Optional function to resolve 409 conflicts. */\n\tresolveConflict?: ConflictResolver;\n\t/** Maximum mutations retained while offline (default: 100). */\n\tmaxQueueSize?: number;\n\t/** Maximum automatic retries for a single conflict (default: 3). */\n\tmaxConflictRetries?: number;\n\t/** Optional durable queue used for offline/server-error mutations. */\n\tofflineQueue?: ZunoOfflineQueue;\n};\n\n/**\n * An extended interface for a Zuno store that includes methods for setting state\n * and a unique key identifier. This represents a store that has been \"bound\" or registered.\n */\nexport type BoundStore<T> = {\n\tkey: string;\n\tget: () => T;\n\tset: (next: T | ((prev: T) => T)) => Promise<unknown>;\n\tsubscribe: (cb: (state: T) => void) => () => void;\n\tequals: (v1: unknown, v2: unknown) => boolean;\n\traw: () => Store<T>;\n};\n\n// --- Store Implementation ---\n\n/**\n * Creates a raw ZUNO state management store.\n */\nexport const createStore = <T>(\n\tinitial: T,\n\treducer?: (prev: T, intent: unknown) => T,\n\tequals: (v1: unknown, v2: unknown) => boolean = Object.is,\n): Store<T> => {\n\tlet state = initial;\n\tconst listeners = new Set<(state: T) => void>();\n\n\tconst notify = () => {\n\t\tlisteners.forEach((l) => {\n\t\t\tl(state);\n\t\t});\n\t};\n\n\treturn {\n\t\tget: () => state,\n\t\tequals,\n\t\tset: (next) => {\n\t\t\tconst value =\n\t\t\t\ttypeof next === \"function\" ? (next as (prev: T) => T)(state) : next;\n\t\t\tif (equals(value, state)) return;\n\t\t\tstate = value;\n\t\t\tnotify();\n\t\t},\n\t\tapply: (intent) => {\n\t\t\tconst i = intent as { type: string; payload?: unknown };\n\t\t\tif (i.type === \"SET\") {\n\t\t\t\tconst value = i.payload as T;\n\t\t\t\tif (equals(value, state)) return;\n\t\t\t\tstate = value;\n\t\t\t\tnotify();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!reducer) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`[Zuno] apply() called for intent \"${i.type}\" on a store without a reducer. Intent ignored.`,\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst nextState = reducer(state, i);\n\t\t\tif (equals(nextState, state)) return;\n\t\t\tstate = nextState;\n\t\t\tnotify();\n\t\t},\n\t\tsubscribe: (listener) => {\n\t\t\tlisteners.add(listener);\n\t\t\treturn () => listeners.delete(listener);\n\t\t},\n\t};\n};\n\n// --- Universe Implementation ---\n\n/**\n * Creates a ZUNO Universe to manage multiple stores.\n */\nexport const createUniverse = (): Universe => {\n\t// biome-ignore lint/suspicious/noExplicitAny: internal registry of heterogeneous stores\n\tconst stores = new Map<string, Store<any>>();\n\tlet cachedSnapshot: Record<string, unknown> | null = null;\n\tconst trackStore = <T>(store: Store<T>) => {\n\t\tstore.subscribe(() => {\n\t\t\tcachedSnapshot = null;\n\t\t});\n\t\treturn store;\n\t};\n\n\tconst universe: Universe = {\n\t\tgetStore<T>(\n\t\t\tkey: string,\n\t\t\tinit: () => T,\n\t\t\treducer?: (prev: T, intent: unknown) => T,\n\t\t\tequals?: (v1: unknown, v2: unknown) => boolean,\n\t\t): Store<T> {\n\t\t\tlet s = stores.get(key);\n\t\t\tif (!s) {\n\t\t\t\ts = trackStore(createStore(init(), reducer, equals));\n\t\t\t\tstores.set(key, s);\n\t\t\t\tcachedSnapshot = null;\n\t\t\t}\n\t\t\treturn s as Store<T>;\n\t\t},\n\t\tsnapshot(): Record<string, unknown> {\n\t\t\tif (cachedSnapshot) return cachedSnapshot;\n\n\t\t\tconst out: Record<string, unknown> = {};\n\t\t\tfor (const [key, store] of stores.entries()) {\n\t\t\t\tout[key] = store.get();\n\t\t\t}\n\t\t\tcachedSnapshot = out;\n\t\t\treturn out;\n\t\t},\n\t\trestore(data: Record<string, unknown>): void {\n\t\t\tfor (const [key, value] of Object.entries(data)) {\n\t\t\t\tconst existing = stores.get(key);\n\t\t\t\tif (existing) {\n\t\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: external data needs to be cast to store type\n\t\t\t\t\texisting.set(value as any);\n\t\t\t\t} else {\n\t\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: external data needs to be cast to store type\n\t\t\t\t\tstores.set(key, trackStore(createStore(value as any)));\n\t\t\t\t\tcachedSnapshot = null;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tdelete(key: string): void {\n\t\t\tstores.delete(key);\n\t\t\tcachedSnapshot = null;\n\t\t},\n\t\tclear(): void {\n\t\t\tstores.clear();\n\t\t\tcachedSnapshot = null;\n\t\t},\n\t\thydrateSnapshot(snapshot: ZunoSnapshot) {\n\t\t\tconst plain: Record<string, unknown> = {};\n\t\t\tfor (const [k, rec] of Object.entries(snapshot.state)) {\n\t\t\t\tplain[k] = rec.state;\n\t\t\t}\n\t\t\tthis.restore(plain);\n\t\t},\n\t};\n\n\treturn universe;\n};\n\n// --- Main Zuno Factory ---\n\n/**\n * Creates a Zuno instance for distributed state synchronization.\n */\nexport const createZuno = (opts: CreateZunoOptions = {}) => {\n\tconst localState = new Map<string, unknown>();\n\tconst versions = new Map<string, number>();\n\tconst universe = opts.universe ?? createUniverse();\n\tconst clientId =\n\t\topts.clientId ?? globalThis.crypto?.randomUUID?.() ?? String(Math.random());\n\tlet _sseReady = false;\n\tlet lastEventId = 0;\n\n\tfunction hydrateSnapshot(snapshot: ZunoSnapshot) {\n\t\tconst plain: Record<string, unknown> = {};\n\t\tfor (const [k, rec] of Object.entries(snapshot.state)) {\n\t\t\tplain[k] = rec.state;\n\t\t\tversions.set(k, rec.version);\n\t\t}\n\t\tuniverse.restore(plain);\n\t\tlastEventId = snapshot.lastEventId;\n\t}\n\n\tconst apply = (event: ZunoStateEvent) => {\n\t\tif (typeof event.eventId === \"number\") {\n\t\t\tlastEventId = Math.max(lastEventId, event.eventId);\n\t\t}\n\t\tapplyIncomingEvent(universe, event, { clientId, localState, versions });\n\t};\n\n\tconst sse =\n\t\topts.sseUrl && opts.syncUrl\n\t\t\t? startSSE({\n\t\t\t\t\tuniverse,\n\t\t\t\t\turl: opts.sseUrl,\n\t\t\t\t\tsyncUrl: opts.syncUrl,\n\t\t\t\t\toptimistic: opts.optimistic ?? true,\n\t\t\t\t\tclientId,\n\t\t\t\t\tversions,\n\t\t\t\t\tgetLastEventId: () => lastEventId,\n\t\t\t\t\tsetLastEventId: (id) => {\n\t\t\t\t\t\tlastEventId = id;\n\t\t\t\t\t},\n\t\t\t\t\tmaxQueueSize: opts.maxQueueSize,\n\t\t\t\t\tmaxConflictRetries: opts.maxConflictRetries,\n\t\t\t\t\tofflineQueue: opts.offlineQueue,\n\t\t\t\t\tonOpen: () => {\n\t\t\t\t\t\t_sseReady = true;\n\t\t\t\t\t},\n\t\t\t\t\tonClose: () => {\n\t\t\t\t\t\t_sseReady = false;\n\t\t\t\t\t},\n\t\t\t\t\tonEvent: (e) => dispatch(e), // Route incoming SSE events through middleware\n\t\t\t\t\tresolveConflict: opts.resolveConflict,\n\t\t\t\t})\n\t\t\t: null;\n\n\tconst bc = opts.channelName\n\t\t? startBroadcastChannel({\n\t\t\t\tchannelName: opts.channelName,\n\t\t\t\tclientId,\n\t\t\t\tonEvent: (e) => dispatch(e), // Route incoming BC events through middleware\n\t\t\t\tgetSnapshot: () => {\n\t\t\t\t\tconst snap = universe.snapshot();\n\t\t\t\t\tconst out: Record<string, { state: unknown; version: number }> = {};\n\t\t\t\t\tfor (const [storeKey, state] of Object.entries(snap)) {\n\t\t\t\t\t\tout[storeKey] = { state, version: versions.get(storeKey) ?? 0 };\n\t\t\t\t\t}\n\t\t\t\t\treturn out;\n\t\t\t\t},\n\t\t\t\tonSnapshot: (snap) => {\n\t\t\t\t\tfor (const [storeKey, rec] of Object.entries(snap)) {\n\t\t\t\t\t\tapply({ storeKey, state: rec.state, version: rec.version });\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t})\n\t\t: null;\n\n\tsetTimeout(() => bc?.hello(), 100);\n\n\t// --- Sync Batching ---\n\tconst pendingSyncs = new Map<string, ZunoStateEvent>();\n\tlet batchPromise: Promise<void> | null = null;\n\n\tconst flushBatch = async () => {\n\t\tconst syncs = Array.from(pendingSyncs.values());\n\t\tpendingSyncs.clear();\n\t\tbatchPromise = null;\n\n\t\tfor (const event of syncs) {\n\t\t\tif (sse) {\n\t\t\t\tsse.dispatch(event).catch((err) => {\n\t\t\t\t\tconsole.error(\"[Zuno] Batch sync failed\", err);\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t};\n\n\tconst coreDispatch = async (\n\t\tevent: ZunoStateEvent,\n\t): Promise<TransportStatus> => {\n\t\t// 1. Incoming/Reflected Event Logic (events WITH origin)\n\t\tif (event.origin) {\n\t\t\t// Always call apply to let applyIncomingEvent handle version checks and application\n\t\t\tapply(event);\n\n\t\t\t// If it's from another client, we are done\n\t\t\tif (event.origin !== clientId) {\n\t\t\t\treturn { ok: true, status: 200, json: null };\n\t\t\t}\n\t\t\t// If it's a reflected local event, we still need to broadcast it (fall through)\n\t\t}\n\n\t\t// 2. Outgoing Event Logic (events WITHOUT origin)\n\t\tif (!event.origin) {\n\t\t\tevent.origin = clientId;\n\n\t\t\t// Resolve state if needed (e.g. from mutate)\n\t\t\tconst store = universe.getStore(event.storeKey, () => undefined);\n\n\t\t\tif (event.state === undefined && event.intent) {\n\t\t\t\t// We need the state to send to server.\n\t\t\t\t// If optimistic, we apply it. If not, we only compute if it's a simple SET.\n\t\t\t\tif (opts.optimistic !== false) {\n\t\t\t\t\tstore.apply(event.intent);\n\t\t\t\t\tevent.state = store.get();\n\t\t\t\t} else {\n\t\t\t\t\tconst i = event.intent as { type: string; payload?: unknown };\n\t\t\t\t\tif (i.type === \"SET\") {\n\t\t\t\t\t\tevent.state = i.payload;\n\t\t\t\t\t}\n\t\t\t\t\t// For other intents with optimistic: false, we might send undefined state\n\t\t\t\t\t// and rely on the server to compute it authoritativeley.\n\t\t\t\t}\n\t\t\t} else if (event.state !== undefined) {\n\t\t\t\tif (opts.optimistic !== false) {\n\t\t\t\t\tstore.set(event.state as never);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Always send the authoritative version this mutation was based on.\n\t\t\tconst current = versions.get(event.storeKey) ?? 0;\n\t\t\tevent.baseVersion ??= current;\n\n\t\t\t// Local bookkeeping and optimistic versioning\n\t\t\tif (opts.optimistic !== false) {\n\t\t\t\tconst nextVersion = current + 1;\n\t\t\t\tversions.set(event.storeKey, nextVersion);\n\t\t\t\tevent.version = nextVersion;\n\t\t\t}\n\n\t\t\t// BROADCAST IMMEDIATELY to local tabs via BC\n\t\t\t// This ensures instant sync across tabs even if SSE is slow or down.\n\t\t\tif (bc) {\n\t\t\t\tbc.publish(event);\n\t\t\t}\n\t\t}\n\n\t\t// 3. Remote Sync (SSE/HTTP) with Optional Batching\n\t\tif (sse) {\n\t\t\tif (opts.batchSync) {\n\t\t\t\t// Coalesce outgoing syncs for the same storeKey within the same microtask\n\t\t\t\tconst pending = pendingSyncs.get(event.storeKey);\n\t\t\t\tpendingSyncs.set(event.storeKey, {\n\t\t\t\t\t...event,\n\t\t\t\t\tbaseVersion: pending?.baseVersion ?? event.baseVersion,\n\t\t\t\t});\n\n\t\t\t\tif (!batchPromise) {\n\t\t\t\t\tbatchPromise = Promise.resolve().then(flushBatch);\n\t\t\t\t}\n\n\t\t\t\t// Note: Batched dispatch currently returns a \"fake\" OK immediately\n\t\t\t\t// to avoid blocking the UI. Error handling is handled via console.error in flushBatch.\n\t\t\t\t// Real conflict resolution still happens via SSE's internal queue/retry.\n\t\t\t\treturn { ok: true, status: 202, json: { batched: true } };\n\t\t\t}\n\n\t\t\treturn await sse.dispatch(event);\n\t\t}\n\n\t\treturn { ok: true, status: 200, json: null };\n\t};\n\n\t// --- Middleware Composition ---\n\tlet dispatch: Dispatch = coreDispatch;\n\n\tif (opts.middleware && opts.middleware.length > 0) {\n\t\tconst middlewareAPI: MiddlewareAPI = {\n\t\t\tuniverse,\n\t\t\tclientId,\n\t\t\tversions,\n\t\t};\n\t\tconst chain = opts.middleware.map((middleware) =>\n\t\t\tmiddleware(middlewareAPI),\n\t\t);\n\t\tdispatch = chain.reduceRight(\n\t\t\t(next, middleware) => middleware(next),\n\t\t\tcoreDispatch,\n\t\t);\n\t}\n\n\tconst store = <T>(\n\t\tstoreKey: string,\n\t\tinit: () => T,\n\t\treducer?: (prev: T, intent: unknown) => T,\n\t\tequals?: (v1: unknown, v2: unknown) => boolean,\n\t): BoundStore<T> => {\n\t\tconst rawStore = universe.getStore<T>(storeKey, init, reducer, equals);\n\t\treturn {\n\t\t\tkey: storeKey,\n\t\t\traw: () => rawStore,\n\t\t\tget: () => rawStore.get(),\n\t\t\tsubscribe: (cb) => rawStore.subscribe(cb),\n\t\t\tequals: (v1, v2) => rawStore.equals(v1, v2),\n\t\t\tset: (next) => {\n\t\t\t\tconst prev = rawStore.get();\n\t\t\t\tconst state =\n\t\t\t\t\ttypeof next === \"function\" ? (next as (prev: T) => T)(prev) : next;\n\t\t\t\treturn dispatch({\n\t\t\t\t\tstoreKey,\n\t\t\t\t\tstate,\n\t\t\t\t\tintent: { type: \"SET\", payload: state },\n\t\t\t\t});\n\t\t\t},\n\t\t};\n\t};\n\n\treturn {\n\t\tuniverse,\n\t\tclientId,\n\t\tstore,\n\t\tgetStore: universe.getStore.bind(universe),\n\t\tget: <T>(key: string, init?: () => T) =>\n\t\t\tuniverse\n\t\t\t\t.getStore<T>(\n\t\t\t\t\tkey,\n\t\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: default init for convenience\n\t\t\t\t\tinit ?? (() => undefined as any),\n\t\t\t\t)\n\t\t\t\t.get(),\n\t\tset: async <T>(key: string, next: T | ((prev: T) => T), init?: () => T) => {\n\t\t\tconst s = universe.getStore<T>(\n\t\t\t\tkey,\n\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: default init for convenience\n\t\t\t\tinit ?? (() => undefined as any),\n\t\t\t);\n\t\t\tconst state =\n\t\t\t\ttypeof next === \"function\" ? (next as (prev: T) => T)(s.get()) : next;\n\n\t\t\t// Don't set origin or version here, let coreDispatch handle it\n\t\t\treturn dispatch({\n\t\t\t\tstoreKey: key,\n\t\t\t\tstate,\n\t\t\t\tintent: { type: \"SET\", payload: state },\n\t\t\t});\n\t\t},\n\t\tmutate: async (\n\t\t\tkey: string,\n\t\t\tintent: { type: string; payload?: unknown },\n\t\t) => {\n\t\t\treturn dispatch({\n\t\t\t\tstoreKey: key,\n\t\t\t\t// coreDispatch will calculate state from intent\n\t\t\t\tstate: undefined as unknown,\n\t\t\t\tintent,\n\t\t\t});\n\t\t},\n\t\tsubscribe: <T>(key: string, init: () => T, cb: (state: T) => void) =>\n\t\t\tuniverse.getStore<T>(key, init).subscribe(cb),\n\t\tdispatch,\n\t\tstop: () => {\n\t\t\tsse?.unsubscribe?.();\n\t\t\tbc?.stop?.();\n\t\t},\n\t\thydrateSnapshot,\n\t\tgetLastEventId: () => lastEventId,\n\t\tsetLastEventId: (id: number) => {\n\t\t\tlastEventId = id;\n\t\t},\n\t};\n};\n","/** Universal UI adapter contract */\nexport type ZunoReadable<T> = {\n\t/** Read current value (sync) */\n\tgetSnapshot(): T;\n\n\t/**\n\t * Subscribe to changes.\n\t * Call `onChange()` whenever snapshot may have changed.\n\t * Return unsubscribe.\n\t */\n\tsubscribe(onChange: () => void): () => void;\n\n\t/** Optional: React SSR (server snapshot) */\n\tgetServerSnapshot?: () => T;\n};\n\n/** Minimal store shape that can be adapted into a readable */\nexport type ZunoSubscribableStore<T> = {\n\tget(): T;\n\tsubscribe(cb: (state: T) => void): () => void;\n\tequals(v1: unknown, v2: unknown): boolean;\n};\n\n/** Adapter helper: convert store => readable */\nexport function toReadable<T>(\n\tstore: ZunoSubscribableStore<T>,\n): ZunoReadable<T> {\n\treturn {\n\t\tgetSnapshot: () => store.get(),\n\t\tsubscribe: (onChange) => store.subscribe(() => onChange()),\n\t};\n}\n","/**\n * Performs a shallow equality check between two values.\n */\nexport function shallowEqual(a: unknown, b: unknown): boolean {\n\tif (Object.is(a, b)) return true;\n\n\tif (\n\t\ttypeof a !== \"object\" ||\n\t\ta === null ||\n\t\ttypeof b !== \"object\" ||\n\t\tb === null\n\t) {\n\t\treturn false;\n\t}\n\n\tconst keysA = Object.keys(a as object);\n\tconst keysB = Object.keys(b as object);\n\n\tif (keysA.length !== keysB.length) return false;\n\n\tconst objA = a as Record<string, unknown>;\n\tconst objB = b as Record<string, unknown>;\n\n\tfor (const key of keysA) {\n\t\tif (!Object.hasOwn(objB, key) || !Object.is(objA[key], objB[key])) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- export { k as BCOptions, B as BoundStore, e as ConflictResolver, C as CreateZunoOptions, D as Dispatch, M as Middleware, a as MiddlewareAPI, j as SSEOptions, S as Store, T as TransportStatus, U as Universe, Z as ZunoSnapshot, f as ZunoStateEvent, g as ZunoTransport, h as applyIncomingEvent, c as createStore, b as createUniverse, d as createZuno, s as startBroadcastChannel, i as startSSE } from './index-3uqI2fJ2.cjs';
1
+ export { k as BCOptions, B as BoundStore, e as ConflictResolver, C as CreateZunoOptions, D as Dispatch, I as IndexedDBOfflineQueueOptions, M as Middleware, a as MiddlewareAPI, j as SSEOptions, S as Store, T as TransportStatus, U as Universe, l as ZunoOfflineQueue, Z as ZunoSnapshot, f as ZunoStateEvent, g as ZunoTransport, h as applyIncomingEvent, m as createIndexedDBOfflineQueue, n as createMemoryOfflineQueue, c as createStore, b as createUniverse, d as createZuno, s as startBroadcastChannel, i as startSSE } from './index-BSBSRWd0.cjs';
2
2
 
3
3
  /** Universal UI adapter contract */
4
4
  type ZunoReadable<T> = {
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { k as BCOptions, B as BoundStore, e as ConflictResolver, C as CreateZunoOptions, D as Dispatch, M as Middleware, a as MiddlewareAPI, j as SSEOptions, S as Store, T as TransportStatus, U as Universe, Z as ZunoSnapshot, f as ZunoStateEvent, g as ZunoTransport, h as applyIncomingEvent, c as createStore, b as createUniverse, d as createZuno, s as startBroadcastChannel, i as startSSE } from './index-3uqI2fJ2.js';
1
+ export { k as BCOptions, B as BoundStore, e as ConflictResolver, C as CreateZunoOptions, D as Dispatch, I as IndexedDBOfflineQueueOptions, M as Middleware, a as MiddlewareAPI, j as SSEOptions, S as Store, T as TransportStatus, U as Universe, l as ZunoOfflineQueue, Z as ZunoSnapshot, f as ZunoStateEvent, g as ZunoTransport, h as applyIncomingEvent, m as createIndexedDBOfflineQueue, n as createMemoryOfflineQueue, c as createStore, b as createUniverse, d as createZuno, s as startBroadcastChannel, i as startSSE } from './index-BSBSRWd0.js';
2
2
 
3
3
  /** Universal UI adapter contract */
4
4
  type ZunoReadable<T> = {
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- function L(t,n,p){let{clientId:a,versions:r}=p,l=n.origin==="server"||n.origin==="conflict-resolution",o=r.get(n.storeKey)??0;if(typeof n.version=="number"){if(!l&&n.version<=o)return;r.set(n.storeKey,n.version);}else if(n.origin===a)return;let d=t.getStore(n.storeKey,()=>n.state);n.intent&&(typeof n.version=="number"&&n.version<=o&&l||d.apply(n.intent)),n.state!==void 0&&(l||typeof n.version=="number"&&n.version>o)&&d.set(n.state);}function M(t){let{url:n,syncUrl:p,universe:a,clientId:r,versions:l,getLastEventId:o,setLastEventId:d,onEvent:g,resolveConflict:b}=t,I=t.maxQueueSize??100,x=t.maxConflictRetries??3;if(!Number.isInteger(I)||I<1)throw new TypeError("maxQueueSize must be a positive integer");if(!Number.isInteger(x)||x<0)throw new TypeError("maxConflictRetries must be a non-negative integer");let k=null,j=0,R=false,h=null,U=null,e=u=>{if(g)g(u);else {if(typeof u.version=="number"){let i=l.get(u.storeKey)??0;if(u.version<=i)return;l.set(u.storeKey,u.version);}let S=a.getStore(u.storeKey,()=>u.state);u.intent?S.apply(u.intent):S.set(u.state);}},s=[],f=new Map,v=false,m=u=>s.length>=I?false:(s.push(u),true),T=()=>{R||U||(U=setTimeout(()=>{U=null,Z();},1e3));};async function Z(){if(R||v||s.length===0||typeof navigator<"u"&&!navigator.onLine)return;v=true;let u=new Map,S=[];for(let i of s)if(u.has(i.storeKey)){let c=u.get(i.storeKey),y=S[c];S[c]={...i,baseVersion:y.baseVersion};}else u.set(i.storeKey,S.length),S.push(i);s.length=0,s.push(...S);try{for(;s.length>0;){let i=s[0];try{let c=await fetch(p,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)});if(!c.ok&&c.status!==409){if(c.status>=400&&c.status<500){s.shift();continue}T();break}if(c.status===409){let y=await c.json();if(y.current){let{state:w,version:O}=y.current,E=w;if(b){let C=a.getStore(i.storeKey,()=>null).get();E=b(C,w,i.storeKey);}if(e({storeKey:i.storeKey,state:E,version:O,origin:"conflict-resolution"}),JSON.stringify(E)!==JSON.stringify(w)){let C=(f.get(i.storeKey)??0)+1;if(C>x){f.delete(i.storeKey),s.shift();continue}f.set(i.storeKey,C),s.unshift({...i,state:E,baseVersion:O});continue}}s.shift();}else if(c.ok){f.delete(i.storeKey);let y=await c.json();y.event&&typeof y.event.version=="number"&&l.set(i.storeKey,y.event.version),s.shift();}else s.shift();}catch(c){console.error("[Zuno] Flush failed, retrying later",c),T();break}}}finally{v=false;}}function K(){if(R)return;let u=o(),S=new URL(n,globalThis.location?.href);u>0&&S.searchParams.set("lastEventId",String(u)),k=new EventSource(S.toString()),k.addEventListener("snapshot",i=>{try{let c=Number.parseInt(i.lastEventId||"0",10);c>=0&&d?.(c);let y=JSON.parse(i.data);for(let[w,O]of Object.entries(y)){let E=O;e({storeKey:w,state:E.state,version:E.version,origin:"server"});}}catch(c){console.error("[Zuno] Failed to parse snapshot",c);}}),k.addEventListener("state",i=>{try{let c=JSON.parse(i.data);if(c.origin||(c.origin="server"),c.origin===r)return;e(c);}catch(c){console.error("[Zuno] Failed to parse SSE event",c);}}),k.onopen=()=>{R||(j=0,t.onOpen?.(),Z());},k.onerror=()=>{if(k?.close(),R)return;t.onClose?.();let i=Math.min(1e3*2**j,3e4);j++,h=setTimeout(()=>{h=null,K();},i);};}typeof window<"u"&&window.addEventListener("online",Z),K();let Q=async(u,S=0)=>{try{if(t.optimistic!==!1&&!u.origin&&e(u),typeof navigator<"u"&&!navigator.onLine)return {ok:!1,status:0,json:null,reason:m(u)?"OFFLINE_QUEUED":"QUEUE_FULL"};let i=await fetch(p,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(u)});if(i.status===409){let y=await i.json();if(y.current){let{state:w,version:O}=y.current,E=w;if(b){let C=a.getStore(u.storeKey,()=>null).get();E=b(C,w,u.storeKey);}if(e({storeKey:u.storeKey,state:E,version:O,origin:"conflict-resolution"}),JSON.stringify(E)!==JSON.stringify(w))return S>=x?{ok:!1,status:409,json:y,reason:"CONFLICT_RETRY_LIMIT"}:await Q({...u,state:E,baseVersion:O},S+1)}return {ok:!1,status:409,json:y,reason:"CONFLICT"}}if(!i.ok){let y=await i.json();if(i.status>=500){let w=m(u);return w&&T(),{ok:!1,status:i.status,json:y,reason:w?"SERVER_ERROR_QUEUED":"QUEUE_FULL"}}return {ok:!1,status:i.status,json:y}}let c=await i.json();if(c.event){let{version:y}=c.event;typeof y=="number"&&l.set(u.storeKey,y);}return {ok:!0,status:200,json:c}}catch(i){let c=m(u);return c&&T(),{ok:false,status:500,json:i,reason:c?"NETWORK_ERROR_QUEUED":"QUEUE_FULL"}}};return {dispatch:Q,unsubscribe:()=>{R=true,k?.close(),h&&clearTimeout(h),U&&clearTimeout(U),typeof window<"u"&&window.removeEventListener("online",Z);}}}function N(t){let{channelName:n,clientId:p,onEvent:a,getSnapshot:r,onSnapshot:l}=t,o=new BroadcastChannel(n);return o.onmessage=d=>{let g=d.data;g.origin!==p&&(g.type==="event"&&a(g.event),g.type==="hello"&&o.postMessage({type:"snapshot",snapshot:r(),origin:p}),g.type==="snapshot"&&l(g.snapshot));},{publish:d=>o.postMessage({type:"event",event:d,origin:p}),hello:()=>o.postMessage({type:"hello",origin:p}),stop:()=>o.close()}}var P=(t,n,p=Object.is)=>{let a=t,r=new Set,l=()=>{r.forEach(o=>{o(a);});};return {get:()=>a,equals:p,set:o=>{let d=typeof o=="function"?o(a):o;p(d,a)||(a=d,l());},apply:o=>{let d=o;if(d.type==="SET"){let b=d.payload;if(p(b,a))return;a=b,l();return}if(!n){console.warn(`[Zuno] apply() called for intent "${d.type}" on a store without a reducer. Intent ignored.`);return}let g=n(a,d);p(g,a)||(a=g,l());},subscribe:o=>(r.add(o),()=>r.delete(o))}},B=()=>{let t=new Map,n=null,p=r=>(r.subscribe(()=>{n=null;}),r);return {getStore(r,l,o,d){let g=t.get(r);return g||(g=p(P(l(),o,d)),t.set(r,g),n=null),g},snapshot(){if(n)return n;let r={};for(let[l,o]of t.entries())r[l]=o.get();return n=r,r},restore(r){for(let[l,o]of Object.entries(r)){let d=t.get(l);d?d.set(o):(t.set(l,p(P(o))),n=null);}},delete(r){t.delete(r),n=null;},clear(){t.clear(),n=null;},hydrateSnapshot(r){let l={};for(let[o,d]of Object.entries(r.state))l[o]=d.state;this.restore(l);}}},F=(t={})=>{let p=new Map,a=t.universe??B(),r=t.clientId??globalThis.crypto?.randomUUID?.()??String(Math.random()),o=0;function d(e){let s={};for(let[f,v]of Object.entries(e.state))s[f]=v.state,p.set(f,v.version);a.restore(s),o=e.lastEventId;}let g=e=>{typeof e.eventId=="number"&&(o=Math.max(o,e.eventId)),L(a,e,{clientId:r,versions:p});},b=t.sseUrl&&t.syncUrl?M({universe:a,url:t.sseUrl,syncUrl:t.syncUrl,optimistic:t.optimistic??true,clientId:r,versions:p,getLastEventId:()=>o,setLastEventId:e=>{o=e;},maxQueueSize:t.maxQueueSize,maxConflictRetries:t.maxConflictRetries,onOpen:()=>{},onClose:()=>{},onEvent:e=>h(e),resolveConflict:t.resolveConflict}):null,I=t.channelName?N({channelName:t.channelName,clientId:r,onEvent:e=>h(e),getSnapshot:()=>{let e=a.snapshot(),s={};for(let[f,v]of Object.entries(e))s[f]={state:v,version:p.get(f)??0};return s},onSnapshot:e=>{for(let[s,f]of Object.entries(e))g({storeKey:s,state:f.state,version:f.version});}}):null;setTimeout(()=>I?.hello(),100);let x=new Map,k=null,j=async()=>{let e=Array.from(x.values());x.clear(),k=null;for(let s of e)b&&b.dispatch(s).catch(f=>{console.error("[Zuno] Batch sync failed",f);});},R=async e=>{if(e.origin&&(g(e),e.origin!==r))return {ok:true,status:200,json:null};if(!e.origin){e.origin=r;let s=a.getStore(e.storeKey,()=>{});if(e.state===void 0&&e.intent)if(t.optimistic!==false)s.apply(e.intent),e.state=s.get();else {let v=e.intent;v.type==="SET"&&(e.state=v.payload);}else e.state!==void 0&&t.optimistic!==false&&s.set(e.state);let f=p.get(e.storeKey)??0;if(e.baseVersion??(e.baseVersion=f),t.optimistic!==false){let v=f+1;p.set(e.storeKey,v),e.version=v;}I&&I.publish(e);}if(b){if(t.batchSync){let s=x.get(e.storeKey);return x.set(e.storeKey,{...e,baseVersion:s?.baseVersion??e.baseVersion}),k||(k=Promise.resolve().then(j)),{ok:true,status:202,json:{batched:true}}}return await b.dispatch(e)}return {ok:true,status:200,json:null}},h=R;if(t.middleware&&t.middleware.length>0){let e={universe:a,clientId:r,versions:p};h=t.middleware.map(f=>f(e)).reduceRight((f,v)=>v(f),R);}return {universe:a,clientId:r,store:(e,s,f,v)=>{let m=a.getStore(e,s,f,v);return {key:e,raw:()=>m,get:()=>m.get(),subscribe:T=>m.subscribe(T),equals:(T,Z)=>m.equals(T,Z),set:T=>{let Z=m.get(),K=typeof T=="function"?T(Z):T;return h({storeKey:e,state:K,intent:{type:"SET",payload:K}})}}},getStore:a.getStore.bind(a),get:(e,s)=>a.getStore(e,s??(()=>{})).get(),set:async(e,s,f)=>{let v=a.getStore(e,f??(()=>{})),m=typeof s=="function"?s(v.get()):s;return h({storeKey:e,state:m,intent:{type:"SET",payload:m}})},mutate:async(e,s)=>h({storeKey:e,state:void 0,intent:s}),subscribe:(e,s,f)=>a.getStore(e,s).subscribe(f),dispatch:h,stop:()=>{b?.unsubscribe?.(),I?.stop?.();},hydrateSnapshot:d,getLastEventId:()=>o,setLastEventId:e=>{o=e;}}};function V(t){return {getSnapshot:()=>t.get(),subscribe:n=>t.subscribe(()=>n())}}function q(t,n){if(Object.is(t,n))return true;if(typeof t!="object"||t===null||typeof n!="object"||n===null)return false;let p=Object.keys(t),a=Object.keys(n);if(p.length!==a.length)return false;let r=t,l=n;for(let o of p)if(!Object.hasOwn(l,o)||!Object.is(r[o],l[o]))return false;return true}export{L as applyIncomingEvent,P as createStore,B as createUniverse,F as createZuno,q as shallowEqual,N as startBroadcastChannel,M as startSSE,V as toReadable};//# sourceMappingURL=index.js.map
1
+ function B(t=[]){let n=structuredClone([...t]);return {async load(){return structuredClone(n)},async save(u){n=structuredClone([...u]);}}}function J(t={}){let n=t.databaseName??"zuno",u=t.storeName??"offline-queues",a=t.queueKey??"default",i=t.version??1;if(!Number.isInteger(i)||i<1)throw new TypeError("version must be a positive integer");let l,r=()=>typeof indexedDB>"u"?Promise.reject(new Error("IndexedDB is not available in this environment")):(l||(l=new Promise((p,y)=>{let g=indexedDB.open(n,i);g.onupgradeneeded=()=>{g.result.objectStoreNames.contains(u)||g.result.createObjectStore(u);},g.onsuccess=()=>p(g.result),g.onerror=()=>y(g.error),g.onblocked=()=>y(new Error(`IndexedDB database "${n}" is blocked`));})),l);return {async load(){let p=await r();return await new Promise((y,g)=>{let S=p.transaction(u,"readonly").objectStore(u).get(a);S.onsuccess=()=>y(Array.isArray(S.result)?S.result:[]),S.onerror=()=>g(S.error);})},async save(p){let y=await r();await new Promise((g,S)=>{let h=y.transaction(u,"readwrite");h.objectStore(u).put([...p],a),h.oncomplete=()=>g(),h.onerror=()=>S(h.error),h.onabort=()=>S(h.error);});}}}function D(t,n,u){let{clientId:a,versions:i}=u,l=n.origin==="server"||n.origin==="conflict-resolution",r=i.get(n.storeKey)??0;if(typeof n.version=="number"){if(!l&&n.version<=r)return;i.set(n.storeKey,n.version);}else if(n.origin===a)return;let p=t.getStore(n.storeKey,()=>n.state);n.intent&&(typeof n.version=="number"&&n.version<=r&&l||p.apply(n.intent)),n.state!==void 0&&(l||typeof n.version=="number"&&n.version>r)&&p.set(n.state);}function L(t){let{url:n,syncUrl:u,universe:a,clientId:i,versions:l,getLastEventId:r,setLastEventId:p,onEvent:y,resolveConflict:g}=t,S=t.maxQueueSize??100,h=t.maxConflictRetries??3,I=t.offlineQueue??B();if(!Number.isInteger(S)||S<1)throw new TypeError("maxQueueSize must be a positive integer");if(!Number.isInteger(h)||h<0)throw new TypeError("maxConflictRetries must be a non-negative integer");let O=null,j=0,w=false,U=null,e=null,f=s=>{if(y)y(s);else {if(typeof s.version=="number"){let c=l.get(s.storeKey)??0;if(s.version<=c)return;l.set(s.storeKey,s.version);}let m=a.getStore(s.storeKey,()=>s.state);s.intent?m.apply(s.intent):m.set(s.state);}},o=[],b=true,T=s=>{b=false,console.error("[Zuno] Offline queue storage failed",s);},x=I.load().then(async s=>{if(o.push(...s.slice(0,S)),s.length>S)try{await I.save(o);}catch(m){T(m);}}).catch(T),Z=new Map,Q=false,R=async()=>{try{return await I.save(o),b=!0,!0}catch(s){return T(s),false}},q=async s=>(await x,b?o.length>=S?"full":(o.push(s),await R()?"queued":(o.pop(),"storage-error")):"storage-error"),P=(s,m)=>s==="queued"?m:s==="full"?"QUEUE_FULL":"QUEUE_STORAGE_ERROR",N=()=>{w||e||(e=setTimeout(()=>{e=null,M();},1e3));};async function M(){if(w||(await x,Q||o.length===0)||typeof navigator<"u"&&!navigator.onLine)return;Q=true;let s=new Map,m=[];for(let c of o)if(s.has(c.storeKey)){let d=s.get(c.storeKey),v=m[d];m[d]={...c,baseVersion:v.baseVersion};}else s.set(c.storeKey,m.length),m.push(c);o.length=0,o.push(...m),await R();try{for(;o.length>0;){let c=o[0];try{let d=await fetch(u,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(c)});if(!d.ok&&d.status!==409){if(d.status>=400&&d.status<500){o.shift(),await R();continue}N();break}if(d.status===409){let v=await d.json();if(v.current){let{state:E,version:C}=v.current,k=E;if(g){let K=a.getStore(c.storeKey,()=>null).get();k=g(K,E,c.storeKey);}if(f({storeKey:c.storeKey,state:k,version:C,origin:"conflict-resolution"}),JSON.stringify(k)!==JSON.stringify(E)){let K=(Z.get(c.storeKey)??0)+1;if(K>h){Z.delete(c.storeKey),o.shift(),await R();continue}Z.set(c.storeKey,K),o.unshift({...c,state:k,baseVersion:C});continue}}o.shift(),await R();}else if(d.ok){Z.delete(c.storeKey);let v=await d.json();v.event&&typeof v.event.version=="number"&&l.set(c.storeKey,v.event.version),o.shift(),await R();}else o.shift(),await R();}catch(d){console.error("[Zuno] Flush failed, retrying later",d),N();break}}}finally{Q=false;}}function F(){if(w)return;let s=r(),m=new URL(n,globalThis.location?.href);s>0&&m.searchParams.set("lastEventId",String(s)),O=new EventSource(m.toString()),O.addEventListener("snapshot",c=>{try{let d=Number.parseInt(c.lastEventId||"0",10);d>=0&&p?.(d);let v=JSON.parse(c.data);for(let[E,C]of Object.entries(v)){let k=C;f({storeKey:E,state:k.state,version:k.version,origin:"server"});}}catch(d){console.error("[Zuno] Failed to parse snapshot",d);}}),O.addEventListener("state",c=>{try{let d=JSON.parse(c.data);if(d.origin||(d.origin="server"),d.origin===i)return;f(d);}catch(d){console.error("[Zuno] Failed to parse SSE event",d);}}),O.onopen=()=>{w||(j=0,t.onOpen?.(),M());},O.onerror=()=>{if(O?.close(),w)return;t.onClose?.();let c=Math.min(1e3*2**j,3e4);j++,U=setTimeout(()=>{U=null,F();},c);};}typeof window<"u"&&window.addEventListener("online",M),F();let _=async(s,m=0)=>{try{if(t.optimistic!==!1&&!s.origin&&f(s),typeof navigator<"u"&&!navigator.onLine){let v=await q(s);return {ok:!1,status:0,json:null,reason:P(v,"OFFLINE_QUEUED")}}let c=await fetch(u,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)});if(c.status===409){let v=await c.json();if(v.current){let{state:E,version:C}=v.current,k=E;if(g){let K=a.getStore(s.storeKey,()=>null).get();k=g(K,E,s.storeKey);}if(f({storeKey:s.storeKey,state:k,version:C,origin:"conflict-resolution"}),JSON.stringify(k)!==JSON.stringify(E))return m>=h?{ok:!1,status:409,json:v,reason:"CONFLICT_RETRY_LIMIT"}:await _({...s,state:k,baseVersion:C},m+1)}return {ok:!1,status:409,json:v,reason:"CONFLICT"}}if(!c.ok){let v=await c.json();if(c.status>=500){let E=await q(s);return E==="queued"&&N(),{ok:!1,status:c.status,json:v,reason:P(E,"SERVER_ERROR_QUEUED")}}return {ok:!1,status:c.status,json:v}}let d=await c.json();if(d.event){let{version:v}=d.event;typeof v=="number"&&l.set(s.storeKey,v);}return {ok:!0,status:200,json:d}}catch(c){let d=await q(s);return d==="queued"&&N(),{ok:false,status:500,json:c,reason:P(d,"NETWORK_ERROR_QUEUED")}}};return {dispatch:_,unsubscribe:()=>{w=true,O?.close(),U&&clearTimeout(U),e&&clearTimeout(e),typeof window<"u"&&window.removeEventListener("online",M);}}}function V(t){let{channelName:n,clientId:u,onEvent:a,getSnapshot:i,onSnapshot:l}=t,r=new BroadcastChannel(n);return r.onmessage=p=>{let y=p.data;y.origin!==u&&(y.type==="event"&&a(y.event),y.type==="hello"&&r.postMessage({type:"snapshot",snapshot:i(),origin:u}),y.type==="snapshot"&&l(y.snapshot));},{publish:p=>r.postMessage({type:"event",event:p,origin:u}),hello:()=>r.postMessage({type:"hello",origin:u}),stop:()=>r.close()}}var A=(t,n,u=Object.is)=>{let a=t,i=new Set,l=()=>{i.forEach(r=>{r(a);});};return {get:()=>a,equals:u,set:r=>{let p=typeof r=="function"?r(a):r;u(p,a)||(a=p,l());},apply:r=>{let p=r;if(p.type==="SET"){let g=p.payload;if(u(g,a))return;a=g,l();return}if(!n){console.warn(`[Zuno] apply() called for intent "${p.type}" on a store without a reducer. Intent ignored.`);return}let y=n(a,p);u(y,a)||(a=y,l());},subscribe:r=>(i.add(r),()=>i.delete(r))}},z=()=>{let t=new Map,n=null,u=i=>(i.subscribe(()=>{n=null;}),i);return {getStore(i,l,r,p){let y=t.get(i);return y||(y=u(A(l(),r,p)),t.set(i,y),n=null),y},snapshot(){if(n)return n;let i={};for(let[l,r]of t.entries())i[l]=r.get();return n=i,i},restore(i){for(let[l,r]of Object.entries(i)){let p=t.get(l);p?p.set(r):(t.set(l,u(A(r))),n=null);}},delete(i){t.delete(i),n=null;},clear(){t.clear(),n=null;},hydrateSnapshot(i){let l={};for(let[r,p]of Object.entries(i.state))l[r]=p.state;this.restore(l);}}},$=(t={})=>{let u=new Map,a=t.universe??z(),i=t.clientId??globalThis.crypto?.randomUUID?.()??String(Math.random()),r=0;function p(e){let f={};for(let[o,b]of Object.entries(e.state))f[o]=b.state,u.set(o,b.version);a.restore(f),r=e.lastEventId;}let y=e=>{typeof e.eventId=="number"&&(r=Math.max(r,e.eventId)),D(a,e,{clientId:i,versions:u});},g=t.sseUrl&&t.syncUrl?L({universe:a,url:t.sseUrl,syncUrl:t.syncUrl,optimistic:t.optimistic??true,clientId:i,versions:u,getLastEventId:()=>r,setLastEventId:e=>{r=e;},maxQueueSize:t.maxQueueSize,maxConflictRetries:t.maxConflictRetries,offlineQueue:t.offlineQueue,onOpen:()=>{},onClose:()=>{},onEvent:e=>w(e),resolveConflict:t.resolveConflict}):null,S=t.channelName?V({channelName:t.channelName,clientId:i,onEvent:e=>w(e),getSnapshot:()=>{let e=a.snapshot(),f={};for(let[o,b]of Object.entries(e))f[o]={state:b,version:u.get(o)??0};return f},onSnapshot:e=>{for(let[f,o]of Object.entries(e))y({storeKey:f,state:o.state,version:o.version});}}):null;setTimeout(()=>S?.hello(),100);let h=new Map,I=null,O=async()=>{let e=Array.from(h.values());h.clear(),I=null;for(let f of e)g&&g.dispatch(f).catch(o=>{console.error("[Zuno] Batch sync failed",o);});},j=async e=>{if(e.origin&&(y(e),e.origin!==i))return {ok:true,status:200,json:null};if(!e.origin){e.origin=i;let f=a.getStore(e.storeKey,()=>{});if(e.state===void 0&&e.intent)if(t.optimistic!==false)f.apply(e.intent),e.state=f.get();else {let b=e.intent;b.type==="SET"&&(e.state=b.payload);}else e.state!==void 0&&t.optimistic!==false&&f.set(e.state);let o=u.get(e.storeKey)??0;if(e.baseVersion??(e.baseVersion=o),t.optimistic!==false){let b=o+1;u.set(e.storeKey,b),e.version=b;}S&&S.publish(e);}if(g){if(t.batchSync){let f=h.get(e.storeKey);return h.set(e.storeKey,{...e,baseVersion:f?.baseVersion??e.baseVersion}),I||(I=Promise.resolve().then(O)),{ok:true,status:202,json:{batched:true}}}return await g.dispatch(e)}return {ok:true,status:200,json:null}},w=j;if(t.middleware&&t.middleware.length>0){let e={universe:a,clientId:i,versions:u};w=t.middleware.map(o=>o(e)).reduceRight((o,b)=>b(o),j);}return {universe:a,clientId:i,store:(e,f,o,b)=>{let T=a.getStore(e,f,o,b);return {key:e,raw:()=>T,get:()=>T.get(),subscribe:x=>T.subscribe(x),equals:(x,Z)=>T.equals(x,Z),set:x=>{let Z=T.get(),Q=typeof x=="function"?x(Z):x;return w({storeKey:e,state:Q,intent:{type:"SET",payload:Q}})}}},getStore:a.getStore.bind(a),get:(e,f)=>a.getStore(e,f??(()=>{})).get(),set:async(e,f,o)=>{let b=a.getStore(e,o??(()=>{})),T=typeof f=="function"?f(b.get()):f;return w({storeKey:e,state:T,intent:{type:"SET",payload:T}})},mutate:async(e,f)=>w({storeKey:e,state:void 0,intent:f}),subscribe:(e,f,o)=>a.getStore(e,f).subscribe(o),dispatch:w,stop:()=>{g?.unsubscribe?.(),S?.stop?.();},hydrateSnapshot:p,getLastEventId:()=>r,setLastEventId:e=>{r=e;}}};function G(t){return {getSnapshot:()=>t.get(),subscribe:n=>t.subscribe(()=>n())}}function H(t,n){if(Object.is(t,n))return true;if(typeof t!="object"||t===null||typeof n!="object"||n===null)return false;let u=Object.keys(t),a=Object.keys(n);if(u.length!==a.length)return false;let i=t,l=n;for(let r of u)if(!Object.hasOwn(l,r)||!Object.is(i[r],l[r]))return false;return true}export{D as applyIncomingEvent,J as createIndexedDBOfflineQueue,B as createMemoryOfflineQueue,A as createStore,z as createUniverse,$ as createZuno,H as shallowEqual,V as startBroadcastChannel,L as startSSE,G as toReadable};//# sourceMappingURL=index.js.map
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/sync/index.ts","../src/core/index.ts","../src/shared/readable.ts","../src/utils.ts"],"names":["applyIncomingEvent","universe","event","context","clientId","versions","isAuthoritative","current","store","startSSE","opts","url","syncUrl","getLastEventId","setLastEventId","onEvent","resolveConflict","maxQueueSize","maxConflictRetries","es","retryCount","stopped","reconnectTimer","flushTimer","applyState","queue","conflictRetries","isFlushing","enqueue","scheduleFlush","flushQueue","keyIndex","reducedQueue","idx","prev","res","data","serverState","serverVersion","nextState","localState","attempts","json","err","connect","lastId","connectUrl","e","snapshotEventId","snap","key","rec","r","delay","dispatchFn","conflictAttempt","queued","version","startBroadcastChannel","channelName","getSnapshot","onSnapshot","channel","msg","createStore","initial","reducer","equals","state","listeners","notify","l","next","value","intent","i","listener","createUniverse","stores","cachedSnapshot","trackStore","init","s","out","existing","snapshot","plain","k","createZuno","lastEventId","hydrateSnapshot","apply","sse","id","dispatch","bc","storeKey","pendingSyncs","batchPromise","flushBatch","syncs","coreDispatch","nextVersion","pending","middlewareAPI","middleware","rawStore","cb","v1","v2","toReadable","onChange","shallowEqual","a","b","keysA","keysB","objA","objB"],"mappings":"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","file":"index.js","sourcesContent":["import type { Universe } from \"../core\";\n\n// --- Types ---\n\nexport type ConflictResolver<T = unknown> = (\n\tlocalState: T,\n\tserverState: T,\n\tstoreKey: string,\n) => T;\n\n/**\n * Authoritative state event.\n */\nexport type ZunoStateEvent = {\n\tstoreKey: string;\n\tstate: unknown; // Was 'any', now strictly 'unknown'\n\tintent?: { type: string; payload?: unknown };\n\tversion?: number;\n\tbaseVersion?: number;\n\torigin?: string;\n\tts?: number;\n\teventId?: number;\n};\n\n/**\n * Generic transport status.\n */\nexport type TransportStatus = {\n\tok: boolean;\n\tstatus: number;\n\t// biome-ignore lint/suspicious/noExplicitAny: generic JSON response\n\tjson: any;\n\treason?: string;\n};\n\n/**\n * Client transport interface.\n */\nexport interface ZunoTransport {\n\tdispatch(event: ZunoStateEvent): Promise<TransportStatus>;\n\tunsubscribe?(): void;\n}\n\n/**\n * Apply incoming event to the universe and local bookkeeping.\n */\nexport function applyIncomingEvent(\n\tuniverse: Universe,\n\tevent: ZunoStateEvent,\n\tcontext: {\n\t\tclientId: string;\n\t\tlocalState: Map<string, unknown>;\n\t\tversions: Map<string, number>;\n\t},\n) {\n\tconst { clientId, versions } = context;\n\n\t// 1. Determine if this event is Authoritative (from Server) or Optimistic (from Peer/Local)\n\tconst isAuthoritative =\n\t\tevent.origin === \"server\" || event.origin === \"conflict-resolution\";\n\tconst current = versions.get(event.storeKey) ?? 0;\n\n\t// 2. Version check\n\tif (typeof event.version === \"number\") {\n\t\t// If it's not authoritative, we strictly enforce incrementing versions\n\t\tif (!isAuthoritative && event.version <= current) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Update version tracker\n\t\tversions.set(event.storeKey, event.version);\n\t} else if (event.origin === clientId) {\n\t\t// Suppress versionless loopback\n\t\treturn;\n\t}\n\n\t// 3. Apply to universe\n\tconst store = universe.getStore(event.storeKey, () => event.state);\n\n\t// If we have an intent, try to apply it first for side effects (but only if it's forward progress or authoritative)\n\tif (event.intent) {\n\t\t// If it's a version match/stale authoritative event, we might want to SKIP the intent\n\t\t// to avoid double-application (since we likely already did it optimistically).\n\t\t// However, snapping state (below) is always safe.\n\t\tif (\n\t\t\ttypeof event.version === \"number\" &&\n\t\t\tevent.version <= current &&\n\t\t\tisAuthoritative\n\t\t) {\n\t\t\t// Skip intent, but snap state anyway below.\n\t\t} else {\n\t\t\tstore.apply(event.intent);\n\t\t}\n\t}\n\n\t// 4. Authoritative State Snap\n\t// ALWAYS apply the state if provided and it's authoritative or has a higher version.\n\tif (event.state !== undefined) {\n\t\tif (\n\t\t\tisAuthoritative ||\n\t\t\t(typeof event.version === \"number\" && event.version > current)\n\t\t) {\n\t\t\tstore.set(event.state);\n\t\t}\n\t}\n}\n\n// --- SSE Client ---\n\nexport type SSEOptions = {\n\tuniverse: Universe;\n\turl: string;\n\tsyncUrl: string;\n\toptimistic: boolean;\n\tclientId: string;\n\tversions: Map<string, number>;\n\tgetLastEventId: () => number;\n\tsetLastEventId?: (id: number) => void;\n\t/** Maximum number of mutations retained while offline (default: 100). */\n\tmaxQueueSize?: number;\n\t/** Maximum automatic retries for a single conflict (default: 3). */\n\tmaxConflictRetries?: number;\n\tonOpen?: () => void;\n\tonClose?: () => void;\n\tonEvent?: (event: ZunoStateEvent) => void;\n\tresolveConflict?: ConflictResolver;\n};\n\nexport function startSSE(opts: SSEOptions): ZunoTransport {\n\tconst {\n\t\turl,\n\t\tsyncUrl,\n\t\tuniverse,\n\t\tclientId,\n\t\tversions,\n\t\tgetLastEventId,\n\t\tsetLastEventId,\n\t\tonEvent,\n\t\tresolveConflict,\n\t} = opts;\n\tconst maxQueueSize = opts.maxQueueSize ?? 100;\n\tconst maxConflictRetries = opts.maxConflictRetries ?? 3;\n\tif (!Number.isInteger(maxQueueSize) || maxQueueSize < 1) {\n\t\tthrow new TypeError(\"maxQueueSize must be a positive integer\");\n\t}\n\tif (!Number.isInteger(maxConflictRetries) || maxConflictRetries < 0) {\n\t\tthrow new TypeError(\"maxConflictRetries must be a non-negative integer\");\n\t}\n\tlet es: EventSource | null = null;\n\tlet retryCount = 0;\n\tlet stopped = false;\n\tlet reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n\tlet flushTimer: ReturnType<typeof setTimeout> | null = null;\n\n\t// Helper to apply state changes\n\tconst applyState = (event: ZunoStateEvent) => {\n\t\tif (onEvent) {\n\t\t\tonEvent(event);\n\t\t} else {\n\t\t\t// Fallback default implementation\n\t\t\tif (typeof event.version === \"number\") {\n\t\t\t\tconst current = versions.get(event.storeKey) ?? 0;\n\t\t\t\tif (event.version <= current) return;\n\t\t\t\tversions.set(event.storeKey, event.version);\n\t\t\t}\n\t\t\tconst store = universe.getStore(event.storeKey, () => event.state);\n\t\t\tif (event.intent) {\n\t\t\t\tstore.apply(event.intent);\n\t\t\t} else {\n\t\t\t\tstore.set(event.state);\n\t\t\t}\n\t\t}\n\t};\n\n\t// --- Offline Support ---\n\tconst queue: ZunoStateEvent[] = [];\n\tconst conflictRetries = new Map<string, number>();\n\tlet isFlushing = false;\n\tconst enqueue = (event: ZunoStateEvent) => {\n\t\tif (queue.length >= maxQueueSize) return false;\n\t\tqueue.push(event);\n\t\treturn true;\n\t};\n\tconst scheduleFlush = () => {\n\t\tif (stopped || flushTimer) return;\n\t\tflushTimer = setTimeout(() => {\n\t\t\tflushTimer = null;\n\t\t\tvoid flushQueue();\n\t\t}, 1000);\n\t};\n\n\tasync function flushQueue() {\n\t\tif (stopped) return;\n\t\tif (isFlushing || queue.length === 0) return;\n\t\tif (typeof navigator !== \"undefined\" && !navigator.onLine) return;\n\n\t\tisFlushing = true;\n\n\t\t// --- Coalesce / Deduplicate Logic ---\n\t\t// 1. Map index of first occurrence of each storeKey\n\t\tconst keyIndex = new Map<string, number>();\n\t\t// 2. Reduced queue construction\n\t\tconst reducedQueue: ZunoStateEvent[] = [];\n\n\t\tfor (const event of queue) {\n\t\t\tif (keyIndex.has(event.storeKey)) {\n\t\t\t\t// We've seen this key before. We want to update the existing entry in reducedQueue.\n\t\t\t\t// biome-ignore lint/style/noNonNullAssertion: key exists per has check\n\t\t\t\tconst idx = keyIndex.get(event.storeKey)!;\n\t\t\t\tconst prev = reducedQueue[idx];\n\t\t\t\t// Merge: keep original baseVersion (from the start of the chain) but use NEW state.\n\t\t\t\t// Note: We also likely want to keep the original 'ts' if strictly ordering,\n\t\t\t\t// but state is what matters.\n\t\t\t\t// The 'version' in the event is the *optimistic* version.\n\t\t\t\t// We can keep the *latest* optimistic version (e.g. v10) in the event,\n\t\t\t\t// but server will likely only verify baseVersion.\n\t\t\t\treducedQueue[idx] = { ...event, baseVersion: prev.baseVersion };\n\t\t\t} else {\n\t\t\t\tkeyIndex.set(event.storeKey, reducedQueue.length);\n\t\t\t\treducedQueue.push(event);\n\t\t\t}\n\t\t}\n\n\t\t// Replace original queue with reduced one.\n\t\t// We modify 'queue' in place or reset it.\n\t\t// Since 'queue' is const binding to array, we can't reassign variable,\n\t\t// but we can clear and push.\n\t\tqueue.length = 0;\n\t\tqueue.push(...reducedQueue);\n\n\t\ttry {\n\t\t\twhile (queue.length > 0) {\n\t\t\t\tconst event = queue[0];\n\t\t\t\ttry {\n\t\t\t\t\tconst res = await fetch(syncUrl, {\n\t\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\t\t\t\tbody: JSON.stringify(event),\n\t\t\t\t\t});\n\n\t\t\t\t\tif (!res.ok && res.status !== 409) {\n\t\t\t\t\t\tif (res.status >= 400 && res.status < 500) {\n\t\t\t\t\t\t\tqueue.shift();\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Preserve retryable server failures at the front of the queue.\n\t\t\t\t\t\tscheduleFlush();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (res.status === 409) {\n\t\t\t\t\t\tconst data = await res.json();\n\t\t\t\t\t\tif (data.current) {\n\t\t\t\t\t\t\tconst { state: serverState, version: serverVersion } =\n\t\t\t\t\t\t\t\tdata.current;\n\n\t\t\t\t\t\t\tlet nextState = serverState;\n\t\t\t\t\t\t\tif (resolveConflict) {\n\t\t\t\t\t\t\t\tconst localState = universe\n\t\t\t\t\t\t\t\t\t.getStore(event.storeKey, () => null)\n\t\t\t\t\t\t\t\t\t.get();\n\t\t\t\t\t\t\t\tnextState = resolveConflict(\n\t\t\t\t\t\t\t\t\tlocalState,\n\t\t\t\t\t\t\t\t\tserverState,\n\t\t\t\t\t\t\t\t\tevent.storeKey,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// versions.set(event.storeKey, serverVersion); // REMOVE THIS\n\n\t\t\t\t\t\t\t// 2. Apply resolved state locally\n\t\t\t\t\t\t\tapplyState({\n\t\t\t\t\t\t\t\tstoreKey: event.storeKey,\n\t\t\t\t\t\t\t\tstate: nextState,\n\t\t\t\t\t\t\t\tversion: serverVersion,\n\t\t\t\t\t\t\t\torigin: \"conflict-resolution\",\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t// 3. If resolved state differs from server, auto-sync back\n\t\t\t\t\t\t\tif (JSON.stringify(nextState) !== JSON.stringify(serverState)) {\n\t\t\t\t\t\t\t\tconst attempts = (conflictRetries.get(event.storeKey) ?? 0) + 1;\n\t\t\t\t\t\t\t\tif (attempts > maxConflictRetries) {\n\t\t\t\t\t\t\t\t\tconflictRetries.delete(event.storeKey);\n\t\t\t\t\t\t\t\t\tqueue.shift();\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tconflictRetries.set(event.storeKey, attempts);\n\t\t\t\t\t\t\t\tqueue.unshift({\n\t\t\t\t\t\t\t\t\t...event,\n\t\t\t\t\t\t\t\t\tstate: nextState,\n\t\t\t\t\t\t\t\t\tbaseVersion: serverVersion,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tqueue.shift();\n\t\t\t\t\t} else if (res.ok) {\n\t\t\t\t\t\tconflictRetries.delete(event.storeKey);\n\t\t\t\t\t\tconst json = await res.json();\n\t\t\t\t\t\tif (json.event && typeof json.event.version === \"number\") {\n\t\t\t\t\t\t\t// Just update version map\n\t\t\t\t\t\t\tversions.set(event.storeKey, json.event.version);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tqueue.shift();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tqueue.shift();\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconsole.error(\"[Zuno] Flush failed, retrying later\", err);\n\t\t\t\t\tscheduleFlush();\n\t\t\t\t\tbreak; // Network error, stop flushing\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\tisFlushing = false;\n\t\t}\n\t}\n\tfunction connect() {\n\t\tif (stopped) return;\n\t\tconst lastId = getLastEventId();\n\t\tconst connectUrl = new URL(url, globalThis.location?.href);\n\t\tif (lastId > 0) connectUrl.searchParams.set(\"lastEventId\", String(lastId));\n\n\t\tes = new EventSource(connectUrl.toString());\n\n\t\t// biome-ignore lint/suspicious/noExplicitAny: EventSource data is string, rec is parsed JSON\n\t\tes.addEventListener(\"snapshot\", (e: any) => {\n\t\t\ttry {\n\t\t\t\tconst snapshotEventId = Number.parseInt(e.lastEventId || \"0\", 10);\n\t\t\t\tif (snapshotEventId >= 0) setLastEventId?.(snapshotEventId);\n\t\t\t\tconst snap = JSON.parse(e.data);\n\t\t\t\tfor (const [key, rec] of Object.entries(snap)) {\n\t\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: rec state can be anything\n\t\t\t\t\tconst r = rec as { state: any; version: number };\n\t\t\t\t\tapplyState({\n\t\t\t\t\t\tstoreKey: key,\n\t\t\t\t\t\tstate: r.state,\n\t\t\t\t\t\tversion: r.version,\n\t\t\t\t\t\torigin: \"server\",\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(\"[Zuno] Failed to parse snapshot\", err);\n\t\t\t}\n\t\t});\n\n\t\t// biome-ignore lint/suspicious/noExplicitAny: EventSource event data\n\t\tes.addEventListener(\"state\", (e: any) => {\n\t\t\ttry {\n\t\t\t\tconst event = JSON.parse(e.data) as ZunoStateEvent;\n\t\t\t\t// If server didn't provide an origin (e.g. manual server-side trigger),\n\t\t\t\t// we treat it as authoritative \"server\" origin.\n\t\t\t\tif (!event.origin) {\n\t\t\t\t\tevent.origin = \"server\";\n\t\t\t\t}\n\n\t\t\t\tif (event.origin === clientId) return;\n\n\t\t\t\tapplyState(event);\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(\"[Zuno] Failed to parse SSE event\", err);\n\t\t\t}\n\t\t});\n\n\t\tes.onopen = () => {\n\t\t\tif (stopped) return;\n\t\t\tretryCount = 0;\n\t\t\topts.onOpen?.();\n\t\t\tflushQueue();\n\t\t};\n\n\t\tes.onerror = () => {\n\t\t\tes?.close();\n\t\t\tif (stopped) return;\n\t\t\topts.onClose?.();\n\t\t\tconst delay = Math.min(1000 * 2 ** retryCount, 30000);\n\t\t\tretryCount++;\n\t\t\treconnectTimer = setTimeout(() => {\n\t\t\t\treconnectTimer = null;\n\t\t\t\tconnect();\n\t\t\t}, delay);\n\t\t};\n\t}\n\n\tif (typeof window !== \"undefined\") {\n\t\twindow.addEventListener(\"online\", flushQueue);\n\t}\n\n\tconnect();\n\n\tconst dispatchFn = async (\n\t\tevent: ZunoStateEvent,\n\t\tconflictAttempt = 0,\n\t): Promise<TransportStatus> => {\n\t\ttry {\n\t\t\t// Removed local application here. Local application is handled by coreDispatch\n\t\t\t// to avoid double-update when intents are used.\n\n\t\t\t// 1. Optimistic Local Apply\n\t\t\t// This is needed for direct transport usage (like in tests)\n\t\t\tif (opts.optimistic !== false && !event.origin) {\n\t\t\t\tapplyState(event);\n\t\t\t}\n\n\t\t\t// Check online status first\n\t\t\tif (typeof navigator !== \"undefined\" && !navigator.onLine) {\n\t\t\t\tconst queued = enqueue(event);\n\t\t\t\treturn {\n\t\t\t\t\tok: false,\n\t\t\t\t\tstatus: 0,\n\t\t\t\t\tjson: null,\n\t\t\t\t\treason: queued ? \"OFFLINE_QUEUED\" : \"QUEUE_FULL\",\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst res = await fetch(syncUrl, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\t\tbody: JSON.stringify(event),\n\t\t\t});\n\n\t\t\tif (res.status === 409) {\n\t\t\t\tconst data = await res.json();\n\t\t\t\tif (data.current) {\n\t\t\t\t\tconst { state: serverState, version: serverVersion } = data.current;\n\n\t\t\t\t\tlet nextState = serverState;\n\t\t\t\t\tif (resolveConflict) {\n\t\t\t\t\t\tconst localState = universe\n\t\t\t\t\t\t\t.getStore(event.storeKey, () => null)\n\t\t\t\t\t\t\t.get();\n\t\t\t\t\t\tnextState = resolveConflict(\n\t\t\t\t\t\t\tlocalState,\n\t\t\t\t\t\t\tserverState,\n\t\t\t\t\t\t\tevent.storeKey,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tapplyState({\n\t\t\t\t\t\tstoreKey: event.storeKey,\n\t\t\t\t\t\tstate: nextState,\n\t\t\t\t\t\tversion: serverVersion,\n\t\t\t\t\t\torigin: \"conflict-resolution\",\n\t\t\t\t\t});\n\n\t\t\t\t\tif (JSON.stringify(nextState) !== JSON.stringify(serverState)) {\n\t\t\t\t\t\tif (conflictAttempt >= maxConflictRetries) {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tok: false,\n\t\t\t\t\t\t\t\tstatus: 409,\n\t\t\t\t\t\t\t\tjson: data,\n\t\t\t\t\t\t\t\treason: \"CONFLICT_RETRY_LIMIT\",\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn await dispatchFn(\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t...event,\n\t\t\t\t\t\t\t\tstate: nextState,\n\t\t\t\t\t\t\t\tbaseVersion: serverVersion,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tconflictAttempt + 1,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn { ok: false, status: 409, json: data, reason: \"CONFLICT\" };\n\t\t\t}\n\n\t\t\tif (!res.ok) {\n\t\t\t\tconst json = await res.json();\n\t\t\t\tif (res.status >= 500) {\n\t\t\t\t\tconst queued = enqueue(event);\n\t\t\t\t\tif (queued) scheduleFlush();\n\t\t\t\t\treturn {\n\t\t\t\t\t\tok: false,\n\t\t\t\t\t\tstatus: res.status,\n\t\t\t\t\t\tjson,\n\t\t\t\t\t\treason: queued ? \"SERVER_ERROR_QUEUED\" : \"QUEUE_FULL\",\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn { ok: false, status: res.status, json };\n\t\t\t}\n\n\t\t\tconst json = await res.json();\n\t\t\tif (json.event) {\n\t\t\t\tconst { version } = json.event;\n\t\t\t\tif (typeof version === \"number\") {\n\t\t\t\t\tversions.set(event.storeKey, version);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn { ok: true, status: 200, json };\n\t\t} catch (err) {\n\t\t\t// Network failure catch\n\t\t\tconst queued = enqueue(event);\n\t\t\tif (queued) scheduleFlush();\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\tstatus: 500,\n\t\t\t\tjson: err,\n\t\t\t\treason: queued ? \"NETWORK_ERROR_QUEUED\" : \"QUEUE_FULL\",\n\t\t\t};\n\t\t}\n\t};\n\n\treturn {\n\t\tdispatch: dispatchFn,\n\t\tunsubscribe: () => {\n\t\t\tstopped = true;\n\t\t\tes?.close();\n\t\t\tif (reconnectTimer) clearTimeout(reconnectTimer);\n\t\t\tif (flushTimer) clearTimeout(flushTimer);\n\t\t\tif (typeof window !== \"undefined\") {\n\t\t\t\twindow.removeEventListener(\"online\", flushQueue);\n\t\t\t}\n\t\t},\n\t};\n}\n\n// --- BroadcastChannel ---\n\nexport type BCOptions = {\n\tchannelName: string;\n\tclientId: string;\n\tonEvent: (event: ZunoStateEvent) => void;\n\tgetSnapshot: () => Record<string, { state: unknown; version: number }>;\n\tonSnapshot: (\n\t\tsnap: Record<string, { state: unknown; version: number }>,\n\t) => void;\n};\n\nexport function startBroadcastChannel(opts: BCOptions) {\n\tconst { channelName, clientId, onEvent, getSnapshot, onSnapshot } = opts;\n\tconst channel = new BroadcastChannel(channelName);\n\n\tchannel.onmessage = (e) => {\n\t\tconst msg = e.data;\n\t\tif (msg.origin === clientId) return;\n\n\t\tif (msg.type === \"event\") onEvent(msg.event);\n\t\tif (msg.type === \"hello\")\n\t\t\tchannel.postMessage({\n\t\t\t\ttype: \"snapshot\",\n\t\t\t\tsnapshot: getSnapshot(),\n\t\t\t\torigin: clientId,\n\t\t\t});\n\t\tif (msg.type === \"snapshot\") onSnapshot(msg.snapshot);\n\t};\n\n\treturn {\n\t\tpublish: (event: ZunoStateEvent) =>\n\t\t\tchannel.postMessage({ type: \"event\", event, origin: clientId }),\n\t\thello: () => channel.postMessage({ type: \"hello\", origin: clientId }),\n\t\tstop: () => channel.close(),\n\t};\n}\n","import type {\n\tConflictResolver,\n\tTransportStatus,\n\tZunoStateEvent,\n} from \"../sync\";\nimport { applyIncomingEvent, startBroadcastChannel, startSSE } from \"../sync\";\n\n// --- Types ---\n\n/**\n * Authoritative snapshot of the entire universe.\n */\nexport type ZunoSnapshot = {\n\tstate: Record<string, { state: unknown; version: number }>;\n\tlastEventId: number;\n};\n\n/**\n * A simple state container for a single keyed value.\n */\nexport interface Store<T> {\n\tget(): T;\n\tset(next: T | ((prev: T) => T)): void;\n\tapply(intent: unknown): void;\n\tsubscribe(listener: (state: T) => void): () => void;\n\tequals(val1: unknown, val2: unknown): boolean;\n}\n\n/**\n * A Universe manages many stores.\n */\nexport interface Universe {\n\tgetStore<T>(\n\t\tkey: string,\n\t\tinit: () => T,\n\t\treducer?: (prev: T, intent: unknown) => T,\n\t\tequals?: (v1: unknown, v2: unknown) => boolean,\n\t): Store<T>;\n\tsnapshot(): Record<string, unknown>;\n\trestore(data: Record<string, unknown>): void;\n\tdelete(key: string): void;\n\tclear(): void;\n\thydrateSnapshot(snapshot: ZunoSnapshot): void;\n}\n\n// --- Middleware Types ---\n\nexport type Dispatch = (event: ZunoStateEvent) => Promise<TransportStatus>;\n\nexport type MiddlewareAPI = {\n\tuniverse: Universe;\n\tclientId: string;\n\tversions: Map<string, number>;\n};\n\nexport type Middleware = (api: MiddlewareAPI) => (next: Dispatch) => Dispatch;\n\n/**\n * Options for creating a Zuno instance.\n */\nexport type CreateZunoOptions = {\n\t/** Optional pre-existing universe. */\n\tuniverse?: Universe;\n\t/** BroadcastChannel name for local tab sync. */\n\tchannelName?: string;\n\t/** SSE endpoint URL. */\n\tsseUrl?: string;\n\t/** Sync endpoint URL (required if sseUrl is provided). */\n\tsyncUrl?: string;\n\t/** Apply updates locally before server confirmation (default: true). */\n\toptimistic?: boolean;\n\t/** Batch multiple updates in the same microtask (default: false). */\n\tbatchSync?: boolean;\n\t/** Unique client identifier (default: random UUID). */\n\tclientId?: string;\n\t/** Middleware chain. */\n\tmiddleware?: Middleware[];\n\t/** Optional function to resolve 409 conflicts. */\n\tresolveConflict?: ConflictResolver;\n\t/** Maximum mutations retained while offline (default: 100). */\n\tmaxQueueSize?: number;\n\t/** Maximum automatic retries for a single conflict (default: 3). */\n\tmaxConflictRetries?: number;\n};\n\n/**\n * An extended interface for a Zuno store that includes methods for setting state\n * and a unique key identifier. This represents a store that has been \"bound\" or registered.\n */\nexport type BoundStore<T> = {\n\tkey: string;\n\tget: () => T;\n\tset: (next: T | ((prev: T) => T)) => Promise<unknown>;\n\tsubscribe: (cb: (state: T) => void) => () => void;\n\tequals: (v1: unknown, v2: unknown) => boolean;\n\traw: () => Store<T>;\n};\n\n// --- Store Implementation ---\n\n/**\n * Creates a raw ZUNO state management store.\n */\nexport const createStore = <T>(\n\tinitial: T,\n\treducer?: (prev: T, intent: unknown) => T,\n\tequals: (v1: unknown, v2: unknown) => boolean = Object.is,\n): Store<T> => {\n\tlet state = initial;\n\tconst listeners = new Set<(state: T) => void>();\n\n\tconst notify = () => {\n\t\tlisteners.forEach((l) => {\n\t\t\tl(state);\n\t\t});\n\t};\n\n\treturn {\n\t\tget: () => state,\n\t\tequals,\n\t\tset: (next) => {\n\t\t\tconst value =\n\t\t\t\ttypeof next === \"function\" ? (next as (prev: T) => T)(state) : next;\n\t\t\tif (equals(value, state)) return;\n\t\t\tstate = value;\n\t\t\tnotify();\n\t\t},\n\t\tapply: (intent) => {\n\t\t\tconst i = intent as { type: string; payload?: unknown };\n\t\t\tif (i.type === \"SET\") {\n\t\t\t\tconst value = i.payload as T;\n\t\t\t\tif (equals(value, state)) return;\n\t\t\t\tstate = value;\n\t\t\t\tnotify();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!reducer) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`[Zuno] apply() called for intent \"${i.type}\" on a store without a reducer. Intent ignored.`,\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst nextState = reducer(state, i);\n\t\t\tif (equals(nextState, state)) return;\n\t\t\tstate = nextState;\n\t\t\tnotify();\n\t\t},\n\t\tsubscribe: (listener) => {\n\t\t\tlisteners.add(listener);\n\t\t\treturn () => listeners.delete(listener);\n\t\t},\n\t};\n};\n\n// --- Universe Implementation ---\n\n/**\n * Creates a ZUNO Universe to manage multiple stores.\n */\nexport const createUniverse = (): Universe => {\n\t// biome-ignore lint/suspicious/noExplicitAny: internal registry of heterogeneous stores\n\tconst stores = new Map<string, Store<any>>();\n\tlet cachedSnapshot: Record<string, unknown> | null = null;\n\tconst trackStore = <T>(store: Store<T>) => {\n\t\tstore.subscribe(() => {\n\t\t\tcachedSnapshot = null;\n\t\t});\n\t\treturn store;\n\t};\n\n\tconst universe: Universe = {\n\t\tgetStore<T>(\n\t\t\tkey: string,\n\t\t\tinit: () => T,\n\t\t\treducer?: (prev: T, intent: unknown) => T,\n\t\t\tequals?: (v1: unknown, v2: unknown) => boolean,\n\t\t): Store<T> {\n\t\t\tlet s = stores.get(key);\n\t\t\tif (!s) {\n\t\t\t\ts = trackStore(createStore(init(), reducer, equals));\n\t\t\t\tstores.set(key, s);\n\t\t\t\tcachedSnapshot = null;\n\t\t\t}\n\t\t\treturn s as Store<T>;\n\t\t},\n\t\tsnapshot(): Record<string, unknown> {\n\t\t\tif (cachedSnapshot) return cachedSnapshot;\n\n\t\t\tconst out: Record<string, unknown> = {};\n\t\t\tfor (const [key, store] of stores.entries()) {\n\t\t\t\tout[key] = store.get();\n\t\t\t}\n\t\t\tcachedSnapshot = out;\n\t\t\treturn out;\n\t\t},\n\t\trestore(data: Record<string, unknown>): void {\n\t\t\tfor (const [key, value] of Object.entries(data)) {\n\t\t\t\tconst existing = stores.get(key);\n\t\t\t\tif (existing) {\n\t\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: external data needs to be cast to store type\n\t\t\t\t\texisting.set(value as any);\n\t\t\t\t} else {\n\t\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: external data needs to be cast to store type\n\t\t\t\t\tstores.set(key, trackStore(createStore(value as any)));\n\t\t\t\t\tcachedSnapshot = null;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tdelete(key: string): void {\n\t\t\tstores.delete(key);\n\t\t\tcachedSnapshot = null;\n\t\t},\n\t\tclear(): void {\n\t\t\tstores.clear();\n\t\t\tcachedSnapshot = null;\n\t\t},\n\t\thydrateSnapshot(snapshot: ZunoSnapshot) {\n\t\t\tconst plain: Record<string, unknown> = {};\n\t\t\tfor (const [k, rec] of Object.entries(snapshot.state)) {\n\t\t\t\tplain[k] = rec.state;\n\t\t\t}\n\t\t\tthis.restore(plain);\n\t\t},\n\t};\n\n\treturn universe;\n};\n\n// --- Main Zuno Factory ---\n\n/**\n * Creates a Zuno instance for distributed state synchronization.\n */\nexport const createZuno = (opts: CreateZunoOptions = {}) => {\n\tconst localState = new Map<string, unknown>();\n\tconst versions = new Map<string, number>();\n\tconst universe = opts.universe ?? createUniverse();\n\tconst clientId =\n\t\topts.clientId ?? globalThis.crypto?.randomUUID?.() ?? String(Math.random());\n\tlet _sseReady = false;\n\tlet lastEventId = 0;\n\n\tfunction hydrateSnapshot(snapshot: ZunoSnapshot) {\n\t\tconst plain: Record<string, unknown> = {};\n\t\tfor (const [k, rec] of Object.entries(snapshot.state)) {\n\t\t\tplain[k] = rec.state;\n\t\t\tversions.set(k, rec.version);\n\t\t}\n\t\tuniverse.restore(plain);\n\t\tlastEventId = snapshot.lastEventId;\n\t}\n\n\tconst apply = (event: ZunoStateEvent) => {\n\t\tif (typeof event.eventId === \"number\") {\n\t\t\tlastEventId = Math.max(lastEventId, event.eventId);\n\t\t}\n\t\tapplyIncomingEvent(universe, event, { clientId, localState, versions });\n\t};\n\n\tconst sse =\n\t\topts.sseUrl && opts.syncUrl\n\t\t\t? startSSE({\n\t\t\t\t\tuniverse,\n\t\t\t\t\turl: opts.sseUrl,\n\t\t\t\t\tsyncUrl: opts.syncUrl,\n\t\t\t\t\toptimistic: opts.optimistic ?? true,\n\t\t\t\t\tclientId,\n\t\t\t\t\tversions,\n\t\t\t\t\tgetLastEventId: () => lastEventId,\n\t\t\t\t\tsetLastEventId: (id) => {\n\t\t\t\t\t\tlastEventId = id;\n\t\t\t\t\t},\n\t\t\t\t\tmaxQueueSize: opts.maxQueueSize,\n\t\t\t\t\tmaxConflictRetries: opts.maxConflictRetries,\n\t\t\t\t\tonOpen: () => {\n\t\t\t\t\t\t_sseReady = true;\n\t\t\t\t\t},\n\t\t\t\t\tonClose: () => {\n\t\t\t\t\t\t_sseReady = false;\n\t\t\t\t\t},\n\t\t\t\t\tonEvent: (e) => dispatch(e), // Route incoming SSE events through middleware\n\t\t\t\t\tresolveConflict: opts.resolveConflict,\n\t\t\t\t})\n\t\t\t: null;\n\n\tconst bc = opts.channelName\n\t\t? startBroadcastChannel({\n\t\t\t\tchannelName: opts.channelName,\n\t\t\t\tclientId,\n\t\t\t\tonEvent: (e) => dispatch(e), // Route incoming BC events through middleware\n\t\t\t\tgetSnapshot: () => {\n\t\t\t\t\tconst snap = universe.snapshot();\n\t\t\t\t\tconst out: Record<string, { state: unknown; version: number }> = {};\n\t\t\t\t\tfor (const [storeKey, state] of Object.entries(snap)) {\n\t\t\t\t\t\tout[storeKey] = { state, version: versions.get(storeKey) ?? 0 };\n\t\t\t\t\t}\n\t\t\t\t\treturn out;\n\t\t\t\t},\n\t\t\t\tonSnapshot: (snap) => {\n\t\t\t\t\tfor (const [storeKey, rec] of Object.entries(snap)) {\n\t\t\t\t\t\tapply({ storeKey, state: rec.state, version: rec.version });\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t})\n\t\t: null;\n\n\tsetTimeout(() => bc?.hello(), 100);\n\n\t// --- Sync Batching ---\n\tconst pendingSyncs = new Map<string, ZunoStateEvent>();\n\tlet batchPromise: Promise<void> | null = null;\n\n\tconst flushBatch = async () => {\n\t\tconst syncs = Array.from(pendingSyncs.values());\n\t\tpendingSyncs.clear();\n\t\tbatchPromise = null;\n\n\t\tfor (const event of syncs) {\n\t\t\tif (sse) {\n\t\t\t\tsse.dispatch(event).catch((err) => {\n\t\t\t\t\tconsole.error(\"[Zuno] Batch sync failed\", err);\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t};\n\n\tconst coreDispatch = async (\n\t\tevent: ZunoStateEvent,\n\t): Promise<TransportStatus> => {\n\t\t// 1. Incoming/Reflected Event Logic (events WITH origin)\n\t\tif (event.origin) {\n\t\t\t// Always call apply to let applyIncomingEvent handle version checks and application\n\t\t\tapply(event);\n\n\t\t\t// If it's from another client, we are done\n\t\t\tif (event.origin !== clientId) {\n\t\t\t\treturn { ok: true, status: 200, json: null };\n\t\t\t}\n\t\t\t// If it's a reflected local event, we still need to broadcast it (fall through)\n\t\t}\n\n\t\t// 2. Outgoing Event Logic (events WITHOUT origin)\n\t\tif (!event.origin) {\n\t\t\tevent.origin = clientId;\n\n\t\t\t// Resolve state if needed (e.g. from mutate)\n\t\t\tconst store = universe.getStore(event.storeKey, () => undefined);\n\n\t\t\tif (event.state === undefined && event.intent) {\n\t\t\t\t// We need the state to send to server.\n\t\t\t\t// If optimistic, we apply it. If not, we only compute if it's a simple SET.\n\t\t\t\tif (opts.optimistic !== false) {\n\t\t\t\t\tstore.apply(event.intent);\n\t\t\t\t\tevent.state = store.get();\n\t\t\t\t} else {\n\t\t\t\t\tconst i = event.intent as { type: string; payload?: unknown };\n\t\t\t\t\tif (i.type === \"SET\") {\n\t\t\t\t\t\tevent.state = i.payload;\n\t\t\t\t\t}\n\t\t\t\t\t// For other intents with optimistic: false, we might send undefined state\n\t\t\t\t\t// and rely on the server to compute it authoritativeley.\n\t\t\t\t}\n\t\t\t} else if (event.state !== undefined) {\n\t\t\t\tif (opts.optimistic !== false) {\n\t\t\t\t\tstore.set(event.state as never);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Always send the authoritative version this mutation was based on.\n\t\t\tconst current = versions.get(event.storeKey) ?? 0;\n\t\t\tevent.baseVersion ??= current;\n\n\t\t\t// Local bookkeeping and optimistic versioning\n\t\t\tif (opts.optimistic !== false) {\n\t\t\t\tconst nextVersion = current + 1;\n\t\t\t\tversions.set(event.storeKey, nextVersion);\n\t\t\t\tevent.version = nextVersion;\n\t\t\t}\n\n\t\t\t// BROADCAST IMMEDIATELY to local tabs via BC\n\t\t\t// This ensures instant sync across tabs even if SSE is slow or down.\n\t\t\tif (bc) {\n\t\t\t\tbc.publish(event);\n\t\t\t}\n\t\t}\n\n\t\t// 3. Remote Sync (SSE/HTTP) with Optional Batching\n\t\tif (sse) {\n\t\t\tif (opts.batchSync) {\n\t\t\t\t// Coalesce outgoing syncs for the same storeKey within the same microtask\n\t\t\t\tconst pending = pendingSyncs.get(event.storeKey);\n\t\t\t\tpendingSyncs.set(event.storeKey, {\n\t\t\t\t\t...event,\n\t\t\t\t\tbaseVersion: pending?.baseVersion ?? event.baseVersion,\n\t\t\t\t});\n\n\t\t\t\tif (!batchPromise) {\n\t\t\t\t\tbatchPromise = Promise.resolve().then(flushBatch);\n\t\t\t\t}\n\n\t\t\t\t// Note: Batched dispatch currently returns a \"fake\" OK immediately\n\t\t\t\t// to avoid blocking the UI. Error handling is handled via console.error in flushBatch.\n\t\t\t\t// Real conflict resolution still happens via SSE's internal queue/retry.\n\t\t\t\treturn { ok: true, status: 202, json: { batched: true } };\n\t\t\t}\n\n\t\t\treturn await sse.dispatch(event);\n\t\t}\n\n\t\treturn { ok: true, status: 200, json: null };\n\t};\n\n\t// --- Middleware Composition ---\n\tlet dispatch: Dispatch = coreDispatch;\n\n\tif (opts.middleware && opts.middleware.length > 0) {\n\t\tconst middlewareAPI: MiddlewareAPI = {\n\t\t\tuniverse,\n\t\t\tclientId,\n\t\t\tversions,\n\t\t};\n\t\tconst chain = opts.middleware.map((middleware) =>\n\t\t\tmiddleware(middlewareAPI),\n\t\t);\n\t\tdispatch = chain.reduceRight(\n\t\t\t(next, middleware) => middleware(next),\n\t\t\tcoreDispatch,\n\t\t);\n\t}\n\n\tconst store = <T>(\n\t\tstoreKey: string,\n\t\tinit: () => T,\n\t\treducer?: (prev: T, intent: unknown) => T,\n\t\tequals?: (v1: unknown, v2: unknown) => boolean,\n\t): BoundStore<T> => {\n\t\tconst rawStore = universe.getStore<T>(storeKey, init, reducer, equals);\n\t\treturn {\n\t\t\tkey: storeKey,\n\t\t\traw: () => rawStore,\n\t\t\tget: () => rawStore.get(),\n\t\t\tsubscribe: (cb) => rawStore.subscribe(cb),\n\t\t\tequals: (v1, v2) => rawStore.equals(v1, v2),\n\t\t\tset: (next) => {\n\t\t\t\tconst prev = rawStore.get();\n\t\t\t\tconst state =\n\t\t\t\t\ttypeof next === \"function\" ? (next as (prev: T) => T)(prev) : next;\n\t\t\t\treturn dispatch({\n\t\t\t\t\tstoreKey,\n\t\t\t\t\tstate,\n\t\t\t\t\tintent: { type: \"SET\", payload: state },\n\t\t\t\t});\n\t\t\t},\n\t\t};\n\t};\n\n\treturn {\n\t\tuniverse,\n\t\tclientId,\n\t\tstore,\n\t\tgetStore: universe.getStore.bind(universe),\n\t\tget: <T>(key: string, init?: () => T) =>\n\t\t\tuniverse\n\t\t\t\t.getStore<T>(\n\t\t\t\t\tkey,\n\t\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: default init for convenience\n\t\t\t\t\tinit ?? (() => undefined as any),\n\t\t\t\t)\n\t\t\t\t.get(),\n\t\tset: async <T>(key: string, next: T | ((prev: T) => T), init?: () => T) => {\n\t\t\tconst s = universe.getStore<T>(\n\t\t\t\tkey,\n\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: default init for convenience\n\t\t\t\tinit ?? (() => undefined as any),\n\t\t\t);\n\t\t\tconst state =\n\t\t\t\ttypeof next === \"function\" ? (next as (prev: T) => T)(s.get()) : next;\n\n\t\t\t// Don't set origin or version here, let coreDispatch handle it\n\t\t\treturn dispatch({\n\t\t\t\tstoreKey: key,\n\t\t\t\tstate,\n\t\t\t\tintent: { type: \"SET\", payload: state },\n\t\t\t});\n\t\t},\n\t\tmutate: async (\n\t\t\tkey: string,\n\t\t\tintent: { type: string; payload?: unknown },\n\t\t) => {\n\t\t\treturn dispatch({\n\t\t\t\tstoreKey: key,\n\t\t\t\t// coreDispatch will calculate state from intent\n\t\t\t\tstate: undefined as unknown,\n\t\t\t\tintent,\n\t\t\t});\n\t\t},\n\t\tsubscribe: <T>(key: string, init: () => T, cb: (state: T) => void) =>\n\t\t\tuniverse.getStore<T>(key, init).subscribe(cb),\n\t\tdispatch,\n\t\tstop: () => {\n\t\t\tsse?.unsubscribe?.();\n\t\t\tbc?.stop?.();\n\t\t},\n\t\thydrateSnapshot,\n\t\tgetLastEventId: () => lastEventId,\n\t\tsetLastEventId: (id: number) => {\n\t\t\tlastEventId = id;\n\t\t},\n\t};\n};\n","/** Universal UI adapter contract */\nexport type ZunoReadable<T> = {\n\t/** Read current value (sync) */\n\tgetSnapshot(): T;\n\n\t/**\n\t * Subscribe to changes.\n\t * Call `onChange()` whenever snapshot may have changed.\n\t * Return unsubscribe.\n\t */\n\tsubscribe(onChange: () => void): () => void;\n\n\t/** Optional: React SSR (server snapshot) */\n\tgetServerSnapshot?: () => T;\n};\n\n/** Minimal store shape that can be adapted into a readable */\nexport type ZunoSubscribableStore<T> = {\n\tget(): T;\n\tsubscribe(cb: (state: T) => void): () => void;\n\tequals(v1: unknown, v2: unknown): boolean;\n};\n\n/** Adapter helper: convert store => readable */\nexport function toReadable<T>(\n\tstore: ZunoSubscribableStore<T>,\n): ZunoReadable<T> {\n\treturn {\n\t\tgetSnapshot: () => store.get(),\n\t\tsubscribe: (onChange) => store.subscribe(() => onChange()),\n\t};\n}\n","/**\n * Performs a shallow equality check between two values.\n */\nexport function shallowEqual(a: unknown, b: unknown): boolean {\n\tif (Object.is(a, b)) return true;\n\n\tif (\n\t\ttypeof a !== \"object\" ||\n\t\ta === null ||\n\t\ttypeof b !== \"object\" ||\n\t\tb === null\n\t) {\n\t\treturn false;\n\t}\n\n\tconst keysA = Object.keys(a as object);\n\tconst keysB = Object.keys(b as object);\n\n\tif (keysA.length !== keysB.length) return false;\n\n\tconst objA = a as Record<string, unknown>;\n\tconst objB = b as Record<string, unknown>;\n\n\tfor (const key of keysA) {\n\t\tif (!Object.hasOwn(objB, key) || !Object.is(objA[key], objB[key])) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\n}\n"]}
1
+ {"version":3,"sources":["../src/sync/offline-queue.ts","../src/sync/index.ts","../src/core/index.ts","../src/shared/readable.ts","../src/utils.ts"],"names":["createMemoryOfflineQueue","initialEvents","events","nextEvents","createIndexedDBOfflineQueue","options","databaseName","storeName","queueKey","version","databasePromise","getDatabase","resolve","reject","request","database","transaction","applyIncomingEvent","universe","event","context","clientId","versions","isAuthoritative","current","store","startSSE","opts","url","syncUrl","getLastEventId","setLastEventId","onEvent","resolveConflict","maxQueueSize","maxConflictRetries","offlineQueue","es","retryCount","stopped","reconnectTimer","flushTimer","applyState","queue","queueStorageHealthy","reportQueueStorageError","error","queueReady","storedEvents","conflictRetries","isFlushing","persistQueue","enqueue","queueReason","result","queuedReason","scheduleFlush","flushQueue","keyIndex","reducedQueue","idx","prev","res","data","serverState","serverVersion","nextState","localState","attempts","json","err","connect","lastId","connectUrl","e","snapshotEventId","snap","key","rec","r","delay","dispatchFn","conflictAttempt","queued","startBroadcastChannel","channelName","getSnapshot","onSnapshot","channel","msg","createStore","initial","reducer","equals","state","listeners","notify","l","next","value","intent","i","listener","createUniverse","stores","cachedSnapshot","trackStore","init","s","out","existing","snapshot","plain","k","createZuno","lastEventId","hydrateSnapshot","apply","sse","id","dispatch","bc","storeKey","pendingSyncs","batchPromise","flushBatch","syncs","coreDispatch","nextVersion","pending","middlewareAPI","middleware","rawStore","cb","v1","v2","toReadable","onChange","shallowEqual","a","b","keysA","keysB","objA","objB"],"mappings":"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","file":"index.js","sourcesContent":["import type { ZunoStateEvent } from \"./index\";\n\n/** Storage contract used by the SSE client to persist queued mutations. */\nexport interface ZunoOfflineQueue {\n\tload(): Promise<ZunoStateEvent[]>;\n\tsave(events: readonly ZunoStateEvent[]): Promise<void>;\n}\n\n/** In-memory queue storage. Useful as the default and for custom integrations/tests. */\nexport function createMemoryOfflineQueue(\n\tinitialEvents: readonly ZunoStateEvent[] = [],\n): ZunoOfflineQueue {\n\tlet events: ZunoStateEvent[] = structuredClone([...initialEvents]);\n\treturn {\n\t\tasync load() {\n\t\t\treturn structuredClone(events);\n\t\t},\n\t\tasync save(nextEvents) {\n\t\t\tevents = structuredClone([...nextEvents]);\n\t\t},\n\t};\n}\n\nexport type IndexedDBOfflineQueueOptions = {\n\t/** IndexedDB database name (default: \"zuno\"). */\n\tdatabaseName?: string;\n\t/** Object-store name (default: \"offline-queues\"). */\n\tstoreName?: string;\n\t/** Key used for this client/namespace queue (default: \"default\"). */\n\tqueueKey?: string;\n\t/** IndexedDB schema version (default: 1). */\n\tversion?: number;\n};\n\n/** Creates durable browser queue storage backed by IndexedDB. */\nexport function createIndexedDBOfflineQueue(\n\toptions: IndexedDBOfflineQueueOptions = {},\n): ZunoOfflineQueue {\n\tconst databaseName = options.databaseName ?? \"zuno\";\n\tconst storeName = options.storeName ?? \"offline-queues\";\n\tconst queueKey = options.queueKey ?? \"default\";\n\tconst version = options.version ?? 1;\n\tif (!Number.isInteger(version) || version < 1) {\n\t\tthrow new TypeError(\"version must be a positive integer\");\n\t}\n\n\tlet databasePromise: Promise<IDBDatabase> | undefined;\n\tconst getDatabase = () => {\n\t\tif (typeof indexedDB === \"undefined\") {\n\t\t\treturn Promise.reject(\n\t\t\t\tnew Error(\"IndexedDB is not available in this environment\"),\n\t\t\t);\n\t\t}\n\t\tif (!databasePromise) {\n\t\t\tdatabasePromise = new Promise((resolve, reject) => {\n\t\t\t\tconst request = indexedDB.open(databaseName, version);\n\t\t\t\trequest.onupgradeneeded = () => {\n\t\t\t\t\tif (!request.result.objectStoreNames.contains(storeName)) {\n\t\t\t\t\t\trequest.result.createObjectStore(storeName);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\trequest.onsuccess = () => resolve(request.result);\n\t\t\t\trequest.onerror = () => reject(request.error);\n\t\t\t\trequest.onblocked = () =>\n\t\t\t\t\treject(new Error(`IndexedDB database \"${databaseName}\" is blocked`));\n\t\t\t});\n\t\t}\n\t\treturn databasePromise;\n\t};\n\n\treturn {\n\t\tasync load() {\n\t\t\tconst database = await getDatabase();\n\t\t\treturn await new Promise<ZunoStateEvent[]>((resolve, reject) => {\n\t\t\t\tconst request = database\n\t\t\t\t\t.transaction(storeName, \"readonly\")\n\t\t\t\t\t.objectStore(storeName)\n\t\t\t\t\t.get(queueKey);\n\t\t\t\trequest.onsuccess = () =>\n\t\t\t\t\tresolve(Array.isArray(request.result) ? request.result : []);\n\t\t\t\trequest.onerror = () => reject(request.error);\n\t\t\t});\n\t\t},\n\t\tasync save(events) {\n\t\t\tconst database = await getDatabase();\n\t\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\t\tconst transaction = database.transaction(storeName, \"readwrite\");\n\t\t\t\ttransaction.objectStore(storeName).put([...events], queueKey);\n\t\t\t\ttransaction.oncomplete = () => resolve();\n\t\t\t\ttransaction.onerror = () => reject(transaction.error);\n\t\t\t\ttransaction.onabort = () => reject(transaction.error);\n\t\t\t});\n\t\t},\n\t};\n}\n","import type { Universe } from \"../core\";\nimport {\n\tcreateMemoryOfflineQueue,\n\ttype ZunoOfflineQueue,\n} from \"./offline-queue\";\n\nexport type {\n\tIndexedDBOfflineQueueOptions,\n\tZunoOfflineQueue,\n} from \"./offline-queue\";\nexport {\n\tcreateIndexedDBOfflineQueue,\n\tcreateMemoryOfflineQueue,\n} from \"./offline-queue\";\n\n// --- Types ---\n\nexport type ConflictResolver<T = unknown> = (\n\tlocalState: T,\n\tserverState: T,\n\tstoreKey: string,\n) => T;\n\n/**\n * Authoritative state event.\n */\nexport type ZunoStateEvent = {\n\tstoreKey: string;\n\tstate: unknown; // Was 'any', now strictly 'unknown'\n\tintent?: { type: string; payload?: unknown };\n\tversion?: number;\n\tbaseVersion?: number;\n\torigin?: string;\n\tts?: number;\n\teventId?: number;\n};\n\n/**\n * Generic transport status.\n */\nexport type TransportStatus = {\n\tok: boolean;\n\tstatus: number;\n\t// biome-ignore lint/suspicious/noExplicitAny: generic JSON response\n\tjson: any;\n\treason?: string;\n};\n\n/**\n * Client transport interface.\n */\nexport interface ZunoTransport {\n\tdispatch(event: ZunoStateEvent): Promise<TransportStatus>;\n\tunsubscribe?(): void;\n}\n\n/**\n * Apply incoming event to the universe and local bookkeeping.\n */\nexport function applyIncomingEvent(\n\tuniverse: Universe,\n\tevent: ZunoStateEvent,\n\tcontext: {\n\t\tclientId: string;\n\t\tlocalState: Map<string, unknown>;\n\t\tversions: Map<string, number>;\n\t},\n) {\n\tconst { clientId, versions } = context;\n\n\t// 1. Determine if this event is Authoritative (from Server) or Optimistic (from Peer/Local)\n\tconst isAuthoritative =\n\t\tevent.origin === \"server\" || event.origin === \"conflict-resolution\";\n\tconst current = versions.get(event.storeKey) ?? 0;\n\n\t// 2. Version check\n\tif (typeof event.version === \"number\") {\n\t\t// If it's not authoritative, we strictly enforce incrementing versions\n\t\tif (!isAuthoritative && event.version <= current) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Update version tracker\n\t\tversions.set(event.storeKey, event.version);\n\t} else if (event.origin === clientId) {\n\t\t// Suppress versionless loopback\n\t\treturn;\n\t}\n\n\t// 3. Apply to universe\n\tconst store = universe.getStore(event.storeKey, () => event.state);\n\n\t// If we have an intent, try to apply it first for side effects (but only if it's forward progress or authoritative)\n\tif (event.intent) {\n\t\t// If it's a version match/stale authoritative event, we might want to SKIP the intent\n\t\t// to avoid double-application (since we likely already did it optimistically).\n\t\t// However, snapping state (below) is always safe.\n\t\tif (\n\t\t\ttypeof event.version === \"number\" &&\n\t\t\tevent.version <= current &&\n\t\t\tisAuthoritative\n\t\t) {\n\t\t\t// Skip intent, but snap state anyway below.\n\t\t} else {\n\t\t\tstore.apply(event.intent);\n\t\t}\n\t}\n\n\t// 4. Authoritative State Snap\n\t// ALWAYS apply the state if provided and it's authoritative or has a higher version.\n\tif (event.state !== undefined) {\n\t\tif (\n\t\t\tisAuthoritative ||\n\t\t\t(typeof event.version === \"number\" && event.version > current)\n\t\t) {\n\t\t\tstore.set(event.state);\n\t\t}\n\t}\n}\n\n// --- SSE Client ---\n\nexport type SSEOptions = {\n\tuniverse: Universe;\n\turl: string;\n\tsyncUrl: string;\n\toptimistic: boolean;\n\tclientId: string;\n\tversions: Map<string, number>;\n\tgetLastEventId: () => number;\n\tsetLastEventId?: (id: number) => void;\n\t/** Maximum number of mutations retained while offline (default: 100). */\n\tmaxQueueSize?: number;\n\t/** Maximum automatic retries for a single conflict (default: 3). */\n\tmaxConflictRetries?: number;\n\t/** Queue persistence provider (default: an in-memory provider). */\n\tofflineQueue?: ZunoOfflineQueue;\n\tonOpen?: () => void;\n\tonClose?: () => void;\n\tonEvent?: (event: ZunoStateEvent) => void;\n\tresolveConflict?: ConflictResolver;\n};\n\nexport function startSSE(opts: SSEOptions): ZunoTransport {\n\tconst {\n\t\turl,\n\t\tsyncUrl,\n\t\tuniverse,\n\t\tclientId,\n\t\tversions,\n\t\tgetLastEventId,\n\t\tsetLastEventId,\n\t\tonEvent,\n\t\tresolveConflict,\n\t} = opts;\n\tconst maxQueueSize = opts.maxQueueSize ?? 100;\n\tconst maxConflictRetries = opts.maxConflictRetries ?? 3;\n\tconst offlineQueue = opts.offlineQueue ?? createMemoryOfflineQueue();\n\tif (!Number.isInteger(maxQueueSize) || maxQueueSize < 1) {\n\t\tthrow new TypeError(\"maxQueueSize must be a positive integer\");\n\t}\n\tif (!Number.isInteger(maxConflictRetries) || maxConflictRetries < 0) {\n\t\tthrow new TypeError(\"maxConflictRetries must be a non-negative integer\");\n\t}\n\tlet es: EventSource | null = null;\n\tlet retryCount = 0;\n\tlet stopped = false;\n\tlet reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n\tlet flushTimer: ReturnType<typeof setTimeout> | null = null;\n\n\t// Helper to apply state changes\n\tconst applyState = (event: ZunoStateEvent) => {\n\t\tif (onEvent) {\n\t\t\tonEvent(event);\n\t\t} else {\n\t\t\t// Fallback default implementation\n\t\t\tif (typeof event.version === \"number\") {\n\t\t\t\tconst current = versions.get(event.storeKey) ?? 0;\n\t\t\t\tif (event.version <= current) return;\n\t\t\t\tversions.set(event.storeKey, event.version);\n\t\t\t}\n\t\t\tconst store = universe.getStore(event.storeKey, () => event.state);\n\t\t\tif (event.intent) {\n\t\t\t\tstore.apply(event.intent);\n\t\t\t} else {\n\t\t\t\tstore.set(event.state);\n\t\t\t}\n\t\t}\n\t};\n\n\t// --- Offline Support ---\n\tconst queue: ZunoStateEvent[] = [];\n\tlet queueStorageHealthy = true;\n\tconst reportQueueStorageError = (error: unknown) => {\n\t\tqueueStorageHealthy = false;\n\t\tconsole.error(\"[Zuno] Offline queue storage failed\", error);\n\t};\n\tconst queueReady = offlineQueue\n\t\t.load()\n\t\t.then(async (storedEvents) => {\n\t\t\tqueue.push(...storedEvents.slice(0, maxQueueSize));\n\t\t\tif (storedEvents.length > maxQueueSize) {\n\t\t\t\ttry {\n\t\t\t\t\tawait offlineQueue.save(queue);\n\t\t\t\t} catch (error) {\n\t\t\t\t\treportQueueStorageError(error);\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t\t.catch(reportQueueStorageError);\n\tconst conflictRetries = new Map<string, number>();\n\tlet isFlushing = false;\n\tconst persistQueue = async () => {\n\t\ttry {\n\t\t\tawait offlineQueue.save(queue);\n\t\t\tqueueStorageHealthy = true;\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\treportQueueStorageError(error);\n\t\t\treturn false;\n\t\t}\n\t};\n\tconst enqueue = async (event: ZunoStateEvent) => {\n\t\tawait queueReady;\n\t\tif (!queueStorageHealthy) return \"storage-error\" as const;\n\t\tif (queue.length >= maxQueueSize) return \"full\" as const;\n\t\tqueue.push(event);\n\t\tif (!(await persistQueue())) {\n\t\t\tqueue.pop();\n\t\t\treturn \"storage-error\" as const;\n\t\t}\n\t\treturn \"queued\" as const;\n\t};\n\tconst queueReason = (\n\t\tresult: \"queued\" | \"full\" | \"storage-error\",\n\t\tqueuedReason: string,\n\t) => {\n\t\tif (result === \"queued\") return queuedReason;\n\t\tif (result === \"full\") return \"QUEUE_FULL\";\n\t\treturn \"QUEUE_STORAGE_ERROR\";\n\t};\n\tconst scheduleFlush = () => {\n\t\tif (stopped || flushTimer) return;\n\t\tflushTimer = setTimeout(() => {\n\t\t\tflushTimer = null;\n\t\t\tvoid flushQueue();\n\t\t}, 1000);\n\t};\n\n\tasync function flushQueue() {\n\t\tif (stopped) return;\n\t\tawait queueReady;\n\t\tif (isFlushing || queue.length === 0) return;\n\t\tif (typeof navigator !== \"undefined\" && !navigator.onLine) return;\n\n\t\tisFlushing = true;\n\n\t\t// --- Coalesce / Deduplicate Logic ---\n\t\t// 1. Map index of first occurrence of each storeKey\n\t\tconst keyIndex = new Map<string, number>();\n\t\t// 2. Reduced queue construction\n\t\tconst reducedQueue: ZunoStateEvent[] = [];\n\n\t\tfor (const event of queue) {\n\t\t\tif (keyIndex.has(event.storeKey)) {\n\t\t\t\t// We've seen this key before. We want to update the existing entry in reducedQueue.\n\t\t\t\t// biome-ignore lint/style/noNonNullAssertion: key exists per has check\n\t\t\t\tconst idx = keyIndex.get(event.storeKey)!;\n\t\t\t\tconst prev = reducedQueue[idx];\n\t\t\t\t// Merge: keep original baseVersion (from the start of the chain) but use NEW state.\n\t\t\t\t// Note: We also likely want to keep the original 'ts' if strictly ordering,\n\t\t\t\t// but state is what matters.\n\t\t\t\t// The 'version' in the event is the *optimistic* version.\n\t\t\t\t// We can keep the *latest* optimistic version (e.g. v10) in the event,\n\t\t\t\t// but server will likely only verify baseVersion.\n\t\t\t\treducedQueue[idx] = { ...event, baseVersion: prev.baseVersion };\n\t\t\t} else {\n\t\t\t\tkeyIndex.set(event.storeKey, reducedQueue.length);\n\t\t\t\treducedQueue.push(event);\n\t\t\t}\n\t\t}\n\n\t\t// Replace original queue with reduced one.\n\t\t// We modify 'queue' in place or reset it.\n\t\t// Since 'queue' is const binding to array, we can't reassign variable,\n\t\t// but we can clear and push.\n\t\tqueue.length = 0;\n\t\tqueue.push(...reducedQueue);\n\t\tawait persistQueue();\n\n\t\ttry {\n\t\t\twhile (queue.length > 0) {\n\t\t\t\tconst event = queue[0];\n\t\t\t\ttry {\n\t\t\t\t\tconst res = await fetch(syncUrl, {\n\t\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\t\t\t\tbody: JSON.stringify(event),\n\t\t\t\t\t});\n\n\t\t\t\t\tif (!res.ok && res.status !== 409) {\n\t\t\t\t\t\tif (res.status >= 400 && res.status < 500) {\n\t\t\t\t\t\t\tqueue.shift();\n\t\t\t\t\t\t\tawait persistQueue();\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Preserve retryable server failures at the front of the queue.\n\t\t\t\t\t\tscheduleFlush();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (res.status === 409) {\n\t\t\t\t\t\tconst data = await res.json();\n\t\t\t\t\t\tif (data.current) {\n\t\t\t\t\t\t\tconst { state: serverState, version: serverVersion } =\n\t\t\t\t\t\t\t\tdata.current;\n\n\t\t\t\t\t\t\tlet nextState = serverState;\n\t\t\t\t\t\t\tif (resolveConflict) {\n\t\t\t\t\t\t\t\tconst localState = universe\n\t\t\t\t\t\t\t\t\t.getStore(event.storeKey, () => null)\n\t\t\t\t\t\t\t\t\t.get();\n\t\t\t\t\t\t\t\tnextState = resolveConflict(\n\t\t\t\t\t\t\t\t\tlocalState,\n\t\t\t\t\t\t\t\t\tserverState,\n\t\t\t\t\t\t\t\t\tevent.storeKey,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// versions.set(event.storeKey, serverVersion); // REMOVE THIS\n\n\t\t\t\t\t\t\t// 2. Apply resolved state locally\n\t\t\t\t\t\t\tapplyState({\n\t\t\t\t\t\t\t\tstoreKey: event.storeKey,\n\t\t\t\t\t\t\t\tstate: nextState,\n\t\t\t\t\t\t\t\tversion: serverVersion,\n\t\t\t\t\t\t\t\torigin: \"conflict-resolution\",\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t// 3. If resolved state differs from server, auto-sync back\n\t\t\t\t\t\t\tif (JSON.stringify(nextState) !== JSON.stringify(serverState)) {\n\t\t\t\t\t\t\t\tconst attempts = (conflictRetries.get(event.storeKey) ?? 0) + 1;\n\t\t\t\t\t\t\t\tif (attempts > maxConflictRetries) {\n\t\t\t\t\t\t\t\t\tconflictRetries.delete(event.storeKey);\n\t\t\t\t\t\t\t\t\tqueue.shift();\n\t\t\t\t\t\t\t\t\tawait persistQueue();\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tconflictRetries.set(event.storeKey, attempts);\n\t\t\t\t\t\t\t\tqueue.unshift({\n\t\t\t\t\t\t\t\t\t...event,\n\t\t\t\t\t\t\t\t\tstate: nextState,\n\t\t\t\t\t\t\t\t\tbaseVersion: serverVersion,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tqueue.shift();\n\t\t\t\t\t\tawait persistQueue();\n\t\t\t\t\t} else if (res.ok) {\n\t\t\t\t\t\tconflictRetries.delete(event.storeKey);\n\t\t\t\t\t\tconst json = await res.json();\n\t\t\t\t\t\tif (json.event && typeof json.event.version === \"number\") {\n\t\t\t\t\t\t\t// Just update version map\n\t\t\t\t\t\t\tversions.set(event.storeKey, json.event.version);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tqueue.shift();\n\t\t\t\t\t\tawait persistQueue();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tqueue.shift();\n\t\t\t\t\t\tawait persistQueue();\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconsole.error(\"[Zuno] Flush failed, retrying later\", err);\n\t\t\t\t\tscheduleFlush();\n\t\t\t\t\tbreak; // Network error, stop flushing\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\tisFlushing = false;\n\t\t}\n\t}\n\tfunction connect() {\n\t\tif (stopped) return;\n\t\tconst lastId = getLastEventId();\n\t\tconst connectUrl = new URL(url, globalThis.location?.href);\n\t\tif (lastId > 0) connectUrl.searchParams.set(\"lastEventId\", String(lastId));\n\n\t\tes = new EventSource(connectUrl.toString());\n\n\t\t// biome-ignore lint/suspicious/noExplicitAny: EventSource data is string, rec is parsed JSON\n\t\tes.addEventListener(\"snapshot\", (e: any) => {\n\t\t\ttry {\n\t\t\t\tconst snapshotEventId = Number.parseInt(e.lastEventId || \"0\", 10);\n\t\t\t\tif (snapshotEventId >= 0) setLastEventId?.(snapshotEventId);\n\t\t\t\tconst snap = JSON.parse(e.data);\n\t\t\t\tfor (const [key, rec] of Object.entries(snap)) {\n\t\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: rec state can be anything\n\t\t\t\t\tconst r = rec as { state: any; version: number };\n\t\t\t\t\tapplyState({\n\t\t\t\t\t\tstoreKey: key,\n\t\t\t\t\t\tstate: r.state,\n\t\t\t\t\t\tversion: r.version,\n\t\t\t\t\t\torigin: \"server\",\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(\"[Zuno] Failed to parse snapshot\", err);\n\t\t\t}\n\t\t});\n\n\t\t// biome-ignore lint/suspicious/noExplicitAny: EventSource event data\n\t\tes.addEventListener(\"state\", (e: any) => {\n\t\t\ttry {\n\t\t\t\tconst event = JSON.parse(e.data) as ZunoStateEvent;\n\t\t\t\t// If server didn't provide an origin (e.g. manual server-side trigger),\n\t\t\t\t// we treat it as authoritative \"server\" origin.\n\t\t\t\tif (!event.origin) {\n\t\t\t\t\tevent.origin = \"server\";\n\t\t\t\t}\n\n\t\t\t\tif (event.origin === clientId) return;\n\n\t\t\t\tapplyState(event);\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(\"[Zuno] Failed to parse SSE event\", err);\n\t\t\t}\n\t\t});\n\n\t\tes.onopen = () => {\n\t\t\tif (stopped) return;\n\t\t\tretryCount = 0;\n\t\t\topts.onOpen?.();\n\t\t\tflushQueue();\n\t\t};\n\n\t\tes.onerror = () => {\n\t\t\tes?.close();\n\t\t\tif (stopped) return;\n\t\t\topts.onClose?.();\n\t\t\tconst delay = Math.min(1000 * 2 ** retryCount, 30000);\n\t\t\tretryCount++;\n\t\t\treconnectTimer = setTimeout(() => {\n\t\t\t\treconnectTimer = null;\n\t\t\t\tconnect();\n\t\t\t}, delay);\n\t\t};\n\t}\n\n\tif (typeof window !== \"undefined\") {\n\t\twindow.addEventListener(\"online\", flushQueue);\n\t}\n\n\tconnect();\n\n\tconst dispatchFn = async (\n\t\tevent: ZunoStateEvent,\n\t\tconflictAttempt = 0,\n\t): Promise<TransportStatus> => {\n\t\ttry {\n\t\t\t// Removed local application here. Local application is handled by coreDispatch\n\t\t\t// to avoid double-update when intents are used.\n\n\t\t\t// 1. Optimistic Local Apply\n\t\t\t// This is needed for direct transport usage (like in tests)\n\t\t\tif (opts.optimistic !== false && !event.origin) {\n\t\t\t\tapplyState(event);\n\t\t\t}\n\n\t\t\t// Check online status first\n\t\t\tif (typeof navigator !== \"undefined\" && !navigator.onLine) {\n\t\t\t\tconst queued = await enqueue(event);\n\t\t\t\treturn {\n\t\t\t\t\tok: false,\n\t\t\t\t\tstatus: 0,\n\t\t\t\t\tjson: null,\n\t\t\t\t\treason: queueReason(queued, \"OFFLINE_QUEUED\"),\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst res = await fetch(syncUrl, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\t\tbody: JSON.stringify(event),\n\t\t\t});\n\n\t\t\tif (res.status === 409) {\n\t\t\t\tconst data = await res.json();\n\t\t\t\tif (data.current) {\n\t\t\t\t\tconst { state: serverState, version: serverVersion } = data.current;\n\n\t\t\t\t\tlet nextState = serverState;\n\t\t\t\t\tif (resolveConflict) {\n\t\t\t\t\t\tconst localState = universe\n\t\t\t\t\t\t\t.getStore(event.storeKey, () => null)\n\t\t\t\t\t\t\t.get();\n\t\t\t\t\t\tnextState = resolveConflict(\n\t\t\t\t\t\t\tlocalState,\n\t\t\t\t\t\t\tserverState,\n\t\t\t\t\t\t\tevent.storeKey,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tapplyState({\n\t\t\t\t\t\tstoreKey: event.storeKey,\n\t\t\t\t\t\tstate: nextState,\n\t\t\t\t\t\tversion: serverVersion,\n\t\t\t\t\t\torigin: \"conflict-resolution\",\n\t\t\t\t\t});\n\n\t\t\t\t\tif (JSON.stringify(nextState) !== JSON.stringify(serverState)) {\n\t\t\t\t\t\tif (conflictAttempt >= maxConflictRetries) {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tok: false,\n\t\t\t\t\t\t\t\tstatus: 409,\n\t\t\t\t\t\t\t\tjson: data,\n\t\t\t\t\t\t\t\treason: \"CONFLICT_RETRY_LIMIT\",\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn await dispatchFn(\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t...event,\n\t\t\t\t\t\t\t\tstate: nextState,\n\t\t\t\t\t\t\t\tbaseVersion: serverVersion,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tconflictAttempt + 1,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn { ok: false, status: 409, json: data, reason: \"CONFLICT\" };\n\t\t\t}\n\n\t\t\tif (!res.ok) {\n\t\t\t\tconst json = await res.json();\n\t\t\t\tif (res.status >= 500) {\n\t\t\t\t\tconst queued = await enqueue(event);\n\t\t\t\t\tif (queued === \"queued\") scheduleFlush();\n\t\t\t\t\treturn {\n\t\t\t\t\t\tok: false,\n\t\t\t\t\t\tstatus: res.status,\n\t\t\t\t\t\tjson,\n\t\t\t\t\t\treason: queueReason(queued, \"SERVER_ERROR_QUEUED\"),\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn { ok: false, status: res.status, json };\n\t\t\t}\n\n\t\t\tconst json = await res.json();\n\t\t\tif (json.event) {\n\t\t\t\tconst { version } = json.event;\n\t\t\t\tif (typeof version === \"number\") {\n\t\t\t\t\tversions.set(event.storeKey, version);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn { ok: true, status: 200, json };\n\t\t} catch (err) {\n\t\t\t// Network failure catch\n\t\t\tconst queued = await enqueue(event);\n\t\t\tif (queued === \"queued\") scheduleFlush();\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\tstatus: 500,\n\t\t\t\tjson: err,\n\t\t\t\treason: queueReason(queued, \"NETWORK_ERROR_QUEUED\"),\n\t\t\t};\n\t\t}\n\t};\n\n\treturn {\n\t\tdispatch: dispatchFn,\n\t\tunsubscribe: () => {\n\t\t\tstopped = true;\n\t\t\tes?.close();\n\t\t\tif (reconnectTimer) clearTimeout(reconnectTimer);\n\t\t\tif (flushTimer) clearTimeout(flushTimer);\n\t\t\tif (typeof window !== \"undefined\") {\n\t\t\t\twindow.removeEventListener(\"online\", flushQueue);\n\t\t\t}\n\t\t},\n\t};\n}\n\n// --- BroadcastChannel ---\n\nexport type BCOptions = {\n\tchannelName: string;\n\tclientId: string;\n\tonEvent: (event: ZunoStateEvent) => void;\n\tgetSnapshot: () => Record<string, { state: unknown; version: number }>;\n\tonSnapshot: (\n\t\tsnap: Record<string, { state: unknown; version: number }>,\n\t) => void;\n};\n\nexport function startBroadcastChannel(opts: BCOptions) {\n\tconst { channelName, clientId, onEvent, getSnapshot, onSnapshot } = opts;\n\tconst channel = new BroadcastChannel(channelName);\n\n\tchannel.onmessage = (e) => {\n\t\tconst msg = e.data;\n\t\tif (msg.origin === clientId) return;\n\n\t\tif (msg.type === \"event\") onEvent(msg.event);\n\t\tif (msg.type === \"hello\")\n\t\t\tchannel.postMessage({\n\t\t\t\ttype: \"snapshot\",\n\t\t\t\tsnapshot: getSnapshot(),\n\t\t\t\torigin: clientId,\n\t\t\t});\n\t\tif (msg.type === \"snapshot\") onSnapshot(msg.snapshot);\n\t};\n\n\treturn {\n\t\tpublish: (event: ZunoStateEvent) =>\n\t\t\tchannel.postMessage({ type: \"event\", event, origin: clientId }),\n\t\thello: () => channel.postMessage({ type: \"hello\", origin: clientId }),\n\t\tstop: () => channel.close(),\n\t};\n}\n","import type {\n\tConflictResolver,\n\tTransportStatus,\n\tZunoOfflineQueue,\n\tZunoStateEvent,\n} from \"../sync\";\nimport { applyIncomingEvent, startBroadcastChannel, startSSE } from \"../sync\";\n\n// --- Types ---\n\n/**\n * Authoritative snapshot of the entire universe.\n */\nexport type ZunoSnapshot = {\n\tstate: Record<string, { state: unknown; version: number }>;\n\tlastEventId: number;\n};\n\n/**\n * A simple state container for a single keyed value.\n */\nexport interface Store<T> {\n\tget(): T;\n\tset(next: T | ((prev: T) => T)): void;\n\tapply(intent: unknown): void;\n\tsubscribe(listener: (state: T) => void): () => void;\n\tequals(val1: unknown, val2: unknown): boolean;\n}\n\n/**\n * A Universe manages many stores.\n */\nexport interface Universe {\n\tgetStore<T>(\n\t\tkey: string,\n\t\tinit: () => T,\n\t\treducer?: (prev: T, intent: unknown) => T,\n\t\tequals?: (v1: unknown, v2: unknown) => boolean,\n\t): Store<T>;\n\tsnapshot(): Record<string, unknown>;\n\trestore(data: Record<string, unknown>): void;\n\tdelete(key: string): void;\n\tclear(): void;\n\thydrateSnapshot(snapshot: ZunoSnapshot): void;\n}\n\n// --- Middleware Types ---\n\nexport type Dispatch = (event: ZunoStateEvent) => Promise<TransportStatus>;\n\nexport type MiddlewareAPI = {\n\tuniverse: Universe;\n\tclientId: string;\n\tversions: Map<string, number>;\n};\n\nexport type Middleware = (api: MiddlewareAPI) => (next: Dispatch) => Dispatch;\n\n/**\n * Options for creating a Zuno instance.\n */\nexport type CreateZunoOptions = {\n\t/** Optional pre-existing universe. */\n\tuniverse?: Universe;\n\t/** BroadcastChannel name for local tab sync. */\n\tchannelName?: string;\n\t/** SSE endpoint URL. */\n\tsseUrl?: string;\n\t/** Sync endpoint URL (required if sseUrl is provided). */\n\tsyncUrl?: string;\n\t/** Apply updates locally before server confirmation (default: true). */\n\toptimistic?: boolean;\n\t/** Batch multiple updates in the same microtask (default: false). */\n\tbatchSync?: boolean;\n\t/** Unique client identifier (default: random UUID). */\n\tclientId?: string;\n\t/** Middleware chain. */\n\tmiddleware?: Middleware[];\n\t/** Optional function to resolve 409 conflicts. */\n\tresolveConflict?: ConflictResolver;\n\t/** Maximum mutations retained while offline (default: 100). */\n\tmaxQueueSize?: number;\n\t/** Maximum automatic retries for a single conflict (default: 3). */\n\tmaxConflictRetries?: number;\n\t/** Optional durable queue used for offline/server-error mutations. */\n\tofflineQueue?: ZunoOfflineQueue;\n};\n\n/**\n * An extended interface for a Zuno store that includes methods for setting state\n * and a unique key identifier. This represents a store that has been \"bound\" or registered.\n */\nexport type BoundStore<T> = {\n\tkey: string;\n\tget: () => T;\n\tset: (next: T | ((prev: T) => T)) => Promise<unknown>;\n\tsubscribe: (cb: (state: T) => void) => () => void;\n\tequals: (v1: unknown, v2: unknown) => boolean;\n\traw: () => Store<T>;\n};\n\n// --- Store Implementation ---\n\n/**\n * Creates a raw ZUNO state management store.\n */\nexport const createStore = <T>(\n\tinitial: T,\n\treducer?: (prev: T, intent: unknown) => T,\n\tequals: (v1: unknown, v2: unknown) => boolean = Object.is,\n): Store<T> => {\n\tlet state = initial;\n\tconst listeners = new Set<(state: T) => void>();\n\n\tconst notify = () => {\n\t\tlisteners.forEach((l) => {\n\t\t\tl(state);\n\t\t});\n\t};\n\n\treturn {\n\t\tget: () => state,\n\t\tequals,\n\t\tset: (next) => {\n\t\t\tconst value =\n\t\t\t\ttypeof next === \"function\" ? (next as (prev: T) => T)(state) : next;\n\t\t\tif (equals(value, state)) return;\n\t\t\tstate = value;\n\t\t\tnotify();\n\t\t},\n\t\tapply: (intent) => {\n\t\t\tconst i = intent as { type: string; payload?: unknown };\n\t\t\tif (i.type === \"SET\") {\n\t\t\t\tconst value = i.payload as T;\n\t\t\t\tif (equals(value, state)) return;\n\t\t\t\tstate = value;\n\t\t\t\tnotify();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!reducer) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`[Zuno] apply() called for intent \"${i.type}\" on a store without a reducer. Intent ignored.`,\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst nextState = reducer(state, i);\n\t\t\tif (equals(nextState, state)) return;\n\t\t\tstate = nextState;\n\t\t\tnotify();\n\t\t},\n\t\tsubscribe: (listener) => {\n\t\t\tlisteners.add(listener);\n\t\t\treturn () => listeners.delete(listener);\n\t\t},\n\t};\n};\n\n// --- Universe Implementation ---\n\n/**\n * Creates a ZUNO Universe to manage multiple stores.\n */\nexport const createUniverse = (): Universe => {\n\t// biome-ignore lint/suspicious/noExplicitAny: internal registry of heterogeneous stores\n\tconst stores = new Map<string, Store<any>>();\n\tlet cachedSnapshot: Record<string, unknown> | null = null;\n\tconst trackStore = <T>(store: Store<T>) => {\n\t\tstore.subscribe(() => {\n\t\t\tcachedSnapshot = null;\n\t\t});\n\t\treturn store;\n\t};\n\n\tconst universe: Universe = {\n\t\tgetStore<T>(\n\t\t\tkey: string,\n\t\t\tinit: () => T,\n\t\t\treducer?: (prev: T, intent: unknown) => T,\n\t\t\tequals?: (v1: unknown, v2: unknown) => boolean,\n\t\t): Store<T> {\n\t\t\tlet s = stores.get(key);\n\t\t\tif (!s) {\n\t\t\t\ts = trackStore(createStore(init(), reducer, equals));\n\t\t\t\tstores.set(key, s);\n\t\t\t\tcachedSnapshot = null;\n\t\t\t}\n\t\t\treturn s as Store<T>;\n\t\t},\n\t\tsnapshot(): Record<string, unknown> {\n\t\t\tif (cachedSnapshot) return cachedSnapshot;\n\n\t\t\tconst out: Record<string, unknown> = {};\n\t\t\tfor (const [key, store] of stores.entries()) {\n\t\t\t\tout[key] = store.get();\n\t\t\t}\n\t\t\tcachedSnapshot = out;\n\t\t\treturn out;\n\t\t},\n\t\trestore(data: Record<string, unknown>): void {\n\t\t\tfor (const [key, value] of Object.entries(data)) {\n\t\t\t\tconst existing = stores.get(key);\n\t\t\t\tif (existing) {\n\t\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: external data needs to be cast to store type\n\t\t\t\t\texisting.set(value as any);\n\t\t\t\t} else {\n\t\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: external data needs to be cast to store type\n\t\t\t\t\tstores.set(key, trackStore(createStore(value as any)));\n\t\t\t\t\tcachedSnapshot = null;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tdelete(key: string): void {\n\t\t\tstores.delete(key);\n\t\t\tcachedSnapshot = null;\n\t\t},\n\t\tclear(): void {\n\t\t\tstores.clear();\n\t\t\tcachedSnapshot = null;\n\t\t},\n\t\thydrateSnapshot(snapshot: ZunoSnapshot) {\n\t\t\tconst plain: Record<string, unknown> = {};\n\t\t\tfor (const [k, rec] of Object.entries(snapshot.state)) {\n\t\t\t\tplain[k] = rec.state;\n\t\t\t}\n\t\t\tthis.restore(plain);\n\t\t},\n\t};\n\n\treturn universe;\n};\n\n// --- Main Zuno Factory ---\n\n/**\n * Creates a Zuno instance for distributed state synchronization.\n */\nexport const createZuno = (opts: CreateZunoOptions = {}) => {\n\tconst localState = new Map<string, unknown>();\n\tconst versions = new Map<string, number>();\n\tconst universe = opts.universe ?? createUniverse();\n\tconst clientId =\n\t\topts.clientId ?? globalThis.crypto?.randomUUID?.() ?? String(Math.random());\n\tlet _sseReady = false;\n\tlet lastEventId = 0;\n\n\tfunction hydrateSnapshot(snapshot: ZunoSnapshot) {\n\t\tconst plain: Record<string, unknown> = {};\n\t\tfor (const [k, rec] of Object.entries(snapshot.state)) {\n\t\t\tplain[k] = rec.state;\n\t\t\tversions.set(k, rec.version);\n\t\t}\n\t\tuniverse.restore(plain);\n\t\tlastEventId = snapshot.lastEventId;\n\t}\n\n\tconst apply = (event: ZunoStateEvent) => {\n\t\tif (typeof event.eventId === \"number\") {\n\t\t\tlastEventId = Math.max(lastEventId, event.eventId);\n\t\t}\n\t\tapplyIncomingEvent(universe, event, { clientId, localState, versions });\n\t};\n\n\tconst sse =\n\t\topts.sseUrl && opts.syncUrl\n\t\t\t? startSSE({\n\t\t\t\t\tuniverse,\n\t\t\t\t\turl: opts.sseUrl,\n\t\t\t\t\tsyncUrl: opts.syncUrl,\n\t\t\t\t\toptimistic: opts.optimistic ?? true,\n\t\t\t\t\tclientId,\n\t\t\t\t\tversions,\n\t\t\t\t\tgetLastEventId: () => lastEventId,\n\t\t\t\t\tsetLastEventId: (id) => {\n\t\t\t\t\t\tlastEventId = id;\n\t\t\t\t\t},\n\t\t\t\t\tmaxQueueSize: opts.maxQueueSize,\n\t\t\t\t\tmaxConflictRetries: opts.maxConflictRetries,\n\t\t\t\t\tofflineQueue: opts.offlineQueue,\n\t\t\t\t\tonOpen: () => {\n\t\t\t\t\t\t_sseReady = true;\n\t\t\t\t\t},\n\t\t\t\t\tonClose: () => {\n\t\t\t\t\t\t_sseReady = false;\n\t\t\t\t\t},\n\t\t\t\t\tonEvent: (e) => dispatch(e), // Route incoming SSE events through middleware\n\t\t\t\t\tresolveConflict: opts.resolveConflict,\n\t\t\t\t})\n\t\t\t: null;\n\n\tconst bc = opts.channelName\n\t\t? startBroadcastChannel({\n\t\t\t\tchannelName: opts.channelName,\n\t\t\t\tclientId,\n\t\t\t\tonEvent: (e) => dispatch(e), // Route incoming BC events through middleware\n\t\t\t\tgetSnapshot: () => {\n\t\t\t\t\tconst snap = universe.snapshot();\n\t\t\t\t\tconst out: Record<string, { state: unknown; version: number }> = {};\n\t\t\t\t\tfor (const [storeKey, state] of Object.entries(snap)) {\n\t\t\t\t\t\tout[storeKey] = { state, version: versions.get(storeKey) ?? 0 };\n\t\t\t\t\t}\n\t\t\t\t\treturn out;\n\t\t\t\t},\n\t\t\t\tonSnapshot: (snap) => {\n\t\t\t\t\tfor (const [storeKey, rec] of Object.entries(snap)) {\n\t\t\t\t\t\tapply({ storeKey, state: rec.state, version: rec.version });\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t})\n\t\t: null;\n\n\tsetTimeout(() => bc?.hello(), 100);\n\n\t// --- Sync Batching ---\n\tconst pendingSyncs = new Map<string, ZunoStateEvent>();\n\tlet batchPromise: Promise<void> | null = null;\n\n\tconst flushBatch = async () => {\n\t\tconst syncs = Array.from(pendingSyncs.values());\n\t\tpendingSyncs.clear();\n\t\tbatchPromise = null;\n\n\t\tfor (const event of syncs) {\n\t\t\tif (sse) {\n\t\t\t\tsse.dispatch(event).catch((err) => {\n\t\t\t\t\tconsole.error(\"[Zuno] Batch sync failed\", err);\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t};\n\n\tconst coreDispatch = async (\n\t\tevent: ZunoStateEvent,\n\t): Promise<TransportStatus> => {\n\t\t// 1. Incoming/Reflected Event Logic (events WITH origin)\n\t\tif (event.origin) {\n\t\t\t// Always call apply to let applyIncomingEvent handle version checks and application\n\t\t\tapply(event);\n\n\t\t\t// If it's from another client, we are done\n\t\t\tif (event.origin !== clientId) {\n\t\t\t\treturn { ok: true, status: 200, json: null };\n\t\t\t}\n\t\t\t// If it's a reflected local event, we still need to broadcast it (fall through)\n\t\t}\n\n\t\t// 2. Outgoing Event Logic (events WITHOUT origin)\n\t\tif (!event.origin) {\n\t\t\tevent.origin = clientId;\n\n\t\t\t// Resolve state if needed (e.g. from mutate)\n\t\t\tconst store = universe.getStore(event.storeKey, () => undefined);\n\n\t\t\tif (event.state === undefined && event.intent) {\n\t\t\t\t// We need the state to send to server.\n\t\t\t\t// If optimistic, we apply it. If not, we only compute if it's a simple SET.\n\t\t\t\tif (opts.optimistic !== false) {\n\t\t\t\t\tstore.apply(event.intent);\n\t\t\t\t\tevent.state = store.get();\n\t\t\t\t} else {\n\t\t\t\t\tconst i = event.intent as { type: string; payload?: unknown };\n\t\t\t\t\tif (i.type === \"SET\") {\n\t\t\t\t\t\tevent.state = i.payload;\n\t\t\t\t\t}\n\t\t\t\t\t// For other intents with optimistic: false, we might send undefined state\n\t\t\t\t\t// and rely on the server to compute it authoritativeley.\n\t\t\t\t}\n\t\t\t} else if (event.state !== undefined) {\n\t\t\t\tif (opts.optimistic !== false) {\n\t\t\t\t\tstore.set(event.state as never);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Always send the authoritative version this mutation was based on.\n\t\t\tconst current = versions.get(event.storeKey) ?? 0;\n\t\t\tevent.baseVersion ??= current;\n\n\t\t\t// Local bookkeeping and optimistic versioning\n\t\t\tif (opts.optimistic !== false) {\n\t\t\t\tconst nextVersion = current + 1;\n\t\t\t\tversions.set(event.storeKey, nextVersion);\n\t\t\t\tevent.version = nextVersion;\n\t\t\t}\n\n\t\t\t// BROADCAST IMMEDIATELY to local tabs via BC\n\t\t\t// This ensures instant sync across tabs even if SSE is slow or down.\n\t\t\tif (bc) {\n\t\t\t\tbc.publish(event);\n\t\t\t}\n\t\t}\n\n\t\t// 3. Remote Sync (SSE/HTTP) with Optional Batching\n\t\tif (sse) {\n\t\t\tif (opts.batchSync) {\n\t\t\t\t// Coalesce outgoing syncs for the same storeKey within the same microtask\n\t\t\t\tconst pending = pendingSyncs.get(event.storeKey);\n\t\t\t\tpendingSyncs.set(event.storeKey, {\n\t\t\t\t\t...event,\n\t\t\t\t\tbaseVersion: pending?.baseVersion ?? event.baseVersion,\n\t\t\t\t});\n\n\t\t\t\tif (!batchPromise) {\n\t\t\t\t\tbatchPromise = Promise.resolve().then(flushBatch);\n\t\t\t\t}\n\n\t\t\t\t// Note: Batched dispatch currently returns a \"fake\" OK immediately\n\t\t\t\t// to avoid blocking the UI. Error handling is handled via console.error in flushBatch.\n\t\t\t\t// Real conflict resolution still happens via SSE's internal queue/retry.\n\t\t\t\treturn { ok: true, status: 202, json: { batched: true } };\n\t\t\t}\n\n\t\t\treturn await sse.dispatch(event);\n\t\t}\n\n\t\treturn { ok: true, status: 200, json: null };\n\t};\n\n\t// --- Middleware Composition ---\n\tlet dispatch: Dispatch = coreDispatch;\n\n\tif (opts.middleware && opts.middleware.length > 0) {\n\t\tconst middlewareAPI: MiddlewareAPI = {\n\t\t\tuniverse,\n\t\t\tclientId,\n\t\t\tversions,\n\t\t};\n\t\tconst chain = opts.middleware.map((middleware) =>\n\t\t\tmiddleware(middlewareAPI),\n\t\t);\n\t\tdispatch = chain.reduceRight(\n\t\t\t(next, middleware) => middleware(next),\n\t\t\tcoreDispatch,\n\t\t);\n\t}\n\n\tconst store = <T>(\n\t\tstoreKey: string,\n\t\tinit: () => T,\n\t\treducer?: (prev: T, intent: unknown) => T,\n\t\tequals?: (v1: unknown, v2: unknown) => boolean,\n\t): BoundStore<T> => {\n\t\tconst rawStore = universe.getStore<T>(storeKey, init, reducer, equals);\n\t\treturn {\n\t\t\tkey: storeKey,\n\t\t\traw: () => rawStore,\n\t\t\tget: () => rawStore.get(),\n\t\t\tsubscribe: (cb) => rawStore.subscribe(cb),\n\t\t\tequals: (v1, v2) => rawStore.equals(v1, v2),\n\t\t\tset: (next) => {\n\t\t\t\tconst prev = rawStore.get();\n\t\t\t\tconst state =\n\t\t\t\t\ttypeof next === \"function\" ? (next as (prev: T) => T)(prev) : next;\n\t\t\t\treturn dispatch({\n\t\t\t\t\tstoreKey,\n\t\t\t\t\tstate,\n\t\t\t\t\tintent: { type: \"SET\", payload: state },\n\t\t\t\t});\n\t\t\t},\n\t\t};\n\t};\n\n\treturn {\n\t\tuniverse,\n\t\tclientId,\n\t\tstore,\n\t\tgetStore: universe.getStore.bind(universe),\n\t\tget: <T>(key: string, init?: () => T) =>\n\t\t\tuniverse\n\t\t\t\t.getStore<T>(\n\t\t\t\t\tkey,\n\t\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: default init for convenience\n\t\t\t\t\tinit ?? (() => undefined as any),\n\t\t\t\t)\n\t\t\t\t.get(),\n\t\tset: async <T>(key: string, next: T | ((prev: T) => T), init?: () => T) => {\n\t\t\tconst s = universe.getStore<T>(\n\t\t\t\tkey,\n\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: default init for convenience\n\t\t\t\tinit ?? (() => undefined as any),\n\t\t\t);\n\t\t\tconst state =\n\t\t\t\ttypeof next === \"function\" ? (next as (prev: T) => T)(s.get()) : next;\n\n\t\t\t// Don't set origin or version here, let coreDispatch handle it\n\t\t\treturn dispatch({\n\t\t\t\tstoreKey: key,\n\t\t\t\tstate,\n\t\t\t\tintent: { type: \"SET\", payload: state },\n\t\t\t});\n\t\t},\n\t\tmutate: async (\n\t\t\tkey: string,\n\t\t\tintent: { type: string; payload?: unknown },\n\t\t) => {\n\t\t\treturn dispatch({\n\t\t\t\tstoreKey: key,\n\t\t\t\t// coreDispatch will calculate state from intent\n\t\t\t\tstate: undefined as unknown,\n\t\t\t\tintent,\n\t\t\t});\n\t\t},\n\t\tsubscribe: <T>(key: string, init: () => T, cb: (state: T) => void) =>\n\t\t\tuniverse.getStore<T>(key, init).subscribe(cb),\n\t\tdispatch,\n\t\tstop: () => {\n\t\t\tsse?.unsubscribe?.();\n\t\t\tbc?.stop?.();\n\t\t},\n\t\thydrateSnapshot,\n\t\tgetLastEventId: () => lastEventId,\n\t\tsetLastEventId: (id: number) => {\n\t\t\tlastEventId = id;\n\t\t},\n\t};\n};\n","/** Universal UI adapter contract */\nexport type ZunoReadable<T> = {\n\t/** Read current value (sync) */\n\tgetSnapshot(): T;\n\n\t/**\n\t * Subscribe to changes.\n\t * Call `onChange()` whenever snapshot may have changed.\n\t * Return unsubscribe.\n\t */\n\tsubscribe(onChange: () => void): () => void;\n\n\t/** Optional: React SSR (server snapshot) */\n\tgetServerSnapshot?: () => T;\n};\n\n/** Minimal store shape that can be adapted into a readable */\nexport type ZunoSubscribableStore<T> = {\n\tget(): T;\n\tsubscribe(cb: (state: T) => void): () => void;\n\tequals(v1: unknown, v2: unknown): boolean;\n};\n\n/** Adapter helper: convert store => readable */\nexport function toReadable<T>(\n\tstore: ZunoSubscribableStore<T>,\n): ZunoReadable<T> {\n\treturn {\n\t\tgetSnapshot: () => store.get(),\n\t\tsubscribe: (onChange) => store.subscribe(() => onChange()),\n\t};\n}\n","/**\n * Performs a shallow equality check between two values.\n */\nexport function shallowEqual(a: unknown, b: unknown): boolean {\n\tif (Object.is(a, b)) return true;\n\n\tif (\n\t\ttypeof a !== \"object\" ||\n\t\ta === null ||\n\t\ttypeof b !== \"object\" ||\n\t\tb === null\n\t) {\n\t\treturn false;\n\t}\n\n\tconst keysA = Object.keys(a as object);\n\tconst keysB = Object.keys(b as object);\n\n\tif (keysA.length !== keysB.length) return false;\n\n\tconst objA = a as Record<string, unknown>;\n\tconst objB = b as Record<string, unknown>;\n\n\tfor (const key of keysA) {\n\t\tif (!Object.hasOwn(objB, key) || !Object.is(objA[key], objB[key])) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { f as ZunoStateEvent } from '../index-3uqI2fJ2.cjs';
1
+ import { f as ZunoStateEvent } from '../index-BSBSRWd0.cjs';
2
2
  import { IncomingMessage, ServerResponse } from 'node:http';
3
3
 
4
4
  type UniverseRecord = {
@@ -1,4 +1,4 @@
1
- import { f as ZunoStateEvent } from '../index-3uqI2fJ2.js';
1
+ import { f as ZunoStateEvent } from '../index-BSBSRWd0.js';
2
2
  import { IncomingMessage, ServerResponse } from 'node:http';
3
3
 
4
4
  type UniverseRecord = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iadev93/zuno",
3
- "version": "0.0.12",
3
+ "version": "0.0.13",
4
4
  "author": "Ibrahim Aftab",
5
5
  "license": "MIT",
6
6
  "type": "module",