@cqrs-ddd/core 0.2.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.
Files changed (212) hide show
  1. package/COMMERCIAL_LICENSE.txt +34 -0
  2. package/LICENSE +661 -0
  3. package/README.md +707 -0
  4. package/dist/application/base.command.d.ts +44 -0
  5. package/dist/application/base.command.d.ts.map +1 -0
  6. package/dist/application/base.command.js +58 -0
  7. package/dist/application/base.command.js.map +1 -0
  8. package/dist/application/base.query.d.ts +42 -0
  9. package/dist/application/base.query.d.ts.map +1 -0
  10. package/dist/application/base.query.js +52 -0
  11. package/dist/application/base.query.js.map +1 -0
  12. package/dist/application/command-base.handler.d.ts +106 -0
  13. package/dist/application/command-base.handler.d.ts.map +1 -0
  14. package/dist/application/command-base.handler.js +119 -0
  15. package/dist/application/command-base.handler.js.map +1 -0
  16. package/dist/application/index.d.ts +16 -0
  17. package/dist/application/index.d.ts.map +1 -0
  18. package/dist/application/index.js +33 -0
  19. package/dist/application/index.js.map +1 -0
  20. package/dist/application/ports/cache.port.d.ts +104 -0
  21. package/dist/application/ports/cache.port.d.ts.map +1 -0
  22. package/dist/application/ports/cache.port.js +17 -0
  23. package/dist/application/ports/cache.port.js.map +1 -0
  24. package/dist/application/ports/command-repository.port.d.ts +28 -0
  25. package/dist/application/ports/command-repository.port.d.ts.map +1 -0
  26. package/dist/application/ports/command-repository.port.js +4 -0
  27. package/dist/application/ports/command-repository.port.js.map +1 -0
  28. package/dist/application/ports/domain-event-publisher.port.d.ts +18 -0
  29. package/dist/application/ports/domain-event-publisher.port.d.ts.map +1 -0
  30. package/dist/application/ports/domain-event-publisher.port.js +4 -0
  31. package/dist/application/ports/domain-event-publisher.port.js.map +1 -0
  32. package/dist/application/ports/query-repository.port.d.ts +26 -0
  33. package/dist/application/ports/query-repository.port.d.ts.map +1 -0
  34. package/dist/application/ports/query-repository.port.js +4 -0
  35. package/dist/application/ports/query-repository.port.js.map +1 -0
  36. package/dist/application/ports/write-side-aggregate-repository.port.d.ts +33 -0
  37. package/dist/application/ports/write-side-aggregate-repository.port.d.ts.map +1 -0
  38. package/dist/application/ports/write-side-aggregate-repository.port.js +4 -0
  39. package/dist/application/ports/write-side-aggregate-repository.port.js.map +1 -0
  40. package/dist/application/query.options.d.ts +22 -0
  41. package/dist/application/query.options.d.ts.map +1 -0
  42. package/dist/application/query.options.js +4 -0
  43. package/dist/application/query.options.js.map +1 -0
  44. package/dist/application/request-fields.helper.d.ts +5 -0
  45. package/dist/application/request-fields.helper.d.ts.map +1 -0
  46. package/dist/application/request-fields.helper.js +20 -0
  47. package/dist/application/request-fields.helper.js.map +1 -0
  48. package/dist/application/tenant-resolver.d.ts +56 -0
  49. package/dist/application/tenant-resolver.d.ts.map +1 -0
  50. package/dist/application/tenant-resolver.js +60 -0
  51. package/dist/application/tenant-resolver.js.map +1 -0
  52. package/dist/domain/decorators/apply-mutation.decorator.d.ts +64 -0
  53. package/dist/domain/decorators/apply-mutation.decorator.d.ts.map +1 -0
  54. package/dist/domain/decorators/apply-mutation.decorator.js +86 -0
  55. package/dist/domain/decorators/apply-mutation.decorator.js.map +1 -0
  56. package/dist/domain/decorators/mutable.decorator.d.ts +54 -0
  57. package/dist/domain/decorators/mutable.decorator.d.ts.map +1 -0
  58. package/dist/domain/decorators/mutable.decorator.js +76 -0
  59. package/dist/domain/decorators/mutable.decorator.js.map +1 -0
  60. package/dist/domain/events/domain.event.d.ts +13 -0
  61. package/dist/domain/events/domain.event.d.ts.map +1 -0
  62. package/dist/domain/events/domain.event.js +20 -0
  63. package/dist/domain/events/domain.event.js.map +1 -0
  64. package/dist/domain/events/event.interface.d.ts +9 -0
  65. package/dist/domain/events/event.interface.d.ts.map +1 -0
  66. package/dist/domain/events/event.interface.js +4 -0
  67. package/dist/domain/events/event.interface.js.map +1 -0
  68. package/dist/domain/events/root-domain.event.d.ts +50 -0
  69. package/dist/domain/events/root-domain.event.d.ts.map +1 -0
  70. package/dist/domain/events/root-domain.event.js +156 -0
  71. package/dist/domain/events/root-domain.event.js.map +1 -0
  72. package/dist/domain/exceptions/concurrency-conflict.error.d.ts +20 -0
  73. package/dist/domain/exceptions/concurrency-conflict.error.d.ts.map +1 -0
  74. package/dist/domain/exceptions/concurrency-conflict.error.js +32 -0
  75. package/dist/domain/exceptions/concurrency-conflict.error.js.map +1 -0
  76. package/dist/domain/exceptions/domain.exception.d.ts +30 -0
  77. package/dist/domain/exceptions/domain.exception.d.ts.map +1 -0
  78. package/dist/domain/exceptions/domain.exception.js +39 -0
  79. package/dist/domain/exceptions/domain.exception.js.map +1 -0
  80. package/dist/domain/exceptions/entity-not-found.exception.d.ts +14 -0
  81. package/dist/domain/exceptions/entity-not-found.exception.d.ts.map +1 -0
  82. package/dist/domain/exceptions/entity-not-found.exception.js +23 -0
  83. package/dist/domain/exceptions/entity-not-found.exception.js.map +1 -0
  84. package/dist/domain/exceptions/invalid-value.exception.d.ts +35 -0
  85. package/dist/domain/exceptions/invalid-value.exception.d.ts.map +1 -0
  86. package/dist/domain/exceptions/invalid-value.exception.js +67 -0
  87. package/dist/domain/exceptions/invalid-value.exception.js.map +1 -0
  88. package/dist/domain/exceptions/missing-tenant-context.exception.d.ts +24 -0
  89. package/dist/domain/exceptions/missing-tenant-context.exception.d.ts.map +1 -0
  90. package/dist/domain/exceptions/missing-tenant-context.exception.js +33 -0
  91. package/dist/domain/exceptions/missing-tenant-context.exception.js.map +1 -0
  92. package/dist/domain/exceptions/transient-operation.error.d.ts +17 -0
  93. package/dist/domain/exceptions/transient-operation.error.d.ts.map +1 -0
  94. package/dist/domain/exceptions/transient-operation.error.js +27 -0
  95. package/dist/domain/exceptions/transient-operation.error.js.map +1 -0
  96. package/dist/domain/exceptions/unknown-mutable-field.error.d.ts +14 -0
  97. package/dist/domain/exceptions/unknown-mutable-field.error.d.ts.map +1 -0
  98. package/dist/domain/exceptions/unknown-mutable-field.error.js +24 -0
  99. package/dist/domain/exceptions/unknown-mutable-field.error.js.map +1 -0
  100. package/dist/domain/index.d.ts +26 -0
  101. package/dist/domain/index.d.ts.map +1 -0
  102. package/dist/domain/index.js +43 -0
  103. package/dist/domain/index.js.map +1 -0
  104. package/dist/domain/interfaces/root-entity-snapshot.interface.d.ts +7 -0
  105. package/dist/domain/interfaces/root-entity-snapshot.interface.d.ts.map +1 -0
  106. package/dist/domain/interfaces/root-entity-snapshot.interface.js +4 -0
  107. package/dist/domain/interfaces/root-entity-snapshot.interface.js.map +1 -0
  108. package/dist/domain/models/aggregate-root.d.ts +87 -0
  109. package/dist/domain/models/aggregate-root.d.ts.map +1 -0
  110. package/dist/domain/models/aggregate-root.js +122 -0
  111. package/dist/domain/models/aggregate-root.js.map +1 -0
  112. package/dist/domain/models/root.entity.d.ts +208 -0
  113. package/dist/domain/models/root.entity.d.ts.map +1 -0
  114. package/dist/domain/models/root.entity.js +350 -0
  115. package/dist/domain/models/root.entity.js.map +1 -0
  116. package/dist/domain/rules/number.rule.d.ts +81 -0
  117. package/dist/domain/rules/number.rule.d.ts.map +1 -0
  118. package/dist/domain/rules/number.rule.js +81 -0
  119. package/dist/domain/rules/number.rule.js.map +1 -0
  120. package/dist/domain/rules/rule-support.d.ts +6 -0
  121. package/dist/domain/rules/rule-support.d.ts.map +1 -0
  122. package/dist/domain/rules/rule-support.js +19 -0
  123. package/dist/domain/rules/rule-support.js.map +1 -0
  124. package/dist/domain/rules/text.rule.d.ts +98 -0
  125. package/dist/domain/rules/text.rule.d.ts.map +1 -0
  126. package/dist/domain/rules/text.rule.js +103 -0
  127. package/dist/domain/rules/text.rule.js.map +1 -0
  128. package/dist/domain/rules/value-violation.d.ts +44 -0
  129. package/dist/domain/rules/value-violation.d.ts.map +1 -0
  130. package/dist/domain/rules/value-violation.js +4 -0
  131. package/dist/domain/rules/value-violation.js.map +1 -0
  132. package/dist/http/domain-error-http-status.d.ts +43 -0
  133. package/dist/http/domain-error-http-status.d.ts.map +1 -0
  134. package/dist/http/domain-error-http-status.js +27 -0
  135. package/dist/http/domain-error-http-status.js.map +1 -0
  136. package/dist/http/index.d.ts +9 -0
  137. package/dist/http/index.d.ts.map +1 -0
  138. package/dist/http/index.js +26 -0
  139. package/dist/http/index.js.map +1 -0
  140. package/dist/index.d.ts +13 -0
  141. package/dist/index.d.ts.map +1 -0
  142. package/dist/index.js +30 -0
  143. package/dist/index.js.map +1 -0
  144. package/dist/persistence/cache/cache-logger.d.ts +29 -0
  145. package/dist/persistence/cache/cache-logger.d.ts.map +1 -0
  146. package/dist/persistence/cache/cache-logger.js +23 -0
  147. package/dist/persistence/cache/cache-logger.js.map +1 -0
  148. package/dist/persistence/cache/memory.cache.d.ts +72 -0
  149. package/dist/persistence/cache/memory.cache.d.ts.map +1 -0
  150. package/dist/persistence/cache/memory.cache.js +183 -0
  151. package/dist/persistence/cache/memory.cache.js.map +1 -0
  152. package/dist/persistence/command-repository.abstract.d.ts +39 -0
  153. package/dist/persistence/command-repository.abstract.d.ts.map +1 -0
  154. package/dist/persistence/command-repository.abstract.js +43 -0
  155. package/dist/persistence/command-repository.abstract.js.map +1 -0
  156. package/dist/persistence/decorators/acknowledge-persisted.decorator.d.ts +82 -0
  157. package/dist/persistence/decorators/acknowledge-persisted.decorator.d.ts.map +1 -0
  158. package/dist/persistence/decorators/acknowledge-persisted.decorator.js +82 -0
  159. package/dist/persistence/decorators/acknowledge-persisted.decorator.js.map +1 -0
  160. package/dist/persistence/decorators/cache.decorator.d.ts +93 -0
  161. package/dist/persistence/decorators/cache.decorator.d.ts.map +1 -0
  162. package/dist/persistence/decorators/cache.decorator.js +200 -0
  163. package/dist/persistence/decorators/cache.decorator.js.map +1 -0
  164. package/dist/persistence/decorators/from-cache.decorator.d.ts +65 -0
  165. package/dist/persistence/decorators/from-cache.decorator.d.ts.map +1 -0
  166. package/dist/persistence/decorators/from-cache.decorator.js +165 -0
  167. package/dist/persistence/decorators/from-cache.decorator.js.map +1 -0
  168. package/dist/persistence/decorators/map-persistence-errors.decorator.d.ts +88 -0
  169. package/dist/persistence/decorators/map-persistence-errors.decorator.d.ts.map +1 -0
  170. package/dist/persistence/decorators/map-persistence-errors.decorator.js +89 -0
  171. package/dist/persistence/decorators/map-persistence-errors.decorator.js.map +1 -0
  172. package/dist/persistence/decorators/persisted-write.decorator.d.ts +61 -0
  173. package/dist/persistence/decorators/persisted-write.decorator.d.ts.map +1 -0
  174. package/dist/persistence/decorators/persisted-write.decorator.js +57 -0
  175. package/dist/persistence/decorators/persisted-write.decorator.js.map +1 -0
  176. package/dist/persistence/helpers/cache-barrier.helper.d.ts +70 -0
  177. package/dist/persistence/helpers/cache-barrier.helper.d.ts.map +1 -0
  178. package/dist/persistence/helpers/cache-barrier.helper.js +57 -0
  179. package/dist/persistence/helpers/cache-barrier.helper.js.map +1 -0
  180. package/dist/persistence/helpers/cache-key.helper.d.ts +73 -0
  181. package/dist/persistence/helpers/cache-key.helper.d.ts.map +1 -0
  182. package/dist/persistence/helpers/cache-key.helper.js +132 -0
  183. package/dist/persistence/helpers/cache-key.helper.js.map +1 -0
  184. package/dist/persistence/helpers/cache-owner.helper.d.ts +9 -0
  185. package/dist/persistence/helpers/cache-owner.helper.d.ts.map +1 -0
  186. package/dist/persistence/helpers/cache-owner.helper.js +22 -0
  187. package/dist/persistence/helpers/cache-owner.helper.js.map +1 -0
  188. package/dist/persistence/helpers/cache-snapshot.helper.d.ts +28 -0
  189. package/dist/persistence/helpers/cache-snapshot.helper.d.ts.map +1 -0
  190. package/dist/persistence/helpers/cache-snapshot.helper.js +42 -0
  191. package/dist/persistence/helpers/cache-snapshot.helper.js.map +1 -0
  192. package/dist/persistence/helpers/cache-version.helper.d.ts +29 -0
  193. package/dist/persistence/helpers/cache-version.helper.d.ts.map +1 -0
  194. package/dist/persistence/helpers/cache-version.helper.js +71 -0
  195. package/dist/persistence/helpers/cache-version.helper.js.map +1 -0
  196. package/dist/persistence/index.d.ts +23 -0
  197. package/dist/persistence/index.d.ts.map +1 -0
  198. package/dist/persistence/index.js +40 -0
  199. package/dist/persistence/index.js.map +1 -0
  200. package/dist/persistence/persistence-dialect.d.ts +35 -0
  201. package/dist/persistence/persistence-dialect.d.ts.map +1 -0
  202. package/dist/persistence/persistence-dialect.js +31 -0
  203. package/dist/persistence/persistence-dialect.js.map +1 -0
  204. package/dist/persistence/query-repository.abstract.d.ts +76 -0
  205. package/dist/persistence/query-repository.abstract.d.ts.map +1 -0
  206. package/dist/persistence/query-repository.abstract.js +67 -0
  207. package/dist/persistence/query-repository.abstract.js.map +1 -0
  208. package/dist/types/Method.type.d.ts +2 -0
  209. package/dist/types/Method.type.d.ts.map +1 -0
  210. package/dist/types/Method.type.js +4 -0
  211. package/dist/types/Method.type.js.map +1 -0
  212. package/package.json +80 -0
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Base class for application CQRS commands.
3
+ *
4
+ * Encapsulates non-enumerable session/authentication metadata and reports which
5
+ * of a declared set of fields this command actually carries, via
6
+ * {@link getUpdateFields}.
7
+ */
8
+ export declare abstract class BaseCommand<TSessionPrincipal = any> {
9
+ readonly sessionPrincipal?: TSessionPrincipal;
10
+ readonly sessionUser?: TSessionPrincipal;
11
+ constructor(sessionPrincipal?: TSessionPrincipal);
12
+ /**
13
+ * Serializes enumerable command payload fields to a plain object.
14
+ *
15
+ * Non-enumerable metadata such as `sessionPrincipal` and `sessionUser` is excluded, and fields whose
16
+ * value is `undefined` are omitted. This makes the result suitable for stable
17
+ * cache/idempotency fingerprinting.
18
+ *
19
+ * @returns The command payload without pipeline/session metadata.
20
+ */
21
+ toJSON(): Record<string, unknown>;
22
+ /**
23
+ * Returns the declared updatable fields that are actually present on this command.
24
+ *
25
+ * A field counts as present when its value is not `undefined`. `null`
26
+ * therefore counts as an intentional mutation, which is important for nullable
27
+ * fields such as clearing a department.
28
+ *
29
+ * Use this with field-level authorization so the authorization surface is an
30
+ * explicit list owned by the command type.
31
+ *
32
+ * @param updatableFields - Allowed updatable field names for this command.
33
+ * @returns Only fields present in the current command payload.
34
+ *
35
+ * @example
36
+ * ```ts
37
+ * // updatableFields: the fields this command type declares updatable.
38
+ * const fields = command.getUpdateFields(updatableFields);
39
+ * authorizer.authorize('update', user, fields);
40
+ * ```
41
+ */
42
+ getUpdateFields(updatableFields: readonly string[]): string[];
43
+ }
44
+ //# sourceMappingURL=base.command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.command.d.ts","sourceRoot":"","sources":["../../application/base.command.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AAEH,8BAAsB,WAAW,CAAC,iBAAiB,GAAG,GAAG;IACvD,SAAwB,gBAAgB,CAAC,EAAE,iBAAiB,CAAC;IAC7D,SAAwB,WAAW,CAAC,EAAE,iBAAiB,CAAC;gBAE5C,gBAAgB,CAAC,EAAE,iBAAiB;IAOhD;;;;;;;;OAQG;IACH,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAIjC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,eAAe,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE;CAK9D"}
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ /* Copyright (C) 2026-present Aristotelis — see repository license. */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.BaseCommand = void 0;
5
+ const request_fields_helper_1 = require("./request-fields.helper");
6
+ /**
7
+ * Base class for application CQRS commands.
8
+ *
9
+ * Encapsulates non-enumerable session/authentication metadata and reports which
10
+ * of a declared set of fields this command actually carries, via
11
+ * {@link getUpdateFields}.
12
+ */
13
+ // biome-ignore lint/suspicious/noExplicitAny: generic session principal default
14
+ class BaseCommand {
15
+ constructor(sessionPrincipal) {
16
+ if (sessionPrincipal !== undefined) {
17
+ (0, request_fields_helper_1.defineHidden)(this, 'sessionPrincipal', sessionPrincipal);
18
+ (0, request_fields_helper_1.defineHidden)(this, 'sessionUser', sessionPrincipal);
19
+ }
20
+ }
21
+ /**
22
+ * Serializes enumerable command payload fields to a plain object.
23
+ *
24
+ * Non-enumerable metadata such as `sessionPrincipal` and `sessionUser` is excluded, and fields whose
25
+ * value is `undefined` are omitted. This makes the result suitable for stable
26
+ * cache/idempotency fingerprinting.
27
+ *
28
+ * @returns The command payload without pipeline/session metadata.
29
+ */
30
+ toJSON() {
31
+ return (0, request_fields_helper_1.definedFields)(this);
32
+ }
33
+ /**
34
+ * Returns the declared updatable fields that are actually present on this command.
35
+ *
36
+ * A field counts as present when its value is not `undefined`. `null`
37
+ * therefore counts as an intentional mutation, which is important for nullable
38
+ * fields such as clearing a department.
39
+ *
40
+ * Use this with field-level authorization so the authorization surface is an
41
+ * explicit list owned by the command type.
42
+ *
43
+ * @param updatableFields - Allowed updatable field names for this command.
44
+ * @returns Only fields present in the current command payload.
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * // updatableFields: the fields this command type declares updatable.
49
+ * const fields = command.getUpdateFields(updatableFields);
50
+ * authorizer.authorize('update', user, fields);
51
+ * ```
52
+ */
53
+ getUpdateFields(updatableFields) {
54
+ return updatableFields.filter((field) => this[field] !== undefined);
55
+ }
56
+ }
57
+ exports.BaseCommand = BaseCommand;
58
+ //# sourceMappingURL=base.command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.command.js","sourceRoot":"","sources":["../../application/base.command.ts"],"names":[],"mappings":";AAAA,sEAAsE;;;AAEtE,mEAAsE;AAEtE;;;;;;GAMG;AACH,gFAAgF;AAChF,MAAsB,WAAW;IAI/B,YAAY,gBAAoC;QAC9C,IAAI,gBAAgB,KAAK,SAAS,EAAE,CAAC;YACnC,IAAA,oCAAY,EAAC,IAAI,EAAE,kBAAkB,EAAE,gBAAgB,CAAC,CAAC;YACzD,IAAA,oCAAY,EAAC,IAAI,EAAE,aAAa,EAAE,gBAAgB,CAAC,CAAC;QACtD,CAAC;IACH,CAAC;IAED;;;;;;;;OAQG;IACH,MAAM;QACJ,OAAO,IAAA,qCAAa,EAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;IAED;;;;;;;;;;;;;;;;;;;OAmBG;IACH,eAAe,CAAC,eAAkC;QAChD,OAAO,eAAe,CAAC,MAAM,CAC3B,CAAC,KAAK,EAAE,EAAE,CAAE,IAAgC,CAAC,KAAK,CAAC,KAAK,SAAS,CAClE,CAAC;IACJ,CAAC;CACF;AAjDD,kCAiDC"}
@@ -0,0 +1,42 @@
1
+ import type { IQueryOptions } from './query.options';
2
+ /**
3
+ * Base class for application CQRS queries.
4
+ *
5
+ * Query options and authentication context are pipeline metadata rather than request
6
+ * payload. They are stored as non-enumerable properties so Zod validation and
7
+ * cache-key serialization operate only on the query payload.
8
+ *
9
+ * @typeParam TSessionUser - Application-specific principal/session metadata type.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * export class GetUserQuery extends BaseQuery<SessionUser> {
14
+ * constructor(
15
+ * public readonly id: string,
16
+ * options?: Partial<IQueryOptions>,
17
+ * sessionUser?: SessionUser,
18
+ * ) {
19
+ * super(options, sessionUser);
20
+ * }
21
+ * }
22
+ *
23
+ * const query = new GetUserQuery(userId, { hydrate: true }, sessionUser);
24
+ * ```
25
+ */
26
+ export declare abstract class BaseQuery<TSessionPrincipal = unknown> implements IQueryOptions {
27
+ readonly hydrate?: boolean;
28
+ readonly refresh?: boolean;
29
+ readonly sessionPrincipal?: TSessionPrincipal;
30
+ readonly sessionUser?: TSessionPrincipal;
31
+ constructor(options?: Partial<IQueryOptions>, sessionPrincipal?: TSessionPrincipal);
32
+ /**
33
+ * Serializes enumerable query payload fields to a plain object.
34
+ *
35
+ * `hydrate`, `refresh`, `sessionPrincipal` and `sessionUser` are non-enumerable metadata and stay
36
+ * out of the payload.
37
+ *
38
+ * @returns The query payload with `undefined` fields omitted.
39
+ */
40
+ toJSON(): Record<string, unknown>;
41
+ }
42
+ //# sourceMappingURL=base.query.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.query.d.ts","sourceRoot":"","sources":["../../application/base.query.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGrD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,8BAAsB,SAAS,CAAC,iBAAiB,GAAG,OAAO,CACzD,YAAW,aAAa;IAExB,SAAwB,OAAO,CAAC,EAAE,OAAO,CAAC;IAC1C,SAAwB,OAAO,CAAC,EAAE,OAAO,CAAC;IAC1C,SAAwB,gBAAgB,CAAC,EAAE,iBAAiB,CAAC;IAC7D,SAAwB,WAAW,CAAC,EAAE,iBAAiB,CAAC;gBAGtD,OAAO,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,EAChC,gBAAgB,CAAC,EAAE,iBAAiB;IAUtC;;;;;;;OAOG;IACH,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAGlC"}
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ /* Copyright (C) 2026-present Aristotelis — see repository license. */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.BaseQuery = void 0;
5
+ const request_fields_helper_1 = require("./request-fields.helper");
6
+ /**
7
+ * Base class for application CQRS queries.
8
+ *
9
+ * Query options and authentication context are pipeline metadata rather than request
10
+ * payload. They are stored as non-enumerable properties so Zod validation and
11
+ * cache-key serialization operate only on the query payload.
12
+ *
13
+ * @typeParam TSessionUser - Application-specific principal/session metadata type.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * export class GetUserQuery extends BaseQuery<SessionUser> {
18
+ * constructor(
19
+ * public readonly id: string,
20
+ * options?: Partial<IQueryOptions>,
21
+ * sessionUser?: SessionUser,
22
+ * ) {
23
+ * super(options, sessionUser);
24
+ * }
25
+ * }
26
+ *
27
+ * const query = new GetUserQuery(userId, { hydrate: true }, sessionUser);
28
+ * ```
29
+ */
30
+ class BaseQuery {
31
+ constructor(options, sessionPrincipal) {
32
+ (0, request_fields_helper_1.defineHidden)(this, 'hydrate', options?.hydrate ?? false);
33
+ (0, request_fields_helper_1.defineHidden)(this, 'refresh', options?.refresh ?? false);
34
+ if (sessionPrincipal !== undefined) {
35
+ (0, request_fields_helper_1.defineHidden)(this, 'sessionPrincipal', sessionPrincipal);
36
+ (0, request_fields_helper_1.defineHidden)(this, 'sessionUser', sessionPrincipal);
37
+ }
38
+ }
39
+ /**
40
+ * Serializes enumerable query payload fields to a plain object.
41
+ *
42
+ * `hydrate`, `refresh`, `sessionPrincipal` and `sessionUser` are non-enumerable metadata and stay
43
+ * out of the payload.
44
+ *
45
+ * @returns The query payload with `undefined` fields omitted.
46
+ */
47
+ toJSON() {
48
+ return (0, request_fields_helper_1.definedFields)(this);
49
+ }
50
+ }
51
+ exports.BaseQuery = BaseQuery;
52
+ //# sourceMappingURL=base.query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.query.js","sourceRoot":"","sources":["../../application/base.query.ts"],"names":[],"mappings":";AAAA,sEAAsE;;;AAGtE,mEAAsE;AAEtE;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAsB,SAAS;IAQ7B,YACE,OAAgC,EAChC,gBAAoC;QAEpC,IAAA,oCAAY,EAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,IAAI,KAAK,CAAC,CAAC;QACzD,IAAA,oCAAY,EAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,IAAI,KAAK,CAAC,CAAC;QACzD,IAAI,gBAAgB,KAAK,SAAS,EAAE,CAAC;YACnC,IAAA,oCAAY,EAAC,IAAI,EAAE,kBAAkB,EAAE,gBAAgB,CAAC,CAAC;YACzD,IAAA,oCAAY,EAAC,IAAI,EAAE,aAAa,EAAE,gBAAgB,CAAC,CAAC;QACtD,CAAC;IACH,CAAC;IAED;;;;;;;OAOG;IACH,MAAM;QACJ,OAAO,IAAA,qCAAa,EAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;CACF;AA/BD,8BA+BC"}
@@ -0,0 +1,106 @@
1
+ import { AggregateRoot } from '../domain/models/aggregate-root';
2
+ import type { IDomainEventPublisher } from './ports/domain-event-publisher.port';
3
+ /**
4
+ * Result shapes that allow `CommandBaseHandler` to publish buffered aggregate events.
5
+ * Return either the aggregate itself or an application result with an `aggregate` field.
6
+ */
7
+ export type AggregateBearingResult = AggregateRoot | {
8
+ readonly aggregate: AggregateRoot;
9
+ };
10
+ /**
11
+ * Base class for all CQRS command handlers.
12
+ *
13
+ * Wraps every concrete command handler with shared lifecycle behavior:
14
+ * 1. Executes command logic via the abstract {@link handle} method.
15
+ * 2. If the result is an {@link AggregateRoot} (or an object containing `aggregate: AggregateRoot`),
16
+ * its buffered uncommitted domain events are automatically published through the
17
+ * {@link IDomainEventPublisher} and cleared after publication.
18
+ *
19
+ * It is framework-neutral. With NestJS CQRS, decorate the subclass with
20
+ * `@CommandHandler` and pass the injected `EventBus`, which satisfies
21
+ * {@link IDomainEventPublisher}; Nest calls {@link execute} as the handler entry point.
22
+ *
23
+ * @typeParam TCommand - The concrete command type this handler processes.
24
+ * @typeParam TResult - The handler's return type (e.g. aggregate entity or result carrying aggregate).
25
+ *
26
+ * @example Returning aggregate root directly (auto-published)
27
+ * ```typescript
28
+ * @CommandHandler(CreateUserCommand)
29
+ * export class CreateUserHandler extends CommandBaseHandler<CreateUserCommand, User> {
30
+ * constructor(
31
+ * @Inject(COMMAND_REPOSITORY.createUser)
32
+ * private readonly commandRepository: ICommandRepository<User, UserSnapshot>,
33
+ * protected readonly eventBus: EventBus,
34
+ * ) {
35
+ * super(eventBus);
36
+ * }
37
+ *
38
+ * async handle(command: CreateUserCommand): Promise<User> {
39
+ * const user = User.create(command.username, command.email);
40
+ * await this.commandRepository.save(user);
41
+ * return user; // execute() automatically publishes user.getUncommittedEvents()
42
+ * }
43
+ * }
44
+ * ```
45
+ *
46
+ * @example Returning an application result carrying an AggregateRoot (auto-published)
47
+ * ```typescript
48
+ * @CommandHandler(CreateAuthCommand)
49
+ * export class CreateAuthHandler extends CommandBaseHandler<CreateAuthCommand, CreateAuthResult> {
50
+ * constructor(
51
+ * @Inject(COMMAND_REPOSITORY.createAuth)
52
+ * private readonly commandRepository: ICommandRepository<Auth, null>,
53
+ * protected readonly eventBus: EventBus,
54
+ * ) {
55
+ * super(eventBus);
56
+ * }
57
+ *
58
+ * async handle(command: CreateAuthCommand): Promise<CreateAuthResult> {
59
+ * const auth = Auth.create(userId, token);
60
+ * await this.commandRepository.save(auth);
61
+ * return {
62
+ * aggregate: auth, // execute() automatically detects aggregate and publishes events
63
+ * id: userId,
64
+ * tenant: tenant,
65
+ * token,
66
+ * };
67
+ * }
68
+ * }
69
+ * ```
70
+ */
71
+ export declare abstract class CommandBaseHandler<TCommand = unknown, TResult extends AggregateBearingResult = AggregateBearingResult> {
72
+ protected readonly eventBus: IDomainEventPublisher;
73
+ /**
74
+ * Constructs the handler with the publisher of domain events.
75
+ *
76
+ * @param eventBus - The publisher used to dispatch domain events, such as the
77
+ * NestJS CQRS `EventBus`.
78
+ */
79
+ protected constructor(eventBus: IDomainEventPublisher);
80
+ /**
81
+ * Executes the business logic for the command.
82
+ *
83
+ * Concrete handlers must implement this method instead of `execute()`.
84
+ * If the returned result is an {@link AggregateRoot} (or contains an `aggregate` property),
85
+ * any uncommitted domain events recorded on it will be published automatically.
86
+ *
87
+ * @param command - The typed command to process.
88
+ * @returns The result of the command execution.
89
+ */
90
+ abstract handle(command: TCommand): Promise<TResult>;
91
+ /**
92
+ * Handler entry point, invoked by the command bus (for example the NestJS CQRS
93
+ * `CommandBus`).
94
+ *
95
+ * Delegates to {@link handle} and automatically publishes any uncommitted domain
96
+ * events if the result is an {@link AggregateRoot} (or an object containing `aggregate: AggregateRoot`).
97
+ *
98
+ * Persistence and in-memory event publication are not atomic. A crash after
99
+ * persistence can lose events; durable delivery requires an explicit outbox.
100
+ *
101
+ * @param command - The command dispatched through the command bus.
102
+ * @returns The result produced by {@link handle}.
103
+ */
104
+ execute(command: TCommand): Promise<TResult>;
105
+ }
106
+ //# sourceMappingURL=command-base.handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-base.handler.d.ts","sourceRoot":"","sources":["../../application/command-base.handler.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAChE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AAEjF;;;GAGG;AACH,MAAM,MAAM,sBAAsB,GAC9B,aAAa,GACb;IAAE,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAA;CAAE,CAAC;AAY1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4DG;AACH,8BAAsB,kBAAkB,CACtC,QAAQ,GAAG,OAAO,EAClB,OAAO,SAAS,sBAAsB,GAAG,sBAAsB;IAQzC,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,qBAAqB;IANxE;;;;;OAKG;IACH,SAAS,aAAgC,QAAQ,EAAE,qBAAqB;IAExE;;;;;;;;;OASG;IACH,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;IAEpD;;;;;;;;;;;;OAYG;IACG,OAAO,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;CAsBnD"}
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+ /* Copyright (C) 2026-present Aristotelis — see repository license. */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.CommandBaseHandler = void 0;
5
+ const aggregate_root_1 = require("../domain/models/aggregate-root");
6
+ function isAggregate(obj) {
7
+ return (obj instanceof aggregate_root_1.AggregateRoot ||
8
+ (typeof obj === 'object' &&
9
+ obj !== null &&
10
+ typeof obj.getUncommittedEvents === 'function' &&
11
+ typeof obj.uncommit === 'function'));
12
+ }
13
+ /**
14
+ * Base class for all CQRS command handlers.
15
+ *
16
+ * Wraps every concrete command handler with shared lifecycle behavior:
17
+ * 1. Executes command logic via the abstract {@link handle} method.
18
+ * 2. If the result is an {@link AggregateRoot} (or an object containing `aggregate: AggregateRoot`),
19
+ * its buffered uncommitted domain events are automatically published through the
20
+ * {@link IDomainEventPublisher} and cleared after publication.
21
+ *
22
+ * It is framework-neutral. With NestJS CQRS, decorate the subclass with
23
+ * `@CommandHandler` and pass the injected `EventBus`, which satisfies
24
+ * {@link IDomainEventPublisher}; Nest calls {@link execute} as the handler entry point.
25
+ *
26
+ * @typeParam TCommand - The concrete command type this handler processes.
27
+ * @typeParam TResult - The handler's return type (e.g. aggregate entity or result carrying aggregate).
28
+ *
29
+ * @example Returning aggregate root directly (auto-published)
30
+ * ```typescript
31
+ * @CommandHandler(CreateUserCommand)
32
+ * export class CreateUserHandler extends CommandBaseHandler<CreateUserCommand, User> {
33
+ * constructor(
34
+ * @Inject(COMMAND_REPOSITORY.createUser)
35
+ * private readonly commandRepository: ICommandRepository<User, UserSnapshot>,
36
+ * protected readonly eventBus: EventBus,
37
+ * ) {
38
+ * super(eventBus);
39
+ * }
40
+ *
41
+ * async handle(command: CreateUserCommand): Promise<User> {
42
+ * const user = User.create(command.username, command.email);
43
+ * await this.commandRepository.save(user);
44
+ * return user; // execute() automatically publishes user.getUncommittedEvents()
45
+ * }
46
+ * }
47
+ * ```
48
+ *
49
+ * @example Returning an application result carrying an AggregateRoot (auto-published)
50
+ * ```typescript
51
+ * @CommandHandler(CreateAuthCommand)
52
+ * export class CreateAuthHandler extends CommandBaseHandler<CreateAuthCommand, CreateAuthResult> {
53
+ * constructor(
54
+ * @Inject(COMMAND_REPOSITORY.createAuth)
55
+ * private readonly commandRepository: ICommandRepository<Auth, null>,
56
+ * protected readonly eventBus: EventBus,
57
+ * ) {
58
+ * super(eventBus);
59
+ * }
60
+ *
61
+ * async handle(command: CreateAuthCommand): Promise<CreateAuthResult> {
62
+ * const auth = Auth.create(userId, token);
63
+ * await this.commandRepository.save(auth);
64
+ * return {
65
+ * aggregate: auth, // execute() automatically detects aggregate and publishes events
66
+ * id: userId,
67
+ * tenant: tenant,
68
+ * token,
69
+ * };
70
+ * }
71
+ * }
72
+ * ```
73
+ */
74
+ class CommandBaseHandler {
75
+ eventBus;
76
+ /**
77
+ * Constructs the handler with the publisher of domain events.
78
+ *
79
+ * @param eventBus - The publisher used to dispatch domain events, such as the
80
+ * NestJS CQRS `EventBus`.
81
+ */
82
+ constructor(eventBus) {
83
+ this.eventBus = eventBus;
84
+ }
85
+ /**
86
+ * Handler entry point, invoked by the command bus (for example the NestJS CQRS
87
+ * `CommandBus`).
88
+ *
89
+ * Delegates to {@link handle} and automatically publishes any uncommitted domain
90
+ * events if the result is an {@link AggregateRoot} (or an object containing `aggregate: AggregateRoot`).
91
+ *
92
+ * Persistence and in-memory event publication are not atomic. A crash after
93
+ * persistence can lose events; durable delivery requires an explicit outbox.
94
+ *
95
+ * @param command - The command dispatched through the command bus.
96
+ * @returns The result produced by {@link handle}.
97
+ */
98
+ async execute(command) {
99
+ const commandResult = await this.handle(command);
100
+ const aggregate = isAggregate(commandResult)
101
+ ? commandResult
102
+ : commandResult &&
103
+ typeof commandResult === 'object' &&
104
+ 'aggregate' in commandResult &&
105
+ isAggregate(commandResult.aggregate)
106
+ ? commandResult.aggregate
107
+ : undefined;
108
+ if (aggregate) {
109
+ const events = [...aggregate.getUncommittedEvents()];
110
+ if (events.length > 0) {
111
+ this.eventBus.publishAll(events);
112
+ aggregate.uncommit();
113
+ }
114
+ }
115
+ return commandResult;
116
+ }
117
+ }
118
+ exports.CommandBaseHandler = CommandBaseHandler;
119
+ //# sourceMappingURL=command-base.handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-base.handler.js","sourceRoot":"","sources":["../../application/command-base.handler.ts"],"names":[],"mappings":";AAAA,sEAAsE;;;AAEtE,oEAAgE;AAWhE,SAAS,WAAW,CAAC,GAAY;IAC/B,OAAO,CACL,GAAG,YAAY,8BAAa;QAC5B,CAAC,OAAO,GAAG,KAAK,QAAQ;YACtB,GAAG,KAAK,IAAI;YACZ,OAAQ,GAAqB,CAAC,oBAAoB,KAAK,UAAU;YACjE,OAAQ,GAAqB,CAAC,QAAQ,KAAK,UAAU,CAAC,CACzD,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4DG;AACH,MAAsB,kBAAkB;IAUG;IANzC;;;;;OAKG;IACH,YAAyC,QAA+B;QAA/B,aAAQ,GAAR,QAAQ,CAAuB;IAAG,CAAC;IAc5E;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,OAAO,CAAC,OAAiB;QAC7B,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAEjD,MAAM,SAAS,GAAG,WAAW,CAAC,aAAa,CAAC;YAC1C,CAAC,CAAC,aAAa;YACf,CAAC,CAAC,aAAa;gBACX,OAAO,aAAa,KAAK,QAAQ;gBACjC,WAAW,IAAI,aAAa;gBAC5B,WAAW,CAAC,aAAa,CAAC,SAAS,CAAC;gBACtC,CAAC,CAAC,aAAa,CAAC,SAAS;gBACzB,CAAC,CAAC,SAAS,CAAC;QAEhB,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC,oBAAoB,EAAE,CAAC,CAAC;YACrD,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACtB,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;gBACjC,SAAS,CAAC,QAAQ,EAAE,CAAC;YACvB,CAAC;QACH,CAAC;QAED,OAAO,aAAa,CAAC;IACvB,CAAC;CACF;AA3DD,gDA2DC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Application-layer primitives and the ports handlers depend on. The ports, in
3
+ * `ports/`, are the contracts a CQRS handler depends on; their adapters stay
4
+ * behind `@cqrs-ddd/core/persistence` or in an adapter package.
5
+ */
6
+ export * from './base.command';
7
+ export * from './base.query';
8
+ export * from './command-base.handler';
9
+ export * from './ports/cache.port';
10
+ export * from './ports/command-repository.port';
11
+ export * from './ports/domain-event-publisher.port';
12
+ export * from './ports/query-repository.port';
13
+ export * from './ports/write-side-aggregate-repository.port';
14
+ export * from './query.options';
15
+ export * from './tenant-resolver';
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../application/index.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,wBAAwB,CAAC;AACvC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iCAAiC,CAAC;AAChD,cAAc,qCAAqC,CAAC;AACpD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,8CAA8C,CAAC;AAC7D,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC"}
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ /* Copyright (C) 2026-present Aristotelis — see repository license. */
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
16
+ };
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ /**
19
+ * Application-layer primitives and the ports handlers depend on. The ports, in
20
+ * `ports/`, are the contracts a CQRS handler depends on; their adapters stay
21
+ * behind `@cqrs-ddd/core/persistence` or in an adapter package.
22
+ */
23
+ __exportStar(require("./base.command"), exports);
24
+ __exportStar(require("./base.query"), exports);
25
+ __exportStar(require("./command-base.handler"), exports);
26
+ __exportStar(require("./ports/cache.port"), exports);
27
+ __exportStar(require("./ports/command-repository.port"), exports);
28
+ __exportStar(require("./ports/domain-event-publisher.port"), exports);
29
+ __exportStar(require("./ports/query-repository.port"), exports);
30
+ __exportStar(require("./ports/write-side-aggregate-repository.port"), exports);
31
+ __exportStar(require("./query.options"), exports);
32
+ __exportStar(require("./tenant-resolver"), exports);
33
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../application/index.ts"],"names":[],"mappings":";AAAA,sEAAsE;;;;;;;;;;;;;;;;AAEtE;;;;GAIG;AAEH,iDAA+B;AAC/B,+CAA6B;AAC7B,yDAAuC;AACvC,qDAAmC;AACnC,kEAAgD;AAChD,sEAAoD;AACpD,gEAA8C;AAC9C,+EAA6D;AAC7D,kDAAgC;AAChC,oDAAkC"}
@@ -0,0 +1,104 @@
1
+ /** Options applied to one cache write. */
2
+ export interface CacheSetOptions {
3
+ /** Entry lifetime in milliseconds. Adapter-specific semantics apply when omitted. */
4
+ ttl?: number;
5
+ /**
6
+ * Atomic stale-write guard. When the adapter can compare an existing value
7
+ * with the incoming value, returning `true` means the cached value is newer
8
+ * and must not be overwritten.
9
+ *
10
+ * {@link isCacheNewer} is the standard comparator for versioned snapshots.
11
+ */
12
+ isNewer?: (cached: unknown, incoming: unknown) => boolean;
13
+ }
14
+ /**
15
+ * Minimal cache port used by DDD repository decorators.
16
+ *
17
+ * Implementations must store detached/serializable snapshots rather than live
18
+ * domain aggregates. `set()` may additionally implement compare-and-set
19
+ * semantics through {@link CacheSetOptions.isNewer}.
20
+ *
21
+ * @typeParam T - Value shape stored by this cache adapter.
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * const cached = await cache.get(userKey);
26
+ * await cache.set(userKey, user.toJSON(), {
27
+ * ttl: 30_000,
28
+ * isNewer: isCacheNewer,
29
+ * });
30
+ * await cache.delete(userKey);
31
+ * ```
32
+ */
33
+ export interface ICache<T = unknown> {
34
+ /** Returns the cached value, or `undefined` when the key is absent. */
35
+ get(key: string): Promise<T | undefined>;
36
+ /** Writes a value under `key`, optionally with TTL/CAS semantics. */
37
+ set(key: string, value: T, options?: CacheSetOptions): Promise<void>;
38
+ /** Removes `key` when present. */
39
+ delete(key: string): Promise<void>;
40
+ }
41
+ /** Cache entry observation state. */
42
+ export type CacheStateStatus = 'hit' | 'miss' | 'expired';
43
+ /**
44
+ * Observed state of a cache key including opaque revision fencing.
45
+ *
46
+ * @typeParam T - Value shape stored by this cache adapter.
47
+ */
48
+ export interface CacheStateEntry<T = unknown> {
49
+ /**
50
+ * Status of the cache entry:
51
+ * - `'hit'`: Value is present and unexpired.
52
+ * - `'miss'`: Key is absent or was invalidated.
53
+ * - `'expired'`: Entry existed but its TTL has elapsed.
54
+ */
55
+ readonly status: CacheStateStatus;
56
+ /** The cached value when status is `'hit'`, otherwise `undefined`. */
57
+ readonly value?: T;
58
+ /**
59
+ * Opaque revision token associated with the key at the moment of inspection.
60
+ * Advances on every write or invalidation, and is preserved on payload expiry
61
+ * to eliminate ABA races during fill attempts.
62
+ */
63
+ readonly revision: string;
64
+ }
65
+ /**
66
+ * Options for revision-fenced cache fill attempts.
67
+ */
68
+ export interface CacheFillOptions {
69
+ /** Entry lifetime in milliseconds. */
70
+ ttl?: number;
71
+ }
72
+ /**
73
+ * Extended cache port providing atomic revision-fenced state operations.
74
+ *
75
+ * Guarantees per-key ordering: a fill started before an observed invalidation
76
+ * cannot repopulate its key afterwards.
77
+ *
78
+ * @typeParam T - Value shape stored by this cache adapter.
79
+ */
80
+ export interface IVersionedCache<T = unknown> extends ICache<T> {
81
+ readonly isVersioned: true;
82
+ /**
83
+ * Observes current key state and opaque revision token.
84
+ */
85
+ readState(key: string): Promise<CacheStateEntry<T>>;
86
+ /**
87
+ * Atomically advances the key revision and evicts the value.
88
+ *
89
+ * @returns The newly advanced revision.
90
+ */
91
+ invalidate(key: string): Promise<string>;
92
+ /**
93
+ * Atomically checks that current revision matches `observedRevision`, writes
94
+ * value, and advances revision on match.
95
+ *
96
+ * @returns `true` if write committed; `false` if rejected due to revision mismatch.
97
+ */
98
+ tryFill(key: string, observedRevision: string, value: T, options?: CacheFillOptions): Promise<boolean>;
99
+ }
100
+ /**
101
+ * Capability guard verifying whether an adapter supports versioned coordination.
102
+ */
103
+ export declare function isVersionedCache<T = unknown>(cache: unknown): cache is IVersionedCache<T>;
104
+ //# sourceMappingURL=cache.port.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.port.d.ts","sourceRoot":"","sources":["../../../application/ports/cache.port.ts"],"names":[],"mappings":"AAEA,0CAA0C;AAC1C,MAAM,WAAW,eAAe;IAC9B,qFAAqF;IACrF,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,KAAK,OAAO,CAAC;CAC3D;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,MAAM,CAAC,CAAC,GAAG,OAAO;IACjC,uEAAuE;IACvE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IAEzC,qEAAqE;IACrE,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAErE,kCAAkC;IAClC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC;AAED,qCAAqC;AACrC,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,MAAM,GAAG,SAAS,CAAC;AAE1D;;;;GAIG;AACH,MAAM,WAAW,eAAe,CAAC,CAAC,GAAG,OAAO;IAC1C;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAElC,sEAAsE;IACtE,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAEnB;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,sCAAsC;IACtC,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe,CAAC,CAAC,GAAG,OAAO,CAAE,SAAQ,MAAM,CAAC,CAAC,CAAC;IAC7D,QAAQ,CAAC,WAAW,EAAE,IAAI,CAAC;IAE3B;;OAEG;IACH,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC;IAEpD;;;;OAIG;IACH,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAEzC;;;;;OAKG;IACH,OAAO,CACL,GAAG,EAAE,MAAM,EACX,gBAAgB,EAAE,MAAM,EACxB,KAAK,EAAE,CAAC,EACR,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,OAAO,CAAC,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,GAAG,OAAO,EAC1C,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,eAAe,CAAC,CAAC,CAAC,CAU7B"}
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ /* Copyright (C) 2026-present Aristotelis — see repository license. */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.isVersionedCache = isVersionedCache;
5
+ /**
6
+ * Capability guard verifying whether an adapter supports versioned coordination.
7
+ */
8
+ function isVersionedCache(cache) {
9
+ return (typeof cache === 'object' &&
10
+ cache !== null &&
11
+ (('isVersioned' in cache &&
12
+ cache.isVersioned === true) ||
13
+ (typeof cache.readState === 'function' &&
14
+ typeof cache.invalidate === 'function' &&
15
+ typeof cache.tryFill === 'function')));
16
+ }
17
+ //# sourceMappingURL=cache.port.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.port.js","sourceRoot":"","sources":["../../../application/ports/cache.port.ts"],"names":[],"mappings":";AAAA,sEAAsE;;AA2HtE,4CAYC;AAfD;;GAEG;AACH,SAAgB,gBAAgB,CAC9B,KAAc;IAEd,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,CAAC,CAAC,aAAa,IAAI,KAAK;YACrB,KAA4B,CAAC,WAAW,KAAK,IAAI,CAAC;YACnD,CAAC,OAAQ,KAA4B,CAAC,SAAS,KAAK,UAAU;gBAC5D,OAAQ,KAA4B,CAAC,UAAU,KAAK,UAAU;gBAC9D,OAAQ,KAA4B,CAAC,OAAO,KAAK,UAAU,CAAC,CAAC,CAClE,CAAC;AACJ,CAAC"}