@classytic/mongokit 3.43.1 → 3.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/README.md +18 -3
  2. package/dist/{PaginationEngine-DZnkbSrr.mjs → PaginationEngine-BRlLTQQz.mjs} +13 -27
  3. package/dist/{PaginationEngine-CRHyuUtw.d.mts → PaginationEngine-BWb-c47a.d.mts} +1 -3
  4. package/dist/{Repository-DnL4xk5w.d.mts → Repository-DJuRmBNx.d.mts} +44 -13
  5. package/dist/{Repository-Dj6xqPxJ.mjs → Repository-DheA7oW-.mjs} +330 -112
  6. package/dist/actions/index.d.mts +1 -1
  7. package/dist/actions/index.mjs +2 -2
  8. package/dist/{actions-ChYfkPYP.mjs → actions-DKQx9ToJ.mjs} +3 -4
  9. package/dist/adapter/index.d.mts +6 -10
  10. package/dist/adapter/index.mjs +1 -1
  11. package/dist/{adapter-CkMoMF83.mjs → adapter-Qzgc3ZD_.mjs} +4 -6
  12. package/dist/ai/index.d.mts +21 -8
  13. package/dist/ai/index.mjs +15 -9
  14. package/dist/better-auth/index.d.mts +21 -20
  15. package/dist/better-auth/index.mjs +12 -23
  16. package/dist/{coercion-BjdPX3YF.d.mts → coercion-COp9DRNw.d.mts} +0 -2
  17. package/dist/{create-repository-UjwPWR1z.mjs → create-repository-C9DHHcl7.mjs} +4 -5
  18. package/dist/{create-repository-CJtVdwig.d.mts → create-repository-DG-gwOf0.d.mts} +5 -7
  19. package/dist/{derive-DRBiegRH.mjs → derive-Dxsc31fV.mjs} +3 -6
  20. package/dist/{error-BuByZwKU.mjs → error-DjdmPLWO.mjs} +1 -2
  21. package/dist/{field-selection-FSQFLpsU.mjs → field-selection-DPFaFw9Y.mjs} +1 -2
  22. package/dist/{id-chunks-BmAwsqNk.mjs → id-chunks-DH-RAZWG.mjs} +13 -8
  23. package/dist/{id-resolution-BqDrk0S2.mjs → id-resolution-Cqh49d9J.mjs} +1 -2
  24. package/dist/idempotency/index.d.mts +4 -7
  25. package/dist/idempotency/index.mjs +1 -2
  26. package/dist/{index-SYF8N28D.d.mts → index-5mhQ63_B.d.mts} +3 -4
  27. package/dist/{index-C0AjVqX3.d.mts → index-ehGZLbrd.d.mts} +2 -8
  28. package/dist/index.d.mts +70 -102
  29. package/dist/index.mjs +36 -52
  30. package/dist/indexes/verify-indexes.d.mts +8 -11
  31. package/dist/indexes/verify-indexes.mjs +1 -2
  32. package/dist/{indexes-DIjMpYES.d.mts → indexes-FfyOuhDK.d.mts} +0 -2
  33. package/dist/{join-scope-DSAznE8E.mjs → join-scope-C1gOtZ59.mjs} +2 -3
  34. package/dist/kernel-conformance/index.d.mts +39 -13
  35. package/dist/kernel-conformance/index.mjs +4 -7
  36. package/dist/lock/index.d.mts +134 -7
  37. package/dist/lock/index.mjs +349 -14
  38. package/dist/{logger-K7dPmu2U.mjs → logger-hbWOlj_X.mjs} +1 -2
  39. package/dist/{method-registry.plugin-C63pGn1d.mjs → method-registry.plugin-BeJfQBJV.mjs} +5 -7
  40. package/dist/{model-registry-ClKtWiHa.mjs → model-registry-DrVfJ3Nt.mjs} +1 -2
  41. package/dist/{mongooseToJsonSchema-C3k4ide0.mjs → mongooseToJsonSchema-DMDotz4_.mjs} +2 -3
  42. package/dist/{multi-tenant.plugin-B_q9NUHc.d.mts → multi-tenant.plugin-BTPtCLNK.d.mts} +143 -11
  43. package/dist/{operations-XiFgG5US.d.mts → operations-D6XsHx4e.d.mts} +19 -11
  44. package/dist/outbox/index.d.mts +24 -9
  45. package/dist/outbox/index.mjs +17 -6
  46. package/dist/pagination/PaginationEngine.d.mts +1 -1
  47. package/dist/pagination/PaginationEngine.mjs +1 -1
  48. package/dist/pagination/utils/limits.d.mts +6 -9
  49. package/dist/pagination/utils/limits.mjs +2 -3
  50. package/dist/{pagination-D6psses0.d.mts → pagination-BAM9cA4N.d.mts} +6 -16
  51. package/dist/{plugin-options-Cirmb4Kp.d.mts → plugin-options-DrNGWV5b.d.mts} +2 -4
  52. package/dist/plugins/index.d.mts +6 -7
  53. package/dist/plugins/index.mjs +6 -7
  54. package/dist/query/primitives/coercion.d.mts +1 -1
  55. package/dist/query/primitives/coercion.mjs +2 -3
  56. package/dist/query/primitives/geo.d.mts +11 -14
  57. package/dist/query/primitives/geo.mjs +1 -2
  58. package/dist/query/primitives/indexes.d.mts +1 -1
  59. package/dist/query/primitives/indexes.mjs +1 -2
  60. package/dist/{query-defaults-BxUcSOoF.mjs → query-defaults-DwvWUjZU.mjs} +18 -54
  61. package/dist/read-model/index.d.mts +18 -21
  62. package/dist/read-model/index.mjs +3 -4
  63. package/dist/{repository-MqAP409e.d.mts → repository-B0aFVgP2.d.mts} +25 -29
  64. package/dist/retention-purge-CCd_VXUf.d.mts +38 -0
  65. package/dist/{rolldown-runtime-D7D4PA-g.mjs → rolldown-runtime-D8jQpDG7.mjs} +1 -2
  66. package/dist/search/index.d.mts +1 -1
  67. package/dist/search/index.mjs +1 -1
  68. package/dist/sync/index.d.mts +113 -17
  69. package/dist/sync/index.mjs +421 -65
  70. package/dist/tenant/index.d.mts +8 -11
  71. package/dist/tenant/index.mjs +1 -2
  72. package/dist/testkit/index.d.mts +179 -23
  73. package/dist/testkit/index.mjs +421 -23
  74. package/dist/{timestamp.plugin-DpOWavVI.mjs → timestamp.plugin-B-IJrlYb.mjs} +192 -49
  75. package/dist/{to-plain-vksRrLtc.mjs → to-plain-CEKv_ylg.mjs} +2 -4
  76. package/dist/{to-plain-o5tUY2nV.d.mts → to-plain-Do-8jTKC.d.mts} +2 -16
  77. package/dist/{transaction-DmiB4k2P.mjs → transaction-C6Oj941P.mjs} +18 -19
  78. package/dist/{type-utils-CLzRFtIA.d.mts → type-utils-CKvuewAL.d.mts} +0 -2
  79. package/dist/{update-WgeAUJ_I.mjs → update-CYaJMu6j.mjs} +13 -23
  80. package/dist/usage/index.d.mts +2 -5
  81. package/dist/usage/index.mjs +8 -6
  82. package/dist/utils/index.d.mts +8 -10
  83. package/dist/utils/index.mjs +7 -7
  84. package/dist/{validation-chain.plugin-BAeC5eVT.d.mts → validation-chain.plugin-COYrUdd8.d.mts} +150 -48
  85. package/dist/{validation-chain.plugin-DRApTmkN.mjs → validation-chain.plugin-DJplVJ12.mjs} +210 -55
  86. package/llms.txt +33 -0
  87. package/package.json +29 -25
  88. package/skills/mongokit/SKILL.md +112 -0
  89. package/skills/mongokit/references/pagination-search.md +87 -0
  90. package/skills/mongokit/references/plugins-tenancy.md +103 -0
  91. package/skills/mongokit/references/repository-api.md +83 -0
  92. package/skills/mongokit/references/transactions-outbox.md +103 -0
