@classytic/mongokit 3.41.0 → 3.43.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 (31) hide show
  1. package/README.md +28 -0
  2. package/dist/{Repository-DlhPbXlG.mjs → Repository-Dj6xqPxJ.mjs} +148 -1
  3. package/dist/{Repository-pnLw1rG5.d.mts → Repository-DnL4xk5w.d.mts} +10 -2
  4. package/dist/ai/index.d.mts +1 -1
  5. package/dist/better-auth/index.mjs +1 -1
  6. package/dist/{create-repository-BUx9vfG9.d.mts → create-repository-CJtVdwig.d.mts} +4 -4
  7. package/dist/{create-repository-Bg0H5rte.mjs → create-repository-UjwPWR1z.mjs} +2 -2
  8. package/dist/derive-DRBiegRH.mjs +375 -0
  9. package/dist/index-C0AjVqX3.d.mts +169 -0
  10. package/dist/index.d.mts +37 -8
  11. package/dist/index.mjs +53 -5
  12. package/dist/{multi-tenant.plugin-a3UhQARj.d.mts → multi-tenant.plugin-B_q9NUHc.d.mts} +1 -1
  13. package/dist/outbox/index.d.mts +1 -1
  14. package/dist/outbox/index.mjs +1 -1
  15. package/dist/{plugin-options-CRhIvSzx.d.mts → plugin-options-Cirmb4Kp.d.mts} +1 -1
  16. package/dist/plugins/index.d.mts +4 -4
  17. package/dist/plugins/index.mjs +50 -18
  18. package/dist/read-model/index.d.mts +1 -1
  19. package/dist/{repository-DNHfjAZX.d.mts → repository-MqAP409e.d.mts} +14 -3
  20. package/dist/search/index.d.mts +2 -0
  21. package/dist/search/index.mjs +2 -0
  22. package/dist/sync/index.d.mts +22 -1
  23. package/dist/sync/index.mjs +236 -61
  24. package/dist/testkit/index.d.mts +2 -2
  25. package/dist/testkit/index.mjs +1 -1
  26. package/dist/{timestamp.plugin-DvZlnKEc.mjs → timestamp.plugin-DpOWavVI.mjs} +1 -1
  27. package/dist/{to-plain-CjgEInWV.d.mts → to-plain-o5tUY2nV.d.mts} +2 -2
  28. package/dist/utils/index.d.mts +1 -1
  29. package/dist/{validation-chain.plugin-CTcNJCmV.d.mts → validation-chain.plugin-BAeC5eVT.d.mts} +12 -3
  30. package/dist/{validation-chain.plugin-D1WsGCYr.mjs → validation-chain.plugin-DRApTmkN.mjs} +3 -2
  31. package/package.json +6 -2
