@classytic/mongokit 3.24.0 → 3.25.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 (38) hide show
  1. package/README.md +11 -2
  2. package/dist/{PaginationEngine-BnZ24ehC.d.mts → PaginationEngine-CBS1XGzp.d.mts} +2 -1
  3. package/dist/{Repository-ClOraFjT.mjs → Repository-KKR8jxfD.mjs} +70 -41
  4. package/dist/actions/index.d.mts +1 -1
  5. package/dist/adapter/index.d.mts +1 -1
  6. package/dist/adapter/index.mjs +1 -1
  7. package/dist/{adapter-BWgJ_Jdc.mjs → adapter-CLvUHiTW.mjs} +1 -1
  8. package/dist/ai/index.d.mts +1 -1
  9. package/dist/better-auth/index.mjs +2 -2
  10. package/dist/core-62oo3N1C.d.mts +50 -0
  11. package/dist/{create-repository-CVupgeRG.mjs → create-repository-DA5VJh-3.mjs} +2 -2
  12. package/dist/{create-repository-Cn1LkvL7.d.mts → create-repository-HjMD9h9_.d.mts} +18 -5
  13. package/dist/{id-resolution-P2OzcyRl.mjs → id-resolution-BqDrk0S2.mjs} +12 -1
  14. package/dist/{index-DLQ6pjal.d.mts → index-DceInCTX.d.mts} +3 -1
  15. package/dist/index.d.mts +53 -213
  16. package/dist/index.mjs +1071 -922
  17. package/dist/{mongooseToJsonSchema-CVnrKFDq.mjs → mongooseToJsonSchema-CByt1VhQ.mjs} +1 -1
  18. package/dist/{multi-tenant.plugin-BjXXuc_g.d.mts → multi-tenant.plugin-DVyVGREb.d.mts} +117 -18
  19. package/dist/operations-C8IcCHF9.d.mts +463 -0
  20. package/dist/pagination/PaginationEngine.d.mts +1 -1
  21. package/dist/pagination-jSUdrACK.d.mts +158 -0
  22. package/dist/plugin-options-vFufQZMZ.d.mts +125 -0
  23. package/dist/plugins/index.d.mts +4 -4
  24. package/dist/plugins/index.mjs +3 -3
  25. package/dist/query/primitives/coercion.mjs +1 -1
  26. package/dist/query/primitives/geo.d.mts +1 -1
  27. package/dist/repository-DCHRWRXw.d.mts +511 -0
  28. package/dist/testkit/index.d.mts +1 -1
  29. package/dist/testkit/index.mjs +1 -1
  30. package/dist/{timestamp.plugin-BhSX0Lu_.mjs → timestamp.plugin-B8252GuQ.mjs} +192 -46
  31. package/dist/{to-plain-g8-gsVxZ.d.mts → to-plain-DkF5px0R.d.mts} +12 -16
  32. package/dist/type-utils-CLzRFtIA.d.mts +163 -0
  33. package/dist/utils/index.d.mts +2 -2
  34. package/dist/utils/index.mjs +3 -3
  35. package/dist/{validation-chain.plugin-Dtt4tO7R.mjs → validation-chain.plugin-C3Vwp-Rk.mjs} +1 -1
  36. package/dist/{validation-chain.plugin-CFJbr964.d.mts → validation-chain.plugin-DxD15h-2.d.mts} +3 -1
  37. package/package.json +5 -3
  38. package/dist/types-BtMuhoX5.d.mts +0 -1830
