@classytic/mongokit 3.4.3 → 3.4.4

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
@@ -16,8 +16,8 @@
16
16
  - **Distributed cache safety** - List cache versions stored in the adapter (Redis) for multi-pod correctness
17
17
  - **Search governance** - Text index guard (throws `400` if no index), allowlisted sort/filter fields, ReDoS protection
18
18
  - **Vector search** - MongoDB Atlas `$vectorSearch` with auto-embedding and multimodal support
19
- - **TypeScript first** - Full type safety with discriminated unions
20
- - **1090+ passing tests** - Battle-tested and production-ready
19
+ - **TypeScript first** - Full type safety with discriminated unions, typed events, and field autocomplete
20
+ - **1150+ passing tests** - Battle-tested and production-ready
21
21
 
22
22
  ## Installation
23
23
 
@@ -119,20 +119,34 @@ UserSchema.index({ organizationId: 1, createdAt: -1, _id: -1 });
119
119
 
120
120
  ### CRUD Operations
121
121
 
122
- | Method | Description |
123
- | -------------------------------- | ---------------------------------- |
124
- | `create(data, opts)` | Create single document |
125
- | `createMany(data[], opts)` | Create multiple documents |
126
- | `getById(id, opts)` | Find by ID |
127
- | `getByQuery(query, opts)` | Find one by query |
128
- | `getAll(params, opts)` | Paginated list (auto-detects mode) |
129
- | `getOrCreate(query, data, opts)` | Find or create |
130
- | `update(id, data, opts)` | Update document |
131
- | `delete(id, opts)` | Delete document |
132
- | `count(query, opts)` | Count documents |
133
- | `exists(query, opts)` | Check existence |
134
-
135
- > **Note:** All read operations (`getById`, `getByQuery`, `getAll`, `count`, `exists`, `aggregate`, etc.) accept a `readPreference` option in the `opts` parameter (e.g., `readPreference: 'secondaryPreferred'`) to support scaling reads across replica sets.
122
+ | Method | Options Type | Description |
123
+ | -------------------------------- | -------------------- | ---------------------------------- |
124
+ | `create(data, opts)` | `CreateOptions` | Create single document |
125
+ | `createMany(data[], opts)` | `CreateOptions` | Create multiple documents |
126
+ | `getById(id, opts)` | `CacheableOptions` | Find by ID |
127
+ | `getByQuery(query, opts)` | `CacheableOptions` | Find one by query |
128
+ | `getAll(params, opts)` | `CacheableOptions` | Paginated list (auto-detects mode) |
129
+ | `findAll(filters, opts)` | `OperationOptions` | All docs without pagination |
130
+ | `getOrCreate(query, data, opts)` | `SessionOptions` | Find or create |
131
+ | `update(id, data, opts)` | `UpdateOptions` | Update document |
132
+ | `delete(id, opts)` | `SessionOptions` | Delete document |
133
+ | `count(query, opts)` | `ReadOptions` | Count documents |
134
+ | `exists(query, opts)` | `ReadOptions` | Check existence |
135
+ | `aggregate(pipeline, opts)` | `AggregateOptions` | Run aggregation pipeline |
136
+ | `distinct(field, query, opts)` | `ReadOptions` | Get distinct values |
137
+
138
+ All option types inherit from a clean hierarchy — import only what you need:
139
+
140
+ ```
141
+ SessionOptions → { session }
142
+ └─ ReadOptions → + readPreference
143
+ ├─ OperationOptions → + select, populate, populateOptions, lean, throwOnNotFound
144
+ │ ├─ CacheableOptions → + skipCache, cacheTtl
145
+ │ └─ UpdateOptions → + updatePipeline, arrayFilters
146
+ ├─ AggregateOptions → + allowDiskUse, collation, maxTimeMS, maxPipelineStages
147
+ └─ LookupPopulateOptions → + filters, lookups, sort, page, limit, collation
148
+ └─ CreateOptions → + ordered
149
+ ```
136
150
 
137
151
  ### Aggregation
138
152
 
@@ -895,34 +909,46 @@ class UserRepo extends Repository<IUser> {}
895
909
  const repo = new UserRepo(Model, [
896
910
  methodRegistryPlugin(),
897
911
  mongoOperationsPlugin(),
898
- // ... other plugins
912
+ softDeletePlugin(),
899
913
  ]) as WithPlugins<IUser, UserRepo>;
900
914
 
901
- // Full TypeScript autocomplete!
902
- await repo.increment(id, "views", 1);
903
- await repo.restore(id);
915
+ // Full TypeScript autocomplete — field names inferred from IUser!
916
+ await repo.increment(id, "age", 1); // ✅ "age" autocompleted from IUser
917
+ await repo.groupBy("status"); // ✅ "status" autocompleted
918
+ await repo.restore(id); // ✅ Returns Promise<IUser>
919
+ await repo.getDeleted(); // ✅ Returns OffsetPaginationResult<IUser>
904
920
  await repo.invalidateCache(id);
905
921
  ```
906
922
 
923
+ Field params use `DocField<TDoc>` — autocomplete for known fields, still accepts arbitrary strings for nested paths like `'address.city'`.
924
+
907
925
  **Individual plugin types:** `MongoOperationsMethods<T>`, `BatchOperationsMethods`, `AggregateHelpersMethods`, `SubdocumentMethods<T>`, `SoftDeleteMethods<T>`, `CacheMethods`, `AuditTrailMethods`
908
926
 
909
927
  ## Event System
910
928
 
911
- ```javascript
929
+ Event names are typed as `RepositoryEvent` — full autocomplete in TypeScript:
930
+
931
+ ```typescript
932
+ // before:* receives context directly — mutate in-place
912
933
  repo.on("before:create", async (context) => {
913
934
  context.data.processedAt = new Date();
914
935
  });
915
936
 
937
+ // after:* receives { context, result }
916
938
  repo.on("after:create", ({ context, result }) => {
917
939
  console.log("Created:", result);
918
940
  });
919
941
 
942
+ // error:* receives { context, error }
920
943
  repo.on("error:create", ({ context, error }) => {
921
944
  console.error("Failed:", error);
922
945
  });
946
+
947
+ // Remove a listener
948
+ repo.off("after:create", myListener);
923
949
  ```
