@classytic/mongokit 3.0.1 → 3.0.2

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,3 +1,3 @@
1
- export { a as aggregate, c as create, _ as deleteActions, r as read, u as update } from '../index-CKy3H2SY.js';
1
+ export { a as aggregate, c as create, _ as deleteActions, r as read, u as update } from '../index-CMCrkd2v.js';
2
2
  import 'mongoose';
3
- import '../types-vDtcOhyx.js';
3
+ import '../types-B3dPUKjs.js';
@@ -147,6 +147,14 @@ __export(update_exports, {
147
147
  updateWithConstraints: () => updateWithConstraints,
148
148
  updateWithValidation: () => updateWithValidation
149
149
  });
150
+ function assertUpdatePipelineAllowed(update2, updatePipeline) {
151
+ if (Array.isArray(update2) && updatePipeline !== true) {
152
+ throw createError(
153
+ 400,
154
+ "Update pipelines (array updates) are disabled by default; pass `{ updatePipeline: true }` to explicitly allow pipeline-style updates."
155
+ );
156
+ }
157
+ }
150
158
  function parsePopulate2(populate) {
151
159
  if (!populate) return [];
152
160
  if (typeof populate === "string") {
@@ -158,6 +166,7 @@ function parsePopulate2(populate) {
158
166
  return [populate];
159
167
  }
160
168
  async function update(Model, id, data, options = {}) {
169
+ assertUpdatePipelineAllowed(data, options.updatePipeline);
161
170
  const document = await Model.findByIdAndUpdate(id, data, {
162
171
  new: true,
163
172
  runValidators: true,
@@ -170,6 +179,7 @@ async function update(Model, id, data, options = {}) {
170
179
  return document;
171
180
  }
172
181
  async function updateWithConstraints(Model, id, data, constraints = {}, options = {}) {
182
+ assertUpdatePipelineAllowed(data, options.updatePipeline);
173
183
  const query = { _id: id, ...constraints };
174
184
  const document = await Model.findOneAndUpdate(query, data, {
175
185
  new: true,
@@ -181,6 +191,7 @@ async function updateWithConstraints(Model, id, data, constraints = {}, options
181
191
  }
182
192
  async function updateWithValidation(Model, id, data, validationOptions = {}, options = {}) {
183
193
  const { buildConstraints, validateUpdate } = validationOptions;
194
+ assertUpdatePipelineAllowed(data, options.updatePipeline);
184
195
  if (buildConstraints) {
185
196
  const constraints = buildConstraints(data);
186
197
  const document = await updateWithConstraints(Model, id, data, constraints, options);
@@ -215,6 +226,7 @@ async function updateWithValidation(Model, id, data, validationOptions = {}, opt
215
226
  return { success: true, data: updated };
216
227
  }
217
228
  async function updateMany(Model, query, data, options = {}) {
229
+ assertUpdatePipelineAllowed(data, options.updatePipeline);
218
230
  const result = await Model.updateMany(query, data, {
219
231
  runValidators: true,
220
232
  session: options.session,
@@ -226,6 +238,7 @@ async function updateMany(Model, query, data, options = {}) {
226
238
  };
227
239
  }
228
240
  async function updateByQuery(Model, query, data, options = {}) {
241
+ assertUpdatePipelineAllowed(data, options.updatePipeline);
229
242
  const document = await Model.findOneAndUpdate(query, data, {
230
243
  new: true,
231
244
  runValidators: true,
@@ -1,5 +1,5 @@
1
1
  import { Model, ClientSession, PipelineStage } from 'mongoose';
2
- import { A as AnyDocument, C as CreateOptions, l as OperationOptions, S as SelectSpec, f as PopulateSpec, g as SortSpec, U as UpdateOptions, n as UpdateWithValidationResult, m as UpdateManyResult, D as DeleteResult, I as GroupResult, G as LookupOptions, M as MinMaxResult } from './types-vDtcOhyx.js';
2
+ import { A as AnyDocument, C as CreateOptions, f as ObjectId, n as OperationOptions, S as SelectSpec, g as PopulateSpec, h as SortSpec, U as UpdateOptions, p as UpdateWithValidationResult, o as UpdateManyResult, D as DeleteResult, N as GroupResult, M as LookupOptions, Q as MinMaxResult } from './types-B3dPUKjs.js';
3
3
 
4
4
  /**
5
5
  * Create Actions
@@ -48,7 +48,7 @@ declare namespace create$1 {
48
48
  * @returns Document or null
49
49
  * @throws Error if document not found and throwOnNotFound is true
50
50
  */
51
- declare function getById<TDoc = AnyDocument>(Model: Model<TDoc>, id: string, options?: OperationOptions): Promise<TDoc | null>;
51
+ declare function getById<TDoc = AnyDocument>(Model: Model<TDoc>, id: string | ObjectId, options?: OperationOptions): Promise<TDoc | null>;
52
52
  /**
53
53
  * Get document by query
54
54
  *
@@ -117,12 +117,12 @@ declare namespace read {
117
117
  /**
118
118
  * Update by ID
119
119
  */
120
- declare function update<TDoc = AnyDocument>(Model: Model<TDoc>, id: string, data: Record<string, unknown>, options?: UpdateOptions): Promise<TDoc>;
120
+ declare function update<TDoc = AnyDocument>(Model: Model<TDoc>, id: string | ObjectId, data: Record<string, unknown>, options?: UpdateOptions): Promise<TDoc>;
121
121
  /**
122
122
  * Update with query constraints (optimized)
123
123
  * Returns null if constraints not met (not an error)
124
124
  */
125
- declare function updateWithConstraints<TDoc = AnyDocument>(Model: Model<TDoc>, id: string, data: Record<string, unknown>, constraints?: Record<string, unknown>, options?: UpdateOptions): Promise<TDoc | null>;
125
+ declare function updateWithConstraints<TDoc = AnyDocument>(Model: Model<TDoc>, id: string | ObjectId, data: Record<string, unknown>, constraints?: Record<string, unknown>, options?: UpdateOptions): Promise<TDoc | null>;
126
126
  /**
127
127
  * Validation options for smart update
128
128
  */
@@ -141,7 +141,7 @@ interface ValidationOptions {
141
141
  * Update with validation (smart optimization)
142
142
  * 1-query on success, 2-queries for detailed errors
143
143
  */
144
- declare function updateWithValidation<TDoc = AnyDocument>(Model: Model<TDoc>, id: string, data: Record<string, unknown>, validationOptions?: ValidationOptions, options?: UpdateOptions): Promise<UpdateWithValidationResult<TDoc>>;
144
+ declare function updateWithValidation<TDoc = AnyDocument>(Model: Model<TDoc>, id: string | ObjectId, data: Record<string, unknown>, validationOptions?: ValidationOptions, options?: UpdateOptions): Promise<UpdateWithValidationResult<TDoc>>;
145
145
  /**
146
146
  * Update many documents
147
147
  */
@@ -156,15 +156,15 @@ declare function updateByQuery<TDoc = AnyDocument>(Model: Model<TDoc>, query: Re
156
156
  /**
157
157
  * Increment field
158
158
  */
159
- declare function increment<TDoc = AnyDocument>(Model: Model<TDoc>, id: string, field: string, value?: number, options?: UpdateOptions): Promise<TDoc>;
159
+ declare function increment<TDoc = AnyDocument>(Model: Model<TDoc>, id: string | ObjectId, field: string, value?: number, options?: UpdateOptions): Promise<TDoc>;
160
160
  /**
161
161
  * Push to array
162
162
  */
163
- declare function pushToArray<TDoc = AnyDocument>(Model: Model<TDoc>, id: string, field: string, value: unknown, options?: UpdateOptions): Promise<TDoc>;
163
+ declare function pushToArray<TDoc = AnyDocument>(Model: Model<TDoc>, id: string | ObjectId, field: string, value: unknown, options?: UpdateOptions): Promise<TDoc>;
164
164
  /**
165
165
  * Pull from array
166
166
  */
167
- declare function pullFromArray<TDoc = AnyDocument>(Model: Model<TDoc>, id: string, field: string, value: unknown, options?: UpdateOptions): Promise<TDoc>;
167
+ declare function pullFromArray<TDoc = AnyDocument>(Model: Model<TDoc>, id: string | ObjectId, field: string, value: unknown, options?: UpdateOptions): Promise<TDoc>;
168
168
 
169
169
  declare const update$1_increment: typeof increment;
170
170
  declare const update$1_pullFromArray: typeof pullFromArray;
@@ -186,7 +186,7 @@ declare namespace update$1 {
186
186
  /**
187
187
  * Delete by ID
188
188
  */
189
- declare function deleteById(Model: Model<any>, id: string, options?: {
189
+ declare function deleteById(Model: Model<any>, id: string | ObjectId, options?: {
190
190
  session?: ClientSession;
191
191
  }): Promise<DeleteResult>;
192
192
  /**
@@ -205,14 +205,14 @@ declare function deleteByQuery(Model: Model<any>, query: Record<string, unknown>
205
205
  /**
206
206
  * Soft delete (set deleted flag)
207
207
  */
208
- declare function softDelete<TDoc = AnyDocument>(Model: Model<TDoc>, id: string, options?: {
208
+ declare function softDelete<TDoc = AnyDocument>(Model: Model<TDoc>, id: string | ObjectId, options?: {
209
209
  session?: ClientSession;
210
210
  userId?: string;
211
211
  }): Promise<DeleteResult>;
212
212
  /**
213
213
  * Restore soft deleted document
214
214
  */
215
- declare function restore<TDoc = AnyDocument>(Model: Model<TDoc>, id: string, options?: {
215
+ declare function restore<TDoc = AnyDocument>(Model: Model<TDoc>, id: string | ObjectId, options?: {
216
216
  session?: ClientSession;
217
217
  }): Promise<DeleteResult>;
218
218
 
package/dist/index.d.ts CHANGED
@@ -1,11 +1,11 @@
1
- import { A as AnyDocument, e as PluginType, P as PaginationConfig, S as SelectSpec, f as PopulateSpec, g as SortSpec, a as OffsetPaginationResult, b as KeysetPaginationResult, d as AggregatePaginationResult, R as RepositoryContext, H as HttpError } from './types-vDtcOhyx.js';
2
- export { c as AggregatePaginationOptions, i as AnyModel, N as CacheAdapter, T as CacheOperationOptions, Q as CacheOptions, W as CacheStats, Y as CascadeOptions, X as CascadeRelation, C as CreateOptions, w as CrudSchemas, x as DecodedCursor, D as DeleteResult, E as EventPayload, F as FieldPreset, u as FieldRules, I as GroupResult, J as JsonSchema, K as KeysetPaginationOptions, L as Logger, G as LookupOptions, M as MinMaxResult, h as ObjectId, O as OffsetPaginationOptions, l as OperationOptions, k as PaginationResult, t as ParsedQuery, p as Plugin, q as PluginFunction, s as RepositoryEvent, r as RepositoryInstance, v as SchemaBuilderOptions, B as SoftDeleteOptions, j as SortDirection, m as UpdateManyResult, U as UpdateOptions, n as UpdateWithValidationResult, o as UserContext, z as ValidationChainOptions, V as ValidationResult, y as ValidatorDefinition } from './types-vDtcOhyx.js';
1
+ import { A as AnyDocument, e as PluginType, P as PaginationConfig, R as RepositoryOptions, f as ObjectId, S as SelectSpec, g as PopulateSpec, h as SortSpec, a as OffsetPaginationResult, b as KeysetPaginationResult, U as UpdateOptions, d as AggregatePaginationResult, i as RepositoryContext, H as HttpError } from './types-B3dPUKjs.js';
2
+ export { c as AggregatePaginationOptions, j as AnyModel, T as CacheAdapter, X as CacheOperationOptions, W as CacheOptions, Y as CacheStats, _ as CascadeOptions, Z as CascadeRelation, C as CreateOptions, y as CrudSchemas, z as DecodedCursor, D as DeleteResult, E as EventPayload, F as FieldPreset, w as FieldRules, N as GroupResult, l as HookMode, J as JsonSchema, K as KeysetPaginationOptions, L as Logger, M as LookupOptions, Q as MinMaxResult, O as OffsetPaginationOptions, n as OperationOptions, m as PaginationResult, v as ParsedQuery, r as Plugin, s as PluginFunction, u as RepositoryEvent, t as RepositoryInstance, x as SchemaBuilderOptions, I as SoftDeleteOptions, k as SortDirection, o as UpdateManyResult, p as UpdateWithValidationResult, q as UserContext, G as ValidationChainOptions, V as ValidationResult, B as ValidatorDefinition } from './types-B3dPUKjs.js';
3
3
  import * as mongoose from 'mongoose';
4
4
  import { Model, ClientSession, PipelineStage, PopulateOptions } from 'mongoose';
5
5
  import { PaginationEngine } from './pagination/PaginationEngine.js';
6
6
  export { aggregateHelpersPlugin, auditLogPlugin, autoInject, batchOperationsPlugin, blockIf, cachePlugin, cascadePlugin, fieldFilterPlugin, immutableField, methodRegistryPlugin, mongoOperationsPlugin, requireField, softDeletePlugin, subdocumentPlugin, timestampPlugin, uniqueField, validationChainPlugin } from './plugins/index.js';
7
- export { b as createError, c as createFieldPreset, d as createMemoryCache, f as filterResponseData, g as getFieldsForUser, a as getMongooseProjection } from './memory-cache-tn3v1xgG.js';
8
- export { i as actions } from './index-CKy3H2SY.js';
7
+ export { b as createError, c as createFieldPreset, d as createMemoryCache, f as filterResponseData, g as getFieldsForUser, a as getMongooseProjection } from './memory-cache-Bn_-Kk-0.js';
8
+ export { i as actions } from './index-CMCrkd2v.js';
9
9
 
10
10
  /**
11
11
  * Repository Pattern - Data Access Layer
@@ -44,8 +44,9 @@ declare class Repository<TDoc = AnyDocument> {
44
44
  readonly model: string;
45
45
  readonly _hooks: Map<string, HookListener[]>;
46
46
  readonly _pagination: PaginationEngine<TDoc>;
47
+ private readonly _hookMode;
47
48
  [key: string]: unknown;
48
- constructor(Model: Model<TDoc>, plugins?: PluginType[], paginationConfig?: PaginationConfig);
49
+ constructor(Model: Model<TDoc>, plugins?: PluginType[], paginationConfig?: PaginationConfig, options?: RepositoryOptions);
49
50
  /**
50
51
  * Register a plugin
51
52
  */
@@ -62,6 +63,8 @@ declare class Repository<TDoc = AnyDocument> {
62
63
  * Emit event and await all async handlers
63
64
  */
64
65
  emitAsync(event: string, data: unknown): Promise<void>;
66
+ private _emitHook;
67
+ private _emitErrorHook;
65
68
  /**
66
69
  * Create single document
67
70
  */
@@ -78,7 +81,7 @@ declare class Repository<TDoc = AnyDocument> {
78
81
  /**
79
82
  * Get document by ID
80
83
  */
81
- getById(id: string, options?: {
84
+ getById(id: string | ObjectId, options?: {
82
85
  select?: SelectSpec;
83
86
  populate?: PopulateSpec;
84
87
  lean?: boolean;
@@ -165,16 +168,11 @@ declare class Repository<TDoc = AnyDocument> {
165
168
  /**
166
169
  * Update document by ID
167
170
  */
168
- update(id: string, data: Record<string, unknown>, options?: {
169
- select?: SelectSpec;
170
- populate?: PopulateSpec;
171
- lean?: boolean;
172
- session?: ClientSession;
173
- }): Promise<TDoc>;
171
+ update(id: string | ObjectId, data: Record<string, unknown>, options?: UpdateOptions): Promise<TDoc>;
174
172
  /**
175
173
  * Delete document by ID
176
174
  */
177
- delete(id: string, options?: {
175
+ delete(id: string | ObjectId, options?: {
178
176
  session?: ClientSession;
179
177
  }): Promise<{
180
178
  success: boolean;
@@ -238,6 +236,6 @@ declare class Repository<TDoc = AnyDocument> {
238
236
  * @example
239
237
  * const userRepo = createRepository(UserModel, [timestampPlugin()]);
240
238
  */
241
- declare function createRepository<TDoc>(Model: mongoose.Model<TDoc>, plugins?: PluginType[]): Repository<TDoc>;
239
+ declare function createRepository<TDoc>(Model: mongoose.Model<TDoc>, plugins?: PluginType[], paginationConfig?: PaginationConfig, options?: RepositoryOptions): Repository<TDoc>;
242
240
 
243
- export { AggregatePaginationResult, AnyDocument, HttpError, KeysetPaginationResult, OffsetPaginationResult, PaginationConfig, PaginationEngine, PluginType, PopulateSpec, Repository, RepositoryContext, SelectSpec, SortSpec, createRepository, Repository as default };
241
+ export { AggregatePaginationResult, AnyDocument, HttpError, KeysetPaginationResult, ObjectId, OffsetPaginationResult, PaginationConfig, PaginationEngine, PluginType, PopulateSpec, Repository, RepositoryContext, RepositoryOptions, SelectSpec, SortSpec, UpdateOptions, createRepository, Repository as default };
package/dist/index.js CHANGED
@@ -147,6 +147,14 @@ __export(update_exports, {
147
147
  updateWithConstraints: () => updateWithConstraints,
148
148
  updateWithValidation: () => updateWithValidation
149
149
  });
150
+ function assertUpdatePipelineAllowed(update2, updatePipeline) {
151
+ if (Array.isArray(update2) && updatePipeline !== true) {
152
+ throw createError(
153
+ 400,
154
+ "Update pipelines (array updates) are disabled by default; pass `{ updatePipeline: true }` to explicitly allow pipeline-style updates."
155
+ );
156
+ }
157
+ }
150
158
  function parsePopulate2(populate) {
151
159
  if (!populate) return [];
152
160
  if (typeof populate === "string") {
@@ -158,6 +166,7 @@ function parsePopulate2(populate) {
158
166
  return [populate];
159
167
  }
160
168
  async function update(Model, id, data, options = {}) {
169
+ assertUpdatePipelineAllowed(data, options.updatePipeline);
161
170
  const document = await Model.findByIdAndUpdate(id, data, {
162
171
  new: true,
163
172
  runValidators: true,
@@ -170,6 +179,7 @@ async function update(Model, id, data, options = {}) {
170
179
  return document;
171
180
  }
172
181
  async function updateWithConstraints(Model, id, data, constraints = {}, options = {}) {
182
+ assertUpdatePipelineAllowed(data, options.updatePipeline);
173
183
  const query = { _id: id, ...constraints };
174
184
  const document = await Model.findOneAndUpdate(query, data, {
175
185
  new: true,
@@ -181,6 +191,7 @@ async function updateWithConstraints(Model, id, data, constraints = {}, options
181
191
  }
182
192
  async function updateWithValidation(Model, id, data, validationOptions = {}, options = {}) {
183
193
  const { buildConstraints, validateUpdate } = validationOptions;
194
+ assertUpdatePipelineAllowed(data, options.updatePipeline);
184
195
  if (buildConstraints) {
185
196
  const constraints = buildConstraints(data);
186
197
  const document = await updateWithConstraints(Model, id, data, constraints, options);
@@ -215,6 +226,7 @@ async function updateWithValidation(Model, id, data, validationOptions = {}, opt
215
226
  return { success: true, data: updated };
216
227
  }
217
228
  async function updateMany(Model, query, data, options = {}) {
229
+ assertUpdatePipelineAllowed(data, options.updatePipeline);
218
230
  const result = await Model.updateMany(query, data, {
219
231
  runValidators: true,
220
232
  session: options.session,
@@ -226,6 +238,7 @@ async function updateMany(Model, query, data, options = {}) {
226
238
  };
227
239
  }
228
240
  async function updateByQuery(Model, query, data, options = {}) {
241
+ assertUpdatePipelineAllowed(data, options.updatePipeline);
229
242
  const document = await Model.findOneAndUpdate(query, data, {
230
243
  new: true,
231
244
  runValidators: true,
@@ -829,11 +842,13 @@ var Repository = class {
829
842
  model;
830
843
  _hooks;
831
844
  _pagination;
832
- constructor(Model, plugins = [], paginationConfig = {}) {
845
+ _hookMode;
846
+ constructor(Model, plugins = [], paginationConfig = {}, options = {}) {
833
847
  this.Model = Model;
834
848
  this.model = Model.modelName;
835
849
  this._hooks = /* @__PURE__ */ new Map();
836
850
  this._pagination = new PaginationEngine(Model, paginationConfig);
851
+ this._hookMode = options.hooks ?? "async";
837
852
  plugins.forEach((plugin) => this.use(plugin));
838
853
  }
839
854
  /**
@@ -862,7 +877,22 @@ var Repository = class {
862
877
  */
863
878
  emit(event, data) {
864
879
  const listeners = this._hooks.get(event) || [];
865
- listeners.forEach((listener) => listener(data));
880
+ for (const listener of listeners) {
881
+ try {
882
+ const result = listener(data);
883
+ if (result && typeof result.then === "function") {
884
+ void result.catch((error) => {
885
+ if (event === "error:hook") return;
886
+ const err = error instanceof Error ? error : new Error(String(error));
887
+ this.emit("error:hook", { event, error: err });
888
+ });
889
+ }
890
+ } catch (error) {
891
+ if (event === "error:hook") continue;
892
+ const err = error instanceof Error ? error : new Error(String(error));
893
+ this.emit("error:hook", { event, error: err });
894
+ }
895
+ }
866
896
  }
867
897
  /**
868
898
  * Emit event and await all async handlers
@@ -873,6 +903,19 @@ var Repository = class {
873
903
  await listener(data);
874
904
  }
875
905
  }
906
+ async _emitHook(event, data) {
907
+ if (this._hookMode === "async") {
908
+ await this.emitAsync(event, data);
909
+ return;
910
+ }
911
+ this.emit(event, data);
912
+ }
913
+ async _emitErrorHook(event, data) {
914
+ try {
915
+ await this._emitHook(event, data);
916
+ } catch {
917
+ }
918
+ }
876
919
  /**
877
920
  * Create single document
878
921
  */
@@ -880,10 +923,10 @@ var Repository = class {
880
923
  const context = await this._buildContext("create", { data, ...options });
881
924
  try {
882
925
  const result = await create(this.Model, context.data || data, options);
883
- this.emit("after:create", { context, result });
926
+ await this._emitHook("after:create", { context, result });
884
927
  return result;
885
928
  } catch (error) {
886
- this.emit("error:create", { context, error });
929
+ await this._emitErrorHook("error:create", { context, error });
887
930
  throw this._handleError(error);
888
931
  }
889
932
  }
@@ -894,10 +937,10 @@ var Repository = class {
894
937
  const context = await this._buildContext("createMany", { dataArray, ...options });
895
938
  try {
896
939
  const result = await createMany(this.Model, context.dataArray || dataArray, options);
897
- this.emit("after:createMany", { context, result });
940
+ await this._emitHook("after:createMany", { context, result });
898
941
  return result;
899
942
  } catch (error) {
900
- this.emit("error:createMany", { context, error });
943
+ await this._emitErrorHook("error:createMany", { context, error });
901
944
  throw this._handleError(error);
902
945
  }
903
946
  }
@@ -910,7 +953,7 @@ var Repository = class {
910
953
  return context._cachedResult;
911
954
  }
912
955
  const result = await getById(this.Model, id, context);
913
- this.emit("after:getById", { context, result });
956
+ await this._emitHook("after:getById", { context, result });
914
957
  return result;
915
958
  }
916
959
  /**
@@ -922,7 +965,7 @@ var Repository = class {
922
965
  return context._cachedResult;
923
966
  }
924
967
  const result = await getByQuery(this.Model, query, context);
925
- this.emit("after:getByQuery", { context, result });
968
+ await this._emitHook("after:getByQuery", { context, result });
926
969
  return result;
927
970
  }
928
971
  /**
@@ -987,7 +1030,7 @@ var Repository = class {
987
1030
  page
988
1031
  });
989
1032
  }
990
- this.emit("after:getAll", { context, result });
1033
+ await this._emitHook("after:getAll", { context, result });
991
1034
  return result;
992
1035
  }
993
1036
  /**
@@ -1015,10 +1058,10 @@ var Repository = class {
1015
1058
  const context = await this._buildContext("update", { id, data, ...options });
1016
1059
  try {
1017
1060
  const result = await update(this.Model, id, context.data || data, context);
1018
- this.emit("after:update", { context, result });
1061
+ await this._emitHook("after:update", { context, result });
1019
1062
  return result;
1020
1063
  } catch (error) {
1021
- this.emit("error:update", { context, error });
1064
+ await this._emitErrorHook("error:update", { context, error });
1022
1065
  throw this._handleError(error);
1023
1066
  }
1024
1067
  }
@@ -1030,14 +1073,14 @@ var Repository = class {
1030
1073
  try {
1031
1074
  if (context.softDeleted) {
1032
1075
  const result2 = { success: true, message: "Soft deleted successfully" };
1033
- await this.emitAsync("after:delete", { context, result: result2 });
1076
+ await this._emitHook("after:delete", { context, result: result2 });
1034
1077
  return result2;
1035
1078
  }
1036
1079
  const result = await deleteById(this.Model, id, options);
1037
- await this.emitAsync("after:delete", { context, result });
1080
+ await this._emitHook("after:delete", { context, result });
1038
1081
  return result;
1039
1082
  } catch (error) {
1040
- this.emit("error:delete", { context, error });
1083
+ await this._emitErrorHook("error:delete", { context, error });
1041
1084
  throw this._handleError(error);
1042
1085
  }
1043
1086
  }
@@ -1086,10 +1129,10 @@ var Repository = class {
1086
1129
  const context = await this._buildContext(operation, {});
1087
1130
  try {
1088
1131
  const result = await buildQuery(this.Model);
1089
- this.emit(`after:${operation}`, { context, result });
1132
+ await this._emitHook(`after:${operation}`, { context, result });
1090
1133
  return result;
1091
1134
  } catch (error) {
1092
- this.emit(`error:${operation}`, { context, error });
1135
+ await this._emitErrorHook(`error:${operation}`, { context, error });
1093
1136
  throw this._handleError(error);
1094
1137
  }
1095
1138
  }
@@ -1570,9 +1613,16 @@ function batchOperationsPlugin() {
1570
1613
  const context = await _buildContext.call(this, "updateMany", { query, data, options });
1571
1614
  try {
1572
1615
  this.emit("before:updateMany", context);
1616
+ if (Array.isArray(data) && options.updatePipeline !== true) {
1617
+ throw createError(
1618
+ 400,
1619
+ "Update pipelines (array updates) are disabled by default; pass `{ updatePipeline: true }` to explicitly allow pipeline-style updates."
1620
+ );
1621
+ }
1573
1622
  const result = await this.Model.updateMany(query, data, {
1574
1623
  runValidators: true,
1575
- session: options.session
1624
+ session: options.session,
1625
+ ...options.updatePipeline !== void 0 ? { updatePipeline: options.updatePipeline } : {}
1576
1626
  }).exec();
1577
1627
  this.emit("after:updateMany", { context, result });
1578
1628
  return result;
@@ -2239,8 +2289,8 @@ __export(actions_exports, {
2239
2289
  });
2240
2290
 
2241
2291
  // src/index.ts
2242
- function createRepository(Model, plugins = []) {
2243
- return new Repository(Model, plugins);
2292
+ function createRepository(Model, plugins = [], paginationConfig = {}, options = {}) {
2293
+ return new Repository(Model, plugins, paginationConfig, options);
2244
2294
  }
2245
2295
  var index_default = Repository;
2246
2296
  /**
@@ -1,4 +1,4 @@
1
- import { o as UserContext, F as FieldPreset, H as HttpError, N as CacheAdapter } from './types-vDtcOhyx.js';
1
+ import { q as UserContext, F as FieldPreset, H as HttpError, T as CacheAdapter } from './types-B3dPUKjs.js';
2
2
 
3
3
  /**
4
4
  * Field Selection Utilities
@@ -1,5 +1,5 @@
1
1
  import { Model } from 'mongoose';
2
- import { A as AnyDocument, P as PaginationConfig, O as OffsetPaginationOptions, a as OffsetPaginationResult, K as KeysetPaginationOptions, b as KeysetPaginationResult, c as AggregatePaginationOptions, d as AggregatePaginationResult } from '../types-vDtcOhyx.js';
2
+ import { A as AnyDocument, P as PaginationConfig, O as OffsetPaginationOptions, a as OffsetPaginationResult, K as KeysetPaginationOptions, b as KeysetPaginationResult, c as AggregatePaginationOptions, d as AggregatePaginationResult } from '../types-B3dPUKjs.js';
3
3
 
4
4
  /**
5
5
  * Pagination Engine
@@ -1,4 +1,4 @@
1
- import { F as FieldPreset, p as Plugin, L as Logger, B as SoftDeleteOptions, r as RepositoryInstance, y as ValidatorDefinition, z as ValidationChainOptions, R as RepositoryContext, Q as CacheOptions, Y as CascadeOptions } from '../types-vDtcOhyx.js';
1
+ import { F as FieldPreset, r as Plugin, L as Logger, I as SoftDeleteOptions, t as RepositoryInstance, B as ValidatorDefinition, G as ValidationChainOptions, i as RepositoryContext, W as CacheOptions, _ as CascadeOptions } from '../types-B3dPUKjs.js';
2
2
  import 'mongoose';
3
3
 
4
4
  /**
@@ -422,9 +422,16 @@ function batchOperationsPlugin() {
422
422
  const context = await _buildContext.call(this, "updateMany", { query, data, options });
423
423
  try {
424
424
  this.emit("before:updateMany", context);
425
+ if (Array.isArray(data) && options.updatePipeline !== true) {
426
+ throw createError(
427
+ 400,
428
+ "Update pipelines (array updates) are disabled by default; pass `{ updatePipeline: true }` to explicitly allow pipeline-style updates."
429
+ );
430
+ }
425
431
  const result = await this.Model.updateMany(query, data, {
426
432
  runValidators: true,
427
- session: options.session
433
+ session: options.session,
434
+ ...options.updatePipeline !== void 0 ? { updatePipeline: options.updatePipeline } : {}
428
435
  }).exec();
429
436
  this.emit("after:updateMany", { context, result });
430
437
  return result;
@@ -24,6 +24,13 @@ type PopulateSpec = string | string[] | PopulateOptions | PopulateOptions[];
24
24
  type SelectSpec = string | string[] | Record<string, 0 | 1>;
25
25
  /** Filter query type for MongoDB queries (compatible with Mongoose 8 & 9) */
26
26
  type FilterQuery<T> = Record<string, unknown>;
27
+ /** Hook execution mode */
28
+ type HookMode = 'sync' | 'async';
29
+ /** Repository options */
30
+ interface RepositoryOptions {
31
+ /** Whether repository event hooks are awaited */
32
+ hooks?: HookMode;
33
+ }
27
34
  /** Pagination configuration */
28
35
  interface PaginationConfig {
29
36
  /** Default number of documents per page (default: 10) */
@@ -253,12 +260,13 @@ interface RepositoryInstance {
253
260
  use(plugin: PluginType): this;
254
261
  on(event: string, listener: (data: any) => void | Promise<void>): this;
255
262
  emit(event: string, data: unknown): void;
263
+ emitAsync(event: string, data: unknown): Promise<void>;
256
264
  registerMethod?(name: string, fn: Function): void;
257
265
  hasMethod?(name: string): boolean;
258
266
  [key: string]: unknown;
259
267
  }
260
268
  /** Repository event names */
261
- type RepositoryEvent = 'before:create' | 'after:create' | 'error:create' | 'before:createMany' | 'after:createMany' | 'error:createMany' | 'before:update' | 'after:update' | 'error:update' | 'before:updateMany' | 'after:updateMany' | 'error:updateMany' | 'before:delete' | 'after:delete' | 'error:delete' | 'before:deleteMany' | 'after:deleteMany' | 'error:deleteMany' | 'before:getById' | 'after:getById' | 'before:getByQuery' | 'after:getByQuery' | 'before:getAll' | 'after:getAll' | 'before:aggregatePaginate' | 'method:registered';
269
+ type RepositoryEvent = 'before:create' | 'after:create' | 'error:create' | 'before:createMany' | 'after:createMany' | 'error:createMany' | 'before:update' | 'after:update' | 'error:update' | 'before:updateMany' | 'after:updateMany' | 'error:updateMany' | 'before:delete' | 'after:delete' | 'error:delete' | 'before:deleteMany' | 'after:deleteMany' | 'error:deleteMany' | 'before:getById' | 'after:getById' | 'before:getByQuery' | 'after:getByQuery' | 'before:getAll' | 'after:getAll' | 'before:aggregatePaginate' | 'method:registered' | 'error:hook';
262
270
  /** Event payload */
263
271
  interface EventPayload {
264
272
  context: RepositoryContext;
@@ -525,4 +533,4 @@ interface HttpError extends Error {
525
533
  }>;
526
534
  }
527
535
 
528
- export type { AnyDocument as A, SoftDeleteOptions as B, CreateOptions as C, DeleteResult as D, EventPayload as E, FieldPreset as F, LookupOptions as G, HttpError as H, GroupResult as I, JsonSchema as J, KeysetPaginationOptions as K, Logger as L, MinMaxResult as M, CacheAdapter as N, OffsetPaginationOptions as O, PaginationConfig as P, CacheOptions as Q, RepositoryContext as R, SelectSpec as S, CacheOperationOptions as T, UpdateOptions as U, ValidationResult as V, CacheStats as W, CascadeRelation as X, CascadeOptions as Y, OffsetPaginationResult as a, KeysetPaginationResult as b, AggregatePaginationOptions as c, AggregatePaginationResult as d, PluginType as e, PopulateSpec as f, SortSpec as g, ObjectId as h, AnyModel as i, SortDirection as j, PaginationResult as k, OperationOptions as l, UpdateManyResult as m, UpdateWithValidationResult as n, UserContext as o, Plugin as p, PluginFunction as q, RepositoryInstance as r, RepositoryEvent as s, ParsedQuery as t, FieldRules as u, SchemaBuilderOptions as v, CrudSchemas as w, DecodedCursor as x, ValidatorDefinition as y, ValidationChainOptions as z };
536
+ export type { AnyDocument as A, ValidatorDefinition as B, CreateOptions as C, DeleteResult as D, EventPayload as E, FieldPreset as F, ValidationChainOptions as G, HttpError as H, SoftDeleteOptions as I, JsonSchema as J, KeysetPaginationOptions as K, Logger as L, LookupOptions as M, GroupResult as N, OffsetPaginationOptions as O, PaginationConfig as P, MinMaxResult as Q, RepositoryOptions as R, SelectSpec as S, CacheAdapter as T, UpdateOptions as U, ValidationResult as V, CacheOptions as W, CacheOperationOptions as X, CacheStats as Y, CascadeRelation as Z, CascadeOptions as _, OffsetPaginationResult as a, KeysetPaginationResult as b, AggregatePaginationOptions as c, AggregatePaginationResult as d, PluginType as e, ObjectId as f, PopulateSpec as g, SortSpec as h, RepositoryContext as i, AnyModel as j, SortDirection as k, HookMode as l, PaginationResult as m, OperationOptions as n, UpdateManyResult as o, UpdateWithValidationResult as p, UserContext as q, Plugin as r, PluginFunction as s, RepositoryInstance as t, RepositoryEvent as u, ParsedQuery as v, FieldRules as w, SchemaBuilderOptions as x, CrudSchemas as y, DecodedCursor as z };
@@ -1,5 +1,5 @@
1
- export { b as createError, c as createFieldPreset, d as createMemoryCache, f as filterResponseData, g as getFieldsForUser, a as getMongooseProjection } from '../memory-cache-tn3v1xgG.js';
2
- import { t as ParsedQuery, v as SchemaBuilderOptions, w as CrudSchemas, V as ValidationResult, S as SelectSpec, f as PopulateSpec, g as SortSpec } from '../types-vDtcOhyx.js';
1
+ export { b as createError, c as createFieldPreset, d as createMemoryCache, f as filterResponseData, g as getFieldsForUser, a as getMongooseProjection } from '../memory-cache-Bn_-Kk-0.js';
2
+ import { v as ParsedQuery, x as SchemaBuilderOptions, y as CrudSchemas, V as ValidationResult, S as SelectSpec, g as PopulateSpec, h as SortSpec } from '../types-B3dPUKjs.js';
3
3
  import mongoose__default, { Schema } from 'mongoose';
4
4
 
5
5
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@classytic/mongokit",
3
- "version": "3.0.1",
3
+ "version": "3.0.2",
4
4
  "description": "Production-grade MongoDB repositories with zero dependencies - smart pagination, events, and plugins",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -91,6 +91,7 @@
91
91
  "devDependencies": {
92
92
  "@types/node": "^22.0.0",
93
93
  "@vitest/coverage-v8": "^3.2.4",
94
+ "mongodb-memory-server": "^10.2.3",
94
95
  "mongoose": "^9.0.0",
95
96
  "tsup": "^8.0.0",
96
97
  "typescript": "^5.7.0",