@lunora/db 1.0.0-alpha.20 → 1.0.0-alpha.21

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.
@@ -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-lJBOVJgq.mjs";
2
- export { type C as CollectionDef, type I as InsertBinding, type L as LunoraDb, d as defineCollections } from "../packem_shared/define-collections.d-Cc1p0x3t.mjs";
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-DgAuvqvn.mjs";
2
+ export { type C as CollectionDef, type I as InsertBinding, type L as LunoraDb, d as defineCollections } from "../packem_shared/define-collections.d-1z8QtQW8.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-lJBOVJgq.js";
2
- export { type C as CollectionDef, type I as InsertBinding, type L as LunoraDb, d as defineCollections } from "../packem_shared/define-collections.d-C01DaKJO.js";
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-DgAuvqvn.js";
2
+ export { type C as CollectionDef, type I as InsertBinding, type L as LunoraDb, d as defineCollections } from "../packem_shared/define-collections.d-DPgIHAtd.js";
3
3
  import '@lunora/client';
4
4
  import '@tanstack/db';
5
5
  import '@tanstack/offline-transactions';
@@ -1,2 +1,2 @@
1
- export { createCheckpointRegistry, lunoraCollectionOptions } from '../packem_shared/createCheckpointRegistry-DkfPWFWz.mjs';
2
- export { defineCollections } from '../packem_shared/defineCollections--aaoqJCd.mjs';
1
+ export { createCheckpointRegistry, lunoraCollectionOptions } from '../packem_shared/createCheckpointRegistry-Bf4JtkVH.mjs';
2
+ export { defineCollections } from '../packem_shared/defineCollections-yLxJvEsu.mjs';
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
- export { type C as CheckpointRegistry, type E as ExecutorOutboxSinkOptions, type L as LunoraCollectionConfig, type a as LunoraCollectionOptions, O as OUTBOX_MUTATION_FN_NAME, type b as OutboxExecutor, type d as OutboxMutationMetadata, type R as Row, type S as SyncWriter, c as createCheckpointRegistry, e as createExecutorOutboxSink, f as createOptimisticOnlineDetector, l as lunoraCollectionOptions, m as makeDiffEmit, r as runOutboxMutation, t as toMap } from "./packem_shared/collection-options.d-lJBOVJgq.mjs";
2
- 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-Cc1p0x3t.mjs";
3
- export { type B as BindMutatorsContext, type a as BoundMutators, type C as ClientMutatorContext, type b as ClientMutatorDef, c as bindMutators, d as defineMutator } from "./packem_shared/define-mutators.d-HWj94_nL.mjs";
1
+ export { type C as CheckpointRegistry, type E as ExecutorOutboxSinkOptions, type L as LunoraCollectionConfig, type a as LunoraCollectionOptions, O as OUTBOX_MUTATION_FN_NAME, type b as OutboxExecutor, type d as OutboxMutationMetadata, type R as Row, type S as SyncWriter, c as createCheckpointRegistry, e as createExecutorOutboxSink, f as createOptimisticOnlineDetector, l as lunoraCollectionOptions, m as makeDiffEmit, r as runOutboxMutation, t as toMap } from "./packem_shared/collection-options.d-DgAuvqvn.mjs";
2
+ 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-1z8QtQW8.mjs";
3
+ export { type B as BindMutatorsContext, type a as BoundMutators, type C as ClientMutatorContext, type b as ClientMutatorDef, c as bindMutators, d as defineMutator } from "./packem_shared/define-mutators.d-Cq_qr5Z1.mjs";
4
4
  import '@lunora/client';
5
5
  import '@tanstack/db';