924
950
 
925
- **Events:** `before:*`, `after:*`, `error:*` for `create`, `createMany`, `update`, `delete`, `deleteMany`, `updateMany`, `getById`, `getByQuery`, `getAll`, `aggregatePaginate`
951
+ **Events:** `before:*`, `after:*`, `error:*` for `create`, `createMany`, `update`, `delete`, `deleteMany`, `updateMany`, `getById`, `getByQuery`, `getAll`, `aggregate`, `aggregatePaginate`, `lookupPopulate`, `getOrCreate`, `count`, `exists`, `distinct`, `bulkWrite`
926
952
 
927
953
  ### Microservice Integration (Kafka / RabbitMQ / Redis Pub-Sub)
928
954
 
@@ -1020,10 +1046,18 @@ const parser = new QueryParser({
1020
1046
  maxLimit: 100, // Prevent excessive queries
1021
1047
  maxFilterDepth: 5, // Prevent nested injection
1022
1048
  maxRegexLength: 100, // ReDoS protection
1049
+ allowedFilterFields: ['status', 'name', 'email'], // Whitelist filter fields
1050
+ allowedSortFields: ['createdAt', 'name'], // Whitelist sort fields
1051
+ allowedOperators: ['eq', 'ne', 'in', 'gt', 'lt'], // Whitelist operators
1023
1052
  });
1024
1053
 
1025
1054
  // Parse request query
1026
1055
  const { filters, limit, page, sort, search } = parser.parse(req.query);
1056
+
1057
+ // Read back configured whitelists (used by Arc MCP integration)
1058
+ parser.allowedFilterFields; // ['status', 'name', 'email'] or undefined
1059
+ parser.allowedSortFields; // ['createdAt', 'name'] or undefined
1060
+ parser.allowedOperators; // ['eq', 'ne', 'in', 'gt', 'lt'] or undefined
1027
1061
  ```
1028
1062
 
1029
1063
  **Supported query patterns:**
@@ -1062,6 +1096,8 @@ GET /posts?populate[author][populate][department][select]=name # Nested
1062
1096
  - Blocks `$where`, `$function`, `$accumulator` operators (`$expr` allowed for `$lookup` correlation)
1063
1097
  - ReDoS protection for regex patterns
1064
1098
  - Max filter depth enforcement
1099
+ - Field allowlists for filters and sorting (`allowedFilterFields`, `allowedSortFields`)
1100
+ - Operator allowlists (`allowedOperators`)
1065
1101
  - Collection allowlists for lookups
1066
1102
  - Populate path sanitization (blocks `$where`, `__proto__`, etc.)
1067
1103
  - Max populate depth limit (default: 5)
@@ -1245,29 +1281,45 @@ app.post("/users", async (req, res) => {
1245
1281
 
1246
1282
  ## TypeScript
1247
1283
 
1248
- ```typescript
1249
- import {
1250
- Repository,
1251
- OffsetPaginationResult,
1252
- KeysetPaginationResult,
1253
- } from "@classytic/mongokit";
1284
+ `TDoc` is inferred from the Mongoose model — no manual annotation needed:
1254
1285
 
1255
- interface IUser extends Document {
1256
- name: string;
1257
- email: string;
1258
- }
1286
+ ```typescript
1287
+ import { Repository } from "@classytic/mongokit";
1288
+ import type { CacheableOptions, ReadOptions } from "@classytic/mongokit";
1259
1289
 
1260
- const repo = new Repository<IUser>(UserModel);
1290
+ const repo = new Repository(UserModel); // TDoc inferred from UserModel
1261
1291
 
1262
- const result = await repo.getAll({ page: 1, limit: 20 });
1292
+ // All return types flow correctly
1293
+ const user = await repo.getById("123"); // IUser | null
1294
+ const users = await repo.getAll({ page: 1 }); // OffsetPaginationResult<IUser> | KeysetPaginationResult<IUser>
1263
1295
 
1264
- // Discriminated union - TypeScript knows the type
1265
- if (result.method === "offset") {
1266
- console.log(result.total, result.pages); // Available
1296
+ // Discriminated union TypeScript narrows the type
1297
+ if (users.method === "offset") {
1298
+ console.log(users.total, users.pages); // Available
1267
1299
  }
1268
- if (result.method === "keyset") {
1269
- console.log(result.next, result.hasMore); // Available
1300
+ if (users.method === "keyset") {
1301
+ console.log(users.next, users.hasMore); // Available
1270
1302
  }
1303
+
1304
+ // Typed options — import and reuse
1305
+ const opts: CacheableOptions = { skipCache: true, lean: true };
1306
+ const fresh = await repo.getById("123", opts);
1307
+ ```
1308
+
1309
+ ### Utility Types
1310
+
1311
+ ```typescript
1312
+ import type {
1313
+ InferDocument, // Extract TDoc from Model: InferDocument<typeof UserModel>
1314
+ InferRawDoc, // TDoc without Mongoose Document methods
1315
+ CreateInput, // Omit<TDoc, '_id' | 'createdAt' | 'updatedAt' | '__v'>
1316
+ UpdateInput, // Partial<Omit<TDoc, '_id' | 'createdAt' | '__v'>>
1317
+ DocField, // (keyof TDoc & string) | (string & {}) — autocomplete + nested paths
1318
+ PartialBy, // Make specific fields optional
1319
+ RequiredBy, // Make specific fields required
1320
+ DeepPartial, // Recursive partial
1321
+ KeysOfType, // Extract keys by value type: KeysOfType<IUser, string>
1322
+ } from "@classytic/mongokit";
1271
1323
  ```
