@cullet/erp-core 1.2.0 → 1.4.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 (218) hide show
  1. package/KIT_CONTEXT.md +5 -3
  2. package/README.md +160 -0
  3. package/dist/abac/index.cjs +7 -0
  4. package/dist/abac/index.d.cts +2 -0
  5. package/dist/abac/index.d.ts +2 -0
  6. package/dist/abac/index.js +2 -0
  7. package/dist/app-error.cjs +193 -0
  8. package/dist/app-error.cjs.map +1 -0
  9. package/dist/app-error.d.cts +108 -0
  10. package/dist/app-error.js +170 -0
  11. package/dist/app-error.js.map +1 -0
  12. package/dist/application/index.cjs +27 -0
  13. package/dist/application/index.d.cts +3 -0
  14. package/dist/application/index.d.ts +2 -1
  15. package/dist/application/index.js +2 -1
  16. package/dist/authorization-error.cjs +157 -0
  17. package/dist/authorization-error.cjs.map +1 -0
  18. package/dist/authorization-error.d.cts +113 -0
  19. package/dist/authorization-error.d.ts +113 -0
  20. package/dist/authorization-error.js +152 -0
  21. package/dist/authorization-error.js.map +1 -0
  22. package/dist/authorizer.port.d.cts +130 -0
  23. package/dist/authorizer.port.d.ts +130 -0
  24. package/dist/composite-authorizer.d.cts +216 -0
  25. package/dist/composite-authorizer.d.ts +216 -0
  26. package/dist/condition-evaluator.cjs +565 -0
  27. package/dist/condition-evaluator.cjs.map +1 -0
  28. package/dist/condition-evaluator.js +536 -0
  29. package/dist/condition-evaluator.js.map +1 -0
  30. package/dist/core-config.d.cts +172 -0
  31. package/dist/{gate-types.d.ts → core-config.d.ts} +78 -77
  32. package/dist/domain/index.cjs +17 -0
  33. package/dist/domain/index.d.cts +4 -0
  34. package/dist/domain/index.d.ts +2 -1
  35. package/dist/domain/index.js +2 -1
  36. package/dist/domain-event-contracts.cjs +34 -0
  37. package/dist/domain-event-contracts.cjs.map +1 -0
  38. package/dist/domain-event-contracts.d.cts +27 -0
  39. package/dist/domain-event-contracts.js +2 -1
  40. package/dist/domain-event-contracts.js.map +1 -1
  41. package/dist/domain-exception.cjs +17 -0
  42. package/dist/domain-exception.cjs.map +1 -0
  43. package/dist/domain-exception.d.cts +7 -0
  44. package/dist/entity.cjs +126 -0
  45. package/dist/entity.cjs.map +1 -0
  46. package/dist/entity.js +115 -0
  47. package/dist/entity.js.map +1 -0
  48. package/dist/errors/index.cjs +43 -0
  49. package/dist/errors/index.d.cts +4 -0
  50. package/dist/errors/index.d.ts +2 -1
  51. package/dist/errors/index.js +4 -2
  52. package/dist/exceptions/index.cjs +17 -0
  53. package/dist/exceptions/index.d.cts +5 -0
  54. package/dist/exceptions/validation-field.cjs +3 -0
  55. package/dist/exceptions/validation-field.d.cts +2 -0
  56. package/dist/gate-engine-registry.cjs +309 -0
  57. package/dist/gate-engine-registry.cjs.map +1 -0
  58. package/dist/gate-engine-registry.d.cts +82 -0
  59. package/dist/gate-engine-registry.d.ts +3 -2
  60. package/dist/gate-engine-registry.js +2 -1
  61. package/dist/gate-engine-registry.js.map +1 -1
  62. package/dist/gate-v1-payload.schema.cjs +76 -0
  63. package/dist/gate-v1-payload.schema.cjs.map +1 -0
  64. package/dist/gate-v1-payload.schema.js +1 -533
  65. package/dist/gate-v1-payload.schema.js.map +1 -1
  66. package/dist/hashing.cjs +66 -0
  67. package/dist/hashing.cjs.map +1 -0
  68. package/dist/immutable.cjs +77 -0
  69. package/dist/immutable.cjs.map +1 -0
  70. package/dist/immutable.d.cts +6 -0
  71. package/dist/index.cjs +181 -0
  72. package/dist/index.cjs.map +1 -0
  73. package/dist/index.d.cts +37 -0
  74. package/dist/index.d.ts +19 -12
  75. package/dist/index.js +15 -9
  76. package/dist/index.js.map +1 -1
  77. package/dist/invalid-state-transition-exception.cjs +47 -0
  78. package/dist/invalid-state-transition-exception.cjs.map +1 -0
  79. package/dist/invariant-violation-exception.cjs +16 -0
  80. package/dist/invariant-violation-exception.cjs.map +1 -0
  81. package/dist/not-found-error.cjs +65 -0
  82. package/dist/not-found-error.cjs.map +1 -0
  83. package/dist/not-found-error.js +1 -1
  84. package/dist/outcome.cjs +97 -0
  85. package/dist/outcome.cjs.map +1 -0
  86. package/dist/outcome.d.cts +58 -0
  87. package/dist/outcome.d.ts +1 -83
  88. package/dist/parse-gate-payload.d.cts +62 -0
  89. package/dist/parse-gate-payload.d.ts +2 -2
  90. package/dist/path.d.cts +90 -0
  91. package/dist/path.d.ts +2 -2
  92. package/dist/plugin.cjs +79 -0
  93. package/dist/plugin.cjs.map +1 -0
  94. package/dist/plugin.d.cts +85 -0
  95. package/dist/plugins/index.cjs +3 -0
  96. package/dist/plugins/index.d.cts +2 -0
  97. package/dist/policies/engines/index.cjs +10 -0
  98. package/dist/policies/engines/index.d.cts +4 -0
  99. package/dist/policies/engines/index.d.ts +1 -1
  100. package/dist/policies/engines/v1/gate/index.cjs +92 -0
  101. package/dist/policies/engines/v1/gate/index.cjs.map +1 -0
  102. package/dist/policies/engines/v1/gate/index.d.cts +121 -0
  103. package/dist/policies/engines/v1/gate/index.d.ts +2 -2
  104. package/dist/policies/engines/v1/gate/index.js +2 -1
  105. package/dist/policies/engines/v1/gate/index.js.map +1 -1
  106. package/dist/policies/index.cjs +41 -0
  107. package/dist/policies/index.d.cts +8 -0
  108. package/dist/policies/index.d.ts +3 -2
  109. package/dist/policies/index.js +2 -2
  110. package/dist/policy-bridge.cjs +437 -0
  111. package/dist/policy-bridge.cjs.map +1 -0
  112. package/dist/policy-bridge.d.cts +185 -0
  113. package/dist/policy-bridge.d.ts +185 -0
  114. package/dist/policy-bridge.js +396 -0
  115. package/dist/policy-bridge.js.map +1 -0
  116. package/dist/policy-service.cjs +1190 -0
  117. package/dist/policy-service.cjs.map +1 -0
  118. package/dist/policy-service.d.cts +559 -0
  119. package/dist/policy-service.d.ts +2 -2
  120. package/dist/policy-service.js +239 -239
  121. package/dist/policy-service.js.map +1 -1
  122. package/dist/rbac/index.cjs +9 -0
  123. package/dist/rbac/index.d.cts +3 -0
  124. package/dist/rbac/index.d.ts +3 -0
  125. package/dist/rbac/index.js +2 -0
  126. package/dist/requested-by.cjs +54 -0
  127. package/dist/requested-by.cjs.map +1 -0
  128. package/dist/requested-by.d.cts +25 -0
  129. package/dist/requested-by.d.ts +25 -0
  130. package/dist/requested-by.js +49 -0
  131. package/dist/requested-by.js.map +1 -0
  132. package/dist/result/index.cjs +7 -0
  133. package/dist/result/index.d.cts +3 -0
  134. package/dist/result/index.d.ts +2 -1
  135. package/dist/result.cjs +135 -0
  136. package/dist/result.cjs.map +1 -0
  137. package/dist/result.d.cts +84 -0
  138. package/dist/result.d.ts +84 -0
  139. package/dist/rule.cjs +327 -0
  140. package/dist/rule.cjs.map +1 -0
  141. package/dist/rule.js +298 -0
  142. package/dist/rule.js.map +1 -0
  143. package/dist/ruleset-registry.cjs +47 -0
  144. package/dist/ruleset-registry.cjs.map +1 -0
  145. package/dist/rulesets/index.cjs +3 -0
  146. package/dist/rulesets/index.d.cts +2 -0
  147. package/dist/temporal-guards.cjs +32 -0
  148. package/dist/temporal-guards.cjs.map +1 -0
  149. package/dist/temporal-use-case.cjs +139 -0
  150. package/dist/temporal-use-case.cjs.map +1 -0
  151. package/dist/temporal-use-case.d.cts +282 -0
  152. package/dist/temporal-use-case.d.ts +5 -27
  153. package/dist/temporal-use-case.js +2 -48
  154. package/dist/temporal-use-case.js.map +1 -1
  155. package/dist/unexpected-error.cjs +19 -0
  156. package/dist/unexpected-error.cjs.map +1 -0
  157. package/dist/unexpected-error.js +2 -167
  158. package/dist/unexpected-error.js.map +1 -1
  159. package/dist/use-case.cjs +96 -0
  160. package/dist/use-case.cjs.map +1 -0
  161. package/dist/uuid-identifier.cjs +65 -0
  162. package/dist/uuid-identifier.cjs.map +1 -0
  163. package/dist/uuid-identifier.d.cts +147 -0
  164. package/dist/uuid-identifier.d.ts +2 -85
  165. package/dist/validation-code.cjs +60 -0
  166. package/dist/validation-code.cjs.map +1 -0
  167. package/dist/validation-code.d.cts +23 -0
  168. package/dist/validation-error.cjs +887 -0
  169. package/dist/validation-error.cjs.map +1 -0
  170. package/dist/validation-error.d.cts +681 -0
  171. package/dist/validation-error.d.ts +2 -98
  172. package/dist/validation-error.js +7 -134
  173. package/dist/validation-error.js.map +1 -1
  174. package/dist/validation-exception.cjs +41 -0
  175. package/dist/validation-exception.cjs.map +1 -0
  176. package/dist/validation-exception.d.cts +50 -0
  177. package/dist/validation-field.cjs +28 -0
  178. package/dist/validation-field.cjs.map +1 -0
  179. package/dist/validation-field.d.cts +12 -0
  180. package/dist/value-object-ruleset.contracts.d.cts +36 -0
  181. package/dist/value-object.cjs +85 -0
  182. package/dist/value-object.cjs.map +1 -0
  183. package/dist/value-object.d.cts +89 -0
  184. package/dist/value-object.d.ts +89 -0
  185. package/dist/value-object.js +1 -112
  186. package/dist/value-object.js.map +1 -1
  187. package/dist/version.d.cts +10 -0
  188. package/dist/versioning/index.cjs +7 -0
  189. package/dist/versioning/index.d.cts +3 -0
  190. package/meta.json +19 -4
  191. package/package.json +173 -28
  192. package/src/abac/index.ts +1 -0
  193. package/src/core/abac/abac-request.ts +29 -0
  194. package/src/core/abac/attributes.ts +39 -0
  195. package/src/core/abac/authorizer.ts +108 -0
  196. package/src/core/abac/combining.ts +63 -0
  197. package/src/core/abac/composite-authorizer.ts +45 -0
  198. package/src/core/abac/domain/policy-set.ts +52 -0
  199. package/src/core/abac/domain/rule.ts +197 -0
  200. package/src/core/abac/index.ts +21 -0
  201. package/src/core/application/ports/abac-authorizer.port.ts +20 -0
  202. package/src/core/application/ports/authorizer.port.ts +22 -0
  203. package/src/core/errors/authorization-error.ts +26 -0
  204. package/src/core/errors/error-codes.ts +1 -0
  205. package/src/core/index.ts +7 -0
  206. package/src/core/rbac/access-request.ts +32 -0
  207. package/src/core/rbac/authorizer.ts +91 -0
  208. package/src/core/rbac/domain/grant.ts +96 -0
  209. package/src/core/rbac/domain/permission-set.ts +67 -0
  210. package/src/core/rbac/domain/permission.ts +119 -0
  211. package/src/core/rbac/domain/role.ts +101 -0
  212. package/src/core/rbac/domain/scope.ts +84 -0
  213. package/src/core/rbac/index.ts +15 -0
  214. package/src/core/rbac/policy-bridge.ts +44 -0
  215. package/src/examples/application/authorize-cancel-order-abac.example.ts +107 -0
  216. package/src/examples/application/authorize-cancel-order.example.ts +101 -0
  217. package/src/rbac/index.ts +1 -0
  218. package/src/version.ts +1 -1