6
6
  import '@tanstack/offline-transactions';
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- export { type C as CheckpointRegistry, type E as ExecutorOutboxSinkOptions, type L as LunoraCollectionConfig, type a as LunoraCollectionOptions, O as OUTBOX_MUTATION_FN_NAME, type b as OutboxExecutor, type d as OutboxMutationMetadata, type R as Row, type S as SyncWriter, c as createCheckpointRegistry, e as createExecutorOutboxSink, f as createOptimisticOnlineDetector, l as lunoraCollectionOptions, m as makeDiffEmit, r as runOutboxMutation, t as toMap } from "./packem_shared/collection-options.d-lJBOVJgq.js";
2
- 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-C01DaKJO.js";
3
- export { type B as BindMutatorsContext, type a as BoundMutators, type C as ClientMutatorContext, type b as ClientMutatorDef, c as bindMutators, d as defineMutator } from "./packem_shared/define-mutators.d-DhO8mWz0.js";
1
+ export { type C as CheckpointRegistry, type E as ExecutorOutboxSinkOptions, type L as LunoraCollectionConfig, type a as LunoraCollectionOptions, O as OUTBOX_MUTATION_FN_NAME, type b as OutboxExecutor, type d as OutboxMutationMetadata, type R as Row, type S as SyncWriter, c as createCheckpointRegistry, e as createExecutorOutboxSink, f as createOptimisticOnlineDetector, l as lunoraCollectionOptions, m as makeDiffEmit, r as runOutboxMutation, t as toMap } from "./packem_shared/collection-options.d-DgAuvqvn.js";
2
+ 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-DPgIHAtd.js";
3
+ export { type B as BindMutatorsContext, type a as BoundMutators, type C as ClientMutatorContext, type b as ClientMutatorDef, c as bindMutators, d as defineMutator } from "./packem_shared/define-mutators.d-10NiOBqm.js";
4
4
  import '@lunora/client';
5
5
  import '@tanstack/db';
6
6
  import '@tanstack/offline-transactions';
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
- export { createCheckpointRegistry, lunoraCollectionOptions } from './packem_shared/createCheckpointRegistry-DkfPWFWz.mjs';
2
- export { defineCollections } from './packem_shared/defineCollections--aaoqJCd.mjs';
1
+ export { createCheckpointRegistry, lunoraCollectionOptions } from './packem_shared/createCheckpointRegistry-Bf4JtkVH.mjs';
2
+ export { defineCollections } from './packem_shared/defineCollections-yLxJvEsu.mjs';
3
3
  export { bindMutators, defineMutator } from './packem_shared/bindMutators-BseARPYg.mjs';
4
4
  export { OUTBOX_MUTATION_FN_NAME, createExecutorOutboxSink, createOptimisticOnlineDetector, makeDiffEmit, runOutboxMutation, toMap } from './packem_shared/OUTBOX_MUTATION_FN_NAME-Cf8iP6Wa.mjs';
5
5
 
@@ -1,5 +1,5 @@
1
- export { type B as BindMutatorsContext, type a as BoundMutators, type C as ClientMutatorContext, type b as ClientMutatorDef, c as bindMutators, d as defineMutator } from "../packem_shared/define-mutators.d-HWj94_nL.mjs";
1
+ export { type B as BindMutatorsContext, type a as BoundMutators, type C as ClientMutatorContext, type b as ClientMutatorDef, c as bindMutators, d as defineMutator } from "../packem_shared/define-mutators.d-Cq_qr5Z1.mjs";
2
2
  import '@lunora/client';
3
3
  import '@tanstack/db';
4
- import "../packem_shared/collection-options.d-lJBOVJgq.mjs";
4
+ import "../packem_shared/collection-options.d-DgAuvqvn.mjs";
5
5
  import '@tanstack/offline-transactions';
@@ -1,5 +1,5 @@
1
- export { type B as BindMutatorsContext, type a as BoundMutators, type C as ClientMutatorContext, type b as ClientMutatorDef, c as bindMutators, d as defineMutator } from "../packem_shared/define-mutators.d-DhO8mWz0.js";
1
+ export { type B as BindMutatorsContext, type a as BoundMutators, type C as ClientMutatorContext, type b as ClientMutatorDef, c as bindMutators, d as defineMutator } from "../packem_shared/define-mutators.d-10NiOBqm.js";
2
2
  import '@lunora/client';
3
3
  import '@tanstack/db';