1272
1324
 
1273
1325
  ## Extending Repository
@@ -12,8 +12,10 @@ import { r as validateKeysetSort, t as getPrimaryField } from "./sort-C-BJEWUZ.m
12
12
  */
13
13
  function validateLimit(limit, config) {
14
14
  const parsed = Number(limit);
15
- if (!Number.isFinite(parsed) || parsed < 1) return config.defaultLimit || 10;
16
- return Math.min(Math.floor(parsed), config.maxLimit || 100);
15
+ if (!Number.isFinite(parsed) || parsed < 1) return config.defaultLimit ?? 10;
16
+ const max = config.maxLimit ?? 100;
17
+ if (max === 0) return Math.floor(parsed);
18
+ return Math.min(Math.floor(parsed), max);
17
19
  }
18
20
  /**
19
21
  * Validates and sanitizes page number
@@ -101,12 +103,12 @@ var PaginationEngine = class {
101
103
  constructor(Model, config = {}) {
102
104
  this.Model = Model;
103
105
  this.config = {
104
- defaultLimit: config.defaultLimit || 10,
105
- maxLimit: config.maxLimit || 100,
106
- maxPage: config.maxPage || 1e4,
107
- deepPageThreshold: config.deepPageThreshold || 100,
108
- cursorVersion: config.cursorVersion || 1,
109
- useEstimatedCount: config.useEstimatedCount || false
106
+ defaultLimit: config.defaultLimit ?? 10,
107
+ maxLimit: config.maxLimit ?? 100,
108
+ maxPage: config.maxPage ?? 1e4,
109
+ deepPageThreshold: config.deepPageThreshold ?? 100,
110
+ cursorVersion: config.cursorVersion ?? 1,
111
+ useEstimatedCount: config.useEstimatedCount ?? false
110
112
  };
111
113
  }
112
114
  /**
@@ -1,2 +1,2 @@
1
- import { a as create_d_exports, i as delete_d_exports, n as update_d_exports, o as aggregate_d_exports, r as read_d_exports } from "../index-DHki2IxZ.mjs";
1
+ import { a as create_d_exports, i as delete_d_exports, n as update_d_exports, o as aggregate_d_exports, r as read_d_exports } from "../index-DxNyLB2w.mjs";
2
2
  export { aggregate_d_exports as aggregate, create_d_exports as create, delete_d_exports as deleteActions, read_d_exports as read, update_d_exports as update };
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "../chunk-CfYAbeIz.mjs";
2
- import { c as read_exports, h as aggregate_exports, n as update_exports, p as create_exports, u as delete_exports } from "../update-DGKMmBgG.mjs";
2
+ import { c as read_exports, h as aggregate_exports, n as update_exports, p as create_exports, u as delete_exports } from "../update-D6FFSUUO.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 { J as Plugin } from "../types-nLhnjmdE.mjs";
1
+ import { J as Plugin } from "../types-sOh6QSzc.mjs";
2
2
  import { ClientSession, PipelineStage } from "mongoose";
3
3
 
4
4
  //#region src/ai/types.d.ts
@@ -1,4 +1,4 @@
1
- import { $ as ReadPreferenceType, At as LookupOptions, D as GroupResult, V as ObjectId, W as OperationOptions, Z as PopulateSpec, _t as UpdateOptions, a as AnyDocument, b as DeleteResult, g as CreateOptions, gt as UpdateManyResult, pt as SortSpec, st as SelectSpec, vt as UpdateWithValidationResult, z as MinMaxResult } from "./types-nLhnjmdE.mjs";
1
+ import { $ as ReadPreferenceType, At as LookupOptions, D as GroupResult, V as ObjectId, W as OperationOptions, Z as PopulateSpec, _t as UpdateOptions, a as AnyDocument, b as DeleteResult, g as CreateOptions, gt as UpdateManyResult, pt as SortSpec, st as SelectSpec, vt as UpdateWithValidationResult, z as MinMaxResult } from "./types-sOh6QSzc.mjs";
2
2
  import { ClientSession, Model, PipelineStage } from "mongoose";
3
3
 
4
4
  //#region src/actions/aggregate.d.ts
package/dist/index.d.mts CHANGED
@@ -1,8 +1,8 @@
1
- import { $ as ReadPreferenceType, A as InferDocument, At as LookupOptions, B as NonNullableFields, C as EventPayload, Ct as WithPlugins, D as GroupResult, Dt as IRequestContext, E as FieldRules, Et as IControllerResponse, F as KeysetPaginationResult, G as PaginationConfig, H as OffsetPaginationOptions, I as Logger, J as Plugin, K as PaginationResult, L as LookupPopulateOptions, M as JsonSchema, N as KeysOfType, O as HookMode, Ot as IResponseFormatter, P as KeysetPaginationOptions, Q as ReadOptions, R as LookupPopulateResult, S as EventHandlers, St as ValidatorDefinition, T as FieldPreset, Tt as IController, U as OffsetPaginationResult, V as ObjectId, W as OperationOptions, X as PluginType, Y as PluginFunction, Z as PopulateSpec, _ as CrudSchemas, _t as UpdateOptions, a as AnyDocument, at as RequiredBy, b as DeleteResult, bt as ValidationChainOptions, c as CacheOperationOptions, ct as SessionOptions, d as CacheableOptions, dt as SoftDeleteRepository, et as RepositoryContext, f as CascadeOptions, ft as SortDirection, g as CreateOptions, gt as UpdateManyResult, h as CreateInput, ht as UpdateInput, i as AllPluginMethods, it as RepositoryOptions, j as InferRawDoc, k as HttpError, kt as LookupBuilder, l as CacheOptions, lt as SoftDeleteFilterMode, m as CollationOptions, mt as Strict, n as AggregatePaginationOptions, nt as RepositoryInstance, o as AnyModel, ot as SchemaBuilderOptions, p as CascadeRelation, pt as SortSpec, q as PartialBy, r as AggregatePaginationResult, rt as RepositoryOperation, s as CacheAdapter, st as SelectSpec, t as AggregateOptions, tt as RepositoryEvent, u as CacheStats, ut as SoftDeleteOptions, v as DecodedCursor, vt as UpdateWithValidationResult, w as EventPhase, wt as WithTransactionOptions, x as DocField, xt as ValidationResult, y as DeepPartial, yt as UserContext, z as MinMaxResult } from "./types-nLhnjmdE.mjs";
2
- import { t as index_d_exports } from "./index-DHki2IxZ.mjs";
1
+ import { $ as ReadPreferenceType, A as InferDocument, At as LookupOptions, B as NonNullableFields, C as EventPayload, Ct as WithPlugins, D as GroupResult, Dt as IRequestContext, E as FieldRules, Et as IControllerResponse, F as KeysetPaginationResult, G as PaginationConfig, H as OffsetPaginationOptions, I as Logger, J as Plugin, K as PaginationResult, L as LookupPopulateOptions, M as JsonSchema, N as KeysOfType, O as HookMode, Ot as IResponseFormatter, P as KeysetPaginationOptions, Q as ReadOptions, R as LookupPopulateResult, S as EventHandlers, St as ValidatorDefinition, T as FieldPreset, Tt as IController, U as OffsetPaginationResult, V as ObjectId, W as OperationOptions, X as PluginType, Y as PluginFunction, Z as PopulateSpec, _ as CrudSchemas, _t as UpdateOptions, a as AnyDocument, at as RequiredBy, b as DeleteResult, bt as ValidationChainOptions, c as CacheOperationOptions, ct as SessionOptions, d as CacheableOptions, dt as SoftDeleteRepository, et as RepositoryContext, f as CascadeOptions, ft as SortDirection, g as CreateOptions, gt as UpdateManyResult, h as CreateInput, ht as UpdateInput, i as AllPluginMethods, it as RepositoryOptions, j as InferRawDoc, k as HttpError, kt as LookupBuilder, l as CacheOptions, lt as SoftDeleteFilterMode, m as CollationOptions, mt as Strict, n as AggregatePaginationOptions, nt as RepositoryInstance, o as AnyModel, ot as SchemaBuilderOptions, p as CascadeRelation, pt as SortSpec, q as PartialBy, r as AggregatePaginationResult, rt as RepositoryOperation, s as CacheAdapter, st as SelectSpec, t as AggregateOptions, tt as RepositoryEvent, u as CacheStats, ut as SoftDeleteOptions, v as DecodedCursor, vt as UpdateWithValidationResult, w as EventPhase, wt as WithTransactionOptions, x as DocField, xt as ValidationResult, y as DeepPartial, yt as UserContext, z as MinMaxResult } from "./types-sOh6QSzc.mjs";
2
+ import { t as index_d_exports } from "./index-DxNyLB2w.mjs";
3
3
  import { PaginationEngine } from "./pagination/PaginationEngine.mjs";
4
- import { A as dateSequentialId, B as AuditEntry, C as elasticSearchPlugin, D as PrefixedIdOptions, E as IdGenerator, F as CacheMethods, G as AuditTrailOptions, H as AuditQueryOptions, I as cachePlugin, J as auditLogPlugin, K as AuditTrailQuery, L as BatchOperationsMethods, M as prefixedId, N as sequentialId, O as SequentialIdOptions, P as cascadePlugin, R as BulkWriteResult, S as ElasticSearchOptions, T as DateSequentialIdOptions, U as AuditQueryResult, V as AuditOperation, W as AuditTrailMethods, X as aggregateHelpersPlugin, Y as AggregateHelpersMethods, _ as MongoOperationsMethods, a as uniqueField, b as methodRegistryPlugin, c as SubdocumentMethods, d as softDeletePlugin, f as ObservabilityOptions, g as multiTenantPlugin, h as MultiTenantOptions, i as requireField, j as getNextSequence, k as customIdPlugin, l as subdocumentPlugin, m as observabilityPlugin, n as blockIf, o as validationChainPlugin, p as OperationMetric, q as auditTrailPlugin, r as immutableField, s as timestampPlugin, t as autoInject, u as SoftDeleteMethods, v as mongoOperationsPlugin, w as CustomIdOptions, x as fieldFilterPlugin, z as batchOperationsPlugin } from "./validation-chain.plugin-C-IGsWHn.mjs";
5
- import { a as isFieldUpdateAllowed, c as configureLogger, d as getFieldsForUser, f as getMongooseProjection, i as getSystemManagedFields, l as createFieldPreset, m as parseDuplicateKeyError, n as buildCrudSchemasFromMongooseSchema, o as validateUpdateBody, p as createError, r as getImmutableFields, s as createMemoryCache, t as buildCrudSchemasFromModel, u as filterResponseData } from "./mongooseToJsonSchema-MTvR0gJv.mjs";
4
+ import { A as dateSequentialId, B as AuditEntry, C as elasticSearchPlugin, D as PrefixedIdOptions, E as IdGenerator, F as CacheMethods, G as AuditTrailOptions, H as AuditQueryOptions, I as cachePlugin, J as auditLogPlugin, K as AuditTrailQuery, L as BatchOperationsMethods, M as prefixedId, N as sequentialId, O as SequentialIdOptions, P as cascadePlugin, R as BulkWriteResult, S as ElasticSearchOptions, T as DateSequentialIdOptions, U as AuditQueryResult, V as AuditOperation, W as AuditTrailMethods, X as aggregateHelpersPlugin, Y as AggregateHelpersMethods, _ as MongoOperationsMethods, a as uniqueField, b as methodRegistryPlugin, c as SubdocumentMethods, d as softDeletePlugin, f as ObservabilityOptions, g as multiTenantPlugin, h as MultiTenantOptions, i as requireField, j as getNextSequence, k as customIdPlugin, l as subdocumentPlugin, m as observabilityPlugin, n as blockIf, o as validationChainPlugin, p as OperationMetric, q as auditTrailPlugin, r as immutableField, s as timestampPlugin, t as autoInject, u as SoftDeleteMethods, v as mongoOperationsPlugin, w as CustomIdOptions, x as fieldFilterPlugin, z as batchOperationsPlugin } from "./validation-chain.plugin-nJtqOI-E.mjs";
5
+ import { a as isFieldUpdateAllowed, c as configureLogger, d as getFieldsForUser, f as getMongooseProjection, i as getSystemManagedFields, l as createFieldPreset, m as parseDuplicateKeyError, n as buildCrudSchemasFromMongooseSchema, o as validateUpdateBody, p as createError, r as getImmutableFields, s as createMemoryCache, t as buildCrudSchemasFromModel, u as filterResponseData } from "./mongooseToJsonSchema-C374oVAV.mjs";
6
6
  import * as _$mongoose from "mongoose";
7
7
  import { ClientSession, Expression, Model, PipelineStage, PopulateOptions } from "mongoose";
8
8
 
@@ -826,6 +826,15 @@ declare class Repository<TDoc = unknown> {
826
826
  * Get single document by query
827
827
  */
