@classytic/mongokit 3.43.1 → 3.45.0

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.
Files changed (92) hide show
  1. package/README.md +18 -3
  2. package/dist/{PaginationEngine-DZnkbSrr.mjs → PaginationEngine-BRlLTQQz.mjs} +13 -27
  3. package/dist/{PaginationEngine-CRHyuUtw.d.mts → PaginationEngine-BWb-c47a.d.mts} +1 -3
  4. package/dist/{Repository-DnL4xk5w.d.mts → Repository-DJuRmBNx.d.mts} +44 -13
  5. package/dist/{Repository-Dj6xqPxJ.mjs → Repository-DheA7oW-.mjs} +330 -112
  6. package/dist/actions/index.d.mts +1 -1
  7. package/dist/actions/index.mjs +2 -2
  8. package/dist/{actions-ChYfkPYP.mjs → actions-DKQx9ToJ.mjs} +3 -4
  9. package/dist/adapter/index.d.mts +6 -10
  10. package/dist/adapter/index.mjs +1 -1
  11. package/dist/{adapter-CkMoMF83.mjs → adapter-Qzgc3ZD_.mjs} +4 -6
  12. package/dist/ai/index.d.mts +21 -8
  13. package/dist/ai/index.mjs +15 -9
  14. package/dist/better-auth/index.d.mts +21 -20
  15. package/dist/better-auth/index.mjs +12 -23
  16. package/dist/{coercion-BjdPX3YF.d.mts → coercion-COp9DRNw.d.mts} +0 -2
  17. package/dist/{create-repository-UjwPWR1z.mjs → create-repository-C9DHHcl7.mjs} +4 -5
  18. package/dist/{create-repository-CJtVdwig.d.mts → create-repository-DG-gwOf0.d.mts} +5 -7
  19. package/dist/{derive-DRBiegRH.mjs → derive-Dxsc31fV.mjs} +3 -6
  20. package/dist/{error-BuByZwKU.mjs → error-DjdmPLWO.mjs} +1 -2
  21. package/dist/{field-selection-FSQFLpsU.mjs → field-selection-DPFaFw9Y.mjs} +1 -2
  22. package/dist/{id-chunks-BmAwsqNk.mjs → id-chunks-DH-RAZWG.mjs} +13 -8
  23. package/dist/{id-resolution-BqDrk0S2.mjs → id-resolution-Cqh49d9J.mjs} +1 -2
  24. package/dist/idempotency/index.d.mts +4 -7
  25. package/dist/idempotency/index.mjs +1 -2
  26. package/dist/{index-SYF8N28D.d.mts → index-5mhQ63_B.d.mts} +3 -4
  27. package/dist/{index-C0AjVqX3.d.mts → index-ehGZLbrd.d.mts} +2 -8
  28. package/dist/index.d.mts +70 -102
  29. package/dist/index.mjs +36 -52
  30. package/dist/indexes/verify-indexes.d.mts +8 -11
  31. package/dist/indexes/verify-indexes.mjs +1 -2
  32. package/dist/{indexes-DIjMpYES.d.mts → indexes-FfyOuhDK.d.mts} +0 -2
  33. package/dist/{join-scope-DSAznE8E.mjs → join-scope-C1gOtZ59.mjs} +2 -3
  34. package/dist/kernel-conformance/index.d.mts +39 -13
  35. package/dist/kernel-conformance/index.mjs +4 -7
  36. package/dist/lock/index.d.mts +134 -7
  37. package/dist/lock/index.mjs +349 -14
  38. package/dist/{logger-K7dPmu2U.mjs → logger-hbWOlj_X.mjs} +1 -2
  39. package/dist/{method-registry.plugin-C63pGn1d.mjs → method-registry.plugin-BeJfQBJV.mjs} +5 -7
  40. package/dist/{model-registry-ClKtWiHa.mjs → model-registry-DrVfJ3Nt.mjs} +1 -2
  41. package/dist/{mongooseToJsonSchema-C3k4ide0.mjs → mongooseToJsonSchema-DMDotz4_.mjs} +2 -3
  42. package/dist/{multi-tenant.plugin-B_q9NUHc.d.mts → multi-tenant.plugin-BTPtCLNK.d.mts} +143 -11
  43. package/dist/{operations-XiFgG5US.d.mts → operations-D6XsHx4e.d.mts} +19 -11
  44. package/dist/outbox/index.d.mts +24 -9
  45. package/dist/outbox/index.mjs +17 -6
  46. package/dist/pagination/PaginationEngine.d.mts +1 -1
  47. package/dist/pagination/PaginationEngine.mjs +1 -1
  48. package/dist/pagination/utils/limits.d.mts +6 -9
  49. package/dist/pagination/utils/limits.mjs +2 -3
  50. package/dist/{pagination-D6psses0.d.mts → pagination-BAM9cA4N.d.mts} +6 -16
  51. package/dist/{plugin-options-Cirmb4Kp.d.mts → plugin-options-DrNGWV5b.d.mts} +2 -4
  52. package/dist/plugins/index.d.mts +6 -7
  53. package/dist/plugins/index.mjs +6 -7
  54. package/dist/query/primitives/coercion.d.mts +1 -1
  55. package/dist/query/primitives/coercion.mjs +2 -3
  56. package/dist/query/primitives/geo.d.mts +11 -14
  57. package/dist/query/primitives/geo.mjs +1 -2
  58. package/dist/query/primitives/indexes.d.mts +1 -1
  59. package/dist/query/primitives/indexes.mjs +1 -2
  60. package/dist/{query-defaults-BxUcSOoF.mjs → query-defaults-DwvWUjZU.mjs} +18 -54
  61. package/dist/read-model/index.d.mts +18 -21
  62. package/dist/read-model/index.mjs +3 -4
  63. package/dist/{repository-MqAP409e.d.mts → repository-B0aFVgP2.d.mts} +25 -29
  64. package/dist/retention-purge-CCd_VXUf.d.mts +38 -0
  65. package/dist/{rolldown-runtime-D7D4PA-g.mjs → rolldown-runtime-D8jQpDG7.mjs} +1 -2
  66. package/dist/search/index.d.mts +1 -1
  67. package/dist/search/index.mjs +1 -1
  68. package/dist/sync/index.d.mts +113 -17
  69. package/dist/sync/index.mjs +421 -65
  70. package/dist/tenant/index.d.mts +8 -11
  71. package/dist/tenant/index.mjs +1 -2
  72. package/dist/testkit/index.d.mts +179 -23
  73. package/dist/testkit/index.mjs +421 -23
  74. package/dist/{timestamp.plugin-DpOWavVI.mjs → timestamp.plugin-B-IJrlYb.mjs} +192 -49
  75. package/dist/{to-plain-vksRrLtc.mjs → to-plain-CEKv_ylg.mjs} +2 -4
  76. package/dist/{to-plain-o5tUY2nV.d.mts → to-plain-Do-8jTKC.d.mts} +2 -16
  77. package/dist/{transaction-DmiB4k2P.mjs → transaction-C6Oj941P.mjs} +18 -19
  78. package/dist/{type-utils-CLzRFtIA.d.mts → type-utils-CKvuewAL.d.mts} +0 -2
  79. package/dist/{update-WgeAUJ_I.mjs → update-CYaJMu6j.mjs} +13 -23
  80. package/dist/usage/index.d.mts +2 -5
  81. package/dist/usage/index.mjs +8 -6
  82. package/dist/utils/index.d.mts +8 -10
  83. package/dist/utils/index.mjs +7 -7
  84. package/dist/{validation-chain.plugin-BAeC5eVT.d.mts → validation-chain.plugin-COYrUdd8.d.mts} +150 -48
  85. package/dist/{validation-chain.plugin-DRApTmkN.mjs → validation-chain.plugin-DJplVJ12.mjs} +210 -55
  86. package/llms.txt +33 -0
  87. package/package.json +29 -25
  88. package/skills/mongokit/SKILL.md +112 -0
  89. package/skills/mongokit/references/pagination-search.md +87 -0
  90. package/skills/mongokit/references/plugins-tenancy.md +103 -0
  91. package/skills/mongokit/references/repository-api.md +83 -0
  92. package/skills/mongokit/references/transactions-outbox.md +103 -0