@@ -1,8 +1,7 @@
1
1
  import { Connection } from "mongoose";
2
2
  import { UsageStore } from "@classytic/repo-core/usage";
3
- //#region src/usage/index.d.ts
4
3
  /** Adapter-construction options. */
5
- interface MongoUsageStoreOptions {
4
+ export interface MongoUsageStoreOptions {
6
5
  /**
7
6
  * Mongoose connection. Defaults to `mongoose.connection` (the
8
7
  * default global connection). Apps using a named connection pass
@@ -18,6 +17,4 @@ interface MongoUsageStoreOptions {
18
17
  * Build a Mongo-backed usage store. Idempotent — the underlying model
19
18
  * is registered once per `(connection, modelName)` pair.
20
19
  */
21
- declare function createMongoUsageStore(options?: MongoUsageStoreOptions): UsageStore;
22
- //#endregion
23
- export { MongoUsageStoreOptions, createMongoUsageStore };
20
+ export declare function createMongoUsageStore(options?: MongoUsageStoreOptions): UsageStore;
@@ -1,6 +1,6 @@
1
- import { n as isDuplicateKeyError } from "../error-BuByZwKU.mjs";
1
+ import { n as isDuplicateKeyError } from "../error-DjdmPLWO.mjs";
2
2
  import mongoose, { Schema } from "mongoose";
3
- //#region src/usage/index.ts
3
+ // src/usage/index.ts
4
4
  /**
5
5
  * Build a Mongo-backed usage store. Idempotent — the underlying model
6
6
  * is registered once per `(connection, modelName)` pair.
@@ -8,9 +8,12 @@ import mongoose, { Schema } from "mongoose";
8
8
  function createMongoUsageStore(options = {}) {
9
9
  const { connection, collectionName = "usage_counters", modelName = "MongoUsageCounter" } = options;
10
10
  const model = getOrCreateModel(connection ?? mongoose, modelName, collectionName);
11
+ const ready = model.init();
12
+ ready.catch(() => void 0);
11
13
  return {
12
14
  name: "mongo",
13
15
  async increment(bucket, amount) {
16
+ await ready;
14
17
  const filter = {
15
18
  actor: bucket.actor,
16
19
  period: bucket.period,
@@ -28,9 +31,9 @@ function createMongoUsageStore(options = {}) {
28
31
  actor,
29
32
  period
30
33
  }).select("kind count").lean();
31
- const out = {};
32
- for (const row of rows) out[row.kind] = row.count;
33
- return out;
34
+ const sums = /* @__PURE__ */ new Map();
35
+ for (const row of rows) sums.set(row.kind, (sums.get(row.kind) ?? 0) + row.count);
36
+ return Object.fromEntries(sums);
34
37
  }
35
38
  };
36
39
  }
@@ -63,5 +66,4 @@ function getOrCreateModel(conn, modelName, collectionName) {
63
66
  }, { unique: true });
64
67
  return conn.model(modelName, schema, collectionName);
65
68
  }