828
828
  getByQuery(query: Record<string, unknown>, options?: CacheableOptions): Promise<TDoc | null>;
829
+ /**
830
+ * Fetch ALL documents matching filters without pagination.
831
+ * Use for background jobs, exports, batch processing where you need every doc.
832
+ *
833
+ * @example
834
+ * const all = await repo.findAll({ status: 'active' });
835
+ * const allLean = await repo.findAll({}, { select: 'name email', lean: true });
836
+ */
837
+ findAll(filters?: Record<string, unknown>, options?: OperationOptions): Promise<TDoc[]>;
829
838
  /**
830
839
  * Unified pagination - auto-detects offset vs keyset based on params
831
840
  *
@@ -868,8 +877,9 @@ declare class Repository<TDoc = unknown> {
868
877
  readPreference?: ReadPreferenceType; /** Advanced populate options (from QueryParser or Arc's BaseController) */
869
878
  populateOptions?: PopulateOptions[]; /** Collation for locale-aware string comparison */
870
879
  collation?: CollationOptions; /** Lookup configurations for $lookup joins (from QueryParser or manual) */
871
- lookups?: LookupOptions[];
872
- }, options?: CacheableOptions): Promise<OffsetPaginationResult<TDoc> | KeysetPaginationResult<TDoc>>;
880
+ lookups?: LookupOptions[]; /** Skip pagination entirely — returns raw TDoc[] (same as findAll) */
881
+ noPagination?: boolean;
882
+ }, options?: CacheableOptions): Promise<OffsetPaginationResult<TDoc> | KeysetPaginationResult<TDoc> | TDoc[]>;
873
883
  /**
874
884
  * Get or create document
875
885
  * Routes through hook system for policy enforcement (multi-tenant, soft-delete)
package/dist/index.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  import { a as warn, n as parseDuplicateKeyError, r as configureLogger, t as createError } from "./error-Bpbi_NKo.mjs";
2
- import { _ as LookupBuilder } from "./update-DGKMmBgG.mjs";
2
+ import { _ as LookupBuilder } from "./update-D6FFSUUO.mjs";
3
3
  import { t as actions_exports } from "./actions/index.mjs";
4
- import { t as PaginationEngine } from "./PaginationEngine-nY04eGUM.mjs";
5
- import { A as aggregateHelpersPlugin, C as HOOK_PRIORITY, D as AuditTrailQuery, E as batchOperationsPlugin, O as auditTrailPlugin, S as cachePlugin, T as AggregationBuilder, _ as dateSequentialId, a as uniqueField, b as sequentialId, c as subdocumentPlugin, d as multiTenantPlugin, f as mongoOperationsPlugin, g as customIdPlugin, h as elasticSearchPlugin, i as requireField, k as auditLogPlugin, l as softDeletePlugin, m as fieldFilterPlugin, n as blockIf, o as validationChainPlugin, p as methodRegistryPlugin, r as immutableField, s as timestampPlugin, t as autoInject, u as observabilityPlugin, v as getNextSequence, w as Repository, x as cascadePlugin, y as prefixedId } from "./validation-chain.plugin-Cp5X5IZu.mjs";
4
+ import { t as PaginationEngine } from "./PaginationEngine-DCs-zKwZ.mjs";
5
+ import { A as aggregateHelpersPlugin, C as HOOK_PRIORITY, D as AuditTrailQuery, E as batchOperationsPlugin, O as auditTrailPlugin, S as cachePlugin, T as AggregationBuilder, _ as dateSequentialId, a as uniqueField, b as sequentialId, c as subdocumentPlugin, d as multiTenantPlugin, f as mongoOperationsPlugin, g as customIdPlugin, h as elasticSearchPlugin, i as requireField, k as auditLogPlugin, l as softDeletePlugin, m as fieldFilterPlugin, n as blockIf, o as validationChainPlugin, p as methodRegistryPlugin, r as immutableField, s as timestampPlugin, t as autoInject, u as observabilityPlugin, v as getNextSequence, w as Repository, x as cascadePlugin, y as prefixedId } from "./validation-chain.plugin-7Pa1wIsD.mjs";
6
6
  import { i as getMongooseProjection, n as filterResponseData, r as getFieldsForUser, t as createFieldPreset } from "./field-selection-reyDRzXf.mjs";
7
7
  import { a as isFieldUpdateAllowed, i as getSystemManagedFields, n as buildCrudSchemasFromMongooseSchema, o as validateUpdateBody, r as getImmutableFields, s as createMemoryCache, t as buildCrudSchemasFromModel } from "./mongooseToJsonSchema-B6Qyl8BK.mjs";
8
8
  import mongoose from "mongoose";
@@ -1,4 +1,4 @@
1
- import { T as FieldPreset, _ as CrudSchemas, k as HttpError, ot as SchemaBuilderOptions, s as CacheAdapter, xt as ValidationResult, yt as UserContext } from "./types-nLhnjmdE.mjs";
1
+ import { T as FieldPreset, _ as CrudSchemas, k as HttpError, ot as SchemaBuilderOptions, s as CacheAdapter, xt as ValidationResult, yt as UserContext } from "./types-sOh6QSzc.mjs";
2
2
  import mongoose, { Schema } from "mongoose";
3
3
 
4
4
  //#region src/utils/error.d.ts
@@ -1,4 +1,4 @@
1
- import { F as KeysetPaginationResult, G as PaginationConfig, H as OffsetPaginationOptions, P as KeysetPaginationOptions, U as OffsetPaginationResult, a as AnyDocument, n as AggregatePaginationOptions, r as AggregatePaginationResult } from "../types-nLhnjmdE.mjs";
1
+ import { F as KeysetPaginationResult, G as PaginationConfig, H as OffsetPaginationOptions, P as KeysetPaginationOptions, U as OffsetPaginationResult, a as AnyDocument, n as AggregatePaginationOptions, r as AggregatePaginationResult } from "../types-sOh6QSzc.mjs";
2
2
  import { Model } from "mongoose";
3
3
 
4
4
  //#region src/pagination/PaginationEngine.d.ts
@@ -1,2 +1,2 @@
1
- import { t as PaginationEngine } from "../PaginationEngine-nY04eGUM.mjs";
1
+ import { t as PaginationEngine } from "../PaginationEngine-DCs-zKwZ.mjs";
2
2
  export { PaginationEngine };
@@ -1,2 +1,2 @@
1
- import { A as dateSequentialId, B as AuditEntry, C as elasticSearchPlugin, D as PrefixedIdOptions, E as IdGenerator, F as CacheMethods, G as AuditTrailOptions, H as AuditQueryOptions, I as cachePlugin, J as auditLogPlugin, K as AuditTrailQuery, L as BatchOperationsMethods, M as prefixedId, N as sequentialId, O as SequentialIdOptions, P as cascadePlugin, S as ElasticSearchOptions, T as DateSequentialIdOptions, U as AuditQueryResult, V as AuditOperation, W as AuditTrailMethods, X as aggregateHelpersPlugin, Y as AggregateHelpersMethods, _ as MongoOperationsMethods, a as uniqueField, b as methodRegistryPlugin, c as SubdocumentMethods, d as softDeletePlugin, f as ObservabilityOptions, g as multiTenantPlugin, h as MultiTenantOptions, i as requireField, j as getNextSequence, k as customIdPlugin, l as subdocumentPlugin, m as observabilityPlugin, n as blockIf, o as validationChainPlugin, p as OperationMetric, q as auditTrailPlugin, r as immutableField, s as timestampPlugin, t as autoInject, u as SoftDeleteMethods, v as mongoOperationsPlugin, w as CustomIdOptions, x as fieldFilterPlugin, y as MethodRegistryRepository, z as batchOperationsPlugin } from "../validation-chain.plugin-C-IGsWHn.mjs";
1
+ import { A as dateSequentialId, B as AuditEntry, C as elasticSearchPlugin, D as PrefixedIdOptions, E as IdGenerator, F as CacheMethods, G as AuditTrailOptions, H as AuditQueryOptions, I as cachePlugin, J as auditLogPlugin, K as AuditTrailQuery, L as BatchOperationsMethods, M as prefixedId, N as sequentialId, O as SequentialIdOptions, P as cascadePlugin, S as ElasticSearchOptions, T as DateSequentialIdOptions, U as AuditQueryResult, V as AuditOperation, W as AuditTrailMethods, X as aggregateHelpersPlugin, Y as AggregateHelpersMethods, _ as MongoOperationsMethods, a as uniqueField, b as methodRegistryPlugin, c as SubdocumentMethods, d as softDeletePlugin, f as ObservabilityOptions, g as multiTenantPlugin, h as MultiTenantOptions, i as requireField, j as getNextSequence, k as customIdPlugin, l as subdocumentPlugin, m as observabilityPlugin, n as blockIf, o as validationChainPlugin, p as OperationMetric, q as auditTrailPlugin, r as immutableField, s as timestampPlugin, t as autoInject, u as SoftDeleteMethods, v as mongoOperationsPlugin, w as CustomIdOptions, x as fieldFilterPlugin, y as MethodRegistryRepository, z as batchOperationsPlugin } from "../validation-chain.plugin-nJtqOI-E.mjs";
2
2
  export { type AggregateHelpersMethods, type AuditEntry, type AuditOperation, type AuditQueryOptions, type AuditQueryResult, type AuditTrailMethods, type AuditTrailOptions, AuditTrailQuery, type BatchOperationsMethods, type CacheMethods, type CustomIdOptions, type DateSequentialIdOptions, type ElasticSearchOptions, type IdGenerator, type MethodRegistryRepository, type MongoOperationsMethods, type MultiTenantOptions, type ObservabilityOptions, type OperationMetric, type PrefixedIdOptions, type SequentialIdOptions, type SoftDeleteMethods, type SubdocumentMethods, aggregateHelpersPlugin, auditLogPlugin, auditTrailPlugin, autoInject, batchOperationsPlugin, blockIf, cachePlugin, cascadePlugin, customIdPlugin, dateSequentialId, elasticSearchPlugin, fieldFilterPlugin, getNextSequence, immutableField, methodRegistryPlugin, mongoOperationsPlugin, multiTenantPlugin, observabilityPlugin, prefixedId, requireField, sequentialId, softDeletePlugin, subdocumentPlugin, timestampPlugin, uniqueField, validationChainPlugin };
@@ -1,2 +1,2 @@
1
- import { A as aggregateHelpersPlugin, D as AuditTrailQuery, E as batchOperationsPlugin, O as auditTrailPlugin, S as cachePlugin, _ as dateSequentialId, a as uniqueField, b as sequentialId, c as subdocumentPlugin, d as multiTenantPlugin, f as mongoOperationsPlugin, g as customIdPlugin, h as elasticSearchPlugin, i as requireField, k as auditLogPlugin, l as softDeletePlugin, m as fieldFilterPlugin, n as blockIf, o as validationChainPlugin, p as methodRegistryPlugin, r as immutableField, s as timestampPlugin, t as autoInject, u as observabilityPlugin, v as getNextSequence, x as cascadePlugin, y as prefixedId } from "../validation-chain.plugin-Cp5X5IZu.mjs";
1
+ import { A as aggregateHelpersPlugin, D as AuditTrailQuery, E as batchOperationsPlugin, O as auditTrailPlugin, S as cachePlugin, _ as dateSequentialId, a as uniqueField, b as sequentialId, c as subdocumentPlugin, d as multiTenantPlugin, f as mongoOperationsPlugin, g as customIdPlugin, h as elasticSearchPlugin, i as requireField, k as auditLogPlugin, l as softDeletePlugin, m as fieldFilterPlugin, n as blockIf, o as validationChainPlugin, p as methodRegistryPlugin, r as immutableField, s as timestampPlugin, t as autoInject, u as observabilityPlugin, v as getNextSequence, x as cascadePlugin, y as prefixedId } from "../validation-chain.plugin-7Pa1wIsD.mjs";
2
2
  export { AuditTrailQuery, aggregateHelpersPlugin, auditLogPlugin, auditTrailPlugin, autoInject, batchOperationsPlugin, blockIf, cachePlugin, cascadePlugin, customIdPlugin, dateSequentialId, elasticSearchPlugin, fieldFilterPlugin, getNextSequence, immutableField, methodRegistryPlugin, mongoOperationsPlugin, multiTenantPlugin, observabilityPlugin, prefixedId, requireField, sequentialId, softDeletePlugin, subdocumentPlugin, timestampPlugin, uniqueField, validationChainPlugin };
@@ -720,7 +720,9 @@ interface WithTransactionOptions {
720
720
  }
721
721
  /** Create operation options */