@@ -1,7 +1,6 @@
1
1
  import { ClientSession, Connection, Model } from "mongoose";
2
- import { ChangeLogAppendOptions, ChangeLogStore, CommandStreamStore, CommandStreamTx } from "@classytic/repo-core/sync";
3
- //#region src/sync/index.d.ts
4
- interface ChangeLogModelOptions {
2
+ import { ChangeEntry, ChangeLogAppendOptions, ChangeLogStore, ChangesPage, ChangesSinceOptions, CommandStreamStore, CommandStreamTx } from "@classytic/repo-core/sync";
3
+ export interface ChangeLogModelOptions {
5
4
  /** Entries collection. Default `sync_changes`; its counter lives in `<collection>_counter`. */
6
5
  collection?: string;
7
6
  /** Mongoose model name prefix. Default `SyncChange`. Must be unique per connection. */
@@ -14,29 +13,87 @@ interface ChangeLogModelOptions {
14
13
  * before, so no reader can checkpoint past an entry that appears later.
15
14
  */
16
15
  sequencing?: 'in-transaction' | 'deferred';
16
+ /**
17
+ * Deferred sequencing: how long the sequencer lease lasts, in ms (default {@link DEFAULT_SEQUENCER_LEASE_MS}).
18
+ * The holder renews it with every batch it commits, so this bounds one batch, not one pass, and it is the longest
19
+ * a sequencer that dies mid-pass can delay numbering. Expiry is judged on the database clock (`$$NOW`), so
20
+ * process clock skew does not stretch it. A holder whose lease was taken over cannot write: each batch commits
21
+ * in one transaction gated on the lease token. Integer, at least 100.
22
+ */
23
+ sequencerLeaseMs?: number;
17
24
  }
18
- interface ChangeLogModels {
25
+ /** Default deferred-sequencer lease: a crashed holder delays numbering at most this long. */
26
+ export declare const DEFAULT_SEQUENCER_LEASE_MS = 5000;
27
+ export interface ChangeLogModels {
19
28
  entries: Model<Record<string, unknown>>;
20
29
  counter: Model<Record<string, unknown>>;
30
+ /**
31
+ * `prune`'s horizons per `(tenantId, scope)` (`<collection>_horizon`, `tenantId: null` for untenanted entries):
32
+ * the highest seq it deleted there. A filtered reader is expired only by the horizons of what it can see.
33
+ * Always set by `createChangeLogModels`; a hand-built models object without it falls back to the feed-wide
34
+ * horizon for every reader.
35
+ */
36
+ horizons?: Model<Record<string, unknown>>;
21
37
  /** Staged, not-yet-numbered entries — present only under `sequencing: 'deferred'`. */
22
38
  pending?: Model<Record<string, unknown>>;
23
39
  sequencing: 'in-transaction' | 'deferred';
40
+ /** Deferred sequencer lease in ms; {@link DEFAULT_SEQUENCER_LEASE_MS} when absent (a hand-built models object). */
41
+ sequencerLeaseMs?: number;
24
42
  /** The counter document's id (one feed per entries collection). */
25
43
  feed: string;
26
44
  }
27
- declare function createChangeLogModels(connection: Connection, options?: ChangeLogModelOptions): ChangeLogModels;
45
+ export declare function createChangeLogModels(connection: Connection, options?: ChangeLogModelOptions): ChangeLogModels;
46
+ /** {@link MongoChangeLogStore.snapshot}'s options: the reader's view, plus the bound after the first page. */
47
+ export interface ChangesSnapshotOptions extends ChangesSinceOptions {
48
+ /** The `upTo` the first page returned; omit it on the first page. */
49
+ readonly upTo?: string;
50
+ }
51
+ /** One snapshot page. `cursor` pages the snapshot; `upTo` is where `since()` resumes once `hasMore` is false. */
52
+ export interface ChangesSnapshotPage extends ChangesPage {
53
+ readonly upTo: string;
54
+ }
28
55
  /** The mongo change feed: the `ChangeLogStore` contract plus superseded-entry compaction. */
29
- interface MongoChangeLogStore extends ChangeLogStore {
56
+ export interface MongoChangeLogStore extends ChangeLogStore {
30
57
  /**
31
- * Delete every entry a later COMMITTED entry of the same `(scope, docId)` replaced. Safe for any client
32
- * cursor: entries carry whole documents, so a reader only ever needs the latest one; tombstones and
33
- * each document's latest entry stay. Idempotent; run it on a schedule.
58
+ * Delete every entry of a `(tenantId, scope, docId)` but the one a reader ends on (the last
59
+ * tombstone, or the highest-version upsert after it). Safe for any client cursor: entries carry
60
+ * whole documents, and a reader would have skipped every deleted one. Idempotent; run it on a schedule.
34
61
  */
35
62
  compactSuperseded(options?: {
36
63
  batchSize?: number;
37
64
  }): Promise<{
38
65
  removed: number;
39
66
  }>;
67
+ /**
68
+ * Retention with a horizon (the `ChangeLogStore.prune` contract). Deletes every entry older than
69
+ * `before` (`at < before`) except, per `(tenantId, scope, docId)`, the one a reader ends on (as
70
+ * `compactSuperseded` keeps), so a snapshot still sees every document. Records a HORIZON (the highest deleted cursor, never lowered) per `(tenantId, scope)`
71
+ * and feed-wide, BEFORE deleting, and returns the feed-wide one, `''` while nothing was ever
72
+ * pruned. `since(cursor, options)` with a cursor below the horizon of what that reader can see
73
+ * (its tenant, shared scopes and `scopes`; the feed-wide horizon when unfiltered; `''` included)
74
+ * throws repo-core's `CursorExpiredError(cursor, horizon)`: that reader missed deleted
75
+ * intermediate entries and must resync from `latestCursor(options)`, which never answers below
76
+ * that horizon. Pruning one tenant never expires another tenant's cursor. Unlike
77
+ * `compactSuperseded`, which is safe for any cursor but silently drops intermediate entries a
78
+ * resuming reader has not seen, a reader never gets a silent gap here. Idempotent; schedule it
79
+ * (e.g. hourly with `before = now - 24h`).
80
+ */
81
+ prune(before: Date, options?: {
82
+ batchSize?: number;
83
+ }): Promise<string>;
84
+ /**
85
+ * The resync bootstrap for a reader `since()` expired: each document's latest entry at or below
86
+ * `upTo` (the reader's horizon, fixed by the first page), tombstones left out, in feed order. Then
87
+ * `since(upTo)` carries on, delivering every change above it, deletes included. Complete because
88
+ * `prune` and `compactSuperseded` never delete a document's latest entry. If that `since(upTo)`
89
+ * expires again, a prune raised the horizon in between: bootstrap again.
90
+ */
91
+ snapshot(cursor: string, options?: ChangesSnapshotOptions): Promise<ChangesSnapshotPage>;
92
+ /**
93
+ * The compaction horizon cursor a reader with these options is held to (`''` while nothing it
94
+ * can see was pruned); feed-wide without options.
95
+ */
96
+ horizon(options?: Pick<ChangesSinceOptions, 'tenantId' | 'scopes' | 'sharedScopes'>): Promise<string>;
40
97
  /**
41
98
  * Number every staged entry (deferred sequencing; a no-op otherwise). Reads call it first; a scheduler may too.
42
99
  * Returns how many it numbered, or `null` when another sequencer holds the lease.
@@ -47,21 +104,62 @@ interface MongoChangeLogStore extends ChangeLogStore {
47
104
  * never use the cursor (`changeLogPlugin`). Under in-transaction sequencing it is `append`.
48
105
  */
49
106
  stage(entry: Parameters<ChangeLogStore['append']>[0], options?: ChangeLogAppendOptions): Promise<void>;
107
+ /**
108
+ * Point read of ONE document's latest recorded change: its last staged entry when one waits for a cursor
109
+ * (deferred sequencing; `cursor: ''`, as `append` answers inside a transaction), else its highest numbered
110
+ * entry; `null` when the feed holds none. Reads only (it never runs the sequencer), so it is cheap on a hot
111
+ * path, e.g. a writer that needs the last recorded state of a record before it appends the next change.
112
+ * A document is `(tenantId, scope, docId)`: `tenantId` omitted or `null` reads the untenanted document.
113
+ * Pass `session` to see what the caller staged or appended in its own transaction. Pruning and
114
+ * compaction keep the entry a reader ends on, which may not be the last one recorded.
115
+ */
116
+ latestOf(scope: string, docId: string, options?: {
117
+ tenantId?: string | null;
118
+ session?: unknown;
119
+ }): Promise<ChangeEntry | null>;
120
+ }
121
+ /** What {@link ChangeLogStoreOptions.onSequenced} is told: new entries now have cursors up to `cursor`. */
122
+ export interface ChangeLogSequencedEvent {
123
+ /** The highest numbered cursor of the feed after the pass (readers reading past their cursor see the new entries). */
124
+ cursor: string;
125
+ /** How many entries were numbered since this store last looked (by this store, or by another holder). */
126
+ numbered: number;
127
+ /** `'self'`: this store's pass numbered them. `'other'`: another holder did, while a read of this store waited. */
128
+ by: 'self' | 'other';
129
+ }
130
+ /** Runtime options of {@link createChangeLogStore} (the models carry the storage options). */
131
+ export interface ChangeLogStoreOptions {
132
+ /**
133
+ * Clock for every entry's `at` (staged and in-transaction appends). Default `() => new Date()`. Inject the host's
134
+ * clock so `at` and `prune(before)` cutoffs agree with a driven test clock. The deferred sequencer's LEASE stays on
135
+ * the database clock (`$$NOW`): it is shared by every process, so it must not depend on any one process's clock.
136
+ */
137
+ now?: () => Date;
138
+ /**
139
+ * Deferred sequencing: called after new entries got cursors, so a host's replay hub can `notify()` its tails at
140
+ * once. Fires when this store's pass numbered entries (`by: 'self'`), and when a read of this store found the
141
+ * sequencer lease held by another holder: the store then retries in the background (short backoff, unref'd
142
+ * timers, for at most three leases) until that holder is done, and reports what it numbered meanwhile
143
+ * (`by: 'other'`), or takes over a lease left by a holder that died and numbers the entries itself
144
+ * (`by: 'self'`). Without this hook nothing is retried in the background. A throwing hook is ignored. Never
145
+ * called under in-transaction sequencing (every append already has its cursor).
146
+ */
147
+ onSequenced?: (event: ChangeLogSequencedEvent) => void;
50
148
  }
51
- declare function createChangeLogStore(models: ChangeLogModels): MongoChangeLogStore;
52
- interface CommandStreamModelOptions {
149
+ export declare function createChangeLogStore(models: ChangeLogModels, storeOptions?: ChangeLogStoreOptions): MongoChangeLogStore;
150
+ export interface CommandStreamModelOptions {
53
151
  /** Collection prefix: `<prefix>_streams`, `<prefix>_verdicts`, `<prefix>_aliases`. Default `sync`. */
54
152
  prefix?: string;
55
153
  /** Mongoose model name prefix. Default `SyncStream`. Must be unique per connection. */
56
154
  modelName?: string;
57
155
  }
58
- interface CommandStreamModels {
156
+ export interface CommandStreamModels {
59
157
  streams: Model<Record<string, unknown>>;
60
158
  verdicts: Model<Record<string, unknown>>;
61
159
  aliases: Model<Record<string, unknown>>;
62
160
  }
63
- declare function createCommandStreamModels(connection: Connection, options?: CommandStreamModelOptions): CommandStreamModels;
64
- interface MongoCommandStreamTx extends CommandStreamTx {
161
+ export declare function createCommandStreamModels(connection: Connection, options?: CommandStreamModelOptions): CommandStreamModels;
162
+ export interface MongoCommandStreamTx extends CommandStreamTx {
65
163
  readonly session: ClientSession;
66
164
  }
67
165
  /**
@@ -69,6 +167,4 @@ interface MongoCommandStreamTx extends CommandStreamTx {
69
167
  * Concurrent transactions on one stream write-conflict on its document and `withTransaction`
70
168
  * retries the loser, which then reads the winner's watermark.
71
169
  */
72
- declare function createCommandStreamStore(connection: Pick<Connection, 'startSession'>, models: CommandStreamModels, changes: ChangeLogStore): CommandStreamStore<MongoCommandStreamTx>;
73
- //#endregion
74
- export { ChangeLogModelOptions, ChangeLogModels, CommandStreamModelOptions, CommandStreamModels, MongoChangeLogStore, MongoCommandStreamTx, createChangeLogModels, createChangeLogStore, createCommandStreamModels, createCommandStreamStore };
170
+ export declare function createCommandStreamStore(connection: Pick<Connection, 'startSession'>, models: CommandStreamModels, changes: ChangeLogStore): CommandStreamStore<MongoCommandStreamTx>;