@lunora/db 1.0.0-alpha.40 → 1.0.0-alpha.42

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
@@ -85,6 +85,12 @@ export const createCollections = (client: LunoraClient) =>
85
85
 
86
86
  > `vis generate lunora-collections` scaffolds this from your `schema.ts` + functions.
87
87
 
88
+ Keep a **single `db` instance**, and treat its collections as the one source of
89
+ truth per table — don't mirror rows into your own store. A derived index (a tree,
90
+ a search index, an undo capture) built from a copy of the rows can silently read
91
+ stale data while the UI renders through `useLiveQuery`. See [One source of truth
92
+ per table](https://lunora.sh/docs/addons/db#one-source-of-truth-per-table).
93
+
88
94
  ### Local-first sync engine
89
95
 
90
96
  Beyond whole-table collections, the `@lunora/db/collections` and
@@ -1,5 +1,5 @@
1
1
  export { type C as CheckpointRegistry, type L as LunoraCollectionConfig, type a as LunoraCollectionOptions, c as createCheckpointRegistry, l as lunoraCollectionOptions } from "../packem_shared/collection-options.d-B_2IXvdU.mjs";
2
- export { type C as CollectionDef, type I as InsertBinding, type L as LunoraDb, d as defineCollections } from "../packem_shared/define-collections.d-C6J1Y4Q_.mjs";
2
+ export { type C as CollectionDef, type I as InsertBinding, type L as LunoraDb, d as defineCollections } from "../packem_shared/define-collections.d-Ciaqcod6.mjs";
3
3
  import '@lunora/client';
4
4
  import '@tanstack/db';
5
5
  import '@tanstack/offline-transactions';
@@ -1,5 +1,5 @@
1
1
  export { type C as CheckpointRegistry, type L as LunoraCollectionConfig, type a as LunoraCollectionOptions, c as createCheckpointRegistry, l as lunoraCollectionOptions } from "../packem_shared/collection-options.d-B_2IXvdU.js";
2
- export { type C as CollectionDef, type I as InsertBinding, type L as LunoraDb, d as defineCollections } from "../packem_shared/define-collections.d-DAFPHFxr.js";
2
+ export { type C as CollectionDef, type I as InsertBinding, type L as LunoraDb, d as defineCollections } from "../packem_shared/define-collections.d-B7pL91T8.js";
3
3
  import '@lunora/client';
4
4
  import '@tanstack/db';
5
5
  import '@tanstack/offline-transactions';
@@ -1 +1 @@
1
- import{createCheckpointRegistry as t,lunoraCollectionOptions as r}from"../packem_shared/CHECKPOINT_FALLBACK_MS-6GmTGWsH.mjs";import{defineCollections as n}from"../packem_shared/defineCollections-4CPSF9OJ.mjs";export{t as createCheckpointRegistry,n as defineCollections,r as lunoraCollectionOptions};
1
+ import{createCheckpointRegistry as t,lunoraCollectionOptions as r}from"../packem_shared/CHECKPOINT_FALLBACK_MS-B0XZscWq.mjs";import{defineCollections as n}from"../packem_shared/defineCollections-BbmvoISF.mjs";export{t as createCheckpointRegistry,n as defineCollections,r as lunoraCollectionOptions};
package/dist/index.d.mts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { Collection } from '@tanstack/db';
2
2
  import { R as Row } from "./packem_shared/collection-options.d-B_2IXvdU.mjs";
3
3
  export { b as CHECKPOINT_FALLBACK_MS, type d as CheckpointFallbackEvent, type C as CheckpointRegistry, type e as CheckpointRegistryOptions, type f as CheckpointRegistryStats, type g as CheckpointWatermark, type E as ExecutorOutboxSinkOptions, type L as LunoraCollectionConfig, type a as LunoraCollectionOptions, O as OUTBOX_MUTATION_FN_NAME, type h as OutboxExecutor, type i as OutboxMutationMetadata, type S as SyncWriter, c as createCheckpointRegistry, j as createExecutorOutboxSink, k as createOptimisticOnlineDetector, m as getShardCheckpoints, l as lunoraCollectionOptions, n as makeDiffEmit, r as releaseShardCheckpoints, o as runOutboxMutation, s as shardCheckpointStats, t as toMap } from "./packem_shared/collection-options.d-B_2IXvdU.mjs";
4
- export { type C as CollectionDef, type D as DefineCollectionsOptions, type I as InsertBinding, type L as LunoraDb, type W as WriteRejectedEvent, d as defineCollections } from "./packem_shared/define-collections.d-C6J1Y4Q_.mjs";
5
- export { type B as BindMutatorsContext, type a as BoundMutatorApi, type b as BoundMutators, type C as ClientMutatorContext, type c as ClientMutatorDef, type d as CollectionMap, D as DIRECT_TRANSACTION_METADATA_KEY, type g as MutatorReference, type M as MutatorRejectedEvent, e as bindMutators, f as defineMutator, i as initMutators } from "./packem_shared/define-mutators.d-BXQN7fju.mjs";
4
+ export { type C as CollectionDef, type D as DefineCollectionsOptions, type I as InsertBinding, type L as LunoraDb, type W as WriteRejectedEvent, d as defineCollections } from "./packem_shared/define-collections.d-Ciaqcod6.mjs";
5
+ export { type B as BindMutatorsContext, type a as BoundMutatorApi, type b as BoundMutators, type C as ClientMutatorContext, type c as ClientMutatorDef, type d as CollectionMap, D as DIRECT_TRANSACTION_METADATA_KEY, type g as MutatorReference, type M as MutatorRejectedEvent, e as bindMutators, f as defineMutator, i as initMutators } from "./packem_shared/define-mutators.d-D51n_r1n.mjs";
6
6
  import '@lunora/client';
7
7
  import '@tanstack/offline-transactions';
8
8
  /** One row to insert. `_id` may be pre-minted client-side so the optimistic row keys match the persisted one. */
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { Collection } from '@tanstack/db';
2
2
  import { R as Row } from "./packem_shared/collection-options.d-B_2IXvdU.js";
3
3
  export { b as CHECKPOINT_FALLBACK_MS, type d as CheckpointFallbackEvent, type C as CheckpointRegistry, type e as CheckpointRegistryOptions, type f as CheckpointRegistryStats, type g as CheckpointWatermark, type E as ExecutorOutboxSinkOptions, type L as LunoraCollectionConfig, type a as LunoraCollectionOptions, O as OUTBOX_MUTATION_FN_NAME, type h as OutboxExecutor, type i as OutboxMutationMetadata, type S as SyncWriter, c as createCheckpointRegistry, j as createExecutorOutboxSink, k as createOptimisticOnlineDetector, m as getShardCheckpoints, l as lunoraCollectionOptions, n as makeDiffEmit, r as releaseShardCheckpoints, o as runOutboxMutation, s as shardCheckpointStats, t as toMap } from "./packem_shared/collection-options.d-B_2IXvdU.js";
4
- export { type C as CollectionDef, type D as DefineCollectionsOptions, type I as InsertBinding, type L as LunoraDb, type W as WriteRejectedEvent, d as defineCollections } from "./packem_shared/define-collections.d-DAFPHFxr.js";
5
- export { type B as BindMutatorsContext, type a as BoundMutatorApi, type b as BoundMutators, type C as ClientMutatorContext, type c as ClientMutatorDef, type d as CollectionMap, D as DIRECT_TRANSACTION_METADATA_KEY, type g as MutatorReference, type M as MutatorRejectedEvent, e as bindMutators, f as defineMutator, i as initMutators } from "./packem_shared/define-mutators.d-DLP_vYu9.js";
4
+ export { type C as CollectionDef, type D as DefineCollectionsOptions, type I as InsertBinding, type L as LunoraDb, type W as WriteRejectedEvent, d as defineCollections } from "./packem_shared/define-collections.d-B7pL91T8.js";
5
+ export { type B as BindMutatorsContext, type a as BoundMutatorApi, type b as BoundMutators, type C as ClientMutatorContext, type c as ClientMutatorDef, type d as CollectionMap, D as DIRECT_TRANSACTION_METADATA_KEY, type g as MutatorReference, type M as MutatorRejectedEvent, e as bindMutators, f as defineMutator, i as initMutators } from "./packem_shared/define-mutators.d-DuAmdkYR.js";
6
6
  import '@lunora/client';
7
7
  import '@tanstack/offline-transactions';
8
8
  /** One row to insert. `_id` may be pre-minted client-side so the optimistic row keys match the persisted one. */
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{applyPlanToCollections as r,applyPlanToDb as i}from"./packem_shared/applyPlanToCollections-C29s6OoX.mjs";import{CHECKPOINT_FALLBACK_MS as a,createCheckpointRegistry as p,getShardCheckpoints as c,lunoraCollectionOptions as l,releaseShardCheckpoints as s,shardCheckpointStats as C}from"./packem_shared/CHECKPOINT_FALLBACK_MS-6GmTGWsH.mjs";import{defineCollections as T}from"./packem_shared/defineCollections-4CPSF9OJ.mjs";import{DIRECT_TRANSACTION_METADATA_KEY as u,bindMutators as x,defineMutator as A,initMutators as M}from"./packem_shared/DIRECT_TRANSACTION_METADATA_KEY-D1XuUJtq.mjs";import{OUTBOX_MUTATION_FN_NAME as E,createExecutorOutboxSink as _,createOptimisticOnlineDetector as h,makeDiffEmit as N,runOutboxMutation as S,toMap as d}from"./packem_shared/OUTBOX_MUTATION_FN_NAME-CebgkYw2.mjs";const t="0.0.0";export{a as CHECKPOINT_FALLBACK_MS,u as DIRECT_TRANSACTION_METADATA_KEY,E as OUTBOX_MUTATION_FN_NAME,t as VERSION,r as applyPlanToCollections,i as applyPlanToDb,x as bindMutators,p as createCheckpointRegistry,_ as createExecutorOutboxSink,h as createOptimisticOnlineDetector,T as defineCollections,A as defineMutator,c as getShardCheckpoints,M as initMutators,l as lunoraCollectionOptions,N as makeDiffEmit,s as releaseShardCheckpoints,S as runOutboxMutation,C as shardCheckpointStats,d as toMap};
1
+ import{applyPlanToCollections as r,applyPlanToDb as i}from"./packem_shared/applyPlanToCollections-C29s6OoX.mjs";import{CHECKPOINT_FALLBACK_MS as a,createCheckpointRegistry as p,getShardCheckpoints as c,lunoraCollectionOptions as l,releaseShardCheckpoints as s,shardCheckpointStats as C}from"./packem_shared/CHECKPOINT_FALLBACK_MS-B0XZscWq.mjs";import{defineCollections as T}from"./packem_shared/defineCollections-BbmvoISF.mjs";import{DIRECT_TRANSACTION_METADATA_KEY as u,bindMutators as x,defineMutator as A,initMutators as M}from"./packem_shared/DIRECT_TRANSACTION_METADATA_KEY-B9s9Zmty.mjs";import{OUTBOX_MUTATION_FN_NAME as E,createExecutorOutboxSink as _,createOptimisticOnlineDetector as h,makeDiffEmit as N,runOutboxMutation as S,toMap as d}from"./packem_shared/OUTBOX_MUTATION_FN_NAME-BznV-kE1.mjs";const t="0.0.0";export{a as CHECKPOINT_FALLBACK_MS,u as DIRECT_TRANSACTION_METADATA_KEY,E as OUTBOX_MUTATION_FN_NAME,t as VERSION,r as applyPlanToCollections,i as applyPlanToDb,x as bindMutators,p as createCheckpointRegistry,_ as createExecutorOutboxSink,h as createOptimisticOnlineDetector,T as defineCollections,A as defineMutator,c as getShardCheckpoints,M as initMutators,l as lunoraCollectionOptions,N as makeDiffEmit,s as releaseShardCheckpoints,S as runOutboxMutation,C as shardCheckpointStats,d as toMap};
@@ -1,4 +1,4 @@
1
- export { type B as BindMutatorsContext, type a as BoundMutatorApi, type b as BoundMutators, type C as ClientMutatorContext, type c as ClientMutatorDef, type d as CollectionMap, type M as MutatorRejectedEvent, e as bindMutators, f as defineMutator, i as initMutators } from "../packem_shared/define-mutators.d-BXQN7fju.mjs";
1
+ export { type B as BindMutatorsContext, type a as BoundMutatorApi, type b as BoundMutators, type C as ClientMutatorContext, type c as ClientMutatorDef, type d as CollectionMap, type M as MutatorRejectedEvent, e as bindMutators, f as defineMutator, i as initMutators } from "../packem_shared/define-mutators.d-D51n_r1n.mjs";
2
2
  import '@lunora/client';
3
3
  import '@tanstack/db';
4
4
  import "../packem_shared/collection-options.d-B_2IXvdU.mjs";
@@ -1,4 +1,4 @@
1
- export { type B as BindMutatorsContext, type a as BoundMutatorApi, type b as BoundMutators, type C as ClientMutatorContext, type c as ClientMutatorDef, type d as CollectionMap, type M as MutatorRejectedEvent, e as bindMutators, f as defineMutator, i as initMutators } from "../packem_shared/define-mutators.d-DLP_vYu9.js";
1
+ export { type B as BindMutatorsContext, type a as BoundMutatorApi, type b as BoundMutators, type C as ClientMutatorContext, type c as ClientMutatorDef, type d as CollectionMap, type M as MutatorRejectedEvent, e as bindMutators, f as defineMutator, i as initMutators } from "../packem_shared/define-mutators.d-DuAmdkYR.js";
2
2
  import '@lunora/client';
3
3
  import '@tanstack/db';
4
4
  import "../packem_shared/collection-options.d-B_2IXvdU.js";
@@ -1 +1 @@
1
- import{bindMutators as r,defineMutator as i,initMutators as a}from"../packem_shared/DIRECT_TRANSACTION_METADATA_KEY-D1XuUJtq.mjs";export{r as bindMutators,i as defineMutator,a as initMutators};
1
+ import{bindMutators as r,defineMutator as i,initMutators as a}from"../packem_shared/DIRECT_TRANSACTION_METADATA_KEY-B9s9Zmty.mjs";export{r as bindMutators,i as defineMutator,a as initMutators};
@@ -1 +1 @@
1
- import{LunoraError as y}from"@lunora/errors";import{BTreeIndex as b}from"@tanstack/db";import{toMap as C,makeDiffEmit as T}from"./OUTBOX_MUTATION_FN_NAME-CebgkYw2.mjs";const I=()=>{let e=Number.NEGATIVE_INFINITY;const r=[];return{advance:o=>{if(!(o<=e)){e=o;for(let a=r.length-1;a>=0;a-=1){const i=r[a];i&&i.threshold<=e&&(i.resolve(),r.splice(a,1))}}},await:o=>o<=e?Promise.resolve():new Promise(a=>{r.push({resolve:a,threshold:o})}),passed:o=>o<=e,waiting:()=>r.length}},M=3e3;let g=!1;const N=e=>{g||(g=!0,console.warn(`[@lunora/db] released an optimistic overlay via the ${String(e.waitedMs)}ms checkpoint fallback: the server confirmed ${e.kind} ${String(e.watermark)} but no sync frame ever echoed it. A dropped shape poke or \`settled\` frame is the usual cause — inspect the subscription rather than raising \`fallbackMs\`. (Reported once per process.)`))},S=(e={})=>{const r=e.fallbackMs??M,o=e.onFallback??N,a=I(),i=I();let d=0;const c=new Set,l=(t,s)=>{for(const n of c)n.kind===t&&n.threshold<=s&&(clearTimeout(n.handle),c.delete(n))},p=(t,s)=>{if(r<=0)return;const n=t==="checkpoint"?a:i;if(n.passed(s))return;for(const k of c)if(k.kind===t&&k.threshold>=s)return;const u={handle:setTimeout(()=>{if(c.delete(u),!n.passed(s)){d+=1,n.advance(s);try{o({kind:t,waitedMs:r,watermark:s})}catch{}}},r),kind:t,threshold:s};c.add(u)};return{acknowledge:({checkpoint:t,mutationId:s})=>{t!==void 0&&p("checkpoint",t),s!==void 0&&p("mutationId",s)},awaitCheckpoint:t=>a.await(t),awaitMutationId:t=>i.await(t),dispose:()=>{for(const t of c)clearTimeout(t.handle);c.clear()},resolve:({checkpoint:t,mutationId:s})=>{t!==void 0&&(a.advance(t),l("checkpoint",t)),s!==void 0&&(i.advance(s),l("mutationId",s))},stats:()=>({fallbacks:d,pendingCheckpointWaiters:a.waiting(),pendingMutationWaiters:i.waiting()})}},m=new WeakMap,E=(e,r,o)=>{let a=m.get(e);a||(a=new Map,m.set(e,a));const i=r??"",d=a.get(i);if(d)return d;const c=S(o);return a.set(i,c),c},w=new WeakSet,K=e=>{w.add(e)},x=e=>w.has(e),F=e=>{const r=m.get(e);if(r){for(const o of r.values())o.resolve({checkpoint:Number.POSITIVE_INFINITY,mutationId:Number.POSITIVE_INFINITY}),o.dispose();m.delete(e)}},O=e=>{const r=m.get(e),o={};if(r)for(const[a,i]of r)o[a]=i.stats();return o},P=e=>{if(e.list===void 0==(e.shape===void 0))throw new y("INTERNAL","lunoraCollectionOptions: pass exactly one of `list` or `shape`");const r=e.getKey??(n=>n._id),o=e.checkpoints??E(e.client,e.shape?.shardKey??e.shardKey);K(o);const a=new Map;let i,d,c,l,p;const t=(n,u)=>{const k=h=>{i?.(C(h,r)),u?.(),e.shape===void 0&&(o.resolve({mutationId:p??e.client.confirmedMutationWatermark(e.shardKey)}),p=void 0)},f=h=>c?.(h),v=h=>{h.mutationId!==void 0&&(p=h.mutationId),o.resolve(h)};return e.shape!==void 0?e.client.subscribeShape({args:n,name:e.shape.name},k,{onCheckpoint:v,onError:f,shardKey:e.shape.shardKey}):e.client.subscribe(e.list,n,k,{onCheckpoint:v,onError:f,shardKey:e.shardKey})},s={autoIndex:"eager",defaultIndexType:b,getKey:r,id:e.id??e.list?.__lunoraRef??`shape:${e.shape?.name??""}`,...e.load==="eager"?{startSync:!0}:{},sync:{sync:n=>(i=T(a,n),c=u=>{n.markReady(),e.onError?.(u)},e.scopeBy===void 0?d=t(e.shape?.args??{},()=>{n.markReady()}):(n.markReady(),l!==void 0&&(d=t(l,void 0))),()=>{i=void 0,c=void 0,d?.(),d=void 0,a.clear()})}};return{checkpoints:o,config:s,scope:n=>{e.scopeBy!==void 0&&(l=n,d?.(),d=void 0,i?.(new Map),n!==void 0&&i!==void 0&&(d=t(n,void 0)))}}};export{M as CHECKPOINT_FALLBACK_MS,S as createCheckpointRegistry,E as getShardCheckpoints,x as hasCheckpointsAttached,P as lunoraCollectionOptions,K as markCheckpointsAttached,F as releaseShardCheckpoints,O as shardCheckpointStats};
1
+ import{LunoraError as y}from"@lunora/errors";import{BTreeIndex as b}from"@tanstack/db";import{toMap as C,makeDiffEmit as T}from"./OUTBOX_MUTATION_FN_NAME-BznV-kE1.mjs";const I=()=>{let e=Number.NEGATIVE_INFINITY;const r=[];return{advance:o=>{if(!(o<=e)){e=o;for(let a=r.length-1;a>=0;a-=1){const i=r[a];i&&i.threshold<=e&&(i.resolve(),r.splice(a,1))}}},await:o=>o<=e?Promise.resolve():new Promise(a=>{r.push({resolve:a,threshold:o})}),passed:o=>o<=e,waiting:()=>r.length}},M=3e3;let g=!1;const N=e=>{g||(g=!0,console.warn(`[@lunora/db] released an optimistic overlay via the ${String(e.waitedMs)}ms checkpoint fallback: the server confirmed ${e.kind} ${String(e.watermark)} but no sync frame ever echoed it. A dropped shape poke or \`settled\` frame is the usual cause — inspect the subscription rather than raising \`fallbackMs\`. (Reported once per process.)`))},S=(e={})=>{const r=e.fallbackMs??M,o=e.onFallback??N,a=I(),i=I();let d=0;const c=new Set,l=(t,s)=>{for(const n of c)n.kind===t&&n.threshold<=s&&(clearTimeout(n.handle),c.delete(n))},p=(t,s)=>{if(r<=0)return;const n=t==="checkpoint"?a:i;if(n.passed(s))return;for(const k of c)if(k.kind===t&&k.threshold>=s)return;const u={handle:setTimeout(()=>{if(c.delete(u),!n.passed(s)){d+=1,n.advance(s);try{o({kind:t,waitedMs:r,watermark:s})}catch{}}},r),kind:t,threshold:s};c.add(u)};return{acknowledge:({checkpoint:t,mutationId:s})=>{t!==void 0&&p("checkpoint",t),s!==void 0&&p("mutationId",s)},awaitCheckpoint:t=>a.await(t),awaitMutationId:t=>i.await(t),dispose:()=>{for(const t of c)clearTimeout(t.handle);c.clear()},resolve:({checkpoint:t,mutationId:s})=>{t!==void 0&&(a.advance(t),l("checkpoint",t)),s!==void 0&&(i.advance(s),l("mutationId",s))},stats:()=>({fallbacks:d,pendingCheckpointWaiters:a.waiting(),pendingMutationWaiters:i.waiting()})}},m=new WeakMap,E=(e,r,o)=>{let a=m.get(e);a||(a=new Map,m.set(e,a));const i=r??"",d=a.get(i);if(d)return d;const c=S(o);return a.set(i,c),c},w=new WeakSet,K=e=>{w.add(e)},x=e=>w.has(e),F=e=>{const r=m.get(e);if(r){for(const o of r.values())o.resolve({checkpoint:Number.POSITIVE_INFINITY,mutationId:Number.POSITIVE_INFINITY}),o.dispose();m.delete(e)}},O=e=>{const r=m.get(e),o={};if(r)for(const[a,i]of r)o[a]=i.stats();return o},P=e=>{if(e.list===void 0==(e.shape===void 0))throw new y("INTERNAL","lunoraCollectionOptions: pass exactly one of `list` or `shape`");const r=e.getKey??(n=>n._id),o=e.checkpoints??E(e.client,e.shape?.shardKey??e.shardKey);K(o);const a=new Map;let i,d,c,l,p;const t=(n,u)=>{const k=h=>{i?.(C(h,r)),u?.(),e.shape===void 0&&(o.resolve({mutationId:p??e.client.confirmedMutationWatermark(e.shardKey)}),p=void 0)},f=h=>c?.(h),v=h=>{h.mutationId!==void 0&&(p=h.mutationId),o.resolve(h)};return e.shape!==void 0?e.client.subscribeShape({args:n,name:e.shape.name},k,{onCheckpoint:v,onError:f,shardKey:e.shape.shardKey}):e.client.subscribe(e.list,n,k,{onCheckpoint:v,onError:f,shardKey:e.shardKey})},s={autoIndex:"eager",defaultIndexType:b,getKey:r,id:e.id??e.list?.__lunoraRef??`shape:${e.shape?.name??""}`,...e.load==="eager"?{startSync:!0}:{},sync:{sync:n=>(i=T(a,n),c=u=>{n.markReady(),e.onError?.(u)},e.scopeBy===void 0?d=t(e.shape?.args??{},()=>{n.markReady()}):(n.markReady(),l!==void 0&&(d=t(l,void 0))),()=>{i=void 0,c=void 0,d?.(),d=void 0,a.clear()})}};return{checkpoints:o,config:s,scope:n=>{e.scopeBy!==void 0&&(l=n,d?.(),d=void 0,i?.(new Map),n!==void 0&&i!==void 0&&(d=t(n,void 0)))}}};export{M as CHECKPOINT_FALLBACK_MS,S as createCheckpointRegistry,E as getShardCheckpoints,x as hasCheckpointsAttached,P as lunoraCollectionOptions,K as markCheckpointsAttached,F as releaseShardCheckpoints,O as shardCheckpointStats};
@@ -1 +1 @@
1
- import{LunoraError as d}from"@lunora/errors";import{createTransaction as w}from"@tanstack/db";import{getShardCheckpoints as M,hasCheckpointsAttached as g}from"./CHECKPOINT_FALLBACK_MS-6GmTGWsH.mjs";import{runOutboxMutation as _}from"./OUTBOX_MUTATION_FN_NAME-CebgkYw2.mjs";const v="__tanstack_db_direct",k="defineMutator: `serverRef` must be a generated mutator reference (api.mutators.*) or a 'namespace:fn' string",T=r=>{const t=typeof r=="string"?r:r?.__lunoraRef;if(typeof t!="string"||t.length===0)throw new d("INTERNAL",k);return t},A=r=>({__lunoraClientMutator:!0,apply:r.apply,serverRef:T(r.serverRef)}),E=(r,t,l)=>{let i=0;const h=()=>(i=Math.max(i,r.confirmedMutationWatermark(t.shardKey))+1,i);let u=Promise.resolve();const p=(o,a)=>{const s=u.then(async()=>{for(let c=0;;c+=1){const n=h();try{const{applied:e}=await r.callMutator(o,a,{clientSeq:n,shardKey:t.shardKey});if(e)return n}catch(e){throw i=r.confirmedMutationWatermark(t.shardKey),e}if(c>=32)throw new d("INTERNAL",`lunora: custom mutator "${o}" could not claim a fresh client sequence after ${String(32)} attempts`)}});return u=s.then(()=>{},()=>{}),s},y=()=>{if(t.checkpoints===!1)return;if(t.checkpoints)return t.checkpoints;const o=M(r,t.shardKey);return g(o)?o:void 0},R=(o,a,s,c)=>{const{onWriteRejected:n}=t;n&&o.isPersisted.promise.catch(e=>{const m=e instanceof Error?e:new Error(String(e));try{n({args:c,code:m.code,error:m,mutator:a,serverRef:s})}catch{}})},f={};for(const[o,a]of Object.entries(l))f[o]=s=>{const c=w({autoCommit:!0,metadata:{[v]:!0,serverRef:a.serverRef},mutationFn:async()=>{let n=0;await _(async()=>{n=await p(a.serverRef,s)});const e=y();e&&(e.acknowledge({mutationId:n}),await e.awaitMutationId(n))}});return c.mutate(()=>{a.apply({collections:t.collections},s)}),R(c,o,a.serverRef,s),c};return f},b=()=>({bindMutators:E,defineMutator:A});export{v as DIRECT_TRANSACTION_METADATA_KEY,E as bindMutators,A as defineMutator,b as initMutators};
1
+ import{LunoraError as d}from"@lunora/errors";import{createTransaction as w}from"@tanstack/db";import{getShardCheckpoints as M,hasCheckpointsAttached as g}from"./CHECKPOINT_FALLBACK_MS-B0XZscWq.mjs";import{runOutboxMutation as _}from"./OUTBOX_MUTATION_FN_NAME-BznV-kE1.mjs";const v="__tanstack_db_direct",k="defineMutator: `serverRef` must be a generated mutator reference (api.mutators.*) or a 'namespace:fn' string",T=r=>{const t=typeof r=="string"?r:r?.__lunoraRef;if(typeof t!="string"||t.length===0)throw new d("INTERNAL",k);return t},A=r=>({__lunoraClientMutator:!0,apply:r.apply,serverRef:T(r.serverRef)}),E=(r,t,l)=>{let i=0;const h=()=>(i=Math.max(i,r.confirmedMutationWatermark(t.shardKey))+1,i);let u=Promise.resolve();const p=(o,a)=>{const s=u.then(async()=>{for(let c=0;;c+=1){const n=h();try{const{applied:e}=await r.callMutator(o,a,{clientSeq:n,shardKey:t.shardKey});if(e)return n}catch(e){throw i=r.confirmedMutationWatermark(t.shardKey),e}if(c>=32)throw new d("INTERNAL",`lunora: custom mutator "${o}" could not claim a fresh client sequence after ${String(32)} attempts`)}});return u=s.then(()=>{},()=>{}),s},y=()=>{if(t.checkpoints===!1)return;if(t.checkpoints)return t.checkpoints;const o=M(r,t.shardKey);return g(o)?o:void 0},R=(o,a,s,c)=>{const{onWriteRejected:n}=t;n&&o.isPersisted.promise.catch(e=>{const m=e instanceof Error?e:new Error(String(e));try{n({args:c,code:m.code,error:m,mutator:a,serverRef:s})}catch{}})},f={};for(const[o,a]of Object.entries(l))f[o]=s=>{const c=w({autoCommit:!0,metadata:{[v]:!0,serverRef:a.serverRef},mutationFn:async()=>{let n=0;await _(async()=>{n=await p(a.serverRef,s)});const e=y();e&&(e.acknowledge({mutationId:n}),await e.awaitMutationId(n))}});return c.mutate(()=>{a.apply({collections:t.collections},s)}),R(c,o,a.serverRef,s),c};return f},b=()=>({bindMutators:E,defineMutator:A});export{v as DIRECT_TRANSACTION_METADATA_KEY,E as bindMutators,A as defineMutator,b as initMutators};
@@ -0,0 +1 @@
1
+ import{createCollection as m,safeRandomUUID as f}from"@tanstack/db";import{NonRetriableError as y}from"@tanstack/offline-transactions";const p=1e3,d="__lunora_outbox__",l=new WeakMap,w=()=>m({getKey:e=>e._id,id:`${d}:${f()}`,startSync:!0,sync:{sync:e=>(e.markReady(),()=>{})}}),x=(e,t)=>{l.set(e,t)};let u=!1;const g=(e,t={})=>{const r=t.maxItems??1e3,a=t.mutationFnName??d;return{enqueue(o){if(e.getPendingCount()>=r){const s=new Error("offline outbox is full");return s.code="OFFLINE_QUEUE_OVERFLOW",Promise.reject(s)}const n={args:o.args,clientId:o.clientId,functionPath:o.functionPath,idempotencyKey:o.idempotencyKey,identity:o.identity,mutationId:o.mutationId,shardKey:o.shardKey},i=l.get(e);!i&&!u&&(u=!0,console.warn("[@lunora/db] createExecutorOutboxSink: no outbox carrier is registered for this executor. On a TanStack OfflineExecutor a zero-mutation transaction is silently dropped, so offline writes may be lost — wire the sink to the executor returned by defineCollections()."));const c=e.createOfflineTransaction({autoCommit:!1,idempotencyKey:o.idempotencyKey,metadata:n,mutationFnName:a});return c.mutate(()=>{i?.insert({_id:o.idempotencyKey})}),c.commit?.().catch(()=>{}),Promise.resolve()}}},h=(e,t)=>new Map(e.map(r=>[t(r),r])),E=(e,t)=>r=>{t.begin();const a=new Map;for(const[o,n]of r){const i=JSON.stringify(n);a.set(o,i),e.has(o)?e.get(o)!==i&&t.write({type:"update",value:n}):t.write({type:"insert",value:n})}for(const o of e.keys())r.has(o)||t.write({key:o,type:"delete"});t.commit(),e.clear();for(const[o,n]of a)e.set(o,n)},_=async e=>{try{await e()}catch(t){if(typeof t.code=="string"){const r=new y(t instanceof Error?t.message:String(t));throw r.code=t.code,r}throw t}},I=()=>{const e=new Set;return{dispose:()=>{for(const t of e)clearInterval(t);e.clear()},isOnline:()=>!0,notifyOnline:()=>{},subscribe:t=>{const r=setInterval(t,p);return e.add(r),()=>{clearInterval(r),e.delete(r)}}}};export{d as OUTBOX_MUTATION_FN_NAME,g as createExecutorOutboxSink,I as createOptimisticOnlineDetector,w as createOutboxCarrier,E as makeDiffEmit,x as registerOutboxCarrier,_ as runOutboxMutation,h as toMap};
@@ -59,7 +59,7 @@ interface CollectionDef<TList extends FunctionReference, TInput = never> {
59
59
  type AnyDef = CollectionDef<any, any>;
60
60
  /**
61
61
  * The public row type a collection exposes — the element type of its `list`
62
- * query's return, with no `& Row`: a `Collection&lt;T>` is invariant in `T`, so the
62
+ * query's return, with no `& Row`: a `Collection<T>` is invariant in `T`, so the
63
63
  * exposed type must be exactly the document type, not a subtype.
64
64
  */
65
65
  type RowOf<C extends AnyDef> = C["list"] extends FunctionReference<infer _K, infer _A, infer R> ? Element<R> : never;
@@ -161,6 +161,11 @@ interface LunoraDb<D extends Record<string, AnyDef>> {
161
161
  *
162
162
  * This is the hand-written form; `@lunora/codegen` can emit a fully-typed call to
163
163
  * it from `schema.ts`, so an app writes nothing.
164
+ *
165
+ * Keep a single instance and treat the returned collections as the one source of
166
+ * truth per table — do not mirror rows into a parallel store, or derived indexes
167
+ * built from the copy can silently read stale data (see the `@lunora/db` docs,
168
+ * "One source of truth per table").
164
169
  */
165
170
  declare const defineCollections: <D extends Record<string, AnyDef>>(client: LunoraClient, defs: D, options?: DefineCollectionsOptions) => LunoraDb<D>;
166
171
  export { CollectionDef as C, DefineCollectionsOptions as D, InsertBinding as I, LunoraDb as L, WriteRejectedEvent as W, defineCollections as d };
@@ -59,7 +59,7 @@ interface CollectionDef<TList extends FunctionReference, TInput = never> {
59
59
  type AnyDef = CollectionDef<any, any>;
60
60
  /**
61
61
  * The public row type a collection exposes — the element type of its `list`
62
- * query's return, with no `& Row`: a `Collection&lt;T>` is invariant in `T`, so the
62
+ * query's return, with no `& Row`: a `Collection<T>` is invariant in `T`, so the
63
63
  * exposed type must be exactly the document type, not a subtype.
64
64
  */
65
65
  type RowOf<C extends AnyDef> = C["list"] extends FunctionReference<infer _K, infer _A, infer R> ? Element<R> : never;
@@ -161,6 +161,11 @@ interface LunoraDb<D extends Record<string, AnyDef>> {
161
161
  *
162
162
  * This is the hand-written form; `@lunora/codegen` can emit a fully-typed call to
163
163
  * it from `schema.ts`, so an app writes nothing.
164
+ *
165
+ * Keep a single instance and treat the returned collections as the one source of
166
+ * truth per table — do not mirror rows into a parallel store, or derived indexes
167
+ * built from the copy can silently read stale data (see the `@lunora/db` docs,
168
+ * "One source of truth per table").
164
169
  */
165
170
  declare const defineCollections: <D extends Record<string, AnyDef>>(client: LunoraClient, defs: D, options?: DefineCollectionsOptions) => LunoraDb<D>;
166
171
  export { CollectionDef as C, DefineCollectionsOptions as D, InsertBinding as I, LunoraDb as L, WriteRejectedEvent as W, defineCollections as d };
@@ -23,11 +23,11 @@ declare const DIRECT_TRANSACTION_METADATA_KEY = "__tanstack_db_direct";
23
23
  * A map of wired collections, keyed by the name the optimistic bodies address them
24
24
  * by.
25
25
  *
26
- * The row type is `any` on purpose. `Collection&lt;T, string>` is **invariant** in
26
+ * The row type is `any` on purpose. `Collection<T, string>` is **invariant** in
27
27
  * `T` (its methods both consume and produce rows), so a concrete
28
- * `Collection&lt;Doc&lt;"nodes"> & Row>` is NOT assignable to `Collection&lt;Row>` — which
29
- * is why the previous `Record&lt;string, Collection&lt;Row, string>>` forced an
30
- * `as never` cast on every entry, and left `context.collections.&lt;name>` too
28
+ * `Collection<Doc<"nodes"> & Row>` is NOT assignable to `Collection<Row>` — which
29
+ * is why the previous `Record<string, Collection<Row, string>>` forced an
30
+ * `as never` cast on every entry, and left `context.collections.<name>` too
31
31
  * untyped to be worth using. Projects recover the concrete types by binding them
32
32
  * once through {@link initMutators}.
33
33
  */
@@ -89,7 +89,7 @@ interface ClientMutatorDef<TArgs, TCollections extends CollectionMap = Collectio
89
89
  *
90
90
  * `context.collections` is typed by whatever map it is bound to — which for this
91
91
  * standalone form is the widest one. Bind the concrete collections once with
92
- * {@link initMutators} to get `collections.&lt;name>` typed inside `apply`.
92
+ * {@link initMutators} to get `collections.<name>` typed inside `apply`.
93
93
  */
94
94
  declare const defineMutator: {
95
95
  <TArgs = Record<string, unknown>>(definition: {
@@ -218,17 +218,17 @@ interface BoundMutatorApi<TCollections extends CollectionMap> {
218
218
  * Bind the mutator surface to **this project's** collections map, once.
219
219
  *
220
220
  * `Collection` is invariant in its row type, so a shared
221
- * `Record&lt;string, Collection&lt;Row, string>>` could neither accept a generated
221
+ * `Record<string, Collection<Row, string>>` could neither accept a generated
222
222
  * collection without an `as never` cast nor hand a usable type back to `apply` —
223
223
  * which is why optimistic bodies tended to ignore `context.collections` and close
224
224
  * over module-scope collection variables instead. Declaring the map once here
225
225
  * fixes both ends: `bindMutators` takes the concrete collections cast-free, and
226
- * `apply` reads `collections.&lt;name>` at its real row type.
226
+ * `apply` reads `collections.<name>` at its real row type.
227
227
  *
228
228
  * Runtime-identical to the standalone {@link defineMutator} / {@link bindMutators}
229
229
  * (this returns those very functions); only the types narrow.
230
230
  * @example
231
- * const { bindMutators, defineMutator } = initMutators&lt;{ nodes: typeof wholeOutlineCollection }>();
231
+ * const { bindMutators, defineMutator } = initMutators<{ nodes: typeof wholeOutlineCollection }>();
232
232
  * const setText = defineMutator({ apply: ({ collections }, args) => collections.nodes.update(args.id, setter), serverRef: api.mutators.setText });
233
233
  */
234
234
  declare const initMutators: <TCollections extends CollectionMap>() => BoundMutatorApi<TCollections>;
@@ -23,11 +23,11 @@ declare const DIRECT_TRANSACTION_METADATA_KEY = "__tanstack_db_direct";
23
23
  * A map of wired collections, keyed by the name the optimistic bodies address them
24
24
  * by.
25
25
  *
26
- * The row type is `any` on purpose. `Collection&lt;T, string>` is **invariant** in
26
+ * The row type is `any` on purpose. `Collection<T, string>` is **invariant** in
27
27
  * `T` (its methods both consume and produce rows), so a concrete
28
- * `Collection&lt;Doc&lt;"nodes"> & Row>` is NOT assignable to `Collection&lt;Row>` — which
29
- * is why the previous `Record&lt;string, Collection&lt;Row, string>>` forced an
30
- * `as never` cast on every entry, and left `context.collections.&lt;name>` too
28
+ * `Collection<Doc<"nodes"> & Row>` is NOT assignable to `Collection<Row>` — which
29
+ * is why the previous `Record<string, Collection<Row, string>>` forced an
30
+ * `as never` cast on every entry, and left `context.collections.<name>` too
31
31
  * untyped to be worth using. Projects recover the concrete types by binding them
32
32
  * once through {@link initMutators}.
33
33
  */
@@ -89,7 +89,7 @@ interface ClientMutatorDef<TArgs, TCollections extends CollectionMap = Collectio
89
89
  *
90
90
  * `context.collections` is typed by whatever map it is bound to — which for this
91
91
  * standalone form is the widest one. Bind the concrete collections once with
92
- * {@link initMutators} to get `collections.&lt;name>` typed inside `apply`.
92
+ * {@link initMutators} to get `collections.<name>` typed inside `apply`.
93
93
  */
94
94
  declare const defineMutator: {
95
95
  <TArgs = Record<string, unknown>>(definition: {
@@ -218,17 +218,17 @@ interface BoundMutatorApi<TCollections extends CollectionMap> {
218
218
  * Bind the mutator surface to **this project's** collections map, once.
219
219
  *
220
220
  * `Collection` is invariant in its row type, so a shared
221
- * `Record&lt;string, Collection&lt;Row, string>>` could neither accept a generated
221
+ * `Record<string, Collection<Row, string>>` could neither accept a generated
222
222
  * collection without an `as never` cast nor hand a usable type back to `apply` —
223
223
  * which is why optimistic bodies tended to ignore `context.collections` and close
224
224
  * over module-scope collection variables instead. Declaring the map once here
225
225
  * fixes both ends: `bindMutators` takes the concrete collections cast-free, and
226
- * `apply` reads `collections.&lt;name>` at its real row type.
226
+ * `apply` reads `collections.<name>` at its real row type.
227
227
  *
228
228
  * Runtime-identical to the standalone {@link defineMutator} / {@link bindMutators}
229
229
  * (this returns those very functions); only the types narrow.
230
230
  * @example
231
- * const { bindMutators, defineMutator } = initMutators&lt;{ nodes: typeof wholeOutlineCollection }>();
231
+ * const { bindMutators, defineMutator } = initMutators<{ nodes: typeof wholeOutlineCollection }>();
232
232
  * const setText = defineMutator({ apply: ({ collections }, args) => collections.nodes.update(args.id, setter), serverRef: api.mutators.setText });
233
233
  */
234
234
  declare const initMutators: <TCollections extends CollectionMap>() => BoundMutatorApi<TCollections>;
@@ -0,0 +1 @@
1
+ import{createCollection as M,safeRandomUUID as v}from"@tanstack/db";import{startOfflineExecutor as E,NonRetriableError as O}from"@tanstack/offline-transactions";import{lunoraCollectionOptions as R}from"./CHECKPOINT_FALLBACK_MS-B0XZscWq.mjs";import{createOutboxCarrier as U,createOptimisticOnlineDetector as _,OUTBOX_MUTATION_FN_NAME as C,registerOutboxCarrier as A,runOutboxMutation as x}from"./OUTBOX_MUTATION_FN_NAME-BznV-kE1.mjs";const N=new WeakMap,I=(n,c)=>{let o=N.get(n);o===void 0&&(o=new Map,N.set(n,o));const i=o.get(c)??0;o.set(c,i+1),i===1&&console.warn(`[@lunora/db] table "${c}" is bound by more than one defineCollections call on this client. Each call creates its own live collection and outbox for the table, so the two can drift and derived indexes built from one can silently read stale rows. Bind every table in a single defineCollections call (see the "One source of truth per table" docs section).`)},D=(n,c,o={})=>{const i={},y={},f={},h=Object.entries(c);for(const[t,e]of h){const r=e.insert;I(n,t);const{config:l,scope:m}=R({client:n,getKey:e.getKey,id:t,list:e.list,...e.load===void 0?{}:{load:e.load},onError:e.onError,scopeBy:e.scopeBy,shardKey:e.shardKey});i[t]=M(l),e.scopeBy!==void 0&&(y[t]=m),r&&(f[t]=async({idempotencyKey:s,transaction:a})=>{for(const[p,K]of a.mutations.entries()){const b=K.modified,F=`${s}:${String(p)}`;try{await x(()=>n.mutation(r.mutation,r.toArgs(b),{mutationId:F}))}catch(u){if(u instanceof O&&o.onWriteRejected)try{o.onWriteRejected({code:u.code,collection:t,error:u,row:b})}catch{}throw u}}})}f[C]=async({transaction:t})=>{const e=t.metadata;if(e){if(e.identity!==n.currentIdentity())throw new O("outbox write dropped: identity changed since it was queued");await x(()=>n.mutation({__lunoraRef:e.functionPath},e.args,{mutationId:e.idempotencyKey,shardKey:e.shardKey}))}};const g=U(),d=E({collections:{...i,[C]:g},mutationFns:f,onlineDetector:_(),...o.onLeadershipChange?{onLeadershipChange:o.onLeadershipChange}:{},...o.onStorageFailure?{onStorageFailure:o.onStorageFailure}:{},onUnknownMutationFn:(t,e)=>{try{o.onWriteRejected?.({code:"UNKNOWN_MUTATION_FN",collection:t,error:new Error(`offline write dropped: mutation "${t}" no longer exists (removed or renamed in a deploy?)`),row:e.mutations[0]?.modified})}catch{}}});A(d,g);const w={};for(const[t,e]of h){const r=e.insert,l=i[t];if(!r||!l)continue;const m=d.createOfflineAction({mutationFnName:t,onMutate:({id:s,input:a})=>{l.insert(r.optimistic(a,s))}});w[t]=s=>{const a=v(),p=m({id:a,input:s});return{id:a,transaction:p}}}return{actions:w,collections:i,executor:d,pendingCount:()=>d.getPendingCount(),scope:y}};export{D as defineCollections};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/db",
3
- "version": "1.0.0-alpha.40",
3
+ "version": "1.0.0-alpha.42",
4
4
  "description": "TanStack DB binding: typed, live-synced collections and a durable offline outbox over the Lunora client",
5
5
  "keywords": [
6
6
  "cloudflare",
@@ -54,8 +54,8 @@
54
54
  "access": "public"
55
55
  },
56
56
  "dependencies": {
57
- "@lunora/client": "1.0.0-alpha.39",
58
- "@lunora/errors": "1.0.0-alpha.13"
57
+ "@lunora/client": "1.0.0-alpha.40",
58
+ "@lunora/errors": "1.0.0-alpha.14"
59
59
  },
60
60
  "peerDependencies": {
61
61
  "@tanstack/db": "^0.6.0",
@@ -1 +0,0 @@
1
- import{createCollection as f,safeRandomUUID as m}from"@tanstack/db";import{NonRetriableError as y}from"@tanstack/offline-transactions";const p=1e3,d="__lunora_outbox__",l=new WeakMap,w=()=>f({getKey:e=>e._id,id:`${d}:${m()}`,startSync:!0,sync:{sync:e=>(e.markReady(),()=>{})}}),x=(e,t)=>{l.set(e,t)};let u=!1;const g=(e,t={})=>{const r=t.maxItems??1e3,n=t.mutationFnName??d;return{enqueue(o){if(e.getPendingCount()>=r){const c=new Error("offline outbox is full");return c.code="OFFLINE_QUEUE_OVERFLOW",Promise.reject(c)}const i={args:o.args,clientId:o.clientId,functionPath:o.functionPath,idempotencyKey:o.idempotencyKey,identity:o.identity,mutationId:o.mutationId,shardKey:o.shardKey},a=l.get(e);!a&&!u&&(u=!0,console.warn("[@lunora/db] createExecutorOutboxSink: no outbox carrier is registered for this executor. On a TanStack OfflineExecutor a zero-mutation transaction is silently dropped, so offline writes may be lost — wire the sink to the executor returned by defineCollections()."));const s=e.createOfflineTransaction({autoCommit:!1,idempotencyKey:o.idempotencyKey,metadata:i,mutationFnName:n});return s.mutate(()=>{a?.insert({_id:o.idempotencyKey})}),s.commit?.().catch(()=>{}),Promise.resolve()}}},h=(e,t)=>{const r=new Map;for(const n of e)r.set(t(n),n);return r},E=(e,t)=>r=>{t.begin();const n=new Map;for(const[o,i]of r){const a=JSON.stringify(i);n.set(o,a),e.has(o)?e.get(o)!==a&&t.write({type:"update",value:i}):t.write({type:"insert",value:i})}for(const o of e.keys())r.has(o)||t.write({key:o,type:"delete"});t.commit(),e.clear();for(const[o,i]of n)e.set(o,i)},_=async e=>{try{await e()}catch(t){if(typeof t.code=="string"){const r=new y(t instanceof Error?t.message:String(t));throw r.code=t.code,r}throw t}},I=()=>{const e=new Set;return{dispose:()=>{for(const t of e)clearInterval(t);e.clear()},isOnline:()=>!0,notifyOnline:()=>{},subscribe:t=>{const r=setInterval(t,p);return e.add(r),()=>{clearInterval(r),e.delete(r)}}}};export{d as OUTBOX_MUTATION_FN_NAME,g as createExecutorOutboxSink,I as createOptimisticOnlineDetector,w as createOutboxCarrier,E as makeDiffEmit,x as registerOutboxCarrier,_ as runOutboxMutation,h as toMap};
@@ -1 +0,0 @@
1
- import{createCollection as I,safeRandomUUID as R}from"@tanstack/db";import{startOfflineExecutor as U,NonRetriableError as w}from"@tanstack/offline-transactions";import{lunoraCollectionOptions as _}from"./CHECKPOINT_FALLBACK_MS-6GmTGWsH.mjs";import{createOutboxCarrier as b,createOptimisticOnlineDetector as E,OUTBOX_MUTATION_FN_NAME as C,registerOutboxCarrier as M,runOutboxMutation as N}from"./OUTBOX_MUTATION_FN_NAME-CebgkYw2.mjs";const S=(a,K,e={})=>{const c={},p={},l={},y=Object.entries(K);for(const[t,o]of y){const n=o.insert,{config:d,scope:m}=_({client:a,getKey:o.getKey,id:t,list:o.list,...o.load===void 0?{}:{load:o.load},onError:o.onError,scopeBy:o.scopeBy,shardKey:o.shardKey});c[t]=I(d),o.scopeBy!==void 0&&(p[t]=m),n&&(l[t]=async({idempotencyKey:r,transaction:i})=>{for(const[f,x]of i.mutations.entries()){const O=x.modified,F=`${r}:${String(f)}`;try{await N(()=>a.mutation(n.mutation,n.toArgs(O),{mutationId:F}))}catch(u){if(u instanceof w&&e.onWriteRejected)try{e.onWriteRejected({code:u.code,collection:t,error:u,row:O})}catch{}throw u}}})}l[C]=async({transaction:t})=>{const o=t.metadata;if(o){if(o.identity!==a.currentIdentity())throw new w("outbox write dropped: identity changed since it was queued");await N(()=>a.mutation({__lunoraRef:o.functionPath},o.args,{mutationId:o.idempotencyKey,shardKey:o.shardKey}))}};const g=b(),s=U({collections:{...c,[C]:g},mutationFns:l,onlineDetector:E(),...e.onLeadershipChange?{onLeadershipChange:e.onLeadershipChange}:{},...e.onStorageFailure?{onStorageFailure:e.onStorageFailure}:{},onUnknownMutationFn:(t,o)=>{try{e.onWriteRejected?.({code:"UNKNOWN_MUTATION_FN",collection:t,error:new Error(`offline write dropped: mutation "${t}" no longer exists (removed or renamed in a deploy?)`),row:o.mutations[0]?.modified})}catch{}}});M(s,g);const h={};for(const[t,o]of y){const n=o.insert,d=c[t];if(!n||!d)continue;const m=s.createOfflineAction({mutationFnName:t,onMutate:({id:r,input:i})=>{d.insert(n.optimistic(i,r))}});h[t]=r=>{const i=R(),f=m({id:i,input:r});return{id:i,transaction:f}}}return{actions:h,collections:c,executor:s,pendingCount:()=>s.getPendingCount(),scope:p}};export{S as defineCollections};