@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,2 +1,2 @@
1
- import { c as create_d_exports, i as delete_d_exports, n as update_d_exports, r as read_d_exports, u as aggregate_d_exports } from "../index-SYF8N28D.mjs";
1
+ import { c as create_d_exports, i as delete_d_exports, n as update_d_exports, r as read_d_exports, u as aggregate_d_exports } from "../index-5mhQ63_B.mjs";
2
2
  export { aggregate_d_exports as aggregate, create_d_exports as create, delete_d_exports as deleteActions, read_d_exports as read, update_d_exports as update };
@@ -1,2 +1,2 @@
1
- export { m as aggregate, S as create, p as deleteActions, u as read, i as update } from "../update-WgeAUJ_I.mjs";
2
- import "../actions-ChYfkPYP.mjs";
1
+ export { m as aggregate, S as create, p as deleteActions, u as read, i as update } from "../update-CYaJMu6j.mjs";
2
+ import "../actions-DKQx9ToJ.mjs";
@@ -1,6 +1,6 @@
1
- import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
- import { S as create_exports, i as update_exports, m as aggregate_exports, p as delete_exports, u as read_exports } from "./update-WgeAUJ_I.mjs";
3
- //#region src/actions/index.ts
1
+ import { t as __exportAll } from "./rolldown-runtime-D8jQpDG7.mjs";
2
+ import { S as create_exports, i as update_exports, m as aggregate_exports, p as delete_exports, u as read_exports } from "./update-CYaJMu6j.mjs";
3
+ // src/actions/index.ts
4
4
  var actions_exports = /* @__PURE__ */ __exportAll({
5
5
  aggregate: () => aggregate_exports,
6
6
  create: () => create_exports,
@@ -8,5 +8,4 @@ var actions_exports = /* @__PURE__ */ __exportAll({
8
8
  read: () => read_exports,
9
9
  update: () => update_exports
10
10
  });
11
- //#endregion
12
11
  export { actions_exports as t };
@@ -2,7 +2,6 @@ import { StandardRepo } from "@classytic/repo-core/repository";
2
2
  import { Document, Model } from "mongoose";
3
3
  import { SchemaBuilderOptions, SchemaGenerator } from "@classytic/repo-core/schema";
4
4
  import { AdapterRepositoryInput, AdapterSchemaContext, AdapterValidationResult, DataAdapter, OpenApiSchemas, RepositoryLike, SchemaMetadata } from "@classytic/repo-core/adapter";
5
- //#region src/adapter/mongoose-adapter.d.ts
6
5
  interface MongooseAdapterOptions<TDoc = unknown, TModelDoc = unknown> {
7
6
  /**
8
7
  * The Mongoose model. Still a real `Model`, so a Schema or a hand-built
@@ -68,8 +67,8 @@ interface MongooseAdapterOptions<TDoc = unknown, TModelDoc = unknown> {
68
67
  * Mongoose data adapter — implements the `DataAdapter<TDoc>` contract from
69
68
  * `@classytic/repo-core/adapter`.
70
69
  */
71
- declare class MongooseAdapter<TDoc = unknown, TModelDoc = unknown> implements DataAdapter<TDoc> {
72
- readonly type: "mongoose";
70
+ export declare class MongooseAdapter<TDoc = unknown, TModelDoc = unknown> implements DataAdapter<TDoc> {
71
+ readonly type: 'mongoose';
73
72
  readonly name: string;
74
73
  /**
75
74
  * The model as given. Its document type is NOT `TDoc` — a lean repository
@@ -196,10 +195,8 @@ declare class MongooseAdapter<TDoc = unknown, TModelDoc = unknown> implements Da
196
195
  * const adapter = createMongooseAdapter(ProductModel, productRepository);
197
196
  * ```
198
197
  */
199
- declare function createMongooseAdapter<TDoc = unknown, TModelDoc = unknown>(model: Model<TModelDoc>, repository: AdapterRepositoryInput<TDoc>): DataAdapter<TDoc>;
200
- declare function createMongooseAdapter<TDoc = unknown, TModelDoc = unknown>(options: MongooseAdapterOptions<TDoc, TModelDoc>): DataAdapter<TDoc>;
201
- //#endregion
202
- //#region src/adapter/types.d.ts
198
+ export declare function createMongooseAdapter<TDoc = unknown, TModelDoc = unknown>(model: Model<TModelDoc>, repository: AdapterRepositoryInput<TDoc>): DataAdapter<TDoc>;
199
+ export declare function createMongooseAdapter<TDoc = unknown, TModelDoc = unknown>(options: MongooseAdapterOptions<TDoc, TModelDoc>): DataAdapter<TDoc>;
203
200
  /**
204
201
  * Infer document type from a Mongoose model.
205
202
  *
@@ -233,7 +230,7 @@ type MatchingModel<TDoc> = Model<TDoc & Document>;
233
230
  /**
234
231
  * Runtime guard: is `value` a Mongoose model?
235
232
  */
236
- declare function isMongooseModel(value: unknown): value is Model<Document>;
233
+ export declare function isMongooseModel(value: unknown): value is Model<Document>;
237
234
  /**
238
235
  * Mongoose SchemaType internal shape (not fully exposed by `@types/mongoose`).
239
236
  * Used to extract field metadata from schema paths.
@@ -252,5 +249,4 @@ interface MongooseSchemaType {
252
249
  };
253
250
  [key: string]: unknown;
254
251
  }
255
- //#endregion
256
- export { type CleanDoc, type InferAdapterDoc, type InferMongooseDoc, type InferRepoDoc, type MatchingModel, MongooseAdapter, type MongooseAdapterOptions, type MongooseDocument, type MongooseSchemaType, createMongooseAdapter, isMongooseModel };
252
+ export type { CleanDoc, InferAdapterDoc, InferMongooseDoc, InferRepoDoc, MatchingModel, MongooseAdapterOptions, MongooseDocument, MongooseSchemaType };
@@ -1 +1 @@
1
- export { t as MongooseAdapter, n as createMongooseAdapter, r as isMongooseModel } from "../adapter-CkMoMF83.mjs";
1
+ export { t as MongooseAdapter, n as createMongooseAdapter, r as isMongooseModel } from "../adapter-Qzgc3ZD_.mjs";
@@ -1,17 +1,16 @@
1
- import { n as warn } from "./logger-K7dPmu2U.mjs";
2
- import { t as buildCrudSchemasFromModel } from "./mongooseToJsonSchema-C3k4ide0.mjs";
1
+ import { n as warn } from "./logger-hbWOlj_X.mjs";
2
+ import { t as buildCrudSchemasFromModel } from "./mongooseToJsonSchema-DMDotz4_.mjs";
3
3
  import { matchesRecordFilter } from "@classytic/repo-core/filter";
4
4
  import { mergeFieldRuleConstraints } from "@classytic/repo-core/schema";
5
5
  import { asRepositoryLike, isRepository } from "@classytic/repo-core/adapter";
6
- //#region src/adapter/types.ts
6
+ // src/adapter/types.ts
7
7
  /**
8
8
  * Runtime guard: is `value` a Mongoose model?
9
9
  */
10
10
  function isMongooseModel(value) {
11
11
  return typeof value === "function" && value.prototype && "modelName" in value && "schema" in value;
12
12
  }
13
- //#endregion
14
- //#region src/adapter/mongoose-adapter.ts
13
+ // src/adapter/mongoose-adapter.ts
15
14
  const REQUIRED_REPO_METHODS = [
16
15
  "getAll",
17
16
  "getById",
@@ -325,5 +324,4 @@ function createMongooseAdapter(modelOrOptions, repository) {
325
324
  }
326
325
  return new MongooseAdapter(modelOrOptions);
327
326
  }
328
- //#endregion
329
327
  export { createMongooseAdapter as n, isMongooseModel as r, MongooseAdapter as t };
@@ -1,6 +1,5 @@
1
- import { l as Plugin } from "../repository-MqAP409e.mjs";
1
+ import { l as Plugin } from "../repository-B0aFVgP2.mjs";
2
2
  import { PipelineStage } from "mongoose";
3
- //#region src/ai/types.d.ts
4
3
  /** Supported similarity metrics for vector search */
5
4
  type SimilarityMetric = 'cosine' | 'euclidean' | 'dotProduct';
6
5
  /** A single piece of content to embed — text, image, or any media */
@@ -65,7 +64,11 @@ interface VectorSearchParams {
65
64
  limit?: number;
66
65
  /** Candidates to consider (higher = more accurate, slower). Default: limit * 10 */
67
66
  numCandidates?: number;
68
- /** Pre-filter documents before vector search */
67
+ /**
68
+ * Pre-filter documents before vector search (`$vectorSearch.filter`). Every path
69
+ * must be declared as a `{ type: 'filter', path }` field on the vector index.
70
+ * With `multiTenantPlugin`, the tenant clause is merged in here automatically.
71
+ */
69
72
  filter?: Record<string, unknown>;
70
73
  /** Use exact KNN instead of approximate (slower but precise) */
71
74
  exact?: boolean;
@@ -81,6 +84,19 @@ interface VectorSearchParams {
81
84
  minScore?: number;
82
85
  /** Additional pipeline stages to append after search */
83
86
  postPipeline?: PipelineStage[];
87
+ /**
88
+ * Tenant scope for `multiTenantPlugin` (default `contextKey`). `searchSimilar`
89
+ * runs the same `before:searchSimilar` policy hooks as other reads, so a
90
+ * required tenant that is missing here (and not resolved via `resolveContext`)
91
+ * throws, exactly like `getAll`.
92
+ */
93
+ organizationId?: string;
94
+ /** Per-call tenant bypass — same semantics as every other repository read. */
95
+ bypassTenant?: boolean;
96
+ /** Abort signal, checked before the policy hooks run. */
97
+ signal?: AbortSignal;
98
+ /** Any other context key a policy plugin reads (e.g. a custom `contextKey` like `branchId`). */
99
+ [contextKey: string]: unknown;
84
100
  }
85
101
  /** Vector search result with score */
86
102
  interface ScoredResult<T = Record<string, unknown>> {
@@ -128,8 +144,6 @@ interface VectorPluginOptions {
128
144
  */
129
145
  blockPrivateIpUrls?: boolean;
130
146
  }
131
- //#endregion
132
- //#region src/ai/vector.plugin.d.ts
133
147
  interface VectorMethods {
134
148
  searchSimilar<T = Record<string, unknown>>(params: VectorSearchParams): Promise<ScoredResult<T>[]>;
135
149
  embed(input: EmbeddingInput | string): Promise<number[]>;
@@ -141,6 +155,5 @@ declare function buildVectorSearchPipeline(field: VectorFieldConfig, queryVector
141
155
  /**
142
156
  * Creates the vector search plugin
143
157
  */
144
- declare function vectorPlugin(options: VectorPluginOptions): Plugin;
145
- //#endregion
146
- export { type BatchEmbedFn, type EmbedFn, type EmbeddingInput, type ScoredResult, type SimilarityMetric, type VectorFieldConfig, type VectorMethods, type VectorPluginOptions, type VectorSearchParams, buildVectorSearchPipeline, vectorPlugin };
158
+ export declare function vectorPlugin(options: VectorPluginOptions): Plugin;
159
+ export { type BatchEmbedFn, type EmbedFn, type EmbeddingInput, type ScoredResult, type SimilarityMetric, type VectorFieldConfig, type VectorMethods, type VectorPluginOptions, type VectorSearchParams, buildVectorSearchPipeline };
package/dist/ai/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { n as warn } from "../logger-K7dPmu2U.mjs";
2
- //#region src/ai/url-policy.ts
1
+ import { n as warn } from "../logger-hbWOlj_X.mjs";
2
+ // src/ai/url-policy.ts
3
3
  /**
4
4
  * URL policy helpers for the vector plugin media pipeline.
5
5
  *
@@ -72,8 +72,7 @@ function isPrivateOrLocalHost(hostname) {
72
72
  if (a === 100 && b >= 64 && b <= 127) return true;
73
73
  return false;
74
74
  }
75
- //#endregion
76
- //#region src/ai/vector-error-hints.ts
75
+ // src/ai/vector-error-hints.ts
77
76
  /**
78
77
  * Pure classifier. Takes the raw error and the context the plugin knows
79
78
  * (index name, dimensions, filter paths it tried to use) and returns a hint.
@@ -157,8 +156,7 @@ function extractErrorMessage(err) {
157
156
  }
158
157
  return String(err);
159
158
  }
160
- //#endregion
161
- //#region src/ai/vector.plugin.ts
159
+ // src/ai/vector.plugin.ts
162
160
  /** Maximum numCandidates allowed by Atlas Vector Search */
163
161
  const MAX_NUM_CANDIDATES = 1e4;
164
162
  /**
@@ -273,6 +271,12 @@ function vectorPlugin(options) {
273
271
  repo.registerMethod("searchSimilar", async function searchSimilar(params) {
274
272
  if (vectorSearchUnavailable) throw vectorSearchUnavailable;
275
273
  const field = resolveField(fields, params.field);
274
+ const { query: _query, filter: callerFilter, ...contextOptions } = params;
275
+ const scopedFilter = (await repo._buildContext("searchSimilar", {
276
+ ...contextOptions,
277
+ ...callerFilter && { filters: callerFilter }
278
+ })).filters;
279
+ const filter = scopedFilter && Object.keys(scopedFilter).length > 0 ? scopedFilter : void 0;
276
280
  let queryVector;
277
281
  if (Array.isArray(params.query)) queryVector = params.query;
278
282
  else {
@@ -281,7 +285,10 @@ function vectorPlugin(options) {
281
285
  queryVector = await embedFn(input);
282
286
  }
283
287
  if (queryVector.length !== field.dimensions) throw new Error(`[mongokit] Query vector has ${queryVector.length} dimensions, expected ${field.dimensions}`);
284
- const pipeline = buildVectorSearchPipeline(field, queryVector, params);
288
+ const pipeline = buildVectorSearchPipeline(field, queryVector, {
289
+ ...params,
290
+ filter
291
+ });
285
292
  const agg = repo.Model.aggregate(pipeline);
286
293
  if (params.session) agg.session(params.session);
287
294
  let results;
@@ -289,7 +296,7 @@ function vectorPlugin(options) {
289
296
  results = await withVectorErrorHints(() => agg.exec(), {
290
297
  indexName: field.index,
291
298
  dimensions: field.dimensions,
292
- filterPaths: params.filter ? Object.keys(params.filter) : void 0
299
+ filterPaths: filter ? Object.keys(filter) : void 0
293
300
  });
294
301
  } catch (err) {
295
302
  if (err.code === "NOT_ATLAS") vectorSearchUnavailable = err;
@@ -391,5 +398,4 @@ function vectorPlugin(options) {
391
398
  }
392
399
  };
393
400
  }
394
- //#endregion
395
401
  export { buildVectorSearchPipeline, vectorPlugin };
@@ -1,12 +1,11 @@
1
1
  import { DataAdapter, RepositoryLike } from "@classytic/repo-core/adapter";
2
2
  import { BetterAuthPluginKey, BetterAuthPluginKey as BetterAuthPluginKey$1 } from "@classytic/repo-core/better-auth";
3
- //#region src/better-auth/index.d.ts
4
3
  /**
5
4
  * Minimal structural type for the Mongoose surface this module touches.
6
5
  * Declared structurally so the file has zero runtime `import` of mongoose —
7
6
  * mongoose stays a peer dep and is never bundled with mongokit.
8
7
  */
9
- interface MongooseLike {
8
+ export interface MongooseLike {
10
9
  models: Record<string, unknown>;
11
10
  Schema: new (definition?: Record<string, unknown>, options?: Record<string, unknown>) => MongooseSchemaLike;
12
11
  model: (name: string, schema?: unknown) => MongooseModelLike;
@@ -26,7 +25,7 @@ interface MongooseModelLike {
26
25
  * `better-auth` from this module — declared as an *optional* peer in
27
26
  * package.json for hosts that import this subpath.
28
27
  */
29
- interface BetterAuthInstance {
28
+ export interface BetterAuthInstance {
30
29
  $context: Promise<{
31
30
  tables: Record<string, BATableConfig>;
32
31
  }> | {
@@ -54,11 +53,14 @@ interface BATableConfig {
54
53
  * log. Measured on a real deployment: `GET /me`, `GET /users/:id` and
55
54
  * `GET /branches/code/:code` all 404'd for rows that existed.
56
55
  *
57
- * There is no safe default that covers both, which is why this is an explicit
56
+ * - `'uuid'` - the host set `advanced.database.generateId: 'uuid'`. BA then stores real BSON UUIDs
57
+ * (not strings), and the schema needs the UUID SchemaType so a string id is cast to one.
58
+ *
59
+ * There is no safe default that covers all three, which is why this is an explicit
58
60
  * option rather than a guess: read `typeof doc._id` from a live row.
59
61
  */
60
- type BetterAuthIdType = 'objectid' | 'string';
61
- interface RegisterBetterAuthStubsOptions {
62
+ export type BetterAuthIdType = 'objectid' | 'string' | 'uuid';
63
+ export interface RegisterBetterAuthStubsOptions {
62
64
  /** Plugin sets to include. `core` is always implied. */
63
65
  plugins?: BetterAuthPluginKey$1[];
64
66
  /** How BA stores `_id` — see {@link BetterAuthIdType}. Default `'objectid'`. */
@@ -102,8 +104,8 @@ interface RegisterBetterAuthStubsOptions {
102
104
  * @returns the model names that were newly registered (excluding any that
103
105
  * already existed on `mongoose.models`).
104
106
  */
105
- declare function registerBetterAuthStubs(mongoose: MongooseLike, options?: RegisterBetterAuthStubsOptions): string[];
106
- interface BetterAuthOverlayOptions<TDoc = Record<string, unknown>> {
107
+ export declare function registerBetterAuthStubs(mongoose: MongooseLike, options?: RegisterBetterAuthStubsOptions): string[];
108
+ export interface BetterAuthOverlayOptions<TDoc = Record<string, unknown>> {
107
109
  /** A `betterAuth()` instance. Used to read the resolved schema (`auth.$context.tables`). */
108
110
  auth: BetterAuthInstance;
109
111
  /** Mongoose instance — passed in to keep mongoose a peer dep. */
@@ -206,7 +208,7 @@ interface BetterAuthOverlayOptions<TDoc = Record<string, unknown>> {
206
208
  * registered on `mongoose.models` from a prior call (re-registration
207
209
  * would silently drop this call's `additionalFields` / `indexes`).
208
210
  */
209
- declare function createBetterAuthOverlay<TDoc = Record<string, unknown>>(options: BetterAuthOverlayOptions<TDoc>): Promise<DataAdapter<TDoc>>;
211
+ export declare function createBetterAuthOverlay<TDoc = Record<string, unknown>>(options: BetterAuthOverlayOptions<TDoc>): Promise<DataAdapter<TDoc>>;
210
212
  /**
211
213
  * Minimal structural surface for the one write we need. Satisfied by BOTH a
212
214
  * native MongoDB `Collection` (`db.collection('session')`) and a Mongoose
@@ -239,7 +241,7 @@ declare function createBetterAuthOverlay<TDoc = Record<string, unknown>>(options
239
241
  * the attempt failed (logged by the caller, never thrown — a missing
240
242
  * TTL degrades storage, and refusing to boot over it is worse).
241
243
  */
242
- declare function ensureBetterAuthSessionTtl(connection: {
244
+ export declare function ensureBetterAuthSessionTtl(connection: {
243
245
  collection(name: string): {
244
246
  createIndex(keys: Record<string, 1>, opts: Record<string, unknown>): Promise<unknown>;
245
247
  };
@@ -255,7 +257,7 @@ declare function ensureBetterAuthSessionTtl(connection: {
255
257
  * because failing a boot over historical duplicates is worse than running with
256
258
  * a plain lookup index and reporting the degradation.
257
259
  */
258
- interface BetterAuthIndexSpec {
260
+ export interface BetterAuthIndexSpec {
259
261
  /** Canonical collection name (`'user'`, `'session'`, ...). */
260
262
  collection: string;
261
263
  keys: Record<string, 1 | -1>;
@@ -280,16 +282,16 @@ interface BetterAuthIndexSpec {
280
282
  * TTL entries (`expiresAt`) additionally keep the collection BOUNDED — see
281
283
  * {@link ensureBetterAuthSessionTtl} for the measurements that motivated it.
282
284
  */
283
- declare const BA_INDEXES_BY_PLUGIN: Record<string, readonly BetterAuthIndexSpec[]>;
285
+ export declare const BA_INDEXES_BY_PLUGIN: Record<string, readonly BetterAuthIndexSpec[]>;
284
286
  /** Outcome of one declared index. */
285
- interface BetterAuthIndexResult {
287
+ export interface BetterAuthIndexResult {
286
288
  collection: string;
287
289
  name: string;
288
290
  status: 'created' | 'degraded' | 'failed';
289
291
  /** Set on `degraded` (unique dropped) and `failed`. */
290
292
  reason?: string;
291
293
  }
292
- interface EnsureBetterAuthIndexesOptions {
294
+ export interface EnsureBetterAuthIndexesOptions {
293
295
  /** Plugin sets to include beyond `core` (always implied). */
294
296
  plugins?: BetterAuthPluginKey$1[];
295
297
  /** Mirror BA's `usePlural` — appends `s` to every collection name. */
@@ -299,7 +301,7 @@ interface EnsureBetterAuthIndexesOptions {
299
301
  /** Canonical collection names to skip entirely. */
300
302
  exclude?: string[];
301
303
  }
302
- interface IndexCreator {
304
+ export interface IndexCreator {
303
305
  collection(name: string): {
304
306
  createIndex(keys: Record<string, 1 | -1>, opts: Record<string, unknown>): Promise<unknown>;
305
307
  };
@@ -323,8 +325,8 @@ interface IndexCreator {
323
325
  *
324
326
  * Call once at boot, after the connection is live. Safe to call again.
325
327
  */
326
- declare function ensureBetterAuthIndexes(connection: IndexCreator, options?: EnsureBetterAuthIndexesOptions): Promise<BetterAuthIndexResult[]>;
327
- interface SessionUpdaterLike {
328
+ export declare function ensureBetterAuthIndexes(connection: IndexCreator, options?: EnsureBetterAuthIndexesOptions): Promise<BetterAuthIndexResult[]>;
329
+ export interface SessionUpdaterLike {
328
330
  updateMany(filter: Record<string, unknown>, update: Record<string, unknown>): Promise<{
329
331
  modifiedCount?: number;
330
332
  }>;
@@ -354,8 +356,7 @@ interface SessionUpdaterLike {
354
356
  *
355
357
  * @returns the number of sessions whose pointer was cleared.
356
358
  */
357
- declare function clearActiveOrganizationFromSessions(sessions: SessionUpdaterLike, organizationId: string, options?: {
359
+ export declare function clearActiveOrganizationFromSessions(sessions: SessionUpdaterLike, organizationId: string, options?: {
358
360
  userId?: unknown;
359
361
  }): Promise<number>;
360
- //#endregion
361
- export { BA_INDEXES_BY_PLUGIN, BetterAuthIdType, BetterAuthIndexResult, BetterAuthIndexSpec, BetterAuthInstance, BetterAuthOverlayOptions, type BetterAuthPluginKey, EnsureBetterAuthIndexesOptions, IndexCreator, MongooseLike, RegisterBetterAuthStubsOptions, SessionUpdaterLike, clearActiveOrganizationFromSessions, createBetterAuthOverlay, ensureBetterAuthIndexes, ensureBetterAuthSessionTtl, registerBetterAuthStubs };
362
+ export type { BetterAuthPluginKey };
@@ -1,8 +1,8 @@
1
- import { n as Repository } from "../Repository-Dj6xqPxJ.mjs";
2
- import { n as createMongooseAdapter } from "../adapter-CkMoMF83.mjs";
1
+ import { n as createMongooseAdapter } from "../adapter-Qzgc3ZD_.mjs";
2
+ import { n as Repository } from "../Repository-DheA7oW-.mjs";
3
3
  import { asReadOnlyRepo } from "@classytic/repo-core/repository";
4
4
  import { pluralizeBetterAuthCollection, resolveBetterAuthCollections } from "@classytic/repo-core/better-auth";
5
- //#region src/better-auth/index.ts
5
+ // src/better-auth/index.ts
6
6
  /**
7
7
  * Field key with ORDER PRESERVED — a compound index is identified by its key sequence.
8
8
  * `{ organizationId: 1, createdAt: -1 }` is a DIFFERENT index from `{ createdAt: -1, organizationId: 1 }`
@@ -42,7 +42,9 @@ function missingIndexesOn(existing, declared) {
42
42
  }
43
43
  /** The `_id` path for a stub/overlay schema, or `{}` to inherit mongoose's ObjectId default. */
44
44
  function idPath(idType) {
45
- return idType === "string" ? { _id: { type: String } } : {};
45
+ if (idType === "string") return { _id: { type: String } };
46
+ if (idType === "uuid") return { _id: { type: "UUID" } };
47
+ return {};
46
48
  }
47
49
  /**
48
50
  * Register stub Mongoose models for Better Auth's collections so that
@@ -331,24 +333,12 @@ const BA_INDEXES_BY_PLUGIN = {
331
333
  keys: { userId: 1 },
332
334
  name: "ba_twoFactor_userId"
333
335
  }],
334
- deviceAuthorization: [
335
- {
336
- collection: "deviceCode",
337
- keys: { deviceCode: 1 },
338
- name: "ba_deviceCode_code"
339
- },
340
- {
341
- collection: "deviceCode",
342
- keys: { userCode: 1 },
343
- name: "ba_deviceCode_userCode"
344
- },
345
- {
346
- collection: "deviceCode",
347
- keys: { expiresAt: 1 },
348
- name: "ttl_deviceCode_expiresAt",
349
- ttl: true
350
- }
351
- ]
336
+ deviceAuthorization: [{
337
+ collection: "deviceCode",
338
+ keys: { expiresAt: 1 },
339
+ name: "ttl_deviceCode_expiresAt",
340
+ ttl: true
341
+ }]
352
342
  };
353
343
  /**
354
344
  * Create every index Better Auth's queries need. Idempotent, never throws.
@@ -462,5 +452,4 @@ async function clearActiveOrganizationFromSessions(sessions, organizationId, opt
462
452
  if (options?.userId != null) filter.userId = options.userId;
463
453
  return (await sessions.updateMany(filter, { $set: { activeOrganizationId: null } })).modifiedCount ?? 0;
464
454
  }
465
- //#endregion
466
455
  export { BA_INDEXES_BY_PLUGIN, clearActiveOrganizationFromSessions, createBetterAuthOverlay, ensureBetterAuthIndexes, ensureBetterAuthSessionTtl, registerBetterAuthStubs };
@@ -1,4 +1,3 @@
1
- //#region src/query/primitives/coercion.d.ts
2
1
  /**
3
2
  * Value coercion primitives
4
3
  *
@@ -102,5 +101,4 @@ declare function coerceToType(value: unknown, type: FieldType): unknown;
102
101
  * preserves-pre-3.5.5-behavior fallback).
103
102
  */
104
103
  declare function coerceFieldValue(field: string, value: unknown, types: Map<string, FieldType>): unknown;
105
- //#endregion
106
104
  export { coerceHeuristic as a, coerceFieldValue as i, SchemaPathsLike as n, coerceToType as o, buildFieldTypeMap as r, normalizeMongooseType as s, FieldType as t };
@@ -1,7 +1,7 @@
1
- import { n as Repository } from "./Repository-Dj6xqPxJ.mjs";
2
- import { b as auditLogPlugin, g as cachePlugin, i as multiTenantPlugin, l as customIdPlugin, n as softDeletePlugin, t as timestampPlugin, v as auditTrailPlugin } from "./timestamp.plugin-DpOWavVI.mjs";
3
- import { n as batchOperationsPlugin, t as methodRegistryPlugin } from "./method-registry.plugin-C63pGn1d.mjs";
4
- //#region src/create-repository.ts
1
+ import { S as auditTrailPlugin, b as cachePlugin, d as customIdPlugin, i as multiTenantPlugin, n as softDeletePlugin, t as timestampPlugin, w as auditLogPlugin } from "./timestamp.plugin-B-IJrlYb.mjs";
2
+ import { n as batchOperationsPlugin, t as methodRegistryPlugin } from "./method-registry.plugin-BeJfQBJV.mjs";
3
+ import { n as Repository } from "./Repository-DheA7oW-.mjs";
4
+ // src/create-repository.ts
5
5
  function isLoggerAudit(value) {
6
6
  const v = value;
7
7
  return typeof v.info === "function" || typeof v.warn === "function" || typeof v.error === "function" || typeof v.debug === "function";
@@ -26,5 +26,4 @@ function createRepository(model, config = {}) {
26
26
  ...repositoryOptions
27
27
  });
28
28
  }
29
- //#endregion
30
29
  export { createRepository as t };
@@ -1,10 +1,9 @@
1
- import { u as PaginationConfig } from "./pagination-D6psses0.mjs";
2
- import { _ as RepositoryOptions, d as PluginType } from "./repository-MqAP409e.mjs";
3
- import { D as AuditTrailOptions, i as CustomIdOptions, t as MultiTenantOptions, y as RepositoryCachePluginOptions } from "./multi-tenant.plugin-B_q9NUHc.mjs";
4
- import { r as Repository } from "./Repository-DnL4xk5w.mjs";
5
- import { i as Logger, o as SoftDeleteOptions } from "./plugin-options-Cirmb4Kp.mjs";
1
+ import { L as AuditTrailOptions, i as CustomIdOptions, k as RepositoryCachePluginOptions, t as MultiTenantOptions } from "./multi-tenant.plugin-BTPtCLNK.mjs";
2
+ import { r as Repository } from "./Repository-DJuRmBNx.mjs";
3
+ import { u as PaginationConfig } from "./pagination-BAM9cA4N.mjs";
4
+ import { i as Logger, o as SoftDeleteOptions } from "./plugin-options-DrNGWV5b.mjs";
5
+ import { _ as RepositoryOptions, d as PluginType } from "./repository-B0aFVgP2.mjs";
6
6
  import { Model } from "mongoose";
7
- //#region src/create-repository.d.ts
8
7
  /**
9
8
  * Audit config — either a `Logger` (routes to `auditLogPlugin`, which
10
9
  * writes structured log lines through your logger) or an
@@ -50,5 +49,4 @@ interface CreateRepositoryConfig extends RepositoryOptions {
50
49
  * ordering guarantees and an example.
51
50
  */
52
51
  declare function createRepository<TDoc>(model: Model<TDoc, any, any, any>, config?: CreateRepositoryConfig): Repository<TDoc>;
53
- //#endregion
54
52
  export { CreateRepositoryConfig as n, createRepository as r, AuditConfig as t };
@@ -1,4 +1,4 @@
1
- //#region src/search/normalize.ts
1
+ // src/search/normalize.ts
2
2
  /**
3
3
  * Search-as-you-type text rules, shared by the WRITER (the search keys stored on
4
4
  * every document) and the READER (the query typed into a search box).
@@ -97,8 +97,7 @@ function findSearchMatches(text, query) {
97
97
  }
98
98
  return out;
99
99
  }
100
- //#endregion
101
- //#region src/search/prefix.ts
100
+ // src/search/prefix.ts
102
101
  /**
103
102
  * Indexed search-as-you-type (`searchMode: 'prefix'`): the stored keys, the
104
103
  * query filter, and the index/schema declarations. Pure: no mongoose import.
@@ -228,8 +227,7 @@ function searchKeysIndex(field = DEFAULT_SEARCH_KEYS_FIELD, options = {}) {
228
227
  options: { name: options.name ?? `${field}_1` }
229
228
  };
230
229
  }
231
- //#endregion
232
- //#region src/search/derive.ts
230
+ // src/search/derive.ts
233
231
  /**
234
232
  * How a write changes the search fields: the pure analysis behind the
235
233
  * search-keys plugin. Given one write (a document, a replacement, or an update
@@ -371,5 +369,4 @@ function fieldValuesOf(doc, fields) {
371
369
  function keysFromValues(values, fields) {
372
370
  return collectSearchTokens(fields.map((f) => values[f]));
373
371
  }
374
- //#endregion
375
372
  export { tokenizeSearchText as _, insertValues as a, writeKeys as c, buildSearchKeys as d, prefixSearchFilter as f, normalizeSearchText as g, findSearchMatches as h, fieldValuesOf as i, DEFAULT_SEARCH_KEYS_FIELD as l, searchKeysPath as m, SearchKeysWriteError as n, keysFromValues as o, searchKeysIndex as p, analyzeUpdate as r, unresolvedForUpdate as s, SEARCH_KEYS_ERROR_CODES as t, MAX_PREFIX_SEARCH_TERMS as u };
@@ -1,4 +1,4 @@
1
- //#region src/utils/error.ts
1
+ // src/utils/error.ts
2
2
  /**
3
3
  * Creates an error with HTTP status code, plus optional stable `code` /
4
4
  * `meta` so callers can `catch` on the code instead of regex-matching the
@@ -71,5 +71,4 @@ function parseDuplicateKeyError(error, options = {}) {
71
71
  };
72
72
  return httpError;
73
73
  }
74
- //#endregion
75
74
  export { isDuplicateKeyError as n, parseDuplicateKeyError as r, createError as t };
@@ -1,4 +1,4 @@
1
- //#region src/utils/field-selection.ts
1
+ // src/utils/field-selection.ts
2
2
  /**
3
3
  * Get allowed fields for a user based on their context
4
4
  *
@@ -95,5 +95,4 @@ function createFieldPreset(config) {
95
95
  admin: config.admin || []
96
96
  };
97
97
  }
98
- //#endregion
99
98
  export { getMongooseProjection as i, filterResponseData as n, getFieldsForUser as r, createFieldPreset as t };
@@ -1,4 +1,4 @@
1
- //#region src/utils/id-chunks.ts
1
+ // src/utils/id-chunks.ts
2
2
  /**
3
3
  * Default slice for `$in` fan-out. Larger than `runChunkedPurge`'s 1000 on purpose:
4
4
  * a purge chunk bounds the WRITE LOCK SCOPE of each progressive strategy step, while a
@@ -35,9 +35,18 @@ function* idChunks(ids, size) {
35
35
  * `baseFilter`.
36
36
  */
37
37
  function keysetFilter(baseFilter, cursor) {
38
- return cursor == null ? baseFilter : {
38
+ return cursor == null ? baseFilter : withIdPredicate(baseFilter, { $gt: cursor });
39
+ }
40
+ /**
41
+ * `baseFilter` AND an `_id` predicate. A base that already constrains `_id` (an ID-bounded
42
+ * purge: `{ _id: { $nin: keep } }`, `{ _id: { $lte: last } }`) is combined with `$and`;
43
+ * spreading would REPLACE the caller's `_id` predicate with the chunk's, so every chunk after
44
+ * the first would escape the caller's bound. Without a base `_id` the flat shape is kept.
45
+ */
46
+ function withIdPredicate(baseFilter, idPredicate) {
47
+ return Object.hasOwn(baseFilter, "_id") ? { $and: [baseFilter, { _id: idPredicate }] } : {
39
48
  ...baseFilter,
40
- _id: { $gt: cursor }
49
+ _id: idPredicate
41
50
  };
42
51
  }
43
52
  /**
@@ -58,10 +67,6 @@ async function selectKeysetChunk(model, filter, limit, options = {}) {
58
67
  * action ports use this shape; use it for any select-then-write over a chunk.
59
68
  */
60
69
  function narrowToIds(baseFilter, ids) {
61
- return {
62
- ...baseFilter,
63
- _id: { $in: ids }
64
- };
70
+ return withIdPredicate(baseFilter, { $in: ids });
65
71
  }
66
- //#endregion
67
72
  export { narrowToIds as a, keysetFilter as i, collectIds as n, selectKeysetChunk as o, idChunks as r, DEFAULT_ID_CHUNK as t };
@@ -1,5 +1,5 @@
1
1
  import mongoose from "mongoose";
2
- //#region src/utils/id-resolution.ts
2
+ // src/utils/id-resolution.ts
3
3
  /**
4
4
  * ID Resolution Primitive
5
5
  *
@@ -113,5 +113,4 @@ function idVariants(id) {
113
113
  if (typeof id === "string" && id.length > 0 && mongoose.Types.ObjectId.isValid(id)) return [id, new mongoose.Types.ObjectId(id)];
114
114
  return [id];
115
115
  }
116
- //#endregion
117
116
  export { toObjectId as a, isValidIdForType as i, idVariants as n, isObjectIdInstance as r, getSchemaIdType as t };
@@ -1,13 +1,12 @@
1
1
  import { Connection, Model } from "mongoose";
2
2
  import { IdempotencyClaimStore } from "@classytic/repo-core/idempotency";
3
- //#region src/idempotency/index.d.ts
4
- interface IdempotencyModelOptions {
3
+ export interface IdempotencyModelOptions {
5
4
  /** Collection name. Default `idempotency_claims`. */
6
5
  collection?: string;
7
6
  /** Mongoose model name. Default `IdempotencyClaim`. Must be unique per connection. */
8
7
  modelName?: string;
9
8
  }
10
- interface IdempotencyStoreOptions {
9
+ export interface IdempotencyStoreOptions {
11
10
  /**
12
11
  * How long a claim is kept after its last write before the TTL monitor removes it.
13
12
  * Default 7 days. Size it to the longest a caller may retry — a retry after the claim
@@ -16,8 +15,6 @@ interface IdempotencyStoreOptions {
16
15
  retentionSeconds?: number;
17
16
  }
18
17
  /** Build (or return) the claims model on `connection`. Idempotent per connection. */
19
- declare function createIdempotencyModel(connection: Connection, options?: IdempotencyModelOptions): Model<Record<string, unknown>>;
18
+ export declare function createIdempotencyModel(connection: Connection, options?: IdempotencyModelOptions): Model<Record<string, unknown>>;
20
19
  /** The store over a model from {@link createIdempotencyModel}. */
21
- declare function createIdempotencyStore(model: Model<Record<string, unknown>>, options?: IdempotencyStoreOptions): IdempotencyClaimStore;
22
- //#endregion
23
- export { IdempotencyModelOptions, IdempotencyStoreOptions, createIdempotencyModel, createIdempotencyStore };
20
+ export declare function createIdempotencyStore(model: Model<Record<string, unknown>>, options?: IdempotencyStoreOptions): IdempotencyClaimStore;
@@ -1,6 +1,6 @@
1
1
  import { Schema } from "mongoose";
2
2
  import { identityKey } from "@classytic/repo-core/idempotency";
3
- //#region src/idempotency/index.ts
3
+ // src/idempotency/index.ts
4
4
  /**
5
5
  * The mongo {@link IdempotencyClaimStore} — use this with `runIdempotent` from
6
6
  * `@classytic/repo-core/idempotency`; never keep a per-module claims table.
@@ -130,5 +130,4 @@ function createIdempotencyStore(model, options = {}) {
130
130
  }
131
131
  };
132
132
  }
133
- //#endregion
134
133
  export { createIdempotencyModel, createIdempotencyStore };