@lunora/db 1.0.0-alpha.5 → 1.0.0-alpha.50
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/LICENSE.md +6 -0
- package/README.md +6 -0
- package/dist/collections/index.d.mts +2 -2
- package/dist/collections/index.d.ts +2 -2
- package/dist/collections/index.mjs +1 -2
- package/dist/index.d.mts +79 -5
- package/dist/index.d.ts +79 -5
- package/dist/index.mjs +1 -8
- package/dist/mutators/index.d.mts +2 -2
- package/dist/mutators/index.d.ts +2 -2
- package/dist/mutators/index.mjs +1 -1
- package/dist/packem_shared/CHECKPOINT_FALLBACK_MS-Dxy7C_Up.mjs +1 -0
- package/dist/packem_shared/DIRECT_TRANSACTION_METADATA_KEY-BxbJYIRz.mjs +1 -0
- package/dist/packem_shared/OUTBOX_MUTATION_FN_NAME-BznV-kE1.mjs +1 -0
- package/dist/packem_shared/applyPlanToCollections-CPB4eTOM.mjs +1 -0
- package/dist/packem_shared/collection-options.d-CmsXU1wV.d.mts +347 -0
- package/dist/packem_shared/collection-options.d-CmsXU1wV.d.ts +347 -0
- package/dist/packem_shared/define-collections.d-CTOC6vMT.d.mts +171 -0
- package/dist/packem_shared/define-collections.d-u87f9B-o.d.ts +171 -0
- package/dist/packem_shared/define-mutators.d-C6MkAEpe.d.ts +235 -0
- package/dist/packem_shared/define-mutators.d-cBFz2vjk.d.mts +235 -0
- package/dist/packem_shared/defineCollections-qbfQ6xN1.mjs +1 -0
- package/package.json +3 -2
- package/dist/packem_shared/OUTBOX_MUTATION_FN_NAME-3cxtwP39.mjs +0 -98
- package/dist/packem_shared/bindMutators-DWGJhyt3.mjs +0 -66
- package/dist/packem_shared/collection-options.d-B3YaP49K.d.mts +0 -196
- package/dist/packem_shared/collection-options.d-B3YaP49K.d.ts +0 -196
- package/dist/packem_shared/createCheckpointRegistry-CR_q270X.mjs +0 -125
- package/dist/packem_shared/define-collections.d-DKc3vPUv.d.ts +0 -85
- package/dist/packem_shared/define-collections.d-L5DVcLnj.d.mts +0 -85
- package/dist/packem_shared/define-mutators.d-Bqd-o1Zp.d.mts +0 -80
- package/dist/packem_shared/define-mutators.d-BqsA6_pd.d.ts +0 -80
- package/dist/packem_shared/defineCollections-it3wN-49.mjs +0 -74
package/LICENSE.md
CHANGED
|
@@ -103,3 +103,9 @@ Unless required by applicable law or agreed to in writing, software distributed
|
|
|
103
103
|
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
104
104
|
CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
105
105
|
specific language governing permissions and limitations under the License.
|
|
106
|
+
|
|
107
|
+
<!-- DEPENDENCIES -->
|
|
108
|
+
<!-- /DEPENDENCIES -->
|
|
109
|
+
|
|
110
|
+
<!-- TYPE_DEPENDENCIES -->
|
|
111
|
+
<!-- /TYPE_DEPENDENCIES -->
|
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
|
-
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-
|
|
2
|
-
export { type C as CollectionDef, type I as InsertBinding, type L as LunoraDb, d as defineCollections } from "../packem_shared/define-collections.d-
|
|
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-CmsXU1wV.mjs";
|
|
2
|
+
export { type C as CollectionDef, type I as InsertBinding, type L as LunoraDb, d as defineCollections } from "../packem_shared/define-collections.d-CTOC6vMT.mjs";
|
|
3
3
|
import '@lunora/client';
|
|
4
4
|
import '@tanstack/db';
|
|
5
5
|
import '@tanstack/offline-transactions';
|
|
@@ -1,5 +1,5 @@
|
|
|
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-
|
|
2
|
-
export { type C as CollectionDef, type I as InsertBinding, type L as LunoraDb, d as defineCollections } from "../packem_shared/define-collections.d-
|
|
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-CmsXU1wV.js";
|
|
2
|
+
export { type C as CollectionDef, type I as InsertBinding, type L as LunoraDb, d as defineCollections } from "../packem_shared/define-collections.d-u87f9B-o.js";
|
|
3
3
|
import '@lunora/client';
|
|
4
4
|
import '@tanstack/db';
|
|
5
5
|
import '@tanstack/offline-transactions';
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export { defineCollections } from '../packem_shared/defineCollections-it3wN-49.mjs';
|
|
1
|
+
import{createCheckpointRegistry as t,lunoraCollectionOptions as r}from"../packem_shared/CHECKPOINT_FALLBACK_MS-Dxy7C_Up.mjs";import{defineCollections as n}from"../packem_shared/defineCollections-qbfQ6xN1.mjs";export{t as createCheckpointRegistry,n as defineCollections,r as lunoraCollectionOptions};
|
package/dist/index.d.mts
CHANGED
|
@@ -1,8 +1,82 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export { type
|
|
1
|
+
import { Collection } from '@tanstack/db';
|
|
2
|
+
import { R as Row } from "./packem_shared/collection-options.d-CmsXU1wV.mjs";
|
|
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-CmsXU1wV.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-CTOC6vMT.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-cBFz2vjk.mjs";
|
|
4
6
|
import '@lunora/client';
|
|
5
|
-
import '@tanstack/db';
|
|
6
7
|
import '@tanstack/offline-transactions';
|
|
8
|
+
/** One row to insert. `_id` may be pre-minted client-side so the optimistic row keys match the persisted one. */
|
|
9
|
+
interface PlanInsert {
|
|
10
|
+
/** Row body. Include `_id` to key the row yourself (the server honors it as the `clientId`). */
|
|
11
|
+
row: Record<string, unknown> & {
|
|
12
|
+
_id?: string;
|
|
13
|
+
};
|
|
14
|
+
table: string;
|
|
15
|
+
}
|
|
16
|
+
/** One row to patch, by id. */
|
|
17
|
+
interface PlanPatch {
|
|
18
|
+
fields: Record<string, unknown>;
|
|
19
|
+
id: string;
|
|
20
|
+
table: string;
|
|
21
|
+
}
|
|
22
|
+
/** One row to delete, by id. */
|
|
23
|
+
interface PlanDelete {
|
|
24
|
+
id: string;
|
|
25
|
+
table: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* A change plan: what a mutator intends to write.
|
|
29
|
+
*
|
|
30
|
+
* Applied in a fixed order — **deletes, then patches, then inserts** — by both
|
|
31
|
+
* appliers. The order is part of the contract, not an implementation detail: a plan
|
|
32
|
+
* that deletes a row and inserts its replacement under the same natural key only
|
|
33
|
+
* behaves the same on both sides if both sides agree which happens first.
|
|
34
|
+
*/
|
|
35
|
+
interface ChangePlan {
|
|
36
|
+
deletes?: ReadonlyArray<PlanDelete>;
|
|
37
|
+
inserts?: ReadonlyArray<PlanInsert>;
|
|
38
|
+
patches?: ReadonlyArray<PlanPatch>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The `ctx.db` methods {@link applyPlanToDb} needs — structural, so any writer
|
|
42
|
+
* satisfies it.
|
|
43
|
+
*
|
|
44
|
+
* The `never` parameter positions are deliberate, not laziness. `ctx.db.delete` is
|
|
45
|
+
* `<T extends string>(id: Id<T>) => …` over the **branded** `Id<T>`, and under
|
|
46
|
+
* `strictFunctionTypes` a parameter is contravariant — so declaring `id: string` here
|
|
47
|
+
* would make the real `ctx.db` un-assignable to `PlanWriter` (`string` is not
|
|
48
|
+
* assignable to `string & { __table }`), and every caller would need a cast at the
|
|
49
|
+
* call site instead. `never` accepts any branded id, which keeps `applyPlanToDb(ctx.db,
|
|
50
|
+
* plan)` cast-free for the caller and confines the two `as never` casts to this module.
|
|
51
|
+
*
|
|
52
|
+
* The trade-off is real: argument checking inside `applyPlanToDb` is erased, so a plan
|
|
53
|
+
* naming a table the schema doesn't have is a runtime error. Use `ctx.db.asId(table,
|
|
54
|
+
* id)` when building the plan to catch a malformed id at the boundary.
|
|
55
|
+
*/
|
|
56
|
+
interface PlanWriter {
|
|
57
|
+
delete: (id: never) => Promise<void>;
|
|
58
|
+
insert: (tableName: never, document: Record<string, unknown>, options?: {
|
|
59
|
+
clientId?: string;
|
|
60
|
+
}) => Promise<unknown>;
|
|
61
|
+
patch: (id: never, patch: Record<string, unknown>) => Promise<void>;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Apply `plan` to a map of TanStack collections — the client (optimistic) half.
|
|
65
|
+
*
|
|
66
|
+
* A plan naming a table with no wired collection is **skipped, not an error**: an app
|
|
67
|
+
* legitimately syncs a subset of the tables its mutators write (a server-only audit
|
|
68
|
+
* row has no client collection), and throwing would make the optimistic body fail on
|
|
69
|
+
* a write the server handles fine.
|
|
70
|
+
*/
|
|
71
|
+
declare const applyPlanToCollections: (collections: Record<string, Collection<Row, string>>, plan: ChangePlan) => void;
|
|
72
|
+
/**
|
|
73
|
+
* Apply `plan` to a `ctx.db` writer — the server (authoritative) half.
|
|
74
|
+
*
|
|
75
|
+
* Sequential by design: the shard's SQLite is single-threaded and a mutation runs
|
|
76
|
+
* inside one BEGIN/COMMIT span, so ordering is observable and a mid-plan failure
|
|
77
|
+
* rolls the whole plan back. An insert carrying an `_id` forwards it as `clientId`,
|
|
78
|
+
* which is how a client-minted key becomes the persisted primary key.
|
|
79
|
+
*/
|
|
80
|
+
declare const applyPlanToDb: (db: PlanWriter, plan: ChangePlan) => Promise<void>;
|
|
7
81
|
declare const VERSION = "0.0.0";
|
|
8
|
-
export { VERSION };
|
|
82
|
+
export { type ChangePlan, type PlanDelete, type PlanInsert, type PlanPatch, type PlanWriter, type Row, VERSION, applyPlanToCollections, applyPlanToDb };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,82 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export { type
|
|
1
|
+
import { Collection } from '@tanstack/db';
|
|
2
|
+
import { R as Row } from "./packem_shared/collection-options.d-CmsXU1wV.js";
|
|
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-CmsXU1wV.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-u87f9B-o.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-C6MkAEpe.js";
|
|
4
6
|
import '@lunora/client';
|
|
5
|
-
import '@tanstack/db';
|
|
6
7
|
import '@tanstack/offline-transactions';
|
|
8
|
+
/** One row to insert. `_id` may be pre-minted client-side so the optimistic row keys match the persisted one. */
|
|
9
|
+
interface PlanInsert {
|
|
10
|
+
/** Row body. Include `_id` to key the row yourself (the server honors it as the `clientId`). */
|
|
11
|
+
row: Record<string, unknown> & {
|
|
12
|
+
_id?: string;
|
|
13
|
+
};
|
|
14
|
+
table: string;
|
|
15
|
+
}
|
|
16
|
+
/** One row to patch, by id. */
|
|
17
|
+
interface PlanPatch {
|
|
18
|
+
fields: Record<string, unknown>;
|
|
19
|
+
id: string;
|
|
20
|
+
table: string;
|
|
21
|
+
}
|
|
22
|
+
/** One row to delete, by id. */
|
|
23
|
+
interface PlanDelete {
|
|
24
|
+
id: string;
|
|
25
|
+
table: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* A change plan: what a mutator intends to write.
|
|
29
|
+
*
|
|
30
|
+
* Applied in a fixed order — **deletes, then patches, then inserts** — by both
|
|
31
|
+
* appliers. The order is part of the contract, not an implementation detail: a plan
|
|
32
|
+
* that deletes a row and inserts its replacement under the same natural key only
|
|
33
|
+
* behaves the same on both sides if both sides agree which happens first.
|
|
34
|
+
*/
|
|
35
|
+
interface ChangePlan {
|
|
36
|
+
deletes?: ReadonlyArray<PlanDelete>;
|
|
37
|
+
inserts?: ReadonlyArray<PlanInsert>;
|
|
38
|
+
patches?: ReadonlyArray<PlanPatch>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The `ctx.db` methods {@link applyPlanToDb} needs — structural, so any writer
|
|
42
|
+
* satisfies it.
|
|
43
|
+
*
|
|
44
|
+
* The `never` parameter positions are deliberate, not laziness. `ctx.db.delete` is
|
|
45
|
+
* `<T extends string>(id: Id<T>) => …` over the **branded** `Id<T>`, and under
|
|
46
|
+
* `strictFunctionTypes` a parameter is contravariant — so declaring `id: string` here
|
|
47
|
+
* would make the real `ctx.db` un-assignable to `PlanWriter` (`string` is not
|
|
48
|
+
* assignable to `string & { __table }`), and every caller would need a cast at the
|
|
49
|
+
* call site instead. `never` accepts any branded id, which keeps `applyPlanToDb(ctx.db,
|
|
50
|
+
* plan)` cast-free for the caller and confines the two `as never` casts to this module.
|
|
51
|
+
*
|
|
52
|
+
* The trade-off is real: argument checking inside `applyPlanToDb` is erased, so a plan
|
|
53
|
+
* naming a table the schema doesn't have is a runtime error. Use `ctx.db.asId(table,
|
|
54
|
+
* id)` when building the plan to catch a malformed id at the boundary.
|
|
55
|
+
*/
|
|
56
|
+
interface PlanWriter {
|
|
57
|
+
delete: (id: never) => Promise<void>;
|
|
58
|
+
insert: (tableName: never, document: Record<string, unknown>, options?: {
|
|
59
|
+
clientId?: string;
|
|
60
|
+
}) => Promise<unknown>;
|
|
61
|
+
patch: (id: never, patch: Record<string, unknown>) => Promise<void>;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Apply `plan` to a map of TanStack collections — the client (optimistic) half.
|
|
65
|
+
*
|
|
66
|
+
* A plan naming a table with no wired collection is **skipped, not an error**: an app
|
|
67
|
+
* legitimately syncs a subset of the tables its mutators write (a server-only audit
|
|
68
|
+
* row has no client collection), and throwing would make the optimistic body fail on
|
|
69
|
+
* a write the server handles fine.
|
|
70
|
+
*/
|
|
71
|
+
declare const applyPlanToCollections: (collections: Record<string, Collection<Row, string>>, plan: ChangePlan) => void;
|
|
72
|
+
/**
|
|
73
|
+
* Apply `plan` to a `ctx.db` writer — the server (authoritative) half.
|
|
74
|
+
*
|
|
75
|
+
* Sequential by design: the shard's SQLite is single-threaded and a mutation runs
|
|
76
|
+
* inside one BEGIN/COMMIT span, so ordering is observable and a mid-plan failure
|
|
77
|
+
* rolls the whole plan back. An insert carrying an `_id` forwards it as `clientId`,
|
|
78
|
+
* which is how a client-minted key becomes the persisted primary key.
|
|
79
|
+
*/
|
|
80
|
+
declare const applyPlanToDb: (db: PlanWriter, plan: ChangePlan) => Promise<void>;
|
|
7
81
|
declare const VERSION = "0.0.0";
|
|
8
|
-
export { VERSION };
|
|
82
|
+
export { type ChangePlan, type PlanDelete, type PlanInsert, type PlanPatch, type PlanWriter, type Row, VERSION, applyPlanToCollections, applyPlanToDb };
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export { defineCollections } from './packem_shared/defineCollections-it3wN-49.mjs';
|
|
3
|
-
export { bindMutators, defineMutator } from './packem_shared/bindMutators-DWGJhyt3.mjs';
|
|
4
|
-
export { OUTBOX_MUTATION_FN_NAME, createExecutorOutboxSink, createOptimisticOnlineDetector, makeDiffEmit, runOutboxMutation, toMap } from './packem_shared/OUTBOX_MUTATION_FN_NAME-3cxtwP39.mjs';
|
|
5
|
-
|
|
6
|
-
const VERSION = "0.0.0";
|
|
7
|
-
|
|
8
|
-
export { VERSION };
|
|
1
|
+
import{applyPlanToCollections as r,applyPlanToDb as i}from"./packem_shared/applyPlanToCollections-CPB4eTOM.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-Dxy7C_Up.mjs";import{defineCollections as T}from"./packem_shared/defineCollections-qbfQ6xN1.mjs";import{DIRECT_TRANSACTION_METADATA_KEY as u,bindMutators as x,defineMutator as A,initMutators as M}from"./packem_shared/DIRECT_TRANSACTION_METADATA_KEY-BxbJYIRz.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,5 +1,5 @@
|
|
|
1
|
-
export { type B as BindMutatorsContext, type a as BoundMutators, type C as ClientMutatorContext, type
|
|
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-cBFz2vjk.mjs";
|
|
2
2
|
import '@lunora/client';
|
|
3
3
|
import '@tanstack/db';
|
|
4
|
-
import "../packem_shared/collection-options.d-
|
|
4
|
+
import "../packem_shared/collection-options.d-CmsXU1wV.mjs";
|
|
5
5
|
import '@tanstack/offline-transactions';
|
package/dist/mutators/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { type B as BindMutatorsContext, type a as BoundMutators, type C as ClientMutatorContext, type
|
|
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-C6MkAEpe.js";
|
|
2
2
|
import '@lunora/client';
|
|
3
3
|
import '@tanstack/db';
|
|
4
|
-
import "../packem_shared/collection-options.d-
|
|
4
|
+
import "../packem_shared/collection-options.d-CmsXU1wV.js";
|
|
5
5
|
import '@tanstack/offline-transactions';
|
package/dist/mutators/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
import{bindMutators as r,defineMutator as i,initMutators as a}from"../packem_shared/DIRECT_TRANSACTION_METADATA_KEY-BxbJYIRz.mjs";export{r as bindMutators,i as defineMutator,a as initMutators};
|
|
@@ -0,0 +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-BznV-kE1.mjs";const I=()=>{let e=Number.NEGATIVE_INFINITY;const i=[];return{advance:o=>{if(!(o<=e)){e=o;for(let a=i.length-1;a>=0;a-=1){const n=i[a];n&&n.threshold<=e&&(n.resolve(),i.splice(a,1))}}},await:o=>o<=e?Promise.resolve():new Promise(a=>{i.push({resolve:a,threshold:o})}),passed:o=>o<=e,waiting:()=>i.length}};let g=!1;const M=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.)`))},m=new WeakMap,w=new WeakSet,N=3e3,S=(e={})=>{const i=e.fallbackMs??N,o=e.onFallback??M,a=I(),n=I();let d=0;const c=new Set,l=(t,s)=>{for(const r of c)r.kind===t&&r.threshold<=s&&(clearTimeout(r.handle),c.delete(r))},p=(t,s)=>{if(i<=0)return;const r=t==="checkpoint"?a:n;if(r.passed(s))return;for(const k of c)if(k.kind===t&&k.threshold>=s)return;const u={handle:setTimeout(()=>{if(c.delete(u),!r.passed(s)){d+=1,r.advance(s);try{o({kind:t,waitedMs:i,watermark:s})}catch{}}},i),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=>n.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&&(n.advance(s),l("mutationId",s))},stats:()=>({fallbacks:d,pendingCheckpointWaiters:a.waiting(),pendingMutationWaiters:n.waiting()})}},E=(e,i,o)=>{let a=m.get(e);a||(a=new Map,m.set(e,a));const n=i??"",d=a.get(n);if(d)return d;const c=S(o);return a.set(n,c),c},K=e=>{w.add(e)},x=e=>w.has(e),F=e=>{const i=m.get(e);if(i){for(const o of i.values())o.resolve({checkpoint:Number.POSITIVE_INFINITY,mutationId:Number.POSITIVE_INFINITY}),o.dispose();m.delete(e)}},O=e=>{const i=m.get(e),o={};if(i)for(const[a,n]of i)o[a]=n.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 i=e.getKey??(r=>r._id),o=e.checkpoints??E(e.client,e.shape?.shardKey??e.shardKey);K(o);const a=new Map;let n,d,c,l,p;const t=(r,u)=>{const k=h=>{n?.(C(h,i)),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:r,name:e.shape.name},k,{onCheckpoint:v,onError:f,shardKey:e.shape.shardKey}):e.client.subscribe(e.list,r,k,{onCheckpoint:v,onError:f,shardKey:e.shardKey})},s={autoIndex:"eager",defaultIndexType:b,getKey:i,id:e.id??e.list?.__lunoraRef??`shape:${e.shape?.name??""}`,...e.load==="eager"?{startSync:!0}:{},sync:{sync:r=>(n=T(a,r),c=u=>{r.markReady(),e.onError?.(u)},e.scopeBy===void 0?d=t(e.shape?.args??{},()=>{r.markReady()}):(r.markReady(),l!==void 0&&(d=t(l,void 0))),()=>{n=void 0,c=void 0,d?.(),d=void 0,a.clear()})}};return{checkpoints:o,config:s,scope:r=>{e.scopeBy!==void 0&&(l=r,d?.(),d=void 0,n?.(new Map),r!==void 0&&n!==void 0&&(d=t(r,void 0)))}}};export{N 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};
|
|
@@ -0,0 +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-Dxy7C_Up.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};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const n=(o,s)=>{for(const t of s.deletes??[])o[t.table]?.delete(t.id);for(const t of s.patches??[]){const e=o[t.table];e&&e.update(t.id,i=>{Object.assign(i,t.fields)})}for(const t of s.inserts??[]){const e=o[t.table];if(e){if(typeof t.row._id!="string")throw new TypeError(`applyPlanToCollections: insert into "${t.table}" needs an "_id" — mint it client-side so the optimistic row keys match the persisted one`);e.insert(t.row)}}},a=async(o,s)=>{for(const t of s.deletes??[])await o.delete(t.id);for(const t of s.patches??[])await o.patch(t.id,t.fields);for(const t of s.inserts??[]){const{_id:e,...i}=t.row;await o.insert(t.table,i,...typeof e=="string"?[{clientId:e}]:[])}};export{n as applyPlanToCollections,a as applyPlanToDb};
|