4
- import "../packem_shared/collection-options.d-lJBOVJgq.js";
4
+ import "../packem_shared/collection-options.d-DgAuvqvn.js";
5
5
  import '@tanstack/offline-transactions';
@@ -191,6 +191,16 @@ interface LunoraCollectionConfig<TRow extends Row> {
191
191
  scopeBy?: string;
192
192
  /** A replication shape as the sync source (partial replication). Mutually exclusive with {@link LunoraCollectionConfig.list}. */
193
193
  shape?: ShapeSource;
194
+ /**
195
+ * Routes the `list` subscription — and the confirmed-mutation watermark its
196
+ * data/`settled` frames advance the checkpoint gate from — to a specific
197
+ * shard's DO. Applies to the `list` source; a `shape` carries its own
198
+ * {@link ShapeSource.shardKey}. Without it the list path falls back to the
199
+ * default ("") watermark bucket, which must not be compared against a
200
+ * per-shard mutator's sequence line (it would drop a sharded overlay early or
201
+ * hang it forever).
202
+ */
203
+ shardKey?: string;
194
204
  }
195
205
  /** The result of {@link lunoraCollectionOptions}: a TanStack collection config plus its sync controls. */
196
206
  interface LunoraCollectionOptions<TRow extends Row> {
@@ -191,6 +191,16 @@ interface LunoraCollectionConfig<TRow extends Row> {
191
191
  scopeBy?: string;
192
192
  /** A replication shape as the sync source (partial replication). Mutually exclusive with {@link LunoraCollectionConfig.list}. */
193
193
  shape?: ShapeSource;
194
+ /**
195
+ * Routes the `list` subscription — and the confirmed-mutation watermark its
196
+ * data/`settled` frames advance the checkpoint gate from — to a specific
197
+ * shard's DO. Applies to the `list` source; a `shape` carries its own
198
+ * {@link ShapeSource.shardKey}. Without it the list path falls back to the
199
+ * default ("") watermark bucket, which must not be compared against a
200
+ * per-shard mutator's sequence line (it would drop a sharded overlay early or
201
+ * hang it forever).
202
+ */
203
+ shardKey?: string;
194
204
  }
195
205
  /** The result of {@link lunoraCollectionOptions}: a TanStack collection config plus its sync controls. */
196
206
  interface LunoraCollectionOptions<TRow extends Row> {
@@ -55,12 +55,13 @@ const lunoraCollectionOptions = (options) => {
55
55
  let emit;
56
56
  let unsubscribe;
57
57
  let onErrorHandler;
58
+ let scopedArgs;
58
59
  const openSubscription = (args, onReady) => {
59
60
  const onRows = (data) => {
60
61
  emit?.(toMap(data, getKey));
61
62
  onReady?.();
62
63
  if (options.shape === void 0) {
63
- checkpoints.resolve({ mutationId: options.client.confirmedMutationWatermark() });
64
+ checkpoints.resolve({ mutationId: options.client.confirmedMutationWatermark(options.shardKey) });
64
65
  }
65
66
  };
66
67
  const onError = (error) => onErrorHandler?.(error);
@@ -74,7 +75,7 @@ const lunoraCollectionOptions = (options) => {
74
75
  shardKey: options.shape.shardKey
75
76
  });
76
77
  }
77
- return options.client.subscribe(options.list, args, onRows, { onCheckpoint, onError });
78
+ return options.client.subscribe(options.list, args, onRows, { onCheckpoint, onError, shardKey: options.shardKey });
78
79
  };
79
80
  const config = {
80
81
  // Auto-build ordered (B-tree) indexes for whatever the app's live queries
@@ -100,12 +101,16 @@ const lunoraCollectionOptions = (options) => {
100
101
  });
101
102
  } else {
102
103
  writer.markReady();
104
+ if (scopedArgs !== void 0) {
105
+ unsubscribe = openSubscription(scopedArgs, void 0);
106
+ }
103
107
  }