@@ -0,0 +1,375 @@
1
+ //#region src/search/normalize.ts
2
+ /**
3
+ * Search-as-you-type text rules, shared by the WRITER (the search keys stored on
4
+ * every document) and the READER (the query typed into a search box).
5
+ *
6
+ * Both sides MUST run the same function, otherwise a key written as `mohammed`
7
+ * is never found by a query normalised to `Mohammed`. That is also why this
8
+ * module is pure (no mongoose, no driver): a portal or mobile client imports it
9
+ * from `@classytic/mongokit/search` to highlight matches with the exact rules
10
+ * the server indexed with.
11
+ *
12
+ * Rules, in order:
13
+ * 1. lower-case (before NFKD: `'İ'.toLowerCase()` yields a combining dot the
14
+ * next step removes);
15
+ * 2. Unicode NFKD, then every combining mark (`\p{M}`) dropped: `é → e`,
16
+ * `fi → fi`, and Arabic tashkeel (fatha, damma, kasra, shadda, sukun,
17
+ * tanween, superscript alef) disappear;
18
+ * 3. Arabic folding: tatweel removed; `أ إ آ ٱ → ا` (the hamza/madda forms
19
+ * decompose to bare alef in step 2, wasla is folded here); `ى → ي`;
20
+ * `ة → ه`; Arabic-Indic and Persian digits → ASCII digits;
21
+ * 4. format characters (`\p{Cf}`: ZWJ, ZWNJ, bidi marks) removed so a pasted
22
+ * name does not split or miss;
23
+ * 5. split on anything that is not a letter or a digit (whitespace and
24
+ * punctuation: `al-harbi` → `al`, `harbi`; `noura.saad@x.io` → `noura`,
25
+ * `saad`, `x`, `io`).
26
+ */
27
+ /** Characters folded after the mark strip (step 3). */
28
+ const FOLD = {
29
+ ٱ: "ا",
30
+ ى: "ي",
31
+ ة: "ه"
32
+ };
33
+ const MARKS = /\p{M}+/gu;
34
+ /** Tatweel (kashida) and format characters (ZWJ/ZWNJ, bidi controls). */
35
+ const DROPPED = /[ـ\p{Cf}]+/gu;
36
+ const FOLDED = /[ٱىة٠-٩۰-۹]/gu;
37
+ const SEPARATORS = /[^\p{L}\p{N}]+/u;
38
+ function foldChar(ch) {
39
+ const code = ch.charCodeAt(0);
40
+ if (code >= 1632 && code <= 1641) return String(code - 1632);
41
+ if (code >= 1776 && code <= 1785) return String(code - 1776);
42
+ return FOLD[ch] ?? ch;
43
+ }
44
+ /**
45
+ * The search tokens of `text`, in order, duplicates kept. Empty for blank text
46
+ * or text with no letters/digits.
47
+ *
48
+ * @example tokenizeSearchText(' Mohammed AL-Harbi ') // ['mohammed', 'al', 'harbi']
49
+ * @example tokenizeSearchText('مُحَمَّد أحمد') // ['محمد', 'احمد']
50
+ */
51
+ function tokenizeSearchText(text) {
52
+ if (typeof text !== "string" || text.length === 0) return [];
53
+ return text.toLowerCase().normalize("NFKD").replace(MARKS, "").replace(DROPPED, "").replace(FOLDED, foldChar).split(SEPARATORS).filter((t) => t.length > 0);
54
+ }
55
+ /**
56
+ * `text` normalised to its tokens joined by single spaces: the canonical form to
57
+ * compare or display ("what the index sees").
58
+ *
59
+ * @example normalizeSearchText('Café Crème') // 'cafe creme'
60
+ */
61
+ function normalizeSearchText(text) {
62
+ return tokenizeSearchText(text).join(" ");
63
+ }
64
+ /** A run of the original text that can hold a token (letters, digits, and the marks/tatweel/format chars the normaliser drops). */
65
+ const WORD = /[\p{L}\p{N}\p{M}ـ\p{Cf}]+/gu;
66
+ /**
67
+ * Where `query` matches `text` under the prefix-search rules: for every word of
68
+ * `text` whose normalised form starts with one of the query's tokens, the
69
+ * shortest leading run of the ORIGINAL characters that covers that token.
70
+ * Offsets index the original string, so a client wraps them in `<mark>` with no
71
+ * re-normalisation of its own.
72
+ *
73
+ * @example findSearchMatches('Mohammed Al-Harbi', 'moh har')
74
+ * // [{ start: 0, end: 3 }, { start: 12, end: 15 }]
75
+ */
76
+ function findSearchMatches(text, query) {
77
+ const terms = [...new Set(tokenizeSearchText(query))];
78
+ if (terms.length === 0 || typeof text !== "string") return [];
79
+ const out = [];
80
+ for (const m of text.matchAll(WORD)) {
81
+ const word = m[0];
82
+ const start = m.index ?? 0;
83
+ const normalized = tokenizeSearchText(word).join("");
84
+ let best = 0;
85
+ for (const term of terms) {
86
+ if (!normalized.startsWith(term)) continue;
87
+ for (let len = 1; len <= word.length; len += 1) if (tokenizeSearchText(word.slice(0, len)).join("").length >= term.length) {
88
+ while (len < word.length && tokenizeSearchText(word.slice(len, len + 1)).length === 0) len += 1;
89
+ best = Math.max(best, len);
90
+ break;
91
+ }
92
+ }
93
+ if (best > 0) out.push({
94
+ start,
95
+ end: start + best
96
+ });
97
+ }
98
+ return out;
99
+ }
100
+ //#endregion
101
+ //#region src/search/prefix.ts
102
+ /**
103
+ * Indexed search-as-you-type (`searchMode: 'prefix'`): the stored keys, the
104
+ * query filter, and the index/schema declarations. Pure: no mongoose import.
105
+ *
106
+ * ## Storage choice: word tokens + anchored regex (not edge n-grams)
107
+ *
108
+ * Each document stores the DISTINCT normalised word tokens of its search fields
109
+ * in one array field (`_searchKeys` by default), covered by a multikey index. A
110
+ * query token `moh` becomes `{ _searchKeys: { $regex: '^moh' } }`: a
111
+ * case-sensitive regex with a literal prefix, which the planner turns into the
112
+ * index range `["moh", "moi")` (IXSCAN, keys examined ≈ matches). Several query
113
+ * tokens AND together, one `$and` arm each; the planner bounds one arm and
114
+ * filters the rest on the fetched documents.
115
+ *
116
+ * The alternative, edge n-grams (`m, mo, moh, ..., mohammed` stored, matched by
117
+ * an exact `$all`), gives the SAME index-range query plan, only with point
118
+ * bounds, while storing one key per prefix length instead of one per word.
119
+ * Measured on 2,000 two-to-three-word names (mongod 8, WiredTiger; see
120
+ * `tests/integration/prefix-search.test.ts`): tokens 6,000 keys / 60 KiB index,
121
+ * edge n-grams (N=20) 34,140 keys / 256 KiB index, ~5.7x the keys and ~4x the
122
+ * index bytes. N-grams also cost a write amplification on every
123
+ * rename, and an arbitrary cut-off N past which longer prefixes stop matching.
124
+ * Tokens keep the index small, have no length cliff, and make the backfill a
125
+ * pure function of the source fields. So tokens are the standard here.
126
+ */
127
+ /** Default name of the field that stores the search keys. */
128
+ const DEFAULT_SEARCH_KEYS_FIELD = "_searchKeys";
129
+ /** Query tokens beyond this many are ignored (each one is an `$and` arm). */
130
+ const MAX_PREFIX_SEARCH_TERMS = 8;
131
+ /** Every value at a dotted `path` of `doc`, arrays flattened (`contacts.name` over an array of contacts). */
132
+ function valuesAtPath(doc, path) {
133
+ const parts = path.split(".");
134
+ const out = [];
135
+ const walk = (value, i) => {
136
+ if (value === void 0 || value === null) return;
137
+ if (Array.isArray(value)) {
138
+ for (const item of value) walk(item, i);
139
+ return;
140
+ }
141
+ if (i === parts.length) {
142
+ out.push(value);
143
+ return;
144
+ }
145
+ if (typeof value !== "object") return;
146
+ walk(value[parts[i]], i + 1);
147
+ };
148
+ walk(doc, 0);
149
+ return out;
150
+ }
151
+ /**
152
+ * Distinct tokens of `values` (arrays flattened, nested arrays too; strings and
153
+ * numbers tokenised, every other value ignored), in first-seen order.
154
+ */
155
+ function collectSearchTokens(values) {
156
+ const keys = /* @__PURE__ */ new Set();
157
+ const add = (v) => {
158
+ if (Array.isArray(v)) {
159
+ for (const item of v) add(item);
160
+ return;
161
+ }
162
+ const text = typeof v === "string" ? v : typeof v === "number" || typeof v === "bigint" ? String(v) : void 0;
163
+ if (text === void 0) return;
164
+ for (const token of tokenizeSearchText(text)) keys.add(token);
165
+ };
166
+ for (const v of values) add(v);
167
+ return [...keys];
168
+ }
169
+ /**
170
+ * The search keys of `doc`: the distinct normalised tokens of every value at
171
+ * every `fields` path (strings and numbers; arrays flattened; other values
172
+ * ignored), in first-seen order. This is exactly what the write paths store.
173
+ *
174
+ * @example buildSearchKeys({ name: 'Ahmed bin Ali', email: 'a.ali@x.io' }, ['name'])
175
+ * // ['ahmed', 'bin', 'ali']
176
+ */
177
+ function buildSearchKeys(doc, fields) {
178
+ return collectSearchTokens(fields.map((f) => valuesAtPath(doc, f)));
179
+ }
180
+ const escapeRegex = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
181
+ /**
182
+ * The MongoDB filter for a prefix search: every query token must be the start of
183
+ * some stored key (AND across words, any order). `null` when `query` has no
184
+ * tokens (blank or punctuation only): the caller decides whether that means "no
185
+ * search" (the repository's choice) or "match nothing".
186
+ *
187
+ * Uses `{ $regex: '^…' }` strings, never RegExp objects, so the filter survives
188
+ * JSON (cache keys, logs, wire) unchanged.
189
+ *
190
+ * @example prefixSearchFilter('Moh Ali')
191
+ * // { $and: [{ _searchKeys: { $regex: '^moh' } }, { _searchKeys: { $regex: '^ali' } }] }
192
+ */
193
+ function prefixSearchFilter(query, options = {}) {
194
+ const field = options.keysField ?? "_searchKeys";
195
+ const max = options.maxTerms ?? 8;
196
+ const terms = [...new Set(tokenizeSearchText(query))].slice(0, Math.max(1, max));
197
+ if (terms.length === 0) return null;
198
+ const arms = terms.map((t) => ({ [field]: { $regex: `^${escapeRegex(t)}` } }));
199
+ return arms.length === 1 ? arms[0] : { $and: arms };
200
+ }
201
+ /**
202
+ * Mongoose schema path for the keys field: an array of strings, never selected
203
+ * by default (`select: false`), absent until written (so a backfill can find
204
+ * rows without it).
205
+ *
206
+ * @example schema.add({ _searchKeys: searchKeysPath() });
207
+ */
208
+ function searchKeysPath() {
209
+ return {
210
+ type: [String],
211
+ select: false,
212
+ default: void 0
213
+ };
214
+ }
215
+ /**
216
+ * Index declaration for the keys field (multikey), in the
217
+ * `{ fields, options }` shape `schema.index(fields, options)` and the Better
218
+ * Auth overlay's `indexes` take. Name defaults to `<field>_1`.
219
+ *
220
+ * @example
221
+ * // Serves getAll({ search }) prefix search (searchMode: 'prefix').
222
+ * const idx = searchKeysIndex();
223
+ * schema.index(idx.fields, idx.options);
224
+ */
225
+ function searchKeysIndex(field = DEFAULT_SEARCH_KEYS_FIELD, options = {}) {
226
+ return {
227
+ fields: { [field]: 1 },
228
+ options: { name: options.name ?? `${field}_1` }
229
+ };
230
+ }
231
+ //#endregion
232
+ //#region src/search/derive.ts
233
+ /**
234
+ * How a write changes the search fields: the pure analysis behind the
235
+ * search-keys plugin. Given one write (a document, a replacement, or an update
236
+ * with its filter), it says which search-field values the write determines and
237
+ * which it leaves to the stored document, so the plugin can derive the keys in
238
+ * the SAME write (no second round-trip, no window where keys are stale).
239
+ */
240
+ /** Thrown (as `status: 400` with a `code`) for a write the keys cannot follow. */
241
+ const SEARCH_KEYS_ERROR_CODES = {
242
+ /** An operator or path the plugin cannot evaluate touches a search field. */
243
+ UNSUPPORTED_UPDATE: "SEARCH_KEYS_UNSUPPORTED_UPDATE",
244
+ /** A multi-document update sets SOME search fields; the rest differ per document. */
245
+ PARTIAL_MULTI_UPDATE: "SEARCH_KEYS_PARTIAL_MULTI_UPDATE"
246
+ };
247
+ var SearchKeysWriteError = class extends Error {
248
+ code;
249
+ status = 400;
250
+ constructor(message, code) {
251
+ super(message);
252
+ this.code = code;
253
+ this.name = "SearchKeysWriteError";
254
+ }
255
+ };
256
+ const isPlainObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v) && (Object.getPrototypeOf(v) === Object.prototype || Object.getPrototypeOf(v) === null);
257
+ /** Operators whose effect on a search field the plugin evaluates. */
258
+ const EVALUATED = /* @__PURE__ */ new Set([
259
+ "$set",
260
+ "$setOnInsert",
261
+ "$unset"
262
+ ]);
263
+ /**
264
+ * Resolve each search field against one `path → value` bag (`$set`, a plain
265
+ * patch): an exact key, or an ANCESTOR key (`profile` for `profile.name`). A
266
+ * DESCENDANT key (`tags.0` for `tags`) changes part of the value the plugin
267
+ * cannot see, so it is refused.
268
+ */
269
+ function resolveBag(bag, fields, op, out, unset = false) {
270
+ for (const key of Object.keys(bag)) for (const field of fields) if (key === field) out[field] = unset ? void 0 : bag[key];
271
+ else if (field.startsWith(`${key}.`)) out[field] = unset ? void 0 : valuesAtPath(bag[key], field.slice(key.length + 1));
272
+ else if (key.startsWith(`${field}.`)) throw new SearchKeysWriteError(`[mongokit] search keys: '${op}' on '${key}' changes part of search field '${field}'; set the whole field ('${field}') so its search keys can be derived`, SEARCH_KEYS_ERROR_CODES.UNSUPPORTED_UPDATE);
273
+ }
274
+ const touches = (key, fields) => fields.some((f) => key === f || f.startsWith(`${key}.`) || key.startsWith(`${f}.`));
275
+ /** Equalities in a filter's top level (and top-level `$and` arms) on search fields. */
276
+ function pinnedValues(filter, fields, out) {
277
+ if (!isPlainObject(filter)) return;
278
+ for (const [key, value] of Object.entries(filter)) {
279
+ if (key === "$and" && Array.isArray(value)) {
280
+ for (const arm of value) pinnedValues(arm, fields, out);
281
+ continue;
282
+ }
283
+ if (!fields.includes(key)) continue;
284
+ if (typeof value === "string" || typeof value === "number") out[key] = value;
285
+ else if (isPlainObject(value) && Object.keys(value).length === 1 && "$eq" in value) {
286
+ const eq = value.$eq;
287
+ if (typeof eq === "string" || typeof eq === "number") out[key] = eq;
288
+ }
289
+ }
290
+ }
291
+ /**
292
+ * Analyse an update (plain patch, operator update, or pipeline) against the
293
+ * search fields. Strips any caller-supplied value for `keysField` (the keys
294
+ * are derived, never client-settable). Throws {@link SearchKeysWriteError} for
295
+ * an operator other than `$set`/`$setOnInsert`/`$unset` (or a pipeline stage)
296
+ * that touches a search field.
297
+ */
298
+ function analyzeUpdate(update, filter, fields, keysField) {
299
+ const effect = {
300
+ updated: {},
301
+ onInsert: {},
302
+ pinned: {}
303
+ };
304
+ pinnedValues(filter, fields, effect.pinned);
305
+ if (Array.isArray(update)) {
306
+ for (const stage of update) {
307
+ if (!isPlainObject(stage)) continue;
308
+ for (const [name, body] of Object.entries(stage)) {
309
+ const keys = name === "$unset" ? [].concat(body).map(String) : isPlainObject(body) ? Object.keys(body) : [];
310
+ if (name === "$replaceRoot" || name === "$replaceWith" || name === "$project" || keys.some((k) => touches(k, fields))) throw new SearchKeysWriteError(`[mongokit] search keys: pipeline stage '${name}' touches a search field (${fields.join(", ")}); use an operator update (\$set / \$unset) so the keys can be derived`, SEARCH_KEYS_ERROR_CODES.UNSUPPORTED_UPDATE);
311
+ }
312
+ }
313
+ return effect;
314
+ }
315
+ if (!isPlainObject(update)) return effect;
316
+ const keys = Object.keys(update);
317
+ if (!keys.some((k) => k.startsWith("$"))) {
318
+ delete update[keysField];
319
+ resolveBag(update, fields, "$set", effect.updated);
320
+ return effect;
321
+ }
322
+ for (const op of keys) {
323
+ const body = update[op];
324
+ if (!isPlainObject(body)) continue;
325
+ if (op === "$set" || op === "$setOnInsert") delete body[keysField];
326
+ if (op === "$unset") delete body[keysField];
327
+ if (!EVALUATED.has(op)) {
328
+ const hit = Object.keys(body).find((k) => touches(k, fields));
329
+ if (hit) throw new SearchKeysWriteError(`[mongokit] search keys: '${op}' on '${hit}' cannot be followed by the search keys; set the whole value with $set (or call rebuildSearchKeys afterwards)`, SEARCH_KEYS_ERROR_CODES.UNSUPPORTED_UPDATE);
330
+ continue;
331
+ }
332
+ if (op === "$set") resolveBag(body, fields, op, effect.updated);
333
+ else if (op === "$unset") resolveBag(body, fields, op, effect.updated, true);
334
+ else resolveBag(body, fields, op, effect.onInsert);
335
+ }
336
+ return effect;
337
+ }
338
+ /** Fields the effect leaves unknown for the update path (neither updated nor pinned). */
339
+ function unresolvedForUpdate(effect, fields) {
340
+ return fields.filter((f) => !(f in effect.updated) && !(f in effect.pinned));
341
+ }
342
+ /** The full value set an INSERT through this update would store. */
343
+ function insertValues(effect) {
344
+ return {
345
+ ...effect.pinned,
346
+ ...effect.onInsert,
347
+ ...effect.updated
348
+ };
349
+ }
350
+ /**
351
+ * Put `keys` into an update in place: a plain patch gets the key directly
352
+ * (mongoose wraps it in `$set`), an operator update under `$set` (or
353
+ * `$setOnInsert` for an insert-only derivation).
354
+ */
355
+ function writeKeys(update, keysField, keys, slot = "$set") {
356
+ if (!Object.keys(update).some((k) => k.startsWith("$"))) {
357
+ update[keysField] = keys;
358
+ return;
359
+ }
360
+ const bag = isPlainObject(update[slot]) ? update[slot] : {};
361
+ bag[keysField] = keys;
362
+ update[slot] = bag;
363
+ }
364
+ /** The values of `fields` read from a stored (or to-be-inserted) document. */
365
+ function fieldValuesOf(doc, fields) {
366
+ const out = {};
367
+ for (const f of fields) out[f] = valuesAtPath(doc, f);
368
+ return out;
369
+ }
370
+ /** The keys for a resolved value set (see {@link collectSearchTokens}), in `fields` order. */
371
+ function keysFromValues(values, fields) {
372
+ return collectSearchTokens(fields.map((f) => values[f]));
373
+ }
374
+ //#endregion
375
+ 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 };
@@ -0,0 +1,169 @@
1
+ //#region src/search/derive.d.ts
2
+ /**
3
+ * How a write changes the search fields: the pure analysis behind the
4
+ * search-keys plugin. Given one write (a document, a replacement, or an update
5
+ * with its filter), it says which search-field values the write determines and
6
+ * which it leaves to the stored document, so the plugin can derive the keys in
7
+ * the SAME write (no second round-trip, no window where keys are stale).
8
+ */
9
+ /** Thrown (as `status: 400` with a `code`) for a write the keys cannot follow. */
10
+ declare const SEARCH_KEYS_ERROR_CODES: {
11
+ /** An operator or path the plugin cannot evaluate touches a search field. */
12
+ readonly UNSUPPORTED_UPDATE: "SEARCH_KEYS_UNSUPPORTED_UPDATE";
13
+ /** A multi-document update sets SOME search fields; the rest differ per document. */
14
+ readonly PARTIAL_MULTI_UPDATE: "SEARCH_KEYS_PARTIAL_MULTI_UPDATE";
15
+ };
16
+ declare class SearchKeysWriteError extends Error {
17
+ readonly code: (typeof SEARCH_KEYS_ERROR_CODES)[keyof typeof SEARCH_KEYS_ERROR_CODES];
18
+ readonly status = 400;
19
+ constructor(message: string, code: (typeof SEARCH_KEYS_ERROR_CODES)[keyof typeof SEARCH_KEYS_ERROR_CODES]);
20
+ }
21
+ //#endregion
22
+ //#region src/search/normalize.d.ts
23
+ /**
24
+ * Search-as-you-type text rules, shared by the WRITER (the search keys stored on
25
+ * every document) and the READER (the query typed into a search box).
26
+ *
27
+ * Both sides MUST run the same function, otherwise a key written as `mohammed`
28
+ * is never found by a query normalised to `Mohammed`. That is also why this
29
+ * module is pure (no mongoose, no driver): a portal or mobile client imports it
30
+ * from `@classytic/mongokit/search` to highlight matches with the exact rules
31
+ * the server indexed with.
32
+ *
33
+ * Rules, in order:
34
+ * 1. lower-case (before NFKD: `'İ'.toLowerCase()` yields a combining dot the
35
+ * next step removes);
36
+ * 2. Unicode NFKD, then every combining mark (`\p{M}`) dropped: `é → e`,
37
+ * `fi → fi`, and Arabic tashkeel (fatha, damma, kasra, shadda, sukun,
38
+ * tanween, superscript alef) disappear;
39
+ * 3. Arabic folding: tatweel removed; `أ إ آ ٱ → ا` (the hamza/madda forms
40
+ * decompose to bare alef in step 2, wasla is folded here); `ى → ي`;
41
+ * `ة → ه`; Arabic-Indic and Persian digits → ASCII digits;
42
+ * 4. format characters (`\p{Cf}`: ZWJ, ZWNJ, bidi marks) removed so a pasted
43
+ * name does not split or miss;
44
+ * 5. split on anything that is not a letter or a digit (whitespace and
45
+ * punctuation: `al-harbi` → `al`, `harbi`; `noura.saad@x.io` → `noura`,
46
+ * `saad`, `x`, `io`).
47
+ */
48
+ /**
49
+ * The search tokens of `text`, in order, duplicates kept. Empty for blank text
50
+ * or text with no letters/digits.
51
+ *
52
+ * @example tokenizeSearchText(' Mohammed AL-Harbi ') // ['mohammed', 'al', 'harbi']
53
+ * @example tokenizeSearchText('مُحَمَّد أحمد') // ['محمد', 'احمد']
54
+ */
55
+ declare function tokenizeSearchText(text: string): string[];
56
+ /**
57
+ * `text` normalised to its tokens joined by single spaces: the canonical form to
58
+ * compare or display ("what the index sees").
59
+ *
60
+ * @example normalizeSearchText('Café Crème') // 'cafe creme'
61
+ */
62
+ declare function normalizeSearchText(text: string): string;
63
+ /** A `[start, end)` range of the ORIGINAL text, as {@link findSearchMatches} returns. */
64
+ interface SearchMatchRange {
65
+ start: number;
66
+ end: number;
67
+ }
68
+ /**
69
+ * Where `query` matches `text` under the prefix-search rules: for every word of
70
+ * `text` whose normalised form starts with one of the query's tokens, the
71
+ * shortest leading run of the ORIGINAL characters that covers that token.
72
+ * Offsets index the original string, so a client wraps them in `<mark>` with no
73
+ * re-normalisation of its own.
74
+ *
75
+ * @example findSearchMatches('Mohammed Al-Harbi', 'moh har')
76
+ * // [{ start: 0, end: 3 }, { start: 12, end: 15 }]
77
+ */
78
+ declare function findSearchMatches(text: string, query: string): SearchMatchRange[];
79
+ //#endregion
80
+ //#region src/search/prefix.d.ts
81
+ /**
82
+ * Indexed search-as-you-type (`searchMode: 'prefix'`): the stored keys, the
83
+ * query filter, and the index/schema declarations. Pure: no mongoose import.
84
+ *
85
+ * ## Storage choice: word tokens + anchored regex (not edge n-grams)
86
+ *
87
+ * Each document stores the DISTINCT normalised word tokens of its search fields
88
+ * in one array field (`_searchKeys` by default), covered by a multikey index. A
89
+ * query token `moh` becomes `{ _searchKeys: { $regex: '^moh' } }`: a
90
+ * case-sensitive regex with a literal prefix, which the planner turns into the
91
+ * index range `["moh", "moi")` (IXSCAN, keys examined ≈ matches). Several query
92
+ * tokens AND together, one `$and` arm each; the planner bounds one arm and
93
+ * filters the rest on the fetched documents.
94
+ *
95
+ * The alternative, edge n-grams (`m, mo, moh, ..., mohammed` stored, matched by
96
+ * an exact `$all`), gives the SAME index-range query plan, only with point
97
+ * bounds, while storing one key per prefix length instead of one per word.
98
+ * Measured on 2,000 two-to-three-word names (mongod 8, WiredTiger; see
99
+ * `tests/integration/prefix-search.test.ts`): tokens 6,000 keys / 60 KiB index,
100
+ * edge n-grams (N=20) 34,140 keys / 256 KiB index, ~5.7x the keys and ~4x the
101
+ * index bytes. N-grams also cost a write amplification on every
102
+ * rename, and an arbitrary cut-off N past which longer prefixes stop matching.
103
+ * Tokens keep the index small, have no length cliff, and make the backfill a
104
+ * pure function of the source fields. So tokens are the standard here.
105
+ */
106
+ /** Default name of the field that stores the search keys. */
107
+ declare const DEFAULT_SEARCH_KEYS_FIELD = "_searchKeys";
108
+ /** Query tokens beyond this many are ignored (each one is an `$and` arm). */
109
+ declare const MAX_PREFIX_SEARCH_TERMS = 8;
110
+ /**
111
+ * The search keys of `doc`: the distinct normalised tokens of every value at
112
+ * every `fields` path (strings and numbers; arrays flattened; other values
113
+ * ignored), in first-seen order. This is exactly what the write paths store.
114
+ *
115
+ * @example buildSearchKeys({ name: 'Ahmed bin Ali', email: 'a.ali@x.io' }, ['name'])
116
+ * // ['ahmed', 'bin', 'ali']
117
+ */
118
+ declare function buildSearchKeys(doc: unknown, fields: readonly string[]): string[];
119
+ interface PrefixSearchFilterOptions {
120
+ /** Field holding the keys. Default {@link DEFAULT_SEARCH_KEYS_FIELD}. */
121
+ keysField?: string;
122
+ /** Cap on query tokens. Default {@link MAX_PREFIX_SEARCH_TERMS}. */
123
+ maxTerms?: number;
124
+ }
125
+ /**
126
+ * The MongoDB filter for a prefix search: every query token must be the start of
127
+ * some stored key (AND across words, any order). `null` when `query` has no
128
+ * tokens (blank or punctuation only): the caller decides whether that means "no
129
+ * search" (the repository's choice) or "match nothing".
130
+ *
131
+ * Uses `{ $regex: '^…' }` strings, never RegExp objects, so the filter survives
132
+ * JSON (cache keys, logs, wire) unchanged.
133
+ *
134
+ * @example prefixSearchFilter('Moh Ali')
135
+ * // { $and: [{ _searchKeys: { $regex: '^moh' } }, { _searchKeys: { $regex: '^ali' } }] }
136
+ */
137
+ declare function prefixSearchFilter(query: string, options?: PrefixSearchFilterOptions): Record<string, unknown> | null;
138
+ /**
139
+ * Mongoose schema path for the keys field: an array of strings, never selected
140
+ * by default (`select: false`), absent until written (so a backfill can find
141
+ * rows without it).
142
+ *
143
+ * @example schema.add({ _searchKeys: searchKeysPath() });
144
+ */
145
+ declare function searchKeysPath(): {
146
+ type: [StringConstructor];
147
+ select: false;
148
+ default: undefined;
149
+ };
150
+ /**
151
+ * Index declaration for the keys field (multikey), in the
152
+ * `{ fields, options }` shape `schema.index(fields, options)` and the Better
153
+ * Auth overlay's `indexes` take. Name defaults to `<field>_1`.
154
+ *
155
+ * @example
156
+ * // Serves getAll({ search }) prefix search (searchMode: 'prefix').
157
+ * const idx = searchKeysIndex();
158
+ * schema.index(idx.fields, idx.options);
159
+ */
160
+ declare function searchKeysIndex(field?: string, options?: {
161
+ name?: string;
162
+ }): {
163
+ fields: Record<string, 1>;
164
+ options: {
165
+ name: string;
166
+ };
167
+ };
168
+ //#endregion
169
+ export { prefixSearchFilter as a, SearchMatchRange as c, tokenizeSearchText as d, SEARCH_KEYS_ERROR_CODES as f, buildSearchKeys as i, findSearchMatches as l, MAX_PREFIX_SEARCH_TERMS as n, searchKeysIndex as o, SearchKeysWriteError as p, PrefixSearchFilterOptions as r, searchKeysPath as s, DEFAULT_SEARCH_KEYS_FIELD as t, normalizeSearchText as u };
package/dist/index.d.mts CHANGED
@@ -2,16 +2,17 @@ import { S as LookupOptions, _ as SessionOptions, a as ConvenientTransactionOpti
2
2
  import { A as ObjectId, C as configureQueryDefaults, D as AnyDocument, E as resolveQueryOptions, F as SortSpec$1, M as ReadPreferenceType, N as SelectSpec, O as AnyModel, P as SortDirection, S as configureAggregateDefaults, T as resetQueryDefaults, _ as QueryDefaults, a as CursorPayload, b as WriteConcernSpec, c as MongokitPageExtras, d as ValueType, f as CursorSecret, g as QUERY_DEFAULTS_ERROR_CODES, h as PerCallQueryOptions, i as CountStrategy, j as PopulateSpec, l as OffsetPaginationOptions, m as CommandKind, n as BasePaginationOptions, o as DecodedCursor, p as AggregateDefaults, r as CollationOptions, s as KeysetPaginationOptions, t as AggregatePaginationOptions, u as PaginationConfig, v as ReadConcernLevel, w as getQueryDefaults, x as assertQueryDefaultsConfigured, y as ResolvedQueryOptions } from "./pagination-D6psses0.mjs";
3
3
  import { a as CreateManyFailure, l as isCreateManyPartialError, o as CreateManyPartial, s as CreateManyPartialError, t as index_d_exports } from "./index-SYF8N28D.mjs";
4
4
  import { a as InferRawDoc, c as NonNullableFields, d as Strict, f as UpdatePatch, i as InferDocument, l as PartialBy, n as DeepPartial, o as KeysOfType, p as UpdateWithValidationResult, r as DocField, s as MongoOperatorUpdate, t as CreateInput, u as RequiredBy } from "./type-utils-CLzRFtIA.mjs";
5
- import { S as RepositoryPluginName, _ as RepositoryOptions, a as HookMode, b as MONGOKIT_PLUGIN_NAMES, c as MinimalRepoView, d as PluginType, f as PrioritizedHook, g as RepositoryOperation, h as RepositoryInstance, i as EventPhase, l as Plugin, m as RepositoryEvent, n as EventHandlers, o as Middleware, p as RepositoryContext, r as EventPayload, s as MiddlewareContext, t as AllPluginMethods, u as PluginFunction, v as UserContext, x as MongoKitPluginName, y as WithPlugins } from "./repository-DNHfjAZX.mjs";
6
- import { A as EnsureAuditTrailReadyOptions, C as AuditQueryOptions, D as AuditTrailOptions, E as AuditTrailMode, M as ensureAuditTrailReady, O as AuditTrailQuery, S as AuditOperation, T as AuditTrailMethods, _ as CacheOptions, a as DateSequentialIdOptions, b as cachePlugin, c as SequentialIdOptions, d as ensureSequenceAtLeast, f as getNextSequence, g as CacheAdapter, h as sequentialId, i as CustomIdOptions, j as auditTrailPlugin, k as AuditTrailQueryOptions, l as customIdPlugin, m as readSequence, n as adminBypass, o as IdGenerator, p as prefixedId, r as multiTenantPlugin, s as PrefixedIdOptions, t as MultiTenantOptions, u as dateSequentialId, v as RepositoryCacheHandle, w as AuditQueryResult, x as AuditEntry, y as RepositoryCachePluginOptions } from "./multi-tenant.plugin-a3UhQARj.mjs";
5
+ import { C as RepositoryPluginName, S as MongoKitPluginName, _ as RepositoryOptions, a as HookMode, b as WithPlugins, c as MinimalRepoView, d as PluginType, f as PrioritizedHook, g as RepositoryOperation, h as RepositoryInstance, i as EventPhase, l as Plugin, m as RepositoryEvent, n as EventHandlers, o as Middleware, p as RepositoryContext, r as EventPayload, s as MiddlewareContext, t as AllPluginMethods, u as PluginFunction, v as RepositorySearchMode, x as MONGOKIT_PLUGIN_NAMES, y as UserContext } from "./repository-MqAP409e.mjs";
6
+ import { A as EnsureAuditTrailReadyOptions, C as AuditQueryOptions, D as AuditTrailOptions, E as AuditTrailMode, M as ensureAuditTrailReady, O as AuditTrailQuery, S as AuditOperation, T as AuditTrailMethods, _ as CacheOptions, a as DateSequentialIdOptions, b as cachePlugin, c as SequentialIdOptions, d as ensureSequenceAtLeast, f as getNextSequence, g as CacheAdapter, h as sequentialId, i as CustomIdOptions, j as auditTrailPlugin, k as AuditTrailQueryOptions, l as customIdPlugin, m as readSequence, n as adminBypass, o as IdGenerator, p as prefixedId, r as multiTenantPlugin, s as PrefixedIdOptions, t as MultiTenantOptions, u as dateSequentialId, v as RepositoryCacheHandle, w as AuditQueryResult, x as AuditEntry, y as RepositoryCachePluginOptions } from "./multi-tenant.plugin-B_q9NUHc.mjs";
7
7
  import { n as PaginationEngine, t as CountMemoKey } from "./PaginationEngine-CRHyuUtw.mjs";
8
- import { a as AggregationBuilder, c as ProjectionSpec, d as VectorSearchOptions, i as TransitionMachine, l as SortOrder, n as HOOK_PRIORITY, o as AggregationPlan, r as Repository, s as GroupSpec, t as GetAllParams, u as SortSpec } from "./Repository-pnLw1rG5.mjs";
9
- import { a as SoftDeleteFilterMode, c as ValidationChainOptions, i as Logger, l as ValidatorDefinition, n as CascadeRelation, o as SoftDeleteOptions, r as FieldPreset, s as SoftDeleteRepository, t as CascadeOptions } from "./plugin-options-CRhIvSzx.mjs";
10
- import { n as CreateRepositoryConfig, r as createRepository, t as AuditConfig } from "./create-repository-BUx9vfG9.mjs";
11
- import { A as IdempotencyStoreMethods, B as batchOperationsPlugin, C as LeaseMethods, D as ImmutableStatesPluginOptions, E as ImmutableClaimView, F as elasticSearchPlugin, G as aggregateHelpersPlugin, H as AppendOnlyPluginOptions, I as cascadePlugin, L as BatchOperationsMethods, M as idempotencyStorePlugin, N as fieldFilterPlugin, O as immutableStatesPlugin, P as ElasticSearchOptions, R as BulkWriteOptions, S as methodRegistryPlugin, T as leasePlugin, U as appendOnlyPlugin, V as auditLogPlugin, W as AggregateHelpersMethods, _ as OperationMetric, a as requireField, b as mongoOperationsPlugin, c as timestampPlugin, d as createTenantContext, f as SubdocumentMethods, g as ObservabilityOptions, h as softDeletePlugin, i as immutableField, j as IdempotencyStorePluginOptions, k as IdempotencyClaim, l as TenantContext, m as SoftDeleteMethods, n as autoInject, o as uniqueField, p as subdocumentPlugin, r as blockIf, s as validationChainPlugin, t as OperationType, u as TenantStore, v as observabilityPlugin, w as LeasePluginOptions, y as MongoOperationsMethods, z as BulkWriteResult } from "./validation-chain.plugin-CTcNJCmV.mjs";
8
+ import { a as AggregationBuilder, c as ProjectionSpec, d as VectorSearchOptions, i as TransitionMachine, l as SortOrder, n as HOOK_PRIORITY, o as AggregationPlan, r as Repository, s as GroupSpec, t as GetAllParams, u as SortSpec } from "./Repository-DnL4xk5w.mjs";
9
+ import { a as SoftDeleteFilterMode, c as ValidationChainOptions, i as Logger, l as ValidatorDefinition, n as CascadeRelation, o as SoftDeleteOptions, r as FieldPreset, s as SoftDeleteRepository, t as CascadeOptions } from "./plugin-options-Cirmb4Kp.mjs";
10
+ import { n as CreateRepositoryConfig, r as createRepository, t as AuditConfig } from "./create-repository-CJtVdwig.mjs";
11
+ import { A as immutableStatesPlugin, B as BulkWriteOptions, D as leasePlugin, E as LeasePluginOptions, F as fieldFilterPlugin, G as appendOnlyPlugin, H as batchOperationsPlugin, I as ElasticSearchOptions, K as AggregateHelpersMethods, L as elasticSearchPlugin, M as IdempotencyStoreMethods, N as IdempotencyStorePluginOptions, O as ImmutableClaimView, P as idempotencyStorePlugin, R as cascadePlugin, S as mongoOperationsPlugin, T as LeaseMethods, U as auditLogPlugin, V as BulkWriteResult, W as AppendOnlyPluginOptions, _ as searchKeysPlugin, a as requireField, b as observabilityPlugin, c as timestampPlugin, d as createTenantContext, f as SubdocumentMethods, g as SearchKeysPluginOptions, h as softDeletePlugin, i as immutableField, j as IdempotencyClaim, k as ImmutableStatesPluginOptions, l as TenantContext, m as SoftDeleteMethods, n as autoInject, o as uniqueField, p as subdocumentPlugin, q as aggregateHelpersPlugin, r as blockIf, s as validationChainPlugin, t as OperationType, u as TenantStore, v as ObservabilityOptions, w as methodRegistryPlugin, x as MongoOperationsMethods, y as OperationMetric, z as BatchOperationsMethods } from "./validation-chain.plugin-BAeC5eVT.mjs";
12
12
  import { n as SchemaPathsLike, t as FieldType$1 } from "./coercion-BjdPX3YF.mjs";
13
13
  import { n as SchemaIndexes } from "./indexes-DIjMpYES.mjs";
14
- import { S as parseDuplicateKeyError, _ as getMongooseProjection, a as createMemoryCache, b as createError, g as getFieldsForUser, h as filterResponseData, i as buildCrudSchemasFromMongooseSchema, m as createFieldPreset, n as CrudSchemasFramework, o as LoggerConfig, r as buildCrudSchemasFromModel, s as configureLogger, t as toPlain, u as idVariants, v as CreateErrorOptions, x as isDuplicateKeyError, y as ParseDuplicateKeyOptions } from "./to-plain-CjgEInWV.mjs";
14
+ import { a as prefixSearchFilter, c as SearchMatchRange, d as tokenizeSearchText, f as SEARCH_KEYS_ERROR_CODES, i as buildSearchKeys, l as findSearchMatches, n as MAX_PREFIX_SEARCH_TERMS, o as searchKeysIndex, p as SearchKeysWriteError, r as PrefixSearchFilterOptions, s as searchKeysPath, t as DEFAULT_SEARCH_KEYS_FIELD, u as normalizeSearchText } from "./index-C0AjVqX3.mjs";
15
+ import { S as parseDuplicateKeyError, _ as getMongooseProjection, a as createMemoryCache, b as createError, g as getFieldsForUser, h as filterResponseData, i as buildCrudSchemasFromMongooseSchema, m as createFieldPreset, n as CrudSchemasFramework, o as LoggerConfig, r as buildCrudSchemasFromModel, s as configureLogger, t as toPlain, u as idVariants, v as CreateErrorOptions, x as isDuplicateKeyError, y as ParseDuplicateKeyOptions } from "./to-plain-o5tUY2nV.mjs";
15
16
  import { RepoCapabilities } from "@classytic/repo-core/repository";
16
17
  import { ClientSession, Connection, Model, PipelineStage, Schema } from "mongoose";
17
18
  import { HttpError } from "@classytic/repo-core/errors";
@@ -753,6 +754,34 @@ declare function declareCollectionScope(model: object, rule: CollectionScopeRule
753
754
  tenantField?: string;
754
755
  }): void;
