@ambiten/core 1.0.1 → 1.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.
- package/dist/index-browser.js +2 -2
- package/dist/index-browser.js.map +1 -1
- package/dist/index-cli.js +1 -1
- package/dist/index-cli.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lib-core/bootstrap/index.d.ts +1 -0
- package/dist/lib-core/bootstrap/index.d.ts.map +1 -1
- package/dist/lib-core/bootstrap/index.js +3 -0
- package/package.json +1 -1
package/dist/index-cli.js
CHANGED
|
@@ -22,5 +22,5 @@
|
|
|
22
22
|
documentUpdated(collection: String!): JSON
|
|
23
23
|
documentDeleted(collection: String!): JSON
|
|
24
24
|
}
|
|
25
|
-
`}defaultResolvers(){return{Query:{findOne:async(e,{collection:t,id:n},i)=>(await this.getCollection(i,t)).findOne({_id:new a.ObjectId(n)}),findAll:async(e,{collection:t},n)=>(await this.getCollection(n,t)).find({}).toArray()},Mutation:{insertOne:async(e,{collection:t,data:n},i)=>{const o=await this.getCollection(i,t),a=await o.insertOne(n),r=await o.findOne({_id:a.insertedId});return await this.publishEvent(`${s.DB_CHANGE_EVENT}`,{documentInserted:{action:"insertOne",collectionName:t,doc:r,tenantId:i.tenantId}}),r},updateOne:async(e,{collection:t,id:n,data:i},o)=>{const r=await this.getCollection(o,t);await r.updateOne({_id:new a.ObjectId(n)},{$set:i});const l=await r.findOne({_id:new a.ObjectId(n)});return await this.publishEvent(`${s.DB_CHANGE_EVENT}`,{documentUpdated:{action:"updateOne",collectionName:t,doc:l,tenantId:o.tenantId}}),l},deleteOne:async(e,{collection:t,id:n},i)=>{const o=await this.getCollection(i,t);return 1===(await o.deleteOne({_id:new a.ObjectId(n)})).deletedCount&&(await this.publishEvent(`${s.DB_CHANGE_EVENT}`,{documentDeleted:{action:"deleteOne",collectionName:t,id:n,tenantId:i.tenantId}}),!0)}},Subscription:{documentInserted:{subscribe:async()=>this.useRedis?(await this.ensureRedis(),this.subscriber):null},documentUpdated:{subscribe:async()=>this.useRedis?(await this.ensureRedis(),this.subscriber):null},documentDeleted:{subscribe:async()=>{if(this.useRedis)return await this.ensureRedis(),this.subscriber}}}}}subscriptions(){return this.useRedis}async generateSchema(){return await this.ensureRedis(),(0,i.makeExecutableSchema)({typeDefs:[this.defaultTypeDefs(),...this.typeDefs],resolvers:[this.defaultResolvers(),...this.resolvers]})}}},7234(e,t){"use strict";var n;Object.defineProperty(t,"__esModule",{value:!0}),t.ErrorType=void 0,function(e){e.AmbitenError="AmbitenError",e.AmbitenErrorType="AmbitenErrorType",e.AmbitenErrorStack="AmbitenErrorStack",e.AmbitenErrorMessage="AmbitenErrorMessage",e.AmbitenErrorCause="AmbitenErrorCause",e.AmbitenCollectionError="CollectionError",e.AmbitenParseError="ParseError",e.AmbitenBulkWriteError="MongoBulkWriteError",e.AmbitenConnectionError="ConnectionError",e.AmbitenSchemaError="SchemaError",e.AmbitenModelError="ModelError",e.INITIALIZATION_ERROR="INITIALIZATION_ERROR",e.Ambiten_ERROR="Ambiten_ERROR",e.NULL_OR_UNDEFINED="NULL_OR_UNDEFINED",e.INVALID_SCHEME_ERROR="INVALID_SCHEME_ERROR",e.CONNECTION_ERROR="CONNECTION_ERROR",e.UNEXPECTED_ERROR="UNEXPECTED_ERROR",e.SCHEMA_ERROR="SCHEMA_ERROR",e.SCHEMA_VALIDATION_ERROR="SCHEMA_VALIDATION_ERROR",e.NOT_FOUND="NOT_FOUND",e.NO_DATABASE_FOUND="NO_DATABASE_FOUND",e.NOT_FOUND_IN_CACHE="NOT_FOUND_IN_CACHE",e.VALIDATION_ERROR="VALIDATION_ERROR",e.UNIQUE_CONSTRAINT_VIOLATION="UNIQUE_CONSTRAINT_VIOLATION"}(n||(t.ErrorType=n={}))},7499(e){"use strict";e.exports=JSON.parse('{"$schema":"http://json-schema.org/draft-07/schema#","title":"Ambiten Configuration Schema","type":"object","additionalProperties":false,"properties":{"projectName":{"type":"string","description":"The name of the project."},"connection":{"type":"object","description":"MongoDB connection configuration used when no external provider is supplied at runtime.","properties":{"uri":{"type":"string","description":"MongoDB connection URI."},"options":{"type":"object","description":"Additional MongoDB client options."}},"required":["uri"],"additionalProperties":true},"multiTenant":{"type":"object","description":"Multi-tenant runtime configuration.","properties":{"enabled":{"type":"boolean","default":false},"headerKey":{"type":"string","default":"x-tenant-id","description":"Header used to resolve the tenant ID."},"tenants":{"type":"object","description":"Mapping of tenant IDs to MongoDB URIs.","additionalProperties":{"type":"string"}},"initOptions":{"type":"object","description":"Initialization options for multi-tenancy.","properties":{"lazy":{"type":"boolean","default":false},"retryAttempts":{"type":"integer","default":3},"config":{"type":"object"}},"additionalProperties":true}},"additionalProperties":false},"logger":{"type":"object","description":"Logger configuration.","properties":{"level":{"type":"string","enum":["debug","info","warn","error","fatal","trace"]},"colorize":{"type":"boolean"},"json":{"type":"boolean"},"transportConfigs":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["console","file","rotating-file"]},"options":{"type":"object"}},"additionalProperties":false}},"formatOptions":{"type":"object"},"excludedSources":{"type":"array","items":{"type":"string"}},"circuitBreaker":{"type":"object","properties":{"enabled":{"type":"boolean","default":true},"retryAttempts":{"type":"integer","default":5}},"additionalProperties":false},"enableMetrics":{"type":"object","properties":{"enabled":{"type":"boolean","default":false},"logInterval":{"type":"integer","minimum":1000,"default":60000}},"additionalProperties":false,"default":{"enabled":false,"logInterval":60000}},"compress":{"type":"object","properties":{"enabled":{"type":"boolean","default":false}},"additionalProperties":false,"default":{"enabled":false}}},"additionalProperties":true},"graphql":{"type":"object","description":"Optional GraphQL auto-generation/bootstrap feature. Useful for playgrounds, prototyping, and generated GraphQL flows.","properties":{"enabled":{"type":"boolean","default":false},"subscriptions":{"type":"boolean","default":false},"playground":{"type":"boolean","default":true},"schemaOutputPath":{"type":"string","default":"./src/graphql/schema.gql"}},"additionalProperties":false},"features":{"type":"object","description":"Optional feature paths and integrations.","properties":{"models":{"type":"string","default":"./src/models"},"schemas":{"type":"string","default":"./src/schemas"},"typeDefs":{"type":"string","default":"./src/graphql/typeDefs"},"resolvers":{"type":"string","default":"./src/graphql/resolvers"},"useRedisCache":{"type":"boolean","default":false},"redisUri":{"type":"string","default":""}},"additionalProperties":false},"advanced":{"type":"object","description":"Advanced runtime configuration.","properties":{"autoInstall":{"type":"boolean","default":false},"circuitBreaker":{"type":"object","properties":{"enabled":{"type":"boolean","default":true},"retryAttempts":{"type":"integer","default":5}},"additionalProperties":false},"garbageCollector":{"type":"object","description":"Garbage collector configuration.","properties":{"enabled":{"type":"boolean","default":false},"retentionPeriod":{"type":"integer","minimum":1,"default":30},"logResults":{"type":"boolean","default":true}},"additionalProperties":false},"gcCron":{"type":"string","default":"0 * * * *"}},"additionalProperties":false},"configVersion":{"type":"string","default":"1.0.0","description":"Version of the Ambiten config format."}}}')},7503(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.AuthService=void 0;const i=n(5584).__importDefault(n(829));n(4469);const o=process.env.JWT_SECRET,a=process.env.REFRESH_SECRET,r=process.env.REFRESH_EXPIRATION||"7d",s=process.env.JWT_EXPIRATION||"1d";t.AuthService=class{static generateToken(e){return i.default.sign(e,o,{expiresIn:s})}static generateRefreshToken(e){return i.default.sign(e,a,{expiresIn:r})}static verifyToken(e){return i.default.verify(e,o)}}},7584(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0})},7624(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.isValidObjectId=void 0,t.isObjectId=a,t.castId=function(e){if("string"==typeof e){const n=e;if(!(0,t.isValidObjectId)(n))throw new Error("Invalid ObjectId format in castId");if(!a(e))throw new Error("Invalid ObjectId in castId");return o.ObjectId.createFromHexString(n)}return e};const i=n(529),o=n(2518);function a(e){return null!=e&&"object"==typeof e&&e.constructor===o.ObjectId&&!0===e[i.objectIdSymbol]}Object.defineProperty(o.ObjectId.prototype,"_id",{configurable:!0,enumerable:!0,get:function(){return this.toHexString()}}),Object.prototype.hasOwnProperty.call(o.ObjectId.prototype,"valueOf")||(o.ObjectId.prototype.valueOf=function(){return this.toString()}),t.isValidObjectId=e=>/^[0-9a-fA-F]{24}$/.test(e),o.ObjectId.prototype.toJSON=function(){return this.toHexString()},o.ObjectId.prototype[i.objectIdSymbol]=!0},7743(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),n(5584).__exportStar(n(2999),t)},7803(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=n(5584);i.__exportStar(n(2590),t),i.__exportStar(n(6941),t),i.__exportStar(n(8183),t)},7825(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.ensureModelNameSafe=function(e){if(!e||"string"!=typeof e)throw new Error("Model name must be a non-empty string");const t=e.trim();if(0===t.length)throw new Error("Model name cannot be just whitespace");if(!/^[A-Za-z0-9_]+$/.test(t))throw new Error("Model name must only contain letters, numbers, and underscores");return t}},7858(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getModelFilesFromPath=r,t.loadModelsFromPath=async function(e){const t=r(e),i=[];for(const e of t)try{const t=await n(1077)(e);t.default?i.push(t.default):console.warn(`No default export found in ${e}`)}catch(t){console.error(`Error loading model from ${e}:`,t)}return i};const i=n(5584),o=i.__importDefault(n(9896)),a=i.__importDefault(n(6928));function r(e){const t=[];return o.default.readdirSync(e).forEach(n=>{const i=a.default.join(e,n);o.default.statSync(i).isDirectory()?t.push(...r(i)):/\.(ts|js)$/.test(n)&&t.push(i)}),t}},7900(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),n(5584).__exportStar(n(7221),t)},8093(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=n(5584);i.__exportStar(n(8781),t),i.__exportStar(n(6013),t),i.__exportStar(n(3904),t),i.__exportStar(n(9001),t)},8183(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.authorize=function(e){return(t,n,o)=>{let a;const r=t.headers?.authorization||t.headers.Authorization;if("string"==typeof r&&r.startsWith("Bearer ")&&(a=r.split(" ")[1]),!a)return n.status(401).json({error:"Access token required"});try{const t=i.AuthService.verifyToken(a);return console.info(`Decoded token: ${JSON.stringify(t)}`),t?e.includes(t.role)?t:n.status(403).json({error:"Access Denied"}):n.status(401).json({error:"Unauthorized"})}catch{n.status(401).json({error:"Unauthorized"})}}};const i=n(7503)},8686(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.AmbitenModelRegistry=void 0,t.clearModelRegistryForTests=function(){for(const e of i)t.AmbitenModelRegistry.unregisterModel(e);i.length=0};const n=new Set;t.AmbitenModelRegistry={registerModel(e){n.add(e)},getRegisteredModel:e=>n.has(e)?e:null,isModelRegistered:e=>n.has(e),unregisterModel(e){n.delete(e)},getAllModels:()=>[...n],clear(){n.clear()}};const i=[]},8742(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=n(5584);i.__exportStar(n(3057),t),i.__exportStar(n(7038),t),i.__exportStar(n(5303),t)},8781(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.AmbitenGC=void 0;const i=n(5584).__importStar(n(2703)),o=n(960),a=n(3904);t.AmbitenGC=class{options;enabled;intervalMs;intervalRef=null;cronTask=null;constructor(e={}){if(this.options=e,this.enabled=!1!==e.enabled,this.intervalMs=e.interval?this.parseInterval(e.interval):6e4,e.retentionPeriod&&(this.intervalMs=24*e.retentionPeriod*60*60*1e3),this.enabled)return e.cron?(this.cronTask=i.schedule(e.cron,()=>{this.runOnce()}),void this.log("info",`[AmbitenGC] Cron schedule set to: ${e.cron}`)):e.interval?(this.start(),void this.log("info",`[AmbitenGC] Interval set to: ${e.interval}`)):void this.log("info","[AmbitenGC] Initialized. Manual run mode enabled.");this.log("info","[AmbitenGC] Garbage Collector is disabled.")}start(){this.enabled&&(this.intervalRef||(this.intervalRef=setInterval(()=>{this.runOnce()},this.intervalMs),this.log("info",`[AmbitenGC] Started GC loop every ${this.intervalMs} ms`)))}stop(){this.intervalRef&&(clearInterval(this.intervalRef),this.intervalRef=null),this.cronTask&&(this.cronTask.stop(),this.cronTask=null),this.log("info","[AmbitenGC] Stopped.")}async runOnce(e){if(!this.enabled)return{scanned:0,succeeded:0,failed:0,models:[]};const t=await(0,a.runGarbageCollectorOnAllModels)({ctx:e??this.options.ctx,continueOnError:this.options.continueOnError??!0});return this.options.logResults&&this.log(t.failed>0?"warn":"info",`[AmbitenGC] Completed. scanned=${t.scanned}, succeeded=${t.succeeded}, failed=${t.failed}`),t}parseInterval(e){const t=e.match(/^(\d+)([smhd])$/);if(!t)throw new Error(`Invalid interval format: ${e}`);const[,n,i]=t,o=Number.parseInt(n,10);switch(i){case"s":return 1e3*o;case"m":return 60*o*1e3;case"h":return 60*o*60*1e3;case"d":return 24*o*60*60*1e3;default:throw new Error(`Unknown time unit: ${i}`)}}log(e,t,n){const i=this.options.logger;i?.[e]?i[e]?.(t,n):"error"!==e?"warn"!==e?console.log((0,o.colorize)(t,"blue"),n??""):console.warn((0,o.colorize)(t,"yellow"),n??""):console.error((0,o.colorize)(t,"red"),n??"")}}},8917(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.invalidateTenantCache=async function(e,t,n){const i=n?`ambiten:${t}:${n}:*`:`ambiten:${t}:*`,o=await e.keys(i);o.length&&(await e.del(o),console.info(`🔁 Cleared ${o.length} cache entries for ${t}${n?` (${n})`:""}`))}},8952(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.eventTypes=void 0,t.eventTypes=["pre-save","post-save","pre-update","post-update","pre-delete","post-delete","aggregate","disconnect","connect","dropDatabase","createIndex","dropIndex","create","find","findOne","insertOne","insertMany","updateOne","updateMany","deleteOne","deleteMany","transaction"]},9001(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.startGarbageCollector=void 0;const i=n(960);t.startGarbageCollector=()=>{console.warn((0,i.colorize)("[GC] Garbage collector is disabled in the browser.","red"))}},9228(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.measureQuery=async function(e,t){if(!o.AmbitenContext.hasActiveContext())throw new Error("[Ambiten] Missing runtime context.");const n=o.AmbitenContext.getLogger(),a=o.AmbitenContext.getObserver(),r=o.AmbitenContext.getLoggerMeta()??{},s=o.AmbitenContext.getTenantId(),l=o.AmbitenContext.getRequestId(),c=o.AmbitenContext.getDbName(),d=e.collectionName??o.AmbitenContext.getCollectionName(),u=o.AmbitenContext.incrementQueries(),m=i.performance.now();try{const h=await t(),p=Math.round(100*(i.performance.now()-m))/100,f=o.AmbitenContext.addQueryTime(p),g={operation:e.operation,collectionName:d,durationMs:p,status:"success",tenantId:s,requestId:l,dbName:c,filter:e.filter,update:e.update,pipeline:e.pipeline,documentCount:e.documentCount,queriesExecuted:u.queriesExecuted,maxQueries:u.maxQueries,totalBudgetUsed:f.totalTimeMs,...r,...e.extra??{}};return setImmediate(()=>{a?.onQuery?.(g),n?.info?n.info("[Ambiten Query]",g):o.AmbitenContext.isDebug()&&console.log("[Ambiten Query]",g)}),h}catch(t){const u=Math.round(100*(i.performance.now()-m))/100,h=o.AmbitenContext.addQueryTime(u),p={operation:e.operation,collectionName:d,durationMs:u,status:"error",tenantId:s,requestId:l,dbName:c,filter:e.filter,update:e.update,pipeline:e.pipeline,documentCount:e.documentCount,queriesExecuted:h.queriesExecuted,maxQueries:h.maxQueries,totalBudgetUsed:h.totalTimeMs,errorMessage:t?.message,errorName:t?.name,...r,...e.extra??{}};throw setImmediate(()=>{a?.onQueryError?.({...p,error:t}),n?.error?n.error("[Ambiten Query Error]",p):o.AmbitenContext.isDebug()&&console.error("[Ambiten Query Error]",p)}),t}};const i=n(2987),o=n(3057)},9451(e){"use strict";e.exports=require("@ambiten/logger")},9490(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),n(5584).__exportStar(n(1891),t)},9493(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.AmbitenModel=void 0;const i=n(5584);n(4469);const o=n(2518),a=n(1679),r=n(6903),s=i.__importDefault(n(4434)),l=n(3946),c=n(901),d=n(3868),u=n(960),m=n(8742),h=n(3907),p=n(9490),f=new l.PubSub;class g{_provider;_collectionName;_collectionOverride;_schema;_initialized=!1;_defaultCtx;_modelGCConfig;_gcConfig;_gcTimer;eventEmitter=new s.default;beforeMiddlewares=new Map;afterMiddlewares=new Map;_softDeleteConfig;constructor(e){if(!e){const t="AmbitenModel options are required.";throw(0,u.createAmbitenError)(u.ErrorType.NULL_OR_UNDEFINED,t,{details:{providedOptions:e,typeError:u.ErrorType.AmbitenModelError}})}if(!e.collectionName){const t="collectionName is required.";throw(0,u.createAmbitenError)(u.ErrorType.NULL_OR_UNDEFINED,t,{details:{providedOptions:e,typeError:u.ErrorType.AmbitenModelError}})}if(this._collectionName=e.collectionName,this._schema=e.schema??new r.AmbitenSchema({}),this._provider=e.provider??a.AmbitenClient.init(),this._collectionOverride=e.collection,this._modelGCConfig=e.gcConfig,e.ctx?.db){const t=e.ctx.db;this._provider={db:async()=>t}}(e.ctx?.tenantId||e.ctx?.dbName||e.ctx?.collectionName)&&(this._defaultCtx={tenantId:e.ctx?.tenantId,dbName:e.ctx?.dbName,collectionName:e.ctx?.collectionName,db:e.ctx?.db,session:e.ctx?.session,config:e.ctx?.config});const t=this.resolveSchemaGCConfig();(this.isGCEnabled()||t)&&u.AmbitenModelRegistry.registerModel(this),this.initMiddleware()}mergeCtx(e){const t=m.AmbitenContext.get(),n={tenantId:e?.tenantId??this._defaultCtx?.tenantId??t.tenantId,dbName:e?.dbName??this._defaultCtx?.dbName??t.dbName,db:e?.db??this._defaultCtx?.db,collectionName:e?.collectionName??this._defaultCtx?.collectionName??t.collectionName,config:e?.config??this._defaultCtx?.config,session:e?.session??this._defaultCtx?.session??t.session,withDeleted:e?.withDeleted,onlyDeleted:e?.onlyDeleted,hardDelete:e?.hardDelete};return Object.values(n).some(e=>void 0!==e)?n:void 0}async runWithModelContext(e,t){if(m.AmbitenContext.hasActiveContext())return t();const n=this.mergeCtx(e);return m.AmbitenContext.run({tenantId:n?.tenantId,dbName:n?.dbName,collectionName:n?.collectionName??this._collectionName,session:n?.session},t)}isGCEnabled(){return!0===this._modelGCConfig?.enableGC}resolveSchemaGCConfig(){return this._schema.getGCConfig?.()}async getCollection(e){if(this._collectionOverride)return this._collectionOverride;this.ensureConfigured();const t=await this.resolveDb(e),n=this.resolveCollectionName(e);return(0,p.debugLog)("Resolved collection",{collectionName:n,dbName:t.databaseName,tenantId:this.mergeCtx(e)?.tenantId}),t.collection(n)}getResolvedTenant(e){const t=c.MultiTenantManager.getTenant(e);if(!t)throw new Error(`Tenant "${e}" is not registered.`);return{...t}}async resolveDb(e){const t=this.mergeCtx(e);if(t?.db)return t.db;if(t?.tenantId){const e=this.getResolvedTenant(t.tenantId),n=await c.MultiTenantManager.getClient(t.tenantId);if(!n)throw new Error(`MongoClient for tenant "${t.tenantId}" is not available.`);const i=t.dbName??e.dbName;if(!i)throw new Error(`No database name configured for tenant "${t.tenantId}".`);return n.db(i)}const n=await this._provider.db(t);if(!n||"function"!=typeof n.collection)throw new Error(`AmbitenModel: provider.db() did not return a valid Db instance for collection "${this._collectionName}".`);return n}resolveCollectionName(e){const t=this.mergeCtx(e),n=t?.collectionName??this._collectionName;if(!n||"string"!=typeof n||!n.trim())throw new Error("AmbitenModel: collectionName is not configured.");return n.trim()}resolveSession(e){return this.mergeCtx(e)?.session}resolveSessionStrict(e,t){return t??e?.session??m.AmbitenContext.getSession()}on(e,t){this.eventEmitter.on(e,t)}once(e,t){this.eventEmitter.once(e,t)}off(e,t){this.eventEmitter.off(e,t)}removeListener(e,t){this.eventEmitter.removeListener(e,t)}ensureConfigured(){if(!this._collectionName||"string"!=typeof this._collectionName)throw new Error("AmbitenModel: collectionName is not configured.");if(!this._provider||"function"!=typeof this._provider.db)throw new Error("AmbitenModel: provider is not configured. Provide a valid DbProvider with a db(ctx) method.")}async init(){if(!this._initialized)try{this.ensureConfigured(),this._schema||(this._schema=new r.AmbitenSchema({})),await this.getCollection(),this.isGCEnabled()&&this._modelGCConfig&&await this.ensureGCIndex(this._modelGCConfig),this._initialized=!0}catch(e){throw(0,u.createAmbitenError)(u.ErrorType.INITIALIZATION_ERROR,`Failed to initialize AmbitenModel: ${e?.message??String(e)}`,{details:{operation:"init",TypeError:u.ErrorType.INITIALIZATION_ERROR}})}}bind(e){const t=Object.create(this);return t._defaultCtx={...this._defaultCtx,...e},t}async registerModel(e){const{ctx:t,collectionName:n,schema:i,collection:o}=e;if(!n)throw new Error("Collection name is required.");this._collectionName=n,this._collectionOverride=o,this._schema=i??new r.AmbitenSchema({}),t&&(this._defaultCtx={...this._defaultCtx,...t}),this._initialized=!1,this.ensureConfigured(),await this.init()}async ensureGCIndex(e){if(!e.enableGC||!e.ttl)return;const t=await this.getCollection(),n=e.field??e.updatedAtField??e.createdAtField??"updatedAt";await t.createIndex({[n]:1},{expireAfterSeconds:e.ttl,name:e.indexName??`${this._collectionName}_${n}_ttl`,background:!0})}get schema(){return this._schema}getSchema(){return this.schema}validate(e){this._schema&&this._schema.validate(e)}async validateAsync(e){return this._schema&&await this._schema.validateAsync(e),e}initMiddleware(){this._schema&&(this._schema.pre("create",async e=>{const t=e.doc;if(!t)return;const n=this._schema.getRelationships()??[];for(const{ref:e,localField:i}of n){const n=(await this.getCollection()).db?.collection(e),o={[i]:t._id};await(n?.updateMany(o,{$set:{[i]:t._id}}))}}),this._schema.post("create",async e=>{const t=e.result??e.doc;if(!t)return;const n=this._schema.getRelationships()??[];for(const{ref:e,localField:i}of n){const n=(await this.getCollection()).db?.collection(e),o={[i]:t._id};await(n?.updateOne(o,{$set:{[i]:t._id}}))}await f.publish("DB_CHANGE",{dbChange:{action:"create",doc:t}})}),this._schema.post("updateOne",async e=>{const t=e.filter,n=e.update;if(!t||!n)return;const i=this._schema.getRelationships()??[];for(const{ref:e,localField:t}of i){const i=(await this.getCollection()).db?.collection(e),o={[t]:n.$set?._id};await(i?.updateOne(o,{$set:{[t]:n.$set?._id}}))}await f.publish("DB_CHANGE",{dbChange:{action:"updateOne",filter:t,update:n}})}),this._schema.pre("deleteOne",async e=>{const t=e.doc??e.result;if(!t)return;const n=this._schema.getRelationships()??[];for(const{ref:e,localField:i}of n){const n=(await this.getCollection()).db?.collection(e),o={[i]:t._id};await(n?.deleteOne(o))}}),this._schema.pre("aggregate",async e=>{const t=e.pipeline;if(!t)return;const n=this._schema.getRelationships()??[];for(const{ref:e,localField:i}of n)t.unshift({$lookup:{from:e,localField:i,foreignField:"_id",as:e}})}),this._schema.post("aggregate",async e=>{const t=e.result;if(!t)return;const n=this._schema.getRelationships()??[];for(const e of t)for(const{ref:t}of n)delete e[t];await f.publish("DB_CHANGE",{dbChange:{action:"aggregate",result:t}})}))}async create(e,t){if(await this.init(),!e||"object"!=typeof e)throw new Error("Document must be a valid object.");return this.runWithModelContext(t,async()=>(0,h.measureQuery)({operation:"create",collectionName:this.resolveCollectionName(t),documentCount:1},async()=>{const n=this.resolveCollectionName(t),i=this.resolveSession(t),o=await this.getCollection(t),a=this.buildMiddlewareContext("create",t,{doc:e});a.collectionName=a.collectionName??n,await this.runBeforeMiddlewares("create",a);const r=a.doc??e;a.doc=r,this.validate(r),await this.schema.executePre("create",this.buildHookPayload("create",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,doc:r,meta:a.meta}));const s=await o.insertOne(r,i?{session:i}:void 0),l={...r,_id:s.insertedId};await this.schema.executePost("create",this.buildHookPayload("create",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,doc:l,result:l,meta:a.meta}));const c=this.toModelResult(l);a.result=c,await this.runAfterMiddlewares("create",a);const d=a.result??c;return await this.invalidateCachePatterns("create",a),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentInserted:{action:"create",collectionName:a.collectionName,doc:d,meta:a.meta}}),d}))}async find(e={},t,n){if(await this.init(),!e||"object"!=typeof e)throw new Error("Filter must be a valid object.");return this.runWithModelContext(t,async()=>(0,h.measureQuery)({operation:"find",collectionName:this.resolveCollectionName(t),filter:e},async()=>{const i=this.resolveCollectionName(t),o=this.resolveSession(t),a=await this.getCollection(t),r=this.buildMiddlewareContext("find",t,{filter:e});r.collectionName=r.collectionName??i,await this.runBeforeMiddlewares("find",r);const s=r.filter??e;r.filter=s;const l=n?.cache?this.resolveCache(n):null;await this.schema.executePre("find",this.buildHookPayload("create",t,{collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:o,filter:s,meta:r.meta}));let c=null;if(l){c=this.buildCacheKey("find",{collectionName:r.collectionName,filter:s,tenantId:r.tenantId,dbName:r.dbName});const e=await l.get(c,{ttlSeconds:"object"==typeof n?.cache?n.cache.ttl:void 0,tenantId:r.tenantId,namespace:r.collectionName});if(e)return r.result=e,await this.schema.executePost("find",this.buildHookPayload("find",t,{collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:o,filter:s,result:e,meta:{...r.meta??{},cacheHit:!0}})),await this.runAfterMiddlewares("find",r),r.result??e}const d=a.find(s,o?{session:o}:void 0),u=await d.toArray(),m=this.toModelResults(u);await this.schema.executePost("find",this.buildHookPayload("find",t,{collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:o,filter:s,result:m,meta:r.meta})),r.result=m,await this.runAfterMiddlewares("find",r);const h=r.result??m;return l&&c&&await l.set(c,h,{ttlSeconds:"object"==typeof n?.cache?n.cache.ttl:void 0,tenantId:r.tenantId,namespace:r.collectionName}),h}))}async findOne(e,t,n){if(await this.init(),!e||"object"!=typeof e)throw new Error("Filter must be a valid object.");return this.runWithModelContext(t,async()=>(0,h.measureQuery)({operation:"findOne",collectionName:this.resolveCollectionName(t),filter:e},async()=>{const i=this.resolveCollectionName(t),o=this.resolveSession(t),a=await this.getCollection(t),r=this.buildMiddlewareContext("findOne",t,{filter:e});r.collectionName=r.collectionName??i,await this.runBeforeMiddlewares("findOne",r);const s=r.filter??e;r.filter=s;const l=n?.cache?this.resolveCache(n):null;let c=null;if(await this.schema.executePre("findOne",this.buildHookPayload("findOne",t,{collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:o,filter:s,meta:r.meta})),l){c=this.buildCacheKey("findOne",{collectionName:r.collectionName,filter:s,tenantId:r.tenantId,dbName:r.dbName});const e=await l.get(c,{ttlSeconds:"object"==typeof n?.cache?n.cache.ttl:void 0,tenantId:r.tenantId,namespace:r.collectionName});if(null!=e)return r.result=e,await this.schema.executePost("findOne",this.buildHookPayload("findOne",t,{collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:o,filter:s,result:e,meta:{...r.meta??{},cacheHit:!0}})),await this.runAfterMiddlewares("findOne",r),r.result??e}const d=await a.findOne(s,o?{session:o}:void 0),u=d?this.toModelResult(d):null;await this.schema.executePost("findOne",{operation:"findOne",collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:o,filter:s,result:u,meta:r.meta}),r.result=u,await this.runAfterMiddlewares("findOne",r);const m=r.result??u;return l&&c&&null!==m&&await l.set(c,m,{ttlSeconds:"object"==typeof n?.cache?n.cache.ttl:void 0,tenantId:r.tenantId,namespace:r.collectionName}),m}))}async updateOne(e,t,n){if(await this.init(),!e||"object"!=typeof e)throw new Error("Filter must be a valid object.");if(!t||"object"!=typeof t)throw new Error("Update must be a valid object.");return this.runWithModelContext(n,async()=>(0,h.measureQuery)({operation:"updateOne",collectionName:this.resolveCollectionName(n),filter:e,update:t},async()=>{const i=this.resolveCollectionName(n),o=this.resolveSession(n),a=await this.getCollection(n),r=this.buildMiddlewareContext("updateOne",n,{filter:e,update:t});r.collectionName=r.collectionName??i,await this.runBeforeMiddlewares("updateOne",r);const s=r.filter??e,l=r.update??t;r.filter=s,r.update=l,await this.schema.executePre("updateOne",{operation:"updateOne",collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:o,filter:s,update:l,meta:r.meta});const c=await a.updateOne(s,l,o?{session:o}:void 0),d={acknowledged:c?.acknowledged,matchedCount:c?.matchedCount,modifiedCount:c?.modifiedCount,upsertedCount:c?.upsertedCount,upsertedId:c?.upsertedId};await this.schema.executePost("updateOne",{operation:"updateOne",collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:o,filter:s,update:l,result:d,meta:r.meta}),r.result=d,await this.runAfterMiddlewares("updateOne",r),await this.invalidateCachePatterns("updateOne",r),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentUpdated:{action:"updateOne",collectionName:r.collectionName,filter:s,update:l,result:d,meta:r.meta}})}))}async bulkInsert(e,t){if(await this.init(),Array.isArray(e)&&0!==e.length)return this.runWithModelContext(t,async()=>(0,h.measureQuery)({operation:"bulkInsert",collectionName:this.resolveCollectionName(t),documentCount:e.length},async()=>{const n=this.resolveCollectionName(t),i=this.resolveSession(t),o=await this.getCollection(t),a=this.buildMiddlewareContext("bulkInsert",t,{docs:e});a.collectionName=a.collectionName??n,await this.runBeforeMiddlewares("bulkInsert",a);const r=a.docs??e;if(a.docs=r,!Array.isArray(r)||0===r.length)return a.result=[],void await this.runAfterMiddlewares("bulkInsert",a);for(const e of r){if(!e||"object"!=typeof e)throw new Error("Each document must be a valid object.");this.validate(e)}const s=this.buildOperationMeta(a.meta,{bulkWrite:!0});await this.schema.executePre("bulkInsert",this.buildHookPayload("bulkInsert",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,docs:r,meta:s}));const l=await o.insertMany(r,{ordered:!1,...i?{session:i}:{}}),c=r.map((e,t)=>({...e,_id:l.insertedIds[t]}));await this.schema.executePost("bulkInsert",this.buildHookPayload("bulkInsert",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,docs:c,result:c,meta:s})),a.result=this.toModelResults(c),await this.runAfterMiddlewares("bulkInsert",a),await this.invalidateCachePatterns("bulkInsert",a),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentInserted:{action:"bulkInsert",collectionName:a.collectionName,docs:a.result,meta:s}})}))}async bulkUpdate(e,t){if(await this.init(),!Array.isArray(e))throw new Error("Updates must be a valid array.");if(0!==e.length)return this.runWithModelContext(t,async()=>(0,h.measureQuery)({operation:"bulkUpdate",collectionName:this.resolveCollectionName(t),documentCount:e.length},async()=>{const n=this.resolveCollectionName(t),i=this.resolveSession(t),o=await this.getCollection(t),a=this.buildMiddlewareContext("bulkUpdate",t,{bulkUpdates:e});a.collectionName=a.collectionName??n,await this.runBeforeMiddlewares("bulkUpdate",a);const r=a.bulkUpdates??e;a.bulkUpdates=r;const s=this.buildOperationMeta(a.meta,{bulkWrite:!0});if(a.meta=s,!Array.isArray(r)||0===r.length)return a.result={acknowledged:!0,matchedCount:0,modifiedCount:0,upsertedCount:0,insertedCount:0,deletedCount:0},void await this.runAfterMiddlewares("bulkUpdate",a);for(const e of r){if(!e||"object"!=typeof e)throw new Error("Each bulk update entry must be a valid object.");if(!e.filter||"object"!=typeof e.filter)throw new Error("Each bulk update filter must be a valid object.");if(!e.update||"object"!=typeof e.update)throw new Error("Each bulk update document must be a valid object.")}const l=r.map(({filter:e,update:t})=>({updateOne:{filter:e,update:{$set:t}}}));await this.schema.executePre("bulkUpdate",this.buildHookPayload("bulkUpdate",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,bulkUpdates:r,meta:s}));const c=await o.bulkWrite(l,{ordered:!1,...i?{session:i}:{}}),d={acknowledged:c?.isOk?.()??!0,matchedCount:c?.matchedCount,modifiedCount:c?.modifiedCount,upsertedCount:c?.upsertedCount,insertedCount:c?.insertedCount,deletedCount:c?.deletedCount};await this.schema.executePost("bulkUpdate",this.buildHookPayload("bulkUpdate",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,bulkUpdates:r,result:d,meta:s})),a.result=d,await this.runAfterMiddlewares("bulkUpdate",a),await this.invalidateCachePatterns("bulkUpdate",a),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentUpdated:{action:"bulkUpdate",collectionName:a.collectionName,bulkUpdates:r,result:d,meta:s}})}))}async deleteOne(e,t){if(await this.init(),!e||"object"!=typeof e)throw new Error("Filter must be a valid object.");return this.runWithModelContext(t,async()=>(0,h.measureQuery)({operation:"deleteOne",collectionName:this.resolveCollectionName(t),filter:e},async()=>{const n=this.resolveCollectionName(t),i=this.resolveSession(t),o=await this.getCollection(t),a=this.buildMiddlewareContext("deleteOne",t,{filter:e});a.collectionName=a.collectionName??n,await this.runBeforeMiddlewares("deleteOne",a);const r=a.filter??e;a.filter=r;const s=await o.findOne(r,i?{session:i}:void 0);if(!s)return a.result=null,void await this.runAfterMiddlewares("deleteOne",a);const l=this.toModelResult(s);a.result=l;const c=this.buildOperationMeta(a.meta);if(a.meta=c,!0===c.softDelete){const e=a.update;if(!e)throw new Error("Soft delete is enabled but no soft delete update payload was provided.");await this.schema.executePre("updateOne",this.buildHookPayload("deleteOne",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,filter:r,update:e,result:l,meta:c})),await o.updateOne(r,e,i?{session:i}:void 0),await this.schema.executePost("updateOne",this.buildHookPayload("deleteOne",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,filter:r,update:e,result:l,meta:c}))}else await this.schema.triggerMiddleware("pre","deleteOne",{operation:"deleteOne",collectionName:a.collectionName,...l}),await this.schema.executePre("deleteOne",this.buildHookPayload("deleteOne",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,doc:l,result:l,meta:c})),await o.deleteOne(r,i?{session:i}:void 0),await this.schema.triggerMiddleware("post","deleteOne",{operation:"deleteOne",collectionName:a.collectionName,...l}),await this.schema.executePost("deleteOne",this.buildHookPayload("deleteOne",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,doc:l,result:l,meta:c}));await this.runAfterMiddlewares("deleteOne",a),await this.invalidateCachePatterns("deleteOne",a),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentDeleted:{action:c.softDelete?"softDelete":"deleteOne",collectionName:a.collectionName,filter:r,meta:a.meta}})}))}async deleteMany(e,t){if(await this.init(),!e||"object"!=typeof e)throw new Error("Filter must be a valid object.");return this.runWithModelContext(t,async()=>(0,h.measureQuery)({operation:"deleteMany",collectionName:this.resolveCollectionName(t),filter:e},async()=>{const n=this.resolveCollectionName(t),i=this.resolveSession(t),o=await this.getCollection(t),a=this.buildMiddlewareContext("deleteMany",t,{filter:e});a.collectionName=a.collectionName??n,await this.runBeforeMiddlewares("deleteMany",a);const r=a.filter??e;a.filter=r;const s=this.buildOperationMeta(a.meta);a.meta=s;const l=await o.find(r,i?{session:i}:void 0).toArray();if(0===l.length)return a.result={deletedCount:0,docs:[]},void await this.runAfterMiddlewares("deleteMany",a);const c=this.toModelResults(l);if(!0===s.softDelete){const e=a.update;if(!e)throw new Error("Soft delete is enabled but no soft delete update payload was provided.");const n=this.buildOperationMeta(s,{softDelete:!0});await this.schema.executePre("updateMany",this.buildHookPayload("deleteMany",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,filter:r,update:e,docs:l,result:c,meta:n}));const d={deletedCount:(await o.updateMany(r,e,i?{session:i}:void 0)).modifiedCount,docs:c,softDeleted:!0};await this.schema.executePost("updateMany",this.buildHookPayload("deleteMany",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,filter:r,update:e,docs:l,result:d,meta:n})),a.result=d}else{await this.schema.triggerMiddleware("pre","deleteMany",{operation:"deleteMany",collectionName:a.collectionName,docs:l}),await this.schema.executePre("deleteMany",this.buildHookPayload("deleteMany",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,docs:l,result:c,meta:s}));const e=await o.deleteMany(r,i?{session:i}:void 0),n={deletedCount:e?.deletedCount??0,docs:c};await this.schema.triggerMiddleware("post","deleteMany",{operation:"deleteMany",collectionName:a.collectionName,docs:l}),await this.schema.executePost("deleteMany",this.buildHookPayload("deleteMany",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,docs:l,result:n,meta:s})),a.result=n}await this.runAfterMiddlewares("deleteMany",a),await this.invalidateCachePatterns("deleteMany",a),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentDeleted:{action:s.softDelete?"softDeleteMany":"deleteMany",collectionName:a.collectionName,filter:r,result:a.result,meta:a.meta}})}))}async populateOne(e,t,n){if(await this.init(),!e||"object"!=typeof e)return null;const i=e[t];if(null==i)return e;const o=await n.findOne({_id:i});return{...e,[t]:o}}async populateMany(e,t,n){if(await this.init(),!e||"object"!=typeof e)return null;const i=e[t];if(!Array.isArray(i)||0===i.length)return e;const o=await n.find({_id:{$in:i}});return{...e,[t]:o}}async createWithTransaction(e,t){if(await this.init(),!e||"object"!=typeof e)throw new Error("Document must be a valid object.");return this.runWithModelContext(t,async()=>this.withTransaction(async()=>(0,h.measureQuery)({operation:"create",collectionName:this.resolveCollectionName(t),documentCount:1},async()=>{const n=this.resolveCollectionName(t),i=this.resolveSession(t),o=await this.getCollection(t),a=this.buildMiddlewareContext("create",t,{doc:e,meta:{transactional:!0}});a.collectionName=a.collectionName??n,await this.runBeforeMiddlewares("create",a);const r=a.doc??e;a.doc=r;const s=this.buildOperationMeta(a.meta,{transactional:!0});this.validate(r),await this.schema.executePre("create",this.buildHookPayload("create",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,doc:r,meta:s}));const l=await o.insertOne(r,i?{session:i}:void 0),c={...r,_id:l.insertedId};await this.schema.executePost("create",this.buildHookPayload("create",t,{operation:"create",collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,doc:c,result:c,meta:s}));const d=this.toModelResult(c);a.result=d,await this.runAfterMiddlewares("create",a),await this.invalidateCachePatterns("create",a);const m=a.result??d;return await f.publish(`${u.DB_CHANGE_EVENT}`,{documentInserted:{action:"create",collectionName:a.collectionName,doc:m,meta:s}}),m}),t))}async bulkWriteWithTransaction(e,t={},n){if(await this.init(),!Array.isArray(e))throw new Error("Operations must be a valid array.");if(0===e.length)throw new Error("Operations array must not be empty.");return this.runWithModelContext(n,async()=>this.withTransaction(async()=>(0,h.measureQuery)({operation:"bulkWrite",collectionName:this.resolveCollectionName(n),documentCount:e.length,extra:{bulkWrite:!0}},async()=>{const i=this.resolveCollectionName(n),o=this.resolveSession(n),a=await this.getCollection(n),r=this.buildMiddlewareContext("bulkUpdate",n,{bulkOperations:e,meta:{transactional:!0,bulkWrite:!0}});r.collectionName=r.collectionName??i,await this.runBeforeMiddlewares("bulkUpdate",r);const s=r.bulkOperations??e;r.bulkOperations=s;const l=this.buildOperationMeta(r.meta,{transactional:!0,bulkWrite:!0});r.meta=l,await this.schema.executePre("bulkUpdate",this.buildHookPayload("bulkUpdate",n,{collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:o,bulkOperations:s,meta:l}));const c=await a.bulkWrite(s,{...t,...o?{session:o}:{}}),d={acknowledged:c?.isOk?.()??!0,matchedCount:c?.matchedCount,modifiedCount:c?.modifiedCount,upsertedCount:c?.upsertedCount,insertedCount:c?.insertedCount,deletedCount:c?.deletedCount};return await this.schema.executePost("bulkUpdate",this.buildHookPayload("bulkUpdate",n,{collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:o,bulkOperations:s,result:d,meta:l})),r.result=d,await this.runAfterMiddlewares("bulkUpdate",r),await this.invalidateCachePatterns("bulkWrite",r),await f.publish(`${u.DB_CHANGE_EVENT}`,{bulkWrite:{action:"bulkWrite",collectionName:r.collectionName,result:d,meta:l}}),c}),n))}async deleteWithTransaction(e,t){if(await this.init(),!e||"object"!=typeof e)throw new Error("Filter must be a valid object.");return this.runWithModelContext(t,async()=>this.withTransaction(async()=>(0,h.measureQuery)({operation:"deleteOne",collectionName:this.resolveCollectionName(t),filter:e},async()=>{const n=this.resolveCollectionName(t),i=this.resolveSession(t),o=await this.getCollection(t),a={transactional:!0},r=this.buildMiddlewareContext("deleteOne",t,{filter:e,meta:a});r.collectionName=r.collectionName??n,await this.runBeforeMiddlewares("deleteOne",r);const s=r.filter??e;r.filter=s;const l=await o.findOne(s,i?{session:i}:void 0);if(!l)return r.result=null,await this.runAfterMiddlewares("deleteOne",r),!1;const c=this.toModelResult(l);r.result=c,await this.schema.triggerMiddleware("pre","deleteOne",{operation:"deleteOne",collectionName:r.collectionName,...c}),await this.schema.executePre("deleteOne",{operation:"deleteOne",collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:i,doc:l,result:c,meta:a});const d=await o.deleteOne(s,i?{session:i}:void 0);return await this.schema.triggerMiddleware("post","deleteOne",{operation:"deleteOne",collectionName:r.collectionName,...c}),await this.schema.executePost("deleteOne",{operation:"deleteOne",collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:i,doc:l,result:c,meta:a}),await this.runAfterMiddlewares("deleteOne",r),await this.invalidateCachePatterns("deleteOne",r),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentDeleted:{action:"deleteOne",collectionName:r.collectionName,filter:s,meta:a}}),1===d.deletedCount}),t))}async updateWithTransaction(e,t,n){if(await this.init(),!e||"object"!=typeof e)throw new Error("Filter must be a valid object.");if(!t||"object"!=typeof t)throw new Error("Update must be a valid object.");return this.runWithModelContext(n,async()=>this.withTransaction(async()=>(0,h.measureQuery)({operation:"updateOne",collectionName:this.resolveCollectionName(n),filter:e,update:t},async()=>{const i=this.resolveCollectionName(n),o=this.resolveSession(n),a=await this.getCollection(n),r={transactional:!0},s=this.buildMiddlewareContext("updateOne",n,{filter:e,update:t,meta:r});s.collectionName=s.collectionName??i,await this.runBeforeMiddlewares("updateOne",s);const l=s.filter??e,c=s.update??t;s.filter=l,s.update=c;const d=await a.findOne(l,o?{session:o}:void 0);if(!d)return s.result=null,await this.runAfterMiddlewares("updateOne",s),null;const m={...d,...c.$set??{}};this.validate(m),await this.schema.executePre("updateOne",{operation:"updateOne",collectionName:s.collectionName,tenantId:s.tenantId,dbName:s.dbName,session:o,filter:l,update:c,meta:r}),await a.updateOne(l,c,o?{session:o}:void 0);const h=await a.findOne(l,o?{session:o}:void 0),p=h?this.toModelResult(h):null;return await this.schema.executePost("updateOne",{operation:"updateOne",collectionName:s.collectionName,tenantId:s.tenantId,dbName:s.dbName,session:o,filter:l,update:c,result:p,meta:r}),s.result=p,await this.runAfterMiddlewares("updateOne",s),await this.invalidateCachePatterns("updateOne",s),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentUpdated:{action:"updateOne",collectionName:s.collectionName,filter:l,update:c,result:p,meta:r}}),s.result??p}),n))}async findOneAndUpdate(e,t,n){if(await this.init(),!e||"object"!=typeof e)throw new Error("Filter must be a valid object.");if(!t||"object"!=typeof t)throw new Error("Update must be a valid object.");return this.runWithModelContext(n,async()=>(0,h.measureQuery)({operation:"findOneAndUpdate",collectionName:this.resolveCollectionName(n),filter:e,update:t},async()=>{const i=this.resolveCollectionName(n),o=this.resolveSession(n),a=await this.getCollection(n),r=this.buildMiddlewareContext("findOneAndUpdate",n,{filter:e,update:t});r.collectionName=r.collectionName??i,await this.runBeforeMiddlewares("findOneAndUpdate",r);const s=r.filter??e,l=r.update??t;r.filter=s,r.update=l,await this.schema.executePre("updateOne",{operation:"findOneAndUpdate",collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:o,filter:s,update:l,meta:r.meta});const c=await a.findOneAndUpdate(s,l,{returnDocument:"after",...o?{session:o}:{}}),d=c&&"object"==typeof c&&"value"in c?c.value:c,m=d?this.toModelResult(d):null;return await this.schema.executePost("updateOne",{operation:"findOneAndUpdate",collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:o,filter:s,update:l,result:m,meta:r.meta}),r.result=m,await this.runAfterMiddlewares("findOneAndUpdate",r),await this.invalidateCachePatterns("findOneAndUpdate",r),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentUpdated:{action:"findOneAndUpdate",collectionName:r.collectionName,filter:s,update:l,result:m,meta:r.meta}}),r.result??m}))}async findOneAndDelete(e,t){if(await this.init(),!e||"object"!=typeof e)throw new Error("Filter must be a valid object.");return this.runWithModelContext(t,async()=>(0,h.measureQuery)({operation:"findOneAndDelete",collectionName:this.resolveCollectionName(t),filter:e},async()=>{const n=this.resolveCollectionName(t),i=this.resolveSession(t),o=await this.getCollection(t),a=this.buildMiddlewareContext("findOneAndDelete",t,{filter:e});a.collectionName=a.collectionName??n,await this.runBeforeMiddlewares("findOneAndDelete",a);const r=a.filter??e;a.filter=r;const s=this.buildOperationMeta(a.meta);a.meta=s;const l=await o.findOne(r,i?{session:i}:void 0);if(!l)return a.result=null,await this.runAfterMiddlewares("findOneAndDelete",a),null;const c=this.toModelResult(l);if(a.result=c,!0===s.softDelete){const e=a.update??this.buildSoftDeleteUpdate();a.update=e;const n=this.buildOperationMeta(s,{softDelete:!0});return await this.schema.executePre("updateOne",this.buildHookPayload("findOneAndDelete",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,filter:r,update:e,result:c,meta:n})),await o.updateOne(r,e,i?{session:i}:void 0),await this.schema.executePost("updateOne",this.buildHookPayload("findOneAndDelete",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,filter:r,update:e,result:c,meta:n})),await this.runAfterMiddlewares("findOneAndDelete",a),await this.invalidateCachePatterns("findOneAndDelete",a),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentDeleted:{action:"softDeleteOne",collectionName:a.collectionName,filter:r,meta:n}}),a.result??c}await this.schema.triggerMiddleware("pre","deleteOne",{operation:"findOneAndDelete",collectionName:a.collectionName,...c}),await this.schema.executePre("deleteOne",this.buildHookPayload("findOneAndDelete",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,doc:l,result:c,meta:s}));const d=i?{session:i}:{},m=await o.findOneAndDelete(r,d),h=m&&"object"==typeof m&&"value"in m?m.value:m,p=h?this.toModelResult(h):c;return await this.schema.triggerMiddleware("post","deleteOne",{operation:"findOneAndDelete",collectionName:a.collectionName,...p??{}}),await this.schema.executePost("deleteOne",this.buildHookPayload("findOneAndDelete",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,doc:l,result:p,meta:s})),a.result=p,await this.runAfterMiddlewares("findOneAndDelete",a),await this.invalidateCachePatterns("findOneAndDelete",a),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentDeleted:{action:"findOneAndDelete",collectionName:a.collectionName,filter:r,result:p,meta:s}}),a.result??p}))}async findOneAndReplace(e,t,n){if(await this.init(),!e||"object"!=typeof e)throw new Error("Filter must be a valid object.");if(!t||"object"!=typeof t)throw new Error("Replacement document must be a valid object.");return this.runWithModelContext(n,async()=>(0,h.measureQuery)({operation:"findOneAndReplace",collectionName:this.resolveCollectionName(n),filter:e},async()=>{const i=this.resolveCollectionName(n),o=this.resolveSession(n),a=await this.getCollection(n),r=this.buildMiddlewareContext("findOneAndReplace",n,{filter:e,doc:t});r.collectionName=r.collectionName??i,await this.runBeforeMiddlewares("findOneAndReplace",r);const s=r.filter??e,l=r.doc??t;r.filter=s,r.doc=l,this.validate(l),await this.schema.executePre("updateOne",{operation:"findOneAndReplace",collectionName:r.collectionName,filter:s,doc:l});const c=await a.findOneAndReplace(s,l,{returnDocument:"after",...o?{session:o}:{}}),d=c&&"object"==typeof c&&"value"in c?c.value:c,m=d?this.toModelResult(d):null;return await this.schema.executePost("updateOne",{operation:"findOneAndReplace",collectionName:r.collectionName,filter:s,doc:l,result:d}),r.result=m,await this.runAfterMiddlewares("findOneAndReplace",r),await this.invalidateCachePatterns("findOneAndReplace",r),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentUpdated:{action:"findOneAndReplace",filter:s,replacement:l}}),r.result??m}))}async findOneAndUpsert(e,t,n){if(await this.init(),!e||"object"!=typeof e)throw new Error("Filter must be a valid object.");if(!t||"object"!=typeof t)throw new Error("Update must be a valid object.");return this.runWithModelContext(n,async()=>(0,h.measureQuery)({operation:"findOneAndUpsert",collectionName:this.resolveCollectionName(n),filter:e,update:t},async()=>{const i=this.resolveCollectionName(n),o=this.resolveSession(n),a=await this.getCollection(n),r=this.buildMiddlewareContext("findOneAndUpsert",n,{filter:e,update:t});r.collectionName=r.collectionName??i,await this.runBeforeMiddlewares("findOneAndUpsert",r);const s=r.filter??e,l=r.update??t;r.filter=s,r.update=l,await this.schema.executePre("updateOne",{operation:"findOneAndUpsert",collectionName:r.collectionName,filter:s,update:l});const c=await a.findOneAndUpdate(s,l,{upsert:!0,returnDocument:"after",...o?{session:o}:{}}),d=c&&"object"==typeof c&&"value"in c?c.value:c,m=d?this.toModelResult(d):null;return await this.schema.executePost("updateOne",{operation:"findOneAndUpsert",collectionName:r.collectionName,filter:s,update:l,result:d}),r.result=m,await this.runAfterMiddlewares("findOneAndUpsert",r),await this.invalidateCachePatterns("findOneAndUpsert",r),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentUpdated:{action:"findOneAndUpsert",filter:s,update:l}}),r.result??m}))}async findOneAndUpsertWithTransaction(e,t,n){if(await this.init(),!e||"object"!=typeof e)throw new Error("Filter must be a valid object.");if(!t||"object"!=typeof t)throw new Error("Update must be a valid object.");return this.runWithModelContext(n,async()=>this.withTransaction(async()=>{const i=this.resolveCollectionName(n),o=await this.getCollection(n),a=this.resolveSession(n),r=this.buildMiddlewareContext("findOneAndUpsert",n,{filter:e,update:t,meta:{transactional:!0}});r.collectionName=r.collectionName??i,await this.runBeforeMiddlewares("findOneAndUpsert",r);const s=r.filter??e,l=r.update??t;r.filter=s,r.update=l,await this.schema.executePre("updateOne",{operation:"findOneAndUpsert",collectionName:r.collectionName,filter:s,update:l,meta:{transactional:!0}});const c=await o.findOneAndUpdate(s,l,{upsert:!0,returnDocument:"after",...a?{session:a}:{}}),d=c&&"object"==typeof c&&"value"in c?c.value:c,m=d?this.toModelResult(d):null;return await this.schema.executePost("updateOne",{operation:"findOneAndUpsert",collectionName:r.collectionName,filter:s,update:l,result:d,meta:{transactional:!0}}),r.result=m,await this.runAfterMiddlewares("findOneAndUpsert",r),await this.invalidateCachePatterns("findOneAndUpsert",r),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentUpdated:{action:"findOneAndUpsert",filter:s,update:l,meta:{transactional:!0}}}),r.result??m},n))}async findOneAndUpsertWithTransactionSecure(e,t,n,i){if(await this.init(),!e||"object"!=typeof e)throw new Error("Filter must be a valid object.");if(!t||"object"!=typeof t)throw new Error("Update must be a valid object.");if(!n)throw new Error("User is required.");return this.runWithModelContext(i,async()=>this.withTransaction(async()=>{if("admin"!==n.role)throw new Error("Unauthorized");const o={transactional:!0,secure:!0,userId:n.id,userRole:n.role},a=this.resolveCollectionName(i),r=await this.getCollection(i),s=this.resolveSession(i),l=this.buildMiddlewareContext("findOneAndUpsert",i,{filter:e,update:t,meta:o});l.collectionName=l.collectionName??a,await this.runBeforeMiddlewares("findOneAndUpsert",l);const c=l.filter??e,d=l.update??t;l.filter=c,l.update=d,await this.schema.executePre("updateOne",{operation:"findOneAndUpsert",collectionName:l.collectionName,filter:c,update:d,meta:o});const m=await r.findOneAndUpdate(c,d,{upsert:!0,returnDocument:"after",...s?{session:s}:{}}),h=m&&"object"==typeof m&&"value"in m?m.value:m,p=h?this.toModelResult(h):null;return await this.schema.executePost("updateOne",{operation:"findOneAndUpsert",collectionName:l.collectionName,filter:c,update:d,result:h,meta:o}),l.result=p,await this.runAfterMiddlewares("findOneAndUpsert",l),await this.invalidateCachePatterns("findOneAndUpsert",l),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentUpdated:{action:"findOneAndUpsert",filter:c,update:d,meta:o}}),l.result??p},i))}async deleteSecure(e,t,n){if(await this.init(),!e||"object"!=typeof e)throw new Error("Filter must be a valid object.");if(!t)throw new Error("User is required.");return this.runWithModelContext(n,async()=>(0,h.measureQuery)({operation:"deleteOne",collectionName:this.resolveCollectionName(n),filter:e},async()=>{if("admin"!==t.role)throw new Error("Unauthorized");const i={secure:!0,userId:t.id,userRole:t.role},o=this.resolveCollectionName(n),a=await this.getCollection(n),r=this.resolveSession(n),s=this.buildMiddlewareContext("deleteOne",n,{filter:e,meta:i});s.collectionName=s.collectionName??o,await this.runBeforeMiddlewares("deleteOne",s);const l=s.filter??e;s.filter=l;const c=await a.findOne(l,r?{session:r}:void 0);if(!c)return s.result=null,void await this.runAfterMiddlewares("deleteOne",s);const d=this.toModelResult(c);s.result=d,await this.schema.executePre("deleteOne",{operation:"deleteOne",collectionName:s.collectionName,...c,meta:i}),await a.deleteOne(l,r?{session:r}:void 0),await this.schema.executePost("deleteOne",{operation:"deleteOne",collectionName:s.collectionName,...c,meta:i}),await this.runAfterMiddlewares("deleteOne",s),await this.invalidateCachePatterns("deleteOne",s),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentDeleted:{action:"deleteOne",filter:l,meta:i}})}))}async aggregate(e,t={},n,i,o){if(await this.init(),!Array.isArray(e))throw new Error("Pipeline must be a valid array.");return this.runWithModelContext(i,async()=>(0,h.measureQuery)({operation:"aggregate",collectionName:this.resolveCollectionName(i),pipeline:e},async()=>{const a=this.resolveCollectionName(i),r=await this.getCollection(i),s=this.resolveSessionStrict(i,n),l=this.buildMiddlewareContext("aggregate",i,{pipeline:e});l.collectionName=l.collectionName??a,await this.runBeforeMiddlewares("aggregate",l);const c=l.pipeline??e;l.pipeline=c;const d=o?.cache?this.resolveCache(o):null;await this.schema.executePre("aggregate",{operation:"aggregate",collectionName:l.collectionName,tenantId:l.tenantId,dbName:l.dbName,session:s,pipeline:c,meta:l.meta});let m=null;if(d){m=this.buildCacheKey("aggregate",{collectionName:l.collectionName,pipeline:c,options:t,tenantId:l.tenantId,dbName:l.dbName});const e=await d.get(m,{ttlSeconds:"object"==typeof o?.cache?o.cache.ttl:void 0,tenantId:l.tenantId,namespace:l.collectionName});if(e)return l.result=e,await this.runAfterMiddlewares("aggregate",l),l.result??e}const h=r.aggregate(c,{...t,...s?{session:s}:{}}),p=await h.toArray();await this.schema.executePost("aggregate",{operation:"aggregate",collectionName:l.collectionName,tenantId:l.tenantId,dbName:l.dbName,session:s,pipeline:c,result:p,meta:l.meta}),l.result=p,await this.runAfterMiddlewares("aggregate",l);const g=l.result??p;return d&&m&&await d.set(m,g,{ttlSeconds:"object"==typeof o?.cache?o.cache.ttl:void 0,tenantId:l.tenantId,namespace:l.collectionName}),await f.publish(`${u.DB_CHANGE_EVENT}`,{dbChange:{action:"aggregate",pipeline:c}}),g}))}async aggregateWithTransaction(e,t={},n){if(await this.init(),!Array.isArray(e))throw new Error("Pipeline must be a valid array.");return this.runWithModelContext(n,async()=>this.withTransaction(async()=>(0,h.measureQuery)({operation:"aggregate",collectionName:this.resolveCollectionName(n),pipeline:e},async()=>{const i=this.resolveCollectionName(n),o=await this.getCollection(n),a=this.resolveSession(n),r=this.buildMiddlewareContext("aggregate",n,{pipeline:e,meta:{transactional:!0}});r.collectionName=r.collectionName??i,await this.runBeforeMiddlewares("aggregate",r);const s=r.pipeline??e;r.pipeline=s,await this.schema.executePre("aggregate",{operation:"aggregate",collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:a,pipeline:s,meta:{...r.meta??{},transactional:!0}});const l=o.aggregate(s,{...t,...a?{session:a}:{}}),c=await l.toArray();await this.schema.executePost("aggregate",{operation:"aggregate",collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:a,pipeline:s,result:c,meta:{...r.meta??{},transactional:!0}}),r.result=c,await this.runAfterMiddlewares("aggregate",r);const d=r.result??c;return await f.publish(`${u.DB_CHANGE_EVENT}`,{dbChange:{action:"aggregate",pipeline:s,meta:{transactional:!0}}}),d}),n))}async withTransaction(e,t){const n=this.mergeCtx(t)??{},i=n.collectionName??this._collectionName,o=n.session,a={tenantId:n.tenantId,dbName:n.dbName,collectionName:i};if(o)return m.AmbitenContext.run({...a,session:o},async()=>e(o));if(this._provider?.startSession){const t=await this.getSession(n);return await m.AmbitenContext.run({...a,session:t},async()=>(0,m.runManualTransaction)(t,e))}return m.AmbitenContext.run(a,async()=>m.AmbitenContext.withTransaction(e))}async runInTransaction(e,t){if(await this.init(),"function"!=typeof e)throw new Error("Operation must be a valid function.");return this.runWithModelContext(t,async()=>this.withTransaction(async t=>e(t),t))}async getSession(e){if(!this._provider?.startSession)throw new Error("Transaction support is not available. Provider does not implement startSession().");return this._provider.startSession(this.mergeCtx(e))}async streamAggregation(e,t={},n){if(await this.init(),!Array.isArray(e))throw new Error("Pipeline must be a valid array.");return this.runWithModelContext(n,async()=>(0,h.measureQuery)({operation:"aggregate",collectionName:this.resolveCollectionName(n),pipeline:e,extra:{streaming:!0}},async()=>{const i=this.resolveCollectionName(n),o=this.resolveSession(n),a=await this.getCollection(n),r=this.buildMiddlewareContext("aggregate",n,{pipeline:e,meta:{streaming:!0}});r.collectionName=r.collectionName??i,await this.runBeforeMiddlewares("aggregate",r);const s=r.pipeline??e;r.pipeline=s;const l={...r.meta??{},streaming:!0};await this.schema.triggerMiddleware("pre","aggregate",{operation:"aggregate",collectionName:r.collectionName,pipeline:s,meta:l}),await this.schema.executePre("aggregate",{operation:"aggregate",collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:o,pipeline:s,meta:l});const c=a.aggregate(s,{...t,...o?{session:o}:{}}).stream();return await this.schema.triggerMiddleware("post","aggregate",{operation:"aggregate",collectionName:r.collectionName,result:c,meta:l}),await this.schema.executePost("aggregate",{operation:"aggregate",collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:o,pipeline:s,result:c,meta:l}),r.result=c,await this.runAfterMiddlewares("aggregate",r),await f.publish(`${u.DB_CHANGE_EVENT}`,{dbChange:{action:"aggregateStream",collectionName:r.collectionName,pipeline:s,meta:l}}),c}))}async aggregateWithCache(e,t,n=300){if(await this.init(),!Array.isArray(e))throw new Error("Pipeline must be an array of objects.");const i=await d.redis.get(t);if(i)return console.info(`[info]: Cache hit: ${t}`),JSON.parse(i);if("string"!=typeof t)throw new Error("Cache key must be a string.");console.info(`[info]: Cache miss: ${t}`);const o=await this.getCollection(),a=await o.aggregate(e).toArray();return await d.redis.set(t,JSON.stringify(a)||""),await d.redis.expire(t,n),console.info("Cache set:",t),this.schema.triggerMiddleware("post","aggregate",{operation:"aggregate",collectionName:this.resolveCollectionName(o),result:[a]}),await f.publish("DB_CHANGE",{dbChange:{action:"aggregate",result:a}}),a||[]}async paginatedFind(e,t,n){await this.init();const i=e;n&&(i._id={$gt:new o.ObjectId(n)});const a=await this.getCollection();return(await a.find(i).limit(t).toArray()).map(({_id:e,...t})=>t)}async watchChanges(e,t){if(await this.init(),"function"!=typeof e)throw new Error("Callback must be a valid function.");return this.runWithModelContext(t,async()=>{const n=this.resolveCollectionName(t),i=(await this.getCollection(t)).watch();return i.on("change",e),await f.publish(`${u.DB_CHANGE_EVENT}`,{dbChange:{action:"watchChanges",collectionName:n}}),i})}async createIndex(e,t){if(await this.init(),!e||"object"!=typeof e)throw new Error("Index fields must be a valid object.");const n=Object.entries(e);if(0===n.length)throw new Error("Index fields must contain at least one entry.");for(const[,e]of n)if(1!==e&&-1!==e)throw new Error("Index direction must be either 1 or -1.");return this.runWithModelContext(t,async()=>{const n=await this.getCollection(t);await n.createIndex(e)})}async dropIndex(e){await this.init();const t=await this.getCollection();await t.dropIndex(e)}async invalidateCachePatterns(e,t){const n=t.tenantId??"default",i=t.dbName??"default",o=t.collectionName??this._collectionName,a=[...[`Ambiten:${n}:${i}:${o}:find:*`,`Ambiten:${n}:${i}:${o}:findOne:*`],`Ambiten:${n}:${i}:${o}:aggregate:*`];await Promise.all([...new Set(a)].map(e=>g.invalidatePattern(e)))}static async invalidatePattern(e){if("string"!=typeof e||0===e.trim().length)throw new Error("Pattern must be a non-empty string.");const t=e.trim();let n=0,i=0;try{do{const e=await d.redis.scan(i,{MATCH:t,COUNT:100}),o=Array.isArray(e)?Number(e[0]):0,a=Array.isArray(e)?e[1]:[];if(Array.isArray(a)&&a.length>0){const e=d.redis.multi();for(const t of a)e.del(t);const t=await e.exec();Array.isArray(t)&&(n+=t.filter(e=>{if(Array.isArray(e)){const[t,n]=e;return!t&&1===n}return 1===e}).length)}i=o}while(0!==i);return n}catch(e){const n=e instanceof Error?e.message:String(e);throw new Error(`Failed to invalidate cache pattern "${t}": ${n}`)}}getContext(){return{ctx:{}}}async invalidateModelPattern(e,t){if(await this.init(),"string"!=typeof e||0===e.trim().length)throw new Error("Pattern must be a non-empty string.");return this.runWithModelContext(t,async()=>{const n=`Ambiten:${t?.tenantId??"default"}:${t?.dbName??"default"}:${t?.collectionName??this._collectionName}:${e.trim()}`;return g.invalidatePattern(n)})}async invalidateDocumentCache(e,t){if(await this.init(),!e||"object"!=typeof e||!("_id"in e)||!e._id)throw new Error("Document must contain a valid _id.");return this.runWithModelContext(t,async()=>{const n=this.mergeCtx(t),i=`Ambiten:${n?.tenantId??"default"}:${n?.dbName??"default"}:${n?.collectionName??this._collectionName}:*${String(e._id)}*`;return g.invalidatePattern(i)})}static async getCacheStats(e){try{const t=await d.redis.info("memory"),n=await d.redis.info("keyspace"),i=Array.from(n.matchAll(/db\d+:keys=(\d+)/g)).reduce((e,t)=>e+Number(t[1]??0),0),o=t.match(/used_memory:(\d+)/),a=o?Number(o[1]):0,r=await d.redis.get("Ambiten:cache:stats:hits")??"0",s=await d.redis.get("Ambiten:cache:stats:misses")??"0",l=Number.parseInt(r,10)||0,c=Number.parseInt(s,10)||0,u=l+c,m=u>0?Math.round(l/u*100):0,h=u>0?Math.round(c/u*100):0;let p;if(e){const t=`Ambiten:${e}:*`;let n=0,i=0;do{const e=await d.redis.scan(n,{MATCH:t,COUNT:100}),o=Array.isArray(e)?Number(e[0]):0,a=Array.isArray(e)?e[1]:[];Array.isArray(a)&&(i+=a.length),n=o}while(0!==n);p=i}return{totalKeys:i,tenantKeys:p,memoryUsageMb:Math.round(a/1024/1024),memoryUsageBytes:a,hitRate:m,missRate:h,totalHits:l,totalMisses:c,totalRequests:u,tenantId:e??null,timestamp:(new Date).toISOString()}}catch(e){const t=e instanceof Error?e.message:String(e);throw new Error(`Failed to get cache stats: ${t}`)}}async runCommand(e,...t){await this.init();const n={[e]:1,...t};return(await this.getCollection()).db.command(n)}async runGC(e){await this.init();const t=this.resolveSchemaGCConfig();if(t&&t.ttlField&&t.expiresIn)return this.runWithModelContext(e,async()=>(0,h.measureQuery)({operation:"runGC",collectionName:this.resolveCollectionName(e)},async()=>{const n=this.resolveCollectionName(e),i=this.resolveSession(e),o=await this.getCollection(e),a=this.buildMiddlewareContext("runGC",e,{meta:{gc:!0}});a.collectionName=a.collectionName??n,await this.runBeforeMiddlewares("runGC",a);const r=new Date(Date.now()-Number(t.expiresIn)),s={[t.ttlField]:{$lt:r}},l=a.filter??s;a.filter=l;const c=await o.find(l,i?{session:i}:void 0).toArray();if(0===c.length)return a.result={scanned:0,affected:0,archived:0,deleted:0,softDeleted:0},void await this.runAfterMiddlewares("runGC",a);let d=0,m=0,h=0;if(t.softDelete){const e={$set:{deletedAt:new Date,isDeleted:!0}};await this.schema.executePre("updateMany",{operation:"runGC",collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,filter:l,update:e,docs:c,meta:{...a.meta??{},gc:!0,softDelete:!0}}),h=(await o.updateMany(l,e,i?{session:i}:void 0)).modifiedCount,await this.schema.executePost("updateMany",{operation:"runGC",collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,filter:l,update:e,docs:c,result:{scanned:c.length,affected:h,archived:0,deleted:0,softDeleted:h},meta:{...a.meta??{},gc:!0,softDelete:!0}})}else{if(t.archiveBeforeDelete){const e=c.map(e=>({...e,_archivedAt:new Date,_from:o.collectionName}));await o.db.collection("Ambiten_archives").insertMany(e,i?{session:i}:void 0),d=e.length}await this.schema.triggerMiddleware("pre","deleteMany",{operation:"runGC",collectionName:a.collectionName,docs:c}),await this.schema.executePre("deleteMany",{operation:"runGC",collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,docs:c,result:this.toModelResults(c),meta:{...a.meta??{},gc:!0}}),m=(await o.deleteMany(l,i?{session:i}:void 0)).deletedCount??0,await this.schema.triggerMiddleware("post","deleteMany",{operation:"runGC",collectionName:a.collectionName,docs:c}),await this.schema.executePost("deleteMany",{operation:"runGC",collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,docs:c,result:{scanned:c.length,affected:m,archived:d,deleted:m,softDeleted:0},meta:{...a.meta??{},gc:!0}})}const p={scanned:c.length,affected:h||m,archived:d,deleted:m,softDeleted:h};a.result=p,await this.runAfterMiddlewares("runGC",a),await this.invalidateCachePatterns("runGC",a),await f.publish(`${u.DB_CHANGE_EVENT}`,{garbageCollection:{action:"runGC",collectionName:a.collectionName,...p,meta:{...a.meta??{},gc:!0}}})}))}startAutoGC(e=36e5){setInterval(()=>this.runGC().catch(console.error),e)}resolveInstrumentationContext(e){const t=m.AmbitenContext.get(),n=this.mergeCtx(e);return{tenantId:n?.tenantId,dbName:n?.dbName,collectionName:n?.collectionName??this._collectionName,session:n?.session,requestId:t.requestId}}buildOperationMeta(e,t){return{...e??{},...t??{},extra:{...e?.extra??{},...t?.extra??{}}}}buildHookPayload(e,t,n={}){const i=this.resolveInstrumentationContext(t);return{operation:e,collectionName:n.collectionName??i.collectionName,tenantId:n.tenantId??i.tenantId,dbName:n.dbName??i.dbName,session:n.session??i.session,filter:n.filter,update:n.update,doc:n.doc,docs:n.docs,pipeline:n.pipeline,result:n.result,meta:n.meta}}resolveCache(e){return e?.cache?{get:async(e,t)=>{try{const t=await d.redis.get(e);if(!t)return await g.trackCacheMiss(),null;const n=JSON.parse(t);return await g.trackCacheHit(),n}catch{return null}},set:async(e,t,n)=>{try{const i=n?.ttlSeconds??300;await d.redis.set(e,JSON.stringify(t),{EX:i})}catch{}}}:null}buildCacheKey(e,t){const n=String(t.tenantId??"default"),i=String(t.dbName??"default"),o=String(t.collectionName??this._collectionName),{tenantId:a,dbName:r,collectionName:s,...l}=t,c=this.sortObjectDeep(l);return`Ambiten:${n}:${i}:${o}:${e}:${JSON.stringify(c)}`}static async trackCacheMiss(){try{const e=(new Date).toISOString().slice(0,10),t=604800,n=d.redis.multi();n.incr("Ambiten:cache:stats:misses"),n.incr(`Ambiten:cache:stats:misses:${e}`),n.expire(`Ambiten:cache:stats:misses:${e}`,t),await n.exec()}catch{}}static async trackCacheHit(){try{const e=(new Date).toISOString().slice(0,10),t=604800,n=d.redis.multi();n.incr("Ambiten:cache:stats:hits"),n.incr(`Ambiten:cache:stats:hits:${e}`),n.expire(`Ambiten:cache:stats:hits:${e}`,t),await n.exec()}catch{}}static async cacheResult(e,t,n=3600){if("string"!=typeof e||0===e.trim().length)throw new Error("Cache key must be a non-empty string.");if(!Number.isFinite(n)||n<=0)throw new Error("TTL must be a positive number.");try{await d.redis.set(e,JSON.stringify(t)),await d.redis.expire(e,n)}catch{}}static async clearCache(e){if(!e||"string"!=typeof e)throw new Error("Cache key must be a non-empty string");try{await d.redis.del(e)}catch(t){throw console.error("Error clearing cache:",t),new Error(`Failed to clear cache for key "${e}": ${t}`)}}async warmCache(e,t=3600,n){if(await this.init(),!Number.isFinite(t)||t<=0)throw new Error("Default TTL must be a positive number.");return this.runWithModelContext(n,async()=>{const i=this.resolveCache({cache:{ttl:t}});if(!i)return;const o=this.resolveInstrumentationContext(n),a=await this.getCollection(n),r=this.resolveSession(n),s=e&&e.length>0?e:[{filter:{},ttl:t}];if(e&&0!==e.length||!(await a.countDocuments({},r?{session:r}:void 0)>1e3))for(const e of s){const n=e.filter??{},s=e.ttl??t,l=await a.find(n,r?{session:r}:void 0).toArray(),c=this.toModelResults(l),d=this.buildCacheKey("find",{collectionName:o.collectionName,filter:n,tenantId:o.tenantId,dbName:o.dbName});await i.set(d,c,{ttlSeconds:s,tenantId:o.tenantId,namespace:o.collectionName})}})}sortObjectDeep(e){return Array.isArray(e)?e.map(e=>this.sortObjectDeep(e)):e instanceof Date?e.toISOString():e&&"object"==typeof e?Object.keys(e).sort().reduce((t,n)=>(t[n]=this.sortObjectDeep(e[n]),t),{}):e}toModelResult(e){const{_id:t,...n}=e;return{...n,_id:t.toString()}}toModelResults(e=[]){return e.map(e=>this.toModelResult(e))}async restoreOne(e,t){if(await this.init(),!e||"object"!=typeof e)throw new Error("Filter must be a valid object.");return this.runWithModelContext(t,async()=>(0,h.measureQuery)({operation:"restoreOne",collectionName:this.resolveCollectionName(t),filter:e},async()=>{const n=this.resolveCollectionName(t),i=this.resolveSession(t),o=await this.getCollection(t),a={restore:!0},r=this.buildMiddlewareContext("restoreOne",t,{filter:e,meta:a});r.collectionName=r.collectionName??n,await this.runBeforeMiddlewares("restoreOne",r);const s=r.filter??e;r.filter=s;const l=this.buildRestoreUpdate();if(!await o.findOne(s,i?{session:i}:void 0))return r.result=null,void await this.runAfterMiddlewares("restoreOne",r);await this.schema.executePre("restoreOne",{operation:"restoreOne",collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:i,filter:s,update:l,meta:a});const c=await o.updateOne(s,l,i?{session:i}:void 0),d=await o.findOne(s,i?{session:i}:void 0),m={acknowledged:c.acknowledged,matchedCount:c.matchedCount,modifiedCount:c.modifiedCount,upsertedCount:c.upsertedCount,upsertedId:c.upsertedId,restored:d?this.toModelResult(d):null};await this.schema.executePost("restoreOne",{operation:"restoreOne",collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:i,filter:s,update:l,result:m,meta:a}),r.result=m,await this.runAfterMiddlewares("restoreOne",r),await this.invalidateCachePatterns("restoreOne",r),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentRestored:{action:"restoreOne",collectionName:r.collectionName,filter:s,result:m,meta:a}})}))}async restoreMany(e,t){if(await this.init(),!e||"object"!=typeof e)throw new Error("Filter must be a valid object.");return this.runWithModelContext(t,async()=>(0,h.measureQuery)({operation:"restoreMany",collectionName:this.resolveCollectionName(t),filter:e},async()=>{const n=this.resolveCollectionName(t),i=this.resolveSession(t),o=await this.getCollection(t),a={restore:!0},r=this.buildMiddlewareContext("restoreMany",t,{filter:e,meta:a});r.collectionName=r.collectionName??n,await this.runBeforeMiddlewares("restoreMany",r);const s=r.filter??e;r.filter=s;const l=this.buildRestoreUpdate(),c=await o.find(s,i?{session:i}:void 0).toArray();if(0===c.length)return r.result={restoredCount:0,docs:[]},void await this.runAfterMiddlewares("restoreMany",r);await this.schema.executePre("updateMany",{operation:"restoreMany",collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:i,filter:s,update:l,docs:c,meta:a});const d=await o.updateMany(s,l,i?{session:i}:void 0),m=await o.find(s,i?{session:i}:void 0).toArray(),h={acknowledged:d.acknowledged,matchedCount:c.length,modifiedCount:d.modifiedCount,restoredCount:d.modifiedCount,docs:this.toModelResults(m)};await this.schema.executePost("updateMany",{operation:"restoreMany",collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:i,filter:s,update:l,docs:m,result:h,meta:a}),r.result=h,await this.runAfterMiddlewares("restoreMany",r),await this.invalidateCachePatterns("restoreMany",r),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentRestored:{action:"restoreMany",collectionName:r.collectionName,filter:s,result:h,meta:a}})}))}buildRestoreUpdate(){const e=this._softDeleteConfig?.deletedAtField??"deletedAt",t=this._softDeleteConfig?.isDeletedField??"isDeleted";return{$set:{[e]:null,[t]:!1}}}buildMiddlewareContext(e,t,n={}){const i=this.mergeCtx(t);return{operation:e,modelName:this.constructor.name,collectionName:n.collectionName??i?.collectionName??this._collectionName,tenantId:n.tenantId??i?.tenantId,dbName:n.dbName??i?.dbName,session:n.session??i?.session,withDeleted:n.withDeleted??i?.withDeleted,onlyDeleted:n.onlyDeleted??i?.onlyDeleted,hardDelete:n.hardDelete??i?.hardDelete,filter:n.filter,update:n.update,doc:n.doc,docs:n.docs,pipeline:n.pipeline,bulkUpdates:n.bulkUpdates,bulkOperations:n.bulkOperations,result:n.result,meta:n.meta}}setSoftDeleteConfig(e){this._softDeleteConfig=e}buildSoftDeleteUpdate(){const e=this._softDeleteConfig?.deletedAtField??"deletedAt",t=this._softDeleteConfig?.isDeletedField??"isDeleted";return{$set:{[e]:new Date,[t]:!0}}}async runBeforeMiddlewares(e,t){const n=this.beforeMiddlewares.get(e)??[];for(const e of n)await e(t)}async runAfterMiddlewares(e,t){const n=this.afterMiddlewares.get(e)??[];for(const e of n)await e(t)}before(e,t){const n=this.beforeMiddlewares.get(e)??[];return n.push(t),this.beforeMiddlewares.set(e,n),this}after(e,t){const n=this.afterMiddlewares.get(e)??[];return n.push(t),this.afterMiddlewares.set(e,n),this}beforeFind(e){return this.before("find",e)}afterFind(e){return this.after("find",e)}beforeFindOne(e){return this.before("findOne",e)}afterFindOne(e){return this.after("findOne",e)}beforeSave(e){return this.before("create",e)}afterSave(e){return this.after("create",e)}beforeUpdateOne(e){return this.before("updateOne",e)}afterUpdateOne(e){return this.after("updateOne",e)}beforeDeleteOne(e){return this.before("deleteOne",e)}afterDeleteOne(e){return this.after("deleteOne",e)}beforeDeleteMany(e){return this.before("deleteMany",e)}afterDeleteMany(e){return this.after("deleteMany",e)}beforeBulkInsert(e){return this.before("bulkInsert",e)}afterBulkInsert(e){return this.after("bulkInsert",e)}beforeBulkUpdate(e){return this.before("bulkUpdate",e)}afterBulkUpdate(e){return this.after("bulkUpdate",e)}beforeAggregate(e){return this.before("aggregate",e)}afterAggregate(e){return this.after("aggregate",e)}beforeFindOneAndUpdate(e){return this.before("findOneAndUpdate",e)}afterFindOneAndUpdate(e){return this.after("findOneAndUpdate",e)}beforeFindOneAndDelete(e){return this.before("findOneAndDelete",e)}afterFindOneAndDelete(e){return this.after("findOneAndDelete",e)}beforeFindOneAndReplace(e){return this.before("findOneAndReplace",e)}afterFindOneAndReplace(e){return this.after("findOneAndReplace",e)}beforeFindOneAndUpsert(e){return this.before("findOneAndUpsert",e)}afterFindOneAndUpsert(e){return this.after("findOneAndUpsert",e)}}t.AmbitenModel=g},9528(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0})},9647(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0})},9729(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=n(5584);i.__exportStar(n(1332),t),i.__exportStar(n(6438),t),i.__exportStar(n(3803),t)},9831(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0})},9881(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=n(5584);i.__exportStar(n(2992),t),i.__exportStar(n(7234),t)},9896(e){"use strict";e.exports=require("fs")}},t={};function n(i){var o=t[i];if(void 0!==o)return o.exports;var a=t[i]={id:i,loaded:!1,exports:{}};return e[i](a,a.exports,n),a.loaded=!0,a.exports}n.c=t,n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),n(n.s=3206)})();
|
|
25
|
+
`}defaultResolvers(){return{Query:{findOne:async(e,{collection:t,id:n},i)=>(await this.getCollection(i,t)).findOne({_id:new a.ObjectId(n)}),findAll:async(e,{collection:t},n)=>(await this.getCollection(n,t)).find({}).toArray()},Mutation:{insertOne:async(e,{collection:t,data:n},i)=>{const o=await this.getCollection(i,t),a=await o.insertOne(n),r=await o.findOne({_id:a.insertedId});return await this.publishEvent(`${s.DB_CHANGE_EVENT}`,{documentInserted:{action:"insertOne",collectionName:t,doc:r,tenantId:i.tenantId}}),r},updateOne:async(e,{collection:t,id:n,data:i},o)=>{const r=await this.getCollection(o,t);await r.updateOne({_id:new a.ObjectId(n)},{$set:i});const l=await r.findOne({_id:new a.ObjectId(n)});return await this.publishEvent(`${s.DB_CHANGE_EVENT}`,{documentUpdated:{action:"updateOne",collectionName:t,doc:l,tenantId:o.tenantId}}),l},deleteOne:async(e,{collection:t,id:n},i)=>{const o=await this.getCollection(i,t);return 1===(await o.deleteOne({_id:new a.ObjectId(n)})).deletedCount&&(await this.publishEvent(`${s.DB_CHANGE_EVENT}`,{documentDeleted:{action:"deleteOne",collectionName:t,id:n,tenantId:i.tenantId}}),!0)}},Subscription:{documentInserted:{subscribe:async()=>this.useRedis?(await this.ensureRedis(),this.subscriber):null},documentUpdated:{subscribe:async()=>this.useRedis?(await this.ensureRedis(),this.subscriber):null},documentDeleted:{subscribe:async()=>{if(this.useRedis)return await this.ensureRedis(),this.subscriber}}}}}subscriptions(){return this.useRedis}async generateSchema(){return await this.ensureRedis(),(0,i.makeExecutableSchema)({typeDefs:[this.defaultTypeDefs(),...this.typeDefs],resolvers:[this.defaultResolvers(),...this.resolvers]})}}},7234(e,t){"use strict";var n;Object.defineProperty(t,"__esModule",{value:!0}),t.ErrorType=void 0,function(e){e.AmbitenError="AmbitenError",e.AmbitenErrorType="AmbitenErrorType",e.AmbitenErrorStack="AmbitenErrorStack",e.AmbitenErrorMessage="AmbitenErrorMessage",e.AmbitenErrorCause="AmbitenErrorCause",e.AmbitenCollectionError="CollectionError",e.AmbitenParseError="ParseError",e.AmbitenBulkWriteError="MongoBulkWriteError",e.AmbitenConnectionError="ConnectionError",e.AmbitenSchemaError="SchemaError",e.AmbitenModelError="ModelError",e.INITIALIZATION_ERROR="INITIALIZATION_ERROR",e.Ambiten_ERROR="Ambiten_ERROR",e.NULL_OR_UNDEFINED="NULL_OR_UNDEFINED",e.INVALID_SCHEME_ERROR="INVALID_SCHEME_ERROR",e.CONNECTION_ERROR="CONNECTION_ERROR",e.UNEXPECTED_ERROR="UNEXPECTED_ERROR",e.SCHEMA_ERROR="SCHEMA_ERROR",e.SCHEMA_VALIDATION_ERROR="SCHEMA_VALIDATION_ERROR",e.NOT_FOUND="NOT_FOUND",e.NO_DATABASE_FOUND="NO_DATABASE_FOUND",e.NOT_FOUND_IN_CACHE="NOT_FOUND_IN_CACHE",e.VALIDATION_ERROR="VALIDATION_ERROR",e.UNIQUE_CONSTRAINT_VIOLATION="UNIQUE_CONSTRAINT_VIOLATION"}(n||(t.ErrorType=n={}))},7499(e){"use strict";e.exports=JSON.parse('{"$schema":"http://json-schema.org/draft-07/schema#","title":"Ambiten Configuration Schema","type":"object","additionalProperties":false,"properties":{"projectName":{"type":"string","description":"The name of the project."},"connection":{"type":"object","description":"MongoDB connection configuration used when no external provider is supplied at runtime.","properties":{"uri":{"type":"string","description":"MongoDB connection URI."},"options":{"type":"object","description":"Additional MongoDB client options."}},"required":["uri"],"additionalProperties":true},"multiTenant":{"type":"object","description":"Multi-tenant runtime configuration.","properties":{"enabled":{"type":"boolean","default":false},"headerKey":{"type":"string","default":"x-tenant-id","description":"Header used to resolve the tenant ID."},"tenants":{"type":"object","description":"Mapping of tenant IDs to MongoDB URIs.","additionalProperties":{"type":"string"}},"initOptions":{"type":"object","description":"Initialization options for multi-tenancy.","properties":{"lazy":{"type":"boolean","default":false},"retryAttempts":{"type":"integer","default":3},"config":{"type":"object"}},"additionalProperties":true}},"additionalProperties":false},"logger":{"type":"object","description":"Logger configuration.","properties":{"level":{"type":"string","enum":["debug","info","warn","error","fatal","trace"]},"colorize":{"type":"boolean"},"json":{"type":"boolean"},"transportConfigs":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["console","file","rotating-file"]},"options":{"type":"object"}},"additionalProperties":false}},"formatOptions":{"type":"object"},"excludedSources":{"type":"array","items":{"type":"string"}},"circuitBreaker":{"type":"object","properties":{"enabled":{"type":"boolean","default":true},"retryAttempts":{"type":"integer","default":5}},"additionalProperties":false},"enableMetrics":{"type":"object","properties":{"enabled":{"type":"boolean","default":false},"logInterval":{"type":"integer","minimum":1000,"default":60000}},"additionalProperties":false,"default":{"enabled":false,"logInterval":60000}},"compress":{"type":"object","properties":{"enabled":{"type":"boolean","default":false}},"additionalProperties":false,"default":{"enabled":false}}},"additionalProperties":true},"graphql":{"type":"object","description":"Optional GraphQL auto-generation/bootstrap feature. Useful for playgrounds, prototyping, and generated GraphQL flows.","properties":{"enabled":{"type":"boolean","default":false},"subscriptions":{"type":"boolean","default":false},"playground":{"type":"boolean","default":true},"schemaOutputPath":{"type":"string","default":"./src/graphql/schema.gql"}},"additionalProperties":false},"features":{"type":"object","description":"Optional feature paths and integrations.","properties":{"models":{"type":"string","default":"./src/models"},"schemas":{"type":"string","default":"./src/schemas"},"typeDefs":{"type":"string","default":"./src/graphql/typeDefs"},"resolvers":{"type":"string","default":"./src/graphql/resolvers"},"useRedisCache":{"type":"boolean","default":false},"redisUri":{"type":"string","default":""}},"additionalProperties":false},"advanced":{"type":"object","description":"Advanced runtime configuration.","properties":{"autoInstall":{"type":"boolean","default":false},"circuitBreaker":{"type":"object","properties":{"enabled":{"type":"boolean","default":true},"retryAttempts":{"type":"integer","default":5}},"additionalProperties":false},"garbageCollector":{"type":"object","description":"Garbage collector configuration.","properties":{"enabled":{"type":"boolean","default":false},"retentionPeriod":{"type":"integer","minimum":1,"default":30},"logResults":{"type":"boolean","default":true}},"additionalProperties":false},"gcCron":{"type":"string","default":"0 * * * *"}},"additionalProperties":false},"configVersion":{"type":"string","default":"1.0.0","description":"Version of the Ambiten config format."}}}')},7503(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.AuthService=void 0;const i=n(5584).__importDefault(n(829));n(4469);const o=process.env.JWT_SECRET,a=process.env.REFRESH_SECRET,r=process.env.REFRESH_EXPIRATION||"7d",s=process.env.JWT_EXPIRATION||"1d";t.AuthService=class{static generateToken(e){return i.default.sign(e,o,{expiresIn:s})}static generateRefreshToken(e){return i.default.sign(e,a,{expiresIn:r})}static verifyToken(e){return i.default.verify(e,o)}}},7584(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0})},7624(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.isValidObjectId=void 0,t.isObjectId=a,t.castId=function(e){if("string"==typeof e){const n=e;if(!(0,t.isValidObjectId)(n))throw new Error("Invalid ObjectId format in castId");if(!a(e))throw new Error("Invalid ObjectId in castId");return o.ObjectId.createFromHexString(n)}return e};const i=n(529),o=n(2518);function a(e){return null!=e&&"object"==typeof e&&e.constructor===o.ObjectId&&!0===e[i.objectIdSymbol]}Object.defineProperty(o.ObjectId.prototype,"_id",{configurable:!0,enumerable:!0,get:function(){return this.toHexString()}}),Object.prototype.hasOwnProperty.call(o.ObjectId.prototype,"valueOf")||(o.ObjectId.prototype.valueOf=function(){return this.toString()}),t.isValidObjectId=e=>/^[0-9a-fA-F]{24}$/.test(e),o.ObjectId.prototype.toJSON=function(){return this.toHexString()},o.ObjectId.prototype[i.objectIdSymbol]=!0},7743(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.AmbitenBootstrapFactory=void 0,n(5584).__exportStar(n(2999),t);var i=n(2999);Object.defineProperty(t,"AmbitenBootstrapFactory",{enumerable:!0,get:function(){return i.AmbitenBootstrapFactory}})},7803(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=n(5584);i.__exportStar(n(2590),t),i.__exportStar(n(6941),t),i.__exportStar(n(8183),t)},7825(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.ensureModelNameSafe=function(e){if(!e||"string"!=typeof e)throw new Error("Model name must be a non-empty string");const t=e.trim();if(0===t.length)throw new Error("Model name cannot be just whitespace");if(!/^[A-Za-z0-9_]+$/.test(t))throw new Error("Model name must only contain letters, numbers, and underscores");return t}},7858(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getModelFilesFromPath=r,t.loadModelsFromPath=async function(e){const t=r(e),i=[];for(const e of t)try{const t=await n(1077)(e);t.default?i.push(t.default):console.warn(`No default export found in ${e}`)}catch(t){console.error(`Error loading model from ${e}:`,t)}return i};const i=n(5584),o=i.__importDefault(n(9896)),a=i.__importDefault(n(6928));function r(e){const t=[];return o.default.readdirSync(e).forEach(n=>{const i=a.default.join(e,n);o.default.statSync(i).isDirectory()?t.push(...r(i)):/\.(ts|js)$/.test(n)&&t.push(i)}),t}},7900(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),n(5584).__exportStar(n(7221),t)},8093(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=n(5584);i.__exportStar(n(8781),t),i.__exportStar(n(6013),t),i.__exportStar(n(3904),t),i.__exportStar(n(9001),t)},8183(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.authorize=function(e){return(t,n,o)=>{let a;const r=t.headers?.authorization||t.headers.Authorization;if("string"==typeof r&&r.startsWith("Bearer ")&&(a=r.split(" ")[1]),!a)return n.status(401).json({error:"Access token required"});try{const t=i.AuthService.verifyToken(a);return console.info(`Decoded token: ${JSON.stringify(t)}`),t?e.includes(t.role)?t:n.status(403).json({error:"Access Denied"}):n.status(401).json({error:"Unauthorized"})}catch{n.status(401).json({error:"Unauthorized"})}}};const i=n(7503)},8686(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.AmbitenModelRegistry=void 0,t.clearModelRegistryForTests=function(){for(const e of i)t.AmbitenModelRegistry.unregisterModel(e);i.length=0};const n=new Set;t.AmbitenModelRegistry={registerModel(e){n.add(e)},getRegisteredModel:e=>n.has(e)?e:null,isModelRegistered:e=>n.has(e),unregisterModel(e){n.delete(e)},getAllModels:()=>[...n],clear(){n.clear()}};const i=[]},8742(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=n(5584);i.__exportStar(n(3057),t),i.__exportStar(n(7038),t),i.__exportStar(n(5303),t)},8781(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.AmbitenGC=void 0;const i=n(5584).__importStar(n(2703)),o=n(960),a=n(3904);t.AmbitenGC=class{options;enabled;intervalMs;intervalRef=null;cronTask=null;constructor(e={}){if(this.options=e,this.enabled=!1!==e.enabled,this.intervalMs=e.interval?this.parseInterval(e.interval):6e4,e.retentionPeriod&&(this.intervalMs=24*e.retentionPeriod*60*60*1e3),this.enabled)return e.cron?(this.cronTask=i.schedule(e.cron,()=>{this.runOnce()}),void this.log("info",`[AmbitenGC] Cron schedule set to: ${e.cron}`)):e.interval?(this.start(),void this.log("info",`[AmbitenGC] Interval set to: ${e.interval}`)):void this.log("info","[AmbitenGC] Initialized. Manual run mode enabled.");this.log("info","[AmbitenGC] Garbage Collector is disabled.")}start(){this.enabled&&(this.intervalRef||(this.intervalRef=setInterval(()=>{this.runOnce()},this.intervalMs),this.log("info",`[AmbitenGC] Started GC loop every ${this.intervalMs} ms`)))}stop(){this.intervalRef&&(clearInterval(this.intervalRef),this.intervalRef=null),this.cronTask&&(this.cronTask.stop(),this.cronTask=null),this.log("info","[AmbitenGC] Stopped.")}async runOnce(e){if(!this.enabled)return{scanned:0,succeeded:0,failed:0,models:[]};const t=await(0,a.runGarbageCollectorOnAllModels)({ctx:e??this.options.ctx,continueOnError:this.options.continueOnError??!0});return this.options.logResults&&this.log(t.failed>0?"warn":"info",`[AmbitenGC] Completed. scanned=${t.scanned}, succeeded=${t.succeeded}, failed=${t.failed}`),t}parseInterval(e){const t=e.match(/^(\d+)([smhd])$/);if(!t)throw new Error(`Invalid interval format: ${e}`);const[,n,i]=t,o=Number.parseInt(n,10);switch(i){case"s":return 1e3*o;case"m":return 60*o*1e3;case"h":return 60*o*60*1e3;case"d":return 24*o*60*60*1e3;default:throw new Error(`Unknown time unit: ${i}`)}}log(e,t,n){const i=this.options.logger;i?.[e]?i[e]?.(t,n):"error"!==e?"warn"!==e?console.log((0,o.colorize)(t,"blue"),n??""):console.warn((0,o.colorize)(t,"yellow"),n??""):console.error((0,o.colorize)(t,"red"),n??"")}}},8917(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.invalidateTenantCache=async function(e,t,n){const i=n?`ambiten:${t}:${n}:*`:`ambiten:${t}:*`,o=await e.keys(i);o.length&&(await e.del(o),console.info(`🔁 Cleared ${o.length} cache entries for ${t}${n?` (${n})`:""}`))}},8952(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.eventTypes=void 0,t.eventTypes=["pre-save","post-save","pre-update","post-update","pre-delete","post-delete","aggregate","disconnect","connect","dropDatabase","createIndex","dropIndex","create","find","findOne","insertOne","insertMany","updateOne","updateMany","deleteOne","deleteMany","transaction"]},9001(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.startGarbageCollector=void 0;const i=n(960);t.startGarbageCollector=()=>{console.warn((0,i.colorize)("[GC] Garbage collector is disabled in the browser.","red"))}},9228(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.measureQuery=async function(e,t){if(!o.AmbitenContext.hasActiveContext())throw new Error("[Ambiten] Missing runtime context.");const n=o.AmbitenContext.getLogger(),a=o.AmbitenContext.getObserver(),r=o.AmbitenContext.getLoggerMeta()??{},s=o.AmbitenContext.getTenantId(),l=o.AmbitenContext.getRequestId(),c=o.AmbitenContext.getDbName(),d=e.collectionName??o.AmbitenContext.getCollectionName(),u=o.AmbitenContext.incrementQueries(),m=i.performance.now();try{const h=await t(),p=Math.round(100*(i.performance.now()-m))/100,f=o.AmbitenContext.addQueryTime(p),g={operation:e.operation,collectionName:d,durationMs:p,status:"success",tenantId:s,requestId:l,dbName:c,filter:e.filter,update:e.update,pipeline:e.pipeline,documentCount:e.documentCount,queriesExecuted:u.queriesExecuted,maxQueries:u.maxQueries,totalBudgetUsed:f.totalTimeMs,...r,...e.extra??{}};return setImmediate(()=>{a?.onQuery?.(g),n?.info?n.info("[Ambiten Query]",g):o.AmbitenContext.isDebug()&&console.log("[Ambiten Query]",g)}),h}catch(t){const u=Math.round(100*(i.performance.now()-m))/100,h=o.AmbitenContext.addQueryTime(u),p={operation:e.operation,collectionName:d,durationMs:u,status:"error",tenantId:s,requestId:l,dbName:c,filter:e.filter,update:e.update,pipeline:e.pipeline,documentCount:e.documentCount,queriesExecuted:h.queriesExecuted,maxQueries:h.maxQueries,totalBudgetUsed:h.totalTimeMs,errorMessage:t?.message,errorName:t?.name,...r,...e.extra??{}};throw setImmediate(()=>{a?.onQueryError?.({...p,error:t}),n?.error?n.error("[Ambiten Query Error]",p):o.AmbitenContext.isDebug()&&console.error("[Ambiten Query Error]",p)}),t}};const i=n(2987),o=n(3057)},9451(e){"use strict";e.exports=require("@ambiten/logger")},9490(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),n(5584).__exportStar(n(1891),t)},9493(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.AmbitenModel=void 0;const i=n(5584);n(4469);const o=n(2518),a=n(1679),r=n(6903),s=i.__importDefault(n(4434)),l=n(3946),c=n(901),d=n(3868),u=n(960),m=n(8742),h=n(3907),p=n(9490),f=new l.PubSub;class g{_provider;_collectionName;_collectionOverride;_schema;_initialized=!1;_defaultCtx;_modelGCConfig;_gcConfig;_gcTimer;eventEmitter=new s.default;beforeMiddlewares=new Map;afterMiddlewares=new Map;_softDeleteConfig;constructor(e){if(!e){const t="AmbitenModel options are required.";throw(0,u.createAmbitenError)(u.ErrorType.NULL_OR_UNDEFINED,t,{details:{providedOptions:e,typeError:u.ErrorType.AmbitenModelError}})}if(!e.collectionName){const t="collectionName is required.";throw(0,u.createAmbitenError)(u.ErrorType.NULL_OR_UNDEFINED,t,{details:{providedOptions:e,typeError:u.ErrorType.AmbitenModelError}})}if(this._collectionName=e.collectionName,this._schema=e.schema??new r.AmbitenSchema({}),this._provider=e.provider??a.AmbitenClient.init(),this._collectionOverride=e.collection,this._modelGCConfig=e.gcConfig,e.ctx?.db){const t=e.ctx.db;this._provider={db:async()=>t}}(e.ctx?.tenantId||e.ctx?.dbName||e.ctx?.collectionName)&&(this._defaultCtx={tenantId:e.ctx?.tenantId,dbName:e.ctx?.dbName,collectionName:e.ctx?.collectionName,db:e.ctx?.db,session:e.ctx?.session,config:e.ctx?.config});const t=this.resolveSchemaGCConfig();(this.isGCEnabled()||t)&&u.AmbitenModelRegistry.registerModel(this),this.initMiddleware()}mergeCtx(e){const t=m.AmbitenContext.get(),n={tenantId:e?.tenantId??this._defaultCtx?.tenantId??t.tenantId,dbName:e?.dbName??this._defaultCtx?.dbName??t.dbName,db:e?.db??this._defaultCtx?.db,collectionName:e?.collectionName??this._defaultCtx?.collectionName??t.collectionName,config:e?.config??this._defaultCtx?.config,session:e?.session??this._defaultCtx?.session??t.session,withDeleted:e?.withDeleted,onlyDeleted:e?.onlyDeleted,hardDelete:e?.hardDelete};return Object.values(n).some(e=>void 0!==e)?n:void 0}async runWithModelContext(e,t){if(m.AmbitenContext.hasActiveContext())return t();const n=this.mergeCtx(e);return m.AmbitenContext.run({tenantId:n?.tenantId,dbName:n?.dbName,collectionName:n?.collectionName??this._collectionName,session:n?.session},t)}isGCEnabled(){return!0===this._modelGCConfig?.enableGC}resolveSchemaGCConfig(){return this._schema.getGCConfig?.()}async getCollection(e){if(this._collectionOverride)return this._collectionOverride;this.ensureConfigured();const t=await this.resolveDb(e),n=this.resolveCollectionName(e);return(0,p.debugLog)("Resolved collection",{collectionName:n,dbName:t.databaseName,tenantId:this.mergeCtx(e)?.tenantId}),t.collection(n)}getResolvedTenant(e){const t=c.MultiTenantManager.getTenant(e);if(!t)throw new Error(`Tenant "${e}" is not registered.`);return{...t}}async resolveDb(e){const t=this.mergeCtx(e);if(t?.db)return t.db;if(t?.tenantId){const e=this.getResolvedTenant(t.tenantId),n=await c.MultiTenantManager.getClient(t.tenantId);if(!n)throw new Error(`MongoClient for tenant "${t.tenantId}" is not available.`);const i=t.dbName??e.dbName;if(!i)throw new Error(`No database name configured for tenant "${t.tenantId}".`);return n.db(i)}const n=await this._provider.db(t);if(!n||"function"!=typeof n.collection)throw new Error(`AmbitenModel: provider.db() did not return a valid Db instance for collection "${this._collectionName}".`);return n}resolveCollectionName(e){const t=this.mergeCtx(e),n=t?.collectionName??this._collectionName;if(!n||"string"!=typeof n||!n.trim())throw new Error("AmbitenModel: collectionName is not configured.");return n.trim()}resolveSession(e){return this.mergeCtx(e)?.session}resolveSessionStrict(e,t){return t??e?.session??m.AmbitenContext.getSession()}on(e,t){this.eventEmitter.on(e,t)}once(e,t){this.eventEmitter.once(e,t)}off(e,t){this.eventEmitter.off(e,t)}removeListener(e,t){this.eventEmitter.removeListener(e,t)}ensureConfigured(){if(!this._collectionName||"string"!=typeof this._collectionName)throw new Error("AmbitenModel: collectionName is not configured.");if(!this._provider||"function"!=typeof this._provider.db)throw new Error("AmbitenModel: provider is not configured. Provide a valid DbProvider with a db(ctx) method.")}async init(){if(!this._initialized)try{this.ensureConfigured(),this._schema||(this._schema=new r.AmbitenSchema({})),await this.getCollection(),this.isGCEnabled()&&this._modelGCConfig&&await this.ensureGCIndex(this._modelGCConfig),this._initialized=!0}catch(e){throw(0,u.createAmbitenError)(u.ErrorType.INITIALIZATION_ERROR,`Failed to initialize AmbitenModel: ${e?.message??String(e)}`,{details:{operation:"init",TypeError:u.ErrorType.INITIALIZATION_ERROR}})}}bind(e){const t=Object.create(this);return t._defaultCtx={...this._defaultCtx,...e},t}async registerModel(e){const{ctx:t,collectionName:n,schema:i,collection:o}=e;if(!n)throw new Error("Collection name is required.");this._collectionName=n,this._collectionOverride=o,this._schema=i??new r.AmbitenSchema({}),t&&(this._defaultCtx={...this._defaultCtx,...t}),this._initialized=!1,this.ensureConfigured(),await this.init()}async ensureGCIndex(e){if(!e.enableGC||!e.ttl)return;const t=await this.getCollection(),n=e.field??e.updatedAtField??e.createdAtField??"updatedAt";await t.createIndex({[n]:1},{expireAfterSeconds:e.ttl,name:e.indexName??`${this._collectionName}_${n}_ttl`,background:!0})}get schema(){return this._schema}getSchema(){return this.schema}validate(e){this._schema&&this._schema.validate(e)}async validateAsync(e){return this._schema&&await this._schema.validateAsync(e),e}initMiddleware(){this._schema&&(this._schema.pre("create",async e=>{const t=e.doc;if(!t)return;const n=this._schema.getRelationships()??[];for(const{ref:e,localField:i}of n){const n=(await this.getCollection()).db?.collection(e),o={[i]:t._id};await(n?.updateMany(o,{$set:{[i]:t._id}}))}}),this._schema.post("create",async e=>{const t=e.result??e.doc;if(!t)return;const n=this._schema.getRelationships()??[];for(const{ref:e,localField:i}of n){const n=(await this.getCollection()).db?.collection(e),o={[i]:t._id};await(n?.updateOne(o,{$set:{[i]:t._id}}))}await f.publish("DB_CHANGE",{dbChange:{action:"create",doc:t}})}),this._schema.post("updateOne",async e=>{const t=e.filter,n=e.update;if(!t||!n)return;const i=this._schema.getRelationships()??[];for(const{ref:e,localField:t}of i){const i=(await this.getCollection()).db?.collection(e),o={[t]:n.$set?._id};await(i?.updateOne(o,{$set:{[t]:n.$set?._id}}))}await f.publish("DB_CHANGE",{dbChange:{action:"updateOne",filter:t,update:n}})}),this._schema.pre("deleteOne",async e=>{const t=e.doc??e.result;if(!t)return;const n=this._schema.getRelationships()??[];for(const{ref:e,localField:i}of n){const n=(await this.getCollection()).db?.collection(e),o={[i]:t._id};await(n?.deleteOne(o))}}),this._schema.pre("aggregate",async e=>{const t=e.pipeline;if(!t)return;const n=this._schema.getRelationships()??[];for(const{ref:e,localField:i}of n)t.unshift({$lookup:{from:e,localField:i,foreignField:"_id",as:e}})}),this._schema.post("aggregate",async e=>{const t=e.result;if(!t)return;const n=this._schema.getRelationships()??[];for(const e of t)for(const{ref:t}of n)delete e[t];await f.publish("DB_CHANGE",{dbChange:{action:"aggregate",result:t}})}))}async create(e,t){if(await this.init(),!e||"object"!=typeof e)throw new Error("Document must be a valid object.");return this.runWithModelContext(t,async()=>(0,h.measureQuery)({operation:"create",collectionName:this.resolveCollectionName(t),documentCount:1},async()=>{const n=this.resolveCollectionName(t),i=this.resolveSession(t),o=await this.getCollection(t),a=this.buildMiddlewareContext("create",t,{doc:e});a.collectionName=a.collectionName??n,await this.runBeforeMiddlewares("create",a);const r=a.doc??e;a.doc=r,this.validate(r),await this.schema.executePre("create",this.buildHookPayload("create",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,doc:r,meta:a.meta}));const s=await o.insertOne(r,i?{session:i}:void 0),l={...r,_id:s.insertedId};await this.schema.executePost("create",this.buildHookPayload("create",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,doc:l,result:l,meta:a.meta}));const c=this.toModelResult(l);a.result=c,await this.runAfterMiddlewares("create",a);const d=a.result??c;return await this.invalidateCachePatterns("create",a),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentInserted:{action:"create",collectionName:a.collectionName,doc:d,meta:a.meta}}),d}))}async find(e={},t,n){if(await this.init(),!e||"object"!=typeof e)throw new Error("Filter must be a valid object.");return this.runWithModelContext(t,async()=>(0,h.measureQuery)({operation:"find",collectionName:this.resolveCollectionName(t),filter:e},async()=>{const i=this.resolveCollectionName(t),o=this.resolveSession(t),a=await this.getCollection(t),r=this.buildMiddlewareContext("find",t,{filter:e});r.collectionName=r.collectionName??i,await this.runBeforeMiddlewares("find",r);const s=r.filter??e;r.filter=s;const l=n?.cache?this.resolveCache(n):null;await this.schema.executePre("find",this.buildHookPayload("create",t,{collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:o,filter:s,meta:r.meta}));let c=null;if(l){c=this.buildCacheKey("find",{collectionName:r.collectionName,filter:s,tenantId:r.tenantId,dbName:r.dbName});const e=await l.get(c,{ttlSeconds:"object"==typeof n?.cache?n.cache.ttl:void 0,tenantId:r.tenantId,namespace:r.collectionName});if(e)return r.result=e,await this.schema.executePost("find",this.buildHookPayload("find",t,{collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:o,filter:s,result:e,meta:{...r.meta??{},cacheHit:!0}})),await this.runAfterMiddlewares("find",r),r.result??e}const d=a.find(s,o?{session:o}:void 0),u=await d.toArray(),m=this.toModelResults(u);await this.schema.executePost("find",this.buildHookPayload("find",t,{collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:o,filter:s,result:m,meta:r.meta})),r.result=m,await this.runAfterMiddlewares("find",r);const h=r.result??m;return l&&c&&await l.set(c,h,{ttlSeconds:"object"==typeof n?.cache?n.cache.ttl:void 0,tenantId:r.tenantId,namespace:r.collectionName}),h}))}async findOne(e,t,n){if(await this.init(),!e||"object"!=typeof e)throw new Error("Filter must be a valid object.");return this.runWithModelContext(t,async()=>(0,h.measureQuery)({operation:"findOne",collectionName:this.resolveCollectionName(t),filter:e},async()=>{const i=this.resolveCollectionName(t),o=this.resolveSession(t),a=await this.getCollection(t),r=this.buildMiddlewareContext("findOne",t,{filter:e});r.collectionName=r.collectionName??i,await this.runBeforeMiddlewares("findOne",r);const s=r.filter??e;r.filter=s;const l=n?.cache?this.resolveCache(n):null;let c=null;if(await this.schema.executePre("findOne",this.buildHookPayload("findOne",t,{collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:o,filter:s,meta:r.meta})),l){c=this.buildCacheKey("findOne",{collectionName:r.collectionName,filter:s,tenantId:r.tenantId,dbName:r.dbName});const e=await l.get(c,{ttlSeconds:"object"==typeof n?.cache?n.cache.ttl:void 0,tenantId:r.tenantId,namespace:r.collectionName});if(null!=e)return r.result=e,await this.schema.executePost("findOne",this.buildHookPayload("findOne",t,{collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:o,filter:s,result:e,meta:{...r.meta??{},cacheHit:!0}})),await this.runAfterMiddlewares("findOne",r),r.result??e}const d=await a.findOne(s,o?{session:o}:void 0),u=d?this.toModelResult(d):null;await this.schema.executePost("findOne",{operation:"findOne",collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:o,filter:s,result:u,meta:r.meta}),r.result=u,await this.runAfterMiddlewares("findOne",r);const m=r.result??u;return l&&c&&null!==m&&await l.set(c,m,{ttlSeconds:"object"==typeof n?.cache?n.cache.ttl:void 0,tenantId:r.tenantId,namespace:r.collectionName}),m}))}async updateOne(e,t,n){if(await this.init(),!e||"object"!=typeof e)throw new Error("Filter must be a valid object.");if(!t||"object"!=typeof t)throw new Error("Update must be a valid object.");return this.runWithModelContext(n,async()=>(0,h.measureQuery)({operation:"updateOne",collectionName:this.resolveCollectionName(n),filter:e,update:t},async()=>{const i=this.resolveCollectionName(n),o=this.resolveSession(n),a=await this.getCollection(n),r=this.buildMiddlewareContext("updateOne",n,{filter:e,update:t});r.collectionName=r.collectionName??i,await this.runBeforeMiddlewares("updateOne",r);const s=r.filter??e,l=r.update??t;r.filter=s,r.update=l,await this.schema.executePre("updateOne",{operation:"updateOne",collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:o,filter:s,update:l,meta:r.meta});const c=await a.updateOne(s,l,o?{session:o}:void 0),d={acknowledged:c?.acknowledged,matchedCount:c?.matchedCount,modifiedCount:c?.modifiedCount,upsertedCount:c?.upsertedCount,upsertedId:c?.upsertedId};await this.schema.executePost("updateOne",{operation:"updateOne",collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:o,filter:s,update:l,result:d,meta:r.meta}),r.result=d,await this.runAfterMiddlewares("updateOne",r),await this.invalidateCachePatterns("updateOne",r),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentUpdated:{action:"updateOne",collectionName:r.collectionName,filter:s,update:l,result:d,meta:r.meta}})}))}async bulkInsert(e,t){if(await this.init(),Array.isArray(e)&&0!==e.length)return this.runWithModelContext(t,async()=>(0,h.measureQuery)({operation:"bulkInsert",collectionName:this.resolveCollectionName(t),documentCount:e.length},async()=>{const n=this.resolveCollectionName(t),i=this.resolveSession(t),o=await this.getCollection(t),a=this.buildMiddlewareContext("bulkInsert",t,{docs:e});a.collectionName=a.collectionName??n,await this.runBeforeMiddlewares("bulkInsert",a);const r=a.docs??e;if(a.docs=r,!Array.isArray(r)||0===r.length)return a.result=[],void await this.runAfterMiddlewares("bulkInsert",a);for(const e of r){if(!e||"object"!=typeof e)throw new Error("Each document must be a valid object.");this.validate(e)}const s=this.buildOperationMeta(a.meta,{bulkWrite:!0});await this.schema.executePre("bulkInsert",this.buildHookPayload("bulkInsert",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,docs:r,meta:s}));const l=await o.insertMany(r,{ordered:!1,...i?{session:i}:{}}),c=r.map((e,t)=>({...e,_id:l.insertedIds[t]}));await this.schema.executePost("bulkInsert",this.buildHookPayload("bulkInsert",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,docs:c,result:c,meta:s})),a.result=this.toModelResults(c),await this.runAfterMiddlewares("bulkInsert",a),await this.invalidateCachePatterns("bulkInsert",a),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentInserted:{action:"bulkInsert",collectionName:a.collectionName,docs:a.result,meta:s}})}))}async bulkUpdate(e,t){if(await this.init(),!Array.isArray(e))throw new Error("Updates must be a valid array.");if(0!==e.length)return this.runWithModelContext(t,async()=>(0,h.measureQuery)({operation:"bulkUpdate",collectionName:this.resolveCollectionName(t),documentCount:e.length},async()=>{const n=this.resolveCollectionName(t),i=this.resolveSession(t),o=await this.getCollection(t),a=this.buildMiddlewareContext("bulkUpdate",t,{bulkUpdates:e});a.collectionName=a.collectionName??n,await this.runBeforeMiddlewares("bulkUpdate",a);const r=a.bulkUpdates??e;a.bulkUpdates=r;const s=this.buildOperationMeta(a.meta,{bulkWrite:!0});if(a.meta=s,!Array.isArray(r)||0===r.length)return a.result={acknowledged:!0,matchedCount:0,modifiedCount:0,upsertedCount:0,insertedCount:0,deletedCount:0},void await this.runAfterMiddlewares("bulkUpdate",a);for(const e of r){if(!e||"object"!=typeof e)throw new Error("Each bulk update entry must be a valid object.");if(!e.filter||"object"!=typeof e.filter)throw new Error("Each bulk update filter must be a valid object.");if(!e.update||"object"!=typeof e.update)throw new Error("Each bulk update document must be a valid object.")}const l=r.map(({filter:e,update:t})=>({updateOne:{filter:e,update:{$set:t}}}));await this.schema.executePre("bulkUpdate",this.buildHookPayload("bulkUpdate",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,bulkUpdates:r,meta:s}));const c=await o.bulkWrite(l,{ordered:!1,...i?{session:i}:{}}),d={acknowledged:c?.isOk?.()??!0,matchedCount:c?.matchedCount,modifiedCount:c?.modifiedCount,upsertedCount:c?.upsertedCount,insertedCount:c?.insertedCount,deletedCount:c?.deletedCount};await this.schema.executePost("bulkUpdate",this.buildHookPayload("bulkUpdate",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,bulkUpdates:r,result:d,meta:s})),a.result=d,await this.runAfterMiddlewares("bulkUpdate",a),await this.invalidateCachePatterns("bulkUpdate",a),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentUpdated:{action:"bulkUpdate",collectionName:a.collectionName,bulkUpdates:r,result:d,meta:s}})}))}async deleteOne(e,t){if(await this.init(),!e||"object"!=typeof e)throw new Error("Filter must be a valid object.");return this.runWithModelContext(t,async()=>(0,h.measureQuery)({operation:"deleteOne",collectionName:this.resolveCollectionName(t),filter:e},async()=>{const n=this.resolveCollectionName(t),i=this.resolveSession(t),o=await this.getCollection(t),a=this.buildMiddlewareContext("deleteOne",t,{filter:e});a.collectionName=a.collectionName??n,await this.runBeforeMiddlewares("deleteOne",a);const r=a.filter??e;a.filter=r;const s=await o.findOne(r,i?{session:i}:void 0);if(!s)return a.result=null,void await this.runAfterMiddlewares("deleteOne",a);const l=this.toModelResult(s);a.result=l;const c=this.buildOperationMeta(a.meta);if(a.meta=c,!0===c.softDelete){const e=a.update;if(!e)throw new Error("Soft delete is enabled but no soft delete update payload was provided.");await this.schema.executePre("updateOne",this.buildHookPayload("deleteOne",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,filter:r,update:e,result:l,meta:c})),await o.updateOne(r,e,i?{session:i}:void 0),await this.schema.executePost("updateOne",this.buildHookPayload("deleteOne",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,filter:r,update:e,result:l,meta:c}))}else await this.schema.triggerMiddleware("pre","deleteOne",{operation:"deleteOne",collectionName:a.collectionName,...l}),await this.schema.executePre("deleteOne",this.buildHookPayload("deleteOne",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,doc:l,result:l,meta:c})),await o.deleteOne(r,i?{session:i}:void 0),await this.schema.triggerMiddleware("post","deleteOne",{operation:"deleteOne",collectionName:a.collectionName,...l}),await this.schema.executePost("deleteOne",this.buildHookPayload("deleteOne",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,doc:l,result:l,meta:c}));await this.runAfterMiddlewares("deleteOne",a),await this.invalidateCachePatterns("deleteOne",a),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentDeleted:{action:c.softDelete?"softDelete":"deleteOne",collectionName:a.collectionName,filter:r,meta:a.meta}})}))}async deleteMany(e,t){if(await this.init(),!e||"object"!=typeof e)throw new Error("Filter must be a valid object.");return this.runWithModelContext(t,async()=>(0,h.measureQuery)({operation:"deleteMany",collectionName:this.resolveCollectionName(t),filter:e},async()=>{const n=this.resolveCollectionName(t),i=this.resolveSession(t),o=await this.getCollection(t),a=this.buildMiddlewareContext("deleteMany",t,{filter:e});a.collectionName=a.collectionName??n,await this.runBeforeMiddlewares("deleteMany",a);const r=a.filter??e;a.filter=r;const s=this.buildOperationMeta(a.meta);a.meta=s;const l=await o.find(r,i?{session:i}:void 0).toArray();if(0===l.length)return a.result={deletedCount:0,docs:[]},void await this.runAfterMiddlewares("deleteMany",a);const c=this.toModelResults(l);if(!0===s.softDelete){const e=a.update;if(!e)throw new Error("Soft delete is enabled but no soft delete update payload was provided.");const n=this.buildOperationMeta(s,{softDelete:!0});await this.schema.executePre("updateMany",this.buildHookPayload("deleteMany",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,filter:r,update:e,docs:l,result:c,meta:n}));const d={deletedCount:(await o.updateMany(r,e,i?{session:i}:void 0)).modifiedCount,docs:c,softDeleted:!0};await this.schema.executePost("updateMany",this.buildHookPayload("deleteMany",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,filter:r,update:e,docs:l,result:d,meta:n})),a.result=d}else{await this.schema.triggerMiddleware("pre","deleteMany",{operation:"deleteMany",collectionName:a.collectionName,docs:l}),await this.schema.executePre("deleteMany",this.buildHookPayload("deleteMany",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,docs:l,result:c,meta:s}));const e=await o.deleteMany(r,i?{session:i}:void 0),n={deletedCount:e?.deletedCount??0,docs:c};await this.schema.triggerMiddleware("post","deleteMany",{operation:"deleteMany",collectionName:a.collectionName,docs:l}),await this.schema.executePost("deleteMany",this.buildHookPayload("deleteMany",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,docs:l,result:n,meta:s})),a.result=n}await this.runAfterMiddlewares("deleteMany",a),await this.invalidateCachePatterns("deleteMany",a),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentDeleted:{action:s.softDelete?"softDeleteMany":"deleteMany",collectionName:a.collectionName,filter:r,result:a.result,meta:a.meta}})}))}async populateOne(e,t,n){if(await this.init(),!e||"object"!=typeof e)return null;const i=e[t];if(null==i)return e;const o=await n.findOne({_id:i});return{...e,[t]:o}}async populateMany(e,t,n){if(await this.init(),!e||"object"!=typeof e)return null;const i=e[t];if(!Array.isArray(i)||0===i.length)return e;const o=await n.find({_id:{$in:i}});return{...e,[t]:o}}async createWithTransaction(e,t){if(await this.init(),!e||"object"!=typeof e)throw new Error("Document must be a valid object.");return this.runWithModelContext(t,async()=>this.withTransaction(async()=>(0,h.measureQuery)({operation:"create",collectionName:this.resolveCollectionName(t),documentCount:1},async()=>{const n=this.resolveCollectionName(t),i=this.resolveSession(t),o=await this.getCollection(t),a=this.buildMiddlewareContext("create",t,{doc:e,meta:{transactional:!0}});a.collectionName=a.collectionName??n,await this.runBeforeMiddlewares("create",a);const r=a.doc??e;a.doc=r;const s=this.buildOperationMeta(a.meta,{transactional:!0});this.validate(r),await this.schema.executePre("create",this.buildHookPayload("create",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,doc:r,meta:s}));const l=await o.insertOne(r,i?{session:i}:void 0),c={...r,_id:l.insertedId};await this.schema.executePost("create",this.buildHookPayload("create",t,{operation:"create",collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,doc:c,result:c,meta:s}));const d=this.toModelResult(c);a.result=d,await this.runAfterMiddlewares("create",a),await this.invalidateCachePatterns("create",a);const m=a.result??d;return await f.publish(`${u.DB_CHANGE_EVENT}`,{documentInserted:{action:"create",collectionName:a.collectionName,doc:m,meta:s}}),m}),t))}async bulkWriteWithTransaction(e,t={},n){if(await this.init(),!Array.isArray(e))throw new Error("Operations must be a valid array.");if(0===e.length)throw new Error("Operations array must not be empty.");return this.runWithModelContext(n,async()=>this.withTransaction(async()=>(0,h.measureQuery)({operation:"bulkWrite",collectionName:this.resolveCollectionName(n),documentCount:e.length,extra:{bulkWrite:!0}},async()=>{const i=this.resolveCollectionName(n),o=this.resolveSession(n),a=await this.getCollection(n),r=this.buildMiddlewareContext("bulkUpdate",n,{bulkOperations:e,meta:{transactional:!0,bulkWrite:!0}});r.collectionName=r.collectionName??i,await this.runBeforeMiddlewares("bulkUpdate",r);const s=r.bulkOperations??e;r.bulkOperations=s;const l=this.buildOperationMeta(r.meta,{transactional:!0,bulkWrite:!0});r.meta=l,await this.schema.executePre("bulkUpdate",this.buildHookPayload("bulkUpdate",n,{collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:o,bulkOperations:s,meta:l}));const c=await a.bulkWrite(s,{...t,...o?{session:o}:{}}),d={acknowledged:c?.isOk?.()??!0,matchedCount:c?.matchedCount,modifiedCount:c?.modifiedCount,upsertedCount:c?.upsertedCount,insertedCount:c?.insertedCount,deletedCount:c?.deletedCount};return await this.schema.executePost("bulkUpdate",this.buildHookPayload("bulkUpdate",n,{collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:o,bulkOperations:s,result:d,meta:l})),r.result=d,await this.runAfterMiddlewares("bulkUpdate",r),await this.invalidateCachePatterns("bulkWrite",r),await f.publish(`${u.DB_CHANGE_EVENT}`,{bulkWrite:{action:"bulkWrite",collectionName:r.collectionName,result:d,meta:l}}),c}),n))}async deleteWithTransaction(e,t){if(await this.init(),!e||"object"!=typeof e)throw new Error("Filter must be a valid object.");return this.runWithModelContext(t,async()=>this.withTransaction(async()=>(0,h.measureQuery)({operation:"deleteOne",collectionName:this.resolveCollectionName(t),filter:e},async()=>{const n=this.resolveCollectionName(t),i=this.resolveSession(t),o=await this.getCollection(t),a={transactional:!0},r=this.buildMiddlewareContext("deleteOne",t,{filter:e,meta:a});r.collectionName=r.collectionName??n,await this.runBeforeMiddlewares("deleteOne",r);const s=r.filter??e;r.filter=s;const l=await o.findOne(s,i?{session:i}:void 0);if(!l)return r.result=null,await this.runAfterMiddlewares("deleteOne",r),!1;const c=this.toModelResult(l);r.result=c,await this.schema.triggerMiddleware("pre","deleteOne",{operation:"deleteOne",collectionName:r.collectionName,...c}),await this.schema.executePre("deleteOne",{operation:"deleteOne",collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:i,doc:l,result:c,meta:a});const d=await o.deleteOne(s,i?{session:i}:void 0);return await this.schema.triggerMiddleware("post","deleteOne",{operation:"deleteOne",collectionName:r.collectionName,...c}),await this.schema.executePost("deleteOne",{operation:"deleteOne",collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:i,doc:l,result:c,meta:a}),await this.runAfterMiddlewares("deleteOne",r),await this.invalidateCachePatterns("deleteOne",r),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentDeleted:{action:"deleteOne",collectionName:r.collectionName,filter:s,meta:a}}),1===d.deletedCount}),t))}async updateWithTransaction(e,t,n){if(await this.init(),!e||"object"!=typeof e)throw new Error("Filter must be a valid object.");if(!t||"object"!=typeof t)throw new Error("Update must be a valid object.");return this.runWithModelContext(n,async()=>this.withTransaction(async()=>(0,h.measureQuery)({operation:"updateOne",collectionName:this.resolveCollectionName(n),filter:e,update:t},async()=>{const i=this.resolveCollectionName(n),o=this.resolveSession(n),a=await this.getCollection(n),r={transactional:!0},s=this.buildMiddlewareContext("updateOne",n,{filter:e,update:t,meta:r});s.collectionName=s.collectionName??i,await this.runBeforeMiddlewares("updateOne",s);const l=s.filter??e,c=s.update??t;s.filter=l,s.update=c;const d=await a.findOne(l,o?{session:o}:void 0);if(!d)return s.result=null,await this.runAfterMiddlewares("updateOne",s),null;const m={...d,...c.$set??{}};this.validate(m),await this.schema.executePre("updateOne",{operation:"updateOne",collectionName:s.collectionName,tenantId:s.tenantId,dbName:s.dbName,session:o,filter:l,update:c,meta:r}),await a.updateOne(l,c,o?{session:o}:void 0);const h=await a.findOne(l,o?{session:o}:void 0),p=h?this.toModelResult(h):null;return await this.schema.executePost("updateOne",{operation:"updateOne",collectionName:s.collectionName,tenantId:s.tenantId,dbName:s.dbName,session:o,filter:l,update:c,result:p,meta:r}),s.result=p,await this.runAfterMiddlewares("updateOne",s),await this.invalidateCachePatterns("updateOne",s),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentUpdated:{action:"updateOne",collectionName:s.collectionName,filter:l,update:c,result:p,meta:r}}),s.result??p}),n))}async findOneAndUpdate(e,t,n){if(await this.init(),!e||"object"!=typeof e)throw new Error("Filter must be a valid object.");if(!t||"object"!=typeof t)throw new Error("Update must be a valid object.");return this.runWithModelContext(n,async()=>(0,h.measureQuery)({operation:"findOneAndUpdate",collectionName:this.resolveCollectionName(n),filter:e,update:t},async()=>{const i=this.resolveCollectionName(n),o=this.resolveSession(n),a=await this.getCollection(n),r=this.buildMiddlewareContext("findOneAndUpdate",n,{filter:e,update:t});r.collectionName=r.collectionName??i,await this.runBeforeMiddlewares("findOneAndUpdate",r);const s=r.filter??e,l=r.update??t;r.filter=s,r.update=l,await this.schema.executePre("updateOne",{operation:"findOneAndUpdate",collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:o,filter:s,update:l,meta:r.meta});const c=await a.findOneAndUpdate(s,l,{returnDocument:"after",...o?{session:o}:{}}),d=c&&"object"==typeof c&&"value"in c?c.value:c,m=d?this.toModelResult(d):null;return await this.schema.executePost("updateOne",{operation:"findOneAndUpdate",collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:o,filter:s,update:l,result:m,meta:r.meta}),r.result=m,await this.runAfterMiddlewares("findOneAndUpdate",r),await this.invalidateCachePatterns("findOneAndUpdate",r),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentUpdated:{action:"findOneAndUpdate",collectionName:r.collectionName,filter:s,update:l,result:m,meta:r.meta}}),r.result??m}))}async findOneAndDelete(e,t){if(await this.init(),!e||"object"!=typeof e)throw new Error("Filter must be a valid object.");return this.runWithModelContext(t,async()=>(0,h.measureQuery)({operation:"findOneAndDelete",collectionName:this.resolveCollectionName(t),filter:e},async()=>{const n=this.resolveCollectionName(t),i=this.resolveSession(t),o=await this.getCollection(t),a=this.buildMiddlewareContext("findOneAndDelete",t,{filter:e});a.collectionName=a.collectionName??n,await this.runBeforeMiddlewares("findOneAndDelete",a);const r=a.filter??e;a.filter=r;const s=this.buildOperationMeta(a.meta);a.meta=s;const l=await o.findOne(r,i?{session:i}:void 0);if(!l)return a.result=null,await this.runAfterMiddlewares("findOneAndDelete",a),null;const c=this.toModelResult(l);if(a.result=c,!0===s.softDelete){const e=a.update??this.buildSoftDeleteUpdate();a.update=e;const n=this.buildOperationMeta(s,{softDelete:!0});return await this.schema.executePre("updateOne",this.buildHookPayload("findOneAndDelete",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,filter:r,update:e,result:c,meta:n})),await o.updateOne(r,e,i?{session:i}:void 0),await this.schema.executePost("updateOne",this.buildHookPayload("findOneAndDelete",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,filter:r,update:e,result:c,meta:n})),await this.runAfterMiddlewares("findOneAndDelete",a),await this.invalidateCachePatterns("findOneAndDelete",a),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentDeleted:{action:"softDeleteOne",collectionName:a.collectionName,filter:r,meta:n}}),a.result??c}await this.schema.triggerMiddleware("pre","deleteOne",{operation:"findOneAndDelete",collectionName:a.collectionName,...c}),await this.schema.executePre("deleteOne",this.buildHookPayload("findOneAndDelete",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,doc:l,result:c,meta:s}));const d=i?{session:i}:{},m=await o.findOneAndDelete(r,d),h=m&&"object"==typeof m&&"value"in m?m.value:m,p=h?this.toModelResult(h):c;return await this.schema.triggerMiddleware("post","deleteOne",{operation:"findOneAndDelete",collectionName:a.collectionName,...p??{}}),await this.schema.executePost("deleteOne",this.buildHookPayload("findOneAndDelete",t,{collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,doc:l,result:p,meta:s})),a.result=p,await this.runAfterMiddlewares("findOneAndDelete",a),await this.invalidateCachePatterns("findOneAndDelete",a),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentDeleted:{action:"findOneAndDelete",collectionName:a.collectionName,filter:r,result:p,meta:s}}),a.result??p}))}async findOneAndReplace(e,t,n){if(await this.init(),!e||"object"!=typeof e)throw new Error("Filter must be a valid object.");if(!t||"object"!=typeof t)throw new Error("Replacement document must be a valid object.");return this.runWithModelContext(n,async()=>(0,h.measureQuery)({operation:"findOneAndReplace",collectionName:this.resolveCollectionName(n),filter:e},async()=>{const i=this.resolveCollectionName(n),o=this.resolveSession(n),a=await this.getCollection(n),r=this.buildMiddlewareContext("findOneAndReplace",n,{filter:e,doc:t});r.collectionName=r.collectionName??i,await this.runBeforeMiddlewares("findOneAndReplace",r);const s=r.filter??e,l=r.doc??t;r.filter=s,r.doc=l,this.validate(l),await this.schema.executePre("updateOne",{operation:"findOneAndReplace",collectionName:r.collectionName,filter:s,doc:l});const c=await a.findOneAndReplace(s,l,{returnDocument:"after",...o?{session:o}:{}}),d=c&&"object"==typeof c&&"value"in c?c.value:c,m=d?this.toModelResult(d):null;return await this.schema.executePost("updateOne",{operation:"findOneAndReplace",collectionName:r.collectionName,filter:s,doc:l,result:d}),r.result=m,await this.runAfterMiddlewares("findOneAndReplace",r),await this.invalidateCachePatterns("findOneAndReplace",r),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentUpdated:{action:"findOneAndReplace",filter:s,replacement:l}}),r.result??m}))}async findOneAndUpsert(e,t,n){if(await this.init(),!e||"object"!=typeof e)throw new Error("Filter must be a valid object.");if(!t||"object"!=typeof t)throw new Error("Update must be a valid object.");return this.runWithModelContext(n,async()=>(0,h.measureQuery)({operation:"findOneAndUpsert",collectionName:this.resolveCollectionName(n),filter:e,update:t},async()=>{const i=this.resolveCollectionName(n),o=this.resolveSession(n),a=await this.getCollection(n),r=this.buildMiddlewareContext("findOneAndUpsert",n,{filter:e,update:t});r.collectionName=r.collectionName??i,await this.runBeforeMiddlewares("findOneAndUpsert",r);const s=r.filter??e,l=r.update??t;r.filter=s,r.update=l,await this.schema.executePre("updateOne",{operation:"findOneAndUpsert",collectionName:r.collectionName,filter:s,update:l});const c=await a.findOneAndUpdate(s,l,{upsert:!0,returnDocument:"after",...o?{session:o}:{}}),d=c&&"object"==typeof c&&"value"in c?c.value:c,m=d?this.toModelResult(d):null;return await this.schema.executePost("updateOne",{operation:"findOneAndUpsert",collectionName:r.collectionName,filter:s,update:l,result:d}),r.result=m,await this.runAfterMiddlewares("findOneAndUpsert",r),await this.invalidateCachePatterns("findOneAndUpsert",r),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentUpdated:{action:"findOneAndUpsert",filter:s,update:l}}),r.result??m}))}async findOneAndUpsertWithTransaction(e,t,n){if(await this.init(),!e||"object"!=typeof e)throw new Error("Filter must be a valid object.");if(!t||"object"!=typeof t)throw new Error("Update must be a valid object.");return this.runWithModelContext(n,async()=>this.withTransaction(async()=>{const i=this.resolveCollectionName(n),o=await this.getCollection(n),a=this.resolveSession(n),r=this.buildMiddlewareContext("findOneAndUpsert",n,{filter:e,update:t,meta:{transactional:!0}});r.collectionName=r.collectionName??i,await this.runBeforeMiddlewares("findOneAndUpsert",r);const s=r.filter??e,l=r.update??t;r.filter=s,r.update=l,await this.schema.executePre("updateOne",{operation:"findOneAndUpsert",collectionName:r.collectionName,filter:s,update:l,meta:{transactional:!0}});const c=await o.findOneAndUpdate(s,l,{upsert:!0,returnDocument:"after",...a?{session:a}:{}}),d=c&&"object"==typeof c&&"value"in c?c.value:c,m=d?this.toModelResult(d):null;return await this.schema.executePost("updateOne",{operation:"findOneAndUpsert",collectionName:r.collectionName,filter:s,update:l,result:d,meta:{transactional:!0}}),r.result=m,await this.runAfterMiddlewares("findOneAndUpsert",r),await this.invalidateCachePatterns("findOneAndUpsert",r),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentUpdated:{action:"findOneAndUpsert",filter:s,update:l,meta:{transactional:!0}}}),r.result??m},n))}async findOneAndUpsertWithTransactionSecure(e,t,n,i){if(await this.init(),!e||"object"!=typeof e)throw new Error("Filter must be a valid object.");if(!t||"object"!=typeof t)throw new Error("Update must be a valid object.");if(!n)throw new Error("User is required.");return this.runWithModelContext(i,async()=>this.withTransaction(async()=>{if("admin"!==n.role)throw new Error("Unauthorized");const o={transactional:!0,secure:!0,userId:n.id,userRole:n.role},a=this.resolveCollectionName(i),r=await this.getCollection(i),s=this.resolveSession(i),l=this.buildMiddlewareContext("findOneAndUpsert",i,{filter:e,update:t,meta:o});l.collectionName=l.collectionName??a,await this.runBeforeMiddlewares("findOneAndUpsert",l);const c=l.filter??e,d=l.update??t;l.filter=c,l.update=d,await this.schema.executePre("updateOne",{operation:"findOneAndUpsert",collectionName:l.collectionName,filter:c,update:d,meta:o});const m=await r.findOneAndUpdate(c,d,{upsert:!0,returnDocument:"after",...s?{session:s}:{}}),h=m&&"object"==typeof m&&"value"in m?m.value:m,p=h?this.toModelResult(h):null;return await this.schema.executePost("updateOne",{operation:"findOneAndUpsert",collectionName:l.collectionName,filter:c,update:d,result:h,meta:o}),l.result=p,await this.runAfterMiddlewares("findOneAndUpsert",l),await this.invalidateCachePatterns("findOneAndUpsert",l),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentUpdated:{action:"findOneAndUpsert",filter:c,update:d,meta:o}}),l.result??p},i))}async deleteSecure(e,t,n){if(await this.init(),!e||"object"!=typeof e)throw new Error("Filter must be a valid object.");if(!t)throw new Error("User is required.");return this.runWithModelContext(n,async()=>(0,h.measureQuery)({operation:"deleteOne",collectionName:this.resolveCollectionName(n),filter:e},async()=>{if("admin"!==t.role)throw new Error("Unauthorized");const i={secure:!0,userId:t.id,userRole:t.role},o=this.resolveCollectionName(n),a=await this.getCollection(n),r=this.resolveSession(n),s=this.buildMiddlewareContext("deleteOne",n,{filter:e,meta:i});s.collectionName=s.collectionName??o,await this.runBeforeMiddlewares("deleteOne",s);const l=s.filter??e;s.filter=l;const c=await a.findOne(l,r?{session:r}:void 0);if(!c)return s.result=null,void await this.runAfterMiddlewares("deleteOne",s);const d=this.toModelResult(c);s.result=d,await this.schema.executePre("deleteOne",{operation:"deleteOne",collectionName:s.collectionName,...c,meta:i}),await a.deleteOne(l,r?{session:r}:void 0),await this.schema.executePost("deleteOne",{operation:"deleteOne",collectionName:s.collectionName,...c,meta:i}),await this.runAfterMiddlewares("deleteOne",s),await this.invalidateCachePatterns("deleteOne",s),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentDeleted:{action:"deleteOne",filter:l,meta:i}})}))}async aggregate(e,t={},n,i,o){if(await this.init(),!Array.isArray(e))throw new Error("Pipeline must be a valid array.");return this.runWithModelContext(i,async()=>(0,h.measureQuery)({operation:"aggregate",collectionName:this.resolveCollectionName(i),pipeline:e},async()=>{const a=this.resolveCollectionName(i),r=await this.getCollection(i),s=this.resolveSessionStrict(i,n),l=this.buildMiddlewareContext("aggregate",i,{pipeline:e});l.collectionName=l.collectionName??a,await this.runBeforeMiddlewares("aggregate",l);const c=l.pipeline??e;l.pipeline=c;const d=o?.cache?this.resolveCache(o):null;await this.schema.executePre("aggregate",{operation:"aggregate",collectionName:l.collectionName,tenantId:l.tenantId,dbName:l.dbName,session:s,pipeline:c,meta:l.meta});let m=null;if(d){m=this.buildCacheKey("aggregate",{collectionName:l.collectionName,pipeline:c,options:t,tenantId:l.tenantId,dbName:l.dbName});const e=await d.get(m,{ttlSeconds:"object"==typeof o?.cache?o.cache.ttl:void 0,tenantId:l.tenantId,namespace:l.collectionName});if(e)return l.result=e,await this.runAfterMiddlewares("aggregate",l),l.result??e}const h=r.aggregate(c,{...t,...s?{session:s}:{}}),p=await h.toArray();await this.schema.executePost("aggregate",{operation:"aggregate",collectionName:l.collectionName,tenantId:l.tenantId,dbName:l.dbName,session:s,pipeline:c,result:p,meta:l.meta}),l.result=p,await this.runAfterMiddlewares("aggregate",l);const g=l.result??p;return d&&m&&await d.set(m,g,{ttlSeconds:"object"==typeof o?.cache?o.cache.ttl:void 0,tenantId:l.tenantId,namespace:l.collectionName}),await f.publish(`${u.DB_CHANGE_EVENT}`,{dbChange:{action:"aggregate",pipeline:c}}),g}))}async aggregateWithTransaction(e,t={},n){if(await this.init(),!Array.isArray(e))throw new Error("Pipeline must be a valid array.");return this.runWithModelContext(n,async()=>this.withTransaction(async()=>(0,h.measureQuery)({operation:"aggregate",collectionName:this.resolveCollectionName(n),pipeline:e},async()=>{const i=this.resolveCollectionName(n),o=await this.getCollection(n),a=this.resolveSession(n),r=this.buildMiddlewareContext("aggregate",n,{pipeline:e,meta:{transactional:!0}});r.collectionName=r.collectionName??i,await this.runBeforeMiddlewares("aggregate",r);const s=r.pipeline??e;r.pipeline=s,await this.schema.executePre("aggregate",{operation:"aggregate",collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:a,pipeline:s,meta:{...r.meta??{},transactional:!0}});const l=o.aggregate(s,{...t,...a?{session:a}:{}}),c=await l.toArray();await this.schema.executePost("aggregate",{operation:"aggregate",collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:a,pipeline:s,result:c,meta:{...r.meta??{},transactional:!0}}),r.result=c,await this.runAfterMiddlewares("aggregate",r);const d=r.result??c;return await f.publish(`${u.DB_CHANGE_EVENT}`,{dbChange:{action:"aggregate",pipeline:s,meta:{transactional:!0}}}),d}),n))}async withTransaction(e,t){const n=this.mergeCtx(t)??{},i=n.collectionName??this._collectionName,o=n.session,a={tenantId:n.tenantId,dbName:n.dbName,collectionName:i};if(o)return m.AmbitenContext.run({...a,session:o},async()=>e(o));if(this._provider?.startSession){const t=await this.getSession(n);return await m.AmbitenContext.run({...a,session:t},async()=>(0,m.runManualTransaction)(t,e))}return m.AmbitenContext.run(a,async()=>m.AmbitenContext.withTransaction(e))}async runInTransaction(e,t){if(await this.init(),"function"!=typeof e)throw new Error("Operation must be a valid function.");return this.runWithModelContext(t,async()=>this.withTransaction(async t=>e(t),t))}async getSession(e){if(!this._provider?.startSession)throw new Error("Transaction support is not available. Provider does not implement startSession().");return this._provider.startSession(this.mergeCtx(e))}async streamAggregation(e,t={},n){if(await this.init(),!Array.isArray(e))throw new Error("Pipeline must be a valid array.");return this.runWithModelContext(n,async()=>(0,h.measureQuery)({operation:"aggregate",collectionName:this.resolveCollectionName(n),pipeline:e,extra:{streaming:!0}},async()=>{const i=this.resolveCollectionName(n),o=this.resolveSession(n),a=await this.getCollection(n),r=this.buildMiddlewareContext("aggregate",n,{pipeline:e,meta:{streaming:!0}});r.collectionName=r.collectionName??i,await this.runBeforeMiddlewares("aggregate",r);const s=r.pipeline??e;r.pipeline=s;const l={...r.meta??{},streaming:!0};await this.schema.triggerMiddleware("pre","aggregate",{operation:"aggregate",collectionName:r.collectionName,pipeline:s,meta:l}),await this.schema.executePre("aggregate",{operation:"aggregate",collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:o,pipeline:s,meta:l});const c=a.aggregate(s,{...t,...o?{session:o}:{}}).stream();return await this.schema.triggerMiddleware("post","aggregate",{operation:"aggregate",collectionName:r.collectionName,result:c,meta:l}),await this.schema.executePost("aggregate",{operation:"aggregate",collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:o,pipeline:s,result:c,meta:l}),r.result=c,await this.runAfterMiddlewares("aggregate",r),await f.publish(`${u.DB_CHANGE_EVENT}`,{dbChange:{action:"aggregateStream",collectionName:r.collectionName,pipeline:s,meta:l}}),c}))}async aggregateWithCache(e,t,n=300){if(await this.init(),!Array.isArray(e))throw new Error("Pipeline must be an array of objects.");const i=await d.redis.get(t);if(i)return console.info(`[info]: Cache hit: ${t}`),JSON.parse(i);if("string"!=typeof t)throw new Error("Cache key must be a string.");console.info(`[info]: Cache miss: ${t}`);const o=await this.getCollection(),a=await o.aggregate(e).toArray();return await d.redis.set(t,JSON.stringify(a)||""),await d.redis.expire(t,n),console.info("Cache set:",t),this.schema.triggerMiddleware("post","aggregate",{operation:"aggregate",collectionName:this.resolveCollectionName(o),result:[a]}),await f.publish("DB_CHANGE",{dbChange:{action:"aggregate",result:a}}),a||[]}async paginatedFind(e,t,n){await this.init();const i=e;n&&(i._id={$gt:new o.ObjectId(n)});const a=await this.getCollection();return(await a.find(i).limit(t).toArray()).map(({_id:e,...t})=>t)}async watchChanges(e,t){if(await this.init(),"function"!=typeof e)throw new Error("Callback must be a valid function.");return this.runWithModelContext(t,async()=>{const n=this.resolveCollectionName(t),i=(await this.getCollection(t)).watch();return i.on("change",e),await f.publish(`${u.DB_CHANGE_EVENT}`,{dbChange:{action:"watchChanges",collectionName:n}}),i})}async createIndex(e,t){if(await this.init(),!e||"object"!=typeof e)throw new Error("Index fields must be a valid object.");const n=Object.entries(e);if(0===n.length)throw new Error("Index fields must contain at least one entry.");for(const[,e]of n)if(1!==e&&-1!==e)throw new Error("Index direction must be either 1 or -1.");return this.runWithModelContext(t,async()=>{const n=await this.getCollection(t);await n.createIndex(e)})}async dropIndex(e){await this.init();const t=await this.getCollection();await t.dropIndex(e)}async invalidateCachePatterns(e,t){const n=t.tenantId??"default",i=t.dbName??"default",o=t.collectionName??this._collectionName,a=[...[`Ambiten:${n}:${i}:${o}:find:*`,`Ambiten:${n}:${i}:${o}:findOne:*`],`Ambiten:${n}:${i}:${o}:aggregate:*`];await Promise.all([...new Set(a)].map(e=>g.invalidatePattern(e)))}static async invalidatePattern(e){if("string"!=typeof e||0===e.trim().length)throw new Error("Pattern must be a non-empty string.");const t=e.trim();let n=0,i=0;try{do{const e=await d.redis.scan(i,{MATCH:t,COUNT:100}),o=Array.isArray(e)?Number(e[0]):0,a=Array.isArray(e)?e[1]:[];if(Array.isArray(a)&&a.length>0){const e=d.redis.multi();for(const t of a)e.del(t);const t=await e.exec();Array.isArray(t)&&(n+=t.filter(e=>{if(Array.isArray(e)){const[t,n]=e;return!t&&1===n}return 1===e}).length)}i=o}while(0!==i);return n}catch(e){const n=e instanceof Error?e.message:String(e);throw new Error(`Failed to invalidate cache pattern "${t}": ${n}`)}}getContext(){return{ctx:{}}}async invalidateModelPattern(e,t){if(await this.init(),"string"!=typeof e||0===e.trim().length)throw new Error("Pattern must be a non-empty string.");return this.runWithModelContext(t,async()=>{const n=`Ambiten:${t?.tenantId??"default"}:${t?.dbName??"default"}:${t?.collectionName??this._collectionName}:${e.trim()}`;return g.invalidatePattern(n)})}async invalidateDocumentCache(e,t){if(await this.init(),!e||"object"!=typeof e||!("_id"in e)||!e._id)throw new Error("Document must contain a valid _id.");return this.runWithModelContext(t,async()=>{const n=this.mergeCtx(t),i=`Ambiten:${n?.tenantId??"default"}:${n?.dbName??"default"}:${n?.collectionName??this._collectionName}:*${String(e._id)}*`;return g.invalidatePattern(i)})}static async getCacheStats(e){try{const t=await d.redis.info("memory"),n=await d.redis.info("keyspace"),i=Array.from(n.matchAll(/db\d+:keys=(\d+)/g)).reduce((e,t)=>e+Number(t[1]??0),0),o=t.match(/used_memory:(\d+)/),a=o?Number(o[1]):0,r=await d.redis.get("Ambiten:cache:stats:hits")??"0",s=await d.redis.get("Ambiten:cache:stats:misses")??"0",l=Number.parseInt(r,10)||0,c=Number.parseInt(s,10)||0,u=l+c,m=u>0?Math.round(l/u*100):0,h=u>0?Math.round(c/u*100):0;let p;if(e){const t=`Ambiten:${e}:*`;let n=0,i=0;do{const e=await d.redis.scan(n,{MATCH:t,COUNT:100}),o=Array.isArray(e)?Number(e[0]):0,a=Array.isArray(e)?e[1]:[];Array.isArray(a)&&(i+=a.length),n=o}while(0!==n);p=i}return{totalKeys:i,tenantKeys:p,memoryUsageMb:Math.round(a/1024/1024),memoryUsageBytes:a,hitRate:m,missRate:h,totalHits:l,totalMisses:c,totalRequests:u,tenantId:e??null,timestamp:(new Date).toISOString()}}catch(e){const t=e instanceof Error?e.message:String(e);throw new Error(`Failed to get cache stats: ${t}`)}}async runCommand(e,...t){await this.init();const n={[e]:1,...t};return(await this.getCollection()).db.command(n)}async runGC(e){await this.init();const t=this.resolveSchemaGCConfig();if(t&&t.ttlField&&t.expiresIn)return this.runWithModelContext(e,async()=>(0,h.measureQuery)({operation:"runGC",collectionName:this.resolveCollectionName(e)},async()=>{const n=this.resolveCollectionName(e),i=this.resolveSession(e),o=await this.getCollection(e),a=this.buildMiddlewareContext("runGC",e,{meta:{gc:!0}});a.collectionName=a.collectionName??n,await this.runBeforeMiddlewares("runGC",a);const r=new Date(Date.now()-Number(t.expiresIn)),s={[t.ttlField]:{$lt:r}},l=a.filter??s;a.filter=l;const c=await o.find(l,i?{session:i}:void 0).toArray();if(0===c.length)return a.result={scanned:0,affected:0,archived:0,deleted:0,softDeleted:0},void await this.runAfterMiddlewares("runGC",a);let d=0,m=0,h=0;if(t.softDelete){const e={$set:{deletedAt:new Date,isDeleted:!0}};await this.schema.executePre("updateMany",{operation:"runGC",collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,filter:l,update:e,docs:c,meta:{...a.meta??{},gc:!0,softDelete:!0}}),h=(await o.updateMany(l,e,i?{session:i}:void 0)).modifiedCount,await this.schema.executePost("updateMany",{operation:"runGC",collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,filter:l,update:e,docs:c,result:{scanned:c.length,affected:h,archived:0,deleted:0,softDeleted:h},meta:{...a.meta??{},gc:!0,softDelete:!0}})}else{if(t.archiveBeforeDelete){const e=c.map(e=>({...e,_archivedAt:new Date,_from:o.collectionName}));await o.db.collection("Ambiten_archives").insertMany(e,i?{session:i}:void 0),d=e.length}await this.schema.triggerMiddleware("pre","deleteMany",{operation:"runGC",collectionName:a.collectionName,docs:c}),await this.schema.executePre("deleteMany",{operation:"runGC",collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,docs:c,result:this.toModelResults(c),meta:{...a.meta??{},gc:!0}}),m=(await o.deleteMany(l,i?{session:i}:void 0)).deletedCount??0,await this.schema.triggerMiddleware("post","deleteMany",{operation:"runGC",collectionName:a.collectionName,docs:c}),await this.schema.executePost("deleteMany",{operation:"runGC",collectionName:a.collectionName,tenantId:a.tenantId,dbName:a.dbName,session:i,docs:c,result:{scanned:c.length,affected:m,archived:d,deleted:m,softDeleted:0},meta:{...a.meta??{},gc:!0}})}const p={scanned:c.length,affected:h||m,archived:d,deleted:m,softDeleted:h};a.result=p,await this.runAfterMiddlewares("runGC",a),await this.invalidateCachePatterns("runGC",a),await f.publish(`${u.DB_CHANGE_EVENT}`,{garbageCollection:{action:"runGC",collectionName:a.collectionName,...p,meta:{...a.meta??{},gc:!0}}})}))}startAutoGC(e=36e5){setInterval(()=>this.runGC().catch(console.error),e)}resolveInstrumentationContext(e){const t=m.AmbitenContext.get(),n=this.mergeCtx(e);return{tenantId:n?.tenantId,dbName:n?.dbName,collectionName:n?.collectionName??this._collectionName,session:n?.session,requestId:t.requestId}}buildOperationMeta(e,t){return{...e??{},...t??{},extra:{...e?.extra??{},...t?.extra??{}}}}buildHookPayload(e,t,n={}){const i=this.resolveInstrumentationContext(t);return{operation:e,collectionName:n.collectionName??i.collectionName,tenantId:n.tenantId??i.tenantId,dbName:n.dbName??i.dbName,session:n.session??i.session,filter:n.filter,update:n.update,doc:n.doc,docs:n.docs,pipeline:n.pipeline,result:n.result,meta:n.meta}}resolveCache(e){return e?.cache?{get:async(e,t)=>{try{const t=await d.redis.get(e);if(!t)return await g.trackCacheMiss(),null;const n=JSON.parse(t);return await g.trackCacheHit(),n}catch{return null}},set:async(e,t,n)=>{try{const i=n?.ttlSeconds??300;await d.redis.set(e,JSON.stringify(t),{EX:i})}catch{}}}:null}buildCacheKey(e,t){const n=String(t.tenantId??"default"),i=String(t.dbName??"default"),o=String(t.collectionName??this._collectionName),{tenantId:a,dbName:r,collectionName:s,...l}=t,c=this.sortObjectDeep(l);return`Ambiten:${n}:${i}:${o}:${e}:${JSON.stringify(c)}`}static async trackCacheMiss(){try{const e=(new Date).toISOString().slice(0,10),t=604800,n=d.redis.multi();n.incr("Ambiten:cache:stats:misses"),n.incr(`Ambiten:cache:stats:misses:${e}`),n.expire(`Ambiten:cache:stats:misses:${e}`,t),await n.exec()}catch{}}static async trackCacheHit(){try{const e=(new Date).toISOString().slice(0,10),t=604800,n=d.redis.multi();n.incr("Ambiten:cache:stats:hits"),n.incr(`Ambiten:cache:stats:hits:${e}`),n.expire(`Ambiten:cache:stats:hits:${e}`,t),await n.exec()}catch{}}static async cacheResult(e,t,n=3600){if("string"!=typeof e||0===e.trim().length)throw new Error("Cache key must be a non-empty string.");if(!Number.isFinite(n)||n<=0)throw new Error("TTL must be a positive number.");try{await d.redis.set(e,JSON.stringify(t)),await d.redis.expire(e,n)}catch{}}static async clearCache(e){if(!e||"string"!=typeof e)throw new Error("Cache key must be a non-empty string");try{await d.redis.del(e)}catch(t){throw console.error("Error clearing cache:",t),new Error(`Failed to clear cache for key "${e}": ${t}`)}}async warmCache(e,t=3600,n){if(await this.init(),!Number.isFinite(t)||t<=0)throw new Error("Default TTL must be a positive number.");return this.runWithModelContext(n,async()=>{const i=this.resolveCache({cache:{ttl:t}});if(!i)return;const o=this.resolveInstrumentationContext(n),a=await this.getCollection(n),r=this.resolveSession(n),s=e&&e.length>0?e:[{filter:{},ttl:t}];if(e&&0!==e.length||!(await a.countDocuments({},r?{session:r}:void 0)>1e3))for(const e of s){const n=e.filter??{},s=e.ttl??t,l=await a.find(n,r?{session:r}:void 0).toArray(),c=this.toModelResults(l),d=this.buildCacheKey("find",{collectionName:o.collectionName,filter:n,tenantId:o.tenantId,dbName:o.dbName});await i.set(d,c,{ttlSeconds:s,tenantId:o.tenantId,namespace:o.collectionName})}})}sortObjectDeep(e){return Array.isArray(e)?e.map(e=>this.sortObjectDeep(e)):e instanceof Date?e.toISOString():e&&"object"==typeof e?Object.keys(e).sort().reduce((t,n)=>(t[n]=this.sortObjectDeep(e[n]),t),{}):e}toModelResult(e){const{_id:t,...n}=e;return{...n,_id:t.toString()}}toModelResults(e=[]){return e.map(e=>this.toModelResult(e))}async restoreOne(e,t){if(await this.init(),!e||"object"!=typeof e)throw new Error("Filter must be a valid object.");return this.runWithModelContext(t,async()=>(0,h.measureQuery)({operation:"restoreOne",collectionName:this.resolveCollectionName(t),filter:e},async()=>{const n=this.resolveCollectionName(t),i=this.resolveSession(t),o=await this.getCollection(t),a={restore:!0},r=this.buildMiddlewareContext("restoreOne",t,{filter:e,meta:a});r.collectionName=r.collectionName??n,await this.runBeforeMiddlewares("restoreOne",r);const s=r.filter??e;r.filter=s;const l=this.buildRestoreUpdate();if(!await o.findOne(s,i?{session:i}:void 0))return r.result=null,void await this.runAfterMiddlewares("restoreOne",r);await this.schema.executePre("restoreOne",{operation:"restoreOne",collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:i,filter:s,update:l,meta:a});const c=await o.updateOne(s,l,i?{session:i}:void 0),d=await o.findOne(s,i?{session:i}:void 0),m={acknowledged:c.acknowledged,matchedCount:c.matchedCount,modifiedCount:c.modifiedCount,upsertedCount:c.upsertedCount,upsertedId:c.upsertedId,restored:d?this.toModelResult(d):null};await this.schema.executePost("restoreOne",{operation:"restoreOne",collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:i,filter:s,update:l,result:m,meta:a}),r.result=m,await this.runAfterMiddlewares("restoreOne",r),await this.invalidateCachePatterns("restoreOne",r),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentRestored:{action:"restoreOne",collectionName:r.collectionName,filter:s,result:m,meta:a}})}))}async restoreMany(e,t){if(await this.init(),!e||"object"!=typeof e)throw new Error("Filter must be a valid object.");return this.runWithModelContext(t,async()=>(0,h.measureQuery)({operation:"restoreMany",collectionName:this.resolveCollectionName(t),filter:e},async()=>{const n=this.resolveCollectionName(t),i=this.resolveSession(t),o=await this.getCollection(t),a={restore:!0},r=this.buildMiddlewareContext("restoreMany",t,{filter:e,meta:a});r.collectionName=r.collectionName??n,await this.runBeforeMiddlewares("restoreMany",r);const s=r.filter??e;r.filter=s;const l=this.buildRestoreUpdate(),c=await o.find(s,i?{session:i}:void 0).toArray();if(0===c.length)return r.result={restoredCount:0,docs:[]},void await this.runAfterMiddlewares("restoreMany",r);await this.schema.executePre("updateMany",{operation:"restoreMany",collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:i,filter:s,update:l,docs:c,meta:a});const d=await o.updateMany(s,l,i?{session:i}:void 0),m=await o.find(s,i?{session:i}:void 0).toArray(),h={acknowledged:d.acknowledged,matchedCount:c.length,modifiedCount:d.modifiedCount,restoredCount:d.modifiedCount,docs:this.toModelResults(m)};await this.schema.executePost("updateMany",{operation:"restoreMany",collectionName:r.collectionName,tenantId:r.tenantId,dbName:r.dbName,session:i,filter:s,update:l,docs:m,result:h,meta:a}),r.result=h,await this.runAfterMiddlewares("restoreMany",r),await this.invalidateCachePatterns("restoreMany",r),await f.publish(`${u.DB_CHANGE_EVENT}`,{documentRestored:{action:"restoreMany",collectionName:r.collectionName,filter:s,result:h,meta:a}})}))}buildRestoreUpdate(){const e=this._softDeleteConfig?.deletedAtField??"deletedAt",t=this._softDeleteConfig?.isDeletedField??"isDeleted";return{$set:{[e]:null,[t]:!1}}}buildMiddlewareContext(e,t,n={}){const i=this.mergeCtx(t);return{operation:e,modelName:this.constructor.name,collectionName:n.collectionName??i?.collectionName??this._collectionName,tenantId:n.tenantId??i?.tenantId,dbName:n.dbName??i?.dbName,session:n.session??i?.session,withDeleted:n.withDeleted??i?.withDeleted,onlyDeleted:n.onlyDeleted??i?.onlyDeleted,hardDelete:n.hardDelete??i?.hardDelete,filter:n.filter,update:n.update,doc:n.doc,docs:n.docs,pipeline:n.pipeline,bulkUpdates:n.bulkUpdates,bulkOperations:n.bulkOperations,result:n.result,meta:n.meta}}setSoftDeleteConfig(e){this._softDeleteConfig=e}buildSoftDeleteUpdate(){const e=this._softDeleteConfig?.deletedAtField??"deletedAt",t=this._softDeleteConfig?.isDeletedField??"isDeleted";return{$set:{[e]:new Date,[t]:!0}}}async runBeforeMiddlewares(e,t){const n=this.beforeMiddlewares.get(e)??[];for(const e of n)await e(t)}async runAfterMiddlewares(e,t){const n=this.afterMiddlewares.get(e)??[];for(const e of n)await e(t)}before(e,t){const n=this.beforeMiddlewares.get(e)??[];return n.push(t),this.beforeMiddlewares.set(e,n),this}after(e,t){const n=this.afterMiddlewares.get(e)??[];return n.push(t),this.afterMiddlewares.set(e,n),this}beforeFind(e){return this.before("find",e)}afterFind(e){return this.after("find",e)}beforeFindOne(e){return this.before("findOne",e)}afterFindOne(e){return this.after("findOne",e)}beforeSave(e){return this.before("create",e)}afterSave(e){return this.after("create",e)}beforeUpdateOne(e){return this.before("updateOne",e)}afterUpdateOne(e){return this.after("updateOne",e)}beforeDeleteOne(e){return this.before("deleteOne",e)}afterDeleteOne(e){return this.after("deleteOne",e)}beforeDeleteMany(e){return this.before("deleteMany",e)}afterDeleteMany(e){return this.after("deleteMany",e)}beforeBulkInsert(e){return this.before("bulkInsert",e)}afterBulkInsert(e){return this.after("bulkInsert",e)}beforeBulkUpdate(e){return this.before("bulkUpdate",e)}afterBulkUpdate(e){return this.after("bulkUpdate",e)}beforeAggregate(e){return this.before("aggregate",e)}afterAggregate(e){return this.after("aggregate",e)}beforeFindOneAndUpdate(e){return this.before("findOneAndUpdate",e)}afterFindOneAndUpdate(e){return this.after("findOneAndUpdate",e)}beforeFindOneAndDelete(e){return this.before("findOneAndDelete",e)}afterFindOneAndDelete(e){return this.after("findOneAndDelete",e)}beforeFindOneAndReplace(e){return this.before("findOneAndReplace",e)}afterFindOneAndReplace(e){return this.after("findOneAndReplace",e)}beforeFindOneAndUpsert(e){return this.before("findOneAndUpsert",e)}afterFindOneAndUpsert(e){return this.after("findOneAndUpsert",e)}}t.AmbitenModel=g},9528(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0})},9647(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0})},9729(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=n(5584);i.__exportStar(n(1332),t),i.__exportStar(n(6438),t),i.__exportStar(n(3803),t)},9831(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0})},9881(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=n(5584);i.__exportStar(n(2992),t),i.__exportStar(n(7234),t)},9896(e){"use strict";e.exports=require("fs")}},t={};function n(i){var o=t[i];if(void 0!==o)return o.exports;var a=t[i]={id:i,loaded:!1,exports:{}};return e[i](a,a.exports,n),a.loaded=!0,a.exports}n.c=t,n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),n(n.s=3206)})();
|
|
26
26
|
//# sourceMappingURL=index-cli.js.map
|