722
722
  interface CreateOptions extends SessionOptions {
723
- /** Keep insertion order on error (default: true) */
723
+ /** Keep insertion order on error (default: false).
724
+ * When false, all valid documents insert even if some fail (e.g. duplicates).
725
+ * Set to true to abort remaining inserts on first error. */
724
726
  ordered?: boolean;
725
727
  }
726
728
  /** Update operation options */
@@ -924,7 +926,7 @@ interface RepositoryInstance {
924
926
  [key: string]: unknown;
925
927
  }
926
928
  /** Repository operation names */
927
- type RepositoryOperation = 'create' | 'createMany' | 'update' | 'updateMany' | 'delete' | 'deleteMany' | 'getById' | 'getByQuery' | 'getAll' | 'getOrCreate' | 'count' | 'exists' | 'distinct' | 'aggregate' | 'aggregatePaginate' | 'lookupPopulate' | 'bulkWrite';
929
+ type RepositoryOperation = 'create' | 'createMany' | 'update' | 'updateMany' | 'delete' | 'deleteMany' | 'getById' | 'getByQuery' | 'getAll' | 'findAll' | 'getOrCreate' | 'count' | 'exists' | 'distinct' | 'aggregate' | 'aggregatePaginate' | 'lookupPopulate' | 'bulkWrite';
928
930
  /** Event lifecycle phases */
