@classytic/mongokit 3.19.0 → 3.21.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/dist/{PaginationEngine-BcvaXBQ-.mjs → PaginationEngine-BT1ywu9k.mjs} +327 -6
- package/dist/{PaginationEngine-4SjzfBQE.d.mts → PaginationEngine-DYpOD2wY.d.mts} +1 -2
- package/dist/{Repository-B01VW_fU.mjs → Repository-dbbgOGjK.mjs} +85 -11
- package/dist/actions/index.d.mts +1 -1
- package/dist/actions/index.mjs +2 -2
- package/dist/adapter/index.d.mts +27 -12
- package/dist/adapter/index.mjs +1 -1
- package/dist/{adapter-BSxhT0Ip.mjs → adapter-rTPLUrAV.mjs} +12 -2
- package/dist/ai/index.d.mts +1 -2
- package/dist/ai/index.mjs +3 -2
- package/dist/better-auth/index.d.mts +0 -1
- package/dist/better-auth/index.mjs +2 -2
- package/dist/{create-repository-K0yft2ht.d.mts → create-repository-0TkQhcv-.d.mts} +107 -13
- package/dist/{create-repository-D5YX0wGs.mjs → create-repository-CJATiAKX.mjs} +2 -2
- package/dist/{id-resolution-CnN0YA8t.mjs → id-resolution-P2OzcyRl.mjs} +10 -5
- package/dist/{index-BgSBwlWu.d.mts → index-Cg3SWugF.d.mts} +1 -3
- package/dist/index.d.mts +9 -10
- package/dist/index.mjs +52 -13
- package/dist/lock/index.d.mts +0 -1
- package/dist/memory-cache-DI1jb4dz.mjs +67 -0
- package/dist/{mongooseToJsonSchema-ChtXSrLT.mjs → mongooseToJsonSchema-CVnrKFDq.mjs} +2 -68
- package/dist/{mongooseToJsonSchema-Bz47aMfH.d.mts → mongooseToJsonSchema-D2CyAMIC.d.mts} +9 -5
- package/dist/{multi-tenant.plugin-D6lw3BsI.d.mts → multi-tenant.plugin-CTsWz0XK.d.mts} +1 -2
- package/dist/pagination/PaginationEngine.d.mts +1 -1
- package/dist/pagination/PaginationEngine.mjs +1 -1
- package/dist/plugins/index.d.mts +3 -4
- package/dist/plugins/index.mjs +2 -2
- package/dist/query/primitives/coercion.d.mts +1 -1
- package/dist/query/primitives/coercion.mjs +1 -1
- package/dist/query/primitives/geo.d.mts +1 -1
- package/dist/query/primitives/indexes.d.mts +1 -1
- package/dist/testkit/index.d.mts +1 -2
- package/dist/testkit/index.mjs +1 -1
- package/dist/{timestamp.plugin-B1A9U-P7.mjs → timestamp.plugin-nG9Z1JEk.mjs} +4 -4
- package/dist/{types-BA8oXjFe.d.mts → types-DNFMofHy.d.mts} +51 -22
- package/dist/{update-CvCMv5Cl.mjs → update-1Lq9OMD2.mjs} +5 -5
- package/dist/utils/index.d.mts +1 -1
- package/dist/utils/index.mjs +6 -5
- package/dist/{validation-chain.plugin-DHZbpb4t.mjs → validation-chain.plugin-Dn_wZYLA.mjs} +6 -6
- package/dist/{validation-chain.plugin-CYOPfFGF.d.mts → validation-chain.plugin-buy3uvyk.d.mts} +1 -2
- package/package.json +8 -7
- package/dist/cursor-_SbWVAn-.mjs +0 -254
- package/dist/sort-Ca1BPfvE.mjs +0 -72
- /package/dist/{coercion-BxxHyLjP.d.mts → coercion-BjdPX3YF.d.mts} +0 -0
- /package/dist/{error-BTeepSNL.mjs → error-BuByZwKU.mjs} +0 -0
- /package/dist/{field-selection-d1qdRiMr.mjs → field-selection-FSQFLpsU.mjs} +0 -0
- /package/dist/{indexes-3eHBWNZ2.d.mts → indexes-DIjMpYES.d.mts} +0 -0
- /package/dist/{logger-B8wf-Mtb.mjs → logger-K7dPmu2U.mjs} +0 -0
- /package/dist/{chunk-CfYAbeIz.mjs → rolldown-runtime-D7D4PA-g.mjs} +0 -0
package/dist/testkit/index.d.mts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { a as Repository, n as CreateRepositoryConfig } from "../create-repository-
|
|
1
|
+
import { a as Repository, n as CreateRepositoryConfig } from "../create-repository-0TkQhcv-.mjs";
|
|
2
2
|
import { Connection, Model, Schema } from "mongoose";
|
|
3
3
|
import { MongoMemoryReplSet, MongoMemoryServer } from "mongodb-memory-server";
|
|
4
|
-
|
|
5
4
|
//#region src/testkit/index.d.ts
|
|
6
5
|
interface MongoMemoryOptions {
|
|
7
6
|
/**
|
package/dist/testkit/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { l as OP_REGISTRY, s as ALL_OPERATIONS, t as HOOK_PRIORITY } from "./Repository-
|
|
2
|
-
import { n as warn } from "./logger-
|
|
3
|
-
import { t as createError } from "./error-
|
|
1
|
+
import { l as OP_REGISTRY, s as ALL_OPERATIONS, t as HOOK_PRIORITY } from "./Repository-dbbgOGjK.mjs";
|
|
2
|
+
import { n as warn } from "./logger-K7dPmu2U.mjs";
|
|
3
|
+
import { t as createError } from "./error-BuByZwKU.mjs";
|
|
4
4
|
import { throwIfAborted, withRetry } from "@classytic/repo-core/repository";
|
|
5
5
|
import mongoose from "mongoose";
|
|
6
6
|
import { cachePlugin } from "@classytic/repo-core/cache";
|
|
@@ -1233,7 +1233,7 @@ function softDeletePlugin(options = {}) {
|
|
|
1233
1233
|
};
|
|
1234
1234
|
}
|
|
1235
1235
|
};
|
|
1236
|
-
const SOFT_DELETE_SPECIAL = new Set([
|
|
1236
|
+
const SOFT_DELETE_SPECIAL = /* @__PURE__ */ new Set([
|
|
1237
1237
|
"updateMany",
|
|
1238
1238
|
"deleteMany",
|
|
1239
1239
|
"bulkWrite"
|
|
@@ -1,16 +1,9 @@
|
|
|
1
|
-
import * as _$_classytic_repo_core_repository0 from "@classytic/repo-core/repository";
|
|
2
1
|
import { DeleteManyResult, DeleteResult, LookupPopulateResult, RepositoryBase, UpdateManyResult } from "@classytic/repo-core/repository";
|
|
3
|
-
import * as _$mongoose from "mongoose";
|
|
4
2
|
import { Document, Model, PipelineStage, PopulateOptions, Types } from "mongoose";
|
|
5
|
-
import * as _$_classytic_repo_core_filter0 from "@classytic/repo-core/filter";
|
|
6
3
|
import { Filter } from "@classytic/repo-core/filter";
|
|
7
|
-
import * as _$_classytic_repo_core_cache0 from "@classytic/repo-core/cache";
|
|
8
|
-
import * as _$_classytic_repo_core_schema0 from "@classytic/repo-core/schema";
|
|
9
4
|
import { ValidationResult } from "@classytic/repo-core/schema";
|
|
10
|
-
import * as _$_classytic_repo_core_events0 from "@classytic/repo-core/events";
|
|
11
5
|
import { AnyPaginationResult, OffsetPaginationResult } from "@classytic/repo-core/pagination";
|
|
12
6
|
import { HttpError } from "@classytic/repo-core/errors";
|
|
13
|
-
|
|
14
7
|
//#region src/query/LookupBuilder.d.ts
|
|
15
8
|
interface LookupOptions {
|
|
16
9
|
/** Collection to join with */
|
|
@@ -172,6 +165,42 @@ declare class LookupBuilder {
|
|
|
172
165
|
*/
|
|
173
166
|
private static _sanitizeDeep;
|
|
174
167
|
}
|
|
168
|
+
/**
|
|
169
|
+
* Performance Guidelines for $lookup at Scale:
|
|
170
|
+
*
|
|
171
|
+
* 1. **Index Requirements** (Critical for millions of records):
|
|
172
|
+
* - localField should be indexed on source collection
|
|
173
|
+
* - foreignField should be indexed on target collection (unique index preferred)
|
|
174
|
+
*
|
|
175
|
+
* Example:
|
|
176
|
+
* ```typescript
|
|
177
|
+
* // Employee collection
|
|
178
|
+
* employeeSchema.index({ departmentSlug: 1 });
|
|
179
|
+
*
|
|
180
|
+
* // Department collection
|
|
181
|
+
* departmentSchema.index({ slug: 1 }, { unique: true });
|
|
182
|
+
* ```
|
|
183
|
+
*
|
|
184
|
+
* 2. **Query Performance**:
|
|
185
|
+
* - With proper indexes: O(log n) per lookup
|
|
186
|
+
* - Without indexes: O(n * m) - AVOID THIS!
|
|
187
|
+
* - Use explain() to verify index usage: IXSCAN (good) vs COLLSCAN (bad)
|
|
188
|
+
*
|
|
189
|
+
* 3. **Pipeline Optimization**:
|
|
190
|
+
* - Place $match stages as early as possible
|
|
191
|
+
* - Use $project to reduce field size before lookups
|
|
192
|
+
* - Limit joined results with pipeline: [{ $match: {...} }, { $limit: n }]
|
|
193
|
+
*
|
|
194
|
+
* 4. **Memory Considerations**:
|
|
195
|
+
* - Each lookup creates a new field in memory
|
|
196
|
+
* - Use $project after lookup to remove unnecessary fields
|
|
197
|
+
* - Consider allowDiskUse: true for very large datasets
|
|
198
|
+
*
|
|
199
|
+
* 5. **Alternative Approaches**:
|
|
200
|
+
* - For 1:1 relationships with high read frequency: Consider storing ObjectId + slug
|
|
201
|
+
* - For read-heavy workloads: Consider caching or materialized views
|
|
202
|
+
* - For real-time dashboards: Consider separate aggregation collections
|
|
203
|
+
*/
|
|
175
204
|
//#endregion
|
|
176
205
|
//#region src/types/controller.types.d.ts
|
|
177
206
|
/**
|
|
@@ -561,20 +590,20 @@ type RequiredBy<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;
|
|
|
561
590
|
* @example
|
|
562
591
|
* type StringFields = KeysOfType<User, string>; // 'name' | 'email'
|
|
563
592
|
*/
|
|
564
|
-
type KeysOfType<T, V> = { [K in keyof T]: T[K] extends V ? K : never }[keyof T];
|
|
593
|
+
type KeysOfType<T, V> = { [K in keyof T]: T[K] extends V ? K : never; }[keyof T];
|
|
565
594
|
/**
|
|
566
595
|
* Deep partial - makes all nested properties optional
|
|
567
596
|
*/
|
|
568
|
-
type DeepPartial<T> = T extends object ? { [P in keyof T]?: DeepPartial<T[P]
|
|
597
|
+
type DeepPartial<T> = T extends object ? { [P in keyof T]?: DeepPartial<T[P]>; } : T;
|
|
569
598
|
/**
|
|
570
599
|
* Strict object type - prevents excess properties
|
|
571
600
|
* Use with `satisfies` for compile-time validation
|
|
572
601
|
*/
|
|
573
|
-
type Strict<T> = T & { [K in Exclude<string, keyof T>]?: never };
|
|
602
|
+
type Strict<T> = T & { [K in Exclude<string, keyof T>]?: never; };
|
|
574
603
|
/**
|
|
575
604
|
* NonNullable fields extractor
|
|
576
605
|
*/
|
|
577
|
-
type NonNullableFields<T> = { [K in keyof T]: NonNullable<T[K]
|
|
606
|
+
type NonNullableFields<T> = { [K in keyof T]: NonNullable<T[K]>; };
|
|
578
607
|
/**
|
|
579
608
|
* Create/Update input types from document
|
|
580
609
|
*/
|
|
@@ -869,20 +898,20 @@ interface RepositoryOptions {
|
|
|
869
898
|
* structured `validationErrors`. Validator output replaces the
|
|
870
899
|
* payload, so schema-declared coercions/defaults flow into the write.
|
|
871
900
|
*/
|
|
872
|
-
schema?:
|
|
901
|
+
schema?: import('@classytic/repo-core/schema').StandardSchemaV1;
|
|
873
902
|
/**
|
|
874
903
|
* Standard Schema validator for `update` payloads. Separate slot
|
|
875
904
|
* because updates are partial — derive one explicitly (e.g.
|
|
876
905
|
* `schema.partial()` in Zod).
|
|
877
906
|
*/
|
|
878
|
-
updateSchema?:
|
|
907
|
+
updateSchema?: import('@classytic/repo-core/schema').StandardSchemaV1;
|
|
879
908
|
/**
|
|
880
909
|
* Domain-event emission. Pass any arc / `@classytic/primitives`-
|
|
881
910
|
* compatible transport and every mutating op publishes
|
|
882
911
|
* `<resource>.<verb>` events (`user.created`, `user.updated`, ...).
|
|
883
912
|
* Omit and the wiring is inert. See `@classytic/repo-core/events`.
|
|
884
913
|
*/
|
|
885
|
-
events?:
|
|
914
|
+
events?: import('@classytic/repo-core/events').RepositoryEventsOptions;
|
|
886
915
|
}
|
|
887
916
|
/** Pagination configuration */
|
|
888
917
|
interface PaginationConfig {
|
|
@@ -1105,7 +1134,7 @@ interface OperationOptions extends ReadOptions {
|
|
|
1105
1134
|
*/
|
|
1106
1135
|
interface CacheableOptions extends OperationOptions {
|
|
1107
1136
|
/** Per-call cache override forwarded to the unified cache plugin. */
|
|
1108
|
-
cache?:
|
|
1137
|
+
cache?: import('@classytic/repo-core/cache').CacheOptions;
|
|
1109
1138
|
}
|
|
1110
1139
|
/** withTransaction options */
|
|
1111
1140
|
interface WithTransactionOptions {
|
|
@@ -1114,7 +1143,7 @@ interface WithTransactionOptions {
|
|
|
1114
1143
|
/** Optional hook to observe fallback triggers */
|
|
1115
1144
|
onFallback?: (error: Error) => void;
|
|
1116
1145
|
/** MongoDB transaction options (readConcern, writeConcern, readPreference, maxCommitTimeMS) */
|
|
1117
|
-
transactionOptions?:
|
|
1146
|
+
transactionOptions?: import('mongoose').mongo.TransactionOptions;
|
|
1118
1147
|
}
|
|
1119
1148
|
/** Create operation options */
|
|
1120
1149
|
interface CreateOptions extends SessionOptions {
|
|
@@ -1200,13 +1229,13 @@ interface LookupPopulateOptions<TBase = unknown> {
|
|
|
1200
1229
|
* controllers produce when typed against `StandardRepo<TDoc>`), or
|
|
1201
1230
|
* a plain `Record<string, unknown>` for ad-hoc callers.
|
|
1202
1231
|
*/
|
|
1203
|
-
filters?:
|
|
1232
|
+
filters?: import('@classytic/repo-core/filter').Filter | (Partial<TBase> & Record<string, unknown>) | Record<string, unknown>;
|
|
1204
1233
|
/**
|
|
1205
1234
|
* Portable `LookupSpec[]` (cross-kit) or mongokit-native
|
|
1206
1235
|
* `LookupOptions[]` (with `pipeline` / `let` / `sanitize`). The
|
|
1207
1236
|
* portable shape is a structural subset, so callers can mix.
|
|
1208
1237
|
*/
|
|
1209
|
-
lookups: readonly
|
|
1238
|
+
lookups: readonly import('@classytic/repo-core/repository').LookupSpec[] | LookupOptions[];
|
|
1210
1239
|
/** Sort specification */
|
|
1211
1240
|
sort?: SortSpec | string;
|
|
1212
1241
|
/** Page number (offset mode, 1-indexed) */
|
|
@@ -1338,7 +1367,7 @@ interface RepositoryContext {
|
|
|
1338
1367
|
* `options.cache` onto the context so the plugin's `before:<op>`
|
|
1339
1368
|
* hook can read it.
|
|
1340
1369
|
*/
|
|
1341
|
-
cache?:
|
|
1370
|
+
cache?: import('@classytic/repo-core/cache').CacheOptions;
|
|
1342
1371
|
/** Whether result was served from cache (internal — set by cache plugin) */
|
|
1343
1372
|
_cacheHit?: boolean;
|
|
1344
1373
|
/** Cached result (internal — set by cache plugin) */
|
|
@@ -1440,7 +1469,7 @@ type EventHandlers<TDoc = unknown> = { [K in RepositoryEvent]?: K extends `befor
|
|
|
1440
1469
|
error: Error;
|
|
1441
1470
|
}) => void | Promise<void> : (payload: {
|
|
1442
1471
|
context: RepositoryContext;
|
|
1443
|
-
}) => void | Promise<void
|
|
1472
|
+
}) => void | Promise<void>; };
|
|
1444
1473
|
/** Event payload */
|
|
1445
1474
|
interface EventPayload {
|
|
1446
1475
|
context: RepositoryContext;
|
|
@@ -1584,7 +1613,7 @@ interface MinMaxResult {
|
|
|
1584
1613
|
*/
|
|
1585
1614
|
interface CacheOperationOptions {
|
|
1586
1615
|
/** Per-call cache override forwarded to the unified cache plugin. */
|
|
1587
|
-
cache?:
|
|
1616
|
+
cache?: import('@classytic/repo-core/cache').CacheOptions;
|
|
1588
1617
|
}
|
|
1589
1618
|
/** Cascade relation definition */
|
|
1590
1619
|
interface CascadeRelation {
|
|
@@ -1721,7 +1750,7 @@ type AllPluginMethods<TDoc> = {
|
|
|
1721
1750
|
* `CacheEngine` plus convenience invalidation helpers. `undefined` when
|
|
1722
1751
|
* no cache plugin is wired.
|
|
1723
1752
|
*/
|
|
1724
|
-
cache?:
|
|
1753
|
+
cache?: import('@classytic/repo-core/cache').RepositoryCacheHandle;
|
|
1725
1754
|
};
|
|
1726
1755
|
/**
|
|
1727
1756
|
* Helper type to add all plugin methods to a repository class
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { t as __exportAll } from "./
|
|
2
|
-
import { n as warn } from "./logger-
|
|
3
|
-
import { t as createError } from "./error-
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
+
import { n as warn } from "./logger-K7dPmu2U.mjs";
|
|
3
|
+
import { t as createError } from "./error-BuByZwKU.mjs";
|
|
4
4
|
import { isFilter } from "@classytic/repo-core/filter";
|
|
5
5
|
//#region src/filter/compile.ts
|
|
6
6
|
/**
|
|
@@ -21,7 +21,7 @@ import { isFilter } from "@classytic/repo-core/filter";
|
|
|
21
21
|
* handles them"). This set covers every operator the arc aggregation
|
|
22
22
|
* guard accepts in `parseDateRange` and `hasFilterOnField`.
|
|
23
23
|
*/
|
|
24
|
-
const SHORTHAND_OPS = new Set([
|
|
24
|
+
const SHORTHAND_OPS = /* @__PURE__ */ new Set([
|
|
25
25
|
"eq",
|
|
26
26
|
"ne",
|
|
27
27
|
"gt",
|
|
@@ -35,7 +35,7 @@ const SHORTHAND_OPS = new Set([
|
|
|
35
35
|
"mod"
|
|
36
36
|
]);
|
|
37
37
|
/** Range operators whose string values should be coerced to Date. */
|
|
38
|
-
const RANGE_OPS = new Set([
|
|
38
|
+
const RANGE_OPS = /* @__PURE__ */ new Set([
|
|
39
39
|
"gt",
|
|
40
40
|
"gte",
|
|
41
41
|
"lt",
|
package/dist/utils/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as IdType, c as isObjectIdInstance, d as filterResponseData, f as getFieldsForUser, i as configureLogger, l as isValidIdForType, m as createError, n as buildCrudSchemasFromMongooseSchema, o as getSchemaIdType, p as getMongooseProjection, r as createMemoryCache, t as buildCrudSchemasFromModel, u as createFieldPreset } from "../mongooseToJsonSchema-
|
|
1
|
+
import { a as IdType, c as isObjectIdInstance, d as filterResponseData, f as getFieldsForUser, i as configureLogger, l as isValidIdForType, m as createError, n as buildCrudSchemasFromMongooseSchema, o as getSchemaIdType, p as getMongooseProjection, r as createMemoryCache, t as buildCrudSchemasFromModel, u as createFieldPreset } from "../mongooseToJsonSchema-D2CyAMIC.mjs";
|
|
2
2
|
export { type IdType, buildCrudSchemasFromModel, buildCrudSchemasFromMongooseSchema, configureLogger, createError, createFieldPreset, createMemoryCache, filterResponseData, getFieldsForUser, getMongooseProjection, getSchemaIdType, isObjectIdInstance, isValidIdForType };
|
package/dist/utils/index.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { i as isValidIdForType, r as isObjectIdInstance, t as getSchemaIdType } from "../id-resolution-
|
|
2
|
-
import { t as configureLogger } from "../logger-
|
|
3
|
-
import { t as createError } from "../error-
|
|
4
|
-
import { i as getMongooseProjection, n as filterResponseData, r as getFieldsForUser, t as createFieldPreset } from "../field-selection-
|
|
5
|
-
import {
|
|
1
|
+
import { i as isValidIdForType, r as isObjectIdInstance, t as getSchemaIdType } from "../id-resolution-P2OzcyRl.mjs";
|
|
2
|
+
import { t as configureLogger } from "../logger-K7dPmu2U.mjs";
|
|
3
|
+
import { t as createError } from "../error-BuByZwKU.mjs";
|
|
4
|
+
import { i as getMongooseProjection, n as filterResponseData, r as getFieldsForUser, t as createFieldPreset } from "../field-selection-FSQFLpsU.mjs";
|
|
5
|
+
import { t as createMemoryCache } from "../memory-cache-DI1jb4dz.mjs";
|
|
6
|
+
import { n as buildCrudSchemasFromMongooseSchema, t as buildCrudSchemasFromModel } from "../mongooseToJsonSchema-CVnrKFDq.mjs";
|
|
6
7
|
export { buildCrudSchemasFromModel, buildCrudSchemasFromMongooseSchema, configureLogger, createError, createFieldPreset, createMemoryCache, filterResponseData, getFieldsForUser, getMongooseProjection, getSchemaIdType, isObjectIdInstance, isValidIdForType };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { s as ALL_OPERATIONS } from "./Repository-
|
|
2
|
-
import { _ as upsert } from "./update-
|
|
3
|
-
import { n as warn } from "./logger-
|
|
4
|
-
import { t as createError } from "./error-
|
|
5
|
-
import { r as getFieldsForUser } from "./field-selection-
|
|
1
|
+
import { s as ALL_OPERATIONS } from "./Repository-dbbgOGjK.mjs";
|
|
2
|
+
import { _ as upsert } from "./update-1Lq9OMD2.mjs";
|
|
3
|
+
import { n as warn } from "./logger-K7dPmu2U.mjs";
|
|
4
|
+
import { t as createError } from "./error-BuByZwKU.mjs";
|
|
5
|
+
import { r as getFieldsForUser } from "./field-selection-FSQFLpsU.mjs";
|
|
6
6
|
import mongoose from "mongoose";
|
|
7
7
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
8
8
|
//#region src/plugins/aggregate-helpers.plugin.ts
|
|
@@ -681,7 +681,7 @@ function mongoOperationsPlugin() {
|
|
|
681
681
|
* }, { arrayFilters: [{ 'elem._id': itemId }] });
|
|
682
682
|
*/
|
|
683
683
|
repo.registerMethod("atomicUpdate", async function(id, operators, options = {}) {
|
|
684
|
-
const validOperators = new Set([
|
|
684
|
+
const validOperators = /* @__PURE__ */ new Set([
|
|
685
685
|
"$inc",
|
|
686
686
|
"$set",
|
|
687
687
|
"$unset",
|
package/dist/{validation-chain.plugin-CYOPfFGF.d.mts → validation-chain.plugin-buy3uvyk.d.mts}
RENAMED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { B as ObjectId, C as FieldPreset, G as Plugin, J as PopulateSpec, Q as RepositoryContext, _t as ValidationChainOptions, et as RepositoryInstance, it as SelectSpec, j as Logger, l as CascadeOptions, st as SoftDeleteOptions, ut as SortSpec, vt as ValidatorDefinition } from "./types-
|
|
1
|
+
import { B as ObjectId, C as FieldPreset, G as Plugin, J as PopulateSpec, Q as RepositoryContext, _t as ValidationChainOptions, et as RepositoryInstance, it as SelectSpec, j as Logger, l as CascadeOptions, st as SoftDeleteOptions, ut as SortSpec, vt as ValidatorDefinition } from "./types-DNFMofHy.mjs";
|
|
2
2
|
import { BulkWriteResult } from "@classytic/repo-core/repository";
|
|
3
3
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
4
4
|
import { OffsetPaginationResult } from "@classytic/repo-core/pagination";
|
|
5
|
-
|
|
6
5
|
//#region src/plugins/aggregate-helpers.plugin.d.ts
|
|
7
6
|
/**
|
|
8
7
|
* Aggregate helpers plugin
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@classytic/mongokit",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.21.0",
|
|
4
4
|
"description": "Production-grade MongoDB repositories - smart pagination, events, and plugins. Built on @classytic/repo-core.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -109,7 +109,7 @@
|
|
|
109
109
|
},
|
|
110
110
|
"homepage": "https://github.com/classytic/mongokit#readme",
|
|
111
111
|
"peerDependencies": {
|
|
112
|
-
"@classytic/repo-core": ">=0.
|
|
112
|
+
"@classytic/repo-core": ">=0.8.0",
|
|
113
113
|
"better-auth": ">=1.6.0",
|
|
114
114
|
"mongodb-memory-server": ">=10.0.0",
|
|
115
115
|
"mongoose": ">=9.4.1"
|
|
@@ -142,10 +142,11 @@
|
|
|
142
142
|
"typecheck:tests": "tsc --noEmit -p tsconfig.tests.json",
|
|
143
143
|
"lint": "biome check src/",
|
|
144
144
|
"lint:fix": "biome check src/ --write",
|
|
145
|
+
"lint:package": "publint && attw --pack . --profile esm-only",
|
|
145
146
|
"format": "biome format src/ --write",
|
|
146
147
|
"check": "biome ci src/ --diagnostic-level=error",
|
|
147
148
|
"push": "classytic-push",
|
|
148
|
-
"prepublishOnly": "npm run check && npm run build && npm run typecheck && npm run typecheck:tests && npm test",
|
|
149
|
+
"prepublishOnly": "npm run check && npm run build && npm run lint:package && npm run typecheck && npm run typecheck:tests && npm test",
|
|
149
150
|
"publish:dry": "npm publish --dry-run --access public",
|
|
150
151
|
"publish:npm": "npm publish --access public",
|
|
151
152
|
"release:tag": "node -e \"require('child_process').execSync('npm run push -- v'+require('./package.json').version,{stdio:'inherit'})\"",
|
|
@@ -160,20 +161,20 @@
|
|
|
160
161
|
"@better-auth/mongo-adapter": "^1.6.22",
|
|
161
162
|
"@biomejs/biome": "^2.4.10",
|
|
162
163
|
"@classytic/dev-tools": "^0.2.0",
|
|
163
|
-
"@classytic/repo-core": "^0.
|
|
164
|
+
"@classytic/repo-core": "^0.9.0",
|
|
164
165
|
"@types/node": "^22.0.0",
|
|
165
166
|
"@vitest/coverage-v8": "^4.1.4",
|
|
166
167
|
"ajv": "^8.18.0",
|
|
167
168
|
"ajv-formats": "^3.0.1",
|
|
168
|
-
"better-auth": "^1.6.
|
|
169
|
+
"better-auth": "^1.6.23",
|
|
169
170
|
"dotenv": "^17.4.2",
|
|
170
171
|
"knip": "^6.3.0",
|
|
171
172
|
"mongodb": "7.2.0",
|
|
172
173
|
"mongodb-memory-server": "^10.4.3",
|
|
173
174
|
"mongoose": "^9.4.1",
|
|
174
175
|
"publint": "^0.3.18",
|
|
175
|
-
"tsdown": "^0.
|
|
176
|
-
"typescript": "^
|
|
176
|
+
"tsdown": "^0.22.5",
|
|
177
|
+
"typescript": "^7.0.2",
|
|
177
178
|
"vitest": "^4.1.4"
|
|
178
179
|
},
|
|
179
180
|
"overrides": {
|
package/dist/cursor-_SbWVAn-.mjs
DELETED
|
@@ -1,254 +0,0 @@
|
|
|
1
|
-
import { t as __exportAll } from "./chunk-CfYAbeIz.mjs";
|
|
2
|
-
import mongoose from "mongoose";
|
|
3
|
-
//#region src/pagination/utils/filter.ts
|
|
4
|
-
/**
|
|
5
|
-
* Builds MongoDB filter for keyset pagination
|
|
6
|
-
* Creates compound $or condition for proper cursor-based filtering
|
|
7
|
-
*
|
|
8
|
-
* @param baseFilters - Existing query filters
|
|
9
|
-
* @param sort - Normalized sort specification
|
|
10
|
-
* @param cursorValue - Primary field value from cursor
|
|
11
|
-
* @param cursorId - _id value from cursor
|
|
12
|
-
* @returns MongoDB filter with keyset condition
|
|
13
|
-
*
|
|
14
|
-
* @example
|
|
15
|
-
* buildKeysetFilter(
|
|
16
|
-
* { status: 'active' },
|
|
17
|
-
* { createdAt: -1, _id: -1 },
|
|
18
|
-
* new Date('2024-01-01'),
|
|
19
|
-
* new ObjectId('...')
|
|
20
|
-
* )
|
|
21
|
-
* // Returns:
|
|
22
|
-
* // {
|
|
23
|
-
* // status: 'active',
|
|
24
|
-
* // $or: [
|
|
25
|
-
* // { createdAt: { $lt: Date('2024-01-01') } },
|
|
26
|
-
* // { createdAt: Date('2024-01-01'), _id: { $lt: ObjectId('...') } }
|
|
27
|
-
* // ]
|
|
28
|
-
* // }
|
|
29
|
-
*/
|
|
30
|
-
function buildKeysetFilter(baseFilters, sort, cursorValue, cursorId, cursorValues) {
|
|
31
|
-
const sortFields = Object.keys(sort).filter((k) => k !== "_id");
|
|
32
|
-
if (sortFields.length <= 1 && !cursorValues) {
|
|
33
|
-
const primaryField = sortFields[0] || "_id";
|
|
34
|
-
const direction = sort[primaryField];
|
|
35
|
-
const operator = direction === 1 ? "$gt" : "$lt";
|
|
36
|
-
if (cursorValue === null || cursorValue === void 0) if (direction === 1) return {
|
|
37
|
-
...baseFilters,
|
|
38
|
-
$or: [{
|
|
39
|
-
[primaryField]: null,
|
|
40
|
-
_id: { $gt: cursorId }
|
|
41
|
-
}, { [primaryField]: { $ne: null } }]
|
|
42
|
-
};
|
|
43
|
-
else return {
|
|
44
|
-
...baseFilters,
|
|
45
|
-
[primaryField]: null,
|
|
46
|
-
_id: { $lt: cursorId }
|
|
47
|
-
};
|
|
48
|
-
return {
|
|
49
|
-
...baseFilters,
|
|
50
|
-
$or: [{ [primaryField]: { [operator]: cursorValue } }, {
|
|
51
|
-
[primaryField]: cursorValue,
|
|
52
|
-
_id: { [operator]: cursorId }
|
|
53
|
-
}]
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
const values = cursorValues || { [sortFields[0]]: cursorValue };
|
|
57
|
-
const allFields = [...sortFields, "_id"];
|
|
58
|
-
const allValues = {
|
|
59
|
-
...values,
|
|
60
|
-
_id: cursorId
|
|
61
|
-
};
|
|
62
|
-
const orConditions = [];
|
|
63
|
-
for (let i = 0; i < allFields.length; i++) {
|
|
64
|
-
const field = allFields[i];
|
|
65
|
-
const operator = (sort[field] ?? sort[sortFields[0]]) === 1 ? "$gt" : "$lt";
|
|
66
|
-
const condition = {};
|
|
67
|
-
for (let j = 0; j < i; j++) condition[allFields[j]] = allValues[allFields[j]];
|
|
68
|
-
condition[field] = { [operator]: allValues[field] };
|
|
69
|
-
orConditions.push(condition);
|
|
70
|
-
}
|
|
71
|
-
return {
|
|
72
|
-
...baseFilters,
|
|
73
|
-
$or: orConditions
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
//#endregion
|
|
77
|
-
//#region src/pagination/utils/cursor.ts
|
|
78
|
-
/**
|
|
79
|
-
* Cursor Utilities
|
|
80
|
-
*
|
|
81
|
-
* Encoding and decoding of cursor tokens for keyset pagination.
|
|
82
|
-
* Cursors are base64-encoded JSON containing position data and metadata.
|
|
83
|
-
*/
|
|
84
|
-
var cursor_exports = /* @__PURE__ */ __exportAll({
|
|
85
|
-
decodeCursor: () => decodeCursor,
|
|
86
|
-
encodeCursor: () => encodeCursor,
|
|
87
|
-
resolveCursorFilter: () => resolveCursorFilter,
|
|
88
|
-
validateCursorSort: () => validateCursorSort,
|
|
89
|
-
validateCursorVersion: () => validateCursorVersion
|
|
90
|
-
});
|
|
91
|
-
/**
|
|
92
|
-
* Encodes document values and sort metadata into a base64 cursor token
|
|
93
|
-
*
|
|
94
|
-
* @param doc - Document to extract cursor values from
|
|
95
|
-
* @param primaryField - Primary sort field name
|
|
96
|
-
* @param sort - Normalized sort specification
|
|
97
|
-
* @param version - Cursor version for forward compatibility
|
|
98
|
-
* @returns Base64-encoded cursor token
|
|
99
|
-
*/
|
|
100
|
-
function encodeCursor(doc, primaryField, sort, version = 1) {
|
|
101
|
-
const primaryValue = doc[primaryField];
|
|
102
|
-
const idValue = doc._id;
|
|
103
|
-
const sortFields = Object.keys(sort).filter((k) => k !== "_id");
|
|
104
|
-
const vals = {};
|
|
105
|
-
const types = {};
|
|
106
|
-
for (const field of sortFields) {
|
|
107
|
-
vals[field] = serializeValue(doc[field]);
|
|
108
|
-
types[field] = getValueType(doc[field]);
|
|
109
|
-
}
|
|
110
|
-
const payload = {
|
|
111
|
-
v: serializeValue(primaryValue),
|
|
112
|
-
t: getValueType(primaryValue),
|
|
113
|
-
id: serializeValue(idValue),
|
|
114
|
-
idType: getValueType(idValue),
|
|
115
|
-
sort,
|
|
116
|
-
ver: version,
|
|
117
|
-
...sortFields.length > 1 && {
|
|
118
|
-
vals,
|
|
119
|
-
types
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
return Buffer.from(JSON.stringify(payload)).toString("base64");
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* Decodes a cursor token back into document values and sort metadata
|
|
126
|
-
*
|
|
127
|
-
* @param token - Base64-encoded cursor token
|
|
128
|
-
* @returns Decoded cursor data
|
|
129
|
-
* @throws Error if token is invalid or malformed
|
|
130
|
-
*/
|
|
131
|
-
function decodeCursor(token) {
|
|
132
|
-
let json;
|
|
133
|
-
try {
|
|
134
|
-
json = Buffer.from(token, "base64").toString("utf-8");
|
|
135
|
-
} catch {
|
|
136
|
-
throw new Error("Invalid cursor token: not valid base64");
|
|
137
|
-
}
|
|
138
|
-
let payload;
|
|
139
|
-
try {
|
|
140
|
-
payload = JSON.parse(json);
|
|
141
|
-
} catch {
|
|
142
|
-
throw new Error("Invalid cursor token: not valid JSON");
|
|
143
|
-
}
|
|
144
|
-
if (!payload || typeof payload !== "object" || !("v" in payload) || !("t" in payload) || !("id" in payload) || !("idType" in payload) || !payload.sort || typeof payload.sort !== "object" || typeof payload.ver !== "number") throw new Error("Invalid cursor token: malformed payload structure");
|
|
145
|
-
const VALID_TYPES = [
|
|
146
|
-
"date",
|
|
147
|
-
"objectid",
|
|
148
|
-
"boolean",
|
|
149
|
-
"number",
|
|
150
|
-
"string",
|
|
151
|
-
"null",
|
|
152
|
-
"unknown"
|
|
153
|
-
];
|
|
154
|
-
if (!VALID_TYPES.includes(payload.t) || !VALID_TYPES.includes(payload.idType)) throw new Error("Invalid cursor token: unrecognized value type");
|
|
155
|
-
try {
|
|
156
|
-
let values;
|
|
157
|
-
if (payload.vals && payload.types) {
|
|
158
|
-
values = {};
|
|
159
|
-
for (const [field, serialized] of Object.entries(payload.vals)) values[field] = rehydrateValue(serialized, payload.types[field]);
|
|
160
|
-
}
|
|
161
|
-
return {
|
|
162
|
-
value: rehydrateValue(payload.v, payload.t),
|
|
163
|
-
id: rehydrateValue(payload.id, payload.idType),
|
|
164
|
-
sort: payload.sort,
|
|
165
|
-
version: payload.ver,
|
|
166
|
-
...values && { values }
|
|
167
|
-
};
|
|
168
|
-
} catch {
|
|
169
|
-
throw new Error("Invalid cursor token: failed to rehydrate values");
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
/**
|
|
173
|
-
* Validates that cursor sort matches current query sort
|
|
174
|
-
*
|
|
175
|
-
* @param cursorSort - Sort specification from cursor
|
|
176
|
-
* @param currentSort - Sort specification from query
|
|
177
|
-
* @throws Error if sorts don't match
|
|
178
|
-
*/
|
|
179
|
-
function validateCursorSort(cursorSort, currentSort) {
|
|
180
|
-
if (JSON.stringify(cursorSort) !== JSON.stringify(currentSort)) throw new Error("Cursor sort does not match current query sort");
|
|
181
|
-
}
|
|
182
|
-
/**
|
|
183
|
-
* Validates cursor version against the server's expected range.
|
|
184
|
-
*
|
|
185
|
-
* - Cursors newer than `expectedVersion` are rejected (client ahead of server).
|
|
186
|
-
* - Cursors older than `minVersion` are rejected (client cached a cursor from
|
|
187
|
-
* a pre-breaking-change deploy). Default `minVersion = 1` keeps the legacy
|
|
188
|
-
* "accept anything <= expected" behavior; bump it when you ship a breaking
|
|
189
|
-
* cursor format change so old clients restart pagination cleanly instead of
|
|
190
|
-
* silently paginating from the wrong position.
|
|
191
|
-
*/
|
|
192
|
-
function validateCursorVersion(cursorVersion, expectedVersion, minVersion = 1) {
|
|
193
|
-
if (cursorVersion > expectedVersion) throw new Error(`Cursor version ${cursorVersion} is newer than expected version ${expectedVersion}. Please upgrade.`);
|
|
194
|
-
if (cursorVersion < minVersion) throw new Error(`Cursor version ${cursorVersion} is older than minimum supported ${minVersion}. Pagination must restart.`);
|
|
195
|
-
}
|
|
196
|
-
/**
|
|
197
|
-
* Serializes a value for cursor storage
|
|
198
|
-
*/
|
|
199
|
-
function serializeValue(value) {
|
|
200
|
-
if (value === null || value === void 0) return null;
|
|
201
|
-
if (value instanceof Date) return value.toISOString();
|
|
202
|
-
if (value instanceof mongoose.Types.ObjectId) return value.toString();
|
|
203
|
-
return value;
|
|
204
|
-
}
|
|
205
|
-
/**
|
|
206
|
-
* Gets the type identifier for a value
|
|
207
|
-
*/
|
|
208
|
-
function getValueType(value) {
|
|
209
|
-
if (value === null || value === void 0) return "null";
|
|
210
|
-
if (value instanceof Date) return "date";
|
|
211
|
-
if (value instanceof mongoose.Types.ObjectId) return "objectid";
|
|
212
|
-
if (typeof value === "boolean") return "boolean";
|
|
213
|
-
if (typeof value === "number") return "number";
|
|
214
|
-
if (typeof value === "string") return "string";
|
|
215
|
-
return "unknown";
|
|
216
|
-
}
|
|
217
|
-
/**
|
|
218
|
-
* Rehydrates a serialized value back to its original type
|
|
219
|
-
*/
|
|
220
|
-
function rehydrateValue(serialized, type) {
|
|
221
|
-
if (type === "null" || serialized === null) return null;
|
|
222
|
-
switch (type) {
|
|
223
|
-
case "date": return new Date(serialized);
|
|
224
|
-
case "objectid": return new mongoose.Types.ObjectId(serialized);
|
|
225
|
-
case "boolean": return serialized === true || serialized === "true";
|
|
226
|
-
case "number": return Number(serialized);
|
|
227
|
-
default: return serialized;
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
/**
|
|
231
|
-
* Resolves cursor token into MongoDB query filters.
|
|
232
|
-
* Shared by PaginationEngine.stream() and Repository.lookupPopulate() keyset path.
|
|
233
|
-
*
|
|
234
|
-
* Handles:
|
|
235
|
-
* - Plain 24-char hex ObjectId strings (fallback cursor)
|
|
236
|
-
* - Base64-encoded cursor tokens (standard cursor)
|
|
237
|
-
* - Cursor version and sort validation
|
|
238
|
-
*/
|
|
239
|
-
function resolveCursorFilter(after, sort, cursorVersion, baseFilters = {}, minCursorVersion = 1) {
|
|
240
|
-
if (/^[a-f0-9]{24}$/i.test(after)) {
|
|
241
|
-
const objectId = new mongoose.Types.ObjectId(after);
|
|
242
|
-
const idOperator = (sort._id || -1) === 1 ? "$gt" : "$lt";
|
|
243
|
-
return {
|
|
244
|
-
...baseFilters,
|
|
245
|
-
_id: { [idOperator]: objectId }
|
|
246
|
-
};
|
|
247
|
-
}
|
|
248
|
-
const cursor = decodeCursor(after);
|
|
249
|
-
validateCursorVersion(cursor.version, cursorVersion, minCursorVersion);
|
|
250
|
-
validateCursorSort(cursor.sort, sort);
|
|
251
|
-
return buildKeysetFilter(baseFilters, sort, cursor.value, cursor.id, cursor.values);
|
|
252
|
-
}
|
|
253
|
-
//#endregion
|
|
254
|
-
export { encodeCursor as n, resolveCursorFilter as r, cursor_exports as t };
|