@classytic/mongokit 3.40.0 → 3.40.1
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 +71 -0
- package/dist/{PaginationEngine-D-P19Y9m.d.mts → PaginationEngine-CRHyuUtw.d.mts} +17 -3
- package/dist/{PaginationEngine-Dvl8jcRY.mjs → PaginationEngine-CfT2Cxkj.mjs} +296 -137
- package/dist/{Repository-BMgPSkqZ.mjs → Repository-CYhSC9ut.mjs} +571 -175
- package/dist/{Repository-CR8Y9g2E.d.mts → Repository-pnLw1rG5.d.mts} +57 -16
- package/dist/actions/index.d.mts +1 -1
- package/dist/actions/index.mjs +1 -1
- package/dist/adapter/index.mjs +1 -1
- package/dist/{adapter-BrVfPFSW.mjs → adapter-CkMoMF83.mjs} +1 -1
- package/dist/ai/index.d.mts +1 -1
- package/dist/better-auth/index.mjs +2 -2
- package/dist/{create-repository-CAle1MSU.d.mts → create-repository-BUx9vfG9.d.mts} +5 -5
- package/dist/{create-repository-BzBUMvd1.mjs → create-repository-BYyWzLbt.mjs} +2 -2
- package/dist/{index-CmjNyulu.d.mts → index-SYF8N28D.d.mts} +37 -19
- package/dist/index.d.mts +55 -15
- package/dist/index.mjs +57 -11
- package/dist/join-scope-DSAznE8E.mjs +168 -0
- package/dist/{mongooseToJsonSchema-waUVQwK4.mjs → mongooseToJsonSchema-C3k4ide0.mjs} +5 -1
- package/dist/{multi-tenant.plugin-CBgCo9im.d.mts → multi-tenant.plugin-a3UhQARj.d.mts} +2 -2
- package/dist/{operations-CrRIoc8Z.d.mts → operations-XiFgG5US.d.mts} +36 -13
- package/dist/outbox/index.d.mts +1 -1
- package/dist/outbox/index.mjs +1 -1
- package/dist/pagination/PaginationEngine.d.mts +2 -2
- package/dist/pagination/PaginationEngine.mjs +1 -1
- package/dist/pagination/utils/limits.d.mts +1 -1
- package/dist/{pagination-BpIv2bdS.d.mts → pagination-D6psses0.d.mts} +116 -13
- package/dist/{plugin-options-Zk46lD6F.d.mts → plugin-options-CRhIvSzx.d.mts} +2 -2
- package/dist/plugins/index.d.mts +3 -3
- package/dist/plugins/index.mjs +2 -2
- package/dist/query-defaults-BxUcSOoF.mjs +208 -0
- package/dist/read-model/index.d.mts +66 -0
- package/dist/read-model/index.mjs +193 -0
- package/dist/{repository-odl03582.d.mts → repository-DNHfjAZX.d.mts} +16 -2
- package/dist/sync/index.d.mts +15 -2
- package/dist/sync/index.mjs +38 -1
- package/dist/testkit/index.d.mts +40 -3
- package/dist/testkit/index.mjs +113 -2
- package/dist/{timestamp.plugin-DF0gJB6p.mjs → timestamp.plugin-zfdLYZiO.mjs} +50 -31
- package/dist/{to-plain-k7SjNlSS.d.mts → to-plain-CjgEInWV.d.mts} +2 -2
- package/dist/{transaction-B5L9glO0.mjs → transaction-BrRYtH_b.mjs} +127 -5
- package/dist/{update-DG0fCwRJ.mjs → update-WgeAUJ_I.mjs} +44 -22
- package/dist/utils/index.d.mts +1 -1
- package/dist/utils/index.mjs +1 -1
- package/dist/{validation-chain.plugin-BLY2gLEk.mjs → validation-chain.plugin-CHUHWMtk.mjs} +15 -3
- package/dist/{validation-chain.plugin-DYp9E7K2.d.mts → validation-chain.plugin-CTcNJCmV.d.mts} +4 -4
- package/package.json +8 -3
package/dist/index.mjs
CHANGED
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|
import { n as idVariants } from "./id-resolution-BqDrk0S2.mjs";
|
|
2
|
-
import { a as MUTATING_OPERATIONS, c as operationsByPolicyKey, i as ALL_OPERATIONS, l as createMongoPurgePort, n as Repository, o as OP_REGISTRY, r as AggregationBuilder, s as READ_OPERATIONS, t as HOOK_PRIORITY } from "./Repository-
|
|
3
|
-
import { C as isCreateManyPartialError, g as LookupBuilder, v as compileFilterToMongo } from "./update-
|
|
2
|
+
import { a as MUTATING_OPERATIONS, c as operationsByPolicyKey, i as ALL_OPERATIONS, l as createMongoPurgePort, n as Repository, o as OP_REGISTRY, r as AggregationBuilder, s as READ_OPERATIONS, t as HOOK_PRIORITY } from "./Repository-CYhSC9ut.mjs";
|
|
3
|
+
import { C as isCreateManyPartialError, g as LookupBuilder, v as compileFilterToMongo } from "./update-WgeAUJ_I.mjs";
|
|
4
4
|
import { n as warn, t as configureLogger } from "./logger-K7dPmu2U.mjs";
|
|
5
5
|
import { n as isDuplicateKeyError, r as parseDuplicateKeyError, t as createError } from "./error-BuByZwKU.mjs";
|
|
6
|
+
import { a as assertQueryDefaultsConfigured, c as getQueryDefaults, l as resetQueryDefaults, o as configureAggregateDefaults, s as configureQueryDefaults, t as QUERY_DEFAULTS_ERROR_CODES, u as resolveQueryOptions } from "./query-defaults-BxUcSOoF.mjs";
|
|
6
7
|
import { t as actions_exports } from "./actions/index.mjs";
|
|
7
|
-
import { c as classifyHelloReply, d as resolveMongoCapabilities, f as resolveTransactionSupport, i as withTransaction, l as probeMongoCapabilities, n as isTransactionUnsupported, o as MONGOKIT_CAPABILITIES, p as transactionResolutionOf, r as supportsTransactions, s as capabilitiesForSupport, t as batchTransaction, u as resetCapabilityProbeCache } from "./transaction-
|
|
8
|
-
import { _ as AuditTrailQuery, a as declareTenantContextKey, b as auditLogPlugin, c as tenantContextKeysOf, d as ensureSequenceAtLeast, f as getNextSequence, g as cachePlugin, h as sequentialId, i as multiTenantPlugin, l as customIdPlugin, m as readSequence, n as softDeletePlugin, o as forwardScope, p as prefixedId, r as adminBypass, s as isScopeKey, t as timestampPlugin, u as dateSequentialId, v as auditTrailPlugin, y as ensureAuditTrailReady } from "./timestamp.plugin-
|
|
8
|
+
import { c as classifyHelloReply, d as resolveMongoCapabilities, f as resolveTransactionSupport, i as withTransaction, l as probeMongoCapabilities, n as isTransactionUnsupported, o as MONGOKIT_CAPABILITIES, p as transactionResolutionOf, r as supportsTransactions, s as capabilitiesForSupport, t as batchTransaction, u as resetCapabilityProbeCache } from "./transaction-BrRYtH_b.mjs";
|
|
9
|
+
import { _ as AuditTrailQuery, a as declareTenantContextKey, b as auditLogPlugin, c as tenantContextKeysOf, d as ensureSequenceAtLeast, f as getNextSequence, g as cachePlugin, h as sequentialId, i as multiTenantPlugin, l as customIdPlugin, m as readSequence, n as softDeletePlugin, o as forwardScope, p as prefixedId, r as adminBypass, s as isScopeKey, t as timestampPlugin, u as dateSequentialId, v as auditTrailPlugin, y as ensureAuditTrailReady } from "./timestamp.plugin-zfdLYZiO.mjs";
|
|
9
10
|
import { n as batchOperationsPlugin, t as methodRegistryPlugin } from "./method-registry.plugin-C63pGn1d.mjs";
|
|
10
|
-
import {
|
|
11
|
+
import { c as PAGINATION_ERROR_CODES, h as resetPaginationDefaults, m as getPaginationDefaults, p as configurePaginationDefaults, t as PaginationEngine } from "./PaginationEngine-CfT2Cxkj.mjs";
|
|
11
12
|
import { GEO_OPERATORS, parseGeoFilter } from "./query/primitives/geo.mjs";
|
|
12
|
-
import { t as
|
|
13
|
+
import { n as declareCollectionScope, t as JOIN_ERROR_CODES } from "./join-scope-DSAznE8E.mjs";
|
|
14
|
+
import { t as createRepository } from "./create-repository-BYyWzLbt.mjs";
|
|
13
15
|
import { n as defineModel, r as isModelRegistered, t as ModelCollisionError } from "./model-registry-ClKtWiHa.mjs";
|
|
14
|
-
import { _ as cascadePlugin, a as uniqueField, c as subdocumentPlugin, d as mongoOperationsPlugin, f as leasePlugin, g as elasticSearchPlugin, h as fieldFilterPlugin, i as requireField, l as observabilityPlugin, m as idempotencyStorePlugin, n as blockIf, o as validationChainPlugin, p as immutableStatesPlugin, r as immutableField, s as createTenantContext, t as autoInject, u as MONGOKIT_PLUGIN_NAMES, v as appendOnlyPlugin, y as aggregateHelpersPlugin } from "./validation-chain.plugin-
|
|
16
|
+
import { _ as cascadePlugin, a as uniqueField, c as subdocumentPlugin, d as mongoOperationsPlugin, f as leasePlugin, g as elasticSearchPlugin, h as fieldFilterPlugin, i as requireField, l as observabilityPlugin, m as idempotencyStorePlugin, n as blockIf, o as validationChainPlugin, p as immutableStatesPlugin, r as immutableField, s as createTenantContext, t as autoInject, u as MONGOKIT_PLUGIN_NAMES, v as appendOnlyPlugin, y as aggregateHelpersPlugin } from "./validation-chain.plugin-CHUHWMtk.mjs";
|
|
15
17
|
import { i as getMongooseProjection, n as filterResponseData, r as getFieldsForUser, t as createFieldPreset } from "./field-selection-FSQFLpsU.mjs";
|
|
16
18
|
import { buildFieldTypeMap, coerceHeuristic } from "./query/primitives/coercion.mjs";
|
|
17
19
|
import { extractSchemaIndexes } from "./query/primitives/indexes.mjs";
|
|
18
20
|
import { n as createMemoryCache, t as toPlain } from "./to-plain-vksRrLtc.mjs";
|
|
19
|
-
import { n as buildCrudSchemasFromMongooseSchema, t as buildCrudSchemasFromModel } from "./mongooseToJsonSchema-
|
|
21
|
+
import { n as buildCrudSchemasFromMongooseSchema, t as buildCrudSchemasFromModel } from "./mongooseToJsonSchema-C3k4ide0.mjs";
|
|
20
22
|
import { runChunkedPurge } from "@classytic/repo-core/repository";
|
|
23
|
+
import { stableStringify } from "@classytic/repo-core/hash";
|
|
21
24
|
import { OPERATOR_DESCRIPTIONS, QueryGrammarError, URL_OPERATORS, clausesToFilter, escapeRegex, isQueryGrammarError, readFilterClauses, readPageRequest, readSearch, readSelect, readSort } from "@classytic/repo-core/query-parser";
|
|
22
25
|
//#region src/actions/cascade-references.ts
|
|
23
26
|
/**
|
|
@@ -219,6 +222,45 @@ function defineModels(spec) {
|
|
|
219
222
|
};
|
|
220
223
|
}
|
|
221
224
|
//#endregion
|
|
225
|
+
//#region src/pagination/keyset-source.ts
|
|
226
|
+
/**
|
|
227
|
+
* `keysetSource(repo, { name, sort, filters, ...scope })` — a mongokit repository as a repo-core
|
|
228
|
+
* `KeysetSource`, for `mergeKeysetPages`. Pages are `getAll({ mode: 'keyset' })` under the given
|
|
229
|
+
* scope; the per-row cursor is `repo.keysetCursor` (scope-bound like every mongokit cursor); the
|
|
230
|
+
* source's `scope` string binds the composite cursor to (collection, filters, tenant values).
|
|
231
|
+
*/
|
|
232
|
+
function keysetSource(repo, options) {
|
|
233
|
+
const { name, sort, filters = {}, ...scope } = options;
|
|
234
|
+
const { session: _session, user: _user, ...tenant } = forwardScope(scope);
|
|
235
|
+
return {
|
|
236
|
+
name,
|
|
237
|
+
scope: `${repo.Model.collection.collectionName}:${stableStringify({
|
|
238
|
+
filters,
|
|
239
|
+
tenant
|
|
240
|
+
})}`,
|
|
241
|
+
async page({ after, limit }) {
|
|
242
|
+
const page = await repo.getAll({
|
|
243
|
+
...scope,
|
|
244
|
+
filters,
|
|
245
|
+
sort,
|
|
246
|
+
limit,
|
|
247
|
+
mode: "keyset",
|
|
248
|
+
...after ? { after } : {}
|
|
249
|
+
});
|
|
250
|
+
if (page.method !== "keyset") throw new Error("[mongokit] keysetSource: getAll did not return a keyset page");
|
|
251
|
+
return {
|
|
252
|
+
data: page.data,
|
|
253
|
+
hasMore: page.hasMore
|
|
254
|
+
};
|
|
255
|
+
},
|
|
256
|
+
cursorOf: (row) => repo.keysetCursor(row, {
|
|
257
|
+
...scope,
|
|
258
|
+
sort,
|
|
259
|
+
filters
|
|
260
|
+
})
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
//#endregion
|
|
222
264
|
//#region src/query/parser/pipeline-sanitizer.ts
|
|
223
265
|
/**
|
|
224
266
|
* Sanitize $match configuration to prevent dangerous operators.
|
|
@@ -1059,12 +1101,14 @@ var QueryParser = class {
|
|
|
1059
1101
|
parse(query) {
|
|
1060
1102
|
const rt = this.rt;
|
|
1061
1103
|
const q = query ?? {};
|
|
1062
|
-
const { page, limit, sort, populate, search, after, cursor, select, lookup, aggregate } = q;
|
|
1104
|
+
const { page, limit, sort, populate, search, after, cursor, before, mode, select, lookup, aggregate } = q;
|
|
1063
1105
|
const pageRequest = guarded(rt, () => readPageRequest({
|
|
1064
1106
|
page,
|
|
1065
1107
|
limit,
|
|
1066
1108
|
after,
|
|
1067
|
-
cursor
|
|
1109
|
+
cursor,
|
|
1110
|
+
before,
|
|
1111
|
+
mode
|
|
1068
1112
|
}, { maxLimit: rt.options.maxLimit }), readPageRequest({}, { maxLimit: rt.options.maxLimit }));
|
|
1069
1113
|
const effectiveSort = sort === void 0 && isSortFieldAllowed(rt, "-createdAt") ? DEFAULT_PARSER_SORT : sort;
|
|
1070
1114
|
const sanitizedSearch = sanitizeSearch(rt, search);
|
|
@@ -1092,6 +1136,8 @@ var QueryParser = class {
|
|
|
1092
1136
|
if (rt.options.enableLookups && lookup) parsed.lookups = parseLookups(rt, lookup);
|
|
1093
1137
|
if (rt.options.enableAggregations && aggregate) parsed.aggregation = parseAggregation(rt, aggregate);
|
|
1094
1138
|
if (pageRequest.after !== void 0) parsed.after = pageRequest.after;
|
|
1139
|
+
if (pageRequest.before !== void 0) parsed.before = pageRequest.before;
|
|
1140
|
+
if (pageRequest.mode !== void 0) parsed.mode = pageRequest.mode;
|
|
1095
1141
|
if (pageRequest.page !== void 0) parsed.page = pageRequest.page;
|
|
1096
1142
|
return parsed;
|
|
1097
1143
|
}
|
|
@@ -1391,4 +1437,4 @@ function systemContext(extra) {
|
|
|
1391
1437
|
*/
|
|
1392
1438
|
var src_default = Repository;
|
|
1393
1439
|
//#endregion
|
|
1394
|
-
export { ALL_OPERATIONS, AggregationBuilder, AuditTrailQuery, HOOK_PRIORITY, LookupBuilder, MONGOKIT_CAPABILITIES, MONGOKIT_PLUGIN_NAMES, MUTATING_OPERATIONS, ModelCollisionError, OP_REGISTRY, PaginationEngine, QueryParser, READ_OPERATIONS, Repository, actions_exports as actions, adminBypass, aggregateHelpersPlugin, appendOnlyPlugin, auditLogPlugin, auditTrailPlugin, autoInject, batchOperationsPlugin, batchTransaction, blockIf, buildCrudSchemasFromModel, buildCrudSchemasFromMongooseSchema, cachePlugin, capabilitiesForSupport, cascadePlugin, cascadePurgeReferences, classifyHelloReply, compileFilterToMongo, configureLogger, configurePaginationDefaults, createError, createFieldPreset, createMemoryCache, createOptionsExtractor, createRepository, createTenantContext, customIdPlugin, dateSequentialId, declareTenantContextKey, src_default as default, defineModel, defineModels, elasticSearchPlugin, ensureAuditTrailReady, ensureSequenceAtLeast, fieldFilterPlugin, filterResponseData, forwardScope, getFieldsForUser, getMongooseProjection, getNextSequence, getPaginationDefaults, idVariants, idempotencyStorePlugin, immutableField, immutableStatesPlugin, isCreateManyPartialError, isDuplicateKeyError, isModelRegistered, isTransactionUnsupported, leasePlugin, methodRegistryPlugin, mongoOperationsPlugin, multiTenantPlugin, observabilityPlugin, operationsByPolicyKey, parseDuplicateKeyError, prefixedId, probeMongoCapabilities, readSequence, repoOptionsFromCtx, requireField, resetCapabilityProbeCache, resetPaginationDefaults, resolveMongoCapabilities, resolveTransactionSupport, sequentialId, softDeletePlugin, subdocumentPlugin, supportsTransactions, systemContext, tenantContextKeysOf, timestampPlugin, toPlain, transactionResolutionOf, uniqueField, validationChainPlugin, withTransaction };
|
|
1440
|
+
export { ALL_OPERATIONS, AggregationBuilder, AuditTrailQuery, HOOK_PRIORITY, JOIN_ERROR_CODES, LookupBuilder, MONGOKIT_CAPABILITIES, MONGOKIT_PLUGIN_NAMES, MUTATING_OPERATIONS, ModelCollisionError, OP_REGISTRY, PAGINATION_ERROR_CODES, PaginationEngine, QUERY_DEFAULTS_ERROR_CODES, QueryParser, READ_OPERATIONS, Repository, actions_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, src_default as default, 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, sequentialId, softDeletePlugin, subdocumentPlugin, supportsTransactions, systemContext, tenantContextKeysOf, timestampPlugin, toPlain, transactionResolutionOf, uniqueField, validationChainPlugin, withTransaction };
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { t as createError } from "./error-BuByZwKU.mjs";
|
|
2
|
+
import mongoose from "mongoose";
|
|
3
|
+
//#region src/repository/join-scope.ts
|
|
4
|
+
/**
|
|
5
|
+
* Join scope — a joined collection is read under ITS OWN policy, or not at all.
|
|
6
|
+
*
|
|
7
|
+
* Policy plugins (`multiTenantPlugin`, `softDeletePlugin`) declare a scope rule on the MODEL they
|
|
8
|
+
* are bound to, and every repository marks its model governed. {@link scopeJoins} walks a
|
|
9
|
+
* pipeline (nested sub-pipelines and `$facet` branches included) and, for each `$lookup`,
|
|
10
|
+
* `$unionWith` and `$graphLookup`, resolves `from` to the registered models that own that
|
|
11
|
+
* collection, then prepends the union of their rules (fail closed). It REFUSES, with a closed
|
|
12
|
+
* code, a `from` no model owns (the silent-empty-join: a wrong literal matches nothing and raises
|
|
13
|
+
* nothing) and a collection no repository governs. `unscopedJoins` names collections the caller
|
|
14
|
+
* asserts are company-wide; a collection with a declared rule cannot be unscoped that way —
|
|
15
|
+
* `bypassTenant` is the explicit cross-tenant form.
|
|
16
|
+
*/
|
|
17
|
+
const JOIN_ERROR_CODES = {
|
|
18
|
+
UNKNOWN_COLLECTION: "mongokit.join.unknown_collection",
|
|
19
|
+
UNGOVERNED_COLLECTION: "mongokit.join.ungoverned_collection",
|
|
20
|
+
UNSCOPE_REFUSED: "mongokit.join.unscope_refused",
|
|
21
|
+
UNRESOLVABLE_FROM: "mongokit.join.unresolvable_from"
|
|
22
|
+
};
|
|
23
|
+
const RULES = Symbol.for("@classytic/mongokit/collection-scope-rules");
|
|
24
|
+
const GOVERNED = Symbol.for("@classytic/mongokit/governed-model");
|
|
25
|
+
const TENANT_FIELDS = Symbol.for("@classytic/mongokit/tenant-fields");
|
|
26
|
+
/** Called by a policy plugin at bind: reads of this model's collection carry `rule`. */
|
|
27
|
+
function declareCollectionScope(model, rule, meta = {}) {
|
|
28
|
+
const holder = model;
|
|
29
|
+
if (!holder[RULES]) Object.defineProperty(holder, RULES, {
|
|
30
|
+
value: /* @__PURE__ */ new Set(),
|
|
31
|
+
enumerable: false
|
|
32
|
+
});
|
|
33
|
+
holder[RULES]?.add(rule);
|
|
34
|
+
if (meta.tenantField) {
|
|
35
|
+
if (!holder[TENANT_FIELDS]) Object.defineProperty(holder, TENANT_FIELDS, {
|
|
36
|
+
value: /* @__PURE__ */ new Set(),
|
|
37
|
+
enumerable: false
|
|
38
|
+
});
|
|
39
|
+
holder[TENANT_FIELDS]?.add(meta.tenantField);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/** The tenant fields declared on this model by its repositories' tenant plugins. */
|
|
43
|
+
function tenantFieldsOf(model) {
|
|
44
|
+
return [...model[TENANT_FIELDS] ?? []];
|
|
45
|
+
}
|
|
46
|
+
/** Called by every Repository: this model's scope is known (possibly none). */
|
|
47
|
+
function markGoverned(model) {
|
|
48
|
+
const holder = model;
|
|
49
|
+
if (!holder[GOVERNED]) Object.defineProperty(holder, GOVERNED, {
|
|
50
|
+
value: true,
|
|
51
|
+
enumerable: false
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
function owners(connection, collection) {
|
|
55
|
+
return Object.values(connection.models).filter((m) => m.collection?.collectionName === collection);
|
|
56
|
+
}
|
|
57
|
+
function resemblance(connection, from) {
|
|
58
|
+
const pluralize = mongoose.pluralize();
|
|
59
|
+
const target = from.toLowerCase();
|
|
60
|
+
return Object.values(connection.models).filter((m) => {
|
|
61
|
+
const name = m.modelName.toLowerCase();
|
|
62
|
+
return name === target || `${name}s` === target || pluralize?.(m.modelName) === target;
|
|
63
|
+
}).map((m) => `model '${m.modelName}' lives in collection '${m.collection?.collectionName}'`).join("; ");
|
|
64
|
+
}
|
|
65
|
+
/** The predicate a join into `from` must carry, `undefined` for none; throws when unknown. */
|
|
66
|
+
function scopeForCollection(from, env) {
|
|
67
|
+
if (typeof from !== "string" || from.length === 0) throw createError(500, `[mongokit] a join's 'from' must be a collection name, got ${JSON.stringify(from)}`, {
|
|
68
|
+
code: JOIN_ERROR_CODES.UNRESOLVABLE_FROM,
|
|
69
|
+
meta: { from }
|
|
70
|
+
});
|
|
71
|
+
const unscoped = env.unscopedJoins?.includes(from) === true;
|
|
72
|
+
const found = owners(env.connection, from);
|
|
73
|
+
if (found.length === 0) {
|
|
74
|
+
if (unscoped) return void 0;
|
|
75
|
+
const hint = resemblance(env.connection, from);
|
|
76
|
+
throw createError(500, `[mongokit] join into '${from}': no registered model owns that collection, so the join would match nothing.${hint ? ` Did you mean: ${hint}?` : ""} Take 'from' from Model.collection.name.`, {
|
|
77
|
+
code: JOIN_ERROR_CODES.UNKNOWN_COLLECTION,
|
|
78
|
+
meta: {
|
|
79
|
+
from,
|
|
80
|
+
suggestion: hint || void 0
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
const governed = found.some((m) => m[GOVERNED] === true);
|
|
85
|
+
const rules = /* @__PURE__ */ new Set();
|
|
86
|
+
for (const m of found) for (const r of m[RULES] ?? []) rules.add(r);
|
|
87
|
+
if (!governed && rules.size === 0) {
|
|
88
|
+
if (unscoped) return void 0;
|
|
89
|
+
throw createError(500, `[mongokit] join into '${from}': no repository governs it, so its tenant/soft-delete scope is unknown. Build its repository, or list it in unscopedJoins if it is company-wide.`, {
|
|
90
|
+
code: JOIN_ERROR_CODES.UNGOVERNED_COLLECTION,
|
|
91
|
+
meta: {
|
|
92
|
+
from,
|
|
93
|
+
models: found.map((m) => m.modelName)
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
const predicates = [];
|
|
98
|
+
for (const rule of rules) {
|
|
99
|
+
const p = rule(env.context, env.operation);
|
|
100
|
+
if (p && Object.keys(p).length > 0) predicates.push(p);
|
|
101
|
+
}
|
|
102
|
+
if (predicates.length === 0) return void 0;
|
|
103
|
+
if (unscoped) throw createError(500, `[mongokit] join into '${from}': it is scoped by its repository and cannot be listed in unscopedJoins. Use bypassTenant for a deliberate cross-tenant read.`, {
|
|
104
|
+
code: JOIN_ERROR_CODES.UNSCOPE_REFUSED,
|
|
105
|
+
meta: { from }
|
|
106
|
+
});
|
|
107
|
+
return predicates.length === 1 ? predicates[0] : { $and: predicates };
|
|
108
|
+
}
|
|
109
|
+
function scopedPipeline(sub, scope, env) {
|
|
110
|
+
const walked = walk(Array.isArray(sub) ? sub : [], env);
|
|
111
|
+
return scope ? [{ $match: scope }, ...walked] : walked;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Return `pipeline` with every join scoped; throws on an unknown or ungoverned `from`. The result
|
|
115
|
+
* is the one documented narrowing of a caller's stage array to mongoose's stage union (stage
|
|
116
|
+
* validity is the server's call); `aggregatePipeline` no longer carries its own.
|
|
117
|
+
*/
|
|
118
|
+
function scopeJoins(pipeline, env) {
|
|
119
|
+
return walk(pipeline, env);
|
|
120
|
+
}
|
|
121
|
+
function walk(pipeline, env) {
|
|
122
|
+
return pipeline.map((raw) => {
|
|
123
|
+
const stage = raw;
|
|
124
|
+
if (stage.$lookup) {
|
|
125
|
+
const l = stage.$lookup;
|
|
126
|
+
if (l.from === void 0) return { $lookup: {
|
|
127
|
+
...l,
|
|
128
|
+
pipeline: scopedPipeline(l.pipeline, void 0, env)
|
|
129
|
+
} };
|
|
130
|
+
const scope = scopeForCollection(l.from, env);
|
|
131
|
+
if (!scope && l.pipeline === void 0) return stage;
|
|
132
|
+
return { $lookup: {
|
|
133
|
+
...l,
|
|
134
|
+
pipeline: scopedPipeline(l.pipeline, scope, env)
|
|
135
|
+
} };
|
|
136
|
+
}
|
|
137
|
+
if (stage.$unionWith) {
|
|
138
|
+
const u = typeof stage.$unionWith === "string" ? { coll: stage.$unionWith } : stage.$unionWith;
|
|
139
|
+
if (u.coll === void 0) return { $unionWith: {
|
|
140
|
+
...u,
|
|
141
|
+
pipeline: scopedPipeline(u.pipeline, void 0, env)
|
|
142
|
+
} };
|
|
143
|
+
const scope = scopeForCollection(u.coll, env);
|
|
144
|
+
if (!scope && u.pipeline === void 0) return stage;
|
|
145
|
+
return { $unionWith: {
|
|
146
|
+
...u,
|
|
147
|
+
pipeline: scopedPipeline(u.pipeline, scope, env)
|
|
148
|
+
} };
|
|
149
|
+
}
|
|
150
|
+
if (stage.$graphLookup) {
|
|
151
|
+
const g = stage.$graphLookup;
|
|
152
|
+
const scope = scopeForCollection(g.from, env);
|
|
153
|
+
if (!scope) return stage;
|
|
154
|
+
const existing = g.restrictSearchWithMatch;
|
|
155
|
+
return { $graphLookup: {
|
|
156
|
+
...g,
|
|
157
|
+
restrictSearchWithMatch: existing ? { $and: [existing, scope] } : scope
|
|
158
|
+
} };
|
|
159
|
+
}
|
|
160
|
+
if (stage.$facet) {
|
|
161
|
+
const branches = stage.$facet;
|
|
162
|
+
return { $facet: Object.fromEntries(Object.entries(branches).map(([k, v]) => [k, walk(v, env)])) };
|
|
163
|
+
}
|
|
164
|
+
return stage;
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
//#endregion
|
|
168
|
+
export { scopeJoins as a, scopeForCollection as i, declareCollectionScope as n, tenantFieldsOf as o, markGoverned as r, JOIN_ERROR_CODES as t };
|
|
@@ -46,14 +46,18 @@ function buildCrudSchemasFromMongooseSchema(mongooseSchema, options = {}) {
|
|
|
46
46
|
const jsonCreate = buildJsonSchemaFromPaths(mongooseSchema, options);
|
|
47
47
|
const jsonUpdate = buildJsonSchemaForUpdate(jsonCreate, options);
|
|
48
48
|
const jsonResponse = buildJsonSchemaForResponse(mongooseSchema, options);
|
|
49
|
+
const idPath = mongooseSchema.path("_id");
|
|
49
50
|
return {
|
|
50
51
|
createBody: jsonCreate,
|
|
51
52
|
updateBody: jsonUpdate,
|
|
52
53
|
params: {
|
|
53
54
|
type: "object",
|
|
54
|
-
properties: { id: {
|
|
55
|
+
properties: { id: idPath === void 0 || isObjectIdInstance(idPath.instance ?? "") ? {
|
|
55
56
|
type: "string",
|
|
56
57
|
pattern: "^[0-9a-fA-F]{24}$"
|
|
58
|
+
} : {
|
|
59
|
+
type: "string",
|
|
60
|
+
minLength: 1
|
|
57
61
|
} },
|
|
58
62
|
required: ["id"]
|
|
59
63
|
},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { l as Plugin, p as RepositoryContext } from "./repository-
|
|
1
|
+
import { A as ObjectId } from "./pagination-D6psses0.mjs";
|
|
2
|
+
import { l as Plugin, p as RepositoryContext } from "./repository-DNHfjAZX.mjs";
|
|
3
3
|
import mongoose, { Connection } from "mongoose";
|
|
4
4
|
import { CacheAdapter as CacheAdapter$1, CacheOptions, RepositoryCacheHandle as RepositoryCacheHandle$1, RepositoryCachePluginOptions, cachePlugin } from "@classytic/repo-core/cache";
|
|
5
5
|
import { TenantConfig } from "@classytic/repo-core/tenant";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { A as ObjectId, F as SortSpec, M as ReadPreferenceType, N as SelectSpec, b as WriteConcernSpec, i as CountStrategy, j as PopulateSpec, r as CollationOptions, v as ReadConcernLevel } from "./pagination-D6psses0.mjs";
|
|
2
2
|
import { DeleteManyResult, DeleteResult, LookupPopulateResult, UpdateManyResult } from "@classytic/repo-core/repository";
|
|
3
3
|
import { PipelineStage, PopulateOptions } from "mongoose";
|
|
4
4
|
import { Filter } from "@classytic/repo-core/filter";
|
|
@@ -312,13 +312,20 @@ interface SessionOptions {
|
|
|
312
312
|
* substitute for access control — gate it at the host layer.
|
|
313
313
|
*/
|
|
314
314
|
bypassAppendOnly?: boolean;
|
|
315
|
+
/** Write concern for this call; beats `queryDefaults.writeConcern`. Ignored by reads. */
|
|
316
|
+
writeConcern?: WriteConcernSpec;
|
|
315
317
|
/** Extensible — plugins can read custom fields from options */
|
|
316
318
|
[key: string]: unknown;
|
|
317
319
|
}
|
|
318
|
-
/** Read options
|
|
320
|
+
/** Read options. Each field beats the repository and deployment `queryDefaults`. */
|
|
319
321
|
interface ReadOptions extends SessionOptions {
|
|
320
322
|
/** Read preference for replica sets (e.g. 'secondaryPreferred') */
|
|
321
323
|
readPreference?: ReadPreferenceType;
|
|
324
|
+
/** Server-side time bound for this command. */
|
|
325
|
+
maxTimeMS?: number;
|
|
326
|
+
readConcern?: ReadConcernLevel;
|
|
327
|
+
/** Profiler / log tag. */
|
|
328
|
+
comment?: string;
|
|
322
329
|
}
|
|
323
330
|
/** Repository operation options */
|
|
324
331
|
interface OperationOptions extends ReadOptions {
|
|
@@ -436,21 +443,17 @@ interface FindOneAndUpdateOptions extends OperationOptions {
|
|
|
436
443
|
runValidators?: boolean;
|
|
437
444
|
/** Collation for locale-aware string comparison. */
|
|
438
445
|
collation?: CollationOptions;
|
|
439
|
-
/**
|
|
440
|
-
|
|
446
|
+
/** Force an index (name or key pattern). */
|
|
447
|
+
hint?: string | Record<string, 1 | -1>;
|
|
441
448
|
}
|
|
442
449
|
/** Aggregate operation options */
|
|
443
450
|
interface AggregateOptions extends ReadOptions {
|
|
444
451
|
/** Allow aggregation to use disk for large sorts/groups */
|
|
445
452
|
allowDiskUse?: boolean;
|
|
446
|
-
/**
|
|
447
|
-
|
|
448
|
-
/**
|
|
449
|
-
|
|
450
|
-
/** Read concern level */
|
|
451
|
-
readConcern?: {
|
|
452
|
-
level: string;
|
|
453
|
-
};
|
|
453
|
+
/** Force an index (name or key pattern). */
|
|
454
|
+
hint?: string | Record<string, 1 | -1>;
|
|
455
|
+
/** Collections the caller asserts are company-wide, joinable without a governing repository. */
|
|
456
|
+
unscopedJoins?: readonly string[];
|
|
454
457
|
/** Collation for locale-aware string comparison */
|
|
455
458
|
collation?: CollationOptions;
|
|
456
459
|
/** Maximum allowed pipeline stages (governance) */
|
|
@@ -532,5 +535,25 @@ interface MinMaxResult {
|
|
|
532
535
|
min: unknown;
|
|
533
536
|
max: unknown;
|
|
534
537
|
}
|
|
538
|
+
/** Kit-native options for the portable `aggregate(req)`; each field beats every default. */
|
|
539
|
+
interface AggregateCallOptions {
|
|
540
|
+
/** Also return the winning plan (a second command). */
|
|
541
|
+
explain?: 'queryPlanner' | 'executionStats' | 'allPlansExecution';
|
|
542
|
+
/** Collections the caller asserts are company-wide (see `join-scope.ts`). */
|
|
543
|
+
unscopedJoins?: readonly string[];
|
|
544
|
+
maxTimeMS?: number;
|
|
545
|
+
readPreference?: ReadPreferenceType;
|
|
546
|
+
readConcern?: ReadConcernLevel;
|
|
547
|
+
comment?: string;
|
|
548
|
+
}
|
|
549
|
+
/** `getByIds` options: chunked `$in` reads, optionally aligned with the input order. */
|
|
550
|
+
interface GetByIdsOptions extends OperationOptions {
|
|
551
|
+
/** Ids per `$in` command. Default `DEFAULT_ID_CHUNK` (10,000). */
|
|
552
|
+
chunkSize?: number;
|
|
553
|
+
/** Chunks in flight at once outside a session. Default 4. */
|
|
554
|
+
concurrency?: number;
|
|
555
|
+
/** Return `Array<TDoc | undefined>` aligned with the input ids instead of a Map. */
|
|
556
|
+
preserveOrder?: boolean;
|
|
557
|
+
}
|
|
535
558
|
//#endregion
|
|
536
|
-
export {
|
|
559
|
+
export { LookupOptions as S, SessionOptions as _, ConvenientTransactionOptions as a, WithTransactionOptions as b, DeleteResult as c, GroupResult as d, LookupPopulateOptions as f, ReadOptions as g, OperationOptions as h, CacheableOptions as i, FindOneAndUpdateOptions as l, MinMaxResult as m, AggregateOptions as n, CreateOptions as o, LookupPopulateResult as p, CacheOperationOptions as r, DeleteManyResult as s, AggregateCallOptions as t, GetByIdsOptions as u, UpdateManyResult as v, LookupBuilder as x, UpdateOptions as y };
|
package/dist/outbox/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as Repository } from "../Repository-
|
|
1
|
+
import { r as Repository } from "../Repository-pnLw1rG5.mjs";
|
|
2
2
|
import { Connection, Model } from "mongoose";
|
|
3
3
|
//#region src/outbox/index.d.ts
|
|
4
4
|
/** Delivery states. `dead_letter` is terminal and operator-visible. */
|
package/dist/outbox/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as Repository } from "../Repository-
|
|
1
|
+
import { n as Repository } from "../Repository-CYhSC9ut.mjs";
|
|
2
2
|
import { n as batchOperationsPlugin, t as methodRegistryPlugin } from "../method-registry.plugin-C63pGn1d.mjs";
|
|
3
3
|
import { Schema } from "mongoose";
|
|
4
4
|
//#region src/outbox/index.ts
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { PaginationEngine };
|
|
1
|
+
import { n as PaginationEngine, t as CountMemoKey } from "../PaginationEngine-CRHyuUtw.mjs";
|
|
2
|
+
export { CountMemoKey, PaginationEngine };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as PaginationEngine } from "../PaginationEngine-
|
|
1
|
+
import { t as PaginationEngine } from "../PaginationEngine-CfT2Cxkj.mjs";
|
|
2
2
|
export { PaginationEngine };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Document, Model, PipelineStage, PopulateOptions, Types } from "mongoose";
|
|
1
|
+
import { Connection, Document, Model, PipelineStage, PopulateOptions, Types } from "mongoose";
|
|
2
2
|
//#region src/types/core.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* Core query/document primitives shared across every mongokit module —
|
|
@@ -47,6 +47,79 @@ type SelectSpec = string | readonly string[] | Record<string, 0 | 1>;
|
|
|
47
47
|
/** Filter query type for MongoDB queries (compatible with Mongoose 8 & 9) */
|
|
48
48
|
type FilterQuery<_T = unknown> = Record<string, unknown>;
|
|
49
49
|
//#endregion
|
|
50
|
+
//#region src/repository/query-defaults.d.ts
|
|
51
|
+
type ReadConcernLevel = 'local' | 'available' | 'majority' | 'linearizable' | 'snapshot';
|
|
52
|
+
interface WriteConcernSpec {
|
|
53
|
+
w?: number | 'majority';
|
|
54
|
+
j?: boolean;
|
|
55
|
+
wtimeoutMS?: number;
|
|
56
|
+
}
|
|
57
|
+
/** Defaults for every repository command. */
|
|
58
|
+
interface QueryDefaults {
|
|
59
|
+
maxTimeMS?: number;
|
|
60
|
+
readPreference?: ReadPreferenceType;
|
|
61
|
+
readConcern?: ReadConcernLevel;
|
|
62
|
+
writeConcern?: WriteConcernSpec;
|
|
63
|
+
/** Profiler / log tag. */
|
|
64
|
+
comment?: string;
|
|
65
|
+
}
|
|
66
|
+
/** Defaults for aggregations only; consulted before {@link QueryDefaults}. */
|
|
67
|
+
interface AggregateDefaults {
|
|
68
|
+
maxTimeMs?: number;
|
|
69
|
+
allowDiskUse?: boolean;
|
|
70
|
+
}
|
|
71
|
+
/** What one call may pass. Every field beats every default. */
|
|
72
|
+
interface PerCallQueryOptions {
|
|
73
|
+
maxTimeMS?: number;
|
|
74
|
+
readPreference?: ReadPreferenceType;
|
|
75
|
+
readConcern?: ReadConcernLevel;
|
|
76
|
+
writeConcern?: WriteConcernSpec;
|
|
77
|
+
comment?: string;
|
|
78
|
+
hint?: string | Record<string, 1 | -1>;
|
|
79
|
+
allowDiskUse?: boolean;
|
|
80
|
+
session?: unknown;
|
|
81
|
+
}
|
|
82
|
+
/** The options a command is executed with, after resolution. */
|
|
83
|
+
interface ResolvedQueryOptions {
|
|
84
|
+
maxTimeMS?: number;
|
|
85
|
+
readPreference?: ReadPreferenceType;
|
|
86
|
+
readConcern?: ReadConcernLevel;
|
|
87
|
+
writeConcern?: WriteConcernSpec;
|
|
88
|
+
comment?: string;
|
|
89
|
+
hint?: string | Record<string, 1 | -1>;
|
|
90
|
+
allowDiskUse?: boolean;
|
|
91
|
+
}
|
|
92
|
+
type CommandKind = 'read' | 'aggregate' | 'write' | 'findAndModify';
|
|
93
|
+
/** Set the deployment's query defaults. Merges; an explicit `undefined` changes nothing. */
|
|
94
|
+
declare function configureQueryDefaults(defaults: QueryDefaults): void;
|
|
95
|
+
/** Set the deployment's aggregation defaults. Merges; an explicit `undefined` changes nothing. */
|
|
96
|
+
declare function configureAggregateDefaults(defaults: AggregateDefaults): void;
|
|
97
|
+
/** A copy of the deployment defaults. */
|
|
98
|
+
declare function getQueryDefaults(): {
|
|
99
|
+
query: QueryDefaults;
|
|
100
|
+
aggregate: AggregateDefaults;
|
|
101
|
+
};
|
|
102
|
+
/** Back to no deployment defaults. For tests. */
|
|
103
|
+
declare function resetQueryDefaults(): void;
|
|
104
|
+
/**
|
|
105
|
+
* Boot check (M7): throws unless the deployment sets a query `maxTimeMS`, and — when a connection
|
|
106
|
+
* is passed — unless its client carries a CSOT `timeoutMS`. Returns what it verified.
|
|
107
|
+
*/
|
|
108
|
+
declare function assertQueryDefaultsConfigured(connection?: Connection): {
|
|
109
|
+
maxTimeMS: number;
|
|
110
|
+
timeoutMS?: number;
|
|
111
|
+
};
|
|
112
|
+
declare const QUERY_DEFAULTS_ERROR_CODES: {
|
|
113
|
+
readonly NOT_CONFIGURED: "mongokit.query_defaults.not_configured";
|
|
114
|
+
/** A per-call bound inside a transaction that carries its own CSOT budget (the driver forbids both). */
|
|
115
|
+
readonly TIMEOUT_IN_TRANSACTION: "mongokit.query_defaults.timeout_in_transaction";
|
|
116
|
+
};
|
|
117
|
+
/** Resolve the options one command runs with. `repo` is the repository's own defaults. */
|
|
118
|
+
declare function resolveQueryOptions(kind: CommandKind, perCall: PerCallQueryOptions, repo?: {
|
|
119
|
+
query?: QueryDefaults;
|
|
120
|
+
aggregate?: AggregateDefaults;
|
|
121
|
+
}): ResolvedQueryOptions;
|
|
122
|
+
//#endregion
|
|
50
123
|
//#region src/pagination/utils/cursor-signing.d.ts
|
|
51
124
|
/**
|
|
52
125
|
* HMAC signing for pagination cursors.
|
|
@@ -108,7 +181,11 @@ type CursorSecret = string | readonly string[];
|
|
|
108
181
|
* Declared ONCE and referenced everywhere — this union was hand-copied to eight
|
|
109
182
|
* declarations, which is how the aggregate variant silently lost a member.
|
|
110
183
|
*/
|
|
111
|
-
|
|
184
|
+
/**
|
|
185
|
+
* `cached`: the capped count memoised per (collection, filter, collation, hint) for
|
|
186
|
+
* `countCacheTtlMs`; never inside a transaction (it would publish uncommitted rows).
|
|
187
|
+
*/
|
|
188
|
+
type CountStrategy = 'exact' | 'estimated' | 'capped' | 'none' | 'cached';
|
|
112
189
|
/**
|
|
113
190
|
* What mongokit adds to repo-core's offset envelope, via its reserved `TExtra`
|
|
114
191
|
* slot: `OffsetPaginationResult<TDoc, MongokitPageExtras>`.
|
|
@@ -123,16 +200,13 @@ type MongokitPageExtras = {
|
|
|
123
200
|
/** Deep-page or clamped-limit advice. Human-readable; never branch on it. */
|
|
124
201
|
warning?: string;
|
|
125
202
|
/**
|
|
126
|
-
* `total` is
|
|
127
|
-
*
|
|
128
|
-
* a total carrying
|
|
129
|
-
*
|
|
130
|
-
* A separate boolean rather than a sentinel `total` (`-1`, `null`): a total
|
|
131
|
-
* that lies in a field typed `number` is read as a number by every consumer
|
|
132
|
-
* that has not been taught otherwise, which is the failure this flag exists
|
|
133
|
-
* to make impossible to miss.
|
|
203
|
+
* `total` is not an exact count of the rows matching right now: a capped count at its
|
|
204
|
+
* ceiling (a floor — render `10,000+`), an estimate, a memoised (`cached`) count, or no count
|
|
205
|
+
* (`none`). Never derive a last-page number or a percentage from a total carrying it.
|
|
134
206
|
*/
|
|
135
|
-
|
|
207
|
+
totalIsEstimate: boolean;
|
|
208
|
+
/** When `total` was counted; `null` when nothing was counted (`none`). */
|
|
209
|
+
countedAt: Date | null;
|
|
136
210
|
};
|
|
137
211
|
/** Pagination configuration */
|
|
138
212
|
interface PaginationConfig {
|
|
@@ -142,6 +216,13 @@ interface PaginationConfig {
|
|
|
142
216
|
maxLimit?: number;
|
|
143
217
|
/** Maximum allowed page number (default: 10000) */
|
|
144
218
|
maxPage?: number;
|
|
219
|
+
/**
|
|
220
|
+
* Deepest `skip` an offset page may ask for (default 100,000). Past it the call is refused
|
|
221
|
+
* with `mongokit.pagination.offset_too_deep` (400): walk with keyset (`after`) instead.
|
|
222
|
+
*/
|
|
223
|
+
maxOffset?: number;
|
|
224
|
+
/** Freshness window of `countStrategy: 'cached'` (default 30,000 ms). */
|
|
225
|
+
countCacheTtlMs?: number;
|
|
145
226
|
/** Page number that triggers performance warning (default: 100) */
|
|
146
227
|
deepPageThreshold?: number;
|
|
147
228
|
/** Cursor version for forward compatibility (default: 1) */
|
|
@@ -249,6 +330,13 @@ interface BasePaginationOptions {
|
|
|
249
330
|
maxTimeMS?: number;
|
|
250
331
|
/** Read preference for replica sets (e.g. 'secondaryPreferred') */
|
|
251
332
|
readPreference?: ReadPreferenceType;
|
|
333
|
+
readConcern?: ReadConcernLevel;
|
|
334
|
+
comment?: string;
|
|
335
|
+
/**
|
|
336
|
+
* Already-resolved time bound and concerns (the Repository passes these, defaults folded in).
|
|
337
|
+
* When absent the engine resolves the per-call fields above against the deployment defaults.
|
|
338
|
+
*/
|
|
339
|
+
queryOptions?: ResolvedQueryOptions;
|
|
252
340
|
/** Collation for locale-aware string comparison and case-insensitive sorting */
|
|
253
341
|
collation?: CollationOptions;
|
|
254
342
|
}
|
|
@@ -325,9 +413,20 @@ interface AggregatePaginationOptions {
|
|
|
325
413
|
mode?: 'offset';
|
|
326
414
|
/** Read preference for replica sets (e.g. 'secondaryPreferred') */
|
|
327
415
|
readPreference?: ReadPreferenceType;
|
|
416
|
+
readConcern?: ReadConcernLevel;
|
|
417
|
+
comment?: string;
|
|
418
|
+
/** Collections the caller asserts are company-wide (see `join-scope.ts`). */
|
|
419
|
+
unscopedJoins?: readonly string[];
|
|
420
|
+
/**
|
|
421
|
+
* The caller states the pipeline's last `$sort` is a TOTAL order (unique per output row), so the
|
|
422
|
+
* not-provably-total warning is silenced. Only for a sort total by domain knowledge.
|
|
423
|
+
*/
|
|
424
|
+
sortIsTotal?: boolean;
|
|
425
|
+
/** Already-resolved options; see {@link BasePaginationOptions.queryOptions}. */
|
|
426
|
+
queryOptions?: ResolvedQueryOptions;
|
|
328
427
|
}
|
|
329
428
|
/** Value type identifier for cursor serialization */
|
|
330
|
-
type ValueType = 'date' | 'objectid' | 'boolean' | 'number' | 'string' | 'null' | 'unknown';
|
|
429
|
+
type ValueType = 'date' | 'objectid' | 'decimal' | 'boolean' | 'number' | 'string' | 'null' | 'unknown';
|
|
331
430
|
/** Cursor payload */
|
|
332
431
|
interface CursorPayload {
|
|
333
432
|
/** Primary sort field value (legacy single-field) */
|
|
@@ -346,6 +445,8 @@ interface CursorPayload {
|
|
|
346
445
|
vals?: Record<string, string | number | boolean | null>;
|
|
347
446
|
/** Compound sort value types */
|
|
348
447
|
types?: Record<string, ValueType>;
|
|
448
|
+
/** Scope fingerprint: collection + post-policy filter + collation (see `utils/guards.ts`). */
|
|
449
|
+
fp: string;
|
|
349
450
|
}
|
|
350
451
|
/** Decoded cursor */
|
|
351
452
|
interface DecodedCursor {
|
|
@@ -359,6 +460,8 @@ interface DecodedCursor {
|
|
|
359
460
|
version: number;
|
|
360
461
|
/** All sort field values (rehydrated) — for compound sort */
|
|
361
462
|
values?: Record<string, unknown>;
|
|
463
|
+
/** Scope fingerprint the cursor was minted under. */
|
|
464
|
+
scope: string;
|
|
362
465
|
}
|
|
363
466
|
//#endregion
|
|
364
|
-
export {
|
|
467
|
+
export { ObjectId as A, configureQueryDefaults as C, AnyDocument as D, resolveQueryOptions as E, SortSpec as F, ReadPreferenceType as M, SelectSpec as N, AnyModel as O, SortDirection as P, configureAggregateDefaults as S, resetQueryDefaults as T, QueryDefaults as _, CursorPayload as a, WriteConcernSpec as b, MongokitPageExtras as c, ValueType as d, CursorSecret as f, QUERY_DEFAULTS_ERROR_CODES as g, PerCallQueryOptions as h, CountStrategy as i, PopulateSpec as j, FilterQuery as k, OffsetPaginationOptions as l, CommandKind as m, BasePaginationOptions as n, DecodedCursor as o, AggregateDefaults as p, CollationOptions as r, KeysetPaginationOptions as s, AggregatePaginationOptions as t, PaginationConfig as u, ReadConcernLevel as v, getQueryDefaults as w, assertQueryDefaultsConfigured as x, ResolvedQueryOptions as y };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { h as RepositoryInstance, p as RepositoryContext } from "./repository-
|
|
1
|
+
import { A as ObjectId, F as SortSpec, N as SelectSpec, j as PopulateSpec } from "./pagination-D6psses0.mjs";
|
|
2
|
+
import { h as RepositoryInstance, p as RepositoryContext } from "./repository-DNHfjAZX.mjs";
|
|
3
3
|
import { OffsetPaginationResult } from "@classytic/repo-core/pagination";
|
|
4
4
|
//#region src/types/plugin-options.d.ts
|
|
5
5
|
/** Field preset configuration (field-filter plugin) */
|