@classytic/mongokit 3.13.0 → 3.13.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 CHANGED
@@ -284,6 +284,58 @@ Each plugin is tree-shakeable. Import only what you use.
284
284
 
285
285
  ---
286
286
 
287
+ ## Composing with mongoose-level plugins
288
+
289
+ mongokit deliberately doesn't reabsorb mongoose plugins that already work via `schema.plugin(...)`. They compose cleanly: the mongoose plugin attaches to the schema before the model lands at mongokit, both layers fire on every write.
290
+
291
+ Canonical examples — install + wire as documented by the upstream package, then hand the model to mongokit:
292
+
293
+ ```ts
294
+ import mongoose from 'mongoose';
295
+ import { Repository, multiTenantPlugin } from '@classytic/mongokit';
296
+ import timelineAuditPlugin from 'mongoose-timeline-audit';
297
+ import slugPlugin from 'mongoose-slug-plugin';
298
+
299
+ const orderSchema = new mongoose.Schema({
300
+ customerId: { type: mongoose.Schema.Types.ObjectId, ref: 'Customer' },
301
+ status: String,
302
+ title: String,
303
+ });
304
+
305
+ // 1. Wire mongoose-level plugins on the schema
306
+ orderSchema.plugin(timelineAuditPlugin, {
307
+ ownerField: 'customerId',
308
+ eventLimits: { 'order.updated': 20 },
309
+ });
310
+ orderSchema.plugin(slugPlugin, { tmpl: '<%=title%>' });
311
+
312
+ // 2. Build the model
313
+ const Order = mongoose.model('Order', orderSchema);
314
+
315
+ // 3. Hand the model to mongokit — kit plugins layer on top
316
+ const orderRepo = new Repository(Order, [
317
+ multiTenantPlugin({ tenantField: 'organizationId' }),
318
+ ]);
319
+
320
+ // Now every write fires BOTH layers:
321
+ // - mongoose pre('save') / post('save') (timeline-audit, slug)
322
+ // - mongokit before:create / after:create (multi-tenant, audit, cache)
323
+ await orderRepo.create({ customerId, status: 'pending', title: 'New order' });
324
+ ```
325
+
326
+ **Why this composition over absorbing into mongokit:** mongoose plugins hook `schema.add()` + `pre('save')`; mongokit plugins hook `before:create` / `after:update`. Different event models, different concerns. Wrapping a mongoose plugin as a mongokit plugin would be a fork, not a wrapper — and the mongoose plugin already works without mongokit being involved at all. Keeping the layers separate also lets each package version independently.
327
+
328
+ **When to use which audit surface:**
329
+
330
+ | Need | Reach for |
331
+ |---|---|
332
+ | Per-doc UX timeline visible to end users (`order.timeline = [{event, actor, at}, ...]`) | `mongoose-timeline-audit` (mongoose plugin) — embedded array on the doc |
333
+ | Compliance audit ledger across models, immutable, queryable | `auditTrailPlugin` (mongokit, ships in this package) — separate collection |
334
+
335
+ The two are complementary, not alternatives. A typical app wires both — timeline for the customer-facing order page, auditTrail for the compliance officer's quarterly export.
336
+
337
+ ---
338
+
287
339
  ## QueryParser (URL → filter)
288
340
 
289
341
  Turn Express / Fastify query strings into sanitized Mongo filters + sort + pagination.
@@ -1,4 +1,4 @@
1
- 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-DLcSSa5b.mjs";
1
+ 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-C-3viiw1.mjs";
2
2
  import { n as warn } from "./logger-DprijP5h.mjs";
3
3
  import { n as isDuplicateKeyError, r as parseDuplicateKeyError, t as createError } from "./error-B00pI7dV.mjs";
4
4
  import { t as PaginationEngine } from "./PaginationEngine-CfQRM1yz.mjs";
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "../chunk-CfYAbeIz.mjs";
2
- import { g as create_exports, i as update_exports, p as delete_exports, u as read_exports, v as aggregate_exports } from "../update-DLcSSa5b.mjs";
2
+ import { g as create_exports, i as update_exports, p as delete_exports, u as read_exports, v as aggregate_exports } from "../update-C-3viiw1.mjs";
3
3
  //#region src/actions/index.ts
