@classytic/mongokit 3.11.0 → 3.12.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.
@@ -1,12 +1,12 @@
1
- import { n as debug, r as warn } from "./logger-DJ7egMnd.mjs";
2
- import { _ as upsert, 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, y as distinct } from "./update-CWXfFC6O.mjs";
3
- import { n as isDuplicateKeyError, r as parseDuplicateKeyError, t as createError } from "./error-CzYwrfUP.mjs";
4
- import { t as PaginationEngine } from "./PaginationEngine-B93fLCcO.mjs";
1
+ import { _ as upsert, 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-CDxPtpsk.mjs";
2
+ import { n as debug, r as warn } from "./logger-8-VS1za6.mjs";
3
+ import { n as isDuplicateKeyError, r as parseDuplicateKeyError, t as createError } from "./error-B00pI7dV.mjs";
4
+ import { t as PaginationEngine } from "./PaginationEngine-BDaAsyPn.mjs";
5
5
  import { hasNearOperator, rewriteNearForCount } from "./query/primitives/geo.mjs";
6
6
  import { r as isValidIdForType, t as getSchemaIdType } from "./id-resolution-e4BT9zAV.mjs";
7
7
  import { a as byIdKey, c as listQueryKey, l as modelPattern, o as byQueryKey, r as getFieldsForUser, u as versionKey } from "./field-selection-dI0m4RBs.mjs";
8
- import mongoose from "mongoose";
9
8
  import { isFilter } from "@classytic/repo-core/filter";
9
+ import mongoose from "mongoose";
10
10
  import { HOOK_PRIORITY } from "@classytic/repo-core/hooks";
11
11
  import { RepositoryBase, validatePluginOrder } from "@classytic/repo-core/repository";
12
12
  import { compileUpdateSpecToMongo, isUpdateSpec } from "@classytic/repo-core/update";
@@ -728,102 +728,6 @@ function batchOperationsPlugin() {
728
728
  };
729
729
  }
730
730
  //#endregion