66
- //#endregion
67
69
  export { createMongoUsageStore };
@@ -1,19 +1,18 @@
1
- import { _ as getMongooseProjection, a as createMemoryCache, b as createError, c as IdType, d as isObjectIdInstance, f as isValidIdForType, g as getFieldsForUser, h as filterResponseData, i as buildCrudSchemasFromMongooseSchema, l as getSchemaIdType, m as createFieldPreset, n as CrudSchemasFramework, o as LoggerConfig, p as toObjectId, r as buildCrudSchemasFromModel, s as configureLogger, t as toPlain, v as CreateErrorOptions, y as ParseDuplicateKeyOptions } from "../to-plain-o5tUY2nV.mjs";
1
+ import { _ as getMongooseProjection, a as createMemoryCache, b as createError, c as IdType, d as isObjectIdInstance, f as isValidIdForType, g as getFieldsForUser, h as filterResponseData, i as buildCrudSchemasFromMongooseSchema, l as getSchemaIdType, m as createFieldPreset, n as CrudSchemasFramework, o as LoggerConfig, p as toObjectId, r as buildCrudSchemasFromModel, s as configureLogger, t as toPlain, v as CreateErrorOptions, y as ParseDuplicateKeyOptions } from "../to-plain-Do-8jTKC.mjs";
2
2
  import { ClientSession, Model } from "mongoose";
3
- //#region src/utils/id-chunks.d.ts
4
3
  /**
5
4
  * Default slice for `$in` fan-out. Larger than `runChunkedPurge`'s 1000 on purpose:
6
5
  * a purge chunk bounds the WRITE LOCK SCOPE of each progressive strategy step, while a
7
6
  * snapshot slice bounds only the query-document size and the per-call working set —
8
7
  * 10k ObjectIds is ~120 KB of `$in`, far under every limit, at 10× fewer round trips.
9
8
  */
10
- declare const DEFAULT_ID_CHUNK = 10000;
9
+ export declare const DEFAULT_ID_CHUNK = 10000;
11
10
  /**
12
11
  * Collect the bare id values matching `filter`, streaming via a driver cursor so the
13
12
  * only O(n) allocation is the returned array itself (a `find().lean()` materializes an
14
13
  * intermediate array of `{_id}` documents first — roughly double the peak for large n).
15
14
  */