@@ -0,0 +1,887 @@
1
+ const require_app_error = require("./app-error.cjs");
2
+ //#region src/core/errors/authentication-error.ts
3
+ var AuthenticationError = class AuthenticationError extends require_app_error.AppError {
4
+ constructor(params) {
5
+ super(params.message, params.code, {
6
+ cause: params.cause,
7
+ metadata: {
8
+ reason: params.reason,
9
+ ...params.metadata ?? {}
10
+ },
11
+ type: params.type,
12
+ severity: params.severity,
13
+ correlationId: params.correlationId,
14
+ requestId: params.requestId,
15
+ commandId: params.commandId,
16
+ createdAtIso: params.createdAtIso,
17
+ publicMessage: params.publicMessage
18
+ });
19
+ this.reason = params.reason;
20
+ Object.freeze(this);
21
+ }
22
+ static missingToken(options) {
23
+ return new AuthenticationError({
24
+ message: "Missing credentials",
25
+ code: require_app_error.ErrorCodes.authentication.missingToken,
26
+ reason: "missing_token",
27
+ metadata: compactMetadata$1(options),
28
+ ...extractAppErrorOptions(options)
29
+ });
30
+ }
31
+ static invalidToken(options) {
32
+ return new AuthenticationError({
33
+ message: "Invalid credentials",
34
+ code: require_app_error.ErrorCodes.authentication.invalidToken,
35
+ reason: "invalid_token",
36
+ metadata: compactMetadata$1({
37
+ authScheme: options?.authScheme,
38
+ tokenLocation: options?.tokenLocation,
39
+ details: options?.details,
40
+ correlationId: options?.correlationId,
41
+ requestId: options?.requestId
42
+ }),
43
+ ...extractAppErrorOptions(options)
44
+ });
45
+ }
46
+ static expiredToken(options) {
47
+ return new AuthenticationError({
48
+ message: "Expired credentials",
49
+ code: require_app_error.ErrorCodes.authentication.expiredToken,
50
+ reason: "expired_token",
51
+ metadata: compactMetadata$1(options),
52
+ ...extractAppErrorOptions(options)
53
+ });
54
+ }
55
+ static invalidCredentials(options) {
56
+ return new AuthenticationError({
57
+ message: "Invalid username or password",
58
+ code: require_app_error.ErrorCodes.authentication.invalidCredentials,
59
+ reason: "invalid_credentials",
60
+ metadata: compactMetadata$1(options),
61
+ ...extractAppErrorOptions(options)
62
+ });
63
+ }
64
+ };
65
+ function extractAppErrorOptions(options) {
66
+ return {
67
+ cause: options?.cause,
68
+ type: options?.type,
69
+ severity: options?.severity,
70
+ correlationId: options?.correlationId,
71
+ requestId: options?.requestId,
72
+ commandId: options?.commandId,
73
+ createdAtIso: options?.createdAtIso,
74
+ publicMessage: options?.publicMessage
75
+ };
76
+ }
77
+ function compactMetadata$1(input) {
78
+ if (!input) return void 0;
79
+ return Object.fromEntries(Object.entries(input).filter(([, value]) => value !== void 0));
80
+ }
81
+ //#endregion
82
+ //#region src/core/errors/conflict-error.ts
83
+ /**
84
+ * Base for errors that signal a state conflict — the request collides with data
85
+ * that already exists. Common at an HTTP 409 boundary.
86
+ *
87
+ * The discriminating {@link kind} lets a handler branch on *why* it conflicted
88
+ * (an already-existing record, a domain duplicate, or a raw storage uniqueness
89
+ * breach) without `instanceof` chains. Abstract: construct one of the concrete
90
+ * subclasses through its `detected(...)` factory, which fills in the right code,
91
+ * message, and metadata. Instances are frozen, so a conflict error can be shared
92
+ * and rethrown without risk of tampering.
93
+ */
94
+ var ConflictError = class extends require_app_error.AppError {
95
+ constructor(params) {
96
+ super(params.message, params.code, {
97
+ ...params,
98
+ metadata: {
99
+ kind: params.kind,
100
+ ...params.metadata
101
+ }
102
+ });
103
+ this.kind = params.kind;
104
+ Object.freeze(this);
105
+ }
106
+ };
107
+ /**
108
+ * The operation cannot proceed because a matching record already exists —
109
+ * e.g. creating something whose natural key is already taken. Construct via
110
+ * {@link AlreadyExistsError.detected}.
111
+ */
112
+ var AlreadyExistsError = class AlreadyExistsError extends ConflictError {
113
+ constructor(input) {
114
+ super({
115
+ message: "A matching record already exists for the requested operation",
116
+ code: require_app_error.ErrorCodes.conflict.alreadyExists,
117
+ kind: "already_exists",
118
+ ...input
119
+ });
120
+ }
121
+ /**
122
+ * Builds an {@link AlreadyExistsError} for a detected collision. `operation`
123
+ * defaults to `"create"` and a generic retry `hint` is supplied when none is
124
+ * given, so the error is actionable even from a minimal call site.
125
+ *
126
+ * @param input - The conflicting entity plus optional non-sensitive context
127
+ * (operation, field, existing id, value hash/preview, correlation ids).
128
+ */
129
+ static detected(input) {
130
+ return new AlreadyExistsError({
131
+ metadata: {
132
+ entity: input.entity,
133
+ operation: input.operation ?? "create",
134
+ field: input.field,
135
+ existingId: input.existingId,
136
+ valueHash: input.valueHash,
137
+ valuePreview: input.valuePreview,
138
+ detectedAtIso: input.detectedAtIso,
139
+ correlationId: input.correlationId,
140
+ requestId: input.requestId,
141
+ commandId: input.commandId,
142
+ hint: input.hint ?? "Verify existing records before retrying."
143
+ },
144
+ cause: input.cause
145
+ });
146
+ }
147
+ };
148
+ /**
149
+ * A domain-level duplicate: the data being written would duplicate an existing
150
+ * record under the model's own uniqueness rules. Use this when the duplication
151
+ * is recognized in the domain, as opposed to a raw DB constraint
152
+ * ({@link UniqueConstraintViolationError}). Construct via
153
+ * {@link DuplicateError.detected}.
154
+ */
155
+ var DuplicateError = class DuplicateError extends ConflictError {
156
+ constructor(input) {
157
+ super({
158
+ message: "Conflict: an existing record violates uniqueness",
159
+ code: require_app_error.ErrorCodes.conflict.duplicate,
160
+ kind: "duplicate",
161
+ ...input
162
+ });
163
+ }
164
+ /**
165
+ * Builds a {@link DuplicateError} for a detected duplicate, defaulting to a
166
+ * "adjust the data so it does not duplicate" hint when none is provided.
167
+ *
168
+ * @param input - The conflicting entity plus optional non-sensitive context
169
+ * (field, constraint name, existing id, value hash/preview, correlation ids).
170
+ */
171
+ static detected(input) {
172
+ return new DuplicateError({
173
+ metadata: {
174
+ entity: input.entity,
175
+ operation: input.operation,
176
+ field: input.field,
177
+ constraintName: input.constraintName,
178
+ existingId: input.existingId,
179
+ valueHash: input.valueHash,
180
+ valuePreview: input.valuePreview,
181
+ detectedAtIso: input.detectedAtIso,
182
+ correlationId: input.correlationId,
183
+ requestId: input.requestId,
184
+ commandId: input.commandId,
185
+ hint: input.hint ?? "Adjust the data so it does not duplicate existing records."
186
+ },
187
+ cause: input.cause
188
+ });
189
+ }
190
+ };
191
+ /**
192
+ * A uniqueness breach surfaced by the storage layer itself (a database unique
193
+ * index), carrying the raw {@link UniqueConstraintViolation} (constraint, table,
194
+ * columns). Keep this distinct from {@link DuplicateError}: this one is the
195
+ * infrastructure signal; translate it into a domain duplicate at the boundary
196
+ * with {@link translateUniqueViolationToDuplicate} when the model should own the
197
+ * message. Construct via {@link UniqueConstraintViolationError.detected}.
198
+ */
199
+ var UniqueConstraintViolationError = class UniqueConstraintViolationError extends ConflictError {
200
+ constructor(input) {
201
+ super({
202
+ message: "Uniqueness violation in storage",
203
+ code: require_app_error.ErrorCodes.conflict.uniqueViolation,
204
+ kind: "unique_violation",
205
+ ...input
206
+ });
207
+ }
208
+ /**
209
+ * Builds a {@link UniqueConstraintViolationError} from the constraint details
210
+ * a driver reports, packaging them into a nested `violation` payload.
211
+ *
212
+ * @param input - The entity plus the offending constraint name, table, and
213
+ * columns, and optional correlation ids.
214
+ */
215
+ static detected(input) {
216
+ return new UniqueConstraintViolationError({
217
+ metadata: {
218
+ entity: input.entity,
219
+ operation: input.operation,
220
+ constraintName: input.constraintName,
221
+ detectedAtIso: input.detectedAtIso,
222
+ correlationId: input.correlationId,
223
+ requestId: input.requestId,
224
+ commandId: input.commandId,
225
+ violation: {
226
+ kind: "unique_violation",
227
+ constraintName: input.constraintName,
228
+ table: input.table,
229
+ columns: input.columns
230
+ },
231
+ hint: "Uniqueness conflict detected in the database."
232
+ },
233
+ cause: input.cause
234
+ });
235
+ }
236
+ };
237
+ /**
238
+ * Translates a raw storage {@link UniqueConstraintViolation} into a domain-level
239
+ * {@link DuplicateError}. This is the seam where an infrastructure concern (a DB
240
+ * unique index firing) is re-expressed in the language of the model, so callers
241
+ * upstream catch a `DuplicateError` and never have to know a database was
242
+ * involved.
243
+ *
244
+ * @param input - The entity, the driver-reported `violation`, and optional
245
+ * request context (`ctx`) carrying correlation ids and a clock instant.
246
+ * @returns A {@link DuplicateError} carrying the constraint name as its field hint.
247
+ */
248
+ function translateUniqueViolationToDuplicate(input) {
249
+ return DuplicateError.detected({
250
+ entity: input.entity,
251
+ operation: input.operation,
252
+ field: input.field,
253
+ constraintName: input.violation.constraintName,
254
+ detectedAtIso: input.ctx?.nowIso,
255
+ correlationId: input.ctx?.correlationId,
256
+ requestId: input.ctx?.requestId,
257
+ commandId: input.ctx?.commandId,
258
+ cause: input.cause
259
+ });
260
+ }
261
+ //#endregion
262
+ //#region src/core/errors/idempotency-error.ts
263
+ var IdempotencyError = class extends require_app_error.AppError {
264
+ constructor(input) {
265
+ super(input.message, input.code, {
266
+ cause: input.cause,
267
+ metadata: {
268
+ kind: input.kind,
269
+ ...input.metadata
270
+ }
271
+ });
272
+ this.kind = input.kind;
273
+ Object.freeze(this);
274
+ }
275
+ static keyMissing(input) {
276
+ return IdempotencyKeyMissingError.detected(input);
277
+ }
278
+ static inProgress(input) {
279
+ return IdempotencyInProgressError.detected(input);
280
+ }
281
+ static payloadMismatch(input) {
282
+ return IdempotencyPayloadMismatchError.detected(input);
283
+ }
284
+ static replayNotSupported(input) {
285
+ return IdempotencyReplayNotSupportedError.detected(input);
286
+ }
287
+ };
288
+ var IdempotencyKeyMissingError = class IdempotencyKeyMissingError extends IdempotencyError {
289
+ constructor(input) {
290
+ super({
291
+ message: "Idempotency key/commandId missing for the requested operation",
292
+ code: require_app_error.ErrorCodes.idempotency.keyMissing,
293
+ kind: "key_missing",
294
+ metadata: input.metadata,
295
+ cause: input.cause
296
+ });
297
+ }
298
+ static detected(input) {
299
+ return new IdempotencyKeyMissingError({
300
+ cause: input.cause,
301
+ metadata: {
302
+ operation: input.operation,
303
+ scope: input.scope,
304
+ entity: input.entity,
305
+ correlationId: input.correlationId,
306
+ requestId: input.requestId,
307
+ commandId: input.commandId,
308
+ detectedAtIso: input.detectedAtIso,
309
+ hint: input.hint ?? "Send a commandId/idempotency key to prevent duplicate processing.",
310
+ details: input.details
311
+ }
312
+ });
313
+ }
314
+ };
315
+ var IdempotencyInProgressError = class IdempotencyInProgressError extends IdempotencyError {
316
+ constructor(input) {
317
+ super({
318
+ message: "The same business intent is already being processed",
319
+ code: require_app_error.ErrorCodes.idempotency.inProgress,
320
+ kind: "in_progress",
321
+ metadata: input.metadata,
322
+ cause: input.cause
323
+ });
324
+ }
325
+ static detected(input) {
326
+ const resolved = resolveKeyIdentity(input.key, input.keyHash, input.keyPreview);
327
+ return new IdempotencyInProgressError({
328
+ cause: input.cause,
329
+ metadata: {
330
+ operation: input.operation,
331
+ scope: input.scope,
332
+ entity: input.entity,
333
+ keyHash: resolved.keyHash,
334
+ keyPreview: resolved.keyPreview,
335
+ idempotencyRecordId: input.idempotencyRecordId,
336
+ correlationId: input.correlationId,
337
+ requestId: input.requestId,
338
+ commandId: input.commandId,
339
+ detectedAtIso: input.detectedAtIso,
340
+ hint: input.hint ?? "Wait for completion and retry using the same key.",
341
+ details: input.details
342
+ }
343
+ });
344
+ }
345
+ };
346
+ var IdempotencyPayloadMismatchError = class IdempotencyPayloadMismatchError extends IdempotencyError {
347
+ constructor(input) {
348
+ super({
349
+ message: "The idempotency key was reused with a different payload",
350
+ code: require_app_error.ErrorCodes.idempotency.payloadMismatch,
351
+ kind: "payload_mismatch",
352
+ metadata: input.metadata,
353
+ cause: input.cause
354
+ });
355
+ }
356
+ static detected(input) {
357
+ const resolved = resolveKeyIdentity(input.key, input.keyHash, input.keyPreview);
358
+ return new IdempotencyPayloadMismatchError({
359
+ cause: input.cause,
360
+ metadata: {
361
+ operation: input.operation,
362
+ scope: input.scope,
363
+ entity: input.entity,
364
+ keyHash: resolved.keyHash,
365
+ keyPreview: resolved.keyPreview,
366
+ incomingPayloadHash: input.incomingPayloadHash,
367
+ existingPayloadHash: input.existingPayloadHash,
368
+ idempotencyRecordId: input.idempotencyRecordId,
369
+ correlationId: input.correlationId,
370
+ requestId: input.requestId,
371
+ commandId: input.commandId,
372
+ detectedAtIso: input.detectedAtIso,
373
+ hint: input.hint ?? "Use a new idempotency key for a new intent. The same key should only be reused for retries of the same payload.",
374
+ details: input.details
375
+ }
376
+ });
377
+ }
378
+ };
379
+ var IdempotencyReplayNotSupportedError = class IdempotencyReplayNotSupportedError extends IdempotencyError {
380
+ constructor(input) {
381
+ super({
382
+ message: "Re-execution detected, but replay of the previous result is not implemented",
383
+ code: require_app_error.ErrorCodes.idempotency.replayNotSupported,
384
+ kind: "replay_not_supported",
385
+ metadata: input.metadata,
386
+ cause: input.cause
387
+ });
388
+ }
389
+ static detected(input) {
390
+ const resolved = resolveKeyIdentity(input.key, input.keyHash, input.keyPreview);
391
+ return new IdempotencyReplayNotSupportedError({
392
+ cause: input.cause,
393
+ metadata: {
394
+ operation: input.operation,
395
+ scope: input.scope,
396
+ entity: input.entity,
397
+ keyHash: resolved.keyHash,
398
+ keyPreview: resolved.keyPreview,
399
+ idempotencyRecordId: input.idempotencyRecordId,
400
+ correlationId: input.correlationId,
401
+ requestId: input.requestId,
402
+ commandId: input.commandId,
403
+ detectedAtIso: input.detectedAtIso,
404
+ hint: input.hint ?? "Try again later, or enable result replay for full idempotency.",
405
+ details: input.details
406
+ }
407
+ });
408
+ }
409
+ };
410
+ function resolveKeyIdentity(key, keyHash, keyPreview) {
411
+ return {
412
+ keyHash,
413
+ keyPreview: keyPreview ?? (key ? key.length <= 8 ? key : key.slice(0, 8) : void 0)
414
+ };
415
+ }
416
+ //#endregion
417
+ //#region src/core/errors/integration-error.ts
418
+ /**
419
+ * Raised when a call to an external provider fails — a timeout, an unreachable
420
+ * endpoint, or a malformed response. This is the boundary error that separates
421
+ * "our code is fine, the outside world misbehaved" from internal faults, which
422
+ * matters for retry and alerting decisions.
423
+ *
424
+ * Every instance records the `provider`, the `operation`, and timing
425
+ * (`startedAtIso` / `durationMs`) so failures are correlatable across services
426
+ * and a slow dependency is visible in the metadata. The discriminating
427
+ * {@link reason} lets callers decide whether a failure is worth retrying.
428
+ * Instances are frozen; construct through the static factories.
429
+ */
430
+ var IntegrationError = class IntegrationError extends require_app_error.AppError {
431
+ constructor(params) {
432
+ const { message, code, metadata, ...rest } = params;
433
+ super(message, code, {
434
+ ...rest,
435
+ metadata
436
+ });
437
+ this.reason = params.reason;
438
+ Object.freeze(this);
439
+ }
440
+ /**
441
+ * The provider did not respond within the allotted time. Usually retryable,
442
+ * since a timeout leaves the outcome unknown rather than known-failed.
443
+ */
444
+ static timeout(options) {
445
+ return new IntegrationError({
446
+ message: "Timeout while integrating with external provider",
447
+ code: require_app_error.ErrorCodes.integration.timeout,
448
+ reason: "timeout",
449
+ metadata: buildMetadata({
450
+ reason: "timeout",
451
+ ...options
452
+ }),
453
+ ...pickAppErrorFields(options)
454
+ });
455
+ }
456
+ /**
457
+ * The provider could not be reached at all (connection refused, DNS
458
+ * failure, network partition) — the request never landed.
459
+ */
460
+ static unreachable(options) {
461
+ return new IntegrationError({
462
+ message: "Provider unavailable",
463
+ code: require_app_error.ErrorCodes.integration.unreachable,
464
+ reason: "unreachable",
465
+ metadata: buildMetadata({
466
+ reason: "unreachable",
467
+ ...options
468
+ }),
469
+ ...pickAppErrorFields(options)
470
+ });
471
+ }
472
+ /**
473
+ * The provider answered, but with something the system cannot use — an
474
+ * unexpected status, an unparsable body, or a contract mismatch. Unlike a
475
+ * timeout this is a definite failure, so blind retries rarely help.
476
+ */
477
+ static badResponse(options) {
478
+ return new IntegrationError({
479
+ message: "Unexpected response from provider",
480
+ code: require_app_error.ErrorCodes.integration.badResponse,
481
+ reason: "bad_response",
482
+ metadata: buildMetadata({
483
+ reason: "bad_response",
484
+ ...options
485
+ }),
486
+ ...pickAppErrorFields(options)
487
+ });
488
+ }
489
+ };
490
+ function buildMetadata(input) {
491
+ return compactMetadata({
492
+ reason: input.reason,
493
+ provider: input.provider,
494
+ operation: input.operation,
495
+ startedAtIso: input.startedAtIso,
496
+ durationMs: input.durationMs,
497
+ detectedAtIso: input.detectedAtIso,
498
+ correlationId: input.correlationId,
499
+ requestId: input.requestId,
500
+ commandId: input.commandId,
501
+ details: input.details,
502
+ statusCode: input.statusCode,
503
+ responseCode: input.responseCode
504
+ });
505
+ }
506
+ function pickAppErrorFields(options) {
507
+ return {
508
+ cause: options.cause,
509
+ type: options.type,
510
+ severity: options.severity,
511
+ correlationId: options.correlationId,
512
+ requestId: options.requestId,
513
+ commandId: options.commandId,
514
+ createdAtIso: options.createdAtIso,
515
+ publicMessage: options.publicMessage
516
+ };
517
+ }
518
+ function compactMetadata(input) {
519
+ return Object.fromEntries(Object.entries(input).filter(([, value]) => value !== void 0));
520
+ }
521
+ //#endregion
522
+ //#region src/core/errors/legacy-incompatible-error.ts
523
+ var LegacyIncompatibleError = class extends require_app_error.AppError {
524
+ constructor(message, context, options) {
525
+ const mergedMetadata = options?.metadata ? {
526
+ ...context ?? {},
527
+ ...options.metadata
528
+ } : context;
529
+ super(message, require_app_error.ErrorCodes.legacyIncompatible, {
530
+ ...options,
531
+ metadata: mergedMetadata
532
+ });
533
+ }
534
+ };
535
+ //#endregion
536
+ //#region src/core/errors/serialization-error.ts
537
+ var SerializationError = class extends require_app_error.AppError {
538
+ constructor(input) {
539
+ super(input.message ?? "Serialization failure", input.code, {
540
+ cause: input.cause,
541
+ metadata: {
542
+ direction: input.direction,
543
+ category: input.category,
544
+ ...input.metadata
545
+ },
546
+ type: input.type,
547
+ severity: input.severity,
548
+ correlationId: input.correlationId,
549
+ requestId: input.requestId,
550
+ commandId: input.commandId,
551
+ createdAtIso: input.createdAtIso,
552
+ publicMessage: input.publicMessage
553
+ });
554
+ this.direction = input.direction;
555
+ this.category = input.category;
556
+ this.boundary = input.metadata.boundary;
557
+ this.contract = input.metadata.contract;
558
+ Object.freeze(this);
559
+ }
560
+ };
561
+ var SerializationInError = class SerializationInError extends SerializationError {
562
+ constructor(input) {
563
+ super(input);
564
+ }
565
+ static failure(category, metadata) {
566
+ return new SerializationInError({
567
+ message: SerializationMessages.message("deserialize", category),
568
+ code: SerializationCodes.code("deserialize", category),
569
+ category,
570
+ direction: "deserialize",
571
+ metadata,
572
+ cause: metadata.cause
573
+ });
574
+ }
575
+ };
576
+ var SerializationOutError = class SerializationOutError extends SerializationError {
577
+ constructor(input) {
578
+ super(input);
579
+ }
580
+ static failure(category, metadata) {
581
+ return new SerializationOutError({
582
+ message: SerializationMessages.message("serialize", category),
583
+ code: SerializationCodes.code("serialize", category),
584
+ category,
585
+ direction: "serialize",
586
+ metadata,
587
+ cause: metadata.cause
588
+ });
589
+ }
590
+ };
591
+ var SerializationCodes = class {
592
+ static code(direction, category) {
593
+ return require_app_error.serializationErrorCode(direction, category);
594
+ }
595
+ };
596
+ var SerializationMessages = class {
597
+ static message(direction, category) {
598
+ if (direction === "deserialize") {
599
+ if (category === "invalid_json") return "Invalid payload: malformed JSON";
600
+ if (category === "schema_version_missing") return "Invalid payload: schemaVersion is missing";
601
+ if (category === "schema_version_unsupported") return "Invalid payload: schemaVersion is not supported";
602
+ if (category === "invalid_shape") return "Invalid payload: incompatible shape";
603
+ if (category === "mapping_not_implemented") return "Unsupported payload: mapping not implemented";
604
+ if (category === "contract_mismatch") return "Payload does not match the expected contract";
605
+ return "Failed to parse incoming payload";
606
+ }
607
+ if (category === "stringify_failed") return "Failed to serialize the response";
608
+ if (category === "contract_mismatch") return "Response does not match the expected contract";
609
+ return "Failed to build the response";
610
+ }
611
+ };
612
+ function safePreview(value, limit = 240) {
613
+ try {
614
+ const serialized = typeof value === "string" ? value : JSON.stringify(value);
615
+ return serialized.length > limit ? `${serialized.slice(0, limit)}…` : serialized;
616
+ } catch {
617
+ return;
618
+ }
619
+ }
620
+ //#endregion
621
+ //#region src/core/errors/temporal-error.ts
622
+ var TemporalError = class extends require_app_error.AppError {
623
+ constructor(input) {
624
+ super(input.message, input.code, {
625
+ ...input,
626
+ metadata: {
627
+ kind: input.kind,
628
+ ...input.metadata
629
+ }
630
+ });
631
+ this.kind = input.kind;
632
+ this.resourceType = input.metadata.resourceType;
633
+ this.evaluatedAtIso = input.metadata.evaluatedAtIso;
634
+ Object.freeze(this);
635
+ }
636
+ };
637
+ var ExpiredError = class ExpiredError extends TemporalError {
638
+ constructor(input) {
639
+ super(input);
640
+ }
641
+ static detected(input) {
642
+ return new ExpiredError({
643
+ message: "The validity of the resource/action has expired",
644
+ code: require_app_error.ErrorCodes.temporal.expired,
645
+ kind: "expired",
646
+ metadata: {
647
+ ...input,
648
+ hint: input.hint ?? "The window has expired. Request a new link or try again within the valid period."
649
+ },
650
+ cause: input.cause,
651
+ type: input.type,
652
+ severity: input.severity,
653
+ correlationId: input.correlationId,
654
+ requestId: input.requestId,
655
+ commandId: input.commandId,
656
+ createdAtIso: input.createdAtIso,
657
+ publicMessage: input.publicMessage
658
+ });
659
+ }
660
+ };
661
+ var NotYetValidError = class NotYetValidError extends TemporalError {
662
+ constructor(input) {
663
+ super(input);
664
+ }
665
+ static detected(input) {
666
+ return new NotYetValidError({
667
+ message: "The resource/action is not yet valid",
668
+ code: require_app_error.ErrorCodes.temporal.notYetValid,
669
+ kind: "not_yet_valid",
670
+ metadata: {
671
+ ...input,
672
+ hint: input.hint ?? "Not yet within the valid period. Try again later."
673
+ },
674
+ cause: input.cause,
675
+ type: input.type,
676
+ severity: input.severity,
677
+ correlationId: input.correlationId,
678
+ requestId: input.requestId,
679
+ commandId: input.commandId,
680
+ createdAtIso: input.createdAtIso,
681
+ publicMessage: input.publicMessage
682
+ });
683
+ }
684
+ };
685
+ function evaluateTemporalWindow(input) {
686
+ const evaluatedMs = Date.parse(input.evaluatedAtIso);
687
+ if (Number.isNaN(evaluatedMs)) return null;
688
+ let notYetValid = false;
689
+ if (input.validFromIso) {
690
+ const fromMs = Date.parse(input.validFromIso);
691
+ if (!Number.isNaN(fromMs) && evaluatedMs < fromMs) notYetValid = true;
692
+ }
693
+ if (input.validUntilIso) {
694
+ const untilMs = Date.parse(input.validUntilIso);
695
+ if (!Number.isNaN(untilMs) && evaluatedMs > untilMs) return {
696
+ expired: true,
697
+ notYetValid: false
698
+ };
699
+ }
700
+ return {
701
+ expired: false,
702
+ notYetValid
703
+ };
704
+ }
705
+ //#endregion
706
+ //#region src/core/errors/validation-error.ts
707
+ /**
708
+ * Raised when a single input fails a validation rule — the canonical
709
+ * "this field is wrong, and here is why" error.
710
+ *
711
+ * It pins the offending `field` and a machine-readable `validationCode` into
712
+ * the metadata (merged ahead of any caller-supplied metadata) so an API layer
713
+ * can map the failure straight onto a form field without parsing the message.
714
+ * The fixed {@link ErrorCodes.validation} code lets callers catch all
715
+ * validation failures uniformly while still distinguishing the specific rule
716
+ * through `validationCode`.
717
+ */
718
+ var ValidationError = class extends require_app_error.AppError {
719
+ /**
720
+ * @param field - The input that failed validation; surfaced as `metadata.field`.
721
+ * @param code - The specific rule that was violated; surfaced as `metadata.validationCode`.
722
+ * @param message - The developer-facing description of the failure.
723
+ * @param options - Optional cause, correlation ids, and extra metadata
724
+ * (merged over the field/code metadata, never overwriting it by accident).
725
+ */
726
+ constructor(field, code, message, options) {
727
+ const baseMetadata = {
728
+ field: field.value,
729
+ validationCode: code.value
730
+ };
731
+ const mergedMetadata = options?.metadata ? {
732
+ ...baseMetadata,
733
+ ...options.metadata
734
+ } : baseMetadata;
735
+ super(message, require_app_error.ErrorCodes.validation, {
736
+ ...options,
737
+ metadata: mergedMetadata
738
+ });
739
+ }
740
+ };
741
+ //#endregion
742
+ Object.defineProperty(exports, "AlreadyExistsError", {
743
+ enumerable: true,
744
+ get: function() {
745
+ return AlreadyExistsError;
746
+ }
747
+ });
748
+ Object.defineProperty(exports, "AuthenticationError", {
749
+ enumerable: true,
750
+ get: function() {
751
+ return AuthenticationError;
752
+ }
753
+ });
754
+ Object.defineProperty(exports, "ConflictError", {
755
+ enumerable: true,
756
+ get: function() {
757
+ return ConflictError;
758
+ }
759
+ });
760
+ Object.defineProperty(exports, "DuplicateError", {
761
+ enumerable: true,
762
+ get: function() {
763
+ return DuplicateError;
764
+ }
765
+ });
766
+ Object.defineProperty(exports, "ExpiredError", {
767
+ enumerable: true,
768
+ get: function() {
769
+ return ExpiredError;
770
+ }
771
+ });
772
+ Object.defineProperty(exports, "IdempotencyError", {
773
+ enumerable: true,
774
+ get: function() {
775
+ return IdempotencyError;
776
+ }
777
+ });
778
+ Object.defineProperty(exports, "IdempotencyInProgressError", {
779
+ enumerable: true,
780
+ get: function() {
781
+ return IdempotencyInProgressError;
782
+ }
783
+ });
784
+ Object.defineProperty(exports, "IdempotencyKeyMissingError", {
785
+ enumerable: true,
786
+ get: function() {
787
+ return IdempotencyKeyMissingError;
788
+ }
789
+ });
790
+ Object.defineProperty(exports, "IdempotencyPayloadMismatchError", {
791
+ enumerable: true,
792
+ get: function() {
793
+ return IdempotencyPayloadMismatchError;
794
+ }
795
+ });
796
+ Object.defineProperty(exports, "IdempotencyReplayNotSupportedError", {
797
+ enumerable: true,
798
+ get: function() {
799
+ return IdempotencyReplayNotSupportedError;
800
+ }
801
+ });
802
+ Object.defineProperty(exports, "IntegrationError", {
803
+ enumerable: true,
804
+ get: function() {
805
+ return IntegrationError;
806
+ }
807
+ });
808
+ Object.defineProperty(exports, "LegacyIncompatibleError", {
809
+ enumerable: true,
810
+ get: function() {
811
+ return LegacyIncompatibleError;
812
+ }
813
+ });
814
+ Object.defineProperty(exports, "NotYetValidError", {
815
+ enumerable: true,
816
+ get: function() {
817
+ return NotYetValidError;
818
+ }
819
+ });
820
+ Object.defineProperty(exports, "SerializationCodes", {
821
+ enumerable: true,
822
+ get: function() {
823
+ return SerializationCodes;
824
+ }
825
+ });
826
+ Object.defineProperty(exports, "SerializationError", {
827
+ enumerable: true,
828
+ get: function() {
829
+ return SerializationError;
830
+ }
831
+ });
832
+ Object.defineProperty(exports, "SerializationInError", {
833
+ enumerable: true,
834
+ get: function() {
835
+ return SerializationInError;
836
+ }
837
+ });
838
+ Object.defineProperty(exports, "SerializationMessages", {
839
+ enumerable: true,
840
+ get: function() {
841
+ return SerializationMessages;
842
+ }
843
+ });
844
+ Object.defineProperty(exports, "SerializationOutError", {
845
+ enumerable: true,
846
+ get: function() {
847
+ return SerializationOutError;
848
+ }
849
+ });
850
+ Object.defineProperty(exports, "TemporalError", {
851
+ enumerable: true,
852
+ get: function() {
853
+ return TemporalError;
854
+ }
855
+ });
856
+ Object.defineProperty(exports, "UniqueConstraintViolationError", {
857
+ enumerable: true,
858
+ get: function() {
859
+ return UniqueConstraintViolationError;
860
+ }
861
+ });
862
+ Object.defineProperty(exports, "ValidationError", {
863
+ enumerable: true,
864
+ get: function() {
865
+ return ValidationError;
866
+ }
867
+ });
868
+ Object.defineProperty(exports, "evaluateTemporalWindow", {
869
+ enumerable: true,
870
+ get: function() {
871
+ return evaluateTemporalWindow;
872
+ }
873
+ });
874
+ Object.defineProperty(exports, "safePreview", {
875
+ enumerable: true,
876
+ get: function() {
877
+ return safePreview;
878
+ }
879
+ });
880
+ Object.defineProperty(exports, "translateUniqueViolationToDuplicate", {
881
+ enumerable: true,
882
+ get: function() {
883
+ return translateUniqueViolationToDuplicate;
884
+ }
885
+ });
886
+
887
+ //# sourceMappingURL=validation-error.cjs.map