4
4
  var actions_exports = /* @__PURE__ */ __exportAll({
5
5
  aggregate: () => aggregate_exports,
@@ -1,4 +1,4 @@
1
- import { n as Repository } from "../Repository-BY40uhcv.mjs";
1
+ import { n as Repository } from "../Repository-d5gWSROf.mjs";
2
2
  import { n as createMongooseAdapter } from "../adapter-DTDMnUOH.mjs";
3
3
  import { pluralizeBetterAuthCollection, resolveBetterAuthCollections } from "@classytic/repo-core/better-auth";
4
4
  //#region src/better-auth/index.ts
package/dist/index.d.mts CHANGED
@@ -12,6 +12,29 @@ import { UpdateInput } from "@classytic/repo-core/update";
12
12
  import { AggregatePaginationResult, KeysetPaginationResult, OffsetPaginationResult, OffsetPaginationResultCore } from "@classytic/repo-core/pagination";
13
13
  import { HttpError } from "@classytic/repo-core/errors";
14
14
 
15
+ //#region src/filter/compile.d.ts
16
+ /**
17
+ * Filter IR → MongoDB query compiler.
18
+ *
19
+ * Mirrors sqlitekit's `compileFilterToDrizzle`: takes a repo-core
20
+ * `Filter` tree and emits a MongoDB query object. Used by `groupBy` /
21
+ * `groupByPaginate` to translate the portable AggRequest's `filter`
22
+ * + `having` into `$match` stages.
23
+ *
24
+ * Scope: the same operator set sqlitekit supports (`eq`, `ne`, `gt`,
25
+ * `gte`, `lt`, `lte`, `in`, `nin`, `exists`, `like`, `regex`, `and`,
26
+ * `or`, `not`, `raw`). Anything else throws so we fail loud instead
27
+ * of silently dropping predicates.
28
+ *
29
+ * Why only this op set here and not everywhere in mongokit? Historic
30
+ * reason: mongokit pre-dates repo-core's Filter IR, so its existing
31
+ * policy plugins (multi-tenant, soft-delete) speak MongoDB query
32
+ * language directly. Converting mongokit's entire filter pipeline
33
+ * to Filter IR is out-of-scope for this change — we introduce the
34
+ * compiler only where the new portable `groupBy` IR needs it.
35
+ */
36
+ declare function compileFilterToMongo(input: unknown): Record<string, unknown>;
37
+ //#endregion
15
38
  //#region src/operations.d.ts
16
39
  /**
17
40
  * Where a plugin should inject its scoping filter (multi-tenant scope,
@@ -2114,4 +2137,4 @@ declare function createOptionsExtractor<TCtx extends Record<string, unknown>>(fi
2114
2137
  */
2115
2138
  declare function createRepository<TDoc>(Model: _$mongoose.Model<TDoc, any, any, any>, plugins?: PluginType[], paginationConfig?: PaginationConfig, options?: RepositoryOptions): Repository<TDoc>;
2116
2139
  //#endregion
2117
- export { ALL_OPERATIONS, type AggregateHelpersMethods, type AggregateOptions, type AggregatePaginationOptions, AggregationBuilder, type AllPluginMethods, type AnyDocument, type AnyModel, type AuditEntry, type AuditOperation, type AuditQueryOptions, type AuditQueryResult, type AuditTrailMethods, type AuditTrailOptions, AuditTrailQuery, type BasePaginationOptions, type BatchOperationsMethods, type BulkWriteResult, type CacheAdapter, type CacheOperationOptions, type CacheOptions, type CacheableOptions, type CascadeOptions, type CascadeRelation, type CollationOptions, type CreateInput, type CreateOptions, type CursorPayload, type CustomIdOptions, type DateSequentialIdOptions, type DecodedCursor, type DeepPartial, type DeleteResult, type DocField, type ElasticSearchOptions, type EventHandlers, type EventPayload, type EventPhase, type FieldPreset, type FieldType, type FilterQuery, type FindOneAndUpdateOptions, type GroupResult, HOOK_PRIORITY, type HookMode, type IController, type IControllerResponse, type IRequestContext, type IResponseFormatter, type IdGenerator, type InferDocument, type InferRawDoc, type KeysOfType, type KeysetPaginationOptions, type LeaseMethods, type LeasePluginOptions, type Logger, LookupBuilder, type LookupOptions, type LookupPopulateOptions, type LookupPopulateResult, MUTATING_OPERATIONS, type Middleware, type MiddlewareContext, type MinMaxResult, type MinimalRepoView, type MongoOperationsMethods, type MongoOperatorUpdate, type MultiTenantOptions, type NonNullableFields, OP_REGISTRY, type ObjectId, type ObservabilityOptions, type OffsetPaginationOptions, type OperationDescriptor, type OperationMetric, type OperationOptions, type PaginationConfig, PaginationEngine, type ParsedQuery, type PartialBy, type Plugin, type PluginFunction, type PluginType, type PolicyKey, type PopulateOption, type PopulateSpec, type PrefixedIdOptions, type PrioritizedHook, QueryParser, type QueryParserOptions, READ_OPERATIONS, type ReadOptions, type ReadPreferenceType, Repository, Repository as default, type RepositoryCacheHandle, type RepositoryCachePluginOptions, type RepositoryContext, type RepositoryEvent, type RepositoryInstance, type RepositoryOperation, type RepositoryOptions, type RequiredBy, type SchemaLike, type SearchMode, type SelectSpec, type SequentialIdOptions, type SessionOptions, type SoftDeleteFilterMode, type SoftDeleteMethods, type SoftDeleteOptions, type SoftDeleteRepository, type SortDirection, type SortSpec, type Strict, type SubdocumentMethods, type TenantContext, type TenantStore, type UpdateManyResult, type UpdateOptions, type UpdatePatch, type UpdateWithValidationResult, type UserContext, type ValidationChainOptions, type ValidatorDefinition, type ValueType, type WithPlugins, type WithTransactionOptions, index_d_exports as actions, adminBypass, aggregateHelpersPlugin, auditLogPlugin, auditTrailPlugin, autoInject, batchOperationsPlugin, batchTransaction, blockIf, buildCrudSchemasFromModel, buildCrudSchemasFromMongooseSchema, cachePlugin, cascadePlugin, configureLogger, createError, createFieldPreset, createMemoryCache, createOptionsExtractor, createRepository, createTenantContext, customIdPlugin, dateSequentialId, elasticSearchPlugin, fieldFilterPlugin, filterResponseData, getFieldsForUser, getMongooseProjection, getNextSequence, immutableField, isDuplicateKeyError, isTransactionUnsupported, leasePlugin, methodRegistryPlugin, mongoOperationsPlugin, multiTenantPlugin, observabilityPlugin, operationsByPolicyKey, parseDuplicateKeyError, prefixedId, repoOptionsFromCtx, requireField, sequentialId, softDeletePlugin, subdocumentPlugin, timestampPlugin, uniqueField, validationChainPlugin, withTransaction };
2140
+ export { ALL_OPERATIONS, type AggregateHelpersMethods, type AggregateOptions, type AggregatePaginationOptions, AggregationBuilder, type AllPluginMethods, type AnyDocument, type AnyModel, type AuditEntry, type AuditOperation, type AuditQueryOptions, type AuditQueryResult, type AuditTrailMethods, type AuditTrailOptions, AuditTrailQuery, type BasePaginationOptions, type BatchOperationsMethods, type BulkWriteResult, type CacheAdapter, type CacheOperationOptions, type CacheOptions, type CacheableOptions, type CascadeOptions, type CascadeRelation, type CollationOptions, type CreateInput, type CreateOptions, type CursorPayload, type CustomIdOptions, type DateSequentialIdOptions, type DecodedCursor, type DeepPartial, type DeleteResult, type DocField, type ElasticSearchOptions, type EventHandlers, type EventPayload, type EventPhase, type FieldPreset, type FieldType, type FilterQuery, type FindOneAndUpdateOptions, type GroupResult, HOOK_PRIORITY, type HookMode, type IController, type IControllerResponse, type IRequestContext, type IResponseFormatter, type IdGenerator, type InferDocument, type InferRawDoc, type KeysOfType, type KeysetPaginationOptions, type LeaseMethods, type LeasePluginOptions, type Logger, LookupBuilder, type LookupOptions, type LookupPopulateOptions, type LookupPopulateResult, MUTATING_OPERATIONS, type Middleware, type MiddlewareContext, type MinMaxResult, type MinimalRepoView, type MongoOperationsMethods, type MongoOperatorUpdate, type MultiTenantOptions, type NonNullableFields, OP_REGISTRY, type ObjectId, type ObservabilityOptions, type OffsetPaginationOptions, type OperationDescriptor, type OperationMetric, type OperationOptions, type PaginationConfig, PaginationEngine, type ParsedQuery, type PartialBy, type Plugin, type PluginFunction, type PluginType, type PolicyKey, type PopulateOption, type PopulateSpec, type PrefixedIdOptions, type PrioritizedHook, QueryParser, type QueryParserOptions, READ_OPERATIONS, type ReadOptions, type ReadPreferenceType, Repository, Repository as default, type RepositoryCacheHandle, type RepositoryCachePluginOptions, type RepositoryContext, type RepositoryEvent, type RepositoryInstance, type RepositoryOperation, type RepositoryOptions, type RequiredBy, type SchemaLike, type SearchMode, type SelectSpec, type SequentialIdOptions, type SessionOptions, type SoftDeleteFilterMode, type SoftDeleteMethods, type SoftDeleteOptions, type SoftDeleteRepository, type SortDirection, type SortSpec, type Strict, type SubdocumentMethods, type TenantContext, type TenantStore, type UpdateManyResult, type UpdateOptions, type UpdatePatch, type UpdateWithValidationResult, type UserContext, type ValidationChainOptions, type ValidatorDefinition, type ValueType, type WithPlugins, type WithTransactionOptions, index_d_exports as actions, adminBypass, aggregateHelpersPlugin, auditLogPlugin, auditTrailPlugin, autoInject, batchOperationsPlugin, batchTransaction, blockIf, buildCrudSchemasFromModel, buildCrudSchemasFromMongooseSchema, cachePlugin, cascadePlugin, compileFilterToMongo, configureLogger, createError, createFieldPreset, createMemoryCache, createOptionsExtractor, createRepository, createTenantContext, customIdPlugin, dateSequentialId, elasticSearchPlugin, fieldFilterPlugin, filterResponseData, getFieldsForUser, getMongooseProjection, getNextSequence, immutableField, isDuplicateKeyError, isTransactionUnsupported, leasePlugin, methodRegistryPlugin, mongoOperationsPlugin, multiTenantPlugin, observabilityPlugin, operationsByPolicyKey, parseDuplicateKeyError, prefixedId, repoOptionsFromCtx, requireField, sequentialId, softDeletePlugin, subdocumentPlugin, timestampPlugin, uniqueField, validationChainPlugin, withTransaction };
package/dist/index.mjs CHANGED
@@ -1,10 +1,10 @@
1
- import { b as LookupBuilder } from "./update-DLcSSa5b.mjs";
1
+ import { b as LookupBuilder, x as compileFilterToMongo } from "./update-C-3viiw1.mjs";
2
2
  import { n as warn, t as configureLogger } from "./logger-DprijP5h.mjs";
3
3
  import { n as isDuplicateKeyError, r as parseDuplicateKeyError, t as createError } from "./error-B00pI7dV.mjs";
4
4
  import { t as actions_exports } from "./actions/index.mjs";
5
- import { a as withTransaction, c as MUTATING_OPERATIONS, d as operationsByPolicyKey, i as isTransactionUnsupported, l as OP_REGISTRY, n as Repository, o as AggregationBuilder, r as batchTransaction, s as ALL_OPERATIONS, t as HOOK_PRIORITY, u as READ_OPERATIONS } from "./Repository-BY40uhcv.mjs";
5
+ import { a as withTransaction, c as MUTATING_OPERATIONS, d as operationsByPolicyKey, i as isTransactionUnsupported, l as OP_REGISTRY, n as Repository, o as AggregationBuilder, r as batchTransaction, s as ALL_OPERATIONS, t as HOOK_PRIORITY, u as READ_OPERATIONS } from "./Repository-d5gWSROf.mjs";
6
6
  import { t as PaginationEngine } from "./PaginationEngine-CfQRM1yz.mjs";
7
- import { A as aggregateHelpersPlugin, C as sequentialId, D as AuditTrailQuery, E as batchOperationsPlugin, O as auditTrailPlugin, S as prefixedId, T as cachePlugin, _ as fieldFilterPlugin, a as uniqueField, b as dateSequentialId, c as createTenantContext, d as observabilityPlugin, f as adminBypass, g as leasePlugin, h as methodRegistryPlugin, i as requireField, k as auditLogPlugin, l as subdocumentPlugin, m as mongoOperationsPlugin, n as blockIf, o as validationChainPlugin, p as multiTenantPlugin, r as immutableField, s as timestampPlugin, t as autoInject, u as softDeletePlugin, v as elasticSearchPlugin, w as cascadePlugin, x as getNextSequence, y as customIdPlugin } from "./validation-chain.plugin-_-WuNml2.mjs";
7
+ import { A as aggregateHelpersPlugin, C as sequentialId, D as AuditTrailQuery, E as batchOperationsPlugin, O as auditTrailPlugin, S as prefixedId, T as cachePlugin, _ as fieldFilterPlugin, a as uniqueField, b as dateSequentialId, c as createTenantContext, d as observabilityPlugin, f as adminBypass, g as leasePlugin, h as methodRegistryPlugin, i as requireField, k as auditLogPlugin, l as subdocumentPlugin, m as mongoOperationsPlugin, n as blockIf, o as validationChainPlugin, p as multiTenantPlugin, r as immutableField, s as timestampPlugin, t as autoInject, u as softDeletePlugin, v as elasticSearchPlugin, w as cascadePlugin, x as getNextSequence, y as customIdPlugin } from "./validation-chain.plugin-BLVp_Pw2.mjs";
8
8
  import { i as getMongooseProjection, n as filterResponseData, r as getFieldsForUser, t as createFieldPreset } from "./field-selection-Br3WPOEb.mjs";
9
9
  import { isGeoOperator, parseGeoFilter } from "./query/primitives/geo.mjs";
10
10
  import { buildFieldTypeMap, coerceFieldValue, coerceHeuristic } from "./query/primitives/coercion.mjs";
@@ -1224,4 +1224,4 @@ function createRepository(Model, plugins = [], paginationConfig = {}, options =
1224
1224
  }
1225
1225
  var src_default = Repository;
1226
1226
  //#endregion
1227
- export { ALL_OPERATIONS, AggregationBuilder, AuditTrailQuery, HOOK_PRIORITY, LookupBuilder, MUTATING_OPERATIONS, OP_REGISTRY, PaginationEngine, QueryParser, READ_OPERATIONS, Repository, actions_exports as actions, adminBypass, aggregateHelpersPlugin, auditLogPlugin, auditTrailPlugin, autoInject, batchOperationsPlugin, batchTransaction, blockIf, buildCrudSchemasFromModel, buildCrudSchemasFromMongooseSchema, cachePlugin, cascadePlugin, configureLogger, createError, createFieldPreset, createMemoryCache, createOptionsExtractor, createRepository, createTenantContext, customIdPlugin, dateSequentialId, src_default as default, elasticSearchPlugin, fieldFilterPlugin, filterResponseData, getFieldsForUser, getMongooseProjection, getNextSequence, immutableField, isDuplicateKeyError, isTransactionUnsupported, leasePlugin, methodRegistryPlugin, mongoOperationsPlugin, multiTenantPlugin, observabilityPlugin, operationsByPolicyKey, parseDuplicateKeyError, prefixedId, repoOptionsFromCtx, requireField, sequentialId, softDeletePlugin, subdocumentPlugin, timestampPlugin, uniqueField, validationChainPlugin, withTransaction };
1227
+ export { ALL_OPERATIONS, AggregationBuilder, AuditTrailQuery, HOOK_PRIORITY, LookupBuilder, MUTATING_OPERATIONS, OP_REGISTRY, PaginationEngine, QueryParser, READ_OPERATIONS, Repository, actions_exports as actions, adminBypass, aggregateHelpersPlugin, auditLogPlugin, auditTrailPlugin, autoInject, batchOperationsPlugin, batchTransaction, blockIf, buildCrudSchemasFromModel, buildCrudSchemasFromMongooseSchema, cachePlugin, cascadePlugin, compileFilterToMongo, configureLogger, createError, createFieldPreset, createMemoryCache, createOptionsExtractor, createRepository, createTenantContext, customIdPlugin, dateSequentialId, src_default as default, elasticSearchPlugin, fieldFilterPlugin, filterResponseData, getFieldsForUser, getMongooseProjection, getNextSequence, immutableField, isDuplicateKeyError, isTransactionUnsupported, leasePlugin, methodRegistryPlugin, mongoOperationsPlugin, multiTenantPlugin, observabilityPlugin, operationsByPolicyKey, parseDuplicateKeyError, prefixedId, repoOptionsFromCtx, requireField, sequentialId, softDeletePlugin, subdocumentPlugin, timestampPlugin, uniqueField, validationChainPlugin, withTransaction };
@@ -1,2 +1,2 @@
1
- import { A as aggregateHelpersPlugin, C as sequentialId, D as AuditTrailQuery, E as batchOperationsPlugin, O as auditTrailPlugin, S as prefixedId, T as cachePlugin, _ as fieldFilterPlugin, a as uniqueField, b as dateSequentialId, c as createTenantContext, d as observabilityPlugin, g as leasePlugin, h as methodRegistryPlugin, i as requireField, k as auditLogPlugin, l as subdocumentPlugin, m as mongoOperationsPlugin, n as blockIf, o as validationChainPlugin, p as multiTenantPlugin, r as immutableField, s as timestampPlugin, t as autoInject, u as softDeletePlugin, v as elasticSearchPlugin, w as cascadePlugin, x as getNextSequence, y as customIdPlugin } from "../validation-chain.plugin-_-WuNml2.mjs";
1
+ import { A as aggregateHelpersPlugin, C as sequentialId, D as AuditTrailQuery, E as batchOperationsPlugin, O as auditTrailPlugin, S as prefixedId, T as cachePlugin, _ as fieldFilterPlugin, a as uniqueField, b as dateSequentialId, c as createTenantContext, d as observabilityPlugin, g as leasePlugin, h as methodRegistryPlugin, i as requireField, k as auditLogPlugin, l as subdocumentPlugin, m as mongoOperationsPlugin, n as blockIf, o as validationChainPlugin, p as multiTenantPlugin, r as immutableField, s as timestampPlugin, t as autoInject, u as softDeletePlugin, v as elasticSearchPlugin, w as cascadePlugin, x as getNextSequence, y as customIdPlugin } from "../validation-chain.plugin-BLVp_Pw2.mjs";
2
2
  export { AuditTrailQuery, aggregateHelpersPlugin, auditLogPlugin, auditTrailPlugin, autoInject, batchOperationsPlugin, blockIf, cachePlugin, cascadePlugin, createTenantContext, customIdPlugin, dateSequentialId, elasticSearchPlugin, fieldFilterPlugin, getNextSequence, immutableField, leasePlugin, methodRegistryPlugin, mongoOperationsPlugin, multiTenantPlugin, observabilityPlugin, prefixedId, requireField, sequentialId, softDeletePlugin, subdocumentPlugin, timestampPlugin, uniqueField, validationChainPlugin };
@@ -13,9 +13,79 @@ import { isFilter } from "@classytic/repo-core/filter";
13
13
  * appropriately. This keeps the portable API ergonomic for apps that
14
14
  * write Mongo queries directly today.
15
15
  */
16
+ /**
17
+ * Operator shorthands arc propagates from bracket-syntax URL params.
18
+ * Fastify parses `?createdAt[gte]=...&createdAt[lte]=...` into
19
+ * `{ createdAt: { gte: '...', lte: '...' } }` — without `$` prefixes.
20
+ * Arc intentionally forwards these as-is ("the kit's filter compiler
21
+ * handles them"). This set covers every operator the arc aggregation
22
+ * guard accepts in `parseDateRange` and `hasFilterOnField`.
23
+ */
24
+ const SHORTHAND_OPS = new Set([
25
+ "eq",
26
+ "ne",
27
+ "gt",
28
+ "gte",
29
+ "lt",
30
+ "lte",
31
+ "in",
32
+ "nin",
33
+ "exists",
34
+ "regex",
35
+ "mod"
36
+ ]);
37
+ /** Range operators whose string values should be coerced to Date. */
38
+ const RANGE_OPS = new Set([
39
+ "gt",
40
+ "gte",
41
+ "lt",
42
+ "lte"
43
+ ]);
44
+ /** ISO-8601 date-only or datetime string pattern. */
45
+ const ISO_DATE_RE = /^\d{4}-\d{2}-\d{2}/;
46
+ /**
47
+ * Coerce a string value to a Date when it looks like an ISO-8601 date.
48
+ * Needed because MongoDB won't match a BSON Date field against a string
49
+ * value even when using range operators — BSON type comparison treats
50
+ * Date (type 9) and String (type 2) as distinct, so `{ createdAt: {
51
+ * $gte: "2026-05-01" } }` never matches a Date-typed field.
52
+ */
53
+ function tryCoerceDate(value) {
54
+ if (typeof value === "string" && ISO_DATE_RE.test(value)) {
55
+ const d = new Date(value);
56
+ return Number.isNaN(d.getTime()) ? value : d;
57
+ }
58
+ return value;
59
+ }
60
+ /**
61
+ * Expand operator shorthand values in a plain Mongo-style query object.
62
+ * Only expands nested objects whose keys are ALL in `SHORTHAND_OPS` — so
63
+ * real nested documents (e.g. `address: { city: 'Dhaka' }`) pass through
64
+ * unchanged, while `createdAt: { gte: '2026-04-01', lte: '2026-05-01' }`
65
+ * becomes `createdAt: { $gte: Date(2026-04-01), $lte: Date(2026-05-01) }`.
66
+ * String values on range operators are coerced to Date when they match the
67
+ * ISO-8601 pattern, so BSON Date fields in MongoDB are compared correctly.
68
+ */
69
+ function expandShorthands(obj) {
70
+ const out = {};
71
+ for (const [key, value] of Object.entries(obj)) {
72
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
73
+ const nested = value;
74
+ const keys = Object.keys(nested);
75
+ if (keys.length > 0 && keys.every((k) => !k.startsWith("$") && SHORTHAND_OPS.has(k))) {
76
+ const expanded = {};
77
+ for (const [op, opVal] of Object.entries(nested)) expanded[`$${op}`] = RANGE_OPS.has(op) ? tryCoerceDate(opVal) : opVal;
78
+ out[key] = expanded;
79
+ continue;
80
+ }
81
+ }
82
+ out[key] = value;
83
+ }
84
+ return out;
85
+ }
16
86
  function compileFilterToMongo(input) {
17
87
  if (!input) return {};
18
- if (!isFilter(input)) return input;
88
+ if (!isFilter(input)) return expandShorthands(input);
19
89
  return compile(input);
20
90
  }
21
91
  function compile(filter) {
@@ -1,7 +1,7 @@
1
- import { _ as upsert } from "./update-DLcSSa5b.mjs";
1
+ import { _ as upsert } from "./update-C-3viiw1.mjs";
2
2
  import { n as warn } from "./logger-DprijP5h.mjs";
3
3
  import { t as createError } from "./error-B00pI7dV.mjs";
4
- import { l as OP_REGISTRY, s as ALL_OPERATIONS, t as HOOK_PRIORITY } from "./Repository-BY40uhcv.mjs";
4
+ import { l as OP_REGISTRY, s as ALL_OPERATIONS, t as HOOK_PRIORITY } from "./Repository-d5gWSROf.mjs";
5
5
  import { r as getFieldsForUser } from "./field-selection-Br3WPOEb.mjs";
6
6
  import mongoose from "mongoose";
7
7
  import { cachePlugin } from "@classytic/repo-core/cache";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@classytic/mongokit",
3
- "version": "3.13.0",
3
+ "version": "3.13.1",
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,