@classytic/mongokit 3.18.0 → 3.19.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 (32) hide show
  1. package/README.md +66 -0
  2. package/dist/PaginationEngine-4SjzfBQE.d.mts +103 -0
  3. package/dist/actions/index.d.mts +1 -1
  4. package/dist/adapter/index.mjs +1 -1
  5. package/dist/ai/index.d.mts +1 -1
  6. package/dist/better-auth/index.mjs +1 -1
  7. package/dist/create-repository-D5YX0wGs.mjs +29 -0
  8. package/dist/create-repository-K0yft2ht.d.mts +1663 -0
  9. package/dist/{index-fi91ycQc.d.mts → index-BgSBwlWu.d.mts} +1 -1
  10. package/dist/index.d.mts +11 -1665
  11. package/dist/index.mjs +5 -29
  12. package/dist/{mongooseToJsonSchema-BdQJU39w.d.mts → mongooseToJsonSchema-Bz47aMfH.d.mts} +1 -1
  13. package/dist/multi-tenant.plugin-D6lw3BsI.d.mts +487 -0
  14. package/dist/pagination/PaginationEngine.d.mts +1 -102
  15. package/dist/plugins/index.d.mts +3 -2
  16. package/dist/plugins/index.mjs +2 -1
  17. package/dist/query/primitives/coercion.d.mts +1 -1
  18. package/dist/query/primitives/indexes.d.mts +1 -1
  19. package/dist/testkit/index.d.mts +129 -0
  20. package/dist/testkit/index.mjs +139 -0
  21. package/dist/{validation-chain.plugin-DJtC0KJ-.mjs → timestamp.plugin-B1A9U-P7.mjs} +1 -1052
  22. package/dist/utils/index.d.mts +1 -1
  23. package/dist/utils/index.mjs +2 -2
  24. package/dist/{validation-chain.plugin-BpMfy18N.d.mts → validation-chain.plugin-CYOPfFGF.d.mts} +2 -486
  25. package/dist/validation-chain.plugin-DHZbpb4t.mjs +1056 -0
  26. package/package.json +9 -1
  27. /package/dist/{adapter-DYEMkLwK.mjs → adapter-BSxhT0Ip.mjs} +0 -0
  28. /package/dist/{coercion-TRMmR49h.d.mts → coercion-BxxHyLjP.d.mts} +0 -0
  29. /package/dist/{field-selection-CQW3WBiK.mjs → field-selection-d1qdRiMr.mjs} +0 -0
  30. /package/dist/{indexes-CgOF7Wjd.d.mts → indexes-3eHBWNZ2.d.mts} +0 -0
  31. /package/dist/{mongooseToJsonSchema-CBEQmeEa.mjs → mongooseToJsonSchema-ChtXSrLT.mjs} +0 -0
  32. /package/dist/{types-CU3SEDbD.d.mts → types-BA8oXjFe.d.mts} +0 -0
@@ -1,2 +1,2 @@
1
- import { a as IdType, c as isObjectIdInstance, d as filterResponseData, f as getFieldsForUser, i as configureLogger, l as isValidIdForType, m as createError, n as buildCrudSchemasFromMongooseSchema, o as getSchemaIdType, p as getMongooseProjection, r as createMemoryCache, t as buildCrudSchemasFromModel, u as createFieldPreset } from "../mongooseToJsonSchema-BdQJU39w.mjs";
1
+ import { a as IdType, c as isObjectIdInstance, d as filterResponseData, f as getFieldsForUser, i as configureLogger, l as isValidIdForType, m as createError, n as buildCrudSchemasFromMongooseSchema, o as getSchemaIdType, p as getMongooseProjection, r as createMemoryCache, t as buildCrudSchemasFromModel, u as createFieldPreset } from "../mongooseToJsonSchema-Bz47aMfH.mjs";
2
2
  export { type IdType, buildCrudSchemasFromModel, buildCrudSchemasFromMongooseSchema, configureLogger, createError, createFieldPreset, createMemoryCache, filterResponseData, getFieldsForUser, getMongooseProjection, getSchemaIdType, isObjectIdInstance, isValidIdForType };
@@ -1,6 +1,6 @@
1
1
  import { i as isValidIdForType, r as isObjectIdInstance, t as getSchemaIdType } from "../id-resolution-CnN0YA8t.mjs";