929
931
  type EventPhase = 'before' | 'after' | 'error';
930
932
  /** Repository event names (generated from template literals) */
@@ -461,7 +461,7 @@ async function create(Model, data, options = {}) {
461
461
  async function createMany(Model, dataArray, options = {}) {
462
462
  return Model.insertMany(dataArray, {
463
463
  session: options.session,
464
- ordered: options.ordered !== false
464
+ ordered: options.ordered === true
465
465
  });
466
466
  }
467
467
  /**
@@ -1,5 +1,5 @@
1
- import { Z as PopulateSpec, pt as SortSpec, st as SelectSpec } from "../types-nLhnjmdE.mjs";
2
- import { a as isFieldUpdateAllowed, c as configureLogger, d as getFieldsForUser, f as getMongooseProjection, i as getSystemManagedFields, l as createFieldPreset, n as buildCrudSchemasFromMongooseSchema, o as validateUpdateBody, p as createError, r as getImmutableFields, s as createMemoryCache, t as buildCrudSchemasFromModel, u as filterResponseData } from "../mongooseToJsonSchema-MTvR0gJv.mjs";
1
+ import { Z as PopulateSpec, pt as SortSpec, st as SelectSpec } from "../types-sOh6QSzc.mjs";
2
+ import { a as isFieldUpdateAllowed, c as configureLogger, d as getFieldsForUser, f as getMongooseProjection, i as getSystemManagedFields, l as createFieldPreset, n as buildCrudSchemasFromMongooseSchema, o as validateUpdateBody, p as createError, r as getImmutableFields, s as createMemoryCache, t as buildCrudSchemasFromModel, u as filterResponseData } from "../mongooseToJsonSchema-C374oVAV.mjs";
3
3
 
4
4
  //#region src/utils/cache-keys.d.ts
5
5
  /**
@@ -1,6 +1,6 @@
1
1
  import { a as warn, i as debug, n as parseDuplicateKeyError, t as createError } from "./error-Bpbi_NKo.mjs";
2
- import { _ as LookupBuilder, a as getById, d as create, f as createMany, g as distinct, i as exists, l as deleteById, m as upsert, o as getByQuery, r as count, s as getOrCreate, t as update } from "./update-DGKMmBgG.mjs";
3
- import { t as PaginationEngine } from "./PaginationEngine-nY04eGUM.mjs";
2
+ import { _ as LookupBuilder, a as getById, d as create, f as createMany, g as distinct, i as exists, l as deleteById, m as upsert, o as getByQuery, r as count, s as getOrCreate, t as update } from "./update-D6FFSUUO.mjs";
3
+ import { t as PaginationEngine } from "./PaginationEngine-DCs-zKwZ.mjs";
4
4
  import { a as byIdKey, c as listQueryKey, l as modelPattern, o as byQueryKey, r as getFieldsForUser, u as versionKey } from "./field-selection-reyDRzXf.mjs";
5
5
  import mongoose from "mongoose";
6
6
  //#region src/plugins/aggregate-helpers.plugin.ts
@@ -1302,6 +1302,10 @@ var Repository = class {
1302
1302
  return cachedResult;
1303
1303
  }
1304
1304
  try {
1305
+ if (typeof id === "string" && !mongoose.Types.ObjectId.isValid(id)) {
1306
+ if (context.throwOnNotFound === false || options.throwOnNotFound === false) return null;
1307
+ throw createError(404, "Document not found");
1308
+ }
1305
1309
  const result = await getById(this.Model, id, context);
1306
1310
  await this._emitHook("after:getById", {
1307
1311
  context,
@@ -1352,6 +1356,42 @@ var Repository = class {
1352
1356
  }
1353
1357
  }
1354
1358
  /**
1359
+ * Fetch ALL documents matching filters without pagination.
1360
+ * Use for background jobs, exports, batch processing where you need every doc.
1361
+ *
1362
+ * @example
1363
+ * const all = await repo.findAll({ status: 'active' });
1364
+ * const allLean = await repo.findAll({}, { select: 'name email', lean: true });
1365
+ */
1366
+ async findAll(filters = {}, options = {}) {
1367
+ const context = await this._buildContext("findAll", {
1368
+ filters,
1369
+ ...options
1370
+ });
1371
+ const resolvedFilters = context.filters ?? filters;
1372
+ try {
1373
+ const query = this.Model.find(resolvedFilters);
1374
+ const selectSpec = context.select || options.select;
1375
+ if (selectSpec) query.select(selectSpec);
1376
+ if (options.populate || context.populate) query.populate(this._parsePopulate(context.populate || options.populate));
1377
+ if (context.lean ?? options.lean ?? true) query.lean();
1378
+ if (options.session) query.session(options.session);
1379
+ if (options.readPreference) query.read(options.readPreference);
1380
+ const result = await query.exec();
1381
+ await this._emitHook("after:findAll", {
1382
+ context,
1383
+ result
1384
+ });
1385
+ return result;
1386
+ } catch (error) {
1387
+ await this._emitErrorHook("error:findAll", {
1388
+ context,
1389
+ error
1390
+ });
1391
+ throw this._handleError(error);
1392
+ }
1393
+ }
1394
+ /**
1355
1395
  * Unified pagination - auto-detects offset vs keyset based on params
1356
1396
  *
1357
1397
  * Auto-detection logic:
@@ -1393,6 +1433,7 @@ var Repository = class {
1393
1433
  });
1394
1434
  return cachedResult;
1395
1435
  }
1436
+ if (params.noPagination) return this.findAll(params.filters ?? {}, options);
1396
1437
  const filters = context.filters ?? params.filters ?? {};
1397
1438
  const search = context.search ?? params.search;
1398
1439
  const sort = context.sort ?? params.sort ?? "-createdAt";
@@ -1,4 +1,4 @@
1
- import { I as Logger, J as Plugin, St as ValidatorDefinition, T as FieldPreset, U as OffsetPaginationResult, V as ObjectId, Z as PopulateSpec, bt as ValidationChainOptions, et as RepositoryContext, f as CascadeOptions, l as CacheOptions, nt as RepositoryInstance, pt as SortSpec, st as SelectSpec, u as CacheStats, ut as SoftDeleteOptions } from "./types-nLhnjmdE.mjs";
1
+ import { I as Logger, J as Plugin, St as ValidatorDefinition, T as FieldPreset, U as OffsetPaginationResult, V as ObjectId, Z as PopulateSpec, bt as ValidationChainOptions, et as RepositoryContext, f as CascadeOptions, l as CacheOptions, nt as RepositoryInstance, pt as SortSpec, st as SelectSpec, u as CacheStats, ut as SoftDeleteOptions } from "./types-sOh6QSzc.mjs";
2
2
  import mongoose, { ClientSession } from "mongoose";
3
3
 
4
4
  //#region src/plugins/aggregate-helpers.plugin.d.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@classytic/mongokit",
3
- "version": "3.4.3",
3
+ "version": "3.4.4",
4
4
  "description": "Production-grade MongoDB repositories with zero dependencies - smart pagination, events, and plugins",
5
5
  "type": "module",
6
6
  "sideEffects": false,