104
108
  return () => {
105
109
  emit = void 0;
106
110
  onErrorHandler = void 0;
107
111
  unsubscribe?.();
108
112
  unsubscribe = void 0;
113
+ syncedJson.clear();
109
114
  };
110
115
  }
111
116
  }
@@ -114,13 +119,16 @@ const lunoraCollectionOptions = (options) => {
114
119
  if (options.scopeBy === void 0) {
115
120
  return;
116
121
  }
122
+ scopedArgs = args;
117
123
  unsubscribe?.();
118
124
  unsubscribe = void 0;
119
125
  emit?.(/* @__PURE__ */ new Map());
120
126
  if (args === void 0) {
121
127
  return;
122
128
  }
123
- unsubscribe = openSubscription(args, void 0);
129
+ if (emit !== void 0) {
130
+ unsubscribe = openSubscription(args, void 0);
131
+ }
124
132
  };
125
133
  return { checkpoints, config, scope };
126
134
  };
@@ -1,7 +1,7 @@
1
1
  import { FunctionReference, SubscriptionError, LunoraClient } from '@lunora/client';
2
2
  import { Transaction, Collection } from '@tanstack/db';
3
3
  import { OfflineExecutor, StorageDiagnostic } from '@tanstack/offline-transactions';
4
- import { R as Row } from "./collection-options.d-lJBOVJgq.js";
4
+ import { R as Row } from "./collection-options.d-DgAuvqvn.mjs";
5
5
  /** Element type of an array (the row type a `list` query returns). */
6
6
  type Element<T> = T extends ReadonlyArray<infer E> ? E : never;
7
7
  /** `true` for the `any` type, `false` otherwise. */
@@ -48,6 +48,13 @@ interface CollectionDef<TList extends FunctionReference, TInput = never> {
48
48
  onError?: (error: SubscriptionError) => void;
49
49
  /** A field that scopes the list (e.g. a shard key); makes the collection re-pointable via `scope`. */
50
50
  scopeBy?: string;
51
+ /**
52
+ * Routes the `list` subscription (and the confirmed-mutation watermark its
53
+ * frames advance the checkpoint gate from) to a specific shard's DO — so a
54
+ * sharded collection's overlay gate compares against that shard's mutator
55
+ * sequence line, not the default ("") watermark bucket.
56
+ */
57
+ shardKey?: string;
51
58
  }
52
59
  type AnyDef = CollectionDef<any, any>;
53
60
  /**
@@ -1,7 +1,7 @@
1
1
  import { FunctionReference, SubscriptionError, LunoraClient } from '@lunora/client';
2
2
  import { Transaction, Collection } from '@tanstack/db';
3
3
  import { OfflineExecutor, StorageDiagnostic } from '@tanstack/offline-transactions';
4
- import { R as Row } from "./collection-options.d-lJBOVJgq.mjs";
4
+ import { R as Row } from "./collection-options.d-DgAuvqvn.js";
5
5
  /** Element type of an array (the row type a `list` query returns). */
6
6
  type Element<T> = T extends ReadonlyArray<infer E> ? E : never;
7
7
  /** `true` for the `any` type, `false` otherwise. */
@@ -48,6 +48,13 @@ interface CollectionDef<TList extends FunctionReference, TInput = never> {
48
48
  onError?: (error: SubscriptionError) => void;
49
49
  /** A field that scopes the list (e.g. a shard key); makes the collection re-pointable via `scope`. */
50
50
  scopeBy?: string;
51
+ /**
52
+ * Routes the `list` subscription (and the confirmed-mutation watermark its
53
+ * frames advance the checkpoint gate from) to a specific shard's DO — so a
54
+ * sharded collection's overlay gate compares against that shard's mutator
55
+ * sequence line, not the default ("") watermark bucket.
56
+ */
57
+ shardKey?: string;
51
58
  }
52
59
  type AnyDef = CollectionDef<any, any>;