755
756
  //#endregion
757
+ //#region src/search/rebuild.d.ts
758
+ /** A prefix-mode `Repository` satisfies this: `rebuildSearchKeys(repo)`. */
759
+ interface SearchKeysSource {
760
+ Model: Model<any, any, any, any>;
761
+ searchFields?: readonly string[] | undefined;
762
+ searchKeysField?: string;
763
+ }
764
+ interface RebuildSearchKeysOptions {
765
+ /** Source fields. Default: the repository's `searchFields`. */
766
+ fields?: readonly string[];
767
+ /** Keys field. Default: the repository's `searchKeysField`, else `'_searchKeys'`. */
768
+ keysField?: string;
769
+ /** Only documents matching this filter. Default: all. */
770
+ filter?: Record<string, unknown>;
771
+ /** Only documents with no keys field yet (cheapest boot-time backfill). Default `false`. */
772
+ onlyMissing?: boolean;
773
+ /** Documents read and written per round-trip. Default 500. */
774
+ batchSize?: number;
775
+ session?: unknown;
776
+ }
777
+ interface RebuildSearchKeysResult {
778
+ /** Documents read. */
779
+ scanned: number;
780
+ /** Documents whose keys were missing or stale and were rewritten (server-reported). */
781
+ updated: number;
782
+ }
783
+ declare function rebuildSearchKeys(source: SearchKeysSource | Model<any, any, any, any>, options?: RebuildSearchKeysOptions): Promise<RebuildSearchKeysResult>;
784
+ //#endregion
756
785
  //#region src/transaction.d.ts
