@vytches/ddd-aggregates 0.26.0 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1 -1
- package/dist/index.js +140 -535
- package/package.json +6 -6
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const T=require("/home/runner/work/ddd/ddd/packages/logging/dist/index.js"),c=require("/home/runner/work/ddd/ddd/packages/domain-primitives/dist/index.js");function D(){return globalThis.crypto.randomUUID()}function I(a,t,e){return{eventName:a,payload:t,metadata:{eventId:D(),timestamp:new Date,...e}}}class p{isType(t){return this.type===t}static get capabilityType(){throw new Error("Capability subclass must override static capabilityType getter")}}class ${constructor(){this.capabilities=new Map}register(t){return this.capabilities.set(t.type,t),this}get(t){const e=t.capabilityType;return this.capabilities.get(e)}getByType(t){return this.capabilities.get(t)}has(t){const e=t.capabilityType;return this.capabilities.has(e)}hasByType(t){return this.capabilities.has(t)}remove(t){const e=t.capabilityType;return this.capabilities.delete(e)}removeByType(t){return this.capabilities.delete(t)}getAll(){return Array.from(this.capabilities.values())}getTypes(){return Array.from(this.capabilities.keys())}clear(){this.capabilities.clear()}get size(){return this.capabilities.size}}class g{constructor(t,e="text"){this.value=t,this.type=e}getValue(){return this.value}getType(){return this.type}validate(t){return t!=null&&t!==void 0}equals(t){return t.getValue()===this.value&&t.getType()===this.type}isType(t){return this.type===t}toString(){return String(this.value)}toJSON(){return JSON.stringify({value:this.value,type:this.type})}static create(){const t="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{const i=Math.random()*16|0;return(e==="x"?i:i&3|8).toString(16)});return new g(t,"uuid")}static createText(t){return new g(t,"text")}static createUuid(t){return new g(t,"uuid")}static createInteger(t){return new g(t.toString(),"integer")}static createBigInt(t){const e=typeof t=="bigint"?t.toString():t;return new g(e,"bigint")}static createWithRandomUUID(){return g.create()}static fromUUID(t){if(!t||typeof t!="string")throw new Error("entity identifier must be provided");if(!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(t))throw new Error("entity identifier must be valid UUID");return new g(t,"uuid")}static fromInteger(t){if(typeof t!="number"||t<0||!Number.isInteger(t))throw new Error("entity identifier must be a non-negative integer");return new g(t.toString(),"integer")}static fromBigInt(t){const e=typeof t=="bigint"?t.toString():t;if(!e||typeof e!="string")throw new Error("entity identifier must be a valid bigint");return new g(e,"bigint")}static fromText(t){if(!t||typeof t!="string")throw new Error("entity identifier must be provided");if(!/^[a-zA-Z0-9_-]+$/.test(t))throw new Error("entity identifier contains invalid characters");return new g(t,"text")}}class o{constructor(t,e,i){this._isSuccess=t,this._value=e,this._error=i}get isSuccess(){return this._isSuccess}get isFailure(){return!this._isSuccess}get value(){if(!this._isSuccess)throw new Error("Cannot get value of a failure result");return this._value}get error(){if(this._isSuccess)throw new Error("Cannot get error of a success result");return this._error}static ok(t){return new o(!0,t)}static empty(){return new o(!0,void 0)}static fail(t){return new o(!1,void 0,t)}static try(t){try{return o.ok(t())}catch(e){return o.fail(e instanceof Error?e:new Error(String(e)))}}map(t){return this.isFailure?o.fail(this.error):o.ok(t(this.value))}flatMap(t){return this.isFailure?o.fail(this.error):t(this.value)}match(t,e){return this.isSuccess?t(this.value):e(this.error)}tap(t){return this.isSuccess&&t(this.value),this}tapError(t){return this.isFailure&&t(this.error),this}mapError(t){return this.isSuccess?o.ok(this.value):o.fail(t(this.error))}static async tryAsync(t){try{const e=await t();return o.ok(e)}catch(e){return o.fail(e instanceof Error?e:new Error(String(e)))}}async mapAsync(t){if(this.isFailure)return o.fail(this.error);try{const e=await t(this.value);return o.ok(e)}catch(e){const i=e instanceof Error?e:new Error(String(e));return o.fail(i)}}async flatMapAsync(t){return this.isFailure?o.fail(this.error):await t(this.value)}}class d extends p{constructor(){super(...arguments),this.type="versioning",this.upcasters=new Map}static get capabilityType(){return"versioning"}attach(t){this.aggregate=t}detach(){this.aggregate=void 0,this.upcasters.clear()}registerUpcaster(t,e,i){this.upcasters.has(t)||this.upcasters.set(t,new Map),this.upcasters.get(t).set(e,i)}handleVersionedEvent(t,e){const i=t.metadata?.version||1,r=t.metadata?.targetVersion||i;let s=t;if(i<r&&this.upcasters.has(t.eventName)){const h=this.upcasters.get(t.eventName),m=T.Logger.forContext("VersioningCapability");for(let l=i;l<r;l++){const S=h.get(l);if(!S){m.warn("Missing upcaster for event version — event will be processed without upcast",{eventName:t.eventName,fromVersion:l,toVersion:l+1});continue}const _=S.upcast(s.payload,s.metadata);s={...s,payload:_,metadata:{...s.metadata,version:l+1}}}}const u=e.get(s.eventName);u&&u(s.payload,s.metadata)}getRegisteredEventTypes(){return Array.from(this.upcasters.keys())}hasUpcaster(t,e){return this.upcasters.get(t)?.has(e)||!1}getUpcastersForType(t){return this.upcasters.get(t)}clearUpcastersForType(t){this.upcasters.delete(t)}getTotalUpcasterCount(){let t=0;for(const e of this.upcasters.values())t+=e.size;return t}}class f{constructor(t){this._version=0,this._initialVersion=0,this._domainEvents=[],this._eventHandlers=new Map,this._capabilities=new $,this._id=t.id,this._version=t.version||0,this._initialVersion=t.version||0,this._maxEvents=t.maxEvents}getId(){return this._id}getVersion(){return this._version}getInitialVersion(){return this._initialVersion}hasChanges(){return this._domainEvents.length>0}getDomainEvents(){return[...this._domainEvents]}commit(){this._domainEvents=[],this._initialVersion=this._version}registerEventHandler(t,e){return this._eventHandlers.set(t,e),this}apply(t,e,i){this._version++;let r,s;typeof t=="string"?(r=I(t,e,i),s=r.metadata):(r=t,s=i?{...r.metadata,...i}:r.metadata);const u=f.sanitizeMetadata({...s,aggregateId:this._id.toString(),aggregateType:this.constructor.name,aggregateVersion:this._version,timestamp:s?.timestamp??new Date}),h=Object.assign(Object.create(Object.getPrototypeOf(r)),r,{metadata:u});if(this._maxEvents!==void 0&&this._domainEvents.length>=this._maxEvents)throw new Error(`Aggregate ${this.constructor.name} (id=${this._id.toString()}) exceeded maxEvents limit of ${this._maxEvents}. This usually indicates a runaway loop or replay of a corrupted event stream. Increase maxEvents in the aggregate constructor params if the limit is too restrictive for your domain.`);this._domainEvents.push(h),this.handleEvent(h)}handleEvent(t){const e=this.getCapability(d);if(e)e.handleVersionedEvent(t,this._eventHandlers);else{const i=this._eventHandlers.get(t.eventName);i&&i(t.payload,t.metadata)}}loadFromHistory(t){this._version=this._initialVersion,this._domainEvents=[];for(const e of t)this.handleEvent(e),this._version++;this._initialVersion=this._version}addCapability(t){return"attach"in t&&typeof t.attach=="function"&&t.attach(this),this._capabilities.register(t),this}getCapability(t){return this._capabilities.get(t)}hasCapability(t){return this._capabilities.has(t)}removeCapability(t){const e=this._capabilities.get(t);return e&&"detach"in e&&typeof e.detach=="function"&&e.detach(),this._capabilities.remove(t),this}getAllCapabilities(){return this._capabilities.getAll()}getCapabilityTypes(){return this._capabilities.getTypes()}static sanitizeMetadata(t){if(!Object.prototype.hasOwnProperty.call(t,"__proto__")&&!Object.prototype.hasOwnProperty.call(t,"constructor")&&!Object.prototype.hasOwnProperty.call(t,"prototype"))return t;const e={};for(const i of Object.keys(t))i==="__proto__"||i==="constructor"||i==="prototype"||(e[i]=t[i]);return e}_internal_setState(t){this._version=t.version,this._initialVersion=t.initialVersion,this._domainEvents=[...t.domainEvents]}}class y extends p{constructor(){super(...arguments),this.type="audit",this.auditLog=[]}static get capabilityType(){return"audit"}attach(t){this.aggregate=t;const e=this.aggregate;typeof e.apply=="function"&&(this.originalApply=e.apply,this.originalApply&&(this.aggregate.apply=(...i)=>{const r=this.originalApply.call(this.aggregate,...i);return this.recordAuditEvent(),r}))}detach(){this.aggregate&&this.originalApply&&(this.aggregate.apply=this.originalApply),this.aggregate=void 0,this.auditLog=[],this.originalApply=void 0}getAuditLog(){return[...this.auditLog]}clearAuditLog(){this.auditLog=[]}getAuditStatistics(){const t={};let e=0;this.auditLog.forEach((r,s)=>{if(t[r.eventName]=(t[r.eventName]||0)+1,s>0){const u=this.auditLog[s-1];if(u){const h=new Date(u.timestamp).getTime(),m=new Date(r.timestamp).getTime();e+=m-h}}});const i=this.auditLog.length>1?e/(this.auditLog.length-1):0;return{totalEvents:this.auditLog.length,eventsByType:t,averageTimeBetweenEvents:i}}recordAuditEvent(){const t=this.aggregate.getDomainEvents(),e=t[t.length-1];e&&this.recordEvent(e)}recordEvent(t){const e={eventId:t.metadata?.eventId||`audit-${Date.now()}-${Math.random()}`,eventName:t.eventName,aggregateId:this.aggregate.getId().toString(),aggregateType:this.aggregate.constructor.name,aggregateVersion:this.aggregate.getVersion(),timestamp:new Date,payload:t.payload,metadata:{...t.metadata,auditCapability:!0},actor:t.metadata?.userId};this.auditLog.push(e)}getEventsByName(t){return this.auditLog.filter(e=>e.eventName===t)}getEventsByTimeRange(t,e){return this.auditLog.filter(i=>{const r=new Date(i.timestamp).getTime();return r>=t.getTime()&&r<=e.getTime()})}getFirstEvent(){return this.auditLog[0]||null}getLastEvent(){return this.auditLog[this.auditLog.length-1]||null}}class n extends c.IDomainError{static invalidArguments(t,e){const i={code:c.DomainErrorCode.InvalidParameter,data:e};return new n(t,i)}static versionConflict(t,e,i,r){const s=`Version conflict: Aggregate ${t} with ID ${e} has version ${i}, but expected ${r}`,u={code:c.DomainErrorCode.ValidationFailed,data:{aggregateType:t,aggregateId:e,currentVersion:i,expectedVersion:r}};return new n(s,u)}static featureNotEnabled(t){const e=`Feature '${t}' is not enabled on aggregate`,i={code:c.DomainErrorCode.ValidationFailed,data:{feature:t}};return new n(e,i)}static methodNotImplemented(t,e){const i=`Method '${t}' must be implemented by ${e} to use this feature`,r={code:c.DomainErrorCode.MissingValue,data:{methodName:t,aggregateType:e}};return new n(i,r)}static invalidSnapshot(t,e){const i=`Invalid snapshot for aggregate ${t}${e?`: ${e}`:""}`,r={code:c.DomainErrorCode.InvalidFormat,data:{aggregateType:t,reason:e}};return new n(i,r)}static idMismatch(t,e){const i=`ID mismatch: Snapshot is for ID ${t}, but aggregate has ID ${e}`,r={code:c.DomainErrorCode.ValidationFailed,data:{snapshotId:t,aggregateId:e}};return new n(i,r)}static typeMismatch(t,e){const i=`Aggregate type mismatch: Snapshot is for type ${t}, but trying to load into ${e}`,r={code:c.DomainErrorCode.ValidationFailed,data:{snapshotType:t,aggregateType:e}};return new n(i,r)}static duplicateUpcaster(t,e){const i=`Upcaster for event ${t} version ${e} already exists`,r={code:c.DomainErrorCode.DuplicateEntry,data:{eventType:t,sourceVersion:e}};return new n(i,r)}static missingUpcaster(t,e,i){const r=`Missing upcaster for event ${t} from version ${e} to ${i}`,s={code:c.DomainErrorCode.MissingValue,data:{eventType:t,fromVersion:e,toVersion:i}};return new n(r,s)}static configurationError(t,e){const i=`Configuration error in ${t}: ${e}`,r={code:c.DomainErrorCode.ValidationFailed,data:{aggregateType:t,configurationError:e}};return new n(i,r)}static cannotInterceptApplyMethod(t,e){const i=`Cannot intercept apply method - method not found on aggregate ${t}`,r={code:c.DomainErrorCode.InternalError,data:{aggergateId:t,...e}};return new n(i,r)}static eventStoreNotConfigured(t){const e="Event store not configured",i={code:c.DomainErrorCode.MissingValue,data:t};return new n(e,i)}static aggregateDoesNotSupportReplay(t,e){const i=`Aggregate ${t} does not support event replay`,r={code:c.DomainErrorCode.MethodNotSupported,data:{aggregateType:t,...e}};return new n(i,r)}}class b extends p{constructor(){super(...arguments),this.type="eventSourcing",this.eventStore=null}static get capabilityType(){return"eventSourcing"}attach(t){this.aggregate=t}detach(){this.aggregate=void 0,this.eventStore=null}setEventStore(t){this.eventStore=t}getEventStore(){return this.eventStore}async loadFromEventStore(t){if(!this.eventStore)throw n.configurationError(this.aggregate.constructor.name,"Event store not configured");const e=await this.eventStore.getEvents(t);if(e.length===0)return;const i=this.aggregate;i.loadFromHistory&&i.loadFromHistory(e)}async saveToEventStore(){if(!this.eventStore)throw n.configurationError(this.aggregate.constructor.name,"Event store not configured");const t=this.aggregate.getDomainEvents();t.length!==0&&await this.eventStore.saveEvents(this.aggregate.getId().toString(),[...t],this.aggregate.getInitialVersion())}hasEventStore(){return this.eventStore!==null}getStreamName(){return`${this.aggregate.constructor.name}-${this.aggregate.getId().toString()}`}async loadFromVersion(t,e){if(!this.eventStore)throw n.configurationError(this.aggregate.constructor.name,"Event store not configured");const i=await this.eventStore.getEventsAfterVersion(t,e),r=this.aggregate;r.loadFromHistory&&i.length>0&&r.loadFromHistory(i)}}class w extends p{constructor(){super(...arguments),this.type="snapshot",this._snapshot=null}static get capabilityType(){return"snapshot"}attach(t){this.aggregate=t}detach(){this.aggregate=void 0,this._snapshot=null}createSnapshot(t,e){const i=this.aggregate.getDomainEvents(),s=(i.length>0?i[i.length-1]:null)?.metadata?.eventId,h={aggregateId:this.aggregate.getId().toString(),version:this.aggregate.getVersion(),aggregateType:this.aggregate.constructor.name,state:t(),timestamp:new Date,...s!==void 0&&{lastEventId:s}};return e&&(h.metadata=e()),h}restoreFromSnapshot(t,e,i){if(!t||!t.state)throw n.invalidSnapshot(this.aggregate.constructor.name,"Invalid snapshot");const r=this.aggregate.getId().toString();if(t.aggregateId!==r)throw n.idMismatch(t.aggregateId,r);if(t.aggregateType!==this.aggregate.constructor.name)throw n.typeMismatch(t.aggregateType,this.aggregate.constructor.name);e(t.state),t.metadata&&i&&i(t.metadata);const s=this.aggregate;s._internal_setState&&s._internal_setState({version:t.version,initialVersion:t.version,domainEvents:[]})}saveTemporaryState(t){this._snapshot=this.createSnapshot(()=>t)}getLastSnapshotTimestamp(){return this._snapshot?.timestamp||null}saveSnapshot(t,e){this._snapshot=this.createSnapshot(t,e)}getPreviousState(){const t=this._snapshot;return this._snapshot=null,t}}class v{constructor(t){this.capabilities=[],this.params=t}static create(t){const e={id:t.id instanceof g?t.id:new g(t.id,"text"),version:t.version||0};return new v(e)}withSnapshots(){return this.capabilities.push({capability:new w}),this}withVersioning(){return this.capabilities.push({capability:new d}),this}withAudit(){return this.capabilities.push({capability:new y}),this}withEventSourcing(t){const e=new b;return this.capabilities.push({capability:e,configure:i=>{const r=i;t?r.setEventStore(t):this.eventStore&&r.setEventStore(this.eventStore)}}),this}withCapability(t,e){return this.capabilities.push({capability:t,configure:e?i=>e(i):void 0}),this}setEventStore(t){return this.eventStore=t,this}build(t){const e=t||f,i=new e(this.params);for(const{capability:r,configure:s}of this.capabilities)i.addCapability(r),s&&s(r);return i}buildWithAllCapabilities(t){return this.withSnapshots().withVersioning().withAudit().withEventSourcing().build(t)}}function N(a){return v.create(a)}class E{constructor(t){this._id=t}getId(){return this._id}equals(t){return t==null?!1:t===this?!0:t instanceof E?this._id.equals(t._id):!1}}function A(a){return a.hasCapability(w)}function C(a){return a.hasCapability(d)}function x(a){return a.hasCapability(y)}function V(a){return a.hasCapability(b)}function M(a){if(!A(a))throw n.featureNotEnabled("snapshot");return a}function F(a){return A(a)?o.ok(a):o.fail(n.featureNotEnabled("snapshot"))}function L(a){if(!C(a))throw n.featureNotEnabled("versioning");return a}function U(a){return C(a)?o.ok(a):o.fail(n.featureNotEnabled("versioning"))}function k(a){if(!x(a))throw n.featureNotEnabled("audit");return a}function B(a){return x(a)?o.ok(a):o.fail(n.featureNotEnabled("audit"))}function O(a){if(!V(a))throw n.featureNotEnabled("eventSourcing");return a}function j(a){return V(a)?o.ok(a):o.fail(n.featureNotEnabled("eventSourcing"))}function H(a){return a.getCapabilityTypes()}function P(a,t){return t.every(e=>a.hasCapability(e))}exports.AggregateBuilder=v;exports.AggregateError=n;exports.AggregateRoot=f;exports.AuditCapability=y;exports.Entity=E;exports.EventSourcingCapability=b;exports.SnapshotCapability=w;exports.VersioningCapability=d;exports.aggregateBuilder=N;exports.asAuditAggregate=k;exports.asEventSourcingAggregate=O;exports.asSnapshotAggregate=M;exports.asVersioningAggregate=L;exports.getAggregateCapabilities=H;exports.hasAllCapabilities=P;exports.tryAsAuditAggregate=B;exports.tryAsEventSourcingAggregate=j;exports.tryAsSnapshotAggregate=F;exports.tryAsVersioningAggregate=U;
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const h=require("@vytches/ddd-contracts"),D=require("@vytches/ddd-logging"),o=require("@vytches/ddd-domain-primitives"),u=require("@vytches/ddd-utils");class d extends h.Capability{constructor(){super(...arguments),this.type="versioning",this.upcasters=new Map}static get capabilityType(){return"versioning"}attach(t){this.aggregate=t}detach(){this.aggregate=void 0,this.upcasters.clear()}registerUpcaster(t,e,i){this.upcasters.has(t)||this.upcasters.set(t,new Map),this.upcasters.get(t).set(e,i)}handleVersionedEvent(t,e){const i=t.metadata?.version||1,a=t.metadata?.targetVersion||i;let n=t;if(i<a&&this.upcasters.has(t.eventName)){const c=this.upcasters.get(t.eventName),m=D.Logger.forContext("VersioningCapability");for(let l=i;l<a;l++){const S=c.get(l);if(!S){m.warn("Missing upcaster for event version — event will be processed without upcast",{eventName:t.eventName,fromVersion:l,toVersion:l+1});continue}const V=S.upcast(n.payload,n.metadata);n={...n,payload:V,metadata:{...n.metadata,version:l+1}}}}const g=e.get(n.eventName);g&&g(n.payload,n.metadata)}getRegisteredEventTypes(){return Array.from(this.upcasters.keys())}hasUpcaster(t,e){return this.upcasters.get(t)?.has(e)||!1}getUpcastersForType(t){return this.upcasters.get(t)}clearUpcastersForType(t){this.upcasters.delete(t)}getTotalUpcasterCount(){let t=0;for(const e of this.upcasters.values())t+=e.size;return t}}class p{constructor(t){this._version=0,this._initialVersion=0,this._domainEvents=[],this._eventHandlers=new Map,this._capabilities=new h.CapabilityRegistry,this._id=t.id,this._version=t.version||0,this._initialVersion=t.version||0,this._maxEvents=t.maxEvents}getId(){return this._id}getVersion(){return this._version}getInitialVersion(){return this._initialVersion}hasChanges(){return this._domainEvents.length>0}getDomainEvents(){return[...this._domainEvents]}commit(){this._domainEvents=[],this._initialVersion=this._version}registerEventHandler(t,e){return this._eventHandlers.set(t,e),this}apply(t,e,i){this._version++;let a,n;typeof t=="string"?(a=h.createDomainEvent(t,e,i),n=a.metadata):(a=t,n=i?{...a.metadata,...i}:a.metadata);const g=p.sanitizeMetadata({...n,aggregateId:this._id.toString(),aggregateType:this.constructor.name,aggregateVersion:this._version,timestamp:n?.timestamp??new Date}),c=Object.assign(Object.create(Object.getPrototypeOf(a)),a,{metadata:g});if(this._maxEvents!==void 0&&this._domainEvents.length>=this._maxEvents)throw new Error(`Aggregate ${this.constructor.name} (id=${this._id.toString()}) exceeded maxEvents limit of ${this._maxEvents}. This usually indicates a runaway loop or replay of a corrupted event stream. Increase maxEvents in the aggregate constructor params if the limit is too restrictive for your domain.`);this._domainEvents.push(c),this.handleEvent(c)}handleEvent(t){const e=this.getCapability(d);if(e)e.handleVersionedEvent(t,this._eventHandlers);else{const i=this._eventHandlers.get(t.eventName);i&&i(t.payload,t.metadata)}}loadFromHistory(t){this._version=this._initialVersion,this._domainEvents=[];for(const e of t)this.handleEvent(e),this._version++;this._initialVersion=this._version}addCapability(t){return"attach"in t&&typeof t.attach=="function"&&t.attach(this),this._capabilities.register(t),this}getCapability(t){return this._capabilities.get(t)}hasCapability(t){return this._capabilities.has(t)}removeCapability(t){const e=this._capabilities.get(t);return e&&"detach"in e&&typeof e.detach=="function"&&e.detach(),this._capabilities.remove(t),this}getAllCapabilities(){return this._capabilities.getAll()}getCapabilityTypes(){return this._capabilities.getTypes()}static sanitizeMetadata(t){if(!Object.prototype.hasOwnProperty.call(t,"__proto__")&&!Object.prototype.hasOwnProperty.call(t,"constructor")&&!Object.prototype.hasOwnProperty.call(t,"prototype"))return t;const e={};for(const i of Object.keys(t))i==="__proto__"||i==="constructor"||i==="prototype"||(e[i]=t[i]);return e}_internal_setState(t){this._version=t.version,this._initialVersion=t.initialVersion,this._domainEvents=[...t.domainEvents]}}class f extends h.Capability{constructor(){super(...arguments),this.type="audit",this.auditLog=[]}static get capabilityType(){return"audit"}attach(t){this.aggregate=t;const e=this.aggregate;typeof e.apply=="function"&&(this.originalApply=e.apply,this.originalApply&&(this.aggregate.apply=(...i)=>{const a=this.originalApply.call(this.aggregate,...i);return this.recordAuditEvent(),a}))}detach(){this.aggregate&&this.originalApply&&(this.aggregate.apply=this.originalApply),this.aggregate=void 0,this.auditLog=[],this.originalApply=void 0}getAuditLog(){return[...this.auditLog]}clearAuditLog(){this.auditLog=[]}getAuditStatistics(){const t={};let e=0;this.auditLog.forEach((a,n)=>{if(t[a.eventName]=(t[a.eventName]||0)+1,n>0){const g=this.auditLog[n-1];if(g){const c=new Date(g.timestamp).getTime(),m=new Date(a.timestamp).getTime();e+=m-c}}});const i=this.auditLog.length>1?e/(this.auditLog.length-1):0;return{totalEvents:this.auditLog.length,eventsByType:t,averageTimeBetweenEvents:i}}recordAuditEvent(){const t=this.aggregate.getDomainEvents(),e=t[t.length-1];e&&this.recordEvent(e)}recordEvent(t){const e={eventId:t.metadata?.eventId||`audit-${Date.now()}-${Math.random()}`,eventName:t.eventName,aggregateId:this.aggregate.getId().toString(),aggregateType:this.aggregate.constructor.name,aggregateVersion:this.aggregate.getVersion(),timestamp:new Date,payload:t.payload,metadata:{...t.metadata,auditCapability:!0},actor:t.metadata?.userId};this.auditLog.push(e)}getEventsByName(t){return this.auditLog.filter(e=>e.eventName===t)}getEventsByTimeRange(t,e){return this.auditLog.filter(i=>{const a=new Date(i.timestamp).getTime();return a>=t.getTime()&&a<=e.getTime()})}getFirstEvent(){return this.auditLog[0]||null}getLastEvent(){return this.auditLog[this.auditLog.length-1]||null}}class r extends o.IDomainError{static invalidArguments(t,e){const i={code:o.DomainErrorCode.InvalidParameter,data:e};return new r(t,i)}static versionConflict(t,e,i,a){const n=`Version conflict: Aggregate ${t} with ID ${e} has version ${i}, but expected ${a}`,g={code:o.DomainErrorCode.ValidationFailed,data:{aggregateType:t,aggregateId:e,currentVersion:i,expectedVersion:a}};return new r(n,g)}static featureNotEnabled(t){const e=`Feature '${t}' is not enabled on aggregate`,i={code:o.DomainErrorCode.ValidationFailed,data:{feature:t}};return new r(e,i)}static methodNotImplemented(t,e){const i=`Method '${t}' must be implemented by ${e} to use this feature`,a={code:o.DomainErrorCode.MissingValue,data:{methodName:t,aggregateType:e}};return new r(i,a)}static invalidSnapshot(t,e){const i=`Invalid snapshot for aggregate ${t}${e?`: ${e}`:""}`,a={code:o.DomainErrorCode.InvalidFormat,data:{aggregateType:t,reason:e}};return new r(i,a)}static idMismatch(t,e){const i=`ID mismatch: Snapshot is for ID ${t}, but aggregate has ID ${e}`,a={code:o.DomainErrorCode.ValidationFailed,data:{snapshotId:t,aggregateId:e}};return new r(i,a)}static typeMismatch(t,e){const i=`Aggregate type mismatch: Snapshot is for type ${t}, but trying to load into ${e}`,a={code:o.DomainErrorCode.ValidationFailed,data:{snapshotType:t,aggregateType:e}};return new r(i,a)}static duplicateUpcaster(t,e){const i=`Upcaster for event ${t} version ${e} already exists`,a={code:o.DomainErrorCode.DuplicateEntry,data:{eventType:t,sourceVersion:e}};return new r(i,a)}static missingUpcaster(t,e,i){const a=`Missing upcaster for event ${t} from version ${e} to ${i}`,n={code:o.DomainErrorCode.MissingValue,data:{eventType:t,fromVersion:e,toVersion:i}};return new r(a,n)}static configurationError(t,e){const i=`Configuration error in ${t}: ${e}`,a={code:o.DomainErrorCode.ValidationFailed,data:{aggregateType:t,configurationError:e}};return new r(i,a)}static cannotInterceptApplyMethod(t,e){const i=`Cannot intercept apply method - method not found on aggregate ${t}`,a={code:o.DomainErrorCode.InternalError,data:{aggergateId:t,...e}};return new r(i,a)}static eventStoreNotConfigured(t){const e="Event store not configured",i={code:o.DomainErrorCode.MissingValue,data:t};return new r(e,i)}static aggregateDoesNotSupportReplay(t,e){const i=`Aggregate ${t} does not support event replay`,a={code:o.DomainErrorCode.MethodNotSupported,data:{aggregateType:t,...e}};return new r(i,a)}}class y extends h.Capability{constructor(){super(...arguments),this.type="eventSourcing",this.eventStore=null}static get capabilityType(){return"eventSourcing"}attach(t){this.aggregate=t}detach(){this.aggregate=void 0,this.eventStore=null}setEventStore(t){this.eventStore=t}getEventStore(){return this.eventStore}async loadFromEventStore(t){if(!this.eventStore)throw r.configurationError(this.aggregate.constructor.name,"Event store not configured");const e=await this.eventStore.getEvents(t);if(e.length===0)return;const i=this.aggregate;i.loadFromHistory&&i.loadFromHistory(e)}async saveToEventStore(){if(!this.eventStore)throw r.configurationError(this.aggregate.constructor.name,"Event store not configured");const t=this.aggregate.getDomainEvents();t.length!==0&&await this.eventStore.saveEvents(this.aggregate.getId().toString(),[...t],this.aggregate.getInitialVersion())}hasEventStore(){return this.eventStore!==null}getStreamName(){return`${this.aggregate.constructor.name}-${this.aggregate.getId().toString()}`}async loadFromVersion(t,e){if(!this.eventStore)throw r.configurationError(this.aggregate.constructor.name,"Event store not configured");const i=await this.eventStore.getEventsAfterVersion(t,e),a=this.aggregate;a.loadFromHistory&&i.length>0&&a.loadFromHistory(i)}}class E extends h.Capability{constructor(){super(...arguments),this.type="snapshot",this._snapshot=null}static get capabilityType(){return"snapshot"}attach(t){this.aggregate=t}detach(){this.aggregate=void 0,this._snapshot=null}createSnapshot(t,e){const i=this.aggregate.getDomainEvents(),n=(i.length>0?i[i.length-1]:null)?.metadata?.eventId,c={aggregateId:this.aggregate.getId().toString(),version:this.aggregate.getVersion(),aggregateType:this.aggregate.constructor.name,state:t(),timestamp:new Date,...n!==void 0&&{lastEventId:n}};return e&&(c.metadata=e()),c}restoreFromSnapshot(t,e,i){if(!t||!t.state)throw r.invalidSnapshot(this.aggregate.constructor.name,"Invalid snapshot");const a=this.aggregate.getId().toString();if(t.aggregateId!==a)throw r.idMismatch(t.aggregateId,a);if(t.aggregateType!==this.aggregate.constructor.name)throw r.typeMismatch(t.aggregateType,this.aggregate.constructor.name);e(t.state),t.metadata&&i&&i(t.metadata);const n=this.aggregate;n._internal_setState&&n._internal_setState({version:t.version,initialVersion:t.version,domainEvents:[]})}saveTemporaryState(t){this._snapshot=this.createSnapshot(()=>t)}getLastSnapshotTimestamp(){return this._snapshot?.timestamp||null}saveSnapshot(t,e){this._snapshot=this.createSnapshot(t,e)}getPreviousState(){const t=this._snapshot;return this._snapshot=null,t}}class v{constructor(t){this.capabilities=[],this.params=t}static create(t){const e={id:t.id instanceof h.EntityId?t.id:new h.EntityId(t.id,"text"),version:t.version||0};return new v(e)}withSnapshots(){return this.capabilities.push({capability:new E}),this}withVersioning(){return this.capabilities.push({capability:new d}),this}withAudit(){return this.capabilities.push({capability:new f}),this}withEventSourcing(t){const e=new y;return this.capabilities.push({capability:e,configure:i=>{const a=i;t?a.setEventStore(t):this.eventStore&&a.setEventStore(this.eventStore)}}),this}withCapability(t,e){return this.capabilities.push({capability:t,configure:e?i=>e(i):void 0}),this}setEventStore(t){return this.eventStore=t,this}build(t){const e=t||p,i=new e(this.params);for(const{capability:a,configure:n}of this.capabilities)i.addCapability(a),n&&n(a);return i}buildWithAllCapabilities(t){return this.withSnapshots().withVersioning().withAudit().withEventSourcing().build(t)}}function I(s){return v.create(s)}class b{constructor(t){this._id=t}getId(){return this._id}equals(t){return t==null?!1:t===this?!0:t instanceof b?this._id.equals(t._id):!1}}function w(s){return s.hasCapability(E)}function C(s){return s.hasCapability(d)}function _(s){return s.hasCapability(f)}function A(s){return s.hasCapability(y)}function $(s){if(!w(s))throw r.featureNotEnabled("snapshot");return s}function N(s){return w(s)?u.Result.ok(s):u.Result.fail(r.featureNotEnabled("snapshot"))}function L(s){if(!C(s))throw r.featureNotEnabled("versioning");return s}function M(s){return C(s)?u.Result.ok(s):u.Result.fail(r.featureNotEnabled("versioning"))}function T(s){if(!_(s))throw r.featureNotEnabled("audit");return s}function F(s){return _(s)?u.Result.ok(s):u.Result.fail(r.featureNotEnabled("audit"))}function x(s){if(!A(s))throw r.featureNotEnabled("eventSourcing");return s}function R(s){return A(s)?u.Result.ok(s):u.Result.fail(r.featureNotEnabled("eventSourcing"))}function U(s){return s.getCapabilityTypes()}function H(s,t){return t.every(e=>s.hasCapability(e))}exports.AggregateBuilder=v;exports.AggregateError=r;exports.AggregateRoot=p;exports.AuditCapability=f;exports.Entity=b;exports.EventSourcingCapability=y;exports.SnapshotCapability=E;exports.VersioningCapability=d;exports.aggregateBuilder=I;exports.asAuditAggregate=T;exports.asEventSourcingAggregate=x;exports.asSnapshotAggregate=$;exports.asVersioningAggregate=L;exports.getAggregateCapabilities=U;exports.hasAllCapabilities=H;exports.tryAsAuditAggregate=F;exports.tryAsEventSourcingAggregate=R;exports.tryAsSnapshotAggregate=N;exports.tryAsVersioningAggregate=M;
|
package/dist/index.js
CHANGED
|
@@ -1,403 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
function N(s, t, e) {
|
|
7
|
-
return {
|
|
8
|
-
eventName: s,
|
|
9
|
-
payload: t,
|
|
10
|
-
metadata: {
|
|
11
|
-
eventId: $(),
|
|
12
|
-
timestamp: /* @__PURE__ */ new Date(),
|
|
13
|
-
...e
|
|
14
|
-
}
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
class p {
|
|
18
|
-
/**
|
|
19
|
-
* Checks if this capability is of a specific type
|
|
20
|
-
*/
|
|
21
|
-
isType(t) {
|
|
22
|
-
return this.type === t;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Static type getter for compile-time type extraction
|
|
26
|
-
* Each capability must override this
|
|
27
|
-
*/
|
|
28
|
-
static get capabilityType() {
|
|
29
|
-
throw new Error("Capability subclass must override static capabilityType getter");
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
class D {
|
|
33
|
-
constructor() {
|
|
34
|
-
this.capabilities = /* @__PURE__ */ new Map();
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Register a capability
|
|
38
|
-
*/
|
|
39
|
-
register(t) {
|
|
40
|
-
return this.capabilities.set(t.type, t), this;
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Get a capability by its constructor
|
|
44
|
-
*/
|
|
45
|
-
get(t) {
|
|
46
|
-
const e = t.capabilityType;
|
|
47
|
-
return this.capabilities.get(e);
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Get a capability by its type string
|
|
51
|
-
*/
|
|
52
|
-
getByType(t) {
|
|
53
|
-
return this.capabilities.get(t);
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Check if a capability exists
|
|
57
|
-
*/
|
|
58
|
-
has(t) {
|
|
59
|
-
const e = t.capabilityType;
|
|
60
|
-
return this.capabilities.has(e);
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Check if a capability exists by type
|
|
64
|
-
*/
|
|
65
|
-
hasByType(t) {
|
|
66
|
-
return this.capabilities.has(t);
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Remove a capability
|
|
70
|
-
*/
|
|
71
|
-
remove(t) {
|
|
72
|
-
const e = t.capabilityType;
|
|
73
|
-
return this.capabilities.delete(e);
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Remove a capability by type
|
|
77
|
-
*/
|
|
78
|
-
removeByType(t) {
|
|
79
|
-
return this.capabilities.delete(t);
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* Get all registered capabilities
|
|
83
|
-
*/
|
|
84
|
-
getAll() {
|
|
85
|
-
return Array.from(this.capabilities.values());
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Get all capability types
|
|
89
|
-
*/
|
|
90
|
-
getTypes() {
|
|
91
|
-
return Array.from(this.capabilities.keys());
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Clear all capabilities
|
|
95
|
-
*/
|
|
96
|
-
clear() {
|
|
97
|
-
this.capabilities.clear();
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* Get the number of registered capabilities
|
|
101
|
-
*/
|
|
102
|
-
get size() {
|
|
103
|
-
return this.capabilities.size;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
class u {
|
|
107
|
-
constructor(t, e = "text") {
|
|
108
|
-
this.value = t, this.type = e;
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Returns the stored identifier value
|
|
112
|
-
* @returns The identifier value
|
|
113
|
-
* @example
|
|
114
|
-
* ```typescript
|
|
115
|
-
* const id = EntityId.fromText('user-123');
|
|
116
|
-
* const value = id.getValue(); // Returns: 'user-123'
|
|
117
|
-
* ```
|
|
118
|
-
*/
|
|
119
|
-
getValue() {
|
|
120
|
-
return this.value;
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* Returns the identifier type (text, uuid, integer, bigint)
|
|
124
|
-
* @returns The identifier type
|
|
125
|
-
* @example
|
|
126
|
-
* ```typescript
|
|
127
|
-
* const id = EntityId.fromUUID('550e8400-e29b-41d4-a716-446655440000');
|
|
128
|
-
* const type = id.getType(); // Returns: 'uuid'
|
|
129
|
-
* ```
|
|
130
|
-
*/
|
|
131
|
-
getType() {
|
|
132
|
-
return this.type;
|
|
133
|
-
}
|
|
134
|
-
validate(t) {
|
|
135
|
-
return t != null && t !== void 0;
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* Compares this EntityId with another for equality
|
|
139
|
-
* @returns True if entities have same value and type
|
|
140
|
-
* @example
|
|
141
|
-
* ```typescript
|
|
142
|
-
* const id1 = EntityId.fromText('user-123');
|
|
143
|
-
* const id2 = EntityId.fromText('user-123');
|
|
144
|
-
* const isEqual = id1.equals(id2); // Returns: true
|
|
145
|
-
* ```
|
|
146
|
-
*/
|
|
147
|
-
equals(t) {
|
|
148
|
-
return t.getValue() === this.value && t.getType() === this.type;
|
|
149
|
-
}
|
|
150
|
-
isType(t) {
|
|
151
|
-
return this.type === t;
|
|
152
|
-
}
|
|
153
|
-
toString() {
|
|
154
|
-
return String(this.value);
|
|
155
|
-
}
|
|
156
|
-
toJSON() {
|
|
157
|
-
return JSON.stringify({
|
|
158
|
-
value: this.value,
|
|
159
|
-
type: this.type
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
/**
|
|
163
|
-
* Primary factory method - creates a new EntityId with a randomly generated UUID
|
|
164
|
-
* @returns New EntityId with random UUID
|
|
165
|
-
* @example
|
|
166
|
-
* ```typescript
|
|
167
|
-
* const id = EntityId.create();
|
|
168
|
-
* console.log(id.getValue()); // Returns: '550e8400-e29b-41d4-a716-446655440000'
|
|
169
|
-
* ```
|
|
170
|
-
*/
|
|
171
|
-
static create() {
|
|
172
|
-
const t = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (e) => {
|
|
173
|
-
const i = Math.random() * 16 | 0;
|
|
174
|
-
return (e === "x" ? i : i & 3 | 8).toString(16);
|
|
175
|
-
});
|
|
176
|
-
return new u(t, "uuid");
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* @deprecated Use `fromText()` instead. Will be removed in next major version.
|
|
180
|
-
*/
|
|
181
|
-
static createText(t) {
|
|
182
|
-
return new u(t, "text");
|
|
183
|
-
}
|
|
184
|
-
/**
|
|
185
|
-
* @deprecated Use `fromUUID()` instead. Will be removed in next major version.
|
|
186
|
-
*/
|
|
187
|
-
static createUuid(t) {
|
|
188
|
-
return new u(t, "uuid");
|
|
189
|
-
}
|
|
190
|
-
/**
|
|
191
|
-
* @deprecated Use `fromInteger()` instead. Will be removed in next major version.
|
|
192
|
-
*/
|
|
193
|
-
static createInteger(t) {
|
|
194
|
-
return new u(t.toString(), "integer");
|
|
195
|
-
}
|
|
196
|
-
/**
|
|
197
|
-
* @deprecated Use `fromBigInt()` instead. Will be removed in next major version.
|
|
198
|
-
*/
|
|
199
|
-
static createBigInt(t) {
|
|
200
|
-
const e = typeof t == "bigint" ? t.toString() : t;
|
|
201
|
-
return new u(e, "bigint");
|
|
202
|
-
}
|
|
203
|
-
/**
|
|
204
|
-
* @deprecated Use `create()` instead. Will be removed in next major version.
|
|
205
|
-
* Creates a new EntityId with a randomly generated UUID
|
|
206
|
-
* @returns New EntityId with random UUID
|
|
207
|
-
*/
|
|
208
|
-
static createWithRandomUUID() {
|
|
209
|
-
return u.create();
|
|
210
|
-
}
|
|
211
|
-
/**
|
|
212
|
-
* Creates an EntityId from a UUID string with validation
|
|
213
|
-
* @returns EntityId from UUID string
|
|
214
|
-
* @example
|
|
215
|
-
* ```typescript
|
|
216
|
-
* const id = EntityId.fromUUID('550e8400-e29b-41d4-a716-446655440000');
|
|
217
|
-
* console.log(id.getType()); // Returns: 'uuid'
|
|
218
|
-
* ```
|
|
219
|
-
*/
|
|
220
|
-
static fromUUID(t) {
|
|
221
|
-
if (!t || typeof t != "string")
|
|
222
|
-
throw new Error("entity identifier must be provided");
|
|
223
|
-
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(t))
|
|
224
|
-
throw new Error("entity identifier must be valid UUID");
|
|
225
|
-
return new u(t, "uuid");
|
|
226
|
-
}
|
|
227
|
-
static fromInteger(t) {
|
|
228
|
-
if (typeof t != "number" || t < 0 || !Number.isInteger(t))
|
|
229
|
-
throw new Error("entity identifier must be a non-negative integer");
|
|
230
|
-
return new u(t.toString(), "integer");
|
|
231
|
-
}
|
|
232
|
-
static fromBigInt(t) {
|
|
233
|
-
const e = typeof t == "bigint" ? t.toString() : t;
|
|
234
|
-
if (!e || typeof e != "string")
|
|
235
|
-
throw new Error("entity identifier must be a valid bigint");
|
|
236
|
-
return new u(e, "bigint");
|
|
237
|
-
}
|
|
238
|
-
/**
|
|
239
|
-
* Creates an EntityId from a text string with validation
|
|
240
|
-
* @returns EntityId from text string
|
|
241
|
-
* @example
|
|
242
|
-
* ```typescript
|
|
243
|
-
* const id = EntityId.fromText('user-123');
|
|
244
|
-
* console.log(id.getValue()); // Returns: 'user-123'
|
|
245
|
-
* ```
|
|
246
|
-
*/
|
|
247
|
-
static fromText(t) {
|
|
248
|
-
if (!t || typeof t != "string")
|
|
249
|
-
throw new Error("entity identifier must be provided");
|
|
250
|
-
if (!/^[a-zA-Z0-9_-]+$/.test(t))
|
|
251
|
-
throw new Error("entity identifier contains invalid characters");
|
|
252
|
-
return new u(t, "text");
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
class o {
|
|
256
|
-
constructor(t, e, i) {
|
|
257
|
-
this._isSuccess = t, this._value = e, this._error = i;
|
|
258
|
-
}
|
|
259
|
-
/**
|
|
260
|
-
* Check if the result is successful
|
|
261
|
-
*/
|
|
262
|
-
get isSuccess() {
|
|
263
|
-
return this._isSuccess;
|
|
264
|
-
}
|
|
265
|
-
/**
|
|
266
|
-
* Check if the result is a failure
|
|
267
|
-
*/
|
|
268
|
-
get isFailure() {
|
|
269
|
-
return !this._isSuccess;
|
|
270
|
-
}
|
|
271
|
-
/**
|
|
272
|
-
* Get the success value
|
|
273
|
-
* @throws Error if the result is a failure
|
|
274
|
-
*/
|
|
275
|
-
get value() {
|
|
276
|
-
if (!this._isSuccess)
|
|
277
|
-
throw new Error("Cannot get value of a failure result");
|
|
278
|
-
return this._value;
|
|
279
|
-
}
|
|
280
|
-
/**
|
|
281
|
-
* Get the error value
|
|
282
|
-
* @throws Error if the result is successful
|
|
283
|
-
*/
|
|
284
|
-
get error() {
|
|
285
|
-
if (this._isSuccess)
|
|
286
|
-
throw new Error("Cannot get error of a success result");
|
|
287
|
-
return this._error;
|
|
288
|
-
}
|
|
289
|
-
/**
|
|
290
|
-
* Create a successful result
|
|
291
|
-
* @param value - The success value (required — use Result.empty() for void operations)
|
|
292
|
-
*/
|
|
293
|
-
static ok(t) {
|
|
294
|
-
return new o(!0, t);
|
|
295
|
-
}
|
|
296
|
-
/**
|
|
297
|
-
* Create a successful void result (no value).
|
|
298
|
-
*/
|
|
299
|
-
static empty() {
|
|
300
|
-
return new o(!0, void 0);
|
|
301
|
-
}
|
|
302
|
-
/**
|
|
303
|
-
* Create a failure result
|
|
304
|
-
* @param error - The error value
|
|
305
|
-
*/
|
|
306
|
-
static fail(t) {
|
|
307
|
-
return new o(!1, void 0, t);
|
|
308
|
-
}
|
|
309
|
-
/**
|
|
310
|
-
* Try to execute a function and wrap the result
|
|
311
|
-
* @param fn - The function to try
|
|
312
|
-
* @returns A Result containing the function result or error
|
|
313
|
-
*/
|
|
314
|
-
static try(t) {
|
|
315
|
-
try {
|
|
316
|
-
return o.ok(t());
|
|
317
|
-
} catch (e) {
|
|
318
|
-
return o.fail(e instanceof Error ? e : new Error(String(e)));
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
/**
|
|
322
|
-
* Transform the success value
|
|
323
|
-
* @param fn - The transformation function
|
|
324
|
-
*/
|
|
325
|
-
map(t) {
|
|
326
|
-
return this.isFailure ? o.fail(this.error) : o.ok(t(this.value));
|
|
327
|
-
}
|
|
328
|
-
/**
|
|
329
|
-
* Transform the success value with a function that returns a Result
|
|
330
|
-
* @param fn - The transformation function
|
|
331
|
-
*/
|
|
332
|
-
flatMap(t) {
|
|
333
|
-
return this.isFailure ? o.fail(this.error) : t(this.value);
|
|
334
|
-
}
|
|
335
|
-
/**
|
|
336
|
-
* Apply a function based on success or failure
|
|
337
|
-
* @param onSuccess - Function to call on success
|
|
338
|
-
* @param onFailure - Function to call on failure
|
|
339
|
-
*/
|
|
340
|
-
match(t, e) {
|
|
341
|
-
return this.isSuccess ? t(this.value) : e(this.error);
|
|
342
|
-
}
|
|
343
|
-
/**
|
|
344
|
-
* Apply a side effect if the result is successful
|
|
345
|
-
* @param fn - The side effect function
|
|
346
|
-
*/
|
|
347
|
-
tap(t) {
|
|
348
|
-
return this.isSuccess && t(this.value), this;
|
|
349
|
-
}
|
|
350
|
-
/**
|
|
351
|
-
* Apply a side effect if the result is a failure
|
|
352
|
-
* @param fn - The side effect function
|
|
353
|
-
*/
|
|
354
|
-
tapError(t) {
|
|
355
|
-
return this.isFailure && t(this.error), this;
|
|
356
|
-
}
|
|
357
|
-
/**
|
|
358
|
-
* Transform the error value if the result is a failure
|
|
359
|
-
* @param fn - The error transformation function
|
|
360
|
-
*/
|
|
361
|
-
mapError(t) {
|
|
362
|
-
return this.isSuccess ? o.ok(this.value) : o.fail(t(this.error));
|
|
363
|
-
}
|
|
364
|
-
/**
|
|
365
|
-
* Try to execute an async function and wrap the result
|
|
366
|
-
* @param fn - The async function to try
|
|
367
|
-
* @returns A Promise of a Result containing the function result or error
|
|
368
|
-
*/
|
|
369
|
-
static async tryAsync(t) {
|
|
370
|
-
try {
|
|
371
|
-
const e = await t();
|
|
372
|
-
return o.ok(e);
|
|
373
|
-
} catch (e) {
|
|
374
|
-
return o.fail(e instanceof Error ? e : new Error(String(e)));
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
/**
|
|
378
|
-
* Transform the success value with an async function
|
|
379
|
-
* @param fn - The async transformation function
|
|
380
|
-
*/
|
|
381
|
-
async mapAsync(t) {
|
|
382
|
-
if (this.isFailure)
|
|
383
|
-
return o.fail(this.error);
|
|
384
|
-
try {
|
|
385
|
-
const e = await t(this.value);
|
|
386
|
-
return o.ok(e);
|
|
387
|
-
} catch (e) {
|
|
388
|
-
const i = e instanceof Error ? e : new Error(String(e));
|
|
389
|
-
return o.fail(i);
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
/**
|
|
393
|
-
* Transform the success value with an async function that returns a Result
|
|
394
|
-
* @param fn - The async transformation function
|
|
395
|
-
*/
|
|
396
|
-
async flatMapAsync(t) {
|
|
397
|
-
return this.isFailure ? o.fail(this.error) : await t(this.value);
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
class f extends p {
|
|
1
|
+
import { Capability as l, CapabilityRegistry as $, createDomainEvent as N, EntityId as y } from "@vytches/ddd-contracts";
|
|
2
|
+
import { Logger as L } from "@vytches/ddd-logging";
|
|
3
|
+
import { IDomainError as M, DomainErrorCode as o } from "@vytches/ddd-domain-primitives";
|
|
4
|
+
import { Result as h } from "@vytches/ddd-utils";
|
|
5
|
+
class p extends l {
|
|
401
6
|
constructor() {
|
|
402
7
|
super(...arguments), this.type = "versioning", this.upcasters = /* @__PURE__ */ new Map();
|
|
403
8
|
}
|
|
@@ -426,36 +31,36 @@ class f extends p {
|
|
|
426
31
|
* @param {Map<string, IAggregateEventHandler>} handlers - Map of event handlers
|
|
427
32
|
*/
|
|
428
33
|
handleVersionedEvent(t, e) {
|
|
429
|
-
const i = t.metadata?.version || 1,
|
|
430
|
-
let
|
|
431
|
-
if (i <
|
|
432
|
-
const g = this.upcasters.get(t.eventName), d =
|
|
433
|
-
for (let
|
|
434
|
-
const
|
|
435
|
-
if (!
|
|
34
|
+
const i = t.metadata?.version || 1, a = t.metadata?.targetVersion || i;
|
|
35
|
+
let n = t;
|
|
36
|
+
if (i < a && this.upcasters.has(t.eventName)) {
|
|
37
|
+
const g = this.upcasters.get(t.eventName), d = L.forContext("VersioningCapability");
|
|
38
|
+
for (let u = i; u < a; u++) {
|
|
39
|
+
const f = g.get(u);
|
|
40
|
+
if (!f) {
|
|
436
41
|
d.warn(
|
|
437
42
|
"Missing upcaster for event version — event will be processed without upcast",
|
|
438
43
|
{
|
|
439
44
|
eventName: t.eventName,
|
|
440
|
-
fromVersion:
|
|
441
|
-
toVersion:
|
|
45
|
+
fromVersion: u,
|
|
46
|
+
toVersion: u + 1
|
|
442
47
|
}
|
|
443
48
|
);
|
|
444
49
|
continue;
|
|
445
50
|
}
|
|
446
|
-
const
|
|
447
|
-
|
|
448
|
-
...
|
|
449
|
-
payload:
|
|
51
|
+
const I = f.upcast(n.payload, n.metadata);
|
|
52
|
+
n = {
|
|
53
|
+
...n,
|
|
54
|
+
payload: I,
|
|
450
55
|
metadata: {
|
|
451
|
-
...
|
|
452
|
-
version:
|
|
56
|
+
...n.metadata,
|
|
57
|
+
version: u + 1
|
|
453
58
|
}
|
|
454
59
|
};
|
|
455
60
|
}
|
|
456
61
|
}
|
|
457
|
-
const
|
|
458
|
-
|
|
62
|
+
const c = e.get(n.eventName);
|
|
63
|
+
c && c(n.payload, n.metadata);
|
|
459
64
|
}
|
|
460
65
|
/**
|
|
461
66
|
* @returns {string[]} Array of event types that have registered upcasters
|
|
@@ -496,7 +101,7 @@ class f extends p {
|
|
|
496
101
|
}
|
|
497
102
|
class v {
|
|
498
103
|
constructor(t) {
|
|
499
|
-
this._version = 0, this._initialVersion = 0, this._domainEvents = [], this._eventHandlers = /* @__PURE__ */ new Map(), this._capabilities = new
|
|
104
|
+
this._version = 0, this._initialVersion = 0, this._domainEvents = [], this._eventHandlers = /* @__PURE__ */ new Map(), this._capabilities = new $(), this._id = t.id, this._version = t.version || 0, this._initialVersion = t.version || 0, this._maxEvents = t.maxEvents;
|
|
500
105
|
}
|
|
501
106
|
// ==========================================
|
|
502
107
|
// CORE AGGREGATE FUNCTIONALITY
|
|
@@ -560,18 +165,18 @@ class v {
|
|
|
560
165
|
*/
|
|
561
166
|
apply(t, e, i) {
|
|
562
167
|
this._version++;
|
|
563
|
-
let
|
|
564
|
-
typeof t == "string" ? (
|
|
565
|
-
const
|
|
566
|
-
...
|
|
168
|
+
let a, n;
|
|
169
|
+
typeof t == "string" ? (a = N(t, e, i), n = a.metadata) : (a = t, n = i ? { ...a.metadata, ...i } : a.metadata);
|
|
170
|
+
const c = v.sanitizeMetadata({
|
|
171
|
+
...n,
|
|
567
172
|
aggregateId: this._id.toString(),
|
|
568
173
|
aggregateType: this.constructor.name,
|
|
569
174
|
aggregateVersion: this._version,
|
|
570
|
-
timestamp:
|
|
175
|
+
timestamp: n?.timestamp ?? /* @__PURE__ */ new Date()
|
|
571
176
|
}), g = Object.assign(
|
|
572
|
-
Object.create(Object.getPrototypeOf(
|
|
573
|
-
|
|
574
|
-
{ metadata:
|
|
177
|
+
Object.create(Object.getPrototypeOf(a)),
|
|
178
|
+
a,
|
|
179
|
+
{ metadata: c }
|
|
575
180
|
);
|
|
576
181
|
if (this._maxEvents !== void 0 && this._domainEvents.length >= this._maxEvents)
|
|
577
182
|
throw new Error(
|
|
@@ -580,7 +185,7 @@ class v {
|
|
|
580
185
|
this._domainEvents.push(g), this.handleEvent(g);
|
|
581
186
|
}
|
|
582
187
|
handleEvent(t) {
|
|
583
|
-
const e = this.getCapability(
|
|
188
|
+
const e = this.getCapability(p);
|
|
584
189
|
if (e)
|
|
585
190
|
e.handleVersionedEvent(t, this._eventHandlers);
|
|
586
191
|
else {
|
|
@@ -665,7 +270,7 @@ class v {
|
|
|
665
270
|
this._version = t.version, this._initialVersion = t.initialVersion, this._domainEvents = [...t.domainEvents];
|
|
666
271
|
}
|
|
667
272
|
}
|
|
668
|
-
class b extends
|
|
273
|
+
class b extends l {
|
|
669
274
|
constructor() {
|
|
670
275
|
super(...arguments), this.type = "audit", this.auditLog = [];
|
|
671
276
|
}
|
|
@@ -679,8 +284,8 @@ class b extends p {
|
|
|
679
284
|
this.aggregate = t;
|
|
680
285
|
const e = this.aggregate;
|
|
681
286
|
typeof e.apply == "function" && (this.originalApply = e.apply, this.originalApply && (this.aggregate.apply = (...i) => {
|
|
682
|
-
const
|
|
683
|
-
return this.recordAuditEvent(),
|
|
287
|
+
const a = this.originalApply.call(this.aggregate, ...i);
|
|
288
|
+
return this.recordAuditEvent(), a;
|
|
684
289
|
}));
|
|
685
290
|
}
|
|
686
291
|
detach() {
|
|
@@ -701,11 +306,11 @@ class b extends p {
|
|
|
701
306
|
getAuditStatistics() {
|
|
702
307
|
const t = {};
|
|
703
308
|
let e = 0;
|
|
704
|
-
this.auditLog.forEach((
|
|
705
|
-
if (t[
|
|
706
|
-
const
|
|
707
|
-
if (
|
|
708
|
-
const g = new Date(
|
|
309
|
+
this.auditLog.forEach((a, n) => {
|
|
310
|
+
if (t[a.eventName] = (t[a.eventName] || 0) + 1, n > 0) {
|
|
311
|
+
const c = this.auditLog[n - 1];
|
|
312
|
+
if (c) {
|
|
313
|
+
const g = new Date(c.timestamp).getTime(), d = new Date(a.timestamp).getTime();
|
|
709
314
|
e += d - g;
|
|
710
315
|
}
|
|
711
316
|
}
|
|
@@ -758,8 +363,8 @@ class b extends p {
|
|
|
758
363
|
*/
|
|
759
364
|
getEventsByTimeRange(t, e) {
|
|
760
365
|
return this.auditLog.filter((i) => {
|
|
761
|
-
const
|
|
762
|
-
return
|
|
366
|
+
const a = new Date(i.timestamp).getTime();
|
|
367
|
+
return a >= t.getTime() && a <= e.getTime();
|
|
763
368
|
});
|
|
764
369
|
}
|
|
765
370
|
/**
|
|
@@ -775,174 +380,174 @@ class b extends p {
|
|
|
775
380
|
return this.auditLog[this.auditLog.length - 1] || null;
|
|
776
381
|
}
|
|
777
382
|
}
|
|
778
|
-
class
|
|
383
|
+
class r extends M {
|
|
779
384
|
/**
|
|
780
385
|
* Error for invalid arguments provided to the aggregate
|
|
781
386
|
*/
|
|
782
387
|
static invalidArguments(t, e) {
|
|
783
388
|
const i = {
|
|
784
|
-
code:
|
|
389
|
+
code: o.InvalidParameter,
|
|
785
390
|
data: e
|
|
786
391
|
};
|
|
787
|
-
return new
|
|
392
|
+
return new r(t, i);
|
|
788
393
|
}
|
|
789
394
|
/**
|
|
790
395
|
* Error for version conflicts in the aggregate
|
|
791
396
|
*/
|
|
792
|
-
static versionConflict(t, e, i,
|
|
793
|
-
const
|
|
794
|
-
code:
|
|
397
|
+
static versionConflict(t, e, i, a) {
|
|
398
|
+
const n = `Version conflict: Aggregate ${t} with ID ${e} has version ${i}, but expected ${a}`, c = {
|
|
399
|
+
code: o.ValidationFailed,
|
|
795
400
|
data: {
|
|
796
401
|
aggregateType: t,
|
|
797
402
|
aggregateId: e,
|
|
798
403
|
currentVersion: i,
|
|
799
|
-
expectedVersion:
|
|
404
|
+
expectedVersion: a
|
|
800
405
|
}
|
|
801
406
|
};
|
|
802
|
-
return new n
|
|
407
|
+
return new r(n, c);
|
|
803
408
|
}
|
|
804
409
|
/**
|
|
805
410
|
* Error for when a required feature is not enabled
|
|
806
411
|
*/
|
|
807
412
|
static featureNotEnabled(t) {
|
|
808
413
|
const e = `Feature '${t}' is not enabled on aggregate`, i = {
|
|
809
|
-
code:
|
|
414
|
+
code: o.ValidationFailed,
|
|
810
415
|
data: {
|
|
811
416
|
feature: t
|
|
812
417
|
}
|
|
813
418
|
};
|
|
814
|
-
return new
|
|
419
|
+
return new r(e, i);
|
|
815
420
|
}
|
|
816
421
|
/**
|
|
817
422
|
* Error for when a required method is not implemented
|
|
818
423
|
*/
|
|
819
424
|
static methodNotImplemented(t, e) {
|
|
820
|
-
const i = `Method '${t}' must be implemented by ${e} to use this feature`,
|
|
821
|
-
code:
|
|
425
|
+
const i = `Method '${t}' must be implemented by ${e} to use this feature`, a = {
|
|
426
|
+
code: o.MissingValue,
|
|
822
427
|
data: {
|
|
823
428
|
methodName: t,
|
|
824
429
|
aggregateType: e
|
|
825
430
|
}
|
|
826
431
|
};
|
|
827
|
-
return new
|
|
432
|
+
return new r(i, a);
|
|
828
433
|
}
|
|
829
434
|
/**
|
|
830
435
|
* Error for invalid snapshot
|
|
831
436
|
*/
|
|
832
437
|
static invalidSnapshot(t, e) {
|
|
833
|
-
const i = `Invalid snapshot for aggregate ${t}${e ? `: ${e}` : ""}`,
|
|
834
|
-
code:
|
|
438
|
+
const i = `Invalid snapshot for aggregate ${t}${e ? `: ${e}` : ""}`, a = {
|
|
439
|
+
code: o.InvalidFormat,
|
|
835
440
|
data: {
|
|
836
441
|
aggregateType: t,
|
|
837
442
|
reason: e
|
|
838
443
|
}
|
|
839
444
|
};
|
|
840
|
-
return new
|
|
445
|
+
return new r(i, a);
|
|
841
446
|
}
|
|
842
447
|
/**
|
|
843
448
|
* Error for ID mismatch during snapshot restoration
|
|
844
449
|
*/
|
|
845
450
|
static idMismatch(t, e) {
|
|
846
|
-
const i = `ID mismatch: Snapshot is for ID ${t}, but aggregate has ID ${e}`,
|
|
847
|
-
code:
|
|
451
|
+
const i = `ID mismatch: Snapshot is for ID ${t}, but aggregate has ID ${e}`, a = {
|
|
452
|
+
code: o.ValidationFailed,
|
|
848
453
|
data: {
|
|
849
454
|
snapshotId: t,
|
|
850
455
|
aggregateId: e
|
|
851
456
|
}
|
|
852
457
|
};
|
|
853
|
-
return new
|
|
458
|
+
return new r(i, a);
|
|
854
459
|
}
|
|
855
460
|
/**
|
|
856
461
|
* Error for type mismatch during snapshot restoration
|
|
857
462
|
*/
|
|
858
463
|
static typeMismatch(t, e) {
|
|
859
|
-
const i = `Aggregate type mismatch: Snapshot is for type ${t}, but trying to load into ${e}`,
|
|
860
|
-
code:
|
|
464
|
+
const i = `Aggregate type mismatch: Snapshot is for type ${t}, but trying to load into ${e}`, a = {
|
|
465
|
+
code: o.ValidationFailed,
|
|
861
466
|
data: {
|
|
862
467
|
snapshotType: t,
|
|
863
468
|
aggregateType: e
|
|
864
469
|
}
|
|
865
470
|
};
|
|
866
|
-
return new
|
|
471
|
+
return new r(i, a);
|
|
867
472
|
}
|
|
868
473
|
/**
|
|
869
474
|
* Error for duplicate upcaster registration
|
|
870
475
|
*/
|
|
871
476
|
static duplicateUpcaster(t, e) {
|
|
872
|
-
const i = `Upcaster for event ${t} version ${e} already exists`,
|
|
873
|
-
code:
|
|
477
|
+
const i = `Upcaster for event ${t} version ${e} already exists`, a = {
|
|
478
|
+
code: o.DuplicateEntry,
|
|
874
479
|
data: {
|
|
875
480
|
eventType: t,
|
|
876
481
|
sourceVersion: e
|
|
877
482
|
}
|
|
878
483
|
};
|
|
879
|
-
return new
|
|
484
|
+
return new r(i, a);
|
|
880
485
|
}
|
|
881
486
|
/**
|
|
882
487
|
* Error for missing upcaster
|
|
883
488
|
*/
|
|
884
489
|
static missingUpcaster(t, e, i) {
|
|
885
|
-
const
|
|
886
|
-
code:
|
|
490
|
+
const a = `Missing upcaster for event ${t} from version ${e} to ${i}`, n = {
|
|
491
|
+
code: o.MissingValue,
|
|
887
492
|
data: {
|
|
888
493
|
eventType: t,
|
|
889
494
|
fromVersion: e,
|
|
890
495
|
toVersion: i
|
|
891
496
|
}
|
|
892
497
|
};
|
|
893
|
-
return new
|
|
498
|
+
return new r(a, n);
|
|
894
499
|
}
|
|
895
500
|
/**
|
|
896
501
|
* Error for configuration problems
|
|
897
502
|
*/
|
|
898
503
|
static configurationError(t, e) {
|
|
899
|
-
const i = `Configuration error in ${t}: ${e}`,
|
|
900
|
-
code:
|
|
504
|
+
const i = `Configuration error in ${t}: ${e}`, a = {
|
|
505
|
+
code: o.ValidationFailed,
|
|
901
506
|
data: {
|
|
902
507
|
aggregateType: t,
|
|
903
508
|
configurationError: e
|
|
904
509
|
}
|
|
905
510
|
};
|
|
906
|
-
return new
|
|
511
|
+
return new r(i, a);
|
|
907
512
|
}
|
|
908
513
|
/**
|
|
909
514
|
* Error for when apply method interception fails (e.g. method not found)
|
|
910
515
|
*/
|
|
911
516
|
static cannotInterceptApplyMethod(t, e) {
|
|
912
|
-
const i = `Cannot intercept apply method - method not found on aggregate ${t}`,
|
|
913
|
-
code:
|
|
517
|
+
const i = `Cannot intercept apply method - method not found on aggregate ${t}`, a = {
|
|
518
|
+
code: o.InternalError,
|
|
914
519
|
data: {
|
|
915
520
|
aggergateId: t,
|
|
916
521
|
...e
|
|
917
522
|
}
|
|
918
523
|
};
|
|
919
|
-
return new
|
|
524
|
+
return new r(i, a);
|
|
920
525
|
}
|
|
921
526
|
/**
|
|
922
527
|
* Error for when event store is not configured
|
|
923
528
|
*/
|
|
924
529
|
static eventStoreNotConfigured(t) {
|
|
925
530
|
const e = "Event store not configured", i = {
|
|
926
|
-
code:
|
|
531
|
+
code: o.MissingValue,
|
|
927
532
|
data: t
|
|
928
533
|
};
|
|
929
|
-
return new
|
|
534
|
+
return new r(e, i);
|
|
930
535
|
}
|
|
931
536
|
/**
|
|
932
537
|
* Error for when aggregate does not support event replay
|
|
933
538
|
*/
|
|
934
539
|
static aggregateDoesNotSupportReplay(t, e) {
|
|
935
|
-
const i = `Aggregate ${t} does not support event replay`,
|
|
936
|
-
code:
|
|
540
|
+
const i = `Aggregate ${t} does not support event replay`, a = {
|
|
541
|
+
code: o.MethodNotSupported,
|
|
937
542
|
data: {
|
|
938
543
|
aggregateType: t,
|
|
939
544
|
...e
|
|
940
545
|
}
|
|
941
546
|
};
|
|
942
|
-
return new
|
|
547
|
+
return new r(i, a);
|
|
943
548
|
}
|
|
944
549
|
}
|
|
945
|
-
class
|
|
550
|
+
class E extends l {
|
|
946
551
|
constructor() {
|
|
947
552
|
super(...arguments), this.type = "eventSourcing", this.eventStore = null;
|
|
948
553
|
}
|
|
@@ -976,7 +581,7 @@ class w extends p {
|
|
|
976
581
|
*/
|
|
977
582
|
async loadFromEventStore(t) {
|
|
978
583
|
if (!this.eventStore)
|
|
979
|
-
throw
|
|
584
|
+
throw r.configurationError(
|
|
980
585
|
this.aggregate.constructor.name,
|
|
981
586
|
"Event store not configured"
|
|
982
587
|
);
|
|
@@ -991,7 +596,7 @@ class w extends p {
|
|
|
991
596
|
*/
|
|
992
597
|
async saveToEventStore() {
|
|
993
598
|
if (!this.eventStore)
|
|
994
|
-
throw
|
|
599
|
+
throw r.configurationError(
|
|
995
600
|
this.aggregate.constructor.name,
|
|
996
601
|
"Event store not configured"
|
|
997
602
|
);
|
|
@@ -1021,15 +626,15 @@ class w extends p {
|
|
|
1021
626
|
*/
|
|
1022
627
|
async loadFromVersion(t, e) {
|
|
1023
628
|
if (!this.eventStore)
|
|
1024
|
-
throw
|
|
629
|
+
throw r.configurationError(
|
|
1025
630
|
this.aggregate.constructor.name,
|
|
1026
631
|
"Event store not configured"
|
|
1027
632
|
);
|
|
1028
|
-
const i = await this.eventStore.getEventsAfterVersion(t, e),
|
|
1029
|
-
|
|
633
|
+
const i = await this.eventStore.getEventsAfterVersion(t, e), a = this.aggregate;
|
|
634
|
+
a.loadFromHistory && i.length > 0 && a.loadFromHistory(i);
|
|
1030
635
|
}
|
|
1031
636
|
}
|
|
1032
|
-
class S extends
|
|
637
|
+
class S extends l {
|
|
1033
638
|
constructor() {
|
|
1034
639
|
super(...arguments), this.type = "snapshot", this._snapshot = null;
|
|
1035
640
|
}
|
|
@@ -1051,13 +656,13 @@ class S extends p {
|
|
|
1051
656
|
* @returns {IAggregateSnapshot<TState, TMeta>} Created snapshot with state and metadata
|
|
1052
657
|
*/
|
|
1053
658
|
createSnapshot(t, e) {
|
|
1054
|
-
const i = this.aggregate.getDomainEvents(),
|
|
659
|
+
const i = this.aggregate.getDomainEvents(), n = (i.length > 0 ? i[i.length - 1] : null)?.metadata?.eventId, g = {
|
|
1055
660
|
aggregateId: this.aggregate.getId().toString(),
|
|
1056
661
|
version: this.aggregate.getVersion(),
|
|
1057
662
|
aggregateType: this.aggregate.constructor.name,
|
|
1058
663
|
state: t(),
|
|
1059
664
|
timestamp: /* @__PURE__ */ new Date(),
|
|
1060
|
-
...
|
|
665
|
+
...n !== void 0 && { lastEventId: n }
|
|
1061
666
|
};
|
|
1062
667
|
return e && (g.metadata = e()), g;
|
|
1063
668
|
}
|
|
@@ -1069,15 +674,15 @@ class S extends p {
|
|
|
1069
674
|
*/
|
|
1070
675
|
restoreFromSnapshot(t, e, i) {
|
|
1071
676
|
if (!t || !t.state)
|
|
1072
|
-
throw
|
|
1073
|
-
const
|
|
1074
|
-
if (t.aggregateId !==
|
|
1075
|
-
throw
|
|
677
|
+
throw r.invalidSnapshot(this.aggregate.constructor.name, "Invalid snapshot");
|
|
678
|
+
const a = this.aggregate.getId().toString();
|
|
679
|
+
if (t.aggregateId !== a)
|
|
680
|
+
throw r.idMismatch(t.aggregateId, a);
|
|
1076
681
|
if (t.aggregateType !== this.aggregate.constructor.name)
|
|
1077
|
-
throw
|
|
682
|
+
throw r.typeMismatch(t.aggregateType, this.aggregate.constructor.name);
|
|
1078
683
|
e(t.state), t.metadata && i && i(t.metadata);
|
|
1079
|
-
const
|
|
1080
|
-
|
|
684
|
+
const n = this.aggregate;
|
|
685
|
+
n._internal_setState && n._internal_setState({
|
|
1081
686
|
version: t.version,
|
|
1082
687
|
initialVersion: t.version,
|
|
1083
688
|
domainEvents: []
|
|
@@ -1119,7 +724,7 @@ class m {
|
|
|
1119
724
|
*/
|
|
1120
725
|
static create(t) {
|
|
1121
726
|
const e = {
|
|
1122
|
-
id: t.id instanceof
|
|
727
|
+
id: t.id instanceof y ? t.id : new y(t.id, "text"),
|
|
1123
728
|
version: t.version || 0
|
|
1124
729
|
};
|
|
1125
730
|
return new m(e);
|
|
@@ -1131,7 +736,7 @@ class m {
|
|
|
1131
736
|
* @returns {this} Builder instance for method chaining
|
|
1132
737
|
*/
|
|
1133
738
|
withVersioning() {
|
|
1134
|
-
return this.capabilities.push({ capability: new
|
|
739
|
+
return this.capabilities.push({ capability: new p() }), this;
|
|
1135
740
|
}
|
|
1136
741
|
/**
|
|
1137
742
|
* @returns {this} Builder instance for method chaining
|
|
@@ -1144,12 +749,12 @@ class m {
|
|
|
1144
749
|
* @returns {this} Builder instance for method chaining
|
|
1145
750
|
*/
|
|
1146
751
|
withEventSourcing(t) {
|
|
1147
|
-
const e = new
|
|
752
|
+
const e = new E();
|
|
1148
753
|
return this.capabilities.push({
|
|
1149
754
|
capability: e,
|
|
1150
755
|
configure: (i) => {
|
|
1151
|
-
const
|
|
1152
|
-
t ?
|
|
756
|
+
const a = i;
|
|
757
|
+
t ? a.setEventStore(t) : this.eventStore && a.setEventStore(this.eventStore);
|
|
1153
758
|
}
|
|
1154
759
|
}), this;
|
|
1155
760
|
}
|
|
@@ -1173,8 +778,8 @@ class m {
|
|
|
1173
778
|
}
|
|
1174
779
|
build(t) {
|
|
1175
780
|
const e = t || v, i = new e(this.params);
|
|
1176
|
-
for (const { capability:
|
|
1177
|
-
i.addCapability(
|
|
781
|
+
for (const { capability: a, configure: n } of this.capabilities)
|
|
782
|
+
i.addCapability(a), n && n(a);
|
|
1178
783
|
return i;
|
|
1179
784
|
}
|
|
1180
785
|
/**
|
|
@@ -1185,10 +790,10 @@ class m {
|
|
|
1185
790
|
return this.withSnapshots().withVersioning().withAudit().withEventSourcing().build(t);
|
|
1186
791
|
}
|
|
1187
792
|
}
|
|
1188
|
-
function
|
|
793
|
+
function H(s) {
|
|
1189
794
|
return m.create(s);
|
|
1190
795
|
}
|
|
1191
|
-
class
|
|
796
|
+
class w {
|
|
1192
797
|
constructor(t) {
|
|
1193
798
|
this._id = t;
|
|
1194
799
|
}
|
|
@@ -1207,54 +812,54 @@ class E {
|
|
|
1207
812
|
* @returns `true` if both entities have the same id; `false` otherwise.
|
|
1208
813
|
*/
|
|
1209
814
|
equals(t) {
|
|
1210
|
-
return t == null ? !1 : t === this ? !0 : t instanceof
|
|
815
|
+
return t == null ? !1 : t === this ? !0 : t instanceof w ? this._id.equals(t._id) : !1;
|
|
1211
816
|
}
|
|
1212
817
|
}
|
|
1213
|
-
function
|
|
818
|
+
function _(s) {
|
|
1214
819
|
return s.hasCapability(S);
|
|
1215
820
|
}
|
|
1216
821
|
function C(s) {
|
|
1217
|
-
return s.hasCapability(
|
|
822
|
+
return s.hasCapability(p);
|
|
1218
823
|
}
|
|
1219
824
|
function V(s) {
|
|
1220
825
|
return s.hasCapability(b);
|
|
1221
826
|
}
|
|
1222
827
|
function A(s) {
|
|
1223
|
-
return s.hasCapability(
|
|
828
|
+
return s.hasCapability(E);
|
|
1224
829
|
}
|
|
1225
830
|
function U(s) {
|
|
1226
|
-
if (!
|
|
1227
|
-
throw
|
|
831
|
+
if (!_(s))
|
|
832
|
+
throw r.featureNotEnabled("snapshot");
|
|
1228
833
|
return s;
|
|
1229
834
|
}
|
|
1230
|
-
function k(s) {
|
|
1231
|
-
return x(s) ? o.ok(s) : o.fail(n.featureNotEnabled("snapshot"));
|
|
1232
|
-
}
|
|
1233
835
|
function O(s) {
|
|
836
|
+
return _(s) ? h.ok(s) : h.fail(r.featureNotEnabled("snapshot"));
|
|
837
|
+
}
|
|
838
|
+
function P(s) {
|
|
1234
839
|
if (!C(s))
|
|
1235
|
-
throw
|
|
840
|
+
throw r.featureNotEnabled("versioning");
|
|
1236
841
|
return s;
|
|
1237
842
|
}
|
|
1238
|
-
function
|
|
1239
|
-
return C(s) ?
|
|
843
|
+
function j(s) {
|
|
844
|
+
return C(s) ? h.ok(s) : h.fail(r.featureNotEnabled("versioning"));
|
|
1240
845
|
}
|
|
1241
|
-
function
|
|
846
|
+
function k(s) {
|
|
1242
847
|
if (!V(s))
|
|
1243
|
-
throw
|
|
848
|
+
throw r.featureNotEnabled("audit");
|
|
1244
849
|
return s;
|
|
1245
850
|
}
|
|
1246
|
-
function
|
|
1247
|
-
return V(s) ?
|
|
851
|
+
function B(s) {
|
|
852
|
+
return V(s) ? h.ok(s) : h.fail(r.featureNotEnabled("audit"));
|
|
1248
853
|
}
|
|
1249
|
-
function
|
|
854
|
+
function W(s) {
|
|
1250
855
|
if (!A(s))
|
|
1251
|
-
throw
|
|
856
|
+
throw r.featureNotEnabled("eventSourcing");
|
|
1252
857
|
return s;
|
|
1253
858
|
}
|
|
1254
|
-
function
|
|
1255
|
-
return A(s) ?
|
|
859
|
+
function R(s) {
|
|
860
|
+
return A(s) ? h.ok(s) : h.fail(r.featureNotEnabled("eventSourcing"));
|
|
1256
861
|
}
|
|
1257
|
-
function
|
|
862
|
+
function z(s) {
|
|
1258
863
|
return s.getCapabilityTypes();
|
|
1259
864
|
}
|
|
1260
865
|
function q(s, t) {
|
|
@@ -1262,22 +867,22 @@ function q(s, t) {
|
|
|
1262
867
|
}
|
|
1263
868
|
export {
|
|
1264
869
|
m as AggregateBuilder,
|
|
1265
|
-
|
|
870
|
+
r as AggregateError,
|
|
1266
871
|
v as AggregateRoot,
|
|
1267
872
|
b as AuditCapability,
|
|
1268
|
-
|
|
1269
|
-
|
|
873
|
+
w as Entity,
|
|
874
|
+
E as EventSourcingCapability,
|
|
1270
875
|
S as SnapshotCapability,
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
876
|
+
p as VersioningCapability,
|
|
877
|
+
H as aggregateBuilder,
|
|
878
|
+
k as asAuditAggregate,
|
|
879
|
+
W as asEventSourcingAggregate,
|
|
1275
880
|
U as asSnapshotAggregate,
|
|
1276
|
-
|
|
1277
|
-
|
|
881
|
+
P as asVersioningAggregate,
|
|
882
|
+
z as getAggregateCapabilities,
|
|
1278
883
|
q as hasAllCapabilities,
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
884
|
+
B as tryAsAuditAggregate,
|
|
885
|
+
R as tryAsEventSourcingAggregate,
|
|
886
|
+
O as tryAsSnapshotAggregate,
|
|
887
|
+
j as tryAsVersioningAggregate
|
|
1283
888
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vytches/ddd-aggregates",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"description": "Aggregate root implementations with capabilities",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -33,17 +33,17 @@
|
|
|
33
33
|
"directory": "packages/aggregates"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@vytches/ddd-contracts": "0.
|
|
37
|
-
"@vytches/ddd-domain-primitives": "0.
|
|
38
|
-
"@vytches/ddd-logging": "0.
|
|
39
|
-
"@vytches/ddd-value-objects": "0.
|
|
36
|
+
"@vytches/ddd-contracts": "0.27.0",
|
|
37
|
+
"@vytches/ddd-domain-primitives": "0.27.0",
|
|
38
|
+
"@vytches/ddd-logging": "0.27.0",
|
|
39
|
+
"@vytches/ddd-value-objects": "0.27.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"typescript": "^5.0.0",
|
|
43
43
|
"vite": "^7.3.2",
|
|
44
44
|
"vite-plugin-dts": "^4.0.0",
|
|
45
45
|
"vitest": "^2.0.0",
|
|
46
|
-
"@vytches/ddd-testing": "0.
|
|
46
|
+
"@vytches/ddd-testing": "0.27.0"
|
|
47
47
|
},
|
|
48
48
|
"nx": {
|
|
49
49
|
"tags": [
|