2
2
  import { t as configureLogger } from "../logger-B8wf-Mtb.mjs";
3
3
  import { t as createError } from "../error-BTeepSNL.mjs";
4
- import { i as getMongooseProjection, n as filterResponseData, r as getFieldsForUser, t as createFieldPreset } from "../field-selection-CQW3WBiK.mjs";
5
- import { n as buildCrudSchemasFromMongooseSchema, r as createMemoryCache, t as buildCrudSchemasFromModel } from "../mongooseToJsonSchema-CBEQmeEa.mjs";
4
+ import { i as getMongooseProjection, n as filterResponseData, r as getFieldsForUser, t as createFieldPreset } from "../field-selection-d1qdRiMr.mjs";
5
+ import { n as buildCrudSchemasFromMongooseSchema, r as createMemoryCache, t as buildCrudSchemasFromModel } from "../mongooseToJsonSchema-ChtXSrLT.mjs";
6
6
  export { buildCrudSchemasFromModel, buildCrudSchemasFromMongooseSchema, configureLogger, createError, createFieldPreset, createMemoryCache, filterResponseData, getFieldsForUser, getMongooseProjection, getSchemaIdType, isObjectIdInstance, isValidIdForType };
@@ -1,492 +1,8 @@
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-CU3SEDbD.mjs";
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-BA8oXjFe.mjs";
2
2
  import { BulkWriteResult } from "@classytic/repo-core/repository";
3
- import mongoose from "mongoose";
4
- import { CacheAdapter as CacheAdapter$1, CacheOptions, RepositoryCacheHandle, RepositoryCachePluginOptions, cachePlugin } from "@classytic/repo-core/cache";
5
3
  import { AsyncLocalStorage } from "node:async_hooks";
6
4
  import { OffsetPaginationResult } from "@classytic/repo-core/pagination";
7
- import { TenantConfig } from "@classytic/repo-core/tenant";
8
5
 