757
786
  /** Minimal shape we need from a Mongoose connection. */
758
787
  interface SessionStarter {
@@ -1116,4 +1145,4 @@ declare function createOptionsExtractor<TCtx extends Record<string, unknown>>(fi
1116
1145
  */
1117
1146
  declare function systemContext(extra?: SessionOptions): SessionOptions;
1118
1147
  //#endregion
1119
- export { ALL_OPERATIONS, type AggregateCallOptions, type AggregateDefaults, type AggregateHelpersMethods, type AggregateOptions, type AggregatePaginationOptions, AggregationBuilder, type AggregationPlan, type SortOrder as AggregationSortOrder, type SortSpec as AggregationSortSpec, type AllPluginMethods, type AnyDocument, type AnyModel, type AppendOnlyPluginOptions, type AuditConfig, type AuditEntry, type AuditOperation, type AuditQueryOptions, type AuditQueryResult, type AuditTrailMethods, type AuditTrailMode, type AuditTrailOptions, AuditTrailQuery, type AuditTrailQueryOptions, type BasePaginationOptions, type BatchOperationsMethods, type BulkWriteOptions, type BulkWriteResult, type CacheAdapter, type CacheOperationOptions, type CacheOptions, type CacheableOptions, type CapabilityConnectionLike, type CapabilityProbeOptions, type CapabilityResolution, type CascadeOptions, type CascadePurgeReferencesOptions, type CascadeRelation, type CollationOptions, type CollectionRWLike, type CollectionScopeRule, type CommandKind, type ConvenientTransactionOptions, type CountMemoKey, type CountStrategy, type CreateErrorOptions, type CreateInput, type CreateManyFailure, type CreateManyPartial, type CreateManyPartialError, type CreateOptions, type CreateRepositoryConfig, type CrudSchemasFramework, type CursorPayload, type CursorSecret, type CustomIdOptions, type DateSequentialIdOptions, type DecodedCursor, type DeepPartial, type DefineModelOptions, type DeleteResult, type DocField, type ElasticSearchOptions, type EnsureAuditTrailReadyOptions, type EventHandlers, type EventPayload, type EventPhase, type ExistingModelPolicy, type FieldPreset, type FieldType, type FilterQuery, type FindOneAndUpdateOptions, type GetAllParams, type GetByIdsOptions, type GroupResult, type GroupSpec, HOOK_PRIORITY, type HookMode, type IdGenerator, type IdempotencyClaim, type IdempotencyStoreMethods, type IdempotencyStorePluginOptions, type ImmutableClaimView, type ImmutableStatesPluginOptions, type InferDocument, type InferRawDoc, JOIN_ERROR_CODES, type KeysOfType, type KeysetPaginationOptions, type KeysetSourceOptions, type LeaseMethods, type LeasePluginOptions, type Logger, type LoggerConfig, LookupBuilder, type LookupOptions, type LookupPopulateOptions, type LookupPopulateResult, MONGOKIT_CAPABILITIES, MONGOKIT_PLUGIN_NAMES, MUTATING_OPERATIONS, type Middleware, type MiddlewareContext, type MinMaxResult, type MinimalRepoView, type ModelBlueprint, ModelCollisionError, type ModelSpec, type MongoKitPluginName, type MongoOperationsMethods, type MongoOperatorUpdate, type MongoRepoCapabilities, type MongokitPageExtras, type MultiTenantOptions, type NonNullableFields, OP_REGISTRY, type ObjectId, type ObservabilityOptions, type OffsetPaginationOptions, type OperationDescriptor, type OperationMetric, type OperationOptions, type OperationType, PAGINATION_ERROR_CODES, type PaginationConfig, type PaginationDefaults, PaginationEngine, type ParseDuplicateKeyOptions, type ParsedQuery, type PartialBy, type PerCallQueryOptions, type Plugin, type PluginFunction, type PluginType, type PolicyKey, type PopulateOption, type PopulateSpec, type PrefixedIdOptions, type PrioritizedHook, type ProjectionSpec, type PurgeMode, type PurgeableRepoLike, QUERY_DEFAULTS_ERROR_CODES, type QueryDefaults, QueryParser, type QueryParserOptions, type QuerySchema, READ_OPERATIONS, type ReadConcernLevel, type ReadOptions, type ReadPreferenceType, type ReferencePurgeResult, type ReferenceRelation, type RepoScope, Repository, Repository as default, type RepositoryCacheHandle, type RepositoryCachePluginOptions, type RepositoryContext, type RepositoryEvent, type RepositoryInstance, type RepositoryOperation, type RepositoryOptions, type RepositoryPluginName, type RequiredBy, type ResolvedQueryOptions, type SchemaLike, type SearchMode, type SelectSpec, type SequentialIdOptions, type SessionOptions, type SessionStarter, type SoftDeleteFilterMode, type SoftDeleteMethods, type SoftDeleteOptions, type SoftDeleteRepository, type SortDirection, type SortSpec$1 as SortSpec, type Strict, type SubdocumentMethods, TRANSACTION_ERROR_CODES, type TenantContext, type TenantStore, type TransactionSupport, type TransitionMachine, type UpdateManyResult, type UpdateOptions, type UpdatePatch, type UpdateWithValidationResult, type UserContext, type ValidationChainOptions, type ValidatorDefinition, type ValueType, type VectorSearchOptions, type WithPlugins, type WithTransactionOptions, type WriteConcernSpec, index_d_exports as actions, adminBypass, aggregateHelpersPlugin, appendOnlyPlugin, assertQueryDefaultsConfigured, auditLogPlugin, auditTrailPlugin, autoInject, batchOperationsPlugin, batchTransaction, blockIf, buildCrudSchemasFromModel, buildCrudSchemasFromMongooseSchema, cachePlugin, capabilitiesForSupport, cascadePlugin, cascadePurgeReferences, classifyHelloReply, compileFilterToMongo, configureAggregateDefaults, configureLogger, configurePaginationDefaults, configureQueryDefaults, createError, createFieldPreset, createMemoryCache, createOptionsExtractor, createRepository, createTenantContext, customIdPlugin, dateSequentialId, declareCollectionScope, declareTenantContextKey, defineModel, defineModels, elasticSearchPlugin, ensureAuditTrailReady, ensureSequenceAtLeast, fieldFilterPlugin, filterResponseData, forwardScope, getFieldsForUser, getMongooseProjection, getNextSequence, getPaginationDefaults, getQueryDefaults, idVariants, idempotencyStorePlugin, immutableField, immutableStatesPlugin, isCreateManyPartialError, isDuplicateKeyError, isModelRegistered, isTransactionUnsupported, keysetSource, leasePlugin, methodRegistryPlugin, mongoOperationsPlugin, multiTenantPlugin, observabilityPlugin, operationsByPolicyKey, parseDuplicateKeyError, prefixedId, probeMongoCapabilities, readSequence, repoOptionsFromCtx, requireField, resetCapabilityProbeCache, resetPaginationDefaults, resetQueryDefaults, resolveMongoCapabilities, resolveQueryOptions, resolveTransactionSupport, runTransaction, sequentialId, softDeletePlugin, subdocumentPlugin, supportsTransactions, systemContext, tenantContextKeysOf, timestampPlugin, toPlain, transactionResolutionOf, uniqueField, validationChainPlugin, withTransaction };
1148
+ export { ALL_OPERATIONS, type AggregateCallOptions, type AggregateDefaults, type AggregateHelpersMethods, type AggregateOptions, type AggregatePaginationOptions, AggregationBuilder, type AggregationPlan, type SortOrder as AggregationSortOrder, type SortSpec as AggregationSortSpec, type AllPluginMethods, type AnyDocument, type AnyModel, type AppendOnlyPluginOptions, type AuditConfig, type AuditEntry, type AuditOperation, type AuditQueryOptions, type AuditQueryResult, type AuditTrailMethods, type AuditTrailMode, type AuditTrailOptions, AuditTrailQuery, type AuditTrailQueryOptions, type BasePaginationOptions, type BatchOperationsMethods, type BulkWriteOptions, type BulkWriteResult, type CacheAdapter, type CacheOperationOptions, type CacheOptions, type CacheableOptions, type CapabilityConnectionLike, type CapabilityProbeOptions, type CapabilityResolution, type CascadeOptions, type CascadePurgeReferencesOptions, type CascadeRelation, type CollationOptions, type CollectionRWLike, type CollectionScopeRule, type CommandKind, type ConvenientTransactionOptions, type CountMemoKey, type CountStrategy, type CreateErrorOptions, type CreateInput, type CreateManyFailure, type CreateManyPartial, type CreateManyPartialError, type CreateOptions, type CreateRepositoryConfig, type CrudSchemasFramework, type CursorPayload, type CursorSecret, type CustomIdOptions, DEFAULT_SEARCH_KEYS_FIELD, type DateSequentialIdOptions, type DecodedCursor, type DeepPartial, type DefineModelOptions, type DeleteResult, type DocField, type ElasticSearchOptions, type EnsureAuditTrailReadyOptions, type EventHandlers, type EventPayload, type EventPhase, type ExistingModelPolicy, type FieldPreset, type FieldType, type FilterQuery, type FindOneAndUpdateOptions, type GetAllParams, type GetByIdsOptions, type GroupResult, type GroupSpec, HOOK_PRIORITY, type HookMode, type IdGenerator, type IdempotencyClaim, type IdempotencyStoreMethods, type IdempotencyStorePluginOptions, type ImmutableClaimView, type ImmutableStatesPluginOptions, type InferDocument, type InferRawDoc, JOIN_ERROR_CODES, type KeysOfType, type KeysetPaginationOptions, type KeysetSourceOptions, type LeaseMethods, type LeasePluginOptions, type Logger, type LoggerConfig, LookupBuilder, type LookupOptions, type LookupPopulateOptions, type LookupPopulateResult, MAX_PREFIX_SEARCH_TERMS, MONGOKIT_CAPABILITIES, MONGOKIT_PLUGIN_NAMES, MUTATING_OPERATIONS, type Middleware, type MiddlewareContext, type MinMaxResult, type MinimalRepoView, type ModelBlueprint, ModelCollisionError, type ModelSpec, type MongoKitPluginName, type MongoOperationsMethods, type MongoOperatorUpdate, type MongoRepoCapabilities, type MongokitPageExtras, type MultiTenantOptions, type NonNullableFields, OP_REGISTRY, type ObjectId, type ObservabilityOptions, type OffsetPaginationOptions, type OperationDescriptor, type OperationMetric, type OperationOptions, type OperationType, PAGINATION_ERROR_CODES, type PaginationConfig, type PaginationDefaults, PaginationEngine, type ParseDuplicateKeyOptions, type ParsedQuery, type PartialBy, type PerCallQueryOptions, type Plugin, type PluginFunction, type PluginType, type PolicyKey, type PopulateOption, type PopulateSpec, type PrefixSearchFilterOptions, type PrefixedIdOptions, type PrioritizedHook, type ProjectionSpec, type PurgeMode, type PurgeableRepoLike, QUERY_DEFAULTS_ERROR_CODES, type QueryDefaults, QueryParser, type QueryParserOptions, type QuerySchema, READ_OPERATIONS, type ReadConcernLevel, type ReadOptions, type ReadPreferenceType, type RebuildSearchKeysOptions, type RebuildSearchKeysResult, type ReferencePurgeResult, type ReferenceRelation, type RepoScope, Repository, Repository as default, type RepositoryCacheHandle, type RepositoryCachePluginOptions, type RepositoryContext, type RepositoryEvent, type RepositoryInstance, type RepositoryOperation, type RepositoryOptions, type RepositoryPluginName, type RepositorySearchMode, type RequiredBy, type ResolvedQueryOptions, SEARCH_KEYS_ERROR_CODES, type SchemaLike, type SearchKeysPluginOptions, type SearchKeysSource, SearchKeysWriteError, type SearchMatchRange, type SearchMode, type SelectSpec, type SequentialIdOptions, type SessionOptions, type SessionStarter, type SoftDeleteFilterMode, type SoftDeleteMethods, type SoftDeleteOptions, type SoftDeleteRepository, type SortDirection, type SortSpec$1 as SortSpec, type Strict, type SubdocumentMethods, TRANSACTION_ERROR_CODES, type TenantContext, type TenantStore, type TransactionSupport, type TransitionMachine, type UpdateManyResult, type UpdateOptions, type UpdatePatch, type UpdateWithValidationResult, type UserContext, type ValidationChainOptions, type ValidatorDefinition, type ValueType, type VectorSearchOptions, type WithPlugins, type WithTransactionOptions, type WriteConcernSpec, index_d_exports as actions, adminBypass, aggregateHelpersPlugin, appendOnlyPlugin, assertQueryDefaultsConfigured, auditLogPlugin, auditTrailPlugin, autoInject, batchOperationsPlugin, batchTransaction, blockIf, buildCrudSchemasFromModel, buildCrudSchemasFromMongooseSchema, buildSearchKeys, cachePlugin, capabilitiesForSupport, cascadePlugin, cascadePurgeReferences, classifyHelloReply, compileFilterToMongo, configureAggregateDefaults, configureLogger, configurePaginationDefaults, configureQueryDefaults, createError, createFieldPreset, createMemoryCache, createOptionsExtractor, createRepository, createTenantContext, customIdPlugin, dateSequentialId, declareCollectionScope, declareTenantContextKey, defineModel, defineModels, elasticSearchPlugin, ensureAuditTrailReady, ensureSequenceAtLeast, fieldFilterPlugin, filterResponseData, findSearchMatches, forwardScope, getFieldsForUser, getMongooseProjection, getNextSequence, getPaginationDefaults, getQueryDefaults, idVariants, idempotencyStorePlugin, immutableField, immutableStatesPlugin, isCreateManyPartialError, isDuplicateKeyError, isModelRegistered, isTransactionUnsupported, keysetSource, leasePlugin, methodRegistryPlugin, mongoOperationsPlugin, multiTenantPlugin, normalizeSearchText, observabilityPlugin, operationsByPolicyKey, parseDuplicateKeyError, prefixSearchFilter, prefixedId, probeMongoCapabilities, readSequence, rebuildSearchKeys, repoOptionsFromCtx, requireField, resetCapabilityProbeCache, resetPaginationDefaults, resetQueryDefaults, resolveMongoCapabilities, resolveQueryOptions, resolveTransactionSupport, runTransaction, searchKeysIndex, searchKeysPath, searchKeysPlugin, sequentialId, softDeletePlugin, subdocumentPlugin, supportsTransactions, systemContext, tenantContextKeysOf, timestampPlugin, toPlain, tokenizeSearchText, transactionResolutionOf, uniqueField, validationChainPlugin, withTransaction };