731
- //#region src/filter/compile.ts
732
- /**
733
- * Compile a Filter IR node to a MongoDB query object. Returns `{}`
734
- * when the node is `TRUE` (or an empty `and`) so callers can merge
735
- * with other scopes without special-casing.
736
- *
737
- * The `input` is typed as `unknown` so callers can pass either a
738
- * Filter IR node or an already-built Mongo query and we dispatch
739
- * appropriately. This keeps the portable API ergonomic for apps that
740
- * write Mongo queries directly today.
741
- */
742
- function compileFilterToMongo(input) {
743
- if (!input) return {};
744
- if (!isFilter(input)) return input;
745
- return compile(input);
746
- }
747
- function compile(filter) {
748
- switch (filter.op) {
749
- case "true": return {};
750
- case "false": return { $expr: false };
751
- case "eq": return { [filter.field]: filter.value };
752
- case "ne": return filter.value === null ? { [filter.field]: { $ne: null } } : { $and: [{ [filter.field]: { $ne: filter.value } }, { [filter.field]: { $ne: null } }] };
753
- case "gt": return { [filter.field]: { $gt: filter.value } };
754
- case "gte": return { [filter.field]: { $gte: filter.value } };
755
- case "lt": return { [filter.field]: { $lt: filter.value } };
756
- case "lte": return { [filter.field]: { $lte: filter.value } };
757
- case "in":
758
- if (filter.values.length === 0) return { $expr: false };
759
- return { [filter.field]: { $in: [...filter.values] } };
760
- case "nin":
761
- if (filter.values.length === 0) return {};
762
- return { [filter.field]: { $nin: [...filter.values] } };
763
- case "exists": return filter.exists ? { [filter.field]: { $ne: null } } : { [filter.field]: null };
764
- case "like": return { [filter.field]: likeToRegex(filter.pattern, filter.caseSensitivity) };
765
- case "regex": return { [filter.field]: { $regex: filter.pattern } };
766
- case "and": {
767
- if (filter.children.length === 0) return {};
768
- const parts = filter.children.map(compile);
769
- if (parts.length === 1) return parts[0];
770
- return { $and: parts };
771
- }
772
- case "or": {
773
- if (filter.children.length === 0) return { $expr: false };
774
- const parts = filter.children.map(compile);
775
- if (parts.length === 1) return parts[0];
776
- return { $or: parts };
777
- }
778
- case "not": return { $nor: [compile(filter.child)] };
779
- case "raw": throw new Error("mongokit/filter: `raw` is a SQL escape hatch and has no safe MongoDB translation. Pass a Mongo query object directly to the filter slot instead.");
780
- }
781
- }
782
- /**
783
- * Translate a SQL-style LIKE pattern to a MongoDB regex.
784
- *
785
- * SQL semantics:
786
- * - `%` → match zero or more characters (`.*`)
787
- * - `_` → match exactly one character (`.`)
788
- * - `\%` → literal percent (escape via backslash)
789
- * - `\_` → literal underscore
790
- * - `\\` → literal backslash
791
- * - everything else is literal — regex metacharacters get escaped.
792
- *
793
- * The naive implementation `pattern.replace(/%/g, '.*')` is wrong:
794
- * it also expands escaped `\%` into a wildcard. We walk the pattern
795
- * char-by-char, honoring backslash escapes, so `like('notes', '50\\% off')`
796
- * matches the literal string `50% off` instead of `50<anything> off`.
797
- *
798
- * Anchored with `^` / `$` so LIKE matches the whole field value, the
799
- * same way sqlitekit's `LIKE` semantically does.
800
- */
801
- function likeToRegex(pattern, caseSensitivity) {
802
- let out = "^";
803
- for (let i = 0; i < pattern.length; i++) {
804
- const ch = pattern[i];
805
- if (ch === "\\" && i + 1 < pattern.length) {
806
- const next = pattern[i + 1];
807
- if (next === "%" || next === "_" || next === "\\") {
808
- out += escapeRegexChar(next);
809
- i++;
810
- continue;
811
- }
812
- }
813
- if (ch === "%") out += ".*";
814
- else if (ch === "_") out += ".";
815
- else out += escapeRegexChar(ch);
816
- }
817
- out += "$";
818
- return caseSensitivity === "sensitive" ? { $regex: out } : {
819
- $regex: out,
820
- $options: "i"
821
- };
822
- }
823
- function escapeRegexChar(ch) {
824
- return /[.*+?^${}()|[\]\\]/.test(ch) ? `\\${ch}` : ch;
825
- }
826
- //#endregion
827
731
  //#region src/actions/aggregate-ir/normalize.ts