@@ -0,0 +1,511 @@
1
+ import { a as PopulateSpec, i as ObjectId, l as SortSpec, o as ReadPreferenceType, r as FilterQuery, s as SelectSpec, t as AnyDocument } from "./core-62oo3N1C.mjs";
2
+ import { r as DocField } from "./type-utils-CLzRFtIA.mjs";
3
+ import { RepositoryBase } from "@classytic/repo-core/repository";
4
+ import { Model, PipelineStage } from "mongoose";
5
+ import { HttpError } from "@classytic/repo-core/errors";
6
+ import { OffsetPaginationResult } from "@classytic/repo-core/pagination";
7
+ //#region src/plugins/names.d.ts
8
+ /**
9
+ * Canonical identifiers exposed by mongokit's bundled plugins.
10
+ *
11
+ * Use these values with `RepositoryOptions.requirePlugins` and
12
+ * `OperationOptions.skipPlugins` instead of repeating string literals.
13
+ * The values intentionally preserve the plugins' existing public names.
14
+ */
15
+ declare const MONGOKIT_PLUGIN_NAMES: {
16
+ readonly aggregateHelpers: "aggregate-helpers";
17
+ readonly appendOnly: "appendOnly";
18
+ readonly auditLog: "auditLog";
19
+ readonly auditTrail: "auditTrail";
20
+ readonly batchOperations: "batch-operations";
21
+ readonly cache: "cache";
22
+ readonly cascade: "cascade";
23
+ readonly changeLog: "changeLog";
24
+ readonly customId: "custom-id";
25
+ readonly elasticSearch: "elastic-search";
26
+ readonly fieldFilter: "fieldFilter";
27
+ readonly immutableStates: "immutableStates";
28
+ readonly lease: "lease";
29
+ readonly methodRegistry: "method-registry";
30
+ readonly mongoOperations: "mongo-operations";
31
+ readonly multiTenant: "multi-tenant";
32
+ readonly observability: "observability";
33
+ readonly softDelete: "softDelete";
34
+ readonly subdocument: "subdocument";
35
+ readonly timestamp: "timestamp";
36
+ readonly validationChain: "validation-chain";
37
+ };
38
+ type MongoKitPluginName = (typeof MONGOKIT_PLUGIN_NAMES)[keyof typeof MONGOKIT_PLUGIN_NAMES];
39
+ /** Bundled-name autocomplete while remaining open to third-party plugins. */
40
+ type RepositoryPluginName = MongoKitPluginName | (string & Record<never, never>);
41
+ //#endregion
42
+ //#region src/types/repository.d.ts
43
+ /** Hook execution mode */
44
+ type HookMode = 'sync' | 'async';
45
+ /**
46
+ * Minimal repo surface exposed to wrap-style middleware via the
47
+ * `repo` field of `MiddlewareContext`. Intentionally narrow — middleware
48
+ * shouldn't reach into the full `Repository` (that would couple every
49
+ * middleware to the kit). The 5 floor methods plus `Model` cover every
50
+ * legitimate middleware need (cross-doc reads, custom queries, type-
51
+ * narrowing on `Model.modelName`).
52
+ */
53
+ interface MinimalRepoView<TDoc> {
54
+ readonly Model: Model<TDoc>;
55
+ readonly model: string;
56
+ getById(id: string | ObjectId, options?: Record<string, unknown>): Promise<TDoc | null>;
57
+ getAll?(params?: Record<string, unknown>, options?: Record<string, unknown>): Promise<unknown>;
58
+ create(data: Record<string, unknown>, options?: Record<string, unknown>): Promise<TDoc>;
59
+ update(id: string | ObjectId, data: Record<string, unknown>, options?: Record<string, unknown>): Promise<unknown>;
60
+ delete(id: string | ObjectId, options?: Record<string, unknown>): Promise<unknown>;
61
+ }
62
+ /**
63
+ * Context passed to a wrap-style middleware. Middleware mutates
64
+ * `context` before calling `await next()` to alter input; inspects /
65
+ * transforms the resolved value to alter output; uses plain try/catch
66
+ * around `next()` for error handling.
67
+ *
68
+ * The `before:` / `after:` / `error:` hook engine still fires from
69
+ * within `next()` — hooks remain authoritative for policy / cache /
70
+ * audit so security and correctness plugins keep working unchanged.
71
+ * Middleware composes ergonomically on top.
72
+ */
73
+ interface MiddlewareContext<TDoc> {
74
+ /** Operation name (`'create'`, `'getById'`, ..., or any plugin op). */
75
+ readonly operation: string;
76
+ /** Live repository context — mutate fields before `next()` to alter input. */
77
+ readonly context: RepositoryContext;
78
+ /**
79
+ * Continue the chain — the next middleware (or, for the innermost
80
+ * middleware, the actual op + after/error hooks). The return value
81
+ * is the resolved op result; throwing propagates up the chain.
82
+ */
83
+ next: () => Promise<unknown>;
84
+ /** Narrow view of the repo for cross-doc reads / custom queries. */
85
+ readonly repo: MinimalRepoView<TDoc>;
86
+ }
87
+ /**
88
+ * Wrap-style middleware — Prisma `$extends.query` / Express middleware
89
+ * shape. Registered via `repo.useMiddleware(mw)`. Composes around every
90
+ * `_runOp` invocation; runs in registration order (first-registered
91
+ * runs outermost).
92
+ *
93
+ * @example Time every operation
94
+ * ```ts
95
+ * repo.useMiddleware(async ({ operation, next }) => {
96
+ * const start = performance.now();
97
+ * try { return await next(); }
98
+ * finally { console.log(`${operation} took ${performance.now() - start}ms`); }
99
+ * });
100
+ * ```
101
+ */
102
+ type Middleware<TDoc = unknown> = (ctx: MiddlewareContext<TDoc>) => Promise<unknown>;
103
+ /** Search strategy used by Repository.getAll when `search` is provided */
104
+ type RepositorySearchMode = 'text' | 'regex' | 'auto';
105
+ /** Repository options */
106
+ interface RepositoryOptions {
107
+ /** Whether repository event hooks are awaited */
108
+ hooks?: HookMode;
109
+ /** Custom ID field used by getById/update/delete (default: '_id').
110
+ * Set to 'slug', 'code', 'chatId', etc. for non-ObjectId lookups. */
111
+ idField?: string;
112
+ /**
113
+ * How Repository.getAll handles the `search` parameter.
114
+ * - 'text' (default): uses MongoDB $text; requires a text index.
115
+ * - 'regex': builds case-insensitive $or of $regex across `searchFields`. No index required.
116
+ * - 'auto': uses 'text' if a text index exists, otherwise falls back to 'regex' when `searchFields` is set.
117
+ *
118
+ * Works standalone (Express/Nest/etc.) or alongside QueryParser — when the parser
119
+ * already consumed `search` into filters, Repository does nothing extra.
120
+ */
121
+ searchMode?: RepositorySearchMode;
122
+ /**
123
+ * Fields used when searchMode is 'regex' (or 'auto' falling back to regex).
124
+ * Required for regex mode to take effect.
125
+ */
126
+ searchFields?: string[];
127
+ /**
128
+ * How to react to a plugin composition that is known to be unsafe.
129
+ * - 'warn' (default): log a warning via the configured logger.
130
+ * - 'throw': fail fast at construction time — recommended for production.
131
+ * - 'off': disable the check entirely.
132
+ *
133
+ * Checks currently enforced:
134
+ * - soft-delete must precede batch-operations (otherwise deleteMany /
135
+ * updateMany skip the soft-delete filter injection).
136
+ * - multi-tenant must precede cache (otherwise cache keys are computed
137
+ * before tenant scoping → cross-tenant cache poisoning risk).
138
+ */
139
+ pluginOrderChecks?: 'warn' | 'throw' | 'off';
140
+ /**
141
+ * When `true` (default `false`), the repository checks every read/
142
+ * write op's filter against the schema's declared paths and warns
143
+ * once per `(modelName, fieldName)` pair if a filter key isn't on
144
+ * the schema AND `strictQuery: true` is in effect.
145
+ *
146
+ * **Why this exists.** With `mongoose.set('strictQuery', true)` (the
147
+ * mongoose 6 default; some projects pin it explicitly), filter keys
148
+ * not declared on the schema are SILENTLY STRIPPED before the query
149
+ * runs. `findOne({ code: 'X' })` on a schema without `code` becomes
150
+ * `findOne({})` — returns the first doc, not null — and the bug
151
+ * masquerades as "wrong row returned" without any error or log.
152
+ *
153
+ * The diagnostic catches the trap at runtime: log once per offending
154
+ * key per model, so a single bad call surfaces during dev/staging
155
+ * instead of in production. Costs O(filter keys) per call against
156
+ * a constructor-cached set; negligible.
157
+ *
158
+ * Hosts who route mongokit's `warn` into their own logger (via
159
+ * `configureLogger({ warn: ... })`) can ship this enabled in
160
+ * production without polluting stdout.
161
+ *
162
+ * @default false
163
+ */
164
+ warnOnStrictQueryStrip?: boolean;
165
+ /**
166
+ * Names of plugins that MUST be present in the plugin chain at
167
+ * construction time. Throws a `TypeError` from the constructor if
168
+ * any listed plugin is absent — eliminates the silent-misconfig
169
+ * shape where a host forgets to wire `multiTenantPlugin` and ships
170
+ * a tenant-leak to production.
171
+ *
172
+ * Names match each plugin's exported `name` property (the plugin's
173
+ * own canonical identifier, NOT the JavaScript function name).
174
+ *
175
+ * @example
176
+ * ```ts
177
+ * import { MONGOKIT_PLUGIN_NAMES } from '@classytic/mongokit';
178
+ *
179
+ * new Repository(OrderModel, [
180
+ * methodRegistryPlugin(),
181
+ * multiTenantPlugin({ tenantField: 'organizationId' }),
182
+ * softDeletePlugin(),
183
+ * auditLogPlugin({ logger }),
184
+ * ], paginationConfig, {
185
+ * requirePlugins: [
186
+ * MONGOKIT_PLUGIN_NAMES.multiTenant,
187
+ * MONGOKIT_PLUGIN_NAMES.softDelete,
188
+ * MONGOKIT_PLUGIN_NAMES.auditLog,
189
+ * ],
190
+ * });
191
+ * ```
192
+ */
193
+ requirePlugins?: readonly RepositoryPluginName[];
194
+ /**
195
+ * Standard Schema validator (Zod 3.24+, Valibot 1+, ArkType 2+, ...)
196
+ * for write payloads. Forwarded to `RepositoryBase`, which validates
197
+ * `create` data and every `createMany` doc at
198
+ * `HOOK_PRIORITY.VALIDATION` (150) — after policy plugins, before
199
+ * cache/observability. Failures throw an `HttpError` 400 with
200
+ * structured `validationErrors`. Validator output replaces the
201
+ * payload, so schema-declared coercions/defaults flow into the write.
202
+ */
203
+ schema?: import('@classytic/repo-core/schema').StandardSchemaV1;
204
+ /**
205
+ * Standard Schema validator for `update` payloads. Separate slot
206
+ * because updates are partial — derive one explicitly (e.g.
207
+ * `schema.partial()` in Zod).
208
+ */
209
+ updateSchema?: import('@classytic/repo-core/schema').StandardSchemaV1;
210
+ /**
211
+ * Domain-event emission. Pass any arc / `@classytic/primitives`-
212
+ * compatible transport and every mutating op publishes
213
+ * `<resource>.<verb>` events (`user.created`, `user.updated`, ...).
214
+ * Omit and the wiring is inert. See `@classytic/repo-core/events`.
215
+ */
216
+ events?: import('@classytic/repo-core/events').RepositoryEventsOptions;
217
+ }
218
+ /** User context for operations */
219
+ interface UserContext {
220
+ _id?: ObjectId | string;
221
+ id?: string;
222
+ roles?: string | string[];
223
+ [key: string]: unknown;
224
+ }
225
+ /** Repository operation context */
226
+ interface RepositoryContext {
227
+ /** Operation name */
228
+ operation: string;
229
+ /** Model name */
230
+ model: string;
231
+ /** Document data (for create/update) */
232
+ data?: Record<string, unknown>;
233
+ /** Array of documents (for createMany) */
234
+ dataArray?: Record<string, unknown>[];
235
+ /** Document ID (for update/delete/getById) */
236
+ id?: string | ObjectId;
237
+ /** Query filters */
238
+ query?: FilterQuery<AnyDocument>;
239
+ /** User making the request */
240
+ user?: UserContext;
241
+ /** Organization ID for multi-tenancy */
242
+ organizationId?: string | ObjectId;
243
+ /** Fields to select */
244
+ select?: SelectSpec;
245
+ /** Fields to populate */
246
+ populate?: PopulateSpec;
247
+ /** Return lean documents */
248
+ lean?: boolean;
249
+ /** MongoDB session */
250
+ session?: unknown;
251
+ /** Read preference for replica sets */
252
+ readPreference?: ReadPreferenceType;
253
+ /**
254
+ * Per-call escape hatch — plugin names listed here that opt into the
255
+ * mechanism (`auditLog`, `auditTrail`, `observability`) skip their
256
+ * work for this call. Threaded from `OperationOptions.skipPlugins`
257
+ * via `_buildContext`. Security/correctness plugins (multi-tenant
258
+ * scope, cache invalidation, soft-delete filter) deliberately ignore
259
+ * this — those must not be skippable per-call.
260
+ */
261
+ skipPlugins?: readonly string[];
262
+ /** Pagination filters */
263
+ filters?: Record<string, unknown>;
264
+ /** Sort specification */
265
+ sort?: SortSpec;
266
+ /** Page number (offset pagination) */
267
+ page?: number;
268
+ /** Items per page */
269
+ limit?: number;
270
+ /** Cursor for next page (keyset pagination) */
271
+ after?: string;
272
+ /** Search query string */
273
+ search?: string;
274
+ /** Pagination mode */
275
+ mode?: 'offset' | 'keyset';
276
+ /** Query hint */
277
+ hint?: string | Record<string, 1 | -1>;
278
+ /** Maximum execution time in milliseconds */
279
+ maxTimeMS?: number;
280
+ /** Count strategy for offset pagination */
281
+ countStrategy?: 'exact' | 'estimated' | 'none';
282
+ /** Whether this is a soft delete operation (set by softDeletePlugin) */
283
+ softDeleted?: boolean;
284
+ /** Include soft-deleted documents in queries */
285
+ includeDeleted?: boolean;
286
+ /**
287
+ * Caller-requested delete semantics, read by softDeletePlugin.
288
+ *
289
+ * - `undefined` (default) — plugin decides: soft if wired, hard otherwise.
290
+ * - `'hard'` — bypass soft-delete and physically remove the document.
291
+ * All policy hooks (multi-tenant scope, audit trails, cache invalidation)
292
+ * still fire; only the soft-delete interception is skipped.
293
+ * - `'soft'` — reserved. Currently treated as default since softDeletePlugin
294
+ * is the only source of soft semantics.
295
+ */
296
+ deleteMode?: 'hard' | 'soft';
297
+ /**
298
+ * Per-call cache options forwarded by the unified cache plugin
299
+ * (`@classytic/repo-core/cache`). Kits copy this from the caller's
300
+ * `options.cache` onto the context so the plugin's `before:<op>`
301
+ * hook can read it.
302
+ */
303
+ cache?: import('@classytic/repo-core/cache').CacheOptions;
304
+ /** Whether result was served from cache (internal — set by cache plugin) */
305
+ _cacheHit?: boolean;
306
+ /** Cached result (internal — set by cache plugin) */
307
+ _cachedResult?: unknown;
308
+ /** Resolved cache options stash (internal — set by cache plugin) */
309
+ _cacheKey?: string;
310
+ /** Resolved cache options stash (internal — set by cache plugin) */
311
+ _cacheResolved?: unknown;
312
+ /** Cache hit status (internal — `'fresh'` or `'stale'`) */
313
+ _cacheStatus?: 'fresh' | 'stale' | 'miss' | 'disabled' | 'bypass';
314
+ /** IDs to cascade delete (internal) */
315
+ _cascadeIds?: unknown[];
316
+ /** Custom context data from plugins */
317
+ [key: string]: unknown;
318
+ }
319
+ /**
320
+ * Plugin interface — generic over the repo type so kit-internal plugins
321
+ * can target the narrower `RepositoryInstance` while cross-package
322
+ * plugins from `@classytic/repo-core/cache` etc. that target the
323
+ * shared `RepositoryBase` flow through the same array.
324
+ *
325
+ * `RepositoryInstance` formally `extends RepositoryBase` (see below),
326
+ * so `Plugin<RepositoryBase>` is structurally assignable to
327
+ * `Plugin<RepositoryInstance>` via TypeScript's method-bivariance
328
+ * rule for interface methods. No host-site casts required.
329
+ */
330
+ interface Plugin<TRepo extends RepositoryBase = RepositoryInstance> {
331
+ /** Plugin name */
332
+ name: string;
333
+ /** Apply plugin to repository */
334
+ apply(repo: TRepo): void;
335
+ }
336
+ /** Plugin function signature. Same TRepo widening as `Plugin`. */
337
+ type PluginFunction<TRepo extends RepositoryBase = RepositoryInstance> = (repo: TRepo) => void;
338
+ /** Plugin type (object or function). */
339
+ type PluginType<TRepo extends RepositoryBase = RepositoryInstance> = Plugin<TRepo> | PluginFunction<TRepo>;
340
+ /** Hook with priority for deterministic phase ordering */
341
+ interface PrioritizedHook {
342
+ listener: (data: any) => void | Promise<void>;
343
+ priority: number;
344
+ }
345
+ /**
346
+ * Repository instance for plugin type reference.
347
+ *
348
+ * Extends `@classytic/repo-core/repository`'s `RepositoryBase` so the
349
+ * full hook + adapter contract is included. This keeps mongokit's
350
+ * `Plugin<RepositoryInstance>` and repo-core's `Plugin<RepositoryBase>`
351
+ * structurally aligned — cross-package plugins (`cachePlugin` from
352
+ * `@classytic/repo-core/cache` etc.) flow into mongokit's `plugins[]`
353
+ * array without per-call casts at the host site.
354
+ *
355
+ * The `[key: string]: unknown` index signature at the bottom keeps
356
+ * dynamic plugin-method registration (`registerMethod`) compatible.
357
+ */
358
+ interface RepositoryInstance extends RepositoryBase {
359
+ Model: Model<any>;
360
+ model: string;
361
+ _hooks: Map<string, PrioritizedHook[]>;
362
+ _pagination: unknown;
363
+ use(plugin: PluginType): this;
364
+ on(event: RepositoryEvent | (string & {}), listener: (data: any) => void | Promise<void>, options?: {
365
+ priority?: number;
366
+ }): this;
367
+ off(event: RepositoryEvent | (string & {}), listener: (data: any) => void | Promise<void>): this;
368
+ removeAllListeners(event?: string): this;
369
+ emit(event: string, data: unknown): void;
370
+ emitAsync(event: string, data: unknown): Promise<void>;
371
+ registerMethod?(name: string, fn: (...args: any[]) => any): void;
372
+ hasMethod?(name: string): boolean;
373
+ _buildContext(operation: string, options: Record<string, unknown> | object): Promise<RepositoryContext>;
374
+ _handleError(error: Error): HttpError;
375
+ update(id: string | ObjectId, data: Record<string, unknown>, options?: Record<string, unknown>): Promise<unknown>;
376
+ findOneAndUpdate(filter: Record<string, unknown>, update: Record<string, unknown> | Record<string, unknown>[], options?: Record<string, unknown>): Promise<unknown>;
377
+ aggregatePipeline(pipeline: PipelineStage[], options?: Record<string, unknown>): Promise<unknown[]>;
378
+ getByQuery(query: Record<string, unknown>, options?: Record<string, unknown>): Promise<unknown>;
379
+ _executeQuery<T>(buildQuery: (Model: Model<any>) => Promise<T>): Promise<T>;
380
+ [key: string]: unknown;
381
+ }
382
+ /** Repository operation names */
383
+ type RepositoryOperation = 'create' | 'createMany' | 'update' | 'updateMany' | 'findOneAndUpdate' | 'delete' | 'deleteMany' | 'restore' | 'getById' | 'getByQuery' | 'getOne' | 'getAll' | 'findAll' | 'getOrCreate' | 'count' | 'exists' | 'distinct' | 'aggregate' | 'aggregatePaginate' | 'aggregatePipeline' | 'aggregatePipelinePaginate' | 'lookupPopulate' | 'bulkWrite' | 'claim' | 'claimVersion' | 'cursor' | 'watch';
384
+ /** Event lifecycle phases */
385
+ type EventPhase = 'before' | 'after' | 'error';
386
+ /** Repository event names (generated from template literals) */
387
+ type RepositoryEvent = `${EventPhase}:${RepositoryOperation}` | 'method:registered' | 'error:hook';
388
+ /**
389
+ * Type-safe event handler map
390
+ *
391
+ * Hook signature contract:
392
+ * - `before:*` — receives `context: RepositoryContext` directly (not wrapped).
393
+ * Plugins mutate context in-place to inject filters, data, etc.
394
+ * - `after:*` — receives `{ context, result }` where result is the operation output.
395
+ * - `error:*` — receives `{ context, error }` where error is the caught Error.
396
+ */
397
+ type EventHandlers<TDoc = unknown> = { [K in RepositoryEvent]?: K extends `before:${string}` ? (context: RepositoryContext) => void | Promise<void> : K extends `after:${string}` ? (payload: {
398
+ context: RepositoryContext;
399
+ result: TDoc | TDoc[];
400
+ }) => void | Promise<void> : K extends `error:${string}` ? (payload: {
401
+ context: RepositoryContext;
402
+ error: Error;
403
+ }) => void | Promise<void> : (payload: {
404
+ context: RepositoryContext;
405
+ }) => void | Promise<void>; };
406
+ /** Event payload */
407
+ interface EventPayload {
408
+ context: RepositoryContext;
409
+ result?: unknown;
410
+ error?: Error;
411
+ }
412
+ /**
413
+ * Combines all plugin method types into a single type.
414
+ * Useful when you're using all plugins and want full type safety.
415
+ *
416
+ * @example
417
+ * ```typescript
418
+ * import { Repository } from '@classytic/mongokit';
419
+ * import type { AllPluginMethods } from '@classytic/mongokit';
420
+ *
421
+ * class UserRepo extends Repository<IUser> {}
422
+ *
423
+ * const repo = new UserRepo(Model, [...allPlugins]) as UserRepo & AllPluginMethods<IUser>;
424
+ *
425
+ * await repo.increment(id, 'views', 1);
426
+ * await repo.restore(id);
427
+ * await repo.cache?.invalidateByTags(['org:abc']);
428
+ * ```
429
+ */
430
+ type AllPluginMethods<TDoc> = {
431
+ upsert(query: Record<string, unknown>, data: Record<string, unknown>, options?: Record<string, unknown>): Promise<TDoc>;
432
+ increment(id: string | ObjectId, field: DocField<TDoc>, value?: number, options?: Record<string, unknown>): Promise<TDoc>;
433
+ decrement(id: string | ObjectId, field: DocField<TDoc>, value?: number, options?: Record<string, unknown>): Promise<TDoc>;
434
+ pushToArray(id: string | ObjectId, field: DocField<TDoc>, value: unknown, options?: Record<string, unknown>): Promise<TDoc>;
435
+ pullFromArray(id: string | ObjectId, field: DocField<TDoc>, value: unknown, options?: Record<string, unknown>): Promise<TDoc>;
436
+ addToSet(id: string | ObjectId, field: DocField<TDoc>, value: unknown, options?: Record<string, unknown>): Promise<TDoc>;
437
+ setField(id: string | ObjectId, field: DocField<TDoc>, value: unknown, options?: Record<string, unknown>): Promise<TDoc>;
438
+ unsetField(id: string | ObjectId, fields: DocField<TDoc> | DocField<TDoc>[], options?: Record<string, unknown>): Promise<TDoc>;
439
+ renameField(id: string | ObjectId, oldName: DocField<TDoc>, newName: string, options?: Record<string, unknown>): Promise<TDoc>;
440
+ multiplyField(id: string | ObjectId, field: DocField<TDoc>, multiplier: number, options?: Record<string, unknown>): Promise<TDoc>;
441
+ setMin(id: string | ObjectId, field: DocField<TDoc>, value: unknown, options?: Record<string, unknown>): Promise<TDoc>;
442
+ setMax(id: string | ObjectId, field: DocField<TDoc>, value: unknown, options?: Record<string, unknown>): Promise<TDoc>;
443
+ atomicUpdate(id: string | ObjectId, operators: Record<string, Record<string, unknown>>, options?: Record<string, unknown>): Promise<TDoc>;
444
+ bulkWrite(operations: Record<string, unknown>[], options?: {
445
+ session?: unknown;
446
+ ordered?: boolean;
447
+ }): Promise<{
448
+ ok: number;
449
+ insertedCount: number;
450
+ upsertedCount: number;
451
+ matchedCount: number;
452
+ modifiedCount: number;
453
+ deletedCount: number;
454
+ insertedIds: Record<number, unknown>;
455
+ upsertedIds: Record<number, unknown>;
456
+ }>;
457
+ groupBy(field: DocField<TDoc>, options?: {
458
+ limit?: number;
459
+ session?: unknown;
460
+ }): Promise<Array<{
461
+ _id: unknown;
462
+ count: number;
463
+ }>>;
464
+ sum(field: DocField<TDoc>, query?: Record<string, unknown>, options?: Record<string, unknown>): Promise<number>;
465
+ average(field: DocField<TDoc>, query?: Record<string, unknown>, options?: Record<string, unknown>): Promise<number>;
466
+ min(field: DocField<TDoc>, query?: Record<string, unknown>, options?: Record<string, unknown>): Promise<number>;
467
+ max(field: DocField<TDoc>, query?: Record<string, unknown>, options?: Record<string, unknown>): Promise<number>;
468
+ addSubdocument(parentId: string | ObjectId, arrayPath: DocField<TDoc>, subData: Record<string, unknown>, options?: Record<string, unknown>): Promise<TDoc>;
469
+ getSubdocument(parentId: string | ObjectId, arrayPath: DocField<TDoc>, subId: string | ObjectId, options?: {
470
+ lean?: boolean;
471
+ session?: unknown;
472
+ }): Promise<Record<string, unknown>>;
473
+ updateSubdocument(parentId: string | ObjectId, arrayPath: DocField<TDoc>, subId: string | ObjectId, updateData: Record<string, unknown>, options?: {
474
+ session?: unknown;
475
+ }): Promise<TDoc>;
476
+ deleteSubdocument(parentId: string | ObjectId, arrayPath: DocField<TDoc>, subId: string | ObjectId, options?: Record<string, unknown>): Promise<TDoc>;
477
+ restore(id: string | ObjectId, options?: {
478
+ session?: unknown;
479
+ }): Promise<TDoc>;
480
+ getDeleted(params?: {
481
+ filters?: Record<string, unknown>;
482
+ sort?: SortSpec | string;
483
+ page?: number;
484
+ limit?: number;
485
+ }, options?: {
486
+ select?: SelectSpec;
487
+ populate?: PopulateSpec;
488
+ lean?: boolean;
489
+ session?: unknown;
490
+ }): Promise<OffsetPaginationResult<TDoc>>;
491
+ /**
492
+ * Cache plugin handle (set by `cachePlugin({ adapter })`). Exposes the
493
+ * `CacheEngine` plus convenience invalidation helpers. `undefined` when
494
+ * no cache plugin is wired.
495
+ */
496
+ cache?: import('@classytic/repo-core/cache').RepositoryCacheHandle;
497
+ };
498
+ /**
499
+ * Helper type to add all plugin methods to a repository class.
500
+ * Cleaner than manually typing the intersection.
501
+ *
502
+ * @example
503
+ * ```typescript
504
+ * const orderRepo = new OrderRepo(Model, [...allPlugins]) as WithPlugins<IOrder, OrderRepo>;
505
+ * await orderRepo.getCustomerOrders('123'); // custom methods
506
+ * await orderRepo.increment(orderId, 'total', 100); // plugin methods
507
+ * ```
508
+ */
509
+ type WithPlugins<TDoc, TRepo extends RepositoryInstance = RepositoryInstance> = TRepo & AllPluginMethods<TDoc>;
510
+ //#endregion
511
+ export { RepositoryPluginName as S, RepositoryOptions as _, HookMode as a, MONGOKIT_PLUGIN_NAMES as b, MinimalRepoView as c, PluginType as d, PrioritizedHook as f, RepositoryOperation as g, RepositoryInstance as h, EventPhase as i, Plugin as l, RepositoryEvent as m, EventHandlers as n, Middleware as o, RepositoryContext as p, EventPayload as r, MiddlewareContext as s, AllPluginMethods as t, PluginFunction as u, UserContext as v, MongoKitPluginName as x, WithPlugins as y };
@@ -1,4 +1,4 @@
1
- import { a as Repository, n as CreateRepositoryConfig } from "../create-repository-Cn1LkvL7.mjs";
1
+ import { a as Repository, n as CreateRepositoryConfig } from "../create-repository-HjMD9h9_.mjs";
2
2
  import { Connection, Model, Schema } from "mongoose";
3
3
  import { MongoMemoryReplSet, MongoMemoryServer } from "mongodb-memory-server";
4
4
  //#region src/testkit/index.d.ts
@@ -1,4 +1,4 @@
1
- import { t as createRepository } from "../create-repository-CVupgeRG.mjs";
1
+ import { t as createRepository } from "../create-repository-DA5VJh-3.mjs";
2
2
  import { createConnection } from "mongoose";
3
3
  //#region src/testkit/index.ts
4
4
  function idempotentStop(server) {