@classytic/mongokit 3.24.0 → 3.28.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.
- package/README.md +12 -2
- package/dist/{PaginationEngine-BnZ24ehC.d.mts → PaginationEngine-CBS1XGzp.d.mts} +2 -1
- package/dist/{Repository-ClOraFjT.mjs → Repository-BFBTAMlA.mjs} +177 -54
- package/dist/actions/index.d.mts +1 -1
- package/dist/adapter/index.d.mts +1 -1
- package/dist/adapter/index.mjs +1 -1
- package/dist/{adapter-BWgJ_Jdc.mjs → adapter-CLvUHiTW.mjs} +1 -1
- package/dist/ai/index.d.mts +1 -1
- package/dist/better-auth/index.mjs +2 -2
- package/dist/core-62oo3N1C.d.mts +50 -0
- package/dist/{create-repository-CVupgeRG.mjs → create-repository-2DMwkYVz.mjs} +2 -2
- package/dist/{create-repository-Cn1LkvL7.d.mts → create-repository-D4ZU94b3.d.mts} +33 -5
- package/dist/{id-resolution-P2OzcyRl.mjs → id-resolution-BqDrk0S2.mjs} +12 -1
- package/dist/{index-DLQ6pjal.d.mts → index-DceInCTX.d.mts} +3 -1
- package/dist/index.d.mts +70 -213
- package/dist/index.mjs +1071 -922
- package/dist/{mongooseToJsonSchema-CVnrKFDq.mjs → mongooseToJsonSchema-CByt1VhQ.mjs} +1 -1
- package/dist/{multi-tenant.plugin-BjXXuc_g.d.mts → multi-tenant.plugin-DVyVGREb.d.mts} +117 -18
- package/dist/operations-C8IcCHF9.d.mts +463 -0
- package/dist/pagination/PaginationEngine.d.mts +1 -1
- package/dist/pagination-jSUdrACK.d.mts +158 -0
- package/dist/plugin-options-vFufQZMZ.d.mts +125 -0
- package/dist/plugins/index.d.mts +4 -4
- package/dist/plugins/index.mjs +3 -3
- package/dist/query/primitives/coercion.mjs +1 -1
- package/dist/query/primitives/geo.d.mts +1 -1
- package/dist/repository-DCHRWRXw.d.mts +511 -0
- package/dist/testkit/index.d.mts +1 -1
- package/dist/testkit/index.mjs +1 -1
- package/dist/{timestamp.plugin-BhSX0Lu_.mjs → timestamp.plugin-ennbatTW.mjs} +192 -46
- package/dist/{to-plain-g8-gsVxZ.d.mts → to-plain-DkF5px0R.d.mts} +12 -16
- package/dist/type-utils-CLzRFtIA.d.mts +163 -0
- package/dist/utils/index.d.mts +2 -2
- package/dist/utils/index.mjs +3 -3
- package/dist/{validation-chain.plugin-CFJbr964.d.mts → validation-chain.plugin-Cm0Ttnd8.d.mts} +140 -2
- package/dist/{validation-chain.plugin-Dtt4tO7R.mjs → validation-chain.plugin-k9joH2qw.mjs} +149 -2
- package/package.json +7 -5
- package/dist/types-BtMuhoX5.d.mts +0 -1830
package/README.md
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@classytic/mongokit)
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
[](https://github.com/sponsors/classytic)
|
|
5
6
|
|
|
6
7
|
Production-ready repository layer for Mongoose apps: tenant-safe CRUD, soft delete, pagination, hooks, retries, transactions, change streams, and plugins.
|
|
7
8
|
|
|
@@ -212,12 +213,21 @@ const parser = new QueryParser({
|
|
|
212
213
|
searchMode: 'auto',
|
|
213
214
|
});
|
|
214
215
|
|
|
215
|
-
const parsed = parser.parse(req.query);
|
|
216
|
+
const parsed = parser.parse(req.query); // throws HttpError(400) on invalid/blocked input
|
|
216
217
|
const result = await invoiceRepo.getAll(parsed);
|
|
217
218
|
```
|
|
218
219
|
|
|
219
220
|
Supports common URL operators such as `_gt`, `_gte`, `_lt`, `_lte`, `_in`, `_nin`, `_regex`, geo filters, populate, and schema-aware coercion.
|
|
220
221
|
|
|
222
|
+
The parser is **fail-closed by default** (`invalidInput: 'throw'`): blocked
|
|
223
|
+
operators, disallowed fields, malformed values, and pathological regex input
|
|
224
|
+
raise HTTP 400 (`code: 'INVALID_QUERY_INPUT'`) instead of being silently
|
|
225
|
+
dropped — dropping a request's *only* filter would broaden the query to every
|
|
226
|
+
record in tenant scope. Literal-semantics input (`search`, `like`/`contains`)
|
|
227
|
+
always escapes rather than rejects, so `?search=c++` never 400s. Trusted
|
|
228
|
+
migration/compat tooling can opt into the legacy warn-and-drop behavior with
|
|
229
|
+
`invalidInput: 'drop'`.
|
|
230
|
+
|
|
221
231
|
## Built-In Plugins
|
|
222
232
|
|
|
223
233
|
| Plugin | Purpose |
|
|
@@ -228,7 +238,7 @@ Supports common URL operators such as `_gt`, `_gte`, `_lt`, `_lte`, `_in`, `_nin
|
|
|
228
238
|
| `timestampPlugin` | `createdAt` / `updatedAt` management |
|
|
229
239
|
| `batchOperationsPlugin` | `bulkWrite` and batch helpers |
|
|
230
240
|
| `cachePlugin` | Pluggable read-through cache |
|
|
231
|
-
| `auditLogPlugin` / `auditTrailPlugin` |
|
|
241
|
+
| `auditLogPlugin` / `auditTrailPlugin` | Audit trails — `auditTrailPlugin({ mode: 'transactional' })` gives session-joined entries that are atomic inside `withTransaction` (compliance-grade); the default `'best-effort'` mode is fire-and-forget observability. Call `ensureAuditTrailReady()` at boot so collection/index creation doesn't happen inside the first transaction |
|
|
232
242
|
| `observabilityPlugin` | Metrics hook points |
|
|
233
243
|
| `cascadePlugin` | Hook-routed cascade delete |
|
|
234
244
|
| `customIdPlugin` | Prefixed or sequential public IDs |
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t as AnyDocument } from "./core-62oo3N1C.mjs";
|
|
2
|
+
import { c as PaginationConfig, o as KeysetPaginationOptions, s as OffsetPaginationOptions, t as AggregatePaginationOptions } from "./pagination-jSUdrACK.mjs";
|
|
2
3
|
import { Model } from "mongoose";
|
|
3
4
|
import { AggregatePaginationResult, KeysetPaginationResult, OffsetPaginationResult } from "@classytic/repo-core/pagination";
|
|
4
5
|
//#region src/pagination/PaginationEngine.d.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as isValidIdForType, t as getSchemaIdType } from "./id-resolution-
|
|
1
|
+
import { i as isValidIdForType, t as getSchemaIdType } from "./id-resolution-BqDrk0S2.mjs";
|
|
2
2
|
import { a as count, b as LookupBuilder, c as getByQuery, d as deleteById, f as deleteByQuery, h as createMany, l as getOrCreate, m as create, n as update, o as exists, r as updateByQuery, s as getById, t as findOneAndUpdate, x as compileFilterToMongo, y as distinct } from "./update-1Lq9OMD2.mjs";
|
|
3
3
|
import { n as warn } from "./logger-K7dPmu2U.mjs";
|
|
4
4
|
import { n as isDuplicateKeyError, r as parseDuplicateKeyError, t as createError } from "./error-BuByZwKU.mjs";
|
|
@@ -16,20 +16,56 @@ import { decodeAggCursor, encodeAggCursor, isKeysetMode, normalizeGroupBy, valid
|
|
|
16
16
|
* predicate the purge targets.
|
|
17
17
|
*/
|
|
18
18
|
function createMongoPurgePort(repo, field, value, session) {
|
|
19
|
-
|
|
19
|
+
return createKeysetPurgePort(repo, { [field]: value }, session);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Build a `PurgePort` bound to a repository + a pre-compiled Mongo filter
|
|
23
|
+
* (the repository compiles Filter IR via `compileFilterToMongo` before
|
|
24
|
+
* calling this) — the range/filter-scoped sibling of
|
|
25
|
+
* {@link createMongoPurgePort}.
|
|
26
|
+
*
|
|
27
|
+
* The per-strategy chunk logic is IDENTICAL to the equality-bound port; the
|
|
28
|
+
* only difference is the base predicate — an arbitrary compiled filter (a
|
|
29
|
+
* `civilDate` window, a retention cutoff, a compound cohort) instead of
|
|
30
|
+
* `{ [field]: value }`. The narrowed write is re-asserted on
|
|
31
|
+
* `{ _id: { $in: ids }, ...filter }`, the same defense the equality port
|
|
32
|
+
* uses, so a row that leaves the matching set between the id select and the
|
|
33
|
+
* write is never touched.
|
|
34
|
+
*
|
|
35
|
+
* Mirrors `createMongoArchivePort`, which likewise binds a pre-compiled
|
|
36
|
+
* filter rather than a `field/value` pair.
|
|
37
|
+
*/
|
|
38
|
+
function createMongoPurgePortFromFilter(repo, filter, session) {
|
|
39
|
+
return createKeysetPurgePort(repo, filter, session);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Shared keyset-progressed port both public factories delegate to. The
|
|
43
|
+
* closure's `cursor` is the port's single-run progression state.
|
|
44
|
+
*/
|
|
45
|
+
function createKeysetPurgePort(repo, baseFilter, session) {
|
|
20
46
|
const baseOpts = {
|
|
21
47
|
session,
|
|
22
48
|
bypassTenant: true
|
|
23
49
|
};
|
|
50
|
+
let cursor = null;
|
|
51
|
+
const selectFilter = () => cursor == null ? baseFilter : {
|
|
52
|
+
...baseFilter,
|
|
53
|
+
_id: { $gt: cursor }
|
|
54
|
+
};
|
|
24
55
|
return { async purgeChunk(strategy, limit) {
|
|
25
56
|
if (strategy.type === "anonymize") {
|
|
26
|
-
if (Object.values(strategy.fields).some((v) => typeof v === "function"))
|
|
57
|
+
if (Object.values(strategy.fields).some((v) => typeof v === "function")) {
|
|
58
|
+
const { processed, lastId } = await purgeAnonymizeFunctional(repo, selectFilter(), strategy.fields, limit, session);
|
|
59
|
+
if (lastId != null) cursor = lastId;
|
|
60
|
+
return processed;
|
|
61
|
+
}
|
|
27
62
|
}
|
|
28
|
-
const idDocs = await repo.Model.find(
|
|
63
|
+
const idDocs = await repo.Model.find(selectFilter(), { _id: 1 }).sort({ _id: 1 }).limit(limit).session(session ?? null).lean().exec();
|
|
29
64
|
if (idDocs.length === 0) return 0;
|
|
65
|
+
const ids = idDocs.map((d) => d._id);
|
|
30
66
|
const chunkFilter = {
|
|
31
|
-
|
|
32
|
-
|
|
67
|
+
...baseFilter,
|
|
68
|
+
_id: { $in: ids }
|
|
33
69
|
};
|
|
34
70
|
switch (strategy.type) {
|
|
35
71
|
case "hard":
|
|
@@ -37,17 +73,19 @@ function createMongoPurgePort(repo, field, value, session) {
|
|
|
37
73
|
...baseOpts,
|
|
38
74
|
mode: "hard"
|
|
39
75
|
});
|
|
40
|
-
|
|
76
|
+
break;
|
|
41
77
|
case "soft":
|
|
42
78
|
await repo.updateMany(chunkFilter, { $set: {
|
|
43
79
|
[strategy.deletedField ?? "deleted"]: true,
|
|
44
80
|
[strategy.deletedAtField ?? "deletedAt"]: /* @__PURE__ */ new Date()
|
|
45
81
|
} }, baseOpts);
|
|
46
|
-
|
|
82
|
+
break;
|
|
47
83
|
case "anonymize":
|
|
48
84
|
await repo.updateMany(chunkFilter, { $set: strategy.fields }, baseOpts);
|
|
49
|
-
|
|
85
|
+
break;
|
|
50
86
|
}
|
|
87
|
+
cursor = ids[ids.length - 1];
|
|
88
|
+
return idDocs.length;
|
|
51
89
|
} };
|
|
52
90
|
}
|
|
53
91
|
/**
|
|
@@ -56,13 +94,20 @@ function createMongoPurgePort(repo, field, value, session) {
|
|
|
56
94
|
* heterogeneous `updateOne` ops. Two round-trips per chunk regardless
|
|
57
95
|
* of N — vs the N+1 of per-doc `update()` fan-out.
|
|
58
96
|
*
|
|
97
|
+
* Selection is `_id`-ascending against the caller's keyset-narrowed
|
|
98
|
+
* filter; returns the chunk's last `_id` so the port can advance its
|
|
99
|
+
* cursor after the write commits.
|
|
100
|
+
*
|
|
59
101
|
* Mongo's `bulkWrite` is ordered: false → independent failures don't
|
|
60
102
|
* abort the batch. For idempotent anonymize (same row anonymized twice
|
|
61
103
|
* is the same write), this matches the at-least-once contract.
|
|
62
104
|
*/
|
|
63
|
-
async function purgeAnonymizeFunctional(repo,
|
|
64
|
-
const docs = await repo.Model.find(
|
|
65
|
-
if (docs.length === 0) return
|
|
105
|
+
async function purgeAnonymizeFunctional(repo, selectFilter, fields, limit, session) {
|
|
106
|
+
const docs = await repo.Model.find(selectFilter).sort({ _id: 1 }).limit(limit).session(session ?? null).lean().exec();
|
|
107
|
+
if (docs.length === 0) return {
|
|
108
|
+
processed: 0,
|
|
109
|
+
lastId: null
|
|
110
|
+
};
|
|
66
111
|
const operations = docs.map((doc) => {
|
|
67
112
|
const set = {};
|
|
68
113
|
for (const [k, v] of Object.entries(fields)) set[k] = typeof v === "function" ? v(doc) : v;
|
|
@@ -75,7 +120,10 @@ async function purgeAnonymizeFunctional(repo, filter, fields, limit, session) {
|
|
|
75
120
|
ordered: false,
|
|
76
121
|
session: session ?? void 0
|
|
77
122
|
});
|
|
78
|
-
return
|
|
123
|
+
return {
|
|
124
|
+
processed: docs.length,
|
|
125
|
+
lastId: docs[docs.length - 1]?._id ?? null
|
|
126
|
+
};
|
|
79
127
|
}
|
|
80
128
|
//#endregion
|
|
81
129
|
//#region src/capabilities.ts
|
|
@@ -97,6 +145,7 @@ const MONGOKIT_CAPABILITIES = {
|
|
|
97
145
|
getOrCreate: true,
|
|
98
146
|
countAndExists: true,
|
|
99
147
|
purgeByField: true,
|
|
148
|
+
purgeByFilter: true,
|
|
100
149
|
archiveByFilter: true,
|
|
101
150
|
arrayOperators: true,
|
|
102
151
|
regexFilter: true,
|
|
@@ -543,7 +592,7 @@ function buildAggPipeline(req) {
|
|
|
543
592
|
const match = compileFilterToMongo(baseFilter);
|
|
544
593
|
if (Object.keys(match).length > 0) stages.push({ $match: match });
|
|
545
594
|
}
|
|
546
|
-
if (req.lookups && req.lookups.length > 0) appendLookupStages(stages, req.lookups);
|
|
595
|
+
if (req.lookups && req.lookups.length > 0) appendLookupStages$1(stages, req.lookups);
|
|
547
596
|
if (joinedFilter !== void 0) {
|
|
548
597
|
const match = compileFilterToMongo(joinedFilter);
|
|
549
598
|
if (Object.keys(match).length > 0) stages.push({ $match: match });
|
|
@@ -698,7 +747,7 @@ function validateBucketAliases(bucketAliases, groupCols, measures) {
|
|
|
698
747
|
function safeIdKey(field) {
|
|
699
748
|
return field.includes(".") ? field.replace(/\./g, "__") : field;
|
|
700
749
|
}
|
|
701
|
-
function appendLookupStages(stages, lookups) {
|
|
750
|
+
function appendLookupStages$1(stages, lookups) {
|
|
702
751
|
const asLookupOptions = lookups;
|
|
703
752
|
stages.push(...LookupBuilder.multiple(asLookupOptions));
|
|
704
753
|
for (const lookup of lookups) if (lookup.single) {
|
|
@@ -1470,6 +1519,59 @@ var AggregationBuilder = class AggregationBuilder {
|
|
|
1470
1519
|
* ```
|
|
1471
1520
|
*/
|
|
1472
1521
|
//#endregion
|
|
1522
|
+
//#region src/repository/lookup-populate.ts
|
|
1523
|
+
/**
|
|
1524
|
+
* Inclusion projections must carry the keyset sort fields (plus `_id`) or
|
|
1525
|
+
* cursor encoding has no values to serialize. No-op for exclusion
|
|
1526
|
+
* projections and cursor-less calls.
|
|
1527
|
+
*/
|
|
1528
|
+
function ensureLookupProjectionIncludesCursorFields(projection, sort) {
|
|
1529
|
+
if (!projection || !sort) return projection;
|
|
1530
|
+
if (!Object.values(projection).some((value) => value === 1)) return projection;
|
|
1531
|
+
const nextProjection = { ...projection };
|
|
1532
|
+
for (const field of [...Object.keys(sort), "_id"]) nextProjection[field] = 1;
|
|
1533
|
+
return nextProjection;
|
|
1534
|
+
}
|
|
1535
|
+
/**
|
|
1536
|
+
* Build the `$project` map from a caller's select spec (string / array /
|
|
1537
|
+
* inclusion-exclusion record). For inclusion projections, every lookup's
|
|
1538
|
+
* `as` field is auto-included so `$project` doesn't strip the joined data.
|
|
1539
|
+
* Returns a fresh object (callers may add fields for cursor encoding).
|
|
1540
|
+
*/
|
|
1541
|
+
function buildLookupProjection(selectSpec, lookups) {
|
|
1542
|
+
if (!selectSpec) return void 0;
|
|
1543
|
+
let projection;
|
|
1544
|
+
if (typeof selectSpec === "string") {
|
|
1545
|
+
projection = {};
|
|
1546
|
+
for (const field of selectSpec.split(",").map((f) => f.trim())) if (field.startsWith("-")) projection[field.substring(1)] = 0;
|
|
1547
|
+
else projection[field] = 1;
|
|
1548
|
+
} else if (Array.isArray(selectSpec)) {
|
|
1549
|
+
projection = {};
|
|
1550
|
+
for (const field of selectSpec) if (field.startsWith("-")) projection[field.substring(1)] = 0;
|
|
1551
|
+
else projection[field] = 1;
|
|
1552
|
+
} else projection = { ...selectSpec };
|
|
1553
|
+
if (Object.values(projection).some((v) => v === 1)) for (const lookup of lookups) {
|
|
1554
|
+
const asField = lookup.as || lookup.from;
|
|
1555
|
+
if (!(asField in projection)) projection[asField] = 1;
|
|
1556
|
+
}
|
|
1557
|
+
return projection;
|
|
1558
|
+
}
|
|
1559
|
+
/**
|
|
1560
|
+
* Append the shared pipeline tail: `$lookup` stages, `$ifNull` coalescing
|
|
1561
|
+
* for `single` lookups, and the final `$project` (with cursor fields kept
|
|
1562
|
+
* when a keyset sort is active). Mutates `pipeline` in place — it is the
|
|
1563
|
+
* tail-builder both the keyset and offset modes share.
|
|
1564
|
+
*/
|
|
1565
|
+
function appendLookupStages(pipeline, lookups, projection, keysetSort) {
|
|
1566
|
+
pipeline.push(...LookupBuilder.multiple(lookups));
|
|
1567
|
+
for (const lookup of lookups) if (lookup.single) {
|
|
1568
|
+
const asField = lookup.as || lookup.from;
|
|
1569
|
+
pipeline.push({ $addFields: { [asField]: { $ifNull: [`$${asField}`, null] } } });
|
|
1570
|
+
}
|
|
1571
|
+
const finalProjection = ensureLookupProjectionIncludesCursorFields(projection, keysetSort);
|
|
1572
|
+
if (finalProjection) pipeline.push({ $project: finalProjection });
|
|
1573
|
+
}
|
|
1574
|
+
//#endregion
|
|
1473
1575
|
//#region src/tx-bound.ts
|
|
1474
1576
|
/**
|
|
1475
1577
|
* Map of session-aware method name → positional index of the `{ session }`
|
|
@@ -1678,15 +1780,35 @@ function isTransactionUnsupported(error) {
|
|
|
1678
1780
|
const message = (error.message || "").toLowerCase();
|
|
1679
1781
|
return message.includes("transaction numbers are only allowed on a replica set member") || message.includes("transaction is not supported") || message.includes("does not support retryable writes");
|
|
1680
1782
|
}
|
|
1783
|
+
/**
|
|
1784
|
+
* PROACTIVELY report whether a connection's deployment supports multi-document
|
|
1785
|
+
* transactions — the read-side companion to {@link isTransactionUnsupported}
|
|
1786
|
+
* (which classifies a FAILED attempt). Single source of truth for the topology
|
|
1787
|
+
* check so callers don't hand-roll `client.topology.description.type` probing.
|
|
1788
|
+
*
|
|
1789
|
+
* Returns `false` ONLY when the topology is positively a standalone (`'Single'`)
|
|
1790
|
+
* server; an unknown/undefined topology (not yet connected, non-standard
|
|
1791
|
+
* connection object) returns `true` — optimistic, because a genuine failure is
|
|
1792
|
+
* still caught reactively by `isTransactionUnsupported`. Lets a caller skip a
|
|
1793
|
+
* doomed transaction attempt on standalone dev Mongo rather than starting one
|
|
1794
|
+
* just to catch the error.
|
|
1795
|
+
*
|
|
1796
|
+
* Accepts a Mongoose `Connection` (or anything exposing `getClient()`/`client`
|
|
1797
|
+
* with a driver `topology`), so it stays decoupled from mongoose types.
|
|
1798
|
+
*/
|
|
1799
|
+
function supportsTransactions(connection) {
|
|
1800
|
+
const probe = connection;
|
|
1801
|
+
if (!probe) return true;
|
|
1802
|
+
let client;
|
|
1803
|
+
try {
|
|
1804
|
+
client = probe.getClient?.() ?? probe.client ?? void 0;
|
|
1805
|
+
} catch {
|
|
1806
|
+
return true;
|
|
1807
|
+
}
|
|
1808
|
+
return client?.topology?.description?.type !== "Single";
|
|
1809
|
+
}
|
|
1681
1810
|
//#endregion
|
|
1682
1811
|
//#region src/Repository.ts
|
|
1683
|
-
function ensureLookupProjectionIncludesCursorFields(projection, sort) {
|
|
1684
|
-
if (!projection || !sort) return projection;
|
|
1685
|
-
if (!Object.values(projection).some((value) => value === 1)) return projection;
|
|
1686
|
-
const nextProjection = { ...projection };
|
|
1687
|
-
for (const field of [...Object.keys(sort), "_id"]) nextProjection[field] = 1;
|
|
1688
|
-
return nextProjection;
|
|
1689
|
-
}
|
|
1690
1812
|
/**
|
|
1691
1813
|
* Validates that an update patch is homogeneous — either all top-level
|
|
1692
1814
|
* keys are `$`-prefixed Mongo operators OR none are. Mixed shapes (e.g.
|
|
@@ -3395,6 +3517,24 @@ var Repository = class extends RepositoryBase {
|
|
|
3395
3517
|
return runChunkedPurge(strategy, options, createMongoPurgePort(this, field, value, options.session));
|
|
3396
3518
|
}
|
|
3397
3519
|
/**
|
|
3520
|
+
* Range/filter-scoped purge — see `StandardRepo.purgeByFilter` for the
|
|
3521
|
+
* cross-kit contract. The compliance primitive for "purge/anonymize a
|
|
3522
|
+
* slice across a RANGE while retaining measures" (redact a PII dimension
|
|
3523
|
+
* across a `civilDate` window, hard-delete past a retention cutoff): the
|
|
3524
|
+
* base predicate is an arbitrary compiled filter, not `field = value`.
|
|
3525
|
+
*
|
|
3526
|
+
* Composes the kit-agnostic `runChunkedPurge` orchestrator (loop, signal,
|
|
3527
|
+
* progress, result envelope) with `createMongoPurgePortFromFilter` (the
|
|
3528
|
+
* filter-bound sibling of `createMongoPurgePort`). Accepts Filter IR or a
|
|
3529
|
+
* Mongo-shaped filter record — compiled once via `compileFilterToMongo`,
|
|
3530
|
+
* the same dual-dialect rule as `archiveByFilter` and every other verb.
|
|
3531
|
+
* See [actions/purge.ts](./actions/purge.ts) for the port.
|
|
3532
|
+
*/
|
|
3533
|
+
async purgeByFilter(filter, strategy, options = {}) {
|
|
3534
|
+
const compiled = compileFilterToMongo(filter);
|
|
3535
|
+
return runChunkedPurge(strategy, options, createMongoPurgePortFromFilter(this, compiled, options.session));
|
|
3536
|
+
}
|
|
3537
|
+
/**
|
|
3398
3538
|
* Chunked cold-storage extraction — see `StandardRepo.archiveByFilter`
|
|
3399
3539
|
* for the cross-kit contract (write-before-delete, at-least-once,
|
|
3400
3540
|
* duplicate-tolerant sinks). Mongokit composes the kit-agnostic
|
|
@@ -3423,6 +3563,15 @@ var Repository = class extends RepositoryBase {
|
|
|
3423
3563
|
* Routes through the hook system for policy enforcement
|
|
3424
3564
|
* (multi-tenant, soft-delete).
|
|
3425
3565
|
*
|
|
3566
|
+
* The pipeline parameter also accepts `readonly unknown[]` (3.25.0):
|
|
3567
|
+
* real-world stage arrays are assembled from exported fragment builders
|
|
3568
|
+
* and spreads whose element type degrades to `unknown` — mongoose's
|
|
3569
|
+
* `PipelineStage` union can't be satisfied without an `as` at every
|
|
3570
|
+
* such call site. Runtime validation is MongoDB's job either way; the
|
|
3571
|
+
* single documented widening lives HERE instead of N host-side casts
|
|
3572
|
+
* (spine PACKAGE_RULES §7.1). Literal arrays still get full
|
|
3573
|
+
* `PipelineStage` contextual checking via the first union member.
|
|
3574
|
+
*
|
|
3426
3575
|
* @param pipeline - MongoDB aggregation stage array
|
|
3427
3576
|
* @param options - Aggregation options including governance controls
|
|
3428
3577
|
*/
|
|
@@ -3748,34 +3897,8 @@ var Repository = class extends RepositoryBase {
|
|
|
3748
3897
|
const pageFromContext = context.page ?? options.page;
|
|
3749
3898
|
const isKeyset = !!after || !pageFromContext && !!sort;
|
|
3750
3899
|
const countStrategy = context.countStrategy ?? options.countStrategy ?? "exact";
|
|
3751
|
-
const
|
|
3752
|
-
|
|
3753
|
-
if (selectSpec) {
|
|
3754
|
-
if (typeof selectSpec === "string") {
|
|
3755
|
-
projection = {};
|
|
3756
|
-
for (const field of selectSpec.split(",").map((f) => f.trim())) if (field.startsWith("-")) projection[field.substring(1)] = 0;
|
|
3757
|
-
else projection[field] = 1;
|
|
3758
|
-
} else if (Array.isArray(selectSpec)) {
|
|
3759
|
-
projection = {};
|
|
3760
|
-
for (const field of selectSpec) if (field.startsWith("-")) projection[field.substring(1)] = 0;
|
|
3761
|
-
else projection[field] = 1;
|
|
3762
|
-
} else projection = { ...selectSpec };
|
|
3763
|
-
if (projection) {
|
|
3764
|
-
if (Object.values(projection).some((v) => v === 1)) for (const lookup of lookups) {
|
|
3765
|
-
const asField = lookup.as || lookup.from;
|
|
3766
|
-
if (!(asField in projection)) projection[asField] = 1;
|
|
3767
|
-
}
|
|
3768
|
-
}
|
|
3769
|
-
}
|
|
3770
|
-
const appendLookupStages = (pipeline) => {
|
|
3771
|
-
pipeline.push(...LookupBuilder.multiple(lookups));
|
|
3772
|
-
for (const lookup of lookups) if (lookup.single) {
|
|
3773
|
-
const asField = lookup.as || lookup.from;
|
|
3774
|
-
pipeline.push({ $addFields: { [asField]: { $ifNull: [`$${asField}`, null] } } });
|
|
3775
|
-
}
|
|
3776
|
-
const finalProjection = ensureLookupProjectionIncludesCursorFields(projection, isKeyset && sort ? this._parseSort(sort) : void 0);
|
|
3777
|
-
if (finalProjection) pipeline.push({ $project: finalProjection });
|
|
3778
|
-
};
|
|
3900
|
+
const projection = buildLookupProjection(context.select ?? options.select, lookups);
|
|
3901
|
+
const appendLookupStages$2 = (pipeline) => appendLookupStages(pipeline, lookups, projection, isKeyset && sort ? this._parseSort(sort) : void 0);
|
|
3779
3902
|
if (isKeyset && sort) {
|
|
3780
3903
|
const parsedSort = this._parseSort(sort);
|
|
3781
3904
|
const { validateKeysetSort } = await import("./PaginationEngine-CczbvCAq.mjs").then((n) => n.n);
|
|
@@ -3794,7 +3917,7 @@ var Repository = class extends RepositoryBase {
|
|
|
3794
3917
|
if (Object.keys(matchFilters).length > 0) pipeline.push({ $match: matchFilters });
|
|
3795
3918
|
pipeline.push({ $sort: normalizedSort });
|
|
3796
3919
|
pipeline.push({ $limit: limit + 1 });
|
|
3797
|
-
appendLookupStages(pipeline);
|
|
3920
|
+
appendLookupStages$2(pipeline);
|
|
3798
3921
|
const aggregation = this.Model.aggregate(pipeline).session(session || null);
|
|
3799
3922
|
if (collation) aggregation.collation(collation);
|
|
3800
3923
|
if (readPref) aggregation.read(readPref);
|
|
@@ -3823,7 +3946,7 @@ var Repository = class extends RepositoryBase {
|
|
|
3823
3946
|
if (sort) dataPipeline.push({ $sort: this._parseSort(sort) });
|
|
3824
3947
|
if (countStrategy === "none") {
|
|
3825
3948
|
dataPipeline.push({ $skip: skip }, { $limit: limit + 1 });
|
|
3826
|
-
appendLookupStages(dataPipeline);
|
|
3949
|
+
appendLookupStages$2(dataPipeline);
|
|
3827
3950
|
const aggregation = this.Model.aggregate(dataPipeline).session(session || null);
|
|
3828
3951
|
if (collation) aggregation.collation(collation);
|
|
3829
3952
|
if (readPref) aggregation.read(readPref);
|
|
@@ -3847,7 +3970,7 @@ var Repository = class extends RepositoryBase {
|
|
|
3847
3970
|
return result;
|
|
3848
3971
|
}
|
|
3849
3972
|
dataPipeline.push({ $skip: skip }, { $limit: limit });
|
|
3850
|
-
appendLookupStages(dataPipeline);
|
|
3973
|
+
appendLookupStages$2(dataPipeline);
|
|
3851
3974
|
const countPipeline = [];
|
|
3852
3975
|
if (filters && Object.keys(filters).length > 0) countPipeline.push({ $match: filters });
|
|
3853
3976
|
countPipeline.push({ $count: "total" });
|
|
@@ -4180,4 +4303,4 @@ var Repository = class extends RepositoryBase {
|
|
|
4180
4303
|
}
|
|
4181
4304
|
};
|
|
4182
4305
|
//#endregion
|
|
4183
|
-
export {
|
|
4306
|
+
export { supportsTransactions as a, ALL_OPERATIONS as c, READ_OPERATIONS as d, operationsByPolicyKey as f, isTransactionUnsupported as i, MUTATING_OPERATIONS as l, createMongoPurgePort as m, Repository as n, withTransaction as o, MONGOKIT_CAPABILITIES as p, batchTransaction as r, AggregationBuilder as s, HOOK_PRIORITY$1 as t, OP_REGISTRY as u };
|
package/dist/actions/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as create_d_exports, i as delete_d_exports, n as update_d_exports, o as aggregate_d_exports, r as read_d_exports } from "../index-
|
|
1
|
+
import { a as create_d_exports, i as delete_d_exports, n as update_d_exports, o as aggregate_d_exports, r as read_d_exports } from "../index-DceInCTX.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 };
|
package/dist/adapter/index.d.mts
CHANGED
|
@@ -59,7 +59,7 @@ interface MongooseAdapterOptions<TDoc = unknown> {
|
|
|
59
59
|
* `@classytic/repo-core/adapter`.
|
|
60
60
|
*/
|
|
61
61
|
declare class MongooseAdapter<TDoc = unknown> implements DataAdapter<TDoc> {
|
|
62
|
-
readonly type:
|
|
62
|
+
readonly type: "mongoose";
|
|
63
63
|
readonly name: string;
|
|
64
64
|
readonly model: Model<TDoc>;
|
|
65
65
|
readonly repository: RepositoryLike<TDoc>;
|
package/dist/adapter/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as createMongooseAdapter, r as isMongooseModel, t as MongooseAdapter } from "../adapter-
|
|
1
|
+
import { n as createMongooseAdapter, r as isMongooseModel, t as MongooseAdapter } from "../adapter-CLvUHiTW.mjs";
|
|
2
2
|
export { MongooseAdapter, createMongooseAdapter, isMongooseModel };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as warn } from "./logger-K7dPmu2U.mjs";
|
|
2
|
-
import { t as buildCrudSchemasFromModel } from "./mongooseToJsonSchema-
|
|
2
|
+
import { t as buildCrudSchemasFromModel } from "./mongooseToJsonSchema-CByt1VhQ.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";
|
package/dist/ai/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { n as Repository } from "../Repository-
|
|
2
|
-
import { n as createMongooseAdapter } from "../adapter-
|
|
1
|
+
import { n as Repository } from "../Repository-BFBTAMlA.mjs";
|
|
2
|
+
import { n as createMongooseAdapter } from "../adapter-CLvUHiTW.mjs";
|
|
3
3
|
import { pluralizeBetterAuthCollection, resolveBetterAuthCollections } from "@classytic/repo-core/better-auth";
|
|
4
4
|
//#region src/better-auth/index.ts
|
|
5
5
|
/**
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Document, Model, PopulateOptions, Types } from "mongoose";
|
|
2
|
+
//#region src/types/core.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Core query/document primitives shared across every mongokit module —
|
|
5
|
+
* sort/select/populate/filter specs and the mongoose-facing aliases.
|
|
6
|
+
*
|
|
7
|
+
* Also the home of the `softRequired` Mongoose declaration merge (this file
|
|
8
|
+
* is loaded by every module, so the augmentation is always in the program).
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Global declaration merge: adds `softRequired` to Mongoose's SchemaTypeOptions
|
|
12
|
+
* so consumers can annotate paths type-safely without importing anything.
|
|
13
|
+
*
|
|
14
|
+
* A path with `softRequired: true` keeps its DB-level `required: true`
|
|
15
|
+
* invariant but is excluded from the auto-generated CRUD body `required[]`
|
|
16
|
+
* array (see buildCrudSchemasFromModel).
|
|
17
|
+
*/
|
|
18
|
+
declare module 'mongoose' {
|
|
19
|
+
interface SchemaTypeOptions<T, EnforcedDocType = any, THydratedDocumentType = HydratedDocument<EnforcedDocType>> {
|
|
20
|
+
/** mongokit: omit from auto-generated CRUD body `required` array. */
|
|
21
|
+
softRequired?: boolean;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/** Read Preference Type for replica sets */
|
|
25
|
+
type ReadPreferenceType = 'primary' | 'primaryPreferred' | 'secondary' | 'secondaryPreferred' | 'nearest' | (string & {});
|
|
26
|
+
/** Re-export mongoose ObjectId */
|
|
27
|
+
type ObjectId = Types.ObjectId;
|
|
28
|
+
/** Generic document type */
|
|
29
|
+
type AnyDocument = Document & Record<string, unknown>;
|
|
30
|
+
/** Generic model type */
|
|
31
|
+
type AnyModel = Model<AnyDocument>;
|
|
32
|
+
/** Sort direction */
|
|
33
|
+
type SortDirection = 1 | -1;
|
|
34
|
+
/** Sort specification for MongoDB queries */
|
|
35
|
+
type SortSpec = Record<string, SortDirection>;
|
|
36
|
+
/** Populate specification */
|
|
37
|
+
type PopulateSpec = string | string[] | PopulateOptions | PopulateOptions[];
|
|
38
|
+
/**
|
|
39
|
+
* Select specification. `readonly string[]` widens the legacy `string[]`
|
|
40
|
+
* form to also accept the immutable variant repo-core's contract uses
|
|
41
|
+
* (`LookupPopulateOptions.select: readonly string[] | Record<string, 0
|
|
42
|
+
* | 1>`), so `Repository<TDoc>` assigns to `StandardRepo<TDoc>` without
|
|
43
|
+
* TS2322 on the `select` field. Any existing mutable-array caller stays
|
|
44
|
+
* compatible — `string[]` is assignable to `readonly string[]`.
|
|
45
|
+
*/
|
|
46
|
+
type SelectSpec = string | readonly string[] | Record<string, 0 | 1>;
|
|
47
|
+
/** Filter query type for MongoDB queries (compatible with Mongoose 8 & 9) */
|
|
48
|
+
type FilterQuery<_T = unknown> = Record<string, unknown>;
|
|
49
|
+
//#endregion
|
|
50
|
+
export { PopulateSpec as a, SortDirection as c, ObjectId as i, SortSpec as l, AnyModel as n, ReadPreferenceType as o, FilterQuery as r, SelectSpec as s, AnyDocument as t };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { n as Repository } from "./Repository-
|
|
2
|
-
import { a as methodRegistryPlugin, d as cachePlugin, f as batchOperationsPlugin,
|
|
1
|
+
import { n as Repository } from "./Repository-BFBTAMlA.mjs";
|
|
2
|
+
import { a as methodRegistryPlugin, d as cachePlugin, f as batchOperationsPlugin, g as auditLogPlugin, i as multiTenantPlugin, m as auditTrailPlugin, n as softDeletePlugin, o as customIdPlugin, t as timestampPlugin } from "./timestamp.plugin-ennbatTW.mjs";
|
|
3
3
|
//#region src/create-repository.ts
|
|
4
4
|
function isLoggerAudit(value) {
|
|
5
5
|
const v = value;
|
|
@@ -1,12 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { t as
|
|
1
|
+
import { _ as WithTransactionOptions, a as DeleteManyResult, f as OperationOptions, g as UpdateOptions, h as UpdateManyResult, i as CreateOptions, l as LookupPopulateOptions, m as SessionOptions, o as DeleteResult, p as ReadOptions, r as CacheableOptions, s as FindOneAndUpdateOptions, t as AggregateOptions, u as LookupPopulateResult, v as LookupBuilder, y as LookupOptions } from "./operations-C8IcCHF9.mjs";
|
|
2
|
+
import { a as PopulateSpec, i as ObjectId, l as SortSpec$1, o as ReadPreferenceType, s as SelectSpec } from "./core-62oo3N1C.mjs";
|
|
3
|
+
import { c as PaginationConfig, r as CollationOptions, t as AggregatePaginationOptions } from "./pagination-jSUdrACK.mjs";
|
|
4
|
+
import { _ as RepositoryOptions, d as PluginType, f as PrioritizedHook, o as Middleware, p as RepositoryContext } from "./repository-DCHRWRXw.mjs";
|
|
5
|
+
import { T as AuditTrailOptions, _ as RepositoryCachePluginOptions, i as CustomIdOptions, t as MultiTenantOptions } from "./multi-tenant.plugin-DVyVGREb.mjs";
|
|
6
|
+
import { t as PaginationEngine } from "./PaginationEngine-CBS1XGzp.mjs";
|
|
7
|
+
import { i as Logger, o as SoftDeleteOptions } from "./plugin-options-vFufQZMZ.mjs";
|
|
4
8
|
import { AggPaginationRequest, AggRequest, AggResult, ArchiveOptions, ArchiveResult, ArchiveSink, ChangeEvent, FilterInput, KeysetAggPaginationResult, QueryOptions, RepoCapabilities, RepositoryBase, TenantPurgeOptions, TenantPurgeResult, TenantPurgeStrategy, WatchOptions } from "@classytic/repo-core/repository";
|
|
5
9
|
import { ClientSession, Expression, Model, PipelineStage, PopulateOptions } from "mongoose";
|
|
6
10
|
import { Filter } from "@classytic/repo-core/filter";
|
|
7
11
|
import { UpdateInput } from "@classytic/repo-core/update";
|
|
8
|
-
import { AggregatePaginationResult, KeysetPaginationResult, OffsetPaginationResult, OffsetPaginationResultCore } from "@classytic/repo-core/pagination";
|
|
9
12
|
import { HttpError } from "@classytic/repo-core/errors";
|
|
13
|
+
import { AggregatePaginationResult, KeysetPaginationResult, OffsetPaginationResult, OffsetPaginationResultCore } from "@classytic/repo-core/pagination";
|
|
10
14
|
//#region src/query/AggregationBuilder.d.ts
|
|
11
15
|
/** Options for $vectorSearch stage (Atlas only) */
|
|
12
16
|
interface VectorSearchOptions {
|
|
@@ -1458,6 +1462,21 @@ declare class Repository<TDoc = unknown> extends RepositoryBase {
|
|
|
1458
1462
|
* the port implementation.
|
|
1459
1463
|
*/
|
|
1460
1464
|
purgeByField(field: string, value: unknown, strategy: TenantPurgeStrategy, options?: TenantPurgeOptions): Promise<TenantPurgeResult>;
|
|
1465
|
+
/**
|
|
1466
|
+
* Range/filter-scoped purge — see `StandardRepo.purgeByFilter` for the
|
|
1467
|
+
* cross-kit contract. The compliance primitive for "purge/anonymize a
|
|
1468
|
+
* slice across a RANGE while retaining measures" (redact a PII dimension
|
|
1469
|
+
* across a `civilDate` window, hard-delete past a retention cutoff): the
|
|
1470
|
+
* base predicate is an arbitrary compiled filter, not `field = value`.
|
|
1471
|
+
*
|
|
1472
|
+
* Composes the kit-agnostic `runChunkedPurge` orchestrator (loop, signal,
|
|
1473
|
+
* progress, result envelope) with `createMongoPurgePortFromFilter` (the
|
|
1474
|
+
* filter-bound sibling of `createMongoPurgePort`). Accepts Filter IR or a
|
|
1475
|
+
* Mongo-shaped filter record — compiled once via `compileFilterToMongo`,
|
|
1476
|
+
* the same dual-dialect rule as `archiveByFilter` and every other verb.
|
|
1477
|
+
* See [actions/purge.ts](./actions/purge.ts) for the port.
|
|
1478
|
+
*/
|
|
1479
|
+
purgeByFilter(filter: Record<string, unknown> | Filter, strategy: TenantPurgeStrategy, options?: TenantPurgeOptions): Promise<TenantPurgeResult>;
|
|
1461
1480
|
/**
|
|
1462
1481
|
* Chunked cold-storage extraction — see `StandardRepo.archiveByFilter`
|
|
1463
1482
|
* for the cross-kit contract (write-before-delete, at-least-once,
|
|
@@ -1486,10 +1505,19 @@ declare class Repository<TDoc = unknown> extends RepositoryBase {
|
|
|
1486
1505
|
* Routes through the hook system for policy enforcement
|
|
1487
1506
|
* (multi-tenant, soft-delete).
|
|
1488
1507
|
*
|
|
1508
|
+
* The pipeline parameter also accepts `readonly unknown[]` (3.25.0):
|
|
1509
|
+
* real-world stage arrays are assembled from exported fragment builders
|
|
1510
|
+
* and spreads whose element type degrades to `unknown` — mongoose's
|
|
1511
|
+
* `PipelineStage` union can't be satisfied without an `as` at every
|
|
1512
|
+
* such call site. Runtime validation is MongoDB's job either way; the
|
|
1513
|
+
* single documented widening lives HERE instead of N host-side casts
|
|
1514
|
+
* (spine PACKAGE_RULES §7.1). Literal arrays still get full
|
|
1515
|
+
* `PipelineStage` contextual checking via the first union member.
|
|
1516
|
+
*
|
|
1489
1517
|
* @param pipeline - MongoDB aggregation stage array
|
|
1490
1518
|
* @param options - Aggregation options including governance controls
|
|
1491
1519
|
*/
|
|
1492
|
-
aggregatePipeline<TResult = unknown>(pipeline: PipelineStage[], options?: AggregateOptions): Promise<TResult[]>;
|
|
1520
|
+
aggregatePipeline<TResult = unknown>(pipeline: PipelineStage[] | readonly unknown[], options?: AggregateOptions): Promise<TResult[]>;
|
|
1493
1521
|
/**
|
|
1494
1522
|
* Paginated kit-native aggregation pipeline. Same mongo-specific
|
|
1495
1523
|
* scope as `aggregatePipeline` — reach for this when you need
|
|
@@ -15,6 +15,17 @@ import mongoose from "mongoose";
|
|
|
15
15
|
* Design: no `this`, no Model, no DB calls. Only reads `schema.paths._id.instance`.
|
|
16
16
|
*/
|
|
17
17
|
/**
|
|
18
|
+
* Null-tolerant `id → ObjectId` coercion — the single seam for optional
|
|
19
|
+
* reference/audit-stamp fields (`approvedBy`, `submittedBy`, …) where an
|
|
20
|
+
* absent actor is a legitimate `null`, not an error. Invalid non-empty
|
|
21
|
+
* strings still throw (mongoose's own constructor validation) — this helper
|
|
22
|
+
* only absorbs the absent case, never bad input. Hosts were hand-rolling
|
|
23
|
+
* this identically at every approval-hook write; import it instead.
|
|
24
|
+
*/
|
|
25
|
+
function toObjectId(id) {
|
|
26
|
+
return id ? new mongoose.Types.ObjectId(id) : null;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
18
29
|
* Check if a Mongoose SchemaType `instance` string is an ObjectId variant.
|
|
19
30
|
* Mongoose 9.x uses `'ObjectId'`, older versions use `'ObjectID'`. This
|
|
20
31
|
* is the single source of truth — use it instead of inline
|
|
@@ -103,4 +114,4 @@ function idVariants(id) {
|
|
|
103
114
|
return [id];
|
|
104
115
|
}
|
|
105
116
|
//#endregion
|
|
106
|
-
export { isValidIdForType as i, idVariants as n, isObjectIdInstance as r, getSchemaIdType as t };
|
|
117
|
+
export { toObjectId as a, isValidIdForType as i, idVariants as n, isObjectIdInstance as r, getSchemaIdType as t };
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { c as GroupResult, d as MinMaxResult, f as OperationOptions, g as UpdateOptions, h as UpdateManyResult, i as CreateOptions, o as DeleteResult, s as FindOneAndUpdateOptions, y as LookupOptions } from "./operations-C8IcCHF9.mjs";
|
|
2
|
+
import { a as PopulateSpec, i as ObjectId, l as SortSpec, o as ReadPreferenceType, s as SelectSpec, t as AnyDocument } from "./core-62oo3N1C.mjs";
|
|
3
|
+
import { p as UpdateWithValidationResult } from "./type-utils-CLzRFtIA.mjs";
|
|
2
4
|
import { Model, PipelineStage } from "mongoose";
|
|
3
5
|
declare namespace aggregate_d_exports {
|
|
4
6
|
export { aggregate, aggregatePaginate, average, countBy, distinct, facet, groupBy, lookup, minMax, sum, unwind };
|