828
732
  /**
829
733
  * Normalize `AggRequest['groupBy']` into a readonly string array.
@@ -1626,32 +1530,6 @@ function createTxBoundRepo(outer, session) {
1626
1530
  }
1627
1531
  //#endregion
1628
1532
  //#region src/Repository.ts
1629
- /**
1630
- * Repository Pattern - Data Access Layer
1631
- *
1632
- * Event-driven, plugin-based abstraction for MongoDB operations
1633
- * Inspired by Meta & Stripe's repository patterns
1634
- *
1635
- * @example
1636
- * ```typescript
1637
- * const userRepo = new Repository(UserModel, [
1638
- * timestampPlugin(),
1639
- * softDeletePlugin(),
1640
- * ]);
1641
- *
1642
- * // Create
1643
- * const user = await userRepo.create({ name: 'John', email: 'john@example.com' });
1644
- *
1645
- * // Read with pagination
1646
- * const users = await userRepo.getAll({ page: 1, limit: 20, filters: { status: 'active' } });
1647
- *
1648
- * // Update
1649
- * const updated = await userRepo.update(user._id, { name: 'John Doe' });
1650
- *
1651
- * // Delete
1652
- * await userRepo.delete(user._id);
1653
- * ```
1654
- */
1655
1533
  function ensureLookupProjectionIncludesCursorFields(projection, sort) {
1656
1534
  if (!projection || !sort) return projection;
1657
1535
  if (!Object.values(projection).some((value) => value === 1)) return projection;
@@ -2300,7 +2178,7 @@ var Repository = class extends RepositoryBase {
2300
2178
  if (context.softDeleted) {
2301
2179
  const result = {
2302
2180
  acknowledged: true,
2303
- deletedCount: 0,
2181
+ deletedCount: context.softDeletedCount ?? 0,
2304
2182
  soft: true
2305
2183
  };
2306
2184
  await this._emitHook("after:deleteMany", {
@@ -2488,19 +2366,31 @@ var Repository = class extends RepositoryBase {
2488
2366
  * Merge policy-hook-injected filters (multi-tenant scope,
2489
2367
  * soft-delete) into the pre-aggregate `filter` slot of the request.
2490
2368
  * Plugins speak mongo-query shape (`context.query` / `context.filters`);
2491
- * we merge those with the portable `req.filter` using `$and`.
2369
+ * the caller's `req.filter` may be either Filter IR or a mongo query.
2492
2370
  *
2493
- * When the caller's filter is a Filter IR node we don't unwrap it —
2494
- * the pipeline compiler does Filter→mongo translation. Merging here
2495
- * as a mongo-shaped `$and` is safe because `compileFilterToMongo`
2496
- * passes through already-mongo queries unchanged.
2371
+ * Each part is compiled through `compileFilterToMongo` BEFORE the
2372
+ * `$and` merge — otherwise an IR node like `eq('status', 'paid')`
2373
+ * (`{ op, field, value }`) gets nested inside `$and` as a literal,
2374
+ * `compileFilterToMongo` of the merged value finds no top-level `op`
2375
+ * (so `isFilter` is false), and Mongo receives the IR object as a
2376
+ * raw query clause that matches no real document. Symptom: aggregates
2377
+ * silently return 0 rows whenever a callerpasses IR + a policy
2378
+ * plugin is installed.
2497
2379
  */
2498
2380
  _injectPolicyScopeIntoAgg(req, context) {
2499
2381
  const scopeCandidates = [];
2500
2382
  for (const candidate of [context.filters, context.query]) if (candidate && typeof candidate === "object" && Object.keys(candidate).length > 0) scopeCandidates.push(candidate);
2501
2383
  if (scopeCandidates.length === 0) return req;
2502
- const parts = [...scopeCandidates];
2503
- if (req.filter) parts.push(req.filter);
2384
+ const parts = [];
2385
+ for (const c of scopeCandidates) {
2386
+ const compiled = compileFilterToMongo(c);
2387
+ if (Object.keys(compiled).length > 0) parts.push(compiled);
2388
+ }
2389
+ if (req.filter) {
2390
+ const compiled = compileFilterToMongo(req.filter);
2391
+ if (Object.keys(compiled).length > 0) parts.push(compiled);
2392
+ }
2393
+ if (parts.length === 0) return req;
2504
2394
  const merged = parts.length === 1 ? parts[0] : { $and: parts };
2505
2395
  return {
2506
2396
  ...req,
@@ -2892,7 +2782,22 @@ var Repository = class extends RepositoryBase {
2892
2782
  ];
2893
2783
  } else query.$or = orConds;
2894
2784
  } else if (this._hasTextIndex) query.$text = { $search: search };
2895
- else throw createError(400, `No text index found for ${this.model}. Cannot perform text search. Configure Repository with searchMode: 'regex' (and searchFields) or 'auto' to enable index-free search.`);
2785
+ else {
2786
+ const modelName = String(this.model);
2787
+ throw createError(400, `No text index found for ${modelName}. Cannot perform text search. Configure ${modelName}'s Repository with { searchMode: 'regex', searchFields: [...] } to enable index-free search, or create a text index on the collection for searchMode: 'text'. See https://github.com/classytic/mongokit/blob/main/docs/README.md#queryparser-url--filter`, {
2788
+ code: "SEARCH_NOT_CONFIGURED",
2789
+ meta: {
2790
+ model: modelName,
2791
+ configuredMode: this.searchMode,
2792
+ availableModes: [
2793
+ "text",
2794
+ "regex",
2795
+ "auto"
2796
+ ],
2797
+ docs: "https://github.com/classytic/mongokit/blob/main/docs/README.md#queryparser-url--filter"
2798
+ }
2799
+ });
2800
+ }
2896
2801
  return query;
2897
2802
  }
2898
2803
  /**
@@ -4315,49 +4220,6 @@ function mongoOperationsPlugin() {
4315
4220
  //#endregion
4316
4221
  //#region src/plugins/multi-tenant.plugin.ts
4317
4222
  /**
4318
- * Multi-Tenant Plugin
4319
- *
4320
- * Automatically injects tenant isolation filters into all queries.
4321
- * Ensures data isolation by adding organizationId (or custom tenant field)
4322
- * to every read and write operation.
4323
- *
4324
- * Uses HOOK_PRIORITY.POLICY (100) to ensure tenant filters are injected
4325
- * BEFORE cache keys are computed (HOOK_PRIORITY.CACHE = 200).
4326
- *
4327
- * @example
4328
- * ```typescript
4329
- * // Basic — scopes every operation by organizationId from context
4330
- * const repo = new Repository(Invoice, [
4331
- * multiTenantPlugin({ tenantField: 'organizationId' }),
4332
- * ]);
4333
- *
4334
- * const invoices = await repo.getAll(
4335
- * { filters: { status: 'paid' } },
4336
- * { organizationId: 'org_123' }
4337
- * );
4338
- * // Actual query: { status: 'paid', organizationId: 'org_123' }
4339
- *
4340
- * // Super admin bypass — skip scoping based on context
4341
- * const repo = new Repository(Invoice, [
4342
- * multiTenantPlugin({
4343
- * tenantField: 'organizationId',
4344
- * skipWhen: (context) => context.role === 'superadmin',
4345
- * }),
4346
- * ]);
4347
- *
4348
- * // Admin sees all orgs
4349
- * await repo.getAll({ page: 1, limit: 10 }, { role: 'superadmin' });
4350
- *
4351
- * // Automatic context — resolve tenant from AsyncLocalStorage
4352
- * const repo = new Repository(Invoice, [
4353
- * multiTenantPlugin({
4354
- * tenantField: 'organizationId',
4355
- * resolveContext: () => asyncLocalStorage.getStore()?.tenantId,
4356
- * }),
4357
- * ]);
4358
- * ```
4359
- */
4360
- /**
4361
4223
  * True when the op's policy target already has `tenantField` set by the
4362
4224
  * caller. Used to decide whether the plugin can safely skip injecting a
4363
4225
  * tenant scope rather than throwing on a missing context.
@@ -4704,8 +4566,9 @@ function softDeletePlugin(options = {}) {
4704
4566
  ...context.query || {},
4705
4567
  ...deleteFilter
4706
4568
  };
4707
- await repo.Model.updateMany(finalQuery, { $set: { [deletedField]: /* @__PURE__ */ new Date() } }, { session: context.session });
4569
+ const updateRes = await repo.Model.updateMany(finalQuery, { $set: { [deletedField]: /* @__PURE__ */ new Date() } }, { session: context.session });
4708
4570
  context.softDeleted = true;
4571
+ context.softDeletedCount = updateRes?.modifiedCount ?? 0;
4709
4572
  }
4710
4573
  }, { priority: HOOK_PRIORITY$1.POLICY });
