@cullet/erp-core 1.0.10 → 1.0.11

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.
@@ -80,6 +80,19 @@ function compactMetadata$1(input) {
80
80
  }
81
81
  //#endregion
82
82
  //#region src/core/errors/authorization-error.ts
83
+ /**
84
+ * Raised when an authenticated actor is not allowed to perform a business
85
+ * action — the "you may not" error, distinct from authentication ("who are
86
+ * you"). Maps to an HTTP 403 at the edge.
87
+ *
88
+ * The discriminating {@link reason} records *why* access was denied (a flat
89
+ * forbid, a missing role/capability, an out-of-scope target, or a policy
90
+ * decision) so the boundary can shape the response without re-deriving it. The
91
+ * metadata is deliberately built around a stable business `action` and a
92
+ * type/id resource reference rather than an HTTP route or full payload, keeping
93
+ * sensitive data out of logs. Instances are frozen. Construct through the
94
+ * static factories, never directly.
95
+ */
83
96
  var AuthorizationError = class AuthorizationError extends AppError {
84
97
  constructor(params) {
85
98
  super(params.message, params.code, {
@@ -96,6 +109,12 @@ var AuthorizationError = class AuthorizationError extends AppError {
96
109
  this.reason = params.reason;
97
110
  Object.freeze(this);
98
111
  }
112
+ /**
113
+ * A flat denial with no more specific reason — the actor simply may not
114
+ * perform this action. Reach for a more precise factory
115
+ * ({@link AuthorizationError.missingCapability}, {@link AuthorizationError.outOfScope},
116
+ * {@link AuthorizationError.policyDenied}) when the cause is known.
117
+ */
99
118
  static forbidden(input) {
100
119
  return new AuthorizationError({
101
120
  message: "Action not allowed",
@@ -108,6 +127,15 @@ var AuthorizationError = class AuthorizationError extends AppError {
108
127
  ...extractAppErrorOptions(input)
109
128
  });
110
129
  }
130
+ /**
131
+ * The action was denied by an evaluated policy. Captures the deciding
132
+ * policy's id, version, and evaluation instant into the metadata (with
133
+ * `decision: "deny"`) so the denial is auditable back to the exact policy
134
+ * that produced it.
135
+ *
136
+ * @param input - Factory options plus the required `policyId`,
137
+ * `policyVersion`, and `evaluatedAtIso` of the deciding policy.
138
+ */
111
139
  static policyDenied(input) {
112
140
  return new AuthorizationError({
113
141
  message: "Action denied by policy",
@@ -121,6 +149,13 @@ var AuthorizationError = class AuthorizationError extends AppError {
121
149
  ...extractAppErrorOptions(input)
122
150
  });
123
151
  }
152
+ /**
153
+ * The actor lacks a required role or capability. The expected
154
+ * {@link AuthorizationRequirement} is recorded so the boundary can tell the
155
+ * caller precisely what grant is missing.
156
+ *
157
+ * @param input - Factory options plus the `required` role/capability/scope.
158
+ */
124
159
  static missingCapability(input) {
125
160
  return new AuthorizationError({
126
161
  message: "Insufficient capability to perform the action",
@@ -133,6 +168,14 @@ var AuthorizationError = class AuthorizationError extends AppError {
133
168
  ...extractAppErrorOptions(input)
134
169
  });
135
170
  }
171
+ /**
172
+ * The actor may perform the action in general, but not on *this* target —
173
+ * the resource falls outside the actor's permitted scope (e.g. a different
174
+ * school or tenant than the one they are bound to).
175
+ *
176
+ * @param input - Factory options plus the optional `required` scope that the
177
+ * target failed to satisfy.
178
+ */
136
179
  static outOfScope(input) {
137
180
  return new AuthorizationError({
138
181
  message: "Action outside the allowed scope",
@@ -182,6 +225,17 @@ var BusinessRuleViolationError = class extends AppError {
182
225
  };
183
226
  //#endregion
184
227
  //#region src/core/errors/conflict-error.ts
228
+ /**
229
+ * Base for errors that signal a state conflict — the request collides with data
230
+ * that already exists. Common at an HTTP 409 boundary.
231
+ *
232
+ * The discriminating {@link kind} lets a handler branch on *why* it conflicted
233
+ * (an already-existing record, a domain duplicate, or a raw storage uniqueness
234
+ * breach) without `instanceof` chains. Abstract: construct one of the concrete
235
+ * subclasses through its `detected(...)` factory, which fills in the right code,
236
+ * message, and metadata. Instances are frozen, so a conflict error can be shared
237
+ * and rethrown without risk of tampering.
238
+ */
185
239
  var ConflictError = class extends AppError {
186
240
  constructor(params) {
187
241
  super(params.message, params.code, {
@@ -195,6 +249,11 @@ var ConflictError = class extends AppError {
195
249
  Object.freeze(this);
196
250
  }
197
251
  };
252
+ /**
253
+ * The operation cannot proceed because a matching record already exists —
254
+ * e.g. creating something whose natural key is already taken. Construct via
255
+ * {@link AlreadyExistsError.detected}.
256
+ */
198
257
  var AlreadyExistsError = class AlreadyExistsError extends ConflictError {
199
258
  constructor(input) {
200
259
  super({
@@ -204,6 +263,14 @@ var AlreadyExistsError = class AlreadyExistsError extends ConflictError {
204
263
  ...input
205
264
  });
206
265
  }
266
+ /**
267
+ * Builds an {@link AlreadyExistsError} for a detected collision. `operation`
268
+ * defaults to `"create"` and a generic retry `hint` is supplied when none is
269
+ * given, so the error is actionable even from a minimal call site.
270
+ *
271
+ * @param input - The conflicting entity plus optional non-sensitive context
272
+ * (operation, field, existing id, value hash/preview, correlation ids).
273
+ */
207
274
  static detected(input) {
208
275
  return new AlreadyExistsError({
209
276
  metadata: {
@@ -223,6 +290,13 @@ var AlreadyExistsError = class AlreadyExistsError extends ConflictError {
223
290
  });
224
291
  }
225
292
  };
293
+ /**
294
+ * A domain-level duplicate: the data being written would duplicate an existing
295
+ * record under the model's own uniqueness rules. Use this when the duplication
296
+ * is recognized in the domain, as opposed to a raw DB constraint
297
+ * ({@link UniqueConstraintViolationError}). Construct via
298
+ * {@link DuplicateError.detected}.
299
+ */
226
300
  var DuplicateError = class DuplicateError extends ConflictError {
227
301
  constructor(input) {
228
302
  super({
@@ -232,6 +306,13 @@ var DuplicateError = class DuplicateError extends ConflictError {
232
306
  ...input
233
307
  });
234
308
  }
309
+ /**
310
+ * Builds a {@link DuplicateError} for a detected duplicate, defaulting to a
311
+ * "adjust the data so it does not duplicate" hint when none is provided.
312
+ *
313
+ * @param input - The conflicting entity plus optional non-sensitive context
314
+ * (field, constraint name, existing id, value hash/preview, correlation ids).
315
+ */
235
316
  static detected(input) {
236
317
  return new DuplicateError({
237
318
  metadata: {
@@ -252,6 +333,14 @@ var DuplicateError = class DuplicateError extends ConflictError {
252
333
  });
253
334
  }
254
335
  };
336
+ /**
337
+ * A uniqueness breach surfaced by the storage layer itself (a database unique
338
+ * index), carrying the raw {@link UniqueConstraintViolation} (constraint, table,
339
+ * columns). Keep this distinct from {@link DuplicateError}: this one is the
340
+ * infrastructure signal; translate it into a domain duplicate at the boundary
341
+ * with {@link translateUniqueViolationToDuplicate} when the model should own the
342
+ * message. Construct via {@link UniqueConstraintViolationError.detected}.
343
+ */
255
344
  var UniqueConstraintViolationError = class UniqueConstraintViolationError extends ConflictError {
256
345
  constructor(input) {
257
346
  super({
@@ -261,6 +350,13 @@ var UniqueConstraintViolationError = class UniqueConstraintViolationError extend
261
350
  ...input
262
351
  });
263
352
  }
353
+ /**
354
+ * Builds a {@link UniqueConstraintViolationError} from the constraint details
355
+ * a driver reports, packaging them into a nested `violation` payload.
356
+ *
357
+ * @param input - The entity plus the offending constraint name, table, and
358
+ * columns, and optional correlation ids.
359
+ */
264
360
  static detected(input) {
265
361
  return new UniqueConstraintViolationError({
266
362
  metadata: {
@@ -283,6 +379,17 @@ var UniqueConstraintViolationError = class UniqueConstraintViolationError extend
283
379
  });
284
380
  }
285
381
  };
382
+ /**
383
+ * Translates a raw storage {@link UniqueConstraintViolation} into a domain-level
384
+ * {@link DuplicateError}. This is the seam where an infrastructure concern (a DB
385
+ * unique index firing) is re-expressed in the language of the model, so callers
386
+ * upstream catch a `DuplicateError` and never have to know a database was
387
+ * involved.
388
+ *
389
+ * @param input - The entity, the driver-reported `violation`, and optional
390
+ * request context (`ctx`) carrying correlation ids and a clock instant.
391
+ * @returns A {@link DuplicateError} carrying the constraint name as its field hint.
392
+ */
286
393
  function translateUniqueViolationToDuplicate(input) {
287
394
  return DuplicateError.detected({
288
395
  entity: input.entity,
@@ -453,6 +560,18 @@ function resolveKeyIdentity(key, keyHash, keyPreview) {
453
560
  }
454
561
  //#endregion
455
562
  //#region src/core/errors/integration-error.ts
563
+ /**
564
+ * Raised when a call to an external provider fails — a timeout, an unreachable
565
+ * endpoint, or a malformed response. This is the boundary error that separates
566
+ * "our code is fine, the outside world misbehaved" from internal faults, which
567
+ * matters for retry and alerting decisions.
568
+ *
569
+ * Every instance records the `provider`, the `operation`, and timing
570
+ * (`startedAtIso` / `durationMs`) so failures are correlatable across services
571
+ * and a slow dependency is visible in the metadata. The discriminating
572
+ * {@link reason} lets callers decide whether a failure is worth retrying.
573
+ * Instances are frozen; construct through the static factories.
574
+ */
456
575
  var IntegrationError = class IntegrationError extends AppError {
457
576
  constructor(params) {
458
577
  const { message, code, metadata, ...rest } = params;
@@ -463,6 +582,10 @@ var IntegrationError = class IntegrationError extends AppError {
463
582
  this.reason = params.reason;
464
583
  Object.freeze(this);
465
584
  }
585
+ /**
586
+ * The provider did not respond within the allotted time. Usually retryable,
587
+ * since a timeout leaves the outcome unknown rather than known-failed.
588
+ */
466
589
  static timeout(options) {
467
590
  return new IntegrationError({
468
591
  message: "Timeout while integrating with external provider",
@@ -475,6 +598,10 @@ var IntegrationError = class IntegrationError extends AppError {
475
598
  ...pickAppErrorFields(options)
476
599
  });
477
600
  }
601
+ /**
602
+ * The provider could not be reached at all (connection refused, DNS
603
+ * failure, network partition) — the request never landed.
604
+ */
478
605
  static unreachable(options) {
479
606
  return new IntegrationError({
480
607
  message: "Provider unavailable",
@@ -487,6 +614,11 @@ var IntegrationError = class IntegrationError extends AppError {
487
614
  ...pickAppErrorFields(options)
488
615
  });
489
616
  }
617
+ /**
618
+ * The provider answered, but with something the system cannot use — an
619
+ * unexpected status, an unparsable body, or a contract mismatch. Unlike a
620
+ * timeout this is a definite failure, so blind retries rarely help.
621
+ */
490
622
  static badResponse(options) {
491
623
  return new IntegrationError({
492
624
  message: "Unexpected response from provider",
@@ -547,7 +679,21 @@ var LegacyIncompatibleError = class extends AppError {
547
679
  };
548
680
  //#endregion
549
681
  //#region src/core/errors/not-found-error.ts
682
+ /**
683
+ * Raised when a requested resource does not exist. Maps naturally onto an HTTP
684
+ * 404 at the edge, but stays transport-agnostic here.
685
+ *
686
+ * The `resource` name builds the message (`"<resource> not found"`) and, with
687
+ * the optional lookup `criteria`, lands in the metadata so logs show *what* was
688
+ * searched for without the caller having to restate it in the message.
689
+ */
550
690
  var NotFoundError = class extends AppError {
691
+ /**
692
+ * @param resource - Human-readable name of the missing resource (e.g. `"Order"`).
693
+ * @param criteria - Optional lookup keys used in the search; recorded in
694
+ * metadata to aid debugging. Avoid putting sensitive values here.
695
+ * @param options - Optional cause, correlation ids, and extra metadata.
696
+ */
551
697
  constructor(resource, criteria, options) {
552
698
  const baseMetadata = criteria ? {
553
699
  resource,
@@ -735,7 +881,25 @@ function evaluateTemporalWindow(input) {
735
881
  }
736
882
  //#endregion
737
883
  //#region src/core/errors/validation-error.ts
884
+ /**
885
+ * Raised when a single input fails a validation rule — the canonical
886
+ * "this field is wrong, and here is why" error.
887
+ *
888
+ * It pins the offending `field` and a machine-readable `validationCode` into
889
+ * the metadata (merged ahead of any caller-supplied metadata) so an API layer
890
+ * can map the failure straight onto a form field without parsing the message.
891
+ * The fixed {@link ErrorCodes.validation} code lets callers catch all
892
+ * validation failures uniformly while still distinguishing the specific rule
893
+ * through `validationCode`.
894
+ */
738
895
  var ValidationError = class extends AppError {
896
+ /**
897
+ * @param field - The input that failed validation; surfaced as `metadata.field`.
898
+ * @param code - The specific rule that was violated; surfaced as `metadata.validationCode`.
899
+ * @param message - The developer-facing description of the failure.
900
+ * @param options - Optional cause, correlation ids, and extra metadata
901
+ * (merged over the field/code metadata, never overwriting it by accident).
902
+ */
739
903
  constructor(field, code, message, options) {
740
904
  const baseMetadata = {
741
905
  field: field.value,