@classytic/mongokit 3.15.0 → 3.16.1
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 +193 -319
- package/dist/{PaginationEngine-CfQRM1yz.mjs → PaginationEngine-0XXTW-9b.mjs} +2 -2
- package/dist/{Repository-BGL1Pq8w.mjs → Repository-DE7D2QeS.mjs} +240 -19
- package/dist/actions/index.d.mts +1 -1
- package/dist/ai/index.d.mts +1 -1
- package/dist/ai/index.mjs +14 -5
- package/dist/better-auth/index.d.mts +15 -0
- package/dist/better-auth/index.mjs +1 -1
- package/dist/{index-Dccha9dw.d.mts → index-CV5vv-8E.d.mts} +1 -1
- package/dist/index.d.mts +1182 -1079
- package/dist/index.mjs +32 -19
- package/dist/{mongooseToJsonSchema-BYbG894y.mjs → mongooseToJsonSchema-CMM2QHzd.mjs} +28 -1
- package/dist/{mongooseToJsonSchema-BgRAaXX-.d.mts → mongooseToJsonSchema-GhvZUjRO.d.mts} +1 -1
- package/dist/pagination/PaginationEngine.d.mts +1 -1
- package/dist/pagination/PaginationEngine.mjs +1 -1
- package/dist/plugins/index.d.mts +1 -1
- package/dist/plugins/index.mjs +1 -1
- package/dist/query/primitives/coercion.mjs +1 -1
- package/dist/{types-BbaPZleN.d.mts → types-BWZILovv.d.mts} +26 -1
- package/dist/utils/index.d.mts +1 -1
- package/dist/utils/index.mjs +3 -3
- package/dist/{validation-chain.plugin-CWhvBRej.mjs → validation-chain.plugin-Crl5nQAY.mjs} +1172 -1137
- package/dist/{validation-chain.plugin-CAPYCj_T.d.mts → validation-chain.plugin-Iee2_puD.d.mts} +368 -344
- package/package.json +6 -6
- /package/dist/{cursor-J84rR6wG.mjs → cursor-4LMYa4ga.mjs} +0 -0
- /package/dist/{field-selection-Br3WPOEb.mjs → field-selection-CQW3WBiK.mjs} +0 -0
- /package/dist/{id-resolution-B0Odvvou.mjs → id-resolution-DduoO4LI.mjs} +0 -0
- /package/dist/{sort-CrZjTK25.mjs → sort-RPVz5u0w.mjs} +0 -0
package/dist/{validation-chain.plugin-CAPYCj_T.d.mts → validation-chain.plugin-Iee2_puD.d.mts}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { B as ObjectId, C as FieldPreset, G as Plugin, J as PopulateSpec, Q as RepositoryContext, _t as ValidationChainOptions, et as RepositoryInstance, it as SelectSpec, j as Logger, l as CascadeOptions, st as SoftDeleteOptions, ut as SortSpec, vt as ValidatorDefinition } from "./types-
|
|
1
|
+
import { B as ObjectId, C as FieldPreset, G as Plugin, J as PopulateSpec, Q as RepositoryContext, _t as ValidationChainOptions, et as RepositoryInstance, it as SelectSpec, j as Logger, l as CascadeOptions, st as SoftDeleteOptions, ut as SortSpec, vt as ValidatorDefinition } from "./types-BWZILovv.mjs";
|
|
2
2
|
import mongoose from "mongoose";
|
|
3
3
|
import { CacheAdapter as CacheAdapter$1, CacheOptions, RepositoryCacheHandle, RepositoryCachePluginOptions, cachePlugin } from "@classytic/repo-core/cache";
|
|
4
4
|
import { BulkWriteResult } from "@classytic/repo-core/repository";
|
|
@@ -6,94 +6,6 @@ import { AsyncLocalStorage } from "node:async_hooks";
|
|
|
6
6
|
import { OffsetPaginationResult } from "@classytic/repo-core/pagination";
|
|
7
7
|
import { TenantConfig } from "@classytic/repo-core/tenant";
|
|
8
8
|
|
|
9
|
-
//#region src/plugins/aggregate-helpers.plugin.d.ts
|
|
10
|
-
/**
|
|
11
|
-
* Aggregate helpers plugin
|
|
12
|
-
*
|
|
13
|
-
* @example
|
|
14
|
-
* const repo = new Repository(Model, [
|
|
15
|
-
* methodRegistryPlugin(),
|
|
16
|
-
* aggregateHelpersPlugin(),
|
|
17
|
-
* ]);
|
|
18
|
-
*
|
|
19
|
-
* const groups = await repo.groupBy('category');
|
|
20
|
-
* const total = await repo.sum('amount', { status: 'completed' });
|
|
21
|
-
*/
|
|
22
|
-
declare function aggregateHelpersPlugin(): Plugin;
|
|
23
|
-
/**
|
|
24
|
-
* Type interface for repositories using aggregateHelpersPlugin
|
|
25
|
-
*
|
|
26
|
-
* @example
|
|
27
|
-
* ```typescript
|
|
28
|
-
* import { Repository, methodRegistryPlugin, aggregateHelpersPlugin } from '@classytic/mongokit';
|
|
29
|
-
* import type { AggregateHelpersMethods } from '@classytic/mongokit';
|
|
30
|
-
*
|
|
31
|
-
* class OrderRepo extends Repository<IOrder> {}
|
|
32
|
-
*
|
|
33
|
-
* type OrderRepoWithAggregates = OrderRepo & AggregateHelpersMethods;
|
|
34
|
-
*
|
|
35
|
-
* const repo = new OrderRepo(OrderModel, [
|
|
36
|
-
* methodRegistryPlugin(),
|
|
37
|
-
* aggregateHelpersPlugin(),
|
|
38
|
-
* ]) as OrderRepoWithAggregates;
|
|
39
|
-
*
|
|
40
|
-
* // TypeScript autocomplete works!
|
|
41
|
-
* const groups = await repo.groupBy('status');
|
|
42
|
-
* const total = await repo.sum('amount', { status: 'completed' });
|
|
43
|
-
* const avg = await repo.average('amount');
|
|
44
|
-
* ```
|
|
45
|
-
*/
|
|
46
|
-
interface AggregateHelpersMethods {
|
|
47
|
-
/**
|
|
48
|
-
* Group documents by field value and count occurrences
|
|
49
|
-
* @param field - Field to group by
|
|
50
|
-
* @param options - Operation options
|
|
51
|
-
* @returns Array of groups with _id and count
|
|
52
|
-
*/
|
|
53
|
-
groupBy(field: string, options?: {
|
|
54
|
-
limit?: number;
|
|
55
|
-
session?: unknown;
|
|
56
|
-
}): Promise<Array<{
|
|
57
|
-
_id: unknown;
|
|
58
|
-
count: number;
|
|
59
|
-
}>>;
|
|
60
|
-
/**
|
|
61
|
-
* Calculate sum of field values
|
|
62
|
-
* @param field - Field to sum
|
|
63
|
-
* @param query - Filter query
|
|
64
|
-
* @param options - Operation options
|
|
65
|
-
* @returns Sum of field values
|
|
66
|
-
*/
|
|
67
|
-
sum(field: string, query?: Record<string, unknown>, options?: Record<string, unknown>): Promise<number>;
|
|
68
|
-
/**
|
|
69
|
-
* Calculate average of field values
|
|
70
|
-
* @param field - Field to average
|
|
71
|
-
* @param query - Filter query
|
|
72
|
-
* @param options - Operation options
|
|
73
|
-
* @returns Average of field values
|
|
74
|
-
*/
|
|
75
|
-
average(field: string, query?: Record<string, unknown>, options?: Record<string, unknown>): Promise<number>;
|
|
76
|
-
/**
|
|
77
|
-
* Get minimum field value
|
|
78
|
-
* @param field - Field to get minimum from
|
|
79
|
-
* @param query - Filter query
|
|
80
|
-
* @param options - Operation options
|
|
81
|
-
* @returns Minimum field value
|
|
82
|
-
*/
|
|
83
|
-
min(field: string, query?: Record<string, unknown>, options?: Record<string, unknown>): Promise<number>;
|
|
84
|
-
/**
|
|
85
|
-
* Get maximum field value
|
|
86
|
-
* @param field - Field to get maximum from
|
|
87
|
-
* @param query - Filter query
|
|
88
|
-
* @param options - Operation options
|
|
89
|
-
* @returns Maximum field value
|
|
90
|
-
*/
|
|
91
|
-
max(field: string, query?: Record<string, unknown>, options?: Record<string, unknown>): Promise<number>;
|
|
92
|
-
}
|
|
93
|
-
//#endregion
|
|
94
|
-
//#region src/plugins/audit-log.plugin.d.ts
|
|
95
|
-
declare function auditLogPlugin(logger: Logger): Plugin;
|
|
96
|
-
//#endregion
|
|
97
9
|
//#region src/plugins/audit-trail.plugin.d.ts
|
|
98
10
|
interface AuditTrailOptions {
|
|
99
11
|
/** Operations to track (default: ['create', 'update', 'delete']) */
|
|
@@ -256,53 +168,6 @@ interface AuditTrailMethods {
|
|
|
256
168
|
}): Promise<AuditQueryResult>;
|
|
257
169
|
}
|
|
258
170
|
//#endregion
|
|
259
|
-
//#region src/plugins/batch-operations.plugin.d.ts
|
|
260
|
-
/**
|
|
261
|
-
* Batch operations plugin.
|
|
262
|
-
*
|
|
263
|
-
* @example
|
|
264
|
-
* const repo = new Repository(Model, [
|
|
265
|
-
* methodRegistryPlugin(),
|
|
266
|
-
* batchOperationsPlugin(),
|
|
267
|
-
* ]);
|
|
268
|
-
*
|
|
269
|
-
* // updateMany + deleteMany are primitives on Repository — no plugin needed.
|
|
270
|
-
* await repo.updateMany({ status: 'pending' }, { status: 'active' });
|
|
271
|
-
* await repo.deleteMany({ status: 'deleted' });
|
|
272
|
-
*
|
|
273
|
-
* // bulkWrite is what this plugin contributes.
|
|
274
|
-
* await repo.bulkWrite([...ops]);
|
|
275
|
-
*/
|
|
276
|
-
declare function batchOperationsPlugin(): Plugin;
|
|
277
|
-
interface BatchOperationsMethods {
|
|
278
|
-
/**
|
|
279
|
-
* Execute heterogeneous bulk write operations in a single database call.
|
|
280
|
-
* Supports insertOne, updateOne, updateMany, deleteOne, deleteMany, replaceOne.
|
|
281
|
-
*
|
|
282
|
-
* @param operations - Array of bulk write operations
|
|
283
|
-
* @param options - Options (session, ordered)
|
|
284
|
-
* @returns Bulk write result with counts per operation type
|
|
285
|
-
*
|
|
286
|
-
* @example
|
|
287
|
-
* const result = await repo.bulkWrite([
|
|
288
|
-
* { insertOne: { document: { name: 'Item', price: 10 } } },
|
|
289
|
-
* { updateOne: { filter: { _id: id }, update: { $inc: { views: 1 } } } },
|
|
290
|
-
* { deleteOne: { filter: { _id: oldId } } },
|
|
291
|
-
* ]);
|
|
292
|
-
* console.log(result.insertedCount, result.modifiedCount, result.deletedCount);
|
|
293
|
-
*/
|
|
294
|
-
bulkWrite(operations: Record<string, unknown>[], options?: {
|
|
295
|
-
session?: unknown;
|
|
296
|
-
ordered?: boolean;
|
|
297
|
-
}): Promise<BulkWriteResult>;
|
|
298
|
-
}
|
|
299
|
-
//#endregion
|
|
300
|
-
//#region src/plugins/cascade.plugin.d.ts
|
|
301
|
-
/**
|
|
302
|
-
* Cascade delete plugin.
|
|
303
|
-
*/
|
|
304
|
-
declare function cascadePlugin(options: CascadeOptions): Plugin;
|
|
305
|
-
//#endregion
|
|
306
171
|
//#region src/plugins/custom-id.plugin.d.ts
|
|
307
172
|
/**
|
|
308
173
|
* Generator function that produces a unique ID.
|
|
@@ -380,87 +245,382 @@ interface DateSequentialIdOptions {
|
|
|
380
245
|
/** Mongoose model — used to derive the counter key */
|
|
381
246
|
model: mongoose.Model<any>;
|
|
382
247
|
/**
|
|
383
|
-
* Partition granularity — counter resets each period.
|
|
384
|
-
* - 'yearly' → BILL-2026-0001, resets every January
|
|
385
|
-
* - 'monthly' → BILL-2026-02-0001, resets every month
|
|
386
|
-
* - 'daily' → BILL-2026-02-20-0001, resets every day
|
|
248
|
+
* Partition granularity — counter resets each period.
|
|
249
|
+
* - 'yearly' → BILL-2026-0001, resets every January
|
|
250
|
+
* - 'monthly' → BILL-2026-02-0001, resets every month
|
|
251
|
+
* - 'daily' → BILL-2026-02-20-0001, resets every day
|
|
252
|
+
*/
|
|
253
|
+
partition?: 'yearly' | 'monthly' | 'daily';
|
|
254
|
+
/** Number of digits to pad to (default: 4) */
|
|
255
|
+
padding?: number;
|
|
256
|
+
/** Separator (default: '-') */
|
|
257
|
+
separator?: string;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Generator: Date-partitioned sequential counter.
|
|
261
|
+
* Counter resets per period — great for invoice/bill numbering.
|
|
262
|
+
*
|
|
263
|
+
* Produces IDs like:
|
|
264
|
+
* - yearly: `BILL-2026-0001`
|
|
265
|
+
* - monthly: `BILL-2026-02-0001`
|
|
266
|
+
* - daily: `BILL-2026-02-20-0001`
|
|
267
|
+
*
|
|
268
|
+
* @example
|
|
269
|
+
* ```typescript
|
|
270
|
+
* customIdPlugin({
|
|
271
|
+
* field: 'billNumber',
|
|
272
|
+
* generator: dateSequentialId({
|
|
273
|
+
* prefix: 'BILL',
|
|
274
|
+
* model: BillModel,
|
|
275
|
+
* partition: 'monthly',
|
|
276
|
+
* }),
|
|
277
|
+
* })
|
|
278
|
+
* ```
|
|
279
|
+
*/
|
|
280
|
+
declare function dateSequentialId(options: DateSequentialIdOptions): IdGenerator;
|
|
281
|
+
interface PrefixedIdOptions {
|
|
282
|
+
/** Prefix string (e.g., 'USR', 'TXN') */
|
|
283
|
+
prefix: string;
|
|
284
|
+
/** Separator (default: '_') */
|
|
285
|
+
separator?: string;
|
|
286
|
+
/** Length of the random suffix (default: 12) */
|
|
287
|
+
length?: number;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Generator: Prefix + random alphanumeric suffix.
|
|
291
|
+
* Does NOT require a database round-trip — purely in-memory.
|
|
292
|
+
*
|
|
293
|
+
* Produces IDs like: `USR_a7b3xk9m2p1q`
|
|
294
|
+
*
|
|
295
|
+
* Good for: user-facing IDs where ordering doesn't matter.
|
|
296
|
+
* Not suitable for sequential numbering.
|
|
297
|
+
*
|
|
298
|
+
* @example
|
|
299
|
+
* ```typescript
|
|
300
|
+
* customIdPlugin({
|
|
301
|
+
* field: 'publicId',
|
|
302
|
+
* generator: prefixedId({ prefix: 'USR', length: 10 }),
|
|
303
|
+
* })
|
|
304
|
+
* ```
|
|
305
|
+
*/
|
|
306
|
+
declare function prefixedId(options: PrefixedIdOptions): IdGenerator;
|
|
307
|
+
/**
|
|
308
|
+
* Custom ID plugin — injects generated IDs into documents before creation.
|
|
309
|
+
*
|
|
310
|
+
* @param options - Configuration for ID generation
|
|
311
|
+
* @returns Plugin instance
|
|
312
|
+
*
|
|
313
|
+
* @example
|
|
314
|
+
* ```typescript
|
|
315
|
+
* import { Repository, customIdPlugin, sequentialId } from '@classytic/mongokit';
|
|
316
|
+
*
|
|
317
|
+
* const invoiceRepo = new Repository(InvoiceModel, [
|
|
318
|
+
* customIdPlugin({
|
|
319
|
+
* field: 'invoiceNumber',
|
|
320
|
+
* generator: sequentialId({ prefix: 'INV', model: InvoiceModel }),
|
|
321
|
+
* }),
|
|
322
|
+
* ]);
|
|
323
|
+
*
|
|
324
|
+
* const inv = await invoiceRepo.create({ amount: 100 });
|
|
325
|
+
* console.log(inv.invoiceNumber); // "INV-0001"
|
|
326
|
+
* ```
|
|
327
|
+
*/
|
|
328
|
+
declare function customIdPlugin(options: CustomIdOptions): Plugin;
|
|
329
|
+
//#endregion
|
|
330
|
+
//#region src/plugins/multi-tenant.plugin.d.ts
|
|
331
|
+
/**
|
|
332
|
+
* Static tenant fields are picked from `@classytic/repo-core/tenant` so the
|
|
333
|
+
* vocabulary (`tenantField`, `contextKey`, `required`, `fieldType`) stays
|
|
334
|
+
* locked to the org-wide canonical source. Mongokit-specific runtime
|
|
335
|
+
* callbacks (`skipWhen`, `resolveContext`, `skipOperations`,
|
|
336
|
+
* `allowDataInjection`) extend on top — those genuinely differ from
|
|
337
|
+
* sqlitekit's runtime shape because mongokit's `RepositoryContext` carries
|
|
338
|
+
* Mongoose-specific bits the resolver may inspect.
|
|
339
|
+
*
|
|
340
|
+
* Mongokit defaults `fieldType` to `'string'` (not repo-core's `'objectId'`)
|
|
341
|
+
* for back-compat — pre-3.x stored tenant ids as raw strings; flipping the
|
|
342
|
+
* default would silently change cast behavior for existing apps.
|
|
343
|
+
*/
|
|
344
|
+
interface MultiTenantOptions extends Pick<TenantConfig, 'tenantField' | 'contextKey' | 'required' | 'fieldType'> {
|
|
345
|
+
/** Operations to skip tenant injection (e.g., for admin/system queries) */
|
|
346
|
+
skipOperations?: string[];
|
|
347
|
+
/**
|
|
348
|
+
* Dynamic skip — receives the context and operation name, returns true to
|
|
349
|
+
* bypass tenant scoping for this call. Use for role-based bypass (e.g.,
|
|
350
|
+
* super admin) without needing a separate repo instance.
|
|
351
|
+
*
|
|
352
|
+
* @example
|
|
353
|
+
* ```typescript
|
|
354
|
+
* skipWhen: (context) => context.role === 'superadmin'
|
|
355
|
+
* ```
|
|
356
|
+
*/
|
|
357
|
+
skipWhen?: (context: RepositoryContext, operation: string) => boolean;
|
|
358
|
+
/**
|
|
359
|
+
* Resolve tenant ID from external source (e.g., AsyncLocalStorage, CLS).
|
|
360
|
+
* Called when tenant ID is not found in context. If it returns a value,
|
|
361
|
+
* that value is used as the tenant ID without requiring it in context.
|
|
362
|
+
*
|
|
363
|
+
* @example
|
|
364
|
+
* ```typescript
|
|
365
|
+
* resolveContext: () => asyncLocalStorage.getStore()?.tenantId
|
|
366
|
+
* ```
|
|
367
|
+
*/
|
|
368
|
+
resolveContext?: () => string | undefined;
|
|
369
|
+
/**
|
|
370
|
+
* When `true`, bypass the `required` throw if the operation's policy
|
|
371
|
+
* target already carries the tenant field. This lets hosts that stamp
|
|
372
|
+
* the tenant into the payload themselves (e.g., `data[tenantField]`
|
|
373
|
+
* on writes, `filters[tenantField]` on paginated reads) use the plugin
|
|
374
|
+
* without having to hand-roll a `skipWhen` that duplicates this check.
|
|
375
|
+
*
|
|
376
|
+
* **Default: `false` (secure / fail-closed).** Tenant scope MUST come
|
|
377
|
+
* from `context` or `resolveContext`, otherwise the plugin throws
|
|
378
|
+
* (when `required: true`). This is the right posture for a security-
|
|
379
|
+
* sensitive boundary: caller-supplied scope on the payload cannot be
|
|
380
|
+
* trusted as authentication. If a host control-plane has already
|
|
381
|
+
* authenticated the tenant out-of-band and stamps it onto every
|
|
382
|
+
* write/read, set this to `true` explicitly — making the trust model
|
|
383
|
+
* visible at the call site.
|
|
384
|
+
*
|
|
385
|
+
* **Migration from < 4.0:** the prior default was `true`. To preserve
|
|
386
|
+
* the old behavior verbatim, set `allowDataInjection: true`. To get
|
|
387
|
+
* the new secure default, leave it unset.
|
|
388
|
+
*
|
|
389
|
+
* Composition: a user-supplied `skipWhen` still runs first and can
|
|
390
|
+
* always opt out. This option controls the behavior after `skipWhen`
|
|
391
|
+
* and `resolveContext` have had their turn.
|
|
392
|
+
*
|
|
393
|
+
* Safety: when the payload supplies the tenant AND this is `true`,
|
|
394
|
+
* the plugin skips its own injection (it does not overwrite). Cross-
|
|
395
|
+
* tenant isolation is therefore only as strong as the caller's own
|
|
396
|
+
* stamping — same guarantee as a hand-rolled `skipWhen`.
|
|
397
|
+
*/
|
|
398
|
+
allowDataInjection?: boolean;
|
|
399
|
+
/**
|
|
400
|
+
* What to do when the call's filter/payload ALREADY carries
|
|
401
|
+
* `tenantField` with a value that does NOT match the resolved tenant
|
|
402
|
+
* scope (a caller-supplied cross-tenant value — fat-fingered org id,
|
|
403
|
+
* stale client state, or an injection attempt).
|
|
404
|
+
*
|
|
405
|
+
* - `'throw'` (default, fail-closed): reject the call with a clear
|
|
406
|
+
* error. A mismatch is never legitimate on a scoped call — callers
|
|
407
|
+
* who genuinely need cross-tenant access use `bypassTenant: true`
|
|
408
|
+
* (per-call) or `skipWhen` (plugin-level), both of which emit the
|
|
409
|
+
* `after:tenant-bypass` audit event. Operator-shaped values
|
|
410
|
+
* (`{ $in: [...] }`) on the tenant field can't be verified against
|
|
411
|
+
* the scope and are rejected too — multi-value tenant scoping is
|
|
412
|
+
* deliberately not supported (see CLAUDE.md); use an explicit
|
|
413
|
+
* bypass + manual filter.
|
|
414
|
+
* - `'overwrite'` (legacy, pre-3.16 behavior): silently replace the
|
|
415
|
+
* supplied value with the resolved scope. Still leak-safe (the
|
|
416
|
+
* resolved scope always wins) but hides caller bugs.
|
|
417
|
+
*
|
|
418
|
+
* Matching values (same tenant, any representation — string vs
|
|
419
|
+
* ObjectId) are never a mismatch; the plugin normalizes them to the
|
|
420
|
+
* configured `fieldType`.
|
|
421
|
+
*/
|
|
422
|
+
onMismatch?: 'throw' | 'overwrite';
|
|
423
|
+
}
|
|
424
|
+
declare function multiTenantPlugin(options?: MultiTenantOptions): Plugin;
|
|
425
|
+
/**
|
|
426
|
+
* Build the canonical `skipWhen` callback for role-based tenant
|
|
427
|
+
* bypass — replaces the hand-rolled
|
|
428
|
+
* `(ctx) => ctx.role === 'superadmin'` callback that ~6 packages
|
|
429
|
+
* across the classytic codebase carry as boilerplate. Eliminates the
|
|
430
|
+
* "I forgot to include 'platform_admin'" drift class — the role
|
|
431
|
+
* vocabulary lives in one place.
|
|
432
|
+
*
|
|
433
|
+
* **Composes with `bypassTenant: true` per-call**, doesn't replace
|
|
434
|
+
* it. `bypassTenant` is the deliberate per-call form for migration
|
|
435
|
+
* scripts and one-off admin queries; `adminBypass` is the
|
|
436
|
+
* always-on role-based bypass for users whose JWT / session carries
|
|
437
|
+
* a privileged role.
|
|
438
|
+
*
|
|
439
|
+
* **NOT a substitute for authentication or RBAC.** This factory only
|
|
440
|
+
* answers "should the tenant scope hook fire for this call?" — it
|
|
441
|
+
* does NOT validate that the caller is authenticated, that their
|
|
442
|
+
* role claim is genuine, or that the requested operation is
|
|
443
|
+
* permitted. Always run auth + RBAC before the call reaches the
|
|
444
|
+
* repository layer; this is the LAST gate, not the only one.
|
|
445
|
+
*
|
|
446
|
+
* @example Single role
|
|
447
|
+
* ```ts
|
|
448
|
+
* import { adminBypass, multiTenantPlugin } from '@classytic/mongokit';
|
|
449
|
+
*
|
|
450
|
+
* const repo = new Repository(InvoiceModel, [
|
|
451
|
+
* multiTenantPlugin({
|
|
452
|
+
* tenantField: 'organizationId',
|
|
453
|
+
* skipWhen: adminBypass({ adminRoles: ['superadmin'] }),
|
|
454
|
+
* }),
|
|
455
|
+
* ]);
|
|
456
|
+
*
|
|
457
|
+
* await repo.getAll({}, { role: 'superadmin' }); // sees all orgs
|
|
458
|
+
* await repo.getAll({}, { role: 'user', organizationId: 'org-1' }); // scoped
|
|
459
|
+
* ```
|
|
460
|
+
*
|
|
461
|
+
* @example Multiple admin roles + custom field name
|
|
462
|
+
* ```ts
|
|
463
|
+
* skipWhen: adminBypass({
|
|
464
|
+
* roleField: 'principalRole', // ctx.principalRole, not ctx.role
|
|
465
|
+
* adminRoles: ['superadmin', 'platform_admin', 'support'],
|
|
466
|
+
* }),
|
|
467
|
+
* ```
|
|
468
|
+
*
|
|
469
|
+
* @example Composing with custom logic
|
|
470
|
+
* ```ts
|
|
471
|
+
* // adminBypass for the role check, then your own additional logic:
|
|
472
|
+
* const adminCheck = adminBypass({ adminRoles: ['superadmin'] });
|
|
473
|
+
* skipWhen: (ctx, op) => adminCheck(ctx, op) || ctx.internalSystemFlag === true,
|
|
474
|
+
* ```
|
|
475
|
+
*
|
|
476
|
+
* @param options.roleField - Path on the context to read the role
|
|
477
|
+
* from. Defaults to `'role'`. Top-level keys only — for nested
|
|
478
|
+
* shapes (e.g. `ctx.user.role`), wrap your own `(ctx) => …` callback
|
|
479
|
+
* instead.
|
|
480
|
+
* @param options.adminRoles - Role values that grant the bypass. The
|
|
481
|
+
* factory does an exact-match `includes` check — case-sensitive,
|
|
482
|
+
* no fuzzy matching. Lowercase your role vocabulary upstream.
|
|
483
|
+
* @returns A `skipWhen`-compatible callback `(ctx, op) → boolean`.
|
|
484
|
+
*/
|
|
485
|
+
declare function adminBypass(options: {
|
|
486
|
+
roleField?: string;
|
|
487
|
+
adminRoles: readonly string[];
|
|
488
|
+
}): (context: RepositoryContext, operation: string) => boolean;
|
|
489
|
+
//#endregion
|
|
490
|
+
//#region src/plugins/aggregate-helpers.plugin.d.ts
|
|
491
|
+
/**
|
|
492
|
+
* Aggregate helpers plugin
|
|
493
|
+
*
|
|
494
|
+
* @example
|
|
495
|
+
* const repo = new Repository(Model, [
|
|
496
|
+
* methodRegistryPlugin(),
|
|
497
|
+
* aggregateHelpersPlugin(),
|
|
498
|
+
* ]);
|
|
499
|
+
*
|
|
500
|
+
* const groups = await repo.groupBy('category');
|
|
501
|
+
* const total = await repo.sum('amount', { status: 'completed' });
|
|
502
|
+
*/
|
|
503
|
+
declare function aggregateHelpersPlugin(): Plugin;
|
|
504
|
+
/**
|
|
505
|
+
* Type interface for repositories using aggregateHelpersPlugin
|
|
506
|
+
*
|
|
507
|
+
* @example
|
|
508
|
+
* ```typescript
|
|
509
|
+
* import { Repository, methodRegistryPlugin, aggregateHelpersPlugin } from '@classytic/mongokit';
|
|
510
|
+
* import type { AggregateHelpersMethods } from '@classytic/mongokit';
|
|
511
|
+
*
|
|
512
|
+
* class OrderRepo extends Repository<IOrder> {}
|
|
513
|
+
*
|
|
514
|
+
* type OrderRepoWithAggregates = OrderRepo & AggregateHelpersMethods;
|
|
515
|
+
*
|
|
516
|
+
* const repo = new OrderRepo(OrderModel, [
|
|
517
|
+
* methodRegistryPlugin(),
|
|
518
|
+
* aggregateHelpersPlugin(),
|
|
519
|
+
* ]) as OrderRepoWithAggregates;
|
|
520
|
+
*
|
|
521
|
+
* // TypeScript autocomplete works!
|
|
522
|
+
* const groups = await repo.groupBy('status');
|
|
523
|
+
* const total = await repo.sum('amount', { status: 'completed' });
|
|
524
|
+
* const avg = await repo.average('amount');
|
|
525
|
+
* ```
|
|
526
|
+
*/
|
|
527
|
+
interface AggregateHelpersMethods {
|
|
528
|
+
/**
|
|
529
|
+
* Group documents by field value and count occurrences
|
|
530
|
+
* @param field - Field to group by
|
|
531
|
+
* @param options - Operation options
|
|
532
|
+
* @returns Array of groups with _id and count
|
|
533
|
+
*/
|
|
534
|
+
groupBy(field: string, options?: {
|
|
535
|
+
limit?: number;
|
|
536
|
+
session?: unknown;
|
|
537
|
+
}): Promise<Array<{
|
|
538
|
+
_id: unknown;
|
|
539
|
+
count: number;
|
|
540
|
+
}>>;
|
|
541
|
+
/**
|
|
542
|
+
* Calculate sum of field values
|
|
543
|
+
* @param field - Field to sum
|
|
544
|
+
* @param query - Filter query
|
|
545
|
+
* @param options - Operation options
|
|
546
|
+
* @returns Sum of field values
|
|
547
|
+
*/
|
|
548
|
+
sum(field: string, query?: Record<string, unknown>, options?: Record<string, unknown>): Promise<number>;
|
|
549
|
+
/**
|
|
550
|
+
* Calculate average of field values
|
|
551
|
+
* @param field - Field to average
|
|
552
|
+
* @param query - Filter query
|
|
553
|
+
* @param options - Operation options
|
|
554
|
+
* @returns Average of field values
|
|
555
|
+
*/
|
|
556
|
+
average(field: string, query?: Record<string, unknown>, options?: Record<string, unknown>): Promise<number>;
|
|
557
|
+
/**
|
|
558
|
+
* Get minimum field value
|
|
559
|
+
* @param field - Field to get minimum from
|
|
560
|
+
* @param query - Filter query
|
|
561
|
+
* @param options - Operation options
|
|
562
|
+
* @returns Minimum field value
|
|
563
|
+
*/
|
|
564
|
+
min(field: string, query?: Record<string, unknown>, options?: Record<string, unknown>): Promise<number>;
|
|
565
|
+
/**
|
|
566
|
+
* Get maximum field value
|
|
567
|
+
* @param field - Field to get maximum from
|
|
568
|
+
* @param query - Filter query
|
|
569
|
+
* @param options - Operation options
|
|
570
|
+
* @returns Maximum field value
|
|
387
571
|
*/
|
|
388
|
-
|
|
389
|
-
/** Number of digits to pad to (default: 4) */
|
|
390
|
-
padding?: number;
|
|
391
|
-
/** Separator (default: '-') */
|
|
392
|
-
separator?: string;
|
|
572
|
+
max(field: string, query?: Record<string, unknown>, options?: Record<string, unknown>): Promise<number>;
|
|
393
573
|
}
|
|
574
|
+
//#endregion
|
|
575
|
+
//#region src/plugins/audit-log.plugin.d.ts
|
|
576
|
+
declare function auditLogPlugin(logger: Logger): Plugin;
|
|
577
|
+
//#endregion
|
|
578
|
+
//#region src/plugins/batch-operations.plugin.d.ts
|
|
394
579
|
/**
|
|
395
|
-
*
|
|
396
|
-
* Counter resets per period — great for invoice/bill numbering.
|
|
397
|
-
*
|
|
398
|
-
* Produces IDs like:
|
|
399
|
-
* - yearly: `BILL-2026-0001`
|
|
400
|
-
* - monthly: `BILL-2026-02-0001`
|
|
401
|
-
* - daily: `BILL-2026-02-20-0001`
|
|
580
|
+
* Batch operations plugin.
|
|
402
581
|
*
|
|
403
582
|
* @example
|
|
404
|
-
*
|
|
405
|
-
*
|
|
406
|
-
*
|
|
407
|
-
*
|
|
408
|
-
* prefix: 'BILL',
|
|
409
|
-
* model: BillModel,
|
|
410
|
-
* partition: 'monthly',
|
|
411
|
-
* }),
|
|
412
|
-
* })
|
|
413
|
-
* ```
|
|
414
|
-
*/
|
|
415
|
-
declare function dateSequentialId(options: DateSequentialIdOptions): IdGenerator;
|
|
416
|
-
interface PrefixedIdOptions {
|
|
417
|
-
/** Prefix string (e.g., 'USR', 'TXN') */
|
|
418
|
-
prefix: string;
|
|
419
|
-
/** Separator (default: '_') */
|
|
420
|
-
separator?: string;
|
|
421
|
-
/** Length of the random suffix (default: 12) */
|
|
422
|
-
length?: number;
|
|
423
|
-
}
|
|
424
|
-
/**
|
|
425
|
-
* Generator: Prefix + random alphanumeric suffix.
|
|
426
|
-
* Does NOT require a database round-trip — purely in-memory.
|
|
427
|
-
*
|
|
428
|
-
* Produces IDs like: `USR_a7b3xk9m2p1q`
|
|
583
|
+
* const repo = new Repository(Model, [
|
|
584
|
+
* methodRegistryPlugin(),
|
|
585
|
+
* batchOperationsPlugin(),
|
|
586
|
+
* ]);
|
|
429
587
|
*
|
|
430
|
-
*
|
|
431
|
-
*
|
|
588
|
+
* // updateMany + deleteMany are primitives on Repository — no plugin needed.
|
|
589
|
+
* await repo.updateMany({ status: 'pending' }, { status: 'active' });
|
|
590
|
+
* await repo.deleteMany({ status: 'deleted' });
|
|
432
591
|
*
|
|
433
|
-
*
|
|
434
|
-
*
|
|
435
|
-
* customIdPlugin({
|
|
436
|
-
* field: 'publicId',
|
|
437
|
-
* generator: prefixedId({ prefix: 'USR', length: 10 }),
|
|
438
|
-
* })
|
|
439
|
-
* ```
|
|
592
|
+
* // bulkWrite is what this plugin contributes.
|
|
593
|
+
* await repo.bulkWrite([...ops]);
|
|
440
594
|
*/
|
|
441
|
-
declare function
|
|
595
|
+
declare function batchOperationsPlugin(): Plugin;
|
|
596
|
+
interface BatchOperationsMethods {
|
|
597
|
+
/**
|
|
598
|
+
* Execute heterogeneous bulk write operations in a single database call.
|
|
599
|
+
* Supports insertOne, updateOne, updateMany, deleteOne, deleteMany, replaceOne.
|
|
600
|
+
*
|
|
601
|
+
* @param operations - Array of bulk write operations
|
|
602
|
+
* @param options - Options (session, ordered)
|
|
603
|
+
* @returns Bulk write result with counts per operation type
|
|
604
|
+
*
|
|
605
|
+
* @example
|
|
606
|
+
* const result = await repo.bulkWrite([
|
|
607
|
+
* { insertOne: { document: { name: 'Item', price: 10 } } },
|
|
608
|
+
* { updateOne: { filter: { _id: id }, update: { $inc: { views: 1 } } } },
|
|
609
|
+
* { deleteOne: { filter: { _id: oldId } } },
|
|
610
|
+
* ]);
|
|
611
|
+
* console.log(result.insertedCount, result.modifiedCount, result.deletedCount);
|
|
612
|
+
*/
|
|
613
|
+
bulkWrite(operations: Record<string, unknown>[], options?: {
|
|
614
|
+
session?: unknown;
|
|
615
|
+
ordered?: boolean;
|
|
616
|
+
}): Promise<BulkWriteResult>;
|
|
617
|
+
}
|
|
618
|
+
//#endregion
|
|
619
|
+
//#region src/plugins/cascade.plugin.d.ts
|
|
442
620
|
/**
|
|
443
|
-
*
|
|
444
|
-
*
|
|
445
|
-
* @param options - Configuration for ID generation
|
|
446
|
-
* @returns Plugin instance
|
|
447
|
-
*
|
|
448
|
-
* @example
|
|
449
|
-
* ```typescript
|
|
450
|
-
* import { Repository, customIdPlugin, sequentialId } from '@classytic/mongokit';
|
|
451
|
-
*
|
|
452
|
-
* const invoiceRepo = new Repository(InvoiceModel, [
|
|
453
|
-
* customIdPlugin({
|
|
454
|
-
* field: 'invoiceNumber',
|
|
455
|
-
* generator: sequentialId({ prefix: 'INV', model: InvoiceModel }),
|
|
456
|
-
* }),
|
|
457
|
-
* ]);
|
|
458
|
-
*
|
|
459
|
-
* const inv = await invoiceRepo.create({ amount: 100 });
|
|
460
|
-
* console.log(inv.invoiceNumber); // "INV-0001"
|
|
461
|
-
* ```
|
|
621
|
+
* Cascade delete plugin.
|
|
462
622
|
*/
|
|
463
|
-
declare function
|
|
623
|
+
declare function cascadePlugin(options: CascadeOptions): Plugin;
|
|
464
624
|
//#endregion
|
|
465
625
|
//#region src/plugins/elastic.plugin.d.ts
|
|
466
626
|
interface ElasticSearchOptions {
|
|
@@ -813,142 +973,6 @@ interface MongoOperationsMethods<TDoc> {
|
|
|
813
973
|
incrementIfBelow(id: string | ObjectId, field: string, ceiling: number, by?: number, options?: Record<string, unknown>): Promise<TDoc | null>;
|
|
814
974
|
}
|
|
815
975
|
//#endregion
|
|
816
|
-
//#region src/plugins/multi-tenant.plugin.d.ts
|
|
817
|
-
/**
|
|
818
|
-
* Static tenant fields are picked from `@classytic/repo-core/tenant` so the
|
|
819
|
-
* vocabulary (`tenantField`, `contextKey`, `required`, `fieldType`) stays
|
|
820
|
-
* locked to the org-wide canonical source. Mongokit-specific runtime
|
|
821
|
-
* callbacks (`skipWhen`, `resolveContext`, `skipOperations`,
|
|
822
|
-
* `allowDataInjection`) extend on top — those genuinely differ from
|
|
823
|
-
* sqlitekit's runtime shape because mongokit's `RepositoryContext` carries
|
|
824
|
-
* Mongoose-specific bits the resolver may inspect.
|
|
825
|
-
*
|
|
826
|
-
* Mongokit defaults `fieldType` to `'string'` (not repo-core's `'objectId'`)
|
|
827
|
-
* for back-compat — pre-3.x stored tenant ids as raw strings; flipping the
|
|
828
|
-
* default would silently change cast behavior for existing apps.
|
|
829
|
-
*/
|
|
830
|
-
interface MultiTenantOptions extends Pick<TenantConfig, 'tenantField' | 'contextKey' | 'required' | 'fieldType'> {
|
|
831
|
-
/** Operations to skip tenant injection (e.g., for admin/system queries) */
|
|
832
|
-
skipOperations?: string[];
|
|
833
|
-
/**
|
|
834
|
-
* Dynamic skip — receives the context and operation name, returns true to
|
|
835
|
-
* bypass tenant scoping for this call. Use for role-based bypass (e.g.,
|
|
836
|
-
* super admin) without needing a separate repo instance.
|
|
837
|
-
*
|
|
838
|
-
* @example
|
|
839
|
-
* ```typescript
|
|
840
|
-
* skipWhen: (context) => context.role === 'superadmin'
|
|
841
|
-
* ```
|
|
842
|
-
*/
|
|
843
|
-
skipWhen?: (context: RepositoryContext, operation: string) => boolean;
|
|
844
|
-
/**
|
|
845
|
-
* Resolve tenant ID from external source (e.g., AsyncLocalStorage, CLS).
|
|
846
|
-
* Called when tenant ID is not found in context. If it returns a value,
|
|
847
|
-
* that value is used as the tenant ID without requiring it in context.
|
|
848
|
-
*
|
|
849
|
-
* @example
|
|
850
|
-
* ```typescript
|
|
851
|
-
* resolveContext: () => asyncLocalStorage.getStore()?.tenantId
|
|
852
|
-
* ```
|
|
853
|
-
*/
|
|
854
|
-
resolveContext?: () => string | undefined;
|
|
855
|
-
/**
|
|
856
|
-
* When `true`, bypass the `required` throw if the operation's policy
|
|
857
|
-
* target already carries the tenant field. This lets hosts that stamp
|
|
858
|
-
* the tenant into the payload themselves (e.g., `data[tenantField]`
|
|
859
|
-
* on writes, `filters[tenantField]` on paginated reads) use the plugin
|
|
860
|
-
* without having to hand-roll a `skipWhen` that duplicates this check.
|
|
861
|
-
*
|
|
862
|
-
* **Default: `false` (secure / fail-closed).** Tenant scope MUST come
|
|
863
|
-
* from `context` or `resolveContext`, otherwise the plugin throws
|
|
864
|
-
* (when `required: true`). This is the right posture for a security-
|
|
865
|
-
* sensitive boundary: caller-supplied scope on the payload cannot be
|
|
866
|
-
* trusted as authentication. If a host control-plane has already
|
|
867
|
-
* authenticated the tenant out-of-band and stamps it onto every
|
|
868
|
-
* write/read, set this to `true` explicitly — making the trust model
|
|
869
|
-
* visible at the call site.
|
|
870
|
-
*
|
|
871
|
-
* **Migration from < 4.0:** the prior default was `true`. To preserve
|
|
872
|
-
* the old behavior verbatim, set `allowDataInjection: true`. To get
|
|
873
|
-
* the new secure default, leave it unset.
|
|
874
|
-
*
|
|
875
|
-
* Composition: a user-supplied `skipWhen` still runs first and can
|
|
876
|
-
* always opt out. This option controls the behavior after `skipWhen`
|
|
877
|
-
* and `resolveContext` have had their turn.
|
|
878
|
-
*
|
|
879
|
-
* Safety: when the payload supplies the tenant AND this is `true`,
|
|
880
|
-
* the plugin skips its own injection (it does not overwrite). Cross-
|
|
881
|
-
* tenant isolation is therefore only as strong as the caller's own
|
|
882
|
-
* stamping — same guarantee as a hand-rolled `skipWhen`.
|
|
883
|
-
*/
|
|
884
|
-
allowDataInjection?: boolean;
|
|
885
|
-
}
|
|
886
|
-
declare function multiTenantPlugin(options?: MultiTenantOptions): Plugin;
|
|
887
|
-
/**
|
|
888
|
-
* Build the canonical `skipWhen` callback for role-based tenant
|
|
889
|
-
* bypass — replaces the hand-rolled
|
|
890
|
-
* `(ctx) => ctx.role === 'superadmin'` callback that ~6 packages
|
|
891
|
-
* across the classytic codebase carry as boilerplate. Eliminates the
|
|
892
|
-
* "I forgot to include 'platform_admin'" drift class — the role
|
|
893
|
-
* vocabulary lives in one place.
|
|
894
|
-
*
|
|
895
|
-
* **Composes with `bypassTenant: true` per-call**, doesn't replace
|
|
896
|
-
* it. `bypassTenant` is the deliberate per-call form for migration
|
|
897
|
-
* scripts and one-off admin queries; `adminBypass` is the
|
|
898
|
-
* always-on role-based bypass for users whose JWT / session carries
|
|
899
|
-
* a privileged role.
|
|
900
|
-
*
|
|
901
|
-
* **NOT a substitute for authentication or RBAC.** This factory only
|
|
902
|
-
* answers "should the tenant scope hook fire for this call?" — it
|
|
903
|
-
* does NOT validate that the caller is authenticated, that their
|
|
904
|
-
* role claim is genuine, or that the requested operation is
|
|
905
|
-
* permitted. Always run auth + RBAC before the call reaches the
|
|
906
|
-
* repository layer; this is the LAST gate, not the only one.
|
|
907
|
-
*
|
|
908
|
-
* @example Single role
|
|
909
|
-
* ```ts
|
|
910
|
-
* import { adminBypass, multiTenantPlugin } from '@classytic/mongokit';
|
|
911
|
-
*
|
|
912
|
-
* const repo = new Repository(InvoiceModel, [
|
|
913
|
-
* multiTenantPlugin({
|
|
914
|
-
* tenantField: 'organizationId',
|
|
915
|
-
* skipWhen: adminBypass({ adminRoles: ['superadmin'] }),
|
|
916
|
-
* }),
|
|
917
|
-
* ]);
|
|
918
|
-
*
|
|
919
|
-
* await repo.getAll({}, { role: 'superadmin' }); // sees all orgs
|
|
920
|
-
* await repo.getAll({}, { role: 'user', organizationId: 'org-1' }); // scoped
|
|
921
|
-
* ```
|
|
922
|
-
*
|
|
923
|
-
* @example Multiple admin roles + custom field name
|
|
924
|
-
* ```ts
|
|
925
|
-
* skipWhen: adminBypass({
|
|
926
|
-
* roleField: 'principalRole', // ctx.principalRole, not ctx.role
|
|
927
|
-
* adminRoles: ['superadmin', 'platform_admin', 'support'],
|
|
928
|
-
* }),
|
|
929
|
-
* ```
|
|
930
|
-
*
|
|
931
|
-
* @example Composing with custom logic
|
|
932
|
-
* ```ts
|
|
933
|
-
* // adminBypass for the role check, then your own additional logic:
|
|
934
|
-
* const adminCheck = adminBypass({ adminRoles: ['superadmin'] });
|
|
935
|
-
* skipWhen: (ctx, op) => adminCheck(ctx, op) || ctx.internalSystemFlag === true,
|
|
936
|
-
* ```
|
|
937
|
-
*
|
|
938
|
-
* @param options.roleField - Path on the context to read the role
|
|
939
|
-
* from. Defaults to `'role'`. Top-level keys only — for nested
|
|
940
|
-
* shapes (e.g. `ctx.user.role`), wrap your own `(ctx) => …` callback
|
|
941
|
-
* instead.
|
|
942
|
-
* @param options.adminRoles - Role values that grant the bypass. The
|
|
943
|
-
* factory does an exact-match `includes` check — case-sensitive,
|
|
944
|
-
* no fuzzy matching. Lowercase your role vocabulary upstream.
|
|
945
|
-
* @returns A `skipWhen`-compatible callback `(ctx, op) → boolean`.
|
|
946
|
-
*/
|
|
947
|
-
declare function adminBypass(options: {
|
|
948
|
-
roleField?: string;
|
|
949
|
-
adminRoles: readonly string[];
|
|
950
|
-
}): (context: RepositoryContext, operation: string) => boolean;
|
|
951
|
-
//#endregion
|
|
952
976
|
//#region src/plugins/observability.plugin.d.ts
|
|
953
977
|
interface OperationMetric {
|
|
954
978
|
/** Operation name (e.g., 'create', 'getAll', 'update') */
|
|
@@ -1220,4 +1244,4 @@ declare function immutableField(field: string): ValidatorDefinition;
|
|
|
1220
1244
|
*/
|
|
1221
1245
|
declare function uniqueField(field: string, errorMessage?: string): ValidatorDefinition;
|
|
1222
1246
|
//#endregion
|
|
1223
|
-
export {
|
|
1247
|
+
export { AuditEntry as $, BulkWriteResult as A, IdGenerator as B, LeasePluginOptions as C, elasticSearchPlugin as D, ElasticSearchOptions as E, MultiTenantOptions as F, getNextSequence as G, SequentialIdOptions as H, adminBypass as I, CacheAdapter$1 as J, prefixedId as K, multiTenantPlugin as L, auditLogPlugin as M, AggregateHelpersMethods as N, cascadePlugin as O, aggregateHelpersPlugin as P, cachePlugin as Q, CustomIdOptions as R, LeaseMethods as S, fieldFilterPlugin as T, customIdPlugin as U, PrefixedIdOptions as V, dateSequentialId as W, RepositoryCacheHandle as X, CacheOptions as Y, RepositoryCachePluginOptions as Z, observabilityPlugin as _, uniqueField as a, AuditTrailQuery as at, MethodRegistryRepository as b, TenantContext as c, SubdocumentMethods as d, AuditOperation as et, subdocumentPlugin as f, OperationMetric as g, ObservabilityOptions as h, requireField as i, AuditTrailOptions as it, batchOperationsPlugin as j, BatchOperationsMethods as k, TenantStore as l, softDeletePlugin as m, blockIf as n, AuditQueryResult as nt, validationChainPlugin as o, auditTrailPlugin as ot, SoftDeleteMethods as p, sequentialId as q, immutableField as r, AuditTrailMethods as rt, timestampPlugin as s, autoInject as t, AuditQueryOptions as tt, createTenantContext as u, MongoOperationsMethods as v, leasePlugin as w, methodRegistryPlugin as x, mongoOperationsPlugin as y, DateSequentialIdOptions as z };
|