4711
4574
  if (addRestoreMethod) {
@@ -1,7 +1,9 @@
1
- import { B as ObjectId, F as Logger, H as OffsetPaginationResult, T as FieldPreset, X as PopulateSpec, bt as ValidationChainOptions, et as RepositoryContext, f as CascadeOptions, ft as SortSpec, l as CacheOptions, lt as SoftDeleteOptions, nt as RepositoryInstance, ot as SelectSpec, q as Plugin, u as CacheStats, xt as ValidatorDefinition } from "./types-xOyTec4n.mjs";
1
+ import { $ as RepositoryInstance, E as FieldPreset, P as Logger, W as Plugin, Z as RepositoryContext, _t as ValidationChainOptions, f as CascadeOptions, l as CacheOptions, lt as SortSpec, ot as SoftDeleteOptions, q as PopulateSpec, rt as SelectSpec, u as CacheStats, vt as ValidatorDefinition, z as ObjectId } from "./types-DXscZnLu.mjs";
2
2
  import mongoose from "mongoose";
3
3
  import { BulkWriteResult } from "@classytic/repo-core/repository";
4
4
  import { AsyncLocalStorage } from "node:async_hooks";
5
+ import { OffsetPaginationResult } from "@classytic/repo-core/pagination";
6
+ import { TenantConfig } from "@classytic/repo-core/tenant";
5
7
 
6
8
  //#region src/plugins/aggregate-helpers.plugin.d.ts
7
9
  /**
@@ -753,13 +755,20 @@ interface MongoOperationsMethods<TDoc> {
753
755
  }
754
756
  //#endregion
755
757
  //#region src/plugins/multi-tenant.plugin.d.ts
756
- interface MultiTenantOptions {
757
- /** Field name used for tenant isolation (default: 'organizationId') */
758
- tenantField?: string;
759
- /** Context key to read tenant ID from (default: 'organizationId') */
760
- contextKey?: string;
761
- /** Throw if tenant ID is missing from context (default: true) */
762
- required?: boolean;
758
+ /**
759
+ * Static tenant fields are picked from `@classytic/repo-core/tenant` so the
760
+ * vocabulary (`tenantField`, `contextKey`, `required`, `fieldType`) stays
761
+ * locked to the org-wide canonical source. Mongokit-specific runtime
762
+ * callbacks (`skipWhen`, `resolveContext`, `skipOperations`,
763
+ * `allowDataInjection`) extend on top — those genuinely differ from
764
+ * sqlitekit's runtime shape because mongokit's `RepositoryContext` carries
765
+ * Mongoose-specific bits the resolver may inspect.
766
+ *
767
+ * Mongokit defaults `fieldType` to `'string'` (not repo-core's `'objectId'`)
768
+ * for back-compat — pre-3.x stored tenant ids as raw strings; flipping the
769
+ * default would silently change cast behavior for existing apps.
770
+ */
771
+ interface MultiTenantOptions extends Pick<TenantConfig, 'tenantField' | 'contextKey' | 'required' | 'fieldType'> {
763
772
  /** Operations to skip tenant injection (e.g., for admin/system queries) */
764
773
  skipOperations?: string[];
765
774
  /**
@@ -784,17 +793,6 @@ interface MultiTenantOptions {
784
793
  * ```
785
794
  */
786
795
  resolveContext?: () => string | undefined;
787
- /**
788
- * How to store/query the tenant ID.
789
- *
790
- * - `'string'` (default): inject the tenant ID as-is (raw string).
791
- * - `'objectId'`: cast to `mongoose.Types.ObjectId` before injecting.
792
- *
793
- * Choose `'objectId'` when the schema declares the tenant field as
794
- * `Schema.Types.ObjectId` (e.g., Flow, accounting). This enables
795
- * `$lookup` and `.populate()` against the referenced collection.
796
- */
797
- fieldType?: 'string' | 'objectId';
798
796
  /**
799
797
  * When `true` (default), bypass the `required` throw if the operation's
800
798
  * policy target already carries the tenant field. This lets hosts that
package/package.json CHANGED
@@ -1,143 +1,146 @@
1
- {
2
- "name": "@classytic/mongokit",
3
- "version": "3.11.0",
4
- "description": "Production-grade MongoDB repositories - smart pagination, events, and plugins. Built on @classytic/repo-core.",
5
- "type": "module",
6
- "sideEffects": false,
7
- "main": "./dist/index.mjs",
8
- "module": "./dist/index.mjs",
9
- "types": "./dist/index.d.mts",
10
- "exports": {
11
- ".": {
12
- "types": "./dist/index.d.mts",
13
- "default": "./dist/index.mjs"
14
- },
15
- "./pagination": {
16
- "types": "./dist/pagination/PaginationEngine.d.mts",
17
- "default": "./dist/pagination/PaginationEngine.mjs"
18
- },
19
- "./plugins": {
20
- "types": "./dist/plugins/index.d.mts",
21
- "default": "./dist/plugins/index.mjs"
22
- },
23
- "./utils": {
24
- "types": "./dist/utils/index.d.mts",
25
- "default": "./dist/utils/index.mjs"
26
- },
27
- "./actions": {
28
- "types": "./dist/actions/index.d.mts",
29
- "default": "./dist/actions/index.mjs"
30
- },
31
- "./ai": {
32
- "types": "./dist/ai/index.d.mts",
33
- "default": "./dist/ai/index.mjs"
34
- },
35
- "./query/primitives/geo": {
36
- "types": "./dist/query/primitives/geo.d.mts",
37
- "default": "./dist/query/primitives/geo.mjs"
38
- },
39
- "./query/primitives/coercion": {
40
- "types": "./dist/query/primitives/coercion.d.mts",
41
- "default": "./dist/query/primitives/coercion.mjs"
42
- },
43
- "./query/primitives/indexes": {
44
- "types": "./dist/query/primitives/indexes.d.mts",
45
- "default": "./dist/query/primitives/indexes.mjs"
46
- }
47
- },
48
- "files": [
49
- "dist",
50
- "README.md",
51
- "LICENSE"
52
- ],
53
- "keywords": [
54
- "mongodb",
55
- "mongoose",
56
- "repository",
57
- "repository-pattern",
58
- "data-access",
59
- "pagination",
60
- "cursor-pagination",
61
- "infinite-scroll",
62
- "offset-pagination",
63
- "keyset-pagination",
64
- "caching",
65
- "redis",
66
- "cache",
67
- "multi-tenant",
68
- "multi-tenancy",
69
- "vector-search",
70
- "embeddings",
71
- "atlas-search",
72
- "observability",
73
- "event-driven",
74
- "plugin-based",
75
- "zero-dependencies",
76
- "express",
77
- "fastify",
78
- "nestjs",
79
- "nextjs",
80
- "typescript"
81
- ],
82
- "author": "Classytic <classytic.dev@gmail.com> (https://github.com/classytic)",
83
- "contributors": [
84
- "Sadman Chowdhury (https://github.com/siam923)"
85
- ],
86
- "license": "MIT",
87
- "repository": {
88
- "type": "git",
89
- "url": "git+https://github.com/classytic/mongokit.git"
90
- },
91
- "bugs": {
92
- "url": "https://github.com/classytic/mongokit/issues"
93
- },
94
- "homepage": "https://github.com/classytic/mongokit#readme",
95
- "peerDependencies": {
96
- "mongoose": ">=9.4.1",
97
- "@classytic/repo-core": ">=0.2.0"
98
- },
99
- "engines": {
100
- "node": ">=22"
101
- },
102
- "scripts": {
103
- "build": "tsdown",
104
- "dev": "tsdown --watch",
105
- "test": "vitest run --project unit --project integration",
106
- "test:unit": "vitest run --project unit",
107
- "test:integration": "vitest run --project integration",
108
- "test:e2e": "vitest run --project e2e",
109
- "test:all": "vitest run --project unit --project integration --project e2e",
110
- "test:watch": "vitest --project unit --project integration",
111
- "test:coverage": "vitest run --coverage",
112
- "typecheck": "tsc --noEmit",
113
- "typecheck:tests": "tsc --noEmit -p tsconfig.tests.json",
114
- "lint": "biome check src/",
115
- "lint:fix": "biome check src/ --write",
116
- "format": "biome format src/ --write",
117
- "check": "biome ci src/ --diagnostic-level=error",
118
- "prepublishOnly": "npm run check && npm run build && npm run typecheck && npm run typecheck:tests && npm test",
119
- "publish:dry": "npm publish --dry-run --access public",
120
- "publish:npm": "npm publish --access public",
121
- "release": "npm run check && npm run build && npm run typecheck && npm run typecheck:tests && npm test && npm publish --access public",
122
- "release:patch": "npm version patch && npm run release",
123
- "release:minor": "npm version minor && npm run release",
124
- "release:major": "npm version major && npm run release"
125
- },
126
- "devDependencies": {
127
- "@arethetypeswrong/cli": "^0.18.2",
128
- "@biomejs/biome": "^2.4.10",
129
- "@classytic/repo-core": ">=0.1.0",
130
- "@types/node": "^22.0.0",
131
- "@vitest/coverage-v8": "^3.2.4",
132
- "ajv": "^8.18.0",
133
- "ajv-formats": "^3.0.1",
134
- "dotenv": "^17.4.2",
135
- "knip": "^6.3.0",
136
- "mongodb-memory-server": "^10.4.3",
137
- "mongoose": "^9.4.1",
138
- "publint": "^0.3.18",
139
- "tsdown": "^0.21.8",
140
- "typescript": "^5.7.0",
141
- "vitest": "^3.2.4"
142
- }
143
- }
1
+ {
2
+ "name": "@classytic/mongokit",
3
+ "version": "3.12.0",
4
+ "description": "Production-grade MongoDB repositories - smart pagination, events, and plugins. Built on @classytic/repo-core.",
5
+ "type": "module",
6
+ "sideEffects": false,
7
+ "main": "./dist/index.mjs",
8
+ "module": "./dist/index.mjs",
9
+ "types": "./dist/index.d.mts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.mts",
13
+ "default": "./dist/index.mjs"
14
+ },
15
+ "./pagination": {
16
+ "types": "./dist/pagination/PaginationEngine.d.mts",
17
+ "default": "./dist/pagination/PaginationEngine.mjs"
18
+ },
19
+ "./plugins": {
20
+ "types": "./dist/plugins/index.d.mts",
21
+ "default": "./dist/plugins/index.mjs"
22
+ },
23
+ "./utils": {
24
+ "types": "./dist/utils/index.d.mts",
25
+ "default": "./dist/utils/index.mjs"
26
+ },
27
+ "./actions": {
28
+ "types": "./dist/actions/index.d.mts",
29
+ "default": "./dist/actions/index.mjs"
30
+ },
31
+ "./ai": {
32
+ "types": "./dist/ai/index.d.mts",
33
+ "default": "./dist/ai/index.mjs"
34
+ },
35
+ "./query/primitives/geo": {
36
+ "types": "./dist/query/primitives/geo.d.mts",
37
+ "default": "./dist/query/primitives/geo.mjs"
38
+ },
39
+ "./query/primitives/coercion": {
40
+ "types": "./dist/query/primitives/coercion.d.mts",
41
+ "default": "./dist/query/primitives/coercion.mjs"
42
+ },
43
+ "./query/primitives/indexes": {
44
+ "types": "./dist/query/primitives/indexes.d.mts",
45
+ "default": "./dist/query/primitives/indexes.mjs"
46
+ }
47
+ },
48
+ "files": [
49
+ "dist",
50
+ "README.md",
51
+ "LICENSE"
52
+ ],
53
+ "keywords": [
54
+ "mongodb",
55
+ "mongoose",
56
+ "repository",
57
+ "repository-pattern",
58
+ "data-access",
59
+ "pagination",
60
+ "cursor-pagination",
61
+ "infinite-scroll",
62
+ "offset-pagination",
63
+ "keyset-pagination",
64
+ "caching",
65
+ "redis",
66
+ "cache",
67
+ "multi-tenant",
68
+ "multi-tenancy",
69
+ "vector-search",
70
+ "embeddings",
71
+ "atlas-search",
72
+ "observability",
73
+ "event-driven",
74
+ "plugin-based",
75
+ "zero-dependencies",
76
+ "express",
77
+ "fastify",
78
+ "nestjs",
79
+ "nextjs",
80
+ "typescript"
81
+ ],
82
+ "author": "Classytic <classytic.dev@gmail.com> (https://github.com/classytic)",
83
+ "contributors": [
84
+ "Sadman Chowdhury (https://github.com/siam923)"
85
+ ],
86
+ "license": "MIT",
87
+ "repository": {
88
+ "type": "git",
89
+ "url": "git+https://github.com/classytic/mongokit.git"
90
+ },
91
+ "bugs": {
92
+ "url": "https://github.com/classytic/mongokit/issues"
93
+ },
94
+ "homepage": "https://github.com/classytic/mongokit#readme",
95
+ "peerDependencies": {
96
+ "@classytic/repo-core": ">=0.3.0",
97
+ "mongoose": ">=9.4.1"
98
+ },
99
+ "engines": {
100
+ "node": ">=22"
101
+ },
102
+ "scripts": {
103
+ "build": "tsdown",
104
+ "dev": "tsdown --watch",
105
+ "test": "vitest run --project unit --project integration",
106
+ "test:unit": "vitest run --project unit",
107
+ "test:integration": "vitest run --project integration",
108
+ "test:e2e": "vitest run --project e2e",
109
+ "test:all": "vitest run --project unit --project integration --project e2e",
110
+ "test:watch": "vitest --project unit --project integration",
111
+ "test:coverage": "vitest run --coverage",
112
+ "typecheck": "tsc --noEmit",
113
+ "typecheck:tests": "tsc --noEmit -p tsconfig.tests.json",
114
+ "lint": "biome check src/",
115
+ "lint:fix": "biome check src/ --write",
116
+ "format": "biome format src/ --write",
117
+ "check": "biome ci src/ --diagnostic-level=error",
118
+ "push": "classytic-push",
119
+ "prepublishOnly": "npm run check && npm run build && npm run typecheck && npm run typecheck:tests && npm test",
120
+ "publish:dry": "npm publish --dry-run --access public",
121
+ "publish:npm": "npm publish --access public",
122
+ "release:tag": "node -e \"require('child_process').execSync('npm run push -- v'+require('./package.json').version,{stdio:'inherit'})\"",
123
+ "release": "npm run push -- main && npm run release:tag && npm publish",
124
+ "release:patch": "npm version patch && npm run release",
125
+ "release:minor": "npm version minor && npm run release",
126
+ "release:major": "npm version major && npm run release"
127
+ },
128
+ "devDependencies": {
129
+ "@arethetypeswrong/cli": "^0.18.2",
130
+ "@biomejs/biome": "^2.4.10",
131
+ "@classytic/dev-tools": "^0.2.0",
132
+ "@classytic/repo-core": "^0.3.0",
133
+ "@types/node": "^22.0.0",
134
+ "@vitest/coverage-v8": "^3.2.4",
135
+ "ajv": "^8.18.0",
136
+ "ajv-formats": "^3.0.1",
137
+ "dotenv": "^17.4.2",
138
+ "knip": "^6.3.0",
139
+ "mongodb-memory-server": "^10.4.3",
140
+ "mongoose": "^9.4.1",
141
+ "publint": "^0.3.18",
142
+ "tsdown": "^0.21.8",
143
+ "typescript": "^5.7.0",
144
+ "vitest": "^3.2.4"
145
+ }
146
+ }