53
60
  /**
@@ -1,6 +1,6 @@
1
1
  import { LunoraClient } from '@lunora/client';
2
2
  import { Collection, Transaction } from '@tanstack/db';
3
- import { C as CheckpointRegistry, R as Row } from "./collection-options.d-lJBOVJgq.js";
3
+ import { C as CheckpointRegistry, R as Row } from "./collection-options.d-DgAuvqvn.js";
4
4
  /** The local store a client mutator's optimistic body writes against. */
5
5
  interface ClientMutatorContext {
6
6
  /** The wired collections, keyed by name — apply optimistic inserts/updates/deletes here. */
@@ -1,6 +1,6 @@
1
1
  import { LunoraClient } from '@lunora/client';
2
2
  import { Collection, Transaction } from '@tanstack/db';
3
- import { C as CheckpointRegistry, R as Row } from "./collection-options.d-lJBOVJgq.mjs";
3
+ import { C as CheckpointRegistry, R as Row } from "./collection-options.d-DgAuvqvn.mjs";
4
4
  /** The local store a client mutator's optimistic body writes against. */
5
5
  interface ClientMutatorContext {
6
6
  /** The wired collections, keyed by name — apply optimistic inserts/updates/deletes here. */
@@ -1,6 +1,6 @@
1
- import { createCollection } from '@tanstack/db';
1
+ import { createCollection, safeRandomUUID } from '@tanstack/db';
2
2
  import { startOfflineExecutor, NonRetriableError } from '@tanstack/offline-transactions';
3
- import { lunoraCollectionOptions } from './createCheckpointRegistry-DkfPWFWz.mjs';
3
+ import { lunoraCollectionOptions } from './createCheckpointRegistry-Bf4JtkVH.mjs';
4
4
  import { createOptimisticOnlineDetector, runOutboxMutation, OUTBOX_MUTATION_FN_NAME } from './OUTBOX_MUTATION_FN_NAME-Cf8iP6Wa.mjs';
5
5
 
6
6
  const defineCollections = (client, defs, options = {}) => {
@@ -18,18 +18,20 @@ const defineCollections = (client, defs, options = {}) => {
18
18
  list: definition.list,
19
19
  ...definition.load === void 0 ? {} : { load: definition.load },
20
20
  onError: definition.onError,
21
- scopeBy: definition.scopeBy
21
+ scopeBy: definition.scopeBy,
22
+ shardKey: definition.shardKey
22
23
  });
23
24
  collections[name] = createCollection(config);
24
25
  if (definition.scopeBy !== void 0) {
25
26
  scope[name] = scopeFunction;
26
27
  }
27
28
  if (insert) {
28
- mutationFns[name] = async ({ transaction }) => {
29
- for (const mutation of transaction.mutations) {
29
+ mutationFns[name] = async ({ idempotencyKey, transaction }) => {
30
+ for (const [mutationIndex, mutation] of transaction.mutations.entries()) {
30
31
  const row = mutation.modified;
32
+ const mutationId = `${idempotencyKey}:${String(mutationIndex)}`;
31
33
  try {
32
- await runOutboxMutation(() => client.mutation(insert.mutation, insert.toArgs(row)));
34
+ await runOutboxMutation(() => client.mutation(insert.mutation, insert.toArgs(row), { mutationId }));
33
35
  } catch (error) {
34
36
  if (error instanceof NonRetriableError && options.onWriteRejected) {
35
37
  try {
@@ -94,7 +96,7 @@ const defineCollections = (client, defs, options = {}) => {
94
96
  }
95
97
  });
96
98
  actions[name] = (input) => {
97
- const id = crypto.randomUUID();
99
+ const id = safeRandomUUID();
98
100
  const transaction = action({ id, input });
99
101
  return { id, transaction };
100
102
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/db",
3
- "version": "1.0.0-alpha.20",
3
+ "version": "1.0.0-alpha.21",
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.20",
58
- "@lunora/errors": "1.0.0-alpha.3"
57
+ "@lunora/client": "1.0.0-alpha.21",
58
+ "@lunora/errors": "1.0.0-alpha.4"
59
59
  },
60
60
  "peerDependencies": {
61
61
  "@tanstack/db": "^0.6.0",