@classytic/mongokit 3.40.0 → 3.41.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.
- package/README.md +71 -0
- package/dist/{PaginationEngine-D-P19Y9m.d.mts → PaginationEngine-CRHyuUtw.d.mts} +17 -3
- package/dist/{PaginationEngine-Dvl8jcRY.mjs → PaginationEngine-DZnkbSrr.mjs} +299 -140
- package/dist/{Repository-BMgPSkqZ.mjs → Repository-DlhPbXlG.mjs} +571 -175
- package/dist/{Repository-CR8Y9g2E.d.mts → Repository-pnLw1rG5.d.mts} +57 -16
- package/dist/actions/index.d.mts +1 -1
- package/dist/actions/index.mjs +1 -1
- package/dist/adapter/index.mjs +1 -1
- package/dist/{adapter-BrVfPFSW.mjs → adapter-CkMoMF83.mjs} +1 -1
- package/dist/ai/index.d.mts +1 -1
- package/dist/better-auth/index.mjs +2 -2
- package/dist/{create-repository-CAle1MSU.d.mts → create-repository-BUx9vfG9.d.mts} +5 -5
- package/dist/{create-repository-BzBUMvd1.mjs → create-repository-Bg0H5rte.mjs} +2 -2
- package/dist/{index-CmjNyulu.d.mts → index-SYF8N28D.d.mts} +37 -19
- package/dist/index.d.mts +69 -15
- package/dist/index.mjs +57 -11
- package/dist/join-scope-DSAznE8E.mjs +168 -0
- package/dist/{mongooseToJsonSchema-waUVQwK4.mjs → mongooseToJsonSchema-C3k4ide0.mjs} +5 -1
- package/dist/{multi-tenant.plugin-CBgCo9im.d.mts → multi-tenant.plugin-a3UhQARj.d.mts} +2 -2
- package/dist/{operations-CrRIoc8Z.d.mts → operations-XiFgG5US.d.mts} +36 -13
- package/dist/outbox/index.d.mts +1 -1
- package/dist/outbox/index.mjs +1 -1
- package/dist/pagination/PaginationEngine.d.mts +2 -2
- package/dist/pagination/PaginationEngine.mjs +1 -1
- package/dist/pagination/utils/limits.d.mts +1 -1
- package/dist/{pagination-BpIv2bdS.d.mts → pagination-D6psses0.d.mts} +116 -13
- package/dist/{plugin-options-Zk46lD6F.d.mts → plugin-options-CRhIvSzx.d.mts} +2 -2
- package/dist/plugins/index.d.mts +3 -3
- package/dist/plugins/index.mjs +2 -2
- package/dist/query-defaults-BxUcSOoF.mjs +208 -0
- package/dist/read-model/index.d.mts +66 -0
- package/dist/read-model/index.mjs +193 -0
- package/dist/{repository-odl03582.d.mts → repository-DNHfjAZX.d.mts} +16 -2
- package/dist/sync/index.d.mts +15 -2
- package/dist/sync/index.mjs +38 -1
- package/dist/testkit/index.d.mts +40 -3
- package/dist/testkit/index.mjs +113 -2
- package/dist/{timestamp.plugin-DF0gJB6p.mjs → timestamp.plugin-DvZlnKEc.mjs} +50 -31
- package/dist/{to-plain-k7SjNlSS.d.mts → to-plain-CjgEInWV.d.mts} +2 -2
- package/dist/{transaction-B5L9glO0.mjs → transaction-DmiB4k2P.mjs} +155 -6
- package/dist/{update-DG0fCwRJ.mjs → update-WgeAUJ_I.mjs} +44 -22
- package/dist/utils/index.d.mts +1 -1
- package/dist/utils/index.mjs +1 -1
- package/dist/{validation-chain.plugin-DYp9E7K2.d.mts → validation-chain.plugin-CTcNJCmV.d.mts} +4 -4
- package/dist/{validation-chain.plugin-BLY2gLEk.mjs → validation-chain.plugin-D1WsGCYr.mjs} +15 -3
- package/package.json +10 -5
package/README.md
CHANGED
|
@@ -170,6 +170,18 @@ const next = await repo.getAll({
|
|
|
170
170
|
});
|
|
171
171
|
```
|
|
172
172
|
|
|
173
|
+
Every sort gets a unique `_id` tiebreaker and `hasNext` comes from a limit+1 fetch. Offset pages
|
|
174
|
+
report `{ total, totalIsEstimate, countedAt }` under every `countStrategy` (`exact`, `capped`,
|
|
175
|
+
`estimated`, `none`, `cached`); a `skip` past `maxOffset` (default 100,000) is refused with
|
|
176
|
+
`mongokit.pagination.offset_too_deep`. A cursor is bound to its collection, filter (tenant
|
|
177
|
+
included) and collation: replayed elsewhere it is `repo.cursor.scope_mismatch` (repo-core `CURSOR_ERROR_CODES`); set
|
|
178
|
+
`cursorSecret` so tampering is detected too.
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
// Boot: the deployment's list policy.
|
|
182
|
+
configurePaginationDefaults({ defaultCountStrategy: 'capped', cursorSecret, maxOffset: 50_000 });
|
|
183
|
+
```
|
|
184
|
+
|
|
173
185
|
### Transactions
|
|
174
186
|
|
|
175
187
|
```ts
|
|
@@ -189,6 +201,55 @@ await orderRepo.withTransaction(async (txRepo) => {
|
|
|
189
201
|
});
|
|
190
202
|
```
|
|
191
203
|
|
|
204
|
+
### Time Bounds And Concerns (`queryDefaults`)
|
|
205
|
+
|
|
206
|
+
```ts
|
|
207
|
+
// Boot: every command is bounded; the boot check fails without it (and without CSOT timeoutMS).
|
|
208
|
+
await mongoose.connect(uri, { timeoutMS: 30_000 });
|
|
209
|
+
configureQueryDefaults({ maxTimeMS: 5_000, writeConcern: { w: 'majority' } });
|
|
210
|
+
configureAggregateDefaults({ maxTimeMs: 15_000 });
|
|
211
|
+
assertQueryDefaultsConfigured(mongoose.connection);
|
|
212
|
+
|
|
213
|
+
// Per repository, and per call (per call always wins):
|
|
214
|
+
const repo = new Repository(Order, plugins, {}, { queryDefaults: { comment: 'orders' } });
|
|
215
|
+
await repo.findAll(filter, { maxTimeMS: 500 });
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Joins Are Scoped
|
|
219
|
+
|
|
220
|
+
A `$lookup` / `$unionWith` / `$graphLookup` reads the joined collection under its own repository's
|
|
221
|
+
tenant and soft-delete scope. Take `from` from `Model.collection.name`: a name no model owns throws
|
|
222
|
+
`mongokit.join.unknown_collection`, a collection no repository governs throws
|
|
223
|
+
`mongokit.join.ungoverned_collection` (list a company-wide one in `unscopedJoins`).
|
|
224
|
+
|
|
225
|
+
### Batch Reads (`getByIds`)
|
|
226
|
+
|
|
227
|
+
```ts
|
|
228
|
+
const byId = await repo.getByIds(ids, { select: 'name sku' }); // Map, chunked $in
|
|
229
|
+
const rows = await repo.getByIds(ids, { preserveOrder: true, chunkSize: 5_000 }); // aligned, undefined = miss
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### Read Models (`bulkUpsert`, `@classytic/mongokit/read-model`)
|
|
233
|
+
|
|
234
|
+
```ts
|
|
235
|
+
const res = await totals.bulkUpsert(rows, { key: ['period', 'rate'], inc: ['tax'], organizationId });
|
|
236
|
+
// res.results[i].outcome: 'inserted' | 'updated' | 'unchanged' | 'failed' (+ code). Needs MongoDB 8.0.
|
|
237
|
+
|
|
238
|
+
import { applyIncrements, rebuildInto, reconcile } from '@classytic/mongokit/read-model';
|
|
239
|
+
await applyIncrements(totals, grains, { session, ledger, organizationId }); // inside the posting transaction
|
|
240
|
+
await rebuildInto(facts, totals, { pipeline, on: ['organizationId', 'period', 'rate'], scope: { organizationId } });
|
|
241
|
+
const { drift } = await reconcile(facts, totals, { pipeline, on, measures: ['tax'], scope: { organizationId } });
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Resumable Sweeps (`iterate`)
|
|
245
|
+
|
|
246
|
+
```ts
|
|
247
|
+
for await (const { docs, checkpoint } of repo.iterate(filter, { batchSize: 1_000, after: saved, organizationId })) {
|
|
248
|
+
await process(docs);
|
|
249
|
+
await saveCheckpoint(checkpoint); // resume later with { after: checkpoint }
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
192
253
|
### Change Streams
|
|
193
254
|
|
|
194
255
|
```ts
|
|
@@ -430,6 +491,16 @@ Atlas **`$search` / `$vectorSearch`** indexes are Atlas-only and don't exist on
|
|
|
430
491
|
|
|
431
492
|
All accept `{ replset?, dbName?, uri? }`.
|
|
432
493
|
|
|
494
|
+
### Query-plan gate
|
|
495
|
+
|
|
496
|
+
```ts
|
|
497
|
+
import { assertQueryPlan } from '@classytic/mongokit/testkit';
|
|
498
|
+
// The connection must be opened with { monitorCommands: true }.
|
|
499
|
+
await assertQueryPlan(() => repo.getAll({ filters: { status: 'open' }, sort: { at: -1 } }), {
|
|
500
|
+
connection, minDocs: 1_000, leadingKeys: ['status', 'at'], // fails on COLLSCAN / unindexed SORT
|
|
501
|
+
});
|
|
502
|
+
```
|
|
503
|
+
|
|
433
504
|
## Kernel Conformance — `@classytic/mongokit/kernel-conformance`
|
|
434
505
|
|
|
435
506
|
An **executable contract suite** for domain kernels built on `defineModels()`. A kernel that
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { c as MongokitPageExtras, f as CursorSecret, i as CountStrategy, l as OffsetPaginationOptions,
|
|
1
|
+
import { D as AnyDocument, c as MongokitPageExtras, f as CursorSecret, i as CountStrategy, l as OffsetPaginationOptions, s as KeysetPaginationOptions, t as AggregatePaginationOptions, u as PaginationConfig } from "./pagination-D6psses0.mjs";
|
|
2
2
|
import { Model } from "mongoose";
|
|
3
|
+
import { TtlMemo } from "@classytic/repo-core/cache";
|
|
3
4
|
import { AggregatePaginationResult, KeysetPaginationResult, OffsetPaginationResult } from "@classytic/repo-core/pagination";
|
|
4
5
|
//#region src/pagination/PaginationEngine.d.ts
|
|
5
6
|
/**
|
|
@@ -18,11 +19,17 @@ interface ResolvedPaginationConfig {
|
|
|
18
19
|
defaultCountLimit: number;
|
|
19
20
|
cursorSecret: CursorSecret | undefined;
|
|
20
21
|
defaultMode: 'offset' | 'keyset' | undefined;
|
|
22
|
+
maxOffset: number;
|
|
23
|
+
countCacheTtlMs: number;
|
|
21
24
|
}
|
|
22
25
|
/**
|
|
23
26
|
* Production-grade pagination engine for MongoDB
|
|
24
27
|
* Supports offset, keyset (cursor), and aggregate pagination
|
|
25
28
|
*/
|
|
29
|
+
interface CountMemoKey {
|
|
30
|
+
key: string;
|
|
31
|
+
run: () => Promise<number>;
|
|
32
|
+
}
|
|
26
33
|
declare class PaginationEngine<TDoc = AnyDocument> {
|
|
27
34
|
readonly Model: Model<TDoc>;
|
|
28
35
|
readonly config: ResolvedPaginationConfig;
|
|
@@ -37,6 +44,13 @@ declare class PaginationEngine<TDoc = AnyDocument> {
|
|
|
37
44
|
* @param Model - Mongoose model to paginate
|
|
38
45
|
* @param config - Pagination configuration
|
|
39
46
|
*/
|
|
47
|
+
/** Memoised capped counts for `countStrategy: 'cached'`, rebuilt when the TTL changes. */
|
|
48
|
+
private _memo;
|
|
49
|
+
/** The `cached` count memo (repo-core `createTtlMemo`: single flight, a failed count caches nothing). */
|
|
50
|
+
_countMemo(): TtlMemo<CountMemoKey, {
|
|
51
|
+
total: number;
|
|
52
|
+
countedAt: Date;
|
|
53
|
+
}>;
|
|
40
54
|
constructor(Model: Model<TDoc, any, any, any>, config?: PaginationConfig);
|
|
41
55
|
/** Memoized schema index lookup — avoids re-walking schema on every stream(). */
|
|
42
56
|
private _getSchemaIndexes;
|
|
@@ -122,7 +136,7 @@ declare class PaginationEngine<TDoc = AnyDocument> {
|
|
|
122
136
|
* limit: 20
|
|
123
137
|
* });
|
|
124
138
|
*/
|
|
125
|
-
aggregatePaginate(options?: AggregatePaginationOptions): Promise<AggregatePaginationResult<TDoc>>;
|
|
139
|
+
aggregatePaginate(options?: AggregatePaginationOptions): Promise<AggregatePaginationResult<TDoc, MongokitPageExtras>>;
|
|
126
140
|
}
|
|
127
141
|
//#endregion
|
|
128
|
-
export { PaginationEngine as t };
|
|
142
|
+
export { PaginationEngine as n, CountMemoKey as t };
|