9
- //#region src/plugins/audit-trail.plugin.d.ts
10
- interface AuditTrailOptions {
11
- /** Operations to track (default: ['create', 'update', 'delete']) */
12
- operations?: AuditOperation[];
13
- /** Store field-level before/after diff on updates (default: true) */
14
- trackChanges?: boolean;
15
- /** Store full document snapshot on create (default: false — can be heavy) */
16
- trackDocument?: boolean;
17
- /** Auto-purge after N days via MongoDB TTL index (default: undefined — keep forever) */
18
- ttlDays?: number;
19
- /** MongoDB collection name (default: 'audit_trails') */
20
- collectionName?: string;
21
- /**
22
- * Extract custom metadata from the repository context.
23
- * Returned object is stored on the audit entry as `metadata`.
24
- */
25
- metadata?: (context: RepositoryContext) => Record<string, unknown>;
26
- /**
27
- * Fields to exclude from change tracking (e.g., passwords, tokens).
28
- * These fields are redacted in the `changes` diff.
29
- */
30
- excludeFields?: string[];
31
- /**
32
- * Custom callback fired when an audit write fails. Receives the error
33
- * and the entry that failed to land. Default: `console.warn` only.
34
- *
35
- * **Use this for compliance-grade audit trails (SOC 2 / PCI / HIPAA)
36
- * where missing entries must be surfaced upstream** — e.g. forward to
37
- * a dead-letter queue, page on-call, or short-circuit the request.
38
- * The default `warn` log is appropriate for development and
39
- * eventually-consistent observability use cases but is invisible to
40
- * compliance review.
41
- *
42
- * The callback runs on the same fire-and-forget microtask that wrote
43
- * the entry, so throwing from here will surface as an unhandled
44
- * rejection — handle (or rethrow into your error reporter) inside.
45
- */
46
- onWriteError?: (error: Error, entry: Omit<AuditEntry, 'timestamp'>) => void;
47
- }
48
- type AuditOperation = 'create' | 'update' | 'delete' | 'findOneAndUpdate';
49
- interface AuditEntry {
50
- model: string;
51
- operation: AuditOperation;
52
- documentId: unknown;
53
- userId?: unknown;
54
- orgId?: unknown;
55
- changes?: Record<string, {
56
- from: unknown;
57
- to: unknown;
58
- }>;
59
- document?: Record<string, unknown>;
60
- metadata?: Record<string, unknown>;
61
- timestamp: Date;
62
- }
63
- declare function auditTrailPlugin(options?: AuditTrailOptions): Plugin;
64
- interface AuditQueryOptions {
65
- model?: string;
66
- documentId?: string | ObjectId;
67
- userId?: string | ObjectId;
68
- orgId?: string | ObjectId;
69
- operation?: AuditOperation;
70
- from?: Date;
71
- to?: Date;
72
- page?: number;
73
- limit?: number;
74
- }
75
- interface AuditQueryResult {
76
- data: AuditEntry[];
77
- page: number;
78
- limit: number;
79
- total: number;
80
- pages: number;
81
- hasNext: boolean;
82
- hasPrev: boolean;
83
- }
84
- /**
85
- * Standalone audit trail query utility.
86
- * Use this to query audits across all models — e.g., admin dashboards, audit APIs.
87
- *
88
- * @example
89
- * ```typescript
90
- * import { AuditTrailQuery } from '@classytic/mongokit';
91
- *
92
- * const auditQuery = new AuditTrailQuery(); // defaults to 'audit_trails' collection
93
- *
94
- * // All audits for an org
95
- * const orgAudits = await auditQuery.query({ orgId: '...' });
96
- *
97
- * // All updates by a user
98
- * const userUpdates = await auditQuery.query({
99
- * userId: '...',
100
- * operation: 'update',
101
- * });
102
- *
103
- * // All audits for a specific document
104
- * const docHistory = await auditQuery.query({
105
- * model: 'Job',
106
- * documentId: '...',
107
- * });
108
- *
109
- * // Date range
110
- * const recent = await auditQuery.query({
111
- * from: new Date('2025-01-01'),
112
- * to: new Date(),
113
- * page: 1,
114
- * limit: 50,
115
- * });
116
- *
117
- * // Direct model access for custom queries
118
- * const model = auditQuery.getModel();
119
- * const count = await model.countDocuments({ operation: 'delete' });
120
- * ```
121
- */
122
- declare class AuditTrailQuery {
123
- private model;
124
- constructor(collectionName?: string, ttlDays?: number);
125
- /**
126
- * Get the underlying Mongoose model for custom queries
127
- */
128
- getModel(): mongoose.Model<AuditEntry>;
129
- /**
130
- * Query audit entries with filters and pagination
131
- */
132
- query(options?: AuditQueryOptions): Promise<AuditQueryResult>;
133
- /**
134
- * Get audit trail for a specific document
135
- */
136
- getDocumentTrail(model: string, documentId: string | ObjectId, options?: {
137
- page?: number;
138
- limit?: number;
139
- operation?: AuditOperation;
140
- }): Promise<AuditQueryResult>;
141
- /**
142
- * Get all audits for a user
143
- */
144
- getUserTrail(userId: string | ObjectId, options?: {
145
- page?: number;
146
- limit?: number;
147
- operation?: AuditOperation;
148
- orgId?: string | ObjectId;
149
- }): Promise<AuditQueryResult>;
150
- /**
151
- * Get all audits for an organization
152
- */
153
- getOrgTrail(orgId: string | ObjectId, options?: {
154
- page?: number;
155
- limit?: number;
156
- operation?: AuditOperation;
157
- model?: string;
158
- }): Promise<AuditQueryResult>;
159
- }
160
- interface AuditTrailMethods {
161
- /**
162
- * Get paginated audit trail for a document
163
- */
164
- getAuditTrail(documentId: string | ObjectId, options?: {
165
- page?: number;
166
- limit?: number;
167
- operation?: AuditOperation;
168
- }): Promise<AuditQueryResult>;
169
- }
170
- //#endregion
171
- //#region src/plugins/custom-id.plugin.d.ts
172
- /**
173
- * Generator function that produces a unique ID.
174
- * Receives the full repository context for conditional logic.
175
- */
176
- type IdGenerator = (context: RepositoryContext) => string | Promise<string>;
177
- interface CustomIdOptions {
178
- /** Field to store the custom ID (default: 'customId') */
179
- field?: string;
180
- /** Function to generate the ID. Can be async. */
181
- generator: IdGenerator;
182
- /** Only generate if the field is missing/empty (default: true) */
183
- generateOnlyIfEmpty?: boolean;
184
- }
185
- /**
186
- * Atomically increment and return the next sequence value for a given key.
187
- * Uses `findOneAndUpdate` with `upsert` + `$inc` — fully atomic even under
188
- * heavy concurrency.
189
- *
190
- * @param counterKey - Unique key identifying this counter (e.g., "Invoice" or "Invoice:2026-02")
191
- * @param increment - Value to increment by (default: 1)
192
- * @param connection - Mongoose connection to use (defaults to the default connection)
193
- * @param session - Optional client session. When provided, the counter bump
194
- * participates in the caller's transaction — if the surrounding transaction
195
- * aborts, the counter does NOT advance. Without a session, the bump commits
196
- * immediately and is not rolled back if a sibling write fails.
197
- * @returns The next sequence number (after increment)
198
- *
199
- * @example
200
- * const seq = await getNextSequence('invoices');
201
- * // First call → 1, second → 2, ...
202
- *
203
- * @example Batch increment for createMany
204
- * const startSeq = await getNextSequence('invoices', 5);
205
- * // If current was 10, returns 15 (you use 11, 12, 13, 14, 15)
206
- *
207
- * @example Transactional counter bump
208
- * await withTransaction(conn, async (session) => {
209
- * const seq = await getNextSequence('invoices', 1, conn, session);
210
- * await invoiceRepo.create({ invoiceNumber: `INV-${seq}` }, { session });
211
- * // if this throws, the counter is rolled back with the insert
212
- * });
213
- */
214
- declare function getNextSequence(counterKey: string, increment?: number, connection?: mongoose.Connection, session?: mongoose.ClientSession): Promise<number>;
215
- interface SequentialIdOptions {
216
- /** Prefix string (e.g., 'INV', 'ORD') */
217
- prefix: string;
218
- /** Mongoose model — used to derive the counter key from model name */
219
- model: mongoose.Model<any>;
220
- /** Number of digits to pad to (default: 4 → "0001") */
221
- padding?: number;
222
- /** Separator between prefix and number (default: '-') */
223
- separator?: string;
224
- /** Custom counter key override (default: model.modelName) */
225
- counterKey?: string;
226
- }
227
- /**
228
- * Generator: Simple sequential counter.
229
- * Produces IDs like `INV-0001`, `INV-0002`, etc.
230
- *
231
- * Uses atomic MongoDB counters — safe under concurrency.
232
- *
233
- * @example
234
- * ```typescript
235
- * customIdPlugin({
236
- * field: 'invoiceNumber',
237
- * generator: sequentialId({ prefix: 'INV', model: InvoiceModel }),
238
- * })
239
- * ```
240
- */
241
- declare function sequentialId(options: SequentialIdOptions): IdGenerator;
242
- interface DateSequentialIdOptions {
243
- /** Prefix string (e.g., 'BILL', 'INV') */
244
- prefix: string;
245
- /** Mongoose model — used to derive the counter key */
246
- model: mongoose.Model<any>;
247
- /**
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
6
  //#region src/plugins/aggregate-helpers.plugin.d.ts
491
7
  /**
492
8
  * Aggregate helpers plugin
@@ -1244,4 +760,4 @@ declare function immutableField(field: string): ValidatorDefinition;
1244
760
  */
1245
761
  declare function uniqueField(field: string, errorMessage?: string): ValidatorDefinition;
1246
762
  //#endregion
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 };
763
+ export { BulkWriteResult as A, LeasePluginOptions as C, elasticSearchPlugin as D, ElasticSearchOptions as E, auditLogPlugin as M, AggregateHelpersMethods as N, cascadePlugin as O, aggregateHelpersPlugin as P, LeaseMethods as S, fieldFilterPlugin as T, observabilityPlugin as _, uniqueField as a, MethodRegistryRepository as b, TenantContext as c, SubdocumentMethods as d, subdocumentPlugin as f, OperationMetric as g, ObservabilityOptions as h, requireField as i, batchOperationsPlugin as j, BatchOperationsMethods as k, TenantStore as l, softDeletePlugin as m, blockIf as n, validationChainPlugin as o, SoftDeleteMethods as p, immutableField as r, timestampPlugin as s, autoInject as t, createTenantContext as u, MongoOperationsMethods as v, leasePlugin as w, methodRegistryPlugin as x, mongoOperationsPlugin as y };