16
- declare function collectIds(model: Model<unknown>, filter: Record<string, unknown>, options?: {
15
+ export declare function collectIds(model: Model<unknown>, filter: Record<string, unknown>, options?: {
17
16
  session?: ClientSession | undefined;
18
17
  idField?: string;
19
18
  }): Promise<unknown[]>;
@@ -22,7 +21,7 @@ declare function collectIds(model: Model<unknown>, filter: Record<string, unknow
22
21
  * array. `size` must be a positive integer — sliced `$in` correctness depends on it,
23
22
  * so a nonsense size throws instead of silently degrading to one giant slice.
24
23
  */
25
- declare function idChunks<T>(ids: readonly T[], size: number): Generator<T[], void, undefined>;
24
+ export declare function idChunks<T>(ids: readonly T[], size: number): Generator<T[], void, undefined>;
26
25
  /**
27
26
  * Compose the keyset-progressed select filter: the base predicate, narrowed to rows past
28
27
  * the last committed `_id`. `cursor == null` means "from the start". Selection paired
@@ -30,7 +29,7 @@ declare function idChunks<T>(ids: readonly T[], size: number): Generator<T[], vo
30
29
  * never revisits a processed row and never skips an unprocessed one. Never mutates
31
30
  * `baseFilter`.
32
31
  */
33
- declare function keysetFilter(baseFilter: Record<string, unknown>, cursor: unknown): Record<string, unknown>;
32
+ export declare function keysetFilter(baseFilter: Record<string, unknown>, cursor: unknown): Record<string, unknown>;
34
33
  /**
35
34
  * The `_id`-ascending bounded chunk select both action ports share:
36
35
  * `find(filter).sort({_id: 1}).limit(limit).lean()`. Lean on purpose — chunk consumers
@@ -38,7 +37,7 @@ declare function keysetFilter(baseFilter: Record<string, unknown>, cursor: unkno
38
37
  * are needed (the purge port's common path); omit it for full docs (archive's readChunk,
39
38
  * anonymize-functional).
40
39
  */
41
- declare function selectKeysetChunk<T>(model: Model<T>, filter: Record<string, unknown>, limit: number, options?: {
40
+ export declare function selectKeysetChunk<T>(model: Model<T>, filter: Record<string, unknown>, limit: number, options?: {
42
41
  session?: ClientSession | undefined;
43
42
  projection?: Record<string, 1 | 0> | undefined;
44
43
  }): Promise<T[]>;
@@ -49,6 +48,5 @@ declare function selectKeysetChunk<T>(model: Model<T>, filter: Record<string, un
49
48
  * write — such a row is silently skipped instead of written outside its cohort. Both
50
49
  * action ports use this shape; use it for any select-then-write over a chunk.
51
50
  */
52
- declare function narrowToIds(baseFilter: Record<string, unknown>, ids: readonly unknown[]): Record<string, unknown>;
53
- //#endregion
54
- export { type CreateErrorOptions, type CrudSchemasFramework, DEFAULT_ID_CHUNK, type IdType, type LoggerConfig, type ParseDuplicateKeyOptions, buildCrudSchemasFromModel, buildCrudSchemasFromMongooseSchema, collectIds, configureLogger, createError, createFieldPreset, createMemoryCache, filterResponseData, getFieldsForUser, getMongooseProjection, getSchemaIdType, idChunks, isObjectIdInstance, isValidIdForType, keysetFilter, narrowToIds, selectKeysetChunk, toObjectId, toPlain };
51
+ export declare function narrowToIds(baseFilter: Record<string, unknown>, ids: readonly unknown[]): Record<string, unknown>;
52
+ export { type CreateErrorOptions, type CrudSchemasFramework, type IdType, type LoggerConfig, type ParseDuplicateKeyOptions, buildCrudSchemasFromModel, buildCrudSchemasFromMongooseSchema, configureLogger, createError, createFieldPreset, createMemoryCache, filterResponseData, getFieldsForUser, getMongooseProjection, getSchemaIdType, isObjectIdInstance, isValidIdForType, toObjectId, toPlain };
@@ -1,8 +1,8 @@
1
- import { a as toObjectId, i as isValidIdForType, r as isObjectIdInstance, t as getSchemaIdType } from "../id-resolution-BqDrk0S2.mjs";
2
- import { a as narrowToIds, i as keysetFilter, n as collectIds, o as selectKeysetChunk, r as idChunks, t as DEFAULT_ID_CHUNK } from "../id-chunks-BmAwsqNk.mjs";
3
- import { t as configureLogger } from "../logger-K7dPmu2U.mjs";
4
- import { t as createError } from "../error-BuByZwKU.mjs";
5
- import { i as getMongooseProjection, n as filterResponseData, r as getFieldsForUser, t as createFieldPreset } from "../field-selection-FSQFLpsU.mjs";
6
- import { n as createMemoryCache, t as toPlain } from "../to-plain-vksRrLtc.mjs";
7
- import { n as buildCrudSchemasFromMongooseSchema, t as buildCrudSchemasFromModel } from "../mongooseToJsonSchema-C3k4ide0.mjs";
1
+ import { t as createError } from "../error-DjdmPLWO.mjs";
2
+ import { i as getMongooseProjection, n as filterResponseData, r as getFieldsForUser, t as createFieldPreset } from "../field-selection-DPFaFw9Y.mjs";
3
+ import { a as narrowToIds, i as keysetFilter, n as collectIds, o as selectKeysetChunk, r as idChunks, t as DEFAULT_ID_CHUNK } from "../id-chunks-DH-RAZWG.mjs";
4
+ import { a as toObjectId, i as isValidIdForType, r as isObjectIdInstance, t as getSchemaIdType } from "../id-resolution-Cqh49d9J.mjs";
5
+ import { t as configureLogger } from "../logger-hbWOlj_X.mjs";
6
+ import { n as createMemoryCache, t as toPlain } from "../to-plain-CEKv_ylg.mjs";
7
+ import { n as buildCrudSchemasFromMongooseSchema, t as buildCrudSchemasFromModel } from "../mongooseToJsonSchema-DMDotz4_.mjs";
8
8
  export { DEFAULT_ID_CHUNK, buildCrudSchemasFromModel, buildCrudSchemasFromMongooseSchema, collectIds, configureLogger, createError, createFieldPreset, createMemoryCache, filterResponseData, getFieldsForUser, getMongooseProjection, getSchemaIdType, idChunks, isObjectIdInstance, isValidIdForType, keysetFilter, narrowToIds, selectKeysetChunk, toObjectId, toPlain };
@@ -1,10 +1,10 @@
1
- import { A as ObjectId, F as SortSpec, N as SelectSpec, j as PopulateSpec } from "./pagination-D6psses0.mjs";
2
- import { h as RepositoryInstance, l as Plugin, p as RepositoryContext } from "./repository-MqAP409e.mjs";
3
- import { c as ValidationChainOptions, i as Logger, l as ValidatorDefinition, o as SoftDeleteOptions, r as FieldPreset, t as CascadeOptions } from "./plugin-options-Cirmb4Kp.mjs";
1
+ import { A as ObjectId, F as SortSpec, N as SelectSpec, j as PopulateSpec } from "./pagination-BAM9cA4N.mjs";
2
+ import { h as RepositoryInstance, l as Plugin, p as RepositoryContext } from "./repository-B0aFVgP2.mjs";
3
+ import { n as RetentionPurgeEvent, r as RetentionPurgeRequest } from "./retention-purge-CCd_VXUf.mjs";
4
+ import { c as ValidationChainOptions, i as Logger, l as ValidatorDefinition, o as SoftDeleteOptions, r as FieldPreset, t as CascadeOptions } from "./plugin-options-DrNGWV5b.mjs";
4
5
  import { BulkWriteResult } from "@classytic/repo-core/repository";
5
6
  import { OffsetPaginationResult } from "@classytic/repo-core/pagination";
6
7
  import { AsyncLocalStorage } from "node:async_hooks";
7
- //#region src/plugins/aggregate-helpers.plugin.d.ts
8
8
  /**
9
9
  * Aggregate helpers plugin
10
10
  *
@@ -88,8 +88,6 @@ interface AggregateHelpersMethods {
88
88
  */
89
89
  max(field: string, query?: Record<string, unknown>, options?: Record<string, unknown>): Promise<number>;
90
90
  }
91
- //#endregion
92
- //#region src/plugins/append-only.plugin.d.ts
93
91
  interface AppendOnlyPluginOptions {
94
92
  /**
95
93
  * Mutating ops to permit besides `create` / `createMany`. Use for a
@@ -106,13 +104,26 @@ interface AppendOnlyPluginOptions {
106
104
  * "append-only", never "missing organizationId".
107
105
  */
108
106
  priority?: number | undefined;
107
+ /**
108
+ * Allow the audited retention purge: `delete` / `deleteMany` with
109
+ * `{ mode: 'hard', retentionPurge: { reason, actor? } }` (and
110
+ * `purgeByFilter` / `purgeByField` with `retentionPurge`) pass the fence,
111
+ * emitting `after:append-only-purge`. Default `false`: the option is
112
+ * refused (403 `RETENTION_PURGE_DISABLED`).
113
+ */
114
+ allowPurge?: boolean | undefined;
115
+ /**
116
+ * Allow `archiveByFilter(filter, sink, { retentionPurge })` to delete the rows its
117
+ * sink acknowledged, and nothing else: a retentionPurge delete without the run's
118
+ * attestation is still refused. Audited via `after:append-only-purge` with
119
+ * `archived: true`. Implied by `allowPurge`. Default `false`.
120
+ */
121
+ allowArchive?: boolean | undefined;
109
122
  }
123
+ /** Payload of `after:append-only-purge`: one per successful purge call. */
124
+ type AppendOnlyPurgeEvent = RetentionPurgeEvent;
110
125
  declare function appendOnlyPlugin(options?: AppendOnlyPluginOptions): Plugin;
111
- //#endregion
112
- //#region src/plugins/audit-log.plugin.d.ts
113
126
  declare function auditLogPlugin(logger: Logger): Plugin;
114
- //#endregion
115
- //#region src/plugins/batch-operations.plugin.d.ts
116
127
  /** Options accepted by `repo.bulkWrite`. Plugin context may ride alongside. */
117
128
  interface BulkWriteOptions {
118
129
  /** Stop at the first failure. Default `true`, matching the driver. */
@@ -123,6 +134,8 @@ interface BulkWriteOptions {
123
134
  comment?: unknown;
124
135
  let?: Record<string, unknown>;
125
136
  ignoreUndefined?: boolean;
137
+ /** Server-side time bound for the write. */
138
+ maxTimeMS?: number;
126
139
  /** Plugin context (tenant id, actor, ...) - spread into the op context. */
127
140
  [key: string]: unknown;
128
141
  }
@@ -144,19 +157,15 @@ interface BatchOperationsMethods {
144
157
  * ]);
145
158
  * console.log(result.insertedCount, result.modifiedCount, result.deletedCount);
146
159
  */
147
- bulkWrite(operations: Record<string, unknown>[], options?: {
160
+ bulkWrite(operations: readonly Record<string, unknown>[], options?: {
148
161
  session?: unknown;
149
162
  ordered?: boolean;
150
163
  }): Promise<BulkWriteResult>;
151
164
  }
152
- //#endregion
153
- //#region src/plugins/cascade.plugin.d.ts
154
165
  /**
155
166
  * Cascade delete plugin.
156
167
  */
157
168
  declare function cascadePlugin(options: CascadeOptions): Plugin;
158
- //#endregion
159
- //#region src/plugins/elastic.plugin.d.ts
160
169
  interface ElasticSearchOptions {
161
170
  /** Elasticsearch or OpenSearch client instance */
162
171
  client: any;
@@ -166,8 +175,6 @@ interface ElasticSearchOptions {
166
175
  idField?: string;
167
176
  }
168
177
  declare function elasticSearchPlugin(options: ElasticSearchOptions): Plugin;
169
- //#endregion
170
- //#region src/plugins/field-filter.plugin.d.ts
171
178
  /**
172
179
  * Field filter plugin that restricts fields based on user context
173
180
  *
@@ -181,8 +188,6 @@ declare function elasticSearchPlugin(options: ElasticSearchOptions): Plugin;
181
188
  * const repo = new Repository(Model, [fieldFilterPlugin(fieldPreset)]);
182
189
  */
183
190
  declare function fieldFilterPlugin(fieldPreset: FieldPreset): Plugin;
184
- //#endregion
185
- //#region src/plugins/idempotency-store.plugin.d.ts
186
191
  interface IdempotencyStorePluginOptions {
187
192
  /** Field carrying the deterministic operation key. @default `'key'` */
188
193
  keyField?: string;
@@ -323,8 +328,6 @@ interface IdempotencyStoreMethods<TProgress = Record<string, unknown>, TResult =
323
328
  * failures, lapsed-claim sweeps). Removed in mongokit 4.
324
329
  */
325
330
  declare function idempotencyStorePlugin(options?: IdempotencyStorePluginOptions): Plugin;
326
- //#endregion
327
- //#region src/plugins/immutable-states.plugin.d.ts
328
331
  /** The slice of a `before:claim` context `allowClaim` predicates see. */
329
332
  interface ImmutableClaimView {
330
333
  id: unknown;
@@ -356,6 +359,20 @@ interface ImmutableStatesPluginOptions {
356
359
  * state — keep the predicate a strict fingerprint.
357
360
  */
358
361
  allowClaim?: ((view: ImmutableClaimView) => boolean) | undefined;
362
+ /**
363
+ * Allow the audited retention purge: `delete` / `deleteMany` with
364
+ * `{ mode: 'hard', retentionPurge: { reason, actor? } }` (and
365
+ * `purgeByFilter` / `purgeByField` with `retentionPurge`) may remove frozen
366
+ * rows, emitting `after:immutable-states-purge`. Default `false`: the
367
+ * option is refused (403 `RETENTION_PURGE_DISABLED`).
368
+ */
369
+ allowPurge?: boolean | undefined;
370
+ /**
371
+ * Allow `archiveByFilter(filter, sink, { retentionPurge })` to delete frozen rows its
372
+ * sink acknowledged, and nothing else (see `appendOnlyPlugin`'s `allowArchive`).
373
+ * Implied by `allowPurge`. Default `false`.
374
+ */
375
+ allowArchive?: boolean | undefined;
359
376
  /** Domain error to throw. Default: 403 `IMMUTABLE_STATE_VIOLATION`. */
360
377
  errorFactory?: ((ctx: {
361
378
  id: unknown;
@@ -363,9 +380,14 @@ interface ImmutableStatesPluginOptions {
363
380
  state?: string | undefined;
364
381
  }) => Error) | undefined;
365
382
  }
383
+ /** Per-call purge request (`options.retentionPurge`). */
384
+ type ImmutablePurgeRequest = RetentionPurgeRequest;
385
+ /** Payload of `after:immutable-states-purge`: one per successful purge call. */
386
+ interface ImmutablePurgeEvent extends RetentionPurgeEvent {
387
+ /** The frozen states configured on the plugin. */
388
+ states: readonly string[];
389
+ }
366
390
  declare function immutableStatesPlugin(options: ImmutableStatesPluginOptions): Plugin;
367
- //#endregion
368
- //#region src/plugins/lease.plugin.d.ts
369
391
  interface LeasePluginOptions {
370
392
  /** Field carrying the row's status. @default `'status'` */
371
393
  statusField?: string;
@@ -381,7 +403,57 @@ interface LeasePluginOptions {
381
403
  doneStatus?: string;
382
404
  /** Sort fields used to pick the FIFO winner from the lease pool. @default `{ createdAt: 1 }` */
383
405
  sort?: Record<string, 1 | -1>;
406
+ /**
407
+ * Clock used by `lease` / `extend` / `release` for both the CAS
408
+ * comparison and the new expiry. A per-call `now` wins over it.
409
+ * Inject one to drive lease expiry from a test or a host `Clock`
410
+ * port. @default `() => new Date()`
411
+ */
412
+ nowFn?: () => Date;
413
+ /**
414
+ * Statuses whose expired lease `lease()` may recover. Only rows in
415
+ * one of these statuses AND with `leaseExpiresAt < now` are dead
416
+ * leases; a row in any other status is never re-leased, whatever its
417
+ * lease field says (a cancelled row with a stale expiry stays
418
+ * cancelled). @default `[processingStatus]`
419
+ */
420
+ deadLeaseStatuses?: readonly string[];
421
+ /**
422
+ * Optional attempts counter. When set, every successful `lease()`
423
+ * (first claim and dead-lease recovery alike) applies
424
+ * `$inc: { [attemptsField]: 1 }`. Off by default.
425
+ */
426
+ attemptsField?: string;
427
+ /**
428
+ * Cap on `attemptsField`. A row whose counter is already
429
+ * `>= maxAttempts` is not leasable; a row missing the field is.
430
+ * Exhausted rows stay where they are until `reapExhausted()` moves
431
+ * them to `exhaustedStatus` (or the host sweeps them itself).
432
+ * Requires `attemptsField` (throws at construction).
433
+ */
434
+ maxAttempts?: number;
435
+ /**
436
+ * Terminal status `reapExhausted()` moves an exhausted row to (e.g.
437
+ * `'failed'`). Requires `maxAttempts`; must differ from
438
+ * `pendingStatus`, `processingStatus` and every `deadLeaseStatuses`
439
+ * entry (throws at construction). Without it `reapExhausted()` needs
440
+ * a per-call `status`.
441
+ */
442
+ exhaustedStatus?: string;
443
+ /** Field `reapExhausted()` stamps with the reap time (e.g. `'failedAt'`). Off by default. */
444
+ exhaustedAtField?: string;
445
+ /**
446
+ * Extra predicate ANDed into the PENDING arm only, so not-yet-due rows
447
+ * wait while a dead lease is still recovered. The object form is
448
+ * STATIC (built once); for a time-relative predicate pass the function
449
+ * form, called per `lease()` with the resolved `now` (per-call `now`,
450
+ * else `nowFn()`): `pendingFilter: (now) => ({ dueAt: { $lte: now } })`.
451
+ * A per-call `pendingFilter` replaces this one.
452
+ */
453
+ pendingFilter?: LeasePendingFilter;
384
454
  }
455
+ /** Static pending-arm predicate, or a builder called with the claim's `now`. */
456
+ type LeasePendingFilter = Record<string, unknown> | ((now: Date) => Record<string, unknown>);
385
457
  /**
386
458
  * Methods contributed by `leasePlugin()`. Use as a type assertion when
387
459
  * constructing the repo so call sites get autocomplete:
@@ -397,9 +469,18 @@ interface LeasePluginOptions {
397
469
  interface LeaseMethods<TDoc> {
398
470
  /**
399
471
  * Atomically claim the next available row. Matches rows that are
400
- * either in `pendingStatus` OR have an expired `leaseExpiresAt` (dead
401
- * lease recovery). Sets status to `processingStatus`, stamps
402
- * `leasedBy`, and pushes `leaseExpiresAt = now + leaseFor`.
472
+ * either in `pendingStatus` (AND `pendingFilter`, when given) OR in a
473
+ * `deadLeaseStatuses` status with an expired `leaseExpiresAt` (dead
474
+ * lease recovery). The caller's `filter` is kept as given (its own
475
+ * `$or` included) and the claim condition is ANDed beside it. Sets
476
+ * status to `processingStatus`, stamps `leasedBy`, pushes
477
+ * `leaseExpiresAt = now + leaseFor`, and bumps `attemptsField` when
478
+ * configured.
479
+ *
480
+ * `leasedBy` is the fencing token for `extend` / `release`: make it
481
+ * unique per claim (e.g. `${instanceId}:${randomUUID()}`). A worker
482
+ * that reuses one id could otherwise finalise a stale run after its
483
+ * own lapsed lease was re-leased under the same id.
403
484
  *
404
485
  * @returns The leased doc, or `null` when no row matches.
405
486
  */
@@ -407,17 +488,24 @@ interface LeaseMethods<TDoc> {
407
488
  filter?: Record<string, unknown>;
408
489
  leaseFor: number;
409
490
  leasedBy: string;
491
+ /** Clock reading for this call. @default plugin `nowFn()` */
492
+ now?: Date;
493
+ /** Replaces the plugin-level `pendingFilter` for this call. */
494
+ pendingFilter?: LeasePendingFilter;
410
495
  options?: Record<string, unknown>;
411
496
  }): Promise<TDoc | null>;
412
497
  /**
413
498
  * Push a held lease's expiry further. Only succeeds when the lease
414
- * is still ours (`leasedBy === leasedBy && leaseExpiresAt > now`).
499
+ * is still ours (`leasedBy === leasedBy && leaseExpiresAt > now`) and
500
+ * the row is still in `processingStatus` (a row the host moved to a
501
+ * terminal status, e.g. cancelled, is not kept alive).
415
502
  * Returns `null` if the lease was lost — caller should drop the
416
503
  * work, since someone else has already started replaying it.
417
504
  */
418
505
  extend(id: string | ObjectId, opts: {
419
506
  leasedBy: string;
420
507
  leaseFor: number;
508
+ now?: Date;
421
509
  options?: Record<string, unknown>;
422
510
  }): Promise<TDoc | null>;
423
511
  /**
@@ -434,17 +522,48 @@ interface LeaseMethods<TDoc> {
434
522
  * `lease()` predicate) skip this row.
435
523
  *
436
524
  * Returns the released doc, or `null` when the CAS lost (lease
437
- * expired / held by another worker / row gone).
525
+ * expired / held by another worker / row gone / row no longer in
526
+ * `processingStatus`, e.g. the host cancelled it mid-run).
438
527
  */
439
528
  release(id: string | ObjectId, opts: {
440
529
  leasedBy: string;
441
530
  finalStatus?: string;
531
+ now?: Date;
442
532
  options?: Record<string, unknown>;
443
533
  }): Promise<TDoc | null>;
534
+ /**
535
+ * Move every EXHAUSTED row to `exhaustedStatus` and return the moved
536
+ * rows (after the move), so the host only audits and alerts. A row is
537
+ * exhausted when `lease()` would claim it but for the attempts cap:
538
+ * `attemptsField >= maxAttempts` AND either pending (and passing
539
+ * `pendingFilter`) or in a `deadLeaseStatuses` status whose lease
540
+ * lapsed (`leaseExpiresAt < now`). A row whose lease is still live is
541
+ * left alone: its holder may still release it.
542
+ *
543
+ * Each move is a compare-and-set on that same condition, so two
544
+ * reapers never both return a row, and a row is returned once: once
545
+ * moved it no longer matches. Clears `leasedBy` / `leaseExpiresAt`
546
+ * and stamps `exhaustedAtField` with `now` when configured. The
547
+ * caller's `filter` is ANDed in as with `lease()`. Requires
548
+ * `maxAttempts`; reads at most `limit` rows (default 100) in `sort`
549
+ * order, so call it again until it returns `[]`. A batch shorter than
550
+ * `limit` does not mean none are left: a concurrent reaper may have
551
+ * moved some of the rows read (and keeps draining them).
552
+ */
553
+ reapExhausted(opts?: {
554
+ filter?: Record<string, unknown>;
555
+ /** Clock reading for this call. @default plugin `nowFn()` */
556
+ now?: Date;
557
+ /** Rows read per call. @default 100 */
558
+ limit?: number;
559
+ /** Replaces the plugin-level `exhaustedStatus` for this call. */
560
+ status?: string;
561
+ /** Replaces the plugin-level `pendingFilter` for this call. */
562
+ pendingFilter?: LeasePendingFilter;
563
+ options?: Record<string, unknown>;
564
+ }): Promise<TDoc[]>;
444
565
  }
445
566
  declare function leasePlugin(options?: LeasePluginOptions): Plugin;
446
- //#endregion
447
- //#region src/plugins/method-registry.plugin.d.ts
448
567
  /**
449
568
  * Extended repository interface with method registry
450
569
  */
@@ -457,8 +576,6 @@ interface MethodRegistryRepository extends RepositoryInstance {
457
576
  * Method registry plugin that enables dynamic method registration
458
577
  */
459
578
  declare function methodRegistryPlugin(): Plugin;
460
- //#endregion
461
- //#region src/plugins/mongo-operations.plugin.d.ts
462
579
  /**
463
580
  * MongoDB operations plugin
464
581
  *
@@ -689,8 +806,6 @@ interface MongoOperationsMethods<TDoc> {
689
806
  */
690
807
  incrementIfBelow(id: string | ObjectId, field: string, ceiling: number, by?: number, options?: Record<string, unknown>): Promise<TDoc | null>;
691
808
  }
692
- //#endregion
693
- //#region src/plugins/observability.plugin.d.ts
694
809
  interface OperationMetric {
695
810
  /** Operation name (e.g., 'create', 'getAll', 'update') */
696
811
  operation: string;
@@ -718,8 +833,6 @@ interface ObservabilityOptions {
718
833
  slowThresholdMs?: number;
719
834
  }
720
835
  declare function observabilityPlugin(options: ObservabilityOptions): Plugin;
721
- //#endregion
722
- //#region src/plugins/search-keys.plugin.d.ts
723
836
  interface SearchKeysPluginOptions {
724
837
  /** Source fields (dotted paths allowed; string, number, or arrays of them). */
725
838
  fields: readonly string[];
@@ -727,8 +840,6 @@ interface SearchKeysPluginOptions {
727
840
  keysField?: string;
728
841
  }
729
842
  declare function searchKeysPlugin(options: SearchKeysPluginOptions): Plugin;
730
- //#endregion
731
- //#region src/plugins/soft-delete.plugin.d.ts
732
843
  /**
733
844
  * Soft delete plugin
734
845
  *
@@ -820,8 +931,6 @@ interface SoftDeleteMethods<TDoc> {
820
931
  session?: unknown;
821
932
  }): Promise<OffsetPaginationResult<TDoc>>;
822
933
  }
823
- //#endregion
824
- //#region src/plugins/subdocument.plugin.d.ts
825
934
  /**
826
935
  * Subdocument plugin for managing nested arrays
827
936
  *
@@ -902,8 +1011,6 @@ interface SubdocumentMethods<TDoc> {
902
1011
  */
903
1012
  deleteSubdocument(parentId: string | ObjectId, arrayPath: string, subId: string | ObjectId, options?: Record<string, unknown>): Promise<TDoc>;
904
1013
  }
905
- //#endregion
906
- //#region src/plugins/tenant-context.d.ts
907
1014
  interface TenantStore {
908
1015
  tenantId: string | undefined;
909
1016
  [key: string]: unknown;
@@ -924,8 +1031,6 @@ interface TenantContext {
924
1031
  readonly storage: AsyncLocalStorage<TenantStore>;
925
1032
  }
926
1033
  declare function createTenantContext(): TenantContext;
927
- //#endregion
928
- //#region src/plugins/timestamp.plugin.d.ts
929
1034
  /**
930
1035
  * Timestamp plugin that auto-injects timestamps
931
1036
  *
@@ -933,8 +1038,6 @@ declare function createTenantContext(): TenantContext;
933
1038
  * const repo = new Repository(Model, [timestampPlugin()]);
934
1039
  */
935
1040
  declare function timestampPlugin(): Plugin;
936
- //#endregion
937
- //#region src/plugins/validation-chain.plugin.d.ts
938
1041
  type OperationType = 'create' | 'createMany' | 'update' | 'findOneAndUpdate' | 'delete';
939
1042
  /**
940
1043
  * Validation chain plugin
@@ -972,5 +1075,4 @@ declare function immutableField(field: string): ValidatorDefinition;
972
1075
  * Ensure field value is unique
973
1076
  */
974
1077
  declare function uniqueField(field: string, errorMessage?: string): ValidatorDefinition;
975
- //#endregion
976
- export { immutableStatesPlugin as A, BulkWriteOptions as B, MethodRegistryRepository as C, leasePlugin as D, LeasePluginOptions as E, fieldFilterPlugin as F, appendOnlyPlugin as G, batchOperationsPlugin as H, ElasticSearchOptions as I, AggregateHelpersMethods as K, elasticSearchPlugin as L, IdempotencyStoreMethods as M, IdempotencyStorePluginOptions as N, ImmutableClaimView as O, idempotencyStorePlugin as P, cascadePlugin as R, mongoOperationsPlugin as S, LeaseMethods as T, auditLogPlugin as U, BulkWriteResult as V, AppendOnlyPluginOptions as W, searchKeysPlugin as _, requireField as a, observabilityPlugin as b, timestampPlugin as c, createTenantContext as d, SubdocumentMethods as f, SearchKeysPluginOptions as g, softDeletePlugin as h, immutableField as i, IdempotencyClaim as j, ImmutableStatesPluginOptions as k, TenantContext as l, SoftDeleteMethods as m, autoInject as n, uniqueField as o, subdocumentPlugin as p, aggregateHelpersPlugin as q, blockIf as r, validationChainPlugin as s, OperationType as t, TenantStore as u, ObservabilityOptions as v, methodRegistryPlugin as w, MongoOperationsMethods as x, OperationMetric as y, BatchOperationsMethods as z };
1078
+ export { ImmutablePurgeEvent as A, elasticSearchPlugin as B, MethodRegistryRepository as C, LeasePluginOptions as D, LeasePendingFilter as E, IdempotencyStoreMethods as F, batchOperationsPlugin as G, BatchOperationsMethods as H, IdempotencyStorePluginOptions as I, AppendOnlyPurgeEvent as J, auditLogPlugin as K, idempotencyStorePlugin as L, ImmutableStatesPluginOptions as M, immutableStatesPlugin as N, leasePlugin as O, IdempotencyClaim as P, fieldFilterPlugin as R, mongoOperationsPlugin as S, LeaseMethods as T, BulkWriteOptions as U, cascadePlugin as V, BulkWriteResult as W, AggregateHelpersMethods as X, appendOnlyPlugin as Y, aggregateHelpersPlugin as Z, searchKeysPlugin as _, requireField as a, observabilityPlugin as b, timestampPlugin as c, createTenantContext as d, SubdocumentMethods as f, SearchKeysPluginOptions as g, softDeletePlugin as h, immutableField as i, ImmutablePurgeRequest as j, ImmutableClaimView as k, TenantContext as l, SoftDeleteMethods as m, autoInject as n, uniqueField as o, subdocumentPlugin as p, AppendOnlyPluginOptions as q, blockIf as r, validationChainPlugin as s, OperationType as t, TenantStore as u, ObservabilityOptions as v, methodRegistryPlugin as w, MongoOperationsMethods as x, OperationMetric as y, ElasticSearchOptions as z };