@cullet/erp-core 1.0.9 → 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.
@@ -1 +1 @@
1
- {"version":3,"file":"validation-error.js","names":["compactMetadata","extractAppErrorOptions"],"sources":["../src/core/errors/authentication-error.ts","../src/core/errors/authorization-error.ts","../src/core/errors/business-rule-violation-error.ts","../src/core/errors/conflict-error.ts","../src/core/errors/idempotency-error.ts","../src/core/errors/integration-error.ts","../src/core/errors/legacy-incompatible-error.ts","../src/core/errors/not-found-error.ts","../src/core/errors/serialization-error.ts","../src/core/errors/temporal-error.ts","../src/core/errors/validation-error.ts"],"sourcesContent":["import { AppError } from \"./app-error.js\";\nimport { ErrorCodes } from \"./error-codes.js\";\nimport type { AppErrorOptions, ErrorSeverity } from \"./types.js\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\ntype AuthenticationErrorReason =\n | \"missing_token\"\n | \"malformed_token\"\n | \"invalid_token\"\n | \"expired_token\"\n | \"revoked_token\"\n | \"invalid_credentials\"\n | \"session_not_found\"\n | \"session_expired\"\n | \"unknown\";\n\ntype AuthenticationErrorMetadata = {\n reason: AuthenticationErrorReason;\n authScheme?: \"bearer\" | \"cookie\" | \"basic\" | \"unknown\";\n tokenLocation?: \"header\" | \"cookie\" | \"query\" | \"unknown\";\n expiresAtIso?: string;\n correlationId?: string;\n requestId?: string;\n details?: string;\n};\n\ntype AuthenticationErrorFactoryOptions = Omit<\n AuthenticationErrorMetadata,\n \"reason\"\n> &\n Omit<AppErrorOptions, \"metadata\">;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// AuthenticationError\n// ─────────────────────────────────────────────────────────────────────────────\n\nclass AuthenticationError extends AppError {\n public readonly reason: AuthenticationErrorReason;\n\n private constructor(params: {\n message: string;\n code: string;\n reason: AuthenticationErrorReason;\n metadata?: Omit<AuthenticationErrorMetadata, \"reason\">;\n cause?: unknown;\n type?: string;\n severity?: ErrorSeverity;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n createdAtIso?: string;\n publicMessage?: string;\n }) {\n super(params.message, params.code, {\n cause: params.cause,\n metadata: {\n reason: params.reason,\n ...(params.metadata ?? {}),\n },\n type: params.type,\n severity: params.severity,\n correlationId: params.correlationId,\n requestId: params.requestId,\n commandId: params.commandId,\n createdAtIso: params.createdAtIso,\n publicMessage: params.publicMessage,\n });\n\n this.reason = params.reason;\n Object.freeze(this);\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Factory methods\n // ─────────────────────────────────────────────────────────────────────────\n\n static missingToken(\n options?: AuthenticationErrorFactoryOptions,\n ): AuthenticationError {\n return new AuthenticationError({\n message: \"Missing credentials\",\n code: ErrorCodes.authentication.missingToken,\n reason: \"missing_token\",\n metadata: compactMetadata(options),\n ...extractAppErrorOptions(options),\n });\n }\n\n static invalidToken(\n options?: AuthenticationErrorFactoryOptions & { cause?: unknown },\n ): AuthenticationError {\n return new AuthenticationError({\n message: \"Invalid credentials\",\n code: ErrorCodes.authentication.invalidToken,\n reason: \"invalid_token\",\n metadata: compactMetadata({\n authScheme: options?.authScheme,\n tokenLocation: options?.tokenLocation,\n details: options?.details,\n correlationId: options?.correlationId,\n requestId: options?.requestId,\n }),\n ...extractAppErrorOptions(options),\n });\n }\n\n static expiredToken(\n options?: AuthenticationErrorFactoryOptions & { sessionId?: string },\n ): AuthenticationError {\n return new AuthenticationError({\n message: \"Expired credentials\",\n code: ErrorCodes.authentication.expiredToken,\n reason: \"expired_token\",\n metadata: compactMetadata(options),\n ...extractAppErrorOptions(options),\n });\n }\n\n static invalidCredentials(\n options?: Pick<\n AuthenticationErrorFactoryOptions,\n | \"correlationId\"\n | \"requestId\"\n | \"type\"\n | \"severity\"\n | \"createdAtIso\"\n | \"publicMessage\"\n >,\n ): AuthenticationError {\n return new AuthenticationError({\n message: \"Invalid username or password\",\n code: ErrorCodes.authentication.invalidCredentials,\n reason: \"invalid_credentials\",\n metadata: compactMetadata(options),\n ...extractAppErrorOptions(options),\n });\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction extractAppErrorOptions(options?: Partial<AppErrorOptions>) {\n return {\n cause: options?.cause,\n type: options?.type,\n severity: options?.severity,\n correlationId: options?.correlationId,\n requestId: options?.requestId,\n commandId: options?.commandId,\n createdAtIso: options?.createdAtIso,\n publicMessage: options?.publicMessage,\n };\n}\n\nfunction compactMetadata<T extends Record<string, unknown>>(\n input?: T,\n): T | undefined {\n if (!input) return undefined;\n\n return Object.fromEntries(\n Object.entries(input).filter(([, value]) => value !== undefined),\n ) as T;\n}\n\nexport { AuthenticationError };\nexport type { AuthenticationErrorMetadata, AuthenticationErrorReason };\n","import { AppError } from \"./app-error.js\";\nimport { ErrorCodes } from \"./error-codes.js\";\nimport type { AppErrorOptions, ErrorSeverity } from \"./types.js\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\ntype AuthorizationErrorReason =\n | \"forbidden\"\n | \"missing_role\"\n | \"missing_capability\"\n | \"out_of_scope\"\n | \"outside_time_window\"\n | \"policy_denied\"\n | \"unknown\";\n\ntype AuthorizationRequirement = {\n role?: string;\n capability?: string;\n scope?: string; // e.g.: \"school:{id}\" or \"class:{id}\"\n};\n\ntype AuthorizationErrorMetadata = {\n reason: AuthorizationErrorReason;\n\n /** Stable action you evaluated (not an HTTP route — a \"business action\") */\n action: string;\n\n /** Resource identification (without leaking the full payload) */\n resource?: { type: string; id?: string };\n\n /** Optional: actor (do not include sensitive data) */\n actor?: { userId: string; role?: string };\n\n /** Optional: expected requirement */\n required?: AuthorizationRequirement;\n\n /** Optional: policy (when you already have PolicyEvaluation or similar) */\n policyId?: string;\n policyVersion?: number;\n evaluatedAtIso?: string;\n decision?: \"allow\" | \"deny\";\n reasonCode?: string;\n\n /** Optional: additional non-sensitive info */\n details?: string;\n};\n\n/**\n * Options for AuthorizationError factory methods.\n * Combines metadata fields (except 'reason') with common AppError options.\n */\ntype AuthorizationErrorFactoryOptions = Omit<\n AuthorizationErrorMetadata,\n \"reason\"\n> &\n Omit<AppErrorOptions, \"metadata\">;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// AuthorizationError\n// ─────────────────────────────────────────────────────────────────────────────\n\nclass AuthorizationError extends AppError {\n public readonly reason: AuthorizationErrorReason;\n\n private constructor(params: {\n message: string;\n code: string;\n reason: AuthorizationErrorReason;\n metadata: AuthorizationErrorMetadata;\n cause?: unknown;\n type?: string;\n severity?: ErrorSeverity;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n createdAtIso?: string;\n publicMessage?: string;\n }) {\n super(params.message, params.code, {\n cause: params.cause,\n metadata: params.metadata,\n type: params.type,\n severity: params.severity,\n correlationId: params.correlationId,\n requestId: params.requestId,\n commandId: params.commandId,\n createdAtIso: params.createdAtIso,\n publicMessage: params.publicMessage,\n });\n\n this.reason = params.reason;\n Object.freeze(this);\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Factories\n // ─────────────────────────────────────────────────────────────────────────\n\n static forbidden(\n input: AuthorizationErrorFactoryOptions,\n ): AuthorizationError {\n return new AuthorizationError({\n message: \"Action not allowed\",\n code: ErrorCodes.authorization.forbidden,\n reason: \"forbidden\",\n metadata: { reason: \"forbidden\", ...extractMetadataOnly(input) },\n ...extractAppErrorOptions(input),\n });\n }\n\n static policyDenied(\n input: AuthorizationErrorFactoryOptions & {\n policyId: string;\n policyVersion: number;\n evaluatedAtIso: string;\n },\n ): AuthorizationError {\n return new AuthorizationError({\n message: \"Action denied by policy\",\n code: ErrorCodes.authorization.policyDenied,\n reason: \"policy_denied\",\n metadata: {\n reason: \"policy_denied\",\n ...extractMetadataOnly(input),\n decision: \"deny\",\n },\n ...extractAppErrorOptions(input),\n });\n }\n\n static missingCapability(\n input: AuthorizationErrorFactoryOptions & {\n required: AuthorizationRequirement;\n },\n ): AuthorizationError {\n return new AuthorizationError({\n message: \"Insufficient capability to perform the action\",\n code: ErrorCodes.authorization.missingCapability,\n reason: \"missing_capability\",\n metadata: {\n reason: \"missing_capability\",\n ...extractMetadataOnly(input),\n },\n ...extractAppErrorOptions(input),\n });\n }\n\n static outOfScope(\n input: AuthorizationErrorFactoryOptions & {\n required?: AuthorizationRequirement;\n },\n ): AuthorizationError {\n return new AuthorizationError({\n message: \"Action outside the allowed scope\",\n code: ErrorCodes.authorization.outOfScope,\n reason: \"out_of_scope\",\n metadata: { reason: \"out_of_scope\", ...extractMetadataOnly(input) },\n ...extractAppErrorOptions(input),\n });\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction extractAppErrorOptions(options?: Partial<AppErrorOptions>) {\n return {\n cause: options?.cause,\n type: options?.type,\n severity: options?.severity,\n correlationId: options?.correlationId,\n requestId: options?.requestId,\n commandId: options?.commandId,\n createdAtIso: options?.createdAtIso,\n publicMessage: options?.publicMessage,\n };\n}\n\nfunction extractMetadataOnly(\n input: AuthorizationErrorFactoryOptions,\n): Omit<AuthorizationErrorMetadata, \"reason\"> {\n const {\n cause,\n type,\n severity,\n correlationId,\n requestId,\n commandId,\n createdAtIso,\n publicMessage,\n ...metadata\n } = input;\n return metadata;\n}\n\nexport { AuthorizationError };\nexport type {\n AuthorizationErrorMetadata,\n AuthorizationErrorReason,\n AuthorizationRequirement,\n};\n","import { AppError } from \"./app-error.js\";\nimport { ErrorCodes } from \"./error-codes.js\";\nimport type { AppErrorOptions } from \"./types.js\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// BusinessRuleViolationError\n// ─────────────────────────────────────────────────────────────────────────────\n\nclass BusinessRuleViolationError extends AppError {\n constructor(\n rule: string,\n message: string,\n detail?: Record<string, unknown>,\n options?: AppErrorOptions,\n ) {\n const baseMetadata = detail ? { rule, detail } : { rule };\n const mergedMetadata = options?.metadata\n ? { ...baseMetadata, ...options.metadata }\n : baseMetadata;\n\n super(message, ErrorCodes.businessRuleViolation, {\n ...options,\n metadata: mergedMetadata,\n });\n }\n}\n\nexport { BusinessRuleViolationError };\n","import { AppError } from \"./app-error.js\";\nimport { ErrorCodes } from \"./error-codes.js\";\nimport type { AppErrorOptions } from \"./types.js\";\n\n/**\n * Conflict kinds we want to distinguish semantically.\n */\ntype ConflictKind = \"already_exists\" | \"duplicate\" | \"unique_violation\";\n\n/**\n * Metadata attached to conflicts without exposing sensitive values.\n */\ntype ConflictErrorMetadata = {\n kind: ConflictKind;\n entity: string;\n operation?: string;\n field?: string;\n constraintName?: string;\n existingId?: string;\n valueHash?: string;\n valuePreview?: string;\n detectedAtIso?: string;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n hint?: string;\n};\n\ntype UniqueConstraintViolation = {\n kind: \"unique_violation\";\n constraintName?: string;\n table?: string;\n columns?: string[];\n};\n\nabstract class ConflictError extends AppError {\n public readonly kind: ConflictKind;\n\n protected constructor(\n params: {\n message: string;\n code: string;\n kind: ConflictKind;\n metadata: Omit<ConflictErrorMetadata, \"kind\">;\n cause?: unknown;\n } & AppErrorOptions,\n ) {\n super(params.message, params.code, {\n ...params,\n metadata: {\n kind: params.kind,\n ...params.metadata,\n },\n });\n\n this.kind = params.kind;\n Object.freeze(this);\n }\n}\n\nclass AlreadyExistsError extends ConflictError {\n private constructor(\n input: {\n metadata: Omit<ConflictErrorMetadata, \"kind\">;\n cause?: unknown;\n } & AppErrorOptions,\n ) {\n super({\n message:\n \"A matching record already exists for the requested operation\",\n code: ErrorCodes.conflict.alreadyExists,\n kind: \"already_exists\",\n ...input,\n });\n }\n\n static detected(input: {\n entity: string;\n operation?: string;\n field?: string;\n existingId?: string;\n valueHash?: string;\n valuePreview?: string;\n detectedAtIso?: string;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n hint?: string;\n cause?: unknown;\n }): AlreadyExistsError {\n return new AlreadyExistsError({\n metadata: {\n entity: input.entity,\n operation: input.operation ?? \"create\",\n field: input.field,\n existingId: input.existingId,\n valueHash: input.valueHash,\n valuePreview: input.valuePreview,\n detectedAtIso: input.detectedAtIso,\n correlationId: input.correlationId,\n requestId: input.requestId,\n commandId: input.commandId,\n hint: input.hint ?? \"Verify existing records before retrying.\",\n },\n cause: input.cause,\n });\n }\n}\n\nclass DuplicateError extends ConflictError {\n private constructor(\n input: {\n metadata: Omit<ConflictErrorMetadata, \"kind\">;\n cause?: unknown;\n } & AppErrorOptions,\n ) {\n super({\n message: \"Conflict: an existing record violates uniqueness\",\n code: ErrorCodes.conflict.duplicate,\n kind: \"duplicate\",\n ...input,\n });\n }\n\n static detected(input: {\n entity: string;\n operation?: string;\n field?: string;\n constraintName?: string;\n existingId?: string;\n valueHash?: string;\n valuePreview?: string;\n detectedAtIso?: string;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n hint?: string;\n cause?: unknown;\n }): DuplicateError {\n return new DuplicateError({\n metadata: {\n entity: input.entity,\n operation: input.operation,\n field: input.field,\n constraintName: input.constraintName,\n existingId: input.existingId,\n valueHash: input.valueHash,\n valuePreview: input.valuePreview,\n detectedAtIso: input.detectedAtIso,\n correlationId: input.correlationId,\n requestId: input.requestId,\n commandId: input.commandId,\n hint:\n input.hint ??\n \"Adjust the data so it does not duplicate existing records.\",\n },\n cause: input.cause,\n });\n }\n}\n\nclass UniqueConstraintViolationError extends ConflictError {\n private constructor(\n input: {\n metadata: Omit<ConflictErrorMetadata, \"kind\"> & {\n violation: UniqueConstraintViolation;\n };\n cause?: unknown;\n } & AppErrorOptions,\n ) {\n super({\n message: \"Uniqueness violation in storage\",\n code: ErrorCodes.conflict.uniqueViolation,\n kind: \"unique_violation\",\n ...input,\n });\n }\n\n static detected(input: {\n entity: string;\n operation?: string;\n constraintName?: string;\n table?: string;\n columns?: string[];\n detectedAtIso?: string;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n cause?: unknown;\n }): UniqueConstraintViolationError {\n return new UniqueConstraintViolationError({\n metadata: {\n entity: input.entity,\n operation: input.operation,\n constraintName: input.constraintName,\n detectedAtIso: input.detectedAtIso,\n correlationId: input.correlationId,\n requestId: input.requestId,\n commandId: input.commandId,\n violation: {\n kind: \"unique_violation\",\n constraintName: input.constraintName,\n table: input.table,\n columns: input.columns,\n },\n hint: \"Uniqueness conflict detected in the database.\",\n },\n cause: input.cause,\n });\n }\n}\n\nfunction translateUniqueViolationToDuplicate(input: {\n entity: string;\n operation?: string;\n violation: UniqueConstraintViolation;\n field?: string;\n ctx?: {\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n nowIso?: string;\n };\n cause?: unknown;\n}): DuplicateError {\n return DuplicateError.detected({\n entity: input.entity,\n operation: input.operation,\n field: input.field,\n constraintName: input.violation.constraintName,\n detectedAtIso: input.ctx?.nowIso,\n correlationId: input.ctx?.correlationId,\n requestId: input.ctx?.requestId,\n commandId: input.ctx?.commandId,\n cause: input.cause,\n });\n}\n\nexport {\n AlreadyExistsError,\n ConflictError,\n DuplicateError,\n translateUniqueViolationToDuplicate,\n UniqueConstraintViolationError,\n};\n\nexport type { ConflictErrorMetadata, ConflictKind, UniqueConstraintViolation };\n","import { payloadHash, sha256Hex, stableStringify } from \"../shared/hashing.js\";\n\nimport { AppError } from \"./app-error.js\";\nimport { ErrorCodes } from \"./error-codes.js\";\n\nexport type IdempotencyFailureKind =\n | \"key_missing\"\n | \"in_progress\"\n | \"payload_mismatch\"\n | \"replay_not_supported\"\n | \"unknown\";\n\nexport type IdempotencyErrorMetadata = {\n kind: IdempotencyFailureKind;\n operation: string;\n scope?: string;\n entity?: string;\n keyHash?: string;\n keyPreview?: string;\n incomingPayloadHash?: string;\n existingPayloadHash?: string;\n idempotencyRecordId?: string;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n detectedAtIso?: string;\n hint?: string;\n details?: string;\n};\n\ntype IdempotencyErrorConstructorInput = {\n message: string;\n code: string;\n kind: IdempotencyFailureKind;\n metadata: Omit<IdempotencyErrorMetadata, \"kind\">;\n cause?: unknown;\n};\n\nabstract class IdempotencyError extends AppError {\n public readonly kind: IdempotencyFailureKind;\n\n protected constructor(input: IdempotencyErrorConstructorInput) {\n super(input.message, input.code, {\n cause: input.cause,\n metadata: { kind: input.kind, ...input.metadata },\n });\n\n this.kind = input.kind;\n Object.freeze(this);\n }\n\n static keyMissing(input: {\n operation: string;\n scope?: string;\n entity?: string;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n detectedAtIso?: string;\n hint?: string;\n details?: string;\n cause?: unknown;\n }): IdempotencyKeyMissingError {\n return IdempotencyKeyMissingError.detected(input);\n }\n\n static inProgress(input: {\n operation: string;\n scope?: string;\n entity?: string;\n key?: string;\n keyHash?: string;\n keyPreview?: string;\n idempotencyRecordId?: string;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n detectedAtIso?: string;\n hint?: string;\n details?: string;\n cause?: unknown;\n }): IdempotencyInProgressError {\n return IdempotencyInProgressError.detected(input);\n }\n\n static payloadMismatch(input: {\n operation: string;\n scope?: string;\n entity?: string;\n key?: string;\n keyHash?: string;\n keyPreview?: string;\n incomingPayloadHash?: string;\n existingPayloadHash?: string;\n idempotencyRecordId?: string;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n detectedAtIso?: string;\n hint?: string;\n details?: string;\n cause?: unknown;\n }): IdempotencyPayloadMismatchError {\n return IdempotencyPayloadMismatchError.detected(input);\n }\n\n static replayNotSupported(input: {\n operation: string;\n scope?: string;\n entity?: string;\n key?: string;\n keyHash?: string;\n keyPreview?: string;\n idempotencyRecordId?: string;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n detectedAtIso?: string;\n hint?: string;\n details?: string;\n cause?: unknown;\n }): IdempotencyReplayNotSupportedError {\n return IdempotencyReplayNotSupportedError.detected(input);\n }\n}\n\nclass IdempotencyKeyMissingError extends IdempotencyError {\n private constructor(input: {\n metadata: Omit<IdempotencyErrorMetadata, \"kind\">;\n cause?: unknown;\n }) {\n super({\n message:\n \"Idempotency key/commandId missing for the requested operation\",\n code: ErrorCodes.idempotency.keyMissing,\n kind: \"key_missing\",\n metadata: input.metadata,\n cause: input.cause,\n });\n }\n\n static detected(input: {\n operation: string;\n scope?: string;\n entity?: string;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n detectedAtIso?: string;\n hint?: string;\n details?: string;\n cause?: unknown;\n }): IdempotencyKeyMissingError {\n return new IdempotencyKeyMissingError({\n cause: input.cause,\n metadata: {\n operation: input.operation,\n scope: input.scope,\n entity: input.entity,\n correlationId: input.correlationId,\n requestId: input.requestId,\n commandId: input.commandId,\n detectedAtIso: input.detectedAtIso,\n hint:\n input.hint ??\n \"Send a commandId/idempotency key to prevent duplicate processing.\",\n details: input.details,\n },\n });\n }\n}\n\nclass IdempotencyInProgressError extends IdempotencyError {\n private constructor(input: {\n metadata: Omit<IdempotencyErrorMetadata, \"kind\">;\n cause?: unknown;\n }) {\n super({\n message: \"The same business intent is already being processed\",\n code: ErrorCodes.idempotency.inProgress,\n kind: \"in_progress\",\n metadata: input.metadata,\n cause: input.cause,\n });\n }\n\n static detected(input: {\n operation: string;\n scope?: string;\n entity?: string;\n key?: string;\n keyHash?: string;\n keyPreview?: string;\n idempotencyRecordId?: string;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n detectedAtIso?: string;\n hint?: string;\n details?: string;\n cause?: unknown;\n }): IdempotencyInProgressError {\n const resolved = resolveKeyIdentity(\n input.key,\n input.keyHash,\n input.keyPreview,\n );\n\n return new IdempotencyInProgressError({\n cause: input.cause,\n metadata: {\n operation: input.operation,\n scope: input.scope,\n entity: input.entity,\n keyHash: resolved.keyHash,\n keyPreview: resolved.keyPreview,\n idempotencyRecordId: input.idempotencyRecordId,\n correlationId: input.correlationId,\n requestId: input.requestId,\n commandId: input.commandId,\n detectedAtIso: input.detectedAtIso,\n hint:\n input.hint ??\n \"Wait for completion and retry using the same key.\",\n details: input.details,\n },\n });\n }\n}\n\nclass IdempotencyPayloadMismatchError extends IdempotencyError {\n private constructor(input: {\n metadata: Omit<IdempotencyErrorMetadata, \"kind\">;\n cause?: unknown;\n }) {\n super({\n message: \"The idempotency key was reused with a different payload\",\n code: ErrorCodes.idempotency.payloadMismatch,\n kind: \"payload_mismatch\",\n metadata: input.metadata,\n cause: input.cause,\n });\n }\n\n static detected(input: {\n operation: string;\n scope?: string;\n entity?: string;\n key?: string;\n keyHash?: string;\n keyPreview?: string;\n incomingPayloadHash?: string;\n existingPayloadHash?: string;\n idempotencyRecordId?: string;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n detectedAtIso?: string;\n hint?: string;\n details?: string;\n cause?: unknown;\n }): IdempotencyPayloadMismatchError {\n const resolved = resolveKeyIdentity(\n input.key,\n input.keyHash,\n input.keyPreview,\n );\n\n return new IdempotencyPayloadMismatchError({\n cause: input.cause,\n metadata: {\n operation: input.operation,\n scope: input.scope,\n entity: input.entity,\n keyHash: resolved.keyHash,\n keyPreview: resolved.keyPreview,\n incomingPayloadHash: input.incomingPayloadHash,\n existingPayloadHash: input.existingPayloadHash,\n idempotencyRecordId: input.idempotencyRecordId,\n correlationId: input.correlationId,\n requestId: input.requestId,\n commandId: input.commandId,\n detectedAtIso: input.detectedAtIso,\n hint:\n input.hint ??\n \"Use a new idempotency key for a new intent. The same key should only be reused for retries of the same payload.\",\n details: input.details,\n },\n });\n }\n}\n\nclass IdempotencyReplayNotSupportedError extends IdempotencyError {\n private constructor(input: {\n metadata: Omit<IdempotencyErrorMetadata, \"kind\">;\n cause?: unknown;\n }) {\n super({\n message:\n \"Re-execution detected, but replay of the previous result is not implemented\",\n code: ErrorCodes.idempotency.replayNotSupported,\n kind: \"replay_not_supported\",\n metadata: input.metadata,\n cause: input.cause,\n });\n }\n\n static detected(input: {\n operation: string;\n scope?: string;\n entity?: string;\n key?: string;\n keyHash?: string;\n keyPreview?: string;\n idempotencyRecordId?: string;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n detectedAtIso?: string;\n hint?: string;\n details?: string;\n cause?: unknown;\n }): IdempotencyReplayNotSupportedError {\n const resolved = resolveKeyIdentity(\n input.key,\n input.keyHash,\n input.keyPreview,\n );\n\n return new IdempotencyReplayNotSupportedError({\n cause: input.cause,\n metadata: {\n operation: input.operation,\n scope: input.scope,\n entity: input.entity,\n keyHash: resolved.keyHash,\n keyPreview: resolved.keyPreview,\n idempotencyRecordId: input.idempotencyRecordId,\n correlationId: input.correlationId,\n requestId: input.requestId,\n commandId: input.commandId,\n detectedAtIso: input.detectedAtIso,\n hint:\n input.hint ??\n \"Try again later, or enable result replay for full idempotency.\",\n details: input.details,\n },\n });\n }\n}\n\nfunction resolveKeyIdentity(\n key?: string,\n keyHash?: string,\n keyPreview?: string,\n): { keyHash?: string; keyPreview?: string } {\n const preview =\n keyPreview ??\n (key ? (key.length <= 8 ? key : key.slice(0, 8)) : undefined);\n\n return {\n keyHash: keyHash,\n keyPreview: preview,\n };\n}\n\nexport {\n IdempotencyError,\n IdempotencyKeyMissingError,\n IdempotencyInProgressError,\n IdempotencyPayloadMismatchError,\n IdempotencyReplayNotSupportedError,\n sha256Hex,\n stableStringify,\n payloadHash,\n};\n","import type { AppErrorOptions, ErrorSeverity } from \"./types.js\";\nimport { AppError } from \"./app-error.js\";\nimport { ErrorCodes } from \"./error-codes.js\";\n\ntype IntegrationErrorReason =\n | \"timeout\"\n | \"unreachable\"\n | \"bad_response\"\n | \"unknown\";\n\ntype IntegrationErrorMetadata = {\n reason: IntegrationErrorReason;\n provider: string;\n operation: string;\n startedAtIso: string;\n durationMs: number;\n detectedAtIso?: string;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n details?: string;\n statusCode?: number;\n responseCode?: string;\n};\n\ntype IntegrationErrorAppOptions = Pick<\n AppErrorOptions,\n | \"cause\"\n | \"type\"\n | \"severity\"\n | \"correlationId\"\n | \"requestId\"\n | \"commandId\"\n | \"createdAtIso\"\n | \"publicMessage\"\n>;\n\ntype IntegrationErrorConstructorParams = {\n message: string;\n code: string;\n reason: IntegrationErrorReason;\n metadata: IntegrationErrorMetadata;\n} & IntegrationErrorAppOptions;\n\nclass IntegrationError extends AppError {\n public readonly reason: IntegrationErrorReason;\n\n private constructor(params: IntegrationErrorConstructorParams) {\n const { message, code, metadata, ...rest } = params;\n super(message, code, {\n ...rest,\n metadata,\n });\n\n this.reason = params.reason;\n Object.freeze(this);\n }\n\n static timeout(options: IntegrationErrorTimeoutOptions): IntegrationError {\n return new IntegrationError({\n message: \"Timeout while integrating with external provider\",\n code: ErrorCodes.integration.timeout,\n reason: \"timeout\",\n metadata: buildMetadata({ reason: \"timeout\", ...options }),\n ...pickAppErrorFields(options),\n });\n }\n\n static unreachable(\n options: IntegrationErrorEndpointOptions,\n ): IntegrationError {\n return new IntegrationError({\n message: \"Provider unavailable\",\n code: ErrorCodes.integration.unreachable,\n reason: \"unreachable\",\n metadata: buildMetadata({ reason: \"unreachable\", ...options }),\n ...pickAppErrorFields(options),\n });\n }\n\n static badResponse(\n options: IntegrationErrorEndpointOptions,\n ): IntegrationError {\n return new IntegrationError({\n message: \"Unexpected response from provider\",\n code: ErrorCodes.integration.badResponse,\n reason: \"bad_response\",\n metadata: buildMetadata({ reason: \"bad_response\", ...options }),\n ...pickAppErrorFields(options),\n });\n }\n}\n\ntype IntegrationErrorBaseOptions = {\n provider: string;\n operation: string;\n startedAtIso: string;\n durationMs: number;\n detectedAtIso?: string;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n details?: string;\n statusCode?: number;\n responseCode?: string;\n cause?: unknown;\n type?: string;\n severity?: ErrorSeverity;\n createdAtIso?: string;\n publicMessage?: string;\n};\n\ntype IntegrationErrorTimeoutOptions = IntegrationErrorBaseOptions;\ntype IntegrationErrorEndpointOptions = IntegrationErrorBaseOptions;\n\nfunction buildMetadata(\n input: IntegrationErrorBaseOptions & { reason: IntegrationErrorReason },\n): IntegrationErrorMetadata {\n return compactMetadata({\n reason: input.reason,\n provider: input.provider,\n operation: input.operation,\n startedAtIso: input.startedAtIso,\n durationMs: input.durationMs,\n detectedAtIso: input.detectedAtIso,\n correlationId: input.correlationId,\n requestId: input.requestId,\n commandId: input.commandId,\n details: input.details,\n statusCode: input.statusCode,\n responseCode: input.responseCode,\n }) as IntegrationErrorMetadata;\n}\n\nfunction pickAppErrorFields(\n options: IntegrationErrorBaseOptions,\n): IntegrationErrorAppOptions {\n return {\n cause: options.cause,\n type: options.type,\n severity: options.severity,\n correlationId: options.correlationId,\n requestId: options.requestId,\n commandId: options.commandId,\n createdAtIso: options.createdAtIso,\n publicMessage: options.publicMessage,\n };\n}\n\nfunction compactMetadata<T extends Record<string, unknown>>(input: T): T {\n return Object.fromEntries(\n Object.entries(input).filter(([, value]) => value !== undefined),\n ) as T;\n}\n\nexport { IntegrationError };\nexport type { IntegrationErrorReason, IntegrationErrorMetadata };\n","import { AppError } from \"./app-error.js\";\nimport { ErrorCodes } from \"./error-codes.js\";\nimport type { AppErrorOptions } from \"./types.js\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// LegacyIncompatibleError\n// ─────────────────────────────────────────────────────────────────────────────\n\nclass LegacyIncompatibleError extends AppError {\n constructor(\n message: string,\n context?: Record<string, unknown>,\n options?: AppErrorOptions,\n ) {\n const mergedMetadata = options?.metadata\n ? { ...(context ?? {}), ...options.metadata }\n : context;\n\n super(message, ErrorCodes.legacyIncompatible, {\n ...options,\n metadata: mergedMetadata,\n });\n }\n}\n\nexport { LegacyIncompatibleError };\n","import { AppError } from \"./app-error.js\";\nimport { ErrorCodes } from \"./error-codes.js\";\nimport type { AppErrorOptions } from \"./types.js\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// NotFoundError\n// ─────────────────────────────────────────────────────────────────────────────\n\nclass NotFoundError extends AppError {\n constructor(\n resource: string,\n criteria?: Record<string, unknown>,\n options?: AppErrorOptions,\n ) {\n const baseMetadata = criteria ? { resource, criteria } : { resource };\n const mergedMetadata = options?.metadata\n ? { ...baseMetadata, ...options.metadata }\n : baseMetadata;\n\n super(`${resource} not found`, ErrorCodes.notFound, {\n ...options,\n metadata: mergedMetadata,\n });\n }\n}\n\nexport { NotFoundError };\n","import { AppError } from \"./app-error.js\";\nimport { serializationErrorCode } from \"./error-codes.js\";\nimport type { AppErrorOptions } from \"./types.js\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\ntype SerializationDirection = \"serialize\" | \"deserialize\";\n\ntype SerializationFailureCategory =\n | \"invalid_json\"\n | \"invalid_shape\"\n | \"missing_field\"\n | \"unexpected_field\"\n | \"invalid_type\"\n | \"schema_version_missing\"\n | \"schema_version_unsupported\"\n | \"mapping_not_implemented\"\n | \"contract_mismatch\"\n | \"parse_failed\"\n | \"stringify_failed\"\n | \"unknown\";\n\ntype SerializationBoundary =\n | \"http_in\"\n | \"http_out\"\n | \"graphql_in\"\n | \"graphql_out\"\n | \"dto_to_domain\"\n | \"domain_to_dto\"\n | \"persistence_to_domain\"\n | \"domain_to_persistence\"\n | \"event_in\"\n | \"event_out\"\n | \"projection\"\n | \"unknown\";\n\n/**\n * Metadata shared by serialization/deserialization failures. Payload previews must be sanitized.\n */\ntype SerializationErrorMetadata = {\n direction: SerializationDirection;\n category: SerializationFailureCategory;\n boundary: SerializationBoundary;\n contract: string;\n schemaVersion?: number | string;\n path?: string;\n payloadPreview?: string;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n hint?: string;\n details?: string;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Base error\n// ─────────────────────────────────────────────────────────────────────────────\n\ntype SerializationErrorOptions = Omit<AppErrorOptions, \"metadata\"> & {\n message: string;\n code: string;\n metadata: Omit<SerializationErrorMetadata, \"direction\" | \"category\">;\n direction: SerializationDirection;\n category: SerializationFailureCategory;\n};\n\nabstract class SerializationError extends AppError {\n public readonly direction: SerializationDirection;\n public readonly category: SerializationFailureCategory;\n public readonly boundary: SerializationBoundary;\n public readonly contract: string;\n\n protected constructor(input: SerializationErrorOptions) {\n super(input.message ?? \"Serialization failure\", input.code, {\n cause: input.cause,\n metadata: {\n direction: input.direction,\n category: input.category,\n ...input.metadata,\n },\n type: input.type,\n severity: input.severity,\n correlationId: input.correlationId,\n requestId: input.requestId,\n commandId: input.commandId,\n createdAtIso: input.createdAtIso,\n publicMessage: input.publicMessage,\n });\n\n this.direction = input.direction;\n this.category = input.category;\n this.boundary = input.metadata.boundary;\n this.contract = input.metadata.contract;\n\n Object.freeze(this);\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Serialization In\n// ─────────────────────────────────────────────────────────────────────────────\n\nclass SerializationInError extends SerializationError {\n private constructor(input: SerializationErrorOptions) {\n super(input);\n }\n\n static failure(\n category: SerializationFailureCategory,\n metadata: Omit<SerializationErrorMetadata, \"direction\" | \"category\"> & {\n cause?: unknown;\n },\n ): SerializationInError {\n return new SerializationInError({\n message: SerializationMessages.message(\"deserialize\", category),\n code: SerializationCodes.code(\"deserialize\", category),\n category,\n direction: \"deserialize\",\n metadata,\n cause: metadata.cause,\n });\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Serialization\n// ─────────────────────────────────────────────────────────────────────────────\n\nclass SerializationOutError extends SerializationError {\n private constructor(input: SerializationErrorOptions) {\n super(input);\n }\n\n static failure(\n category: SerializationFailureCategory,\n metadata: Omit<SerializationErrorMetadata, \"direction\" | \"category\"> & {\n cause?: unknown;\n },\n ): SerializationOutError {\n return new SerializationOutError({\n message: SerializationMessages.message(\"serialize\", category),\n code: SerializationCodes.code(\"serialize\", category),\n category,\n direction: \"serialize\",\n metadata,\n cause: metadata.cause,\n });\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Codes + Messages helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\nclass SerializationCodes {\n static code(\n direction: SerializationDirection,\n category: SerializationFailureCategory,\n ): string {\n return serializationErrorCode(direction, category);\n }\n}\n\nclass SerializationMessages {\n static message(\n direction: SerializationDirection,\n category: SerializationFailureCategory,\n ): string {\n if (direction === \"deserialize\") {\n if (category === \"invalid_json\") {\n return \"Invalid payload: malformed JSON\";\n }\n if (category === \"schema_version_missing\") {\n return \"Invalid payload: schemaVersion is missing\";\n }\n if (category === \"schema_version_unsupported\") {\n return \"Invalid payload: schemaVersion is not supported\";\n }\n if (category === \"invalid_shape\") {\n return \"Invalid payload: incompatible shape\";\n }\n if (category === \"mapping_not_implemented\") {\n return \"Unsupported payload: mapping not implemented\";\n }\n if (category === \"contract_mismatch\") {\n return \"Payload does not match the expected contract\";\n }\n return \"Failed to parse incoming payload\";\n }\n\n if (category === \"stringify_failed\") {\n return \"Failed to serialize the response\";\n }\n if (category === \"contract_mismatch\") {\n return \"Response does not match the expected contract\";\n }\n return \"Failed to build the response\";\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Utilities\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction safePreview(value: unknown, limit = 240): string | undefined {\n try {\n const serialized =\n typeof value === \"string\" ? value : JSON.stringify(value);\n return serialized.length > limit\n ? `${serialized.slice(0, limit)}…`\n : serialized;\n } catch {\n return undefined;\n }\n}\n\nexport {\n safePreview,\n SerializationCodes,\n SerializationError,\n SerializationInError as DeserializationError,\n SerializationInError,\n SerializationMessages,\n SerializationOutError,\n};\nexport type {\n SerializationBoundary,\n SerializationDirection,\n SerializationErrorMetadata,\n SerializationFailureCategory,\n};\n","import { AppError } from \"./app-error.js\";\nimport { ErrorCodes } from \"./error-codes.js\";\nimport type { AppErrorOptions } from \"./types.js\";\n\ntype TemporalKind = \"expired\" | \"not_yet_valid\";\n\ntype TemporalPrecision = \"EXACT\" | \"ESTIMATED\" | \"UNKNOWN\" | \"APPROXIMATE\";\n\ntype TemporalErrorMetadata = {\n resourceType: string;\n resourceId?: string;\n operation?: string;\n validFromIso?: string | null;\n validUntilIso?: string | null;\n evaluatedAtIso: string;\n policyId?: string;\n precision?: TemporalPrecision;\n hint?: string;\n details?: string;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n};\n\ntype TemporalErrorOptions = {\n message: string;\n code: string;\n kind: TemporalKind;\n metadata: TemporalErrorMetadata;\n} & AppErrorOptions;\n\nabstract class TemporalError extends AppError {\n public readonly kind: TemporalKind;\n public readonly resourceType: string;\n public readonly evaluatedAtIso: string;\n\n protected constructor(input: TemporalErrorOptions) {\n super(input.message, input.code, {\n ...input,\n metadata: {\n kind: input.kind,\n ...input.metadata,\n },\n });\n\n this.kind = input.kind;\n this.resourceType = input.metadata.resourceType;\n this.evaluatedAtIso = input.metadata.evaluatedAtIso;\n Object.freeze(this);\n }\n}\n\ntype TemporalCreationInput = TemporalErrorMetadata &\n Partial<Omit<AppErrorOptions, \"metadata\">> & {\n cause?: unknown;\n };\n\nclass ExpiredError extends TemporalError {\n private constructor(input: TemporalErrorOptions) {\n super(input);\n }\n\n static detected(input: TemporalCreationInput): ExpiredError {\n return new ExpiredError({\n message: \"The validity of the resource/action has expired\",\n code: ErrorCodes.temporal.expired,\n kind: \"expired\",\n metadata: {\n ...input,\n hint:\n input.hint ??\n \"The window has expired. Request a new link or try again within the valid period.\",\n },\n cause: input.cause,\n type: input.type,\n severity: input.severity,\n correlationId: input.correlationId,\n requestId: input.requestId,\n commandId: input.commandId,\n createdAtIso: input.createdAtIso,\n publicMessage: input.publicMessage,\n });\n }\n}\n\nclass NotYetValidError extends TemporalError {\n private constructor(input: TemporalErrorOptions) {\n super(input);\n }\n\n static detected(input: TemporalCreationInput): NotYetValidError {\n return new NotYetValidError({\n message: \"The resource/action is not yet valid\",\n code: ErrorCodes.temporal.notYetValid,\n kind: \"not_yet_valid\",\n metadata: {\n ...input,\n hint:\n input.hint ??\n \"Not yet within the valid period. Try again later.\",\n },\n cause: input.cause,\n type: input.type,\n severity: input.severity,\n correlationId: input.correlationId,\n requestId: input.requestId,\n commandId: input.commandId,\n createdAtIso: input.createdAtIso,\n publicMessage: input.publicMessage,\n });\n }\n}\n\nfunction evaluateTemporalWindow(input: {\n validFromIso?: string | null;\n validUntilIso?: string | null;\n evaluatedAtIso: string;\n}): { expired: boolean; notYetValid: boolean } | null {\n const evaluatedMs = Date.parse(input.evaluatedAtIso);\n if (Number.isNaN(evaluatedMs)) return null;\n\n let notYetValid = false;\n\n if (input.validFromIso) {\n const fromMs = Date.parse(input.validFromIso);\n if (!Number.isNaN(fromMs) && evaluatedMs < fromMs) {\n notYetValid = true;\n }\n }\n\n if (input.validUntilIso) {\n const untilMs = Date.parse(input.validUntilIso);\n if (!Number.isNaN(untilMs) && evaluatedMs > untilMs) {\n return { expired: true, notYetValid: false };\n }\n }\n\n return { expired: false, notYetValid };\n}\n\nexport {\n evaluateTemporalWindow,\n ExpiredError,\n NotYetValidError,\n TemporalError,\n};\nexport type { TemporalErrorMetadata, TemporalKind, TemporalPrecision };\n","import { ValidationCode } from \"../exceptions/validation-code.js\";\nimport { ValidationField } from \"../exceptions/validation-field.js\";\n\nimport { AppError } from \"./app-error.js\";\nimport { ErrorCodes } from \"./error-codes.js\";\nimport type { AppErrorOptions } from \"./types.js\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// ValidationError\n// ─────────────────────────────────────────────────────────────────────────────\n\nclass ValidationError extends AppError {\n constructor(\n field: ValidationField,\n code: ValidationCode,\n message: string,\n options?: AppErrorOptions,\n ) {\n const baseMetadata = {\n field: field.value,\n validationCode: code.value,\n };\n const mergedMetadata = options?.metadata\n ? { ...baseMetadata, ...options.metadata }\n : baseMetadata;\n\n super(message, ErrorCodes.validation, {\n ...options,\n metadata: mergedMetadata,\n });\n }\n}\n\nexport { ValidationError };\n"],"mappings":";;AAuCA,IAAM,sBAAN,MAAM,4BAA4B,SAAS;CAGvC,YAAoB,QAajB;EACC,MAAM,OAAO,SAAS,OAAO,MAAM;GAC/B,OAAO,OAAO;GACd,UAAU;IACN,QAAQ,OAAO;IACf,GAAI,OAAO,YAAY,CAAC;GAC5B;GACA,MAAM,OAAO;GACb,UAAU,OAAO;GACjB,eAAe,OAAO;GACtB,WAAW,OAAO;GAClB,WAAW,OAAO;GAClB,cAAc,OAAO;GACrB,eAAe,OAAO;EAC1B,CAAC;EAED,KAAK,SAAS,OAAO;EACrB,OAAO,OAAO,IAAI;CACtB;CAMA,OAAO,aACH,SACmB;EACnB,OAAO,IAAI,oBAAoB;GAC3B,SAAS;GACT,MAAM,WAAW,eAAe;GAChC,QAAQ;GACR,UAAUA,kBAAgB,OAAO;GACjC,GAAGC,yBAAuB,OAAO;EACrC,CAAC;CACL;CAEA,OAAO,aACH,SACmB;EACnB,OAAO,IAAI,oBAAoB;GAC3B,SAAS;GACT,MAAM,WAAW,eAAe;GAChC,QAAQ;GACR,UAAUD,kBAAgB;IACtB,YAAY,SAAS;IACrB,eAAe,SAAS;IACxB,SAAS,SAAS;IAClB,eAAe,SAAS;IACxB,WAAW,SAAS;GACxB,CAAC;GACD,GAAGC,yBAAuB,OAAO;EACrC,CAAC;CACL;CAEA,OAAO,aACH,SACmB;EACnB,OAAO,IAAI,oBAAoB;GAC3B,SAAS;GACT,MAAM,WAAW,eAAe;GAChC,QAAQ;GACR,UAAUD,kBAAgB,OAAO;GACjC,GAAGC,yBAAuB,OAAO;EACrC,CAAC;CACL;CAEA,OAAO,mBACH,SASmB;EACnB,OAAO,IAAI,oBAAoB;GAC3B,SAAS;GACT,MAAM,WAAW,eAAe;GAChC,QAAQ;GACR,UAAUD,kBAAgB,OAAO;GACjC,GAAGC,yBAAuB,OAAO;EACrC,CAAC;CACL;AACJ;AAMA,SAASA,yBAAuB,SAAoC;CAChE,OAAO;EACH,OAAO,SAAS;EAChB,MAAM,SAAS;EACf,UAAU,SAAS;EACnB,eAAe,SAAS;EACxB,WAAW,SAAS;EACpB,WAAW,SAAS;EACpB,cAAc,SAAS;EACvB,eAAe,SAAS;CAC5B;AACJ;AAEA,SAASD,kBACL,OACa;CACb,IAAI,CAAC,OAAO,OAAO,KAAA;CAEnB,OAAO,OAAO,YACV,OAAO,QAAQ,KAAK,EAAE,QAAQ,GAAG,WAAW,UAAU,KAAA,CAAS,CACnE;AACJ;;;ACxGA,IAAM,qBAAN,MAAM,2BAA2B,SAAS;CAGtC,YAAoB,QAajB;EACC,MAAM,OAAO,SAAS,OAAO,MAAM;GAC/B,OAAO,OAAO;GACd,UAAU,OAAO;GACjB,MAAM,OAAO;GACb,UAAU,OAAO;GACjB,eAAe,OAAO;GACtB,WAAW,OAAO;GAClB,WAAW,OAAO;GAClB,cAAc,OAAO;GACrB,eAAe,OAAO;EAC1B,CAAC;EAED,KAAK,SAAS,OAAO;EACrB,OAAO,OAAO,IAAI;CACtB;CAMA,OAAO,UACH,OACkB;EAClB,OAAO,IAAI,mBAAmB;GAC1B,SAAS;GACT,MAAM,WAAW,cAAc;GAC/B,QAAQ;GACR,UAAU;IAAE,QAAQ;IAAa,GAAG,oBAAoB,KAAK;GAAE;GAC/D,GAAG,uBAAuB,KAAK;EACnC,CAAC;CACL;CAEA,OAAO,aACH,OAKkB;EAClB,OAAO,IAAI,mBAAmB;GAC1B,SAAS;GACT,MAAM,WAAW,cAAc;GAC/B,QAAQ;GACR,UAAU;IACN,QAAQ;IACR,GAAG,oBAAoB,KAAK;IAC5B,UAAU;GACd;GACA,GAAG,uBAAuB,KAAK;EACnC,CAAC;CACL;CAEA,OAAO,kBACH,OAGkB;EAClB,OAAO,IAAI,mBAAmB;GAC1B,SAAS;GACT,MAAM,WAAW,cAAc;GAC/B,QAAQ;GACR,UAAU;IACN,QAAQ;IACR,GAAG,oBAAoB,KAAK;GAChC;GACA,GAAG,uBAAuB,KAAK;EACnC,CAAC;CACL;CAEA,OAAO,WACH,OAGkB;EAClB,OAAO,IAAI,mBAAmB;GAC1B,SAAS;GACT,MAAM,WAAW,cAAc;GAC/B,QAAQ;GACR,UAAU;IAAE,QAAQ;IAAgB,GAAG,oBAAoB,KAAK;GAAE;GAClE,GAAG,uBAAuB,KAAK;EACnC,CAAC;CACL;AACJ;AAMA,SAAS,uBAAuB,SAAoC;CAChE,OAAO;EACH,OAAO,SAAS;EAChB,MAAM,SAAS;EACf,UAAU,SAAS;EACnB,eAAe,SAAS;EACxB,WAAW,SAAS;EACpB,WAAW,SAAS;EACpB,cAAc,SAAS;EACvB,eAAe,SAAS;CAC5B;AACJ;AAEA,SAAS,oBACL,OAC0C;CAC1C,MAAM,EACF,OACA,MACA,UACA,eACA,WACA,WACA,cACA,eACA,GAAG,aACH;CACJ,OAAO;AACX;;;AC5LA,IAAM,6BAAN,cAAyC,SAAS;CAC9C,YACI,MACA,SACA,QACA,SACF;EACE,MAAM,eAAe,SAAS;GAAE;GAAM;EAAO,IAAI,EAAE,KAAK;EACxD,MAAM,iBAAiB,SAAS,WAC1B;GAAE,GAAG;GAAc,GAAG,QAAQ;EAAS,IACvC;EAEN,MAAM,SAAS,WAAW,uBAAuB;GAC7C,GAAG;GACH,UAAU;EACd,CAAC;CACL;AACJ;;;ACUA,IAAe,gBAAf,cAAqC,SAAS;CAG1C,YACI,QAOF;EACE,MAAM,OAAO,SAAS,OAAO,MAAM;GAC/B,GAAG;GACH,UAAU;IACN,MAAM,OAAO;IACb,GAAG,OAAO;GACd;EACJ,CAAC;EAED,KAAK,OAAO,OAAO;EACnB,OAAO,OAAO,IAAI;CACtB;AACJ;AAEA,IAAM,qBAAN,MAAM,2BAA2B,cAAc;CAC3C,YACI,OAIF;EACE,MAAM;GACF,SACI;GACJ,MAAM,WAAW,SAAS;GAC1B,MAAM;GACN,GAAG;EACP,CAAC;CACL;CAEA,OAAO,SAAS,OAaO;EACnB,OAAO,IAAI,mBAAmB;GAC1B,UAAU;IACN,QAAQ,MAAM;IACd,WAAW,MAAM,aAAa;IAC9B,OAAO,MAAM;IACb,YAAY,MAAM;IAClB,WAAW,MAAM;IACjB,cAAc,MAAM;IACpB,eAAe,MAAM;IACrB,eAAe,MAAM;IACrB,WAAW,MAAM;IACjB,WAAW,MAAM;IACjB,MAAM,MAAM,QAAQ;GACxB;GACA,OAAO,MAAM;EACjB,CAAC;CACL;AACJ;AAEA,IAAM,iBAAN,MAAM,uBAAuB,cAAc;CACvC,YACI,OAIF;EACE,MAAM;GACF,SAAS;GACT,MAAM,WAAW,SAAS;GAC1B,MAAM;GACN,GAAG;EACP,CAAC;CACL;CAEA,OAAO,SAAS,OAcG;EACf,OAAO,IAAI,eAAe;GACtB,UAAU;IACN,QAAQ,MAAM;IACd,WAAW,MAAM;IACjB,OAAO,MAAM;IACb,gBAAgB,MAAM;IACtB,YAAY,MAAM;IAClB,WAAW,MAAM;IACjB,cAAc,MAAM;IACpB,eAAe,MAAM;IACrB,eAAe,MAAM;IACrB,WAAW,MAAM;IACjB,WAAW,MAAM;IACjB,MACI,MAAM,QACN;GACR;GACA,OAAO,MAAM;EACjB,CAAC;CACL;AACJ;AAEA,IAAM,iCAAN,MAAM,uCAAuC,cAAc;CACvD,YACI,OAMF;EACE,MAAM;GACF,SAAS;GACT,MAAM,WAAW,SAAS;GAC1B,MAAM;GACN,GAAG;EACP,CAAC;CACL;CAEA,OAAO,SAAS,OAWmB;EAC/B,OAAO,IAAI,+BAA+B;GACtC,UAAU;IACN,QAAQ,MAAM;IACd,WAAW,MAAM;IACjB,gBAAgB,MAAM;IACtB,eAAe,MAAM;IACrB,eAAe,MAAM;IACrB,WAAW,MAAM;IACjB,WAAW,MAAM;IACjB,WAAW;KACP,MAAM;KACN,gBAAgB,MAAM;KACtB,OAAO,MAAM;KACb,SAAS,MAAM;IACnB;IACA,MAAM;GACV;GACA,OAAO,MAAM;EACjB,CAAC;CACL;AACJ;AAEA,SAAS,oCAAoC,OAY1B;CACf,OAAO,eAAe,SAAS;EAC3B,QAAQ,MAAM;EACd,WAAW,MAAM;EACjB,OAAO,MAAM;EACb,gBAAgB,MAAM,UAAU;EAChC,eAAe,MAAM,KAAK;EAC1B,eAAe,MAAM,KAAK;EAC1B,WAAW,MAAM,KAAK;EACtB,WAAW,MAAM,KAAK;EACtB,OAAO,MAAM;CACjB,CAAC;AACL;;;ACtMA,IAAe,mBAAf,cAAwC,SAAS;CAG7C,YAAsB,OAAyC;EAC3D,MAAM,MAAM,SAAS,MAAM,MAAM;GAC7B,OAAO,MAAM;GACb,UAAU;IAAE,MAAM,MAAM;IAAM,GAAG,MAAM;GAAS;EACpD,CAAC;EAED,KAAK,OAAO,MAAM;EAClB,OAAO,OAAO,IAAI;CACtB;CAEA,OAAO,WAAW,OAWa;EAC3B,OAAO,2BAA2B,SAAS,KAAK;CACpD;CAEA,OAAO,WAAW,OAea;EAC3B,OAAO,2BAA2B,SAAS,KAAK;CACpD;CAEA,OAAO,gBAAgB,OAiBa;EAChC,OAAO,gCAAgC,SAAS,KAAK;CACzD;CAEA,OAAO,mBAAmB,OAea;EACnC,OAAO,mCAAmC,SAAS,KAAK;CAC5D;AACJ;AAEA,IAAM,6BAAN,MAAM,mCAAmC,iBAAiB;CACtD,YAAoB,OAGjB;EACC,MAAM;GACF,SACI;GACJ,MAAM,WAAW,YAAY;GAC7B,MAAM;GACN,UAAU,MAAM;GAChB,OAAO,MAAM;EACjB,CAAC;CACL;CAEA,OAAO,SAAS,OAWe;EAC3B,OAAO,IAAI,2BAA2B;GAClC,OAAO,MAAM;GACb,UAAU;IACN,WAAW,MAAM;IACjB,OAAO,MAAM;IACb,QAAQ,MAAM;IACd,eAAe,MAAM;IACrB,WAAW,MAAM;IACjB,WAAW,MAAM;IACjB,eAAe,MAAM;IACrB,MACI,MAAM,QACN;IACJ,SAAS,MAAM;GACnB;EACJ,CAAC;CACL;AACJ;AAEA,IAAM,6BAAN,MAAM,mCAAmC,iBAAiB;CACtD,YAAoB,OAGjB;EACC,MAAM;GACF,SAAS;GACT,MAAM,WAAW,YAAY;GAC7B,MAAM;GACN,UAAU,MAAM;GAChB,OAAO,MAAM;EACjB,CAAC;CACL;CAEA,OAAO,SAAS,OAee;EAC3B,MAAM,WAAW,mBACb,MAAM,KACN,MAAM,SACN,MAAM,UACV;EAEA,OAAO,IAAI,2BAA2B;GAClC,OAAO,MAAM;GACb,UAAU;IACN,WAAW,MAAM;IACjB,OAAO,MAAM;IACb,QAAQ,MAAM;IACd,SAAS,SAAS;IAClB,YAAY,SAAS;IACrB,qBAAqB,MAAM;IAC3B,eAAe,MAAM;IACrB,WAAW,MAAM;IACjB,WAAW,MAAM;IACjB,eAAe,MAAM;IACrB,MACI,MAAM,QACN;IACJ,SAAS,MAAM;GACnB;EACJ,CAAC;CACL;AACJ;AAEA,IAAM,kCAAN,MAAM,wCAAwC,iBAAiB;CAC3D,YAAoB,OAGjB;EACC,MAAM;GACF,SAAS;GACT,MAAM,WAAW,YAAY;GAC7B,MAAM;GACN,UAAU,MAAM;GAChB,OAAO,MAAM;EACjB,CAAC;CACL;CAEA,OAAO,SAAS,OAiBoB;EAChC,MAAM,WAAW,mBACb,MAAM,KACN,MAAM,SACN,MAAM,UACV;EAEA,OAAO,IAAI,gCAAgC;GACvC,OAAO,MAAM;GACb,UAAU;IACN,WAAW,MAAM;IACjB,OAAO,MAAM;IACb,QAAQ,MAAM;IACd,SAAS,SAAS;IAClB,YAAY,SAAS;IACrB,qBAAqB,MAAM;IAC3B,qBAAqB,MAAM;IAC3B,qBAAqB,MAAM;IAC3B,eAAe,MAAM;IACrB,WAAW,MAAM;IACjB,WAAW,MAAM;IACjB,eAAe,MAAM;IACrB,MACI,MAAM,QACN;IACJ,SAAS,MAAM;GACnB;EACJ,CAAC;CACL;AACJ;AAEA,IAAM,qCAAN,MAAM,2CAA2C,iBAAiB;CAC9D,YAAoB,OAGjB;EACC,MAAM;GACF,SACI;GACJ,MAAM,WAAW,YAAY;GAC7B,MAAM;GACN,UAAU,MAAM;GAChB,OAAO,MAAM;EACjB,CAAC;CACL;CAEA,OAAO,SAAS,OAeuB;EACnC,MAAM,WAAW,mBACb,MAAM,KACN,MAAM,SACN,MAAM,UACV;EAEA,OAAO,IAAI,mCAAmC;GAC1C,OAAO,MAAM;GACb,UAAU;IACN,WAAW,MAAM;IACjB,OAAO,MAAM;IACb,QAAQ,MAAM;IACd,SAAS,SAAS;IAClB,YAAY,SAAS;IACrB,qBAAqB,MAAM;IAC3B,eAAe,MAAM;IACrB,WAAW,MAAM;IACjB,WAAW,MAAM;IACjB,eAAe,MAAM;IACrB,MACI,MAAM,QACN;IACJ,SAAS,MAAM;GACnB;EACJ,CAAC;CACL;AACJ;AAEA,SAAS,mBACL,KACA,SACA,YACyC;CAKzC,OAAO;EACM;EACT,YALA,eACC,MAAO,IAAI,UAAU,IAAI,MAAM,IAAI,MAAM,GAAG,CAAC,IAAK,KAAA;CAKvD;AACJ;;;AChUA,IAAM,mBAAN,MAAM,yBAAyB,SAAS;CAGpC,YAAoB,QAA2C;EAC3D,MAAM,EAAE,SAAS,MAAM,UAAU,GAAG,SAAS;EAC7C,MAAM,SAAS,MAAM;GACjB,GAAG;GACH;EACJ,CAAC;EAED,KAAK,SAAS,OAAO;EACrB,OAAO,OAAO,IAAI;CACtB;CAEA,OAAO,QAAQ,SAA2D;EACtE,OAAO,IAAI,iBAAiB;GACxB,SAAS;GACT,MAAM,WAAW,YAAY;GAC7B,QAAQ;GACR,UAAU,cAAc;IAAE,QAAQ;IAAW,GAAG;GAAQ,CAAC;GACzD,GAAG,mBAAmB,OAAO;EACjC,CAAC;CACL;CAEA,OAAO,YACH,SACgB;EAChB,OAAO,IAAI,iBAAiB;GACxB,SAAS;GACT,MAAM,WAAW,YAAY;GAC7B,QAAQ;GACR,UAAU,cAAc;IAAE,QAAQ;IAAe,GAAG;GAAQ,CAAC;GAC7D,GAAG,mBAAmB,OAAO;EACjC,CAAC;CACL;CAEA,OAAO,YACH,SACgB;EAChB,OAAO,IAAI,iBAAiB;GACxB,SAAS;GACT,MAAM,WAAW,YAAY;GAC7B,QAAQ;GACR,UAAU,cAAc;IAAE,QAAQ;IAAgB,GAAG;GAAQ,CAAC;GAC9D,GAAG,mBAAmB,OAAO;EACjC,CAAC;CACL;AACJ;AAwBA,SAAS,cACL,OACwB;CACxB,OAAO,gBAAgB;EACnB,QAAQ,MAAM;EACd,UAAU,MAAM;EAChB,WAAW,MAAM;EACjB,cAAc,MAAM;EACpB,YAAY,MAAM;EAClB,eAAe,MAAM;EACrB,eAAe,MAAM;EACrB,WAAW,MAAM;EACjB,WAAW,MAAM;EACjB,SAAS,MAAM;EACf,YAAY,MAAM;EAClB,cAAc,MAAM;CACxB,CAAC;AACL;AAEA,SAAS,mBACL,SAC0B;CAC1B,OAAO;EACH,OAAO,QAAQ;EACf,MAAM,QAAQ;EACd,UAAU,QAAQ;EAClB,eAAe,QAAQ;EACvB,WAAW,QAAQ;EACnB,WAAW,QAAQ;EACnB,cAAc,QAAQ;EACtB,eAAe,QAAQ;CAC3B;AACJ;AAEA,SAAS,gBAAmD,OAAa;CACrE,OAAO,OAAO,YACV,OAAO,QAAQ,KAAK,EAAE,QAAQ,GAAG,WAAW,UAAU,KAAA,CAAS,CACnE;AACJ;;;ACjJA,IAAM,0BAAN,cAAsC,SAAS;CAC3C,YACI,SACA,SACA,SACF;EACE,MAAM,iBAAiB,SAAS,WAC1B;GAAE,GAAI,WAAW,CAAC;GAAI,GAAG,QAAQ;EAAS,IAC1C;EAEN,MAAM,SAAS,WAAW,oBAAoB;GAC1C,GAAG;GACH,UAAU;EACd,CAAC;CACL;AACJ;;;ACfA,IAAM,gBAAN,cAA4B,SAAS;CACjC,YACI,UACA,UACA,SACF;EACE,MAAM,eAAe,WAAW;GAAE;GAAU;EAAS,IAAI,EAAE,SAAS;EACpE,MAAM,iBAAiB,SAAS,WAC1B;GAAE,GAAG;GAAc,GAAG,QAAQ;EAAS,IACvC;EAEN,MAAM,GAAG,SAAS,aAAa,WAAW,UAAU;GAChD,GAAG;GACH,UAAU;EACd,CAAC;CACL;AACJ;;;AC4CA,IAAe,qBAAf,cAA0C,SAAS;CAM/C,YAAsB,OAAkC;EACpD,MAAM,MAAM,WAAW,yBAAyB,MAAM,MAAM;GACxD,OAAO,MAAM;GACb,UAAU;IACN,WAAW,MAAM;IACjB,UAAU,MAAM;IAChB,GAAG,MAAM;GACb;GACA,MAAM,MAAM;GACZ,UAAU,MAAM;GAChB,eAAe,MAAM;GACrB,WAAW,MAAM;GACjB,WAAW,MAAM;GACjB,cAAc,MAAM;GACpB,eAAe,MAAM;EACzB,CAAC;EAED,KAAK,YAAY,MAAM;EACvB,KAAK,WAAW,MAAM;EACtB,KAAK,WAAW,MAAM,SAAS;EAC/B,KAAK,WAAW,MAAM,SAAS;EAE/B,OAAO,OAAO,IAAI;CACtB;AACJ;AAMA,IAAM,uBAAN,MAAM,6BAA6B,mBAAmB;CAClD,YAAoB,OAAkC;EAClD,MAAM,KAAK;CACf;CAEA,OAAO,QACH,UACA,UAGoB;EACpB,OAAO,IAAI,qBAAqB;GAC5B,SAAS,sBAAsB,QAAQ,eAAe,QAAQ;GAC9D,MAAM,mBAAmB,KAAK,eAAe,QAAQ;GACrD;GACA,WAAW;GACX;GACA,OAAO,SAAS;EACpB,CAAC;CACL;AACJ;AAMA,IAAM,wBAAN,MAAM,8BAA8B,mBAAmB;CACnD,YAAoB,OAAkC;EAClD,MAAM,KAAK;CACf;CAEA,OAAO,QACH,UACA,UAGqB;EACrB,OAAO,IAAI,sBAAsB;GAC7B,SAAS,sBAAsB,QAAQ,aAAa,QAAQ;GAC5D,MAAM,mBAAmB,KAAK,aAAa,QAAQ;GACnD;GACA,WAAW;GACX;GACA,OAAO,SAAS;EACpB,CAAC;CACL;AACJ;AAMA,IAAM,qBAAN,MAAyB;CACrB,OAAO,KACH,WACA,UACM;EACN,OAAO,uBAAuB,WAAW,QAAQ;CACrD;AACJ;AAEA,IAAM,wBAAN,MAA4B;CACxB,OAAO,QACH,WACA,UACM;EACN,IAAI,cAAc,eAAe;GAC7B,IAAI,aAAa,gBACb,OAAO;GAEX,IAAI,aAAa,0BACb,OAAO;GAEX,IAAI,aAAa,8BACb,OAAO;GAEX,IAAI,aAAa,iBACb,OAAO;GAEX,IAAI,aAAa,2BACb,OAAO;GAEX,IAAI,aAAa,qBACb,OAAO;GAEX,OAAO;EACX;EAEA,IAAI,aAAa,oBACb,OAAO;EAEX,IAAI,aAAa,qBACb,OAAO;EAEX,OAAO;CACX;AACJ;AAMA,SAAS,YAAY,OAAgB,QAAQ,KAAyB;CAClE,IAAI;EACA,MAAM,aACF,OAAO,UAAU,WAAW,QAAQ,KAAK,UAAU,KAAK;EAC5D,OAAO,WAAW,SAAS,QACrB,GAAG,WAAW,MAAM,GAAG,KAAK,EAAE,KAC9B;CACV,QAAQ;EACJ;CACJ;AACJ;;;ACzLA,IAAe,gBAAf,cAAqC,SAAS;CAK1C,YAAsB,OAA6B;EAC/C,MAAM,MAAM,SAAS,MAAM,MAAM;GAC7B,GAAG;GACH,UAAU;IACN,MAAM,MAAM;IACZ,GAAG,MAAM;GACb;EACJ,CAAC;EAED,KAAK,OAAO,MAAM;EAClB,KAAK,eAAe,MAAM,SAAS;EACnC,KAAK,iBAAiB,MAAM,SAAS;EACrC,OAAO,OAAO,IAAI;CACtB;AACJ;AAOA,IAAM,eAAN,MAAM,qBAAqB,cAAc;CACrC,YAAoB,OAA6B;EAC7C,MAAM,KAAK;CACf;CAEA,OAAO,SAAS,OAA4C;EACxD,OAAO,IAAI,aAAa;GACpB,SAAS;GACT,MAAM,WAAW,SAAS;GAC1B,MAAM;GACN,UAAU;IACN,GAAG;IACH,MACI,MAAM,QACN;GACR;GACA,OAAO,MAAM;GACb,MAAM,MAAM;GACZ,UAAU,MAAM;GAChB,eAAe,MAAM;GACrB,WAAW,MAAM;GACjB,WAAW,MAAM;GACjB,cAAc,MAAM;GACpB,eAAe,MAAM;EACzB,CAAC;CACL;AACJ;AAEA,IAAM,mBAAN,MAAM,yBAAyB,cAAc;CACzC,YAAoB,OAA6B;EAC7C,MAAM,KAAK;CACf;CAEA,OAAO,SAAS,OAAgD;EAC5D,OAAO,IAAI,iBAAiB;GACxB,SAAS;GACT,MAAM,WAAW,SAAS;GAC1B,MAAM;GACN,UAAU;IACN,GAAG;IACH,MACI,MAAM,QACN;GACR;GACA,OAAO,MAAM;GACb,MAAM,MAAM;GACZ,UAAU,MAAM;GAChB,eAAe,MAAM;GACrB,WAAW,MAAM;GACjB,WAAW,MAAM;GACjB,cAAc,MAAM;GACpB,eAAe,MAAM;EACzB,CAAC;CACL;AACJ;AAEA,SAAS,uBAAuB,OAIsB;CAClD,MAAM,cAAc,KAAK,MAAM,MAAM,cAAc;CACnD,IAAI,OAAO,MAAM,WAAW,GAAG,OAAO;CAEtC,IAAI,cAAc;CAElB,IAAI,MAAM,cAAc;EACpB,MAAM,SAAS,KAAK,MAAM,MAAM,YAAY;EAC5C,IAAI,CAAC,OAAO,MAAM,MAAM,KAAK,cAAc,QACvC,cAAc;CAEtB;CAEA,IAAI,MAAM,eAAe;EACrB,MAAM,UAAU,KAAK,MAAM,MAAM,aAAa;EAC9C,IAAI,CAAC,OAAO,MAAM,OAAO,KAAK,cAAc,SACxC,OAAO;GAAE,SAAS;GAAM,aAAa;EAAM;CAEnD;CAEA,OAAO;EAAE,SAAS;EAAO;CAAY;AACzC;;;AC/HA,IAAM,kBAAN,cAA8B,SAAS;CACnC,YACI,OACA,MACA,SACA,SACF;EACE,MAAM,eAAe;GACjB,OAAO,MAAM;GACb,gBAAgB,KAAK;EACzB;EACA,MAAM,iBAAiB,SAAS,WAC1B;GAAE,GAAG;GAAc,GAAG,QAAQ;EAAS,IACvC;EAEN,MAAM,SAAS,WAAW,YAAY;GAClC,GAAG;GACH,UAAU;EACd,CAAC;CACL;AACJ"}
1
+ {"version":3,"file":"validation-error.js","names":["compactMetadata","extractAppErrorOptions"],"sources":["../src/core/errors/authentication-error.ts","../src/core/errors/authorization-error.ts","../src/core/errors/business-rule-violation-error.ts","../src/core/errors/conflict-error.ts","../src/core/errors/idempotency-error.ts","../src/core/errors/integration-error.ts","../src/core/errors/legacy-incompatible-error.ts","../src/core/errors/not-found-error.ts","../src/core/errors/serialization-error.ts","../src/core/errors/temporal-error.ts","../src/core/errors/validation-error.ts"],"sourcesContent":["import { AppError } from \"./app-error.js\";\nimport { ErrorCodes } from \"./error-codes.js\";\nimport type { AppErrorOptions, ErrorSeverity } from \"./types.js\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\ntype AuthenticationErrorReason =\n | \"missing_token\"\n | \"malformed_token\"\n | \"invalid_token\"\n | \"expired_token\"\n | \"revoked_token\"\n | \"invalid_credentials\"\n | \"session_not_found\"\n | \"session_expired\"\n | \"unknown\";\n\ntype AuthenticationErrorMetadata = {\n reason: AuthenticationErrorReason;\n authScheme?: \"bearer\" | \"cookie\" | \"basic\" | \"unknown\";\n tokenLocation?: \"header\" | \"cookie\" | \"query\" | \"unknown\";\n expiresAtIso?: string;\n correlationId?: string;\n requestId?: string;\n details?: string;\n};\n\ntype AuthenticationErrorFactoryOptions = Omit<\n AuthenticationErrorMetadata,\n \"reason\"\n> &\n Omit<AppErrorOptions, \"metadata\">;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// AuthenticationError\n// ─────────────────────────────────────────────────────────────────────────────\n\nclass AuthenticationError extends AppError {\n public readonly reason: AuthenticationErrorReason;\n\n private constructor(params: {\n message: string;\n code: string;\n reason: AuthenticationErrorReason;\n metadata?: Omit<AuthenticationErrorMetadata, \"reason\">;\n cause?: unknown;\n type?: string;\n severity?: ErrorSeverity;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n createdAtIso?: string;\n publicMessage?: string;\n }) {\n super(params.message, params.code, {\n cause: params.cause,\n metadata: {\n reason: params.reason,\n ...(params.metadata ?? {}),\n },\n type: params.type,\n severity: params.severity,\n correlationId: params.correlationId,\n requestId: params.requestId,\n commandId: params.commandId,\n createdAtIso: params.createdAtIso,\n publicMessage: params.publicMessage,\n });\n\n this.reason = params.reason;\n Object.freeze(this);\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Factory methods\n // ─────────────────────────────────────────────────────────────────────────\n\n static missingToken(\n options?: AuthenticationErrorFactoryOptions,\n ): AuthenticationError {\n return new AuthenticationError({\n message: \"Missing credentials\",\n code: ErrorCodes.authentication.missingToken,\n reason: \"missing_token\",\n metadata: compactMetadata(options),\n ...extractAppErrorOptions(options),\n });\n }\n\n static invalidToken(\n options?: AuthenticationErrorFactoryOptions & { cause?: unknown },\n ): AuthenticationError {\n return new AuthenticationError({\n message: \"Invalid credentials\",\n code: ErrorCodes.authentication.invalidToken,\n reason: \"invalid_token\",\n metadata: compactMetadata({\n authScheme: options?.authScheme,\n tokenLocation: options?.tokenLocation,\n details: options?.details,\n correlationId: options?.correlationId,\n requestId: options?.requestId,\n }),\n ...extractAppErrorOptions(options),\n });\n }\n\n static expiredToken(\n options?: AuthenticationErrorFactoryOptions & { sessionId?: string },\n ): AuthenticationError {\n return new AuthenticationError({\n message: \"Expired credentials\",\n code: ErrorCodes.authentication.expiredToken,\n reason: \"expired_token\",\n metadata: compactMetadata(options),\n ...extractAppErrorOptions(options),\n });\n }\n\n static invalidCredentials(\n options?: Pick<\n AuthenticationErrorFactoryOptions,\n | \"correlationId\"\n | \"requestId\"\n | \"type\"\n | \"severity\"\n | \"createdAtIso\"\n | \"publicMessage\"\n >,\n ): AuthenticationError {\n return new AuthenticationError({\n message: \"Invalid username or password\",\n code: ErrorCodes.authentication.invalidCredentials,\n reason: \"invalid_credentials\",\n metadata: compactMetadata(options),\n ...extractAppErrorOptions(options),\n });\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction extractAppErrorOptions(options?: Partial<AppErrorOptions>) {\n return {\n cause: options?.cause,\n type: options?.type,\n severity: options?.severity,\n correlationId: options?.correlationId,\n requestId: options?.requestId,\n commandId: options?.commandId,\n createdAtIso: options?.createdAtIso,\n publicMessage: options?.publicMessage,\n };\n}\n\nfunction compactMetadata<T extends Record<string, unknown>>(\n input?: T,\n): T | undefined {\n if (!input) return undefined;\n\n return Object.fromEntries(\n Object.entries(input).filter(([, value]) => value !== undefined),\n ) as T;\n}\n\nexport { AuthenticationError };\nexport type { AuthenticationErrorMetadata, AuthenticationErrorReason };\n","import { AppError } from \"./app-error.js\";\nimport { ErrorCodes } from \"./error-codes.js\";\nimport type { AppErrorOptions, ErrorSeverity } from \"./types.js\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\ntype AuthorizationErrorReason =\n | \"forbidden\"\n | \"missing_role\"\n | \"missing_capability\"\n | \"out_of_scope\"\n | \"outside_time_window\"\n | \"policy_denied\"\n | \"unknown\";\n\ntype AuthorizationRequirement = {\n role?: string;\n capability?: string;\n scope?: string; // e.g.: \"school:{id}\" or \"class:{id}\"\n};\n\ntype AuthorizationErrorMetadata = {\n reason: AuthorizationErrorReason;\n\n /** Stable action you evaluated (not an HTTP route — a \"business action\") */\n action: string;\n\n /** Resource identification (without leaking the full payload) */\n resource?: { type: string; id?: string };\n\n /** Optional: actor (do not include sensitive data) */\n actor?: { userId: string; role?: string };\n\n /** Optional: expected requirement */\n required?: AuthorizationRequirement;\n\n /** Optional: policy (when you already have PolicyEvaluation or similar) */\n policyId?: string;\n policyVersion?: number;\n evaluatedAtIso?: string;\n decision?: \"allow\" | \"deny\";\n reasonCode?: string;\n\n /** Optional: additional non-sensitive info */\n details?: string;\n};\n\n/**\n * Options for AuthorizationError factory methods.\n * Combines metadata fields (except 'reason') with common AppError options.\n */\ntype AuthorizationErrorFactoryOptions = Omit<\n AuthorizationErrorMetadata,\n \"reason\"\n> &\n Omit<AppErrorOptions, \"metadata\">;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// AuthorizationError\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Raised when an authenticated actor is not allowed to perform a business\n * action — the \"you may not\" error, distinct from authentication (\"who are\n * you\"). Maps to an HTTP 403 at the edge.\n *\n * The discriminating {@link reason} records *why* access was denied (a flat\n * forbid, a missing role/capability, an out-of-scope target, or a policy\n * decision) so the boundary can shape the response without re-deriving it. The\n * metadata is deliberately built around a stable business `action` and a\n * type/id resource reference rather than an HTTP route or full payload, keeping\n * sensitive data out of logs. Instances are frozen. Construct through the\n * static factories, never directly.\n */\nclass AuthorizationError extends AppError {\n public readonly reason: AuthorizationErrorReason;\n\n private constructor(params: {\n message: string;\n code: string;\n reason: AuthorizationErrorReason;\n metadata: AuthorizationErrorMetadata;\n cause?: unknown;\n type?: string;\n severity?: ErrorSeverity;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n createdAtIso?: string;\n publicMessage?: string;\n }) {\n super(params.message, params.code, {\n cause: params.cause,\n metadata: params.metadata,\n type: params.type,\n severity: params.severity,\n correlationId: params.correlationId,\n requestId: params.requestId,\n commandId: params.commandId,\n createdAtIso: params.createdAtIso,\n publicMessage: params.publicMessage,\n });\n\n this.reason = params.reason;\n Object.freeze(this);\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Factories\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * A flat denial with no more specific reason — the actor simply may not\n * perform this action. Reach for a more precise factory\n * ({@link AuthorizationError.missingCapability}, {@link AuthorizationError.outOfScope},\n * {@link AuthorizationError.policyDenied}) when the cause is known.\n */\n static forbidden(\n input: AuthorizationErrorFactoryOptions,\n ): AuthorizationError {\n return new AuthorizationError({\n message: \"Action not allowed\",\n code: ErrorCodes.authorization.forbidden,\n reason: \"forbidden\",\n metadata: { reason: \"forbidden\", ...extractMetadataOnly(input) },\n ...extractAppErrorOptions(input),\n });\n }\n\n /**\n * The action was denied by an evaluated policy. Captures the deciding\n * policy's id, version, and evaluation instant into the metadata (with\n * `decision: \"deny\"`) so the denial is auditable back to the exact policy\n * that produced it.\n *\n * @param input - Factory options plus the required `policyId`,\n * `policyVersion`, and `evaluatedAtIso` of the deciding policy.\n */\n static policyDenied(\n input: AuthorizationErrorFactoryOptions & {\n policyId: string;\n policyVersion: number;\n evaluatedAtIso: string;\n },\n ): AuthorizationError {\n return new AuthorizationError({\n message: \"Action denied by policy\",\n code: ErrorCodes.authorization.policyDenied,\n reason: \"policy_denied\",\n metadata: {\n reason: \"policy_denied\",\n ...extractMetadataOnly(input),\n decision: \"deny\",\n },\n ...extractAppErrorOptions(input),\n });\n }\n\n /**\n * The actor lacks a required role or capability. The expected\n * {@link AuthorizationRequirement} is recorded so the boundary can tell the\n * caller precisely what grant is missing.\n *\n * @param input - Factory options plus the `required` role/capability/scope.\n */\n static missingCapability(\n input: AuthorizationErrorFactoryOptions & {\n required: AuthorizationRequirement;\n },\n ): AuthorizationError {\n return new AuthorizationError({\n message: \"Insufficient capability to perform the action\",\n code: ErrorCodes.authorization.missingCapability,\n reason: \"missing_capability\",\n metadata: {\n reason: \"missing_capability\",\n ...extractMetadataOnly(input),\n },\n ...extractAppErrorOptions(input),\n });\n }\n\n /**\n * The actor may perform the action in general, but not on *this* target —\n * the resource falls outside the actor's permitted scope (e.g. a different\n * school or tenant than the one they are bound to).\n *\n * @param input - Factory options plus the optional `required` scope that the\n * target failed to satisfy.\n */\n static outOfScope(\n input: AuthorizationErrorFactoryOptions & {\n required?: AuthorizationRequirement;\n },\n ): AuthorizationError {\n return new AuthorizationError({\n message: \"Action outside the allowed scope\",\n code: ErrorCodes.authorization.outOfScope,\n reason: \"out_of_scope\",\n metadata: { reason: \"out_of_scope\", ...extractMetadataOnly(input) },\n ...extractAppErrorOptions(input),\n });\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction extractAppErrorOptions(options?: Partial<AppErrorOptions>) {\n return {\n cause: options?.cause,\n type: options?.type,\n severity: options?.severity,\n correlationId: options?.correlationId,\n requestId: options?.requestId,\n commandId: options?.commandId,\n createdAtIso: options?.createdAtIso,\n publicMessage: options?.publicMessage,\n };\n}\n\nfunction extractMetadataOnly(\n input: AuthorizationErrorFactoryOptions,\n): Omit<AuthorizationErrorMetadata, \"reason\"> {\n const {\n cause,\n type,\n severity,\n correlationId,\n requestId,\n commandId,\n createdAtIso,\n publicMessage,\n ...metadata\n } = input;\n return metadata;\n}\n\nexport { AuthorizationError };\nexport type {\n AuthorizationErrorMetadata,\n AuthorizationErrorReason,\n AuthorizationRequirement,\n};\n","import { AppError } from \"./app-error.js\";\nimport { ErrorCodes } from \"./error-codes.js\";\nimport type { AppErrorOptions } from \"./types.js\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// BusinessRuleViolationError\n// ─────────────────────────────────────────────────────────────────────────────\n\nclass BusinessRuleViolationError extends AppError {\n constructor(\n rule: string,\n message: string,\n detail?: Record<string, unknown>,\n options?: AppErrorOptions,\n ) {\n const baseMetadata = detail ? { rule, detail } : { rule };\n const mergedMetadata = options?.metadata\n ? { ...baseMetadata, ...options.metadata }\n : baseMetadata;\n\n super(message, ErrorCodes.businessRuleViolation, {\n ...options,\n metadata: mergedMetadata,\n });\n }\n}\n\nexport { BusinessRuleViolationError };\n","import { AppError } from \"./app-error.js\";\nimport { ErrorCodes } from \"./error-codes.js\";\nimport type { AppErrorOptions } from \"./types.js\";\n\n/**\n * Conflict kinds we want to distinguish semantically.\n */\ntype ConflictKind = \"already_exists\" | \"duplicate\" | \"unique_violation\";\n\n/**\n * Metadata attached to conflicts without exposing sensitive values.\n */\ntype ConflictErrorMetadata = {\n kind: ConflictKind;\n entity: string;\n operation?: string;\n field?: string;\n constraintName?: string;\n existingId?: string;\n valueHash?: string;\n valuePreview?: string;\n detectedAtIso?: string;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n hint?: string;\n};\n\n/**\n * Storage-level description of a unique-constraint breach, as reported by a\n * database driver. Used to translate a raw DB error into a domain\n * {@link DuplicateError} via {@link translateUniqueViolationToDuplicate}.\n */\ntype UniqueConstraintViolation = {\n kind: \"unique_violation\";\n constraintName?: string;\n table?: string;\n columns?: string[];\n};\n\n/**\n * Base for errors that signal a state conflict — the request collides with data\n * that already exists. Common at an HTTP 409 boundary.\n *\n * The discriminating {@link kind} lets a handler branch on *why* it conflicted\n * (an already-existing record, a domain duplicate, or a raw storage uniqueness\n * breach) without `instanceof` chains. Abstract: construct one of the concrete\n * subclasses through its `detected(...)` factory, which fills in the right code,\n * message, and metadata. Instances are frozen, so a conflict error can be shared\n * and rethrown without risk of tampering.\n */\nabstract class ConflictError extends AppError {\n public readonly kind: ConflictKind;\n\n protected constructor(\n params: {\n message: string;\n code: string;\n kind: ConflictKind;\n metadata: Omit<ConflictErrorMetadata, \"kind\">;\n cause?: unknown;\n } & AppErrorOptions,\n ) {\n super(params.message, params.code, {\n ...params,\n metadata: {\n kind: params.kind,\n ...params.metadata,\n },\n });\n\n this.kind = params.kind;\n Object.freeze(this);\n }\n}\n\n/**\n * The operation cannot proceed because a matching record already exists —\n * e.g. creating something whose natural key is already taken. Construct via\n * {@link AlreadyExistsError.detected}.\n */\nclass AlreadyExistsError extends ConflictError {\n private constructor(\n input: {\n metadata: Omit<ConflictErrorMetadata, \"kind\">;\n cause?: unknown;\n } & AppErrorOptions,\n ) {\n super({\n message:\n \"A matching record already exists for the requested operation\",\n code: ErrorCodes.conflict.alreadyExists,\n kind: \"already_exists\",\n ...input,\n });\n }\n\n /**\n * Builds an {@link AlreadyExistsError} for a detected collision. `operation`\n * defaults to `\"create\"` and a generic retry `hint` is supplied when none is\n * given, so the error is actionable even from a minimal call site.\n *\n * @param input - The conflicting entity plus optional non-sensitive context\n * (operation, field, existing id, value hash/preview, correlation ids).\n */\n static detected(input: {\n entity: string;\n operation?: string;\n field?: string;\n existingId?: string;\n valueHash?: string;\n valuePreview?: string;\n detectedAtIso?: string;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n hint?: string;\n cause?: unknown;\n }): AlreadyExistsError {\n return new AlreadyExistsError({\n metadata: {\n entity: input.entity,\n operation: input.operation ?? \"create\",\n field: input.field,\n existingId: input.existingId,\n valueHash: input.valueHash,\n valuePreview: input.valuePreview,\n detectedAtIso: input.detectedAtIso,\n correlationId: input.correlationId,\n requestId: input.requestId,\n commandId: input.commandId,\n hint: input.hint ?? \"Verify existing records before retrying.\",\n },\n cause: input.cause,\n });\n }\n}\n\n/**\n * A domain-level duplicate: the data being written would duplicate an existing\n * record under the model's own uniqueness rules. Use this when the duplication\n * is recognized in the domain, as opposed to a raw DB constraint\n * ({@link UniqueConstraintViolationError}). Construct via\n * {@link DuplicateError.detected}.\n */\nclass DuplicateError extends ConflictError {\n private constructor(\n input: {\n metadata: Omit<ConflictErrorMetadata, \"kind\">;\n cause?: unknown;\n } & AppErrorOptions,\n ) {\n super({\n message: \"Conflict: an existing record violates uniqueness\",\n code: ErrorCodes.conflict.duplicate,\n kind: \"duplicate\",\n ...input,\n });\n }\n\n /**\n * Builds a {@link DuplicateError} for a detected duplicate, defaulting to a\n * \"adjust the data so it does not duplicate\" hint when none is provided.\n *\n * @param input - The conflicting entity plus optional non-sensitive context\n * (field, constraint name, existing id, value hash/preview, correlation ids).\n */\n static detected(input: {\n entity: string;\n operation?: string;\n field?: string;\n constraintName?: string;\n existingId?: string;\n valueHash?: string;\n valuePreview?: string;\n detectedAtIso?: string;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n hint?: string;\n cause?: unknown;\n }): DuplicateError {\n return new DuplicateError({\n metadata: {\n entity: input.entity,\n operation: input.operation,\n field: input.field,\n constraintName: input.constraintName,\n existingId: input.existingId,\n valueHash: input.valueHash,\n valuePreview: input.valuePreview,\n detectedAtIso: input.detectedAtIso,\n correlationId: input.correlationId,\n requestId: input.requestId,\n commandId: input.commandId,\n hint:\n input.hint ??\n \"Adjust the data so it does not duplicate existing records.\",\n },\n cause: input.cause,\n });\n }\n}\n\n/**\n * A uniqueness breach surfaced by the storage layer itself (a database unique\n * index), carrying the raw {@link UniqueConstraintViolation} (constraint, table,\n * columns). Keep this distinct from {@link DuplicateError}: this one is the\n * infrastructure signal; translate it into a domain duplicate at the boundary\n * with {@link translateUniqueViolationToDuplicate} when the model should own the\n * message. Construct via {@link UniqueConstraintViolationError.detected}.\n */\nclass UniqueConstraintViolationError extends ConflictError {\n private constructor(\n input: {\n metadata: Omit<ConflictErrorMetadata, \"kind\"> & {\n violation: UniqueConstraintViolation;\n };\n cause?: unknown;\n } & AppErrorOptions,\n ) {\n super({\n message: \"Uniqueness violation in storage\",\n code: ErrorCodes.conflict.uniqueViolation,\n kind: \"unique_violation\",\n ...input,\n });\n }\n\n /**\n * Builds a {@link UniqueConstraintViolationError} from the constraint details\n * a driver reports, packaging them into a nested `violation` payload.\n *\n * @param input - The entity plus the offending constraint name, table, and\n * columns, and optional correlation ids.\n */\n static detected(input: {\n entity: string;\n operation?: string;\n constraintName?: string;\n table?: string;\n columns?: string[];\n detectedAtIso?: string;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n cause?: unknown;\n }): UniqueConstraintViolationError {\n return new UniqueConstraintViolationError({\n metadata: {\n entity: input.entity,\n operation: input.operation,\n constraintName: input.constraintName,\n detectedAtIso: input.detectedAtIso,\n correlationId: input.correlationId,\n requestId: input.requestId,\n commandId: input.commandId,\n violation: {\n kind: \"unique_violation\",\n constraintName: input.constraintName,\n table: input.table,\n columns: input.columns,\n },\n hint: \"Uniqueness conflict detected in the database.\",\n },\n cause: input.cause,\n });\n }\n}\n\n/**\n * Translates a raw storage {@link UniqueConstraintViolation} into a domain-level\n * {@link DuplicateError}. This is the seam where an infrastructure concern (a DB\n * unique index firing) is re-expressed in the language of the model, so callers\n * upstream catch a `DuplicateError` and never have to know a database was\n * involved.\n *\n * @param input - The entity, the driver-reported `violation`, and optional\n * request context (`ctx`) carrying correlation ids and a clock instant.\n * @returns A {@link DuplicateError} carrying the constraint name as its field hint.\n */\nfunction translateUniqueViolationToDuplicate(input: {\n entity: string;\n operation?: string;\n violation: UniqueConstraintViolation;\n field?: string;\n ctx?: {\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n nowIso?: string;\n };\n cause?: unknown;\n}): DuplicateError {\n return DuplicateError.detected({\n entity: input.entity,\n operation: input.operation,\n field: input.field,\n constraintName: input.violation.constraintName,\n detectedAtIso: input.ctx?.nowIso,\n correlationId: input.ctx?.correlationId,\n requestId: input.ctx?.requestId,\n commandId: input.ctx?.commandId,\n cause: input.cause,\n });\n}\n\nexport {\n AlreadyExistsError,\n ConflictError,\n DuplicateError,\n translateUniqueViolationToDuplicate,\n UniqueConstraintViolationError,\n};\n\nexport type { ConflictErrorMetadata, ConflictKind, UniqueConstraintViolation };\n","import { payloadHash, sha256Hex, stableStringify } from \"../shared/hashing.js\";\n\nimport { AppError } from \"./app-error.js\";\nimport { ErrorCodes } from \"./error-codes.js\";\n\nexport type IdempotencyFailureKind =\n | \"key_missing\"\n | \"in_progress\"\n | \"payload_mismatch\"\n | \"replay_not_supported\"\n | \"unknown\";\n\nexport type IdempotencyErrorMetadata = {\n kind: IdempotencyFailureKind;\n operation: string;\n scope?: string;\n entity?: string;\n keyHash?: string;\n keyPreview?: string;\n incomingPayloadHash?: string;\n existingPayloadHash?: string;\n idempotencyRecordId?: string;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n detectedAtIso?: string;\n hint?: string;\n details?: string;\n};\n\ntype IdempotencyErrorConstructorInput = {\n message: string;\n code: string;\n kind: IdempotencyFailureKind;\n metadata: Omit<IdempotencyErrorMetadata, \"kind\">;\n cause?: unknown;\n};\n\nabstract class IdempotencyError extends AppError {\n public readonly kind: IdempotencyFailureKind;\n\n protected constructor(input: IdempotencyErrorConstructorInput) {\n super(input.message, input.code, {\n cause: input.cause,\n metadata: { kind: input.kind, ...input.metadata },\n });\n\n this.kind = input.kind;\n Object.freeze(this);\n }\n\n static keyMissing(input: {\n operation: string;\n scope?: string;\n entity?: string;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n detectedAtIso?: string;\n hint?: string;\n details?: string;\n cause?: unknown;\n }): IdempotencyKeyMissingError {\n return IdempotencyKeyMissingError.detected(input);\n }\n\n static inProgress(input: {\n operation: string;\n scope?: string;\n entity?: string;\n key?: string;\n keyHash?: string;\n keyPreview?: string;\n idempotencyRecordId?: string;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n detectedAtIso?: string;\n hint?: string;\n details?: string;\n cause?: unknown;\n }): IdempotencyInProgressError {\n return IdempotencyInProgressError.detected(input);\n }\n\n static payloadMismatch(input: {\n operation: string;\n scope?: string;\n entity?: string;\n key?: string;\n keyHash?: string;\n keyPreview?: string;\n incomingPayloadHash?: string;\n existingPayloadHash?: string;\n idempotencyRecordId?: string;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n detectedAtIso?: string;\n hint?: string;\n details?: string;\n cause?: unknown;\n }): IdempotencyPayloadMismatchError {\n return IdempotencyPayloadMismatchError.detected(input);\n }\n\n static replayNotSupported(input: {\n operation: string;\n scope?: string;\n entity?: string;\n key?: string;\n keyHash?: string;\n keyPreview?: string;\n idempotencyRecordId?: string;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n detectedAtIso?: string;\n hint?: string;\n details?: string;\n cause?: unknown;\n }): IdempotencyReplayNotSupportedError {\n return IdempotencyReplayNotSupportedError.detected(input);\n }\n}\n\nclass IdempotencyKeyMissingError extends IdempotencyError {\n private constructor(input: {\n metadata: Omit<IdempotencyErrorMetadata, \"kind\">;\n cause?: unknown;\n }) {\n super({\n message:\n \"Idempotency key/commandId missing for the requested operation\",\n code: ErrorCodes.idempotency.keyMissing,\n kind: \"key_missing\",\n metadata: input.metadata,\n cause: input.cause,\n });\n }\n\n static detected(input: {\n operation: string;\n scope?: string;\n entity?: string;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n detectedAtIso?: string;\n hint?: string;\n details?: string;\n cause?: unknown;\n }): IdempotencyKeyMissingError {\n return new IdempotencyKeyMissingError({\n cause: input.cause,\n metadata: {\n operation: input.operation,\n scope: input.scope,\n entity: input.entity,\n correlationId: input.correlationId,\n requestId: input.requestId,\n commandId: input.commandId,\n detectedAtIso: input.detectedAtIso,\n hint:\n input.hint ??\n \"Send a commandId/idempotency key to prevent duplicate processing.\",\n details: input.details,\n },\n });\n }\n}\n\nclass IdempotencyInProgressError extends IdempotencyError {\n private constructor(input: {\n metadata: Omit<IdempotencyErrorMetadata, \"kind\">;\n cause?: unknown;\n }) {\n super({\n message: \"The same business intent is already being processed\",\n code: ErrorCodes.idempotency.inProgress,\n kind: \"in_progress\",\n metadata: input.metadata,\n cause: input.cause,\n });\n }\n\n static detected(input: {\n operation: string;\n scope?: string;\n entity?: string;\n key?: string;\n keyHash?: string;\n keyPreview?: string;\n idempotencyRecordId?: string;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n detectedAtIso?: string;\n hint?: string;\n details?: string;\n cause?: unknown;\n }): IdempotencyInProgressError {\n const resolved = resolveKeyIdentity(\n input.key,\n input.keyHash,\n input.keyPreview,\n );\n\n return new IdempotencyInProgressError({\n cause: input.cause,\n metadata: {\n operation: input.operation,\n scope: input.scope,\n entity: input.entity,\n keyHash: resolved.keyHash,\n keyPreview: resolved.keyPreview,\n idempotencyRecordId: input.idempotencyRecordId,\n correlationId: input.correlationId,\n requestId: input.requestId,\n commandId: input.commandId,\n detectedAtIso: input.detectedAtIso,\n hint:\n input.hint ??\n \"Wait for completion and retry using the same key.\",\n details: input.details,\n },\n });\n }\n}\n\nclass IdempotencyPayloadMismatchError extends IdempotencyError {\n private constructor(input: {\n metadata: Omit<IdempotencyErrorMetadata, \"kind\">;\n cause?: unknown;\n }) {\n super({\n message: \"The idempotency key was reused with a different payload\",\n code: ErrorCodes.idempotency.payloadMismatch,\n kind: \"payload_mismatch\",\n metadata: input.metadata,\n cause: input.cause,\n });\n }\n\n static detected(input: {\n operation: string;\n scope?: string;\n entity?: string;\n key?: string;\n keyHash?: string;\n keyPreview?: string;\n incomingPayloadHash?: string;\n existingPayloadHash?: string;\n idempotencyRecordId?: string;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n detectedAtIso?: string;\n hint?: string;\n details?: string;\n cause?: unknown;\n }): IdempotencyPayloadMismatchError {\n const resolved = resolveKeyIdentity(\n input.key,\n input.keyHash,\n input.keyPreview,\n );\n\n return new IdempotencyPayloadMismatchError({\n cause: input.cause,\n metadata: {\n operation: input.operation,\n scope: input.scope,\n entity: input.entity,\n keyHash: resolved.keyHash,\n keyPreview: resolved.keyPreview,\n incomingPayloadHash: input.incomingPayloadHash,\n existingPayloadHash: input.existingPayloadHash,\n idempotencyRecordId: input.idempotencyRecordId,\n correlationId: input.correlationId,\n requestId: input.requestId,\n commandId: input.commandId,\n detectedAtIso: input.detectedAtIso,\n hint:\n input.hint ??\n \"Use a new idempotency key for a new intent. The same key should only be reused for retries of the same payload.\",\n details: input.details,\n },\n });\n }\n}\n\nclass IdempotencyReplayNotSupportedError extends IdempotencyError {\n private constructor(input: {\n metadata: Omit<IdempotencyErrorMetadata, \"kind\">;\n cause?: unknown;\n }) {\n super({\n message:\n \"Re-execution detected, but replay of the previous result is not implemented\",\n code: ErrorCodes.idempotency.replayNotSupported,\n kind: \"replay_not_supported\",\n metadata: input.metadata,\n cause: input.cause,\n });\n }\n\n static detected(input: {\n operation: string;\n scope?: string;\n entity?: string;\n key?: string;\n keyHash?: string;\n keyPreview?: string;\n idempotencyRecordId?: string;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n detectedAtIso?: string;\n hint?: string;\n details?: string;\n cause?: unknown;\n }): IdempotencyReplayNotSupportedError {\n const resolved = resolveKeyIdentity(\n input.key,\n input.keyHash,\n input.keyPreview,\n );\n\n return new IdempotencyReplayNotSupportedError({\n cause: input.cause,\n metadata: {\n operation: input.operation,\n scope: input.scope,\n entity: input.entity,\n keyHash: resolved.keyHash,\n keyPreview: resolved.keyPreview,\n idempotencyRecordId: input.idempotencyRecordId,\n correlationId: input.correlationId,\n requestId: input.requestId,\n commandId: input.commandId,\n detectedAtIso: input.detectedAtIso,\n hint:\n input.hint ??\n \"Try again later, or enable result replay for full idempotency.\",\n details: input.details,\n },\n });\n }\n}\n\nfunction resolveKeyIdentity(\n key?: string,\n keyHash?: string,\n keyPreview?: string,\n): { keyHash?: string; keyPreview?: string } {\n const preview =\n keyPreview ??\n (key ? (key.length <= 8 ? key : key.slice(0, 8)) : undefined);\n\n return {\n keyHash: keyHash,\n keyPreview: preview,\n };\n}\n\nexport {\n IdempotencyError,\n IdempotencyKeyMissingError,\n IdempotencyInProgressError,\n IdempotencyPayloadMismatchError,\n IdempotencyReplayNotSupportedError,\n sha256Hex,\n stableStringify,\n payloadHash,\n};\n","import type { AppErrorOptions, ErrorSeverity } from \"./types.js\";\nimport { AppError } from \"./app-error.js\";\nimport { ErrorCodes } from \"./error-codes.js\";\n\ntype IntegrationErrorReason =\n | \"timeout\"\n | \"unreachable\"\n | \"bad_response\"\n | \"unknown\";\n\ntype IntegrationErrorMetadata = {\n reason: IntegrationErrorReason;\n provider: string;\n operation: string;\n startedAtIso: string;\n durationMs: number;\n detectedAtIso?: string;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n details?: string;\n statusCode?: number;\n responseCode?: string;\n};\n\ntype IntegrationErrorAppOptions = Pick<\n AppErrorOptions,\n | \"cause\"\n | \"type\"\n | \"severity\"\n | \"correlationId\"\n | \"requestId\"\n | \"commandId\"\n | \"createdAtIso\"\n | \"publicMessage\"\n>;\n\ntype IntegrationErrorConstructorParams = {\n message: string;\n code: string;\n reason: IntegrationErrorReason;\n metadata: IntegrationErrorMetadata;\n} & IntegrationErrorAppOptions;\n\n/**\n * Raised when a call to an external provider fails — a timeout, an unreachable\n * endpoint, or a malformed response. This is the boundary error that separates\n * \"our code is fine, the outside world misbehaved\" from internal faults, which\n * matters for retry and alerting decisions.\n *\n * Every instance records the `provider`, the `operation`, and timing\n * (`startedAtIso` / `durationMs`) so failures are correlatable across services\n * and a slow dependency is visible in the metadata. The discriminating\n * {@link reason} lets callers decide whether a failure is worth retrying.\n * Instances are frozen; construct through the static factories.\n */\nclass IntegrationError extends AppError {\n public readonly reason: IntegrationErrorReason;\n\n private constructor(params: IntegrationErrorConstructorParams) {\n const { message, code, metadata, ...rest } = params;\n super(message, code, {\n ...rest,\n metadata,\n });\n\n this.reason = params.reason;\n Object.freeze(this);\n }\n\n /**\n * The provider did not respond within the allotted time. Usually retryable,\n * since a timeout leaves the outcome unknown rather than known-failed.\n */\n static timeout(options: IntegrationErrorTimeoutOptions): IntegrationError {\n return new IntegrationError({\n message: \"Timeout while integrating with external provider\",\n code: ErrorCodes.integration.timeout,\n reason: \"timeout\",\n metadata: buildMetadata({ reason: \"timeout\", ...options }),\n ...pickAppErrorFields(options),\n });\n }\n\n /**\n * The provider could not be reached at all (connection refused, DNS\n * failure, network partition) — the request never landed.\n */\n static unreachable(\n options: IntegrationErrorEndpointOptions,\n ): IntegrationError {\n return new IntegrationError({\n message: \"Provider unavailable\",\n code: ErrorCodes.integration.unreachable,\n reason: \"unreachable\",\n metadata: buildMetadata({ reason: \"unreachable\", ...options }),\n ...pickAppErrorFields(options),\n });\n }\n\n /**\n * The provider answered, but with something the system cannot use — an\n * unexpected status, an unparsable body, or a contract mismatch. Unlike a\n * timeout this is a definite failure, so blind retries rarely help.\n */\n static badResponse(\n options: IntegrationErrorEndpointOptions,\n ): IntegrationError {\n return new IntegrationError({\n message: \"Unexpected response from provider\",\n code: ErrorCodes.integration.badResponse,\n reason: \"bad_response\",\n metadata: buildMetadata({ reason: \"bad_response\", ...options }),\n ...pickAppErrorFields(options),\n });\n }\n}\n\ntype IntegrationErrorBaseOptions = {\n provider: string;\n operation: string;\n startedAtIso: string;\n durationMs: number;\n detectedAtIso?: string;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n details?: string;\n statusCode?: number;\n responseCode?: string;\n cause?: unknown;\n type?: string;\n severity?: ErrorSeverity;\n createdAtIso?: string;\n publicMessage?: string;\n};\n\ntype IntegrationErrorTimeoutOptions = IntegrationErrorBaseOptions;\ntype IntegrationErrorEndpointOptions = IntegrationErrorBaseOptions;\n\nfunction buildMetadata(\n input: IntegrationErrorBaseOptions & { reason: IntegrationErrorReason },\n): IntegrationErrorMetadata {\n return compactMetadata({\n reason: input.reason,\n provider: input.provider,\n operation: input.operation,\n startedAtIso: input.startedAtIso,\n durationMs: input.durationMs,\n detectedAtIso: input.detectedAtIso,\n correlationId: input.correlationId,\n requestId: input.requestId,\n commandId: input.commandId,\n details: input.details,\n statusCode: input.statusCode,\n responseCode: input.responseCode,\n }) as IntegrationErrorMetadata;\n}\n\nfunction pickAppErrorFields(\n options: IntegrationErrorBaseOptions,\n): IntegrationErrorAppOptions {\n return {\n cause: options.cause,\n type: options.type,\n severity: options.severity,\n correlationId: options.correlationId,\n requestId: options.requestId,\n commandId: options.commandId,\n createdAtIso: options.createdAtIso,\n publicMessage: options.publicMessage,\n };\n}\n\nfunction compactMetadata<T extends Record<string, unknown>>(input: T): T {\n return Object.fromEntries(\n Object.entries(input).filter(([, value]) => value !== undefined),\n ) as T;\n}\n\nexport { IntegrationError };\nexport type { IntegrationErrorReason, IntegrationErrorMetadata };\n","import { AppError } from \"./app-error.js\";\nimport { ErrorCodes } from \"./error-codes.js\";\nimport type { AppErrorOptions } from \"./types.js\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// LegacyIncompatibleError\n// ─────────────────────────────────────────────────────────────────────────────\n\nclass LegacyIncompatibleError extends AppError {\n constructor(\n message: string,\n context?: Record<string, unknown>,\n options?: AppErrorOptions,\n ) {\n const mergedMetadata = options?.metadata\n ? { ...(context ?? {}), ...options.metadata }\n : context;\n\n super(message, ErrorCodes.legacyIncompatible, {\n ...options,\n metadata: mergedMetadata,\n });\n }\n}\n\nexport { LegacyIncompatibleError };\n","import { AppError } from \"./app-error.js\";\nimport { ErrorCodes } from \"./error-codes.js\";\nimport type { AppErrorOptions } from \"./types.js\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// NotFoundError\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Raised when a requested resource does not exist. Maps naturally onto an HTTP\n * 404 at the edge, but stays transport-agnostic here.\n *\n * The `resource` name builds the message (`\"<resource> not found\"`) and, with\n * the optional lookup `criteria`, lands in the metadata so logs show *what* was\n * searched for without the caller having to restate it in the message.\n */\nclass NotFoundError extends AppError {\n /**\n * @param resource - Human-readable name of the missing resource (e.g. `\"Order\"`).\n * @param criteria - Optional lookup keys used in the search; recorded in\n * metadata to aid debugging. Avoid putting sensitive values here.\n * @param options - Optional cause, correlation ids, and extra metadata.\n */\n constructor(\n resource: string,\n criteria?: Record<string, unknown>,\n options?: AppErrorOptions,\n ) {\n const baseMetadata = criteria ? { resource, criteria } : { resource };\n const mergedMetadata = options?.metadata\n ? { ...baseMetadata, ...options.metadata }\n : baseMetadata;\n\n super(`${resource} not found`, ErrorCodes.notFound, {\n ...options,\n metadata: mergedMetadata,\n });\n }\n}\n\nexport { NotFoundError };\n","import { AppError } from \"./app-error.js\";\nimport { serializationErrorCode } from \"./error-codes.js\";\nimport type { AppErrorOptions } from \"./types.js\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\ntype SerializationDirection = \"serialize\" | \"deserialize\";\n\ntype SerializationFailureCategory =\n | \"invalid_json\"\n | \"invalid_shape\"\n | \"missing_field\"\n | \"unexpected_field\"\n | \"invalid_type\"\n | \"schema_version_missing\"\n | \"schema_version_unsupported\"\n | \"mapping_not_implemented\"\n | \"contract_mismatch\"\n | \"parse_failed\"\n | \"stringify_failed\"\n | \"unknown\";\n\ntype SerializationBoundary =\n | \"http_in\"\n | \"http_out\"\n | \"graphql_in\"\n | \"graphql_out\"\n | \"dto_to_domain\"\n | \"domain_to_dto\"\n | \"persistence_to_domain\"\n | \"domain_to_persistence\"\n | \"event_in\"\n | \"event_out\"\n | \"projection\"\n | \"unknown\";\n\n/**\n * Metadata shared by serialization/deserialization failures. Payload previews must be sanitized.\n */\ntype SerializationErrorMetadata = {\n direction: SerializationDirection;\n category: SerializationFailureCategory;\n boundary: SerializationBoundary;\n contract: string;\n schemaVersion?: number | string;\n path?: string;\n payloadPreview?: string;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n hint?: string;\n details?: string;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Base error\n// ─────────────────────────────────────────────────────────────────────────────\n\ntype SerializationErrorOptions = Omit<AppErrorOptions, \"metadata\"> & {\n message: string;\n code: string;\n metadata: Omit<SerializationErrorMetadata, \"direction\" | \"category\">;\n direction: SerializationDirection;\n category: SerializationFailureCategory;\n};\n\nabstract class SerializationError extends AppError {\n public readonly direction: SerializationDirection;\n public readonly category: SerializationFailureCategory;\n public readonly boundary: SerializationBoundary;\n public readonly contract: string;\n\n protected constructor(input: SerializationErrorOptions) {\n super(input.message ?? \"Serialization failure\", input.code, {\n cause: input.cause,\n metadata: {\n direction: input.direction,\n category: input.category,\n ...input.metadata,\n },\n type: input.type,\n severity: input.severity,\n correlationId: input.correlationId,\n requestId: input.requestId,\n commandId: input.commandId,\n createdAtIso: input.createdAtIso,\n publicMessage: input.publicMessage,\n });\n\n this.direction = input.direction;\n this.category = input.category;\n this.boundary = input.metadata.boundary;\n this.contract = input.metadata.contract;\n\n Object.freeze(this);\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Serialization In\n// ─────────────────────────────────────────────────────────────────────────────\n\nclass SerializationInError extends SerializationError {\n private constructor(input: SerializationErrorOptions) {\n super(input);\n }\n\n static failure(\n category: SerializationFailureCategory,\n metadata: Omit<SerializationErrorMetadata, \"direction\" | \"category\"> & {\n cause?: unknown;\n },\n ): SerializationInError {\n return new SerializationInError({\n message: SerializationMessages.message(\"deserialize\", category),\n code: SerializationCodes.code(\"deserialize\", category),\n category,\n direction: \"deserialize\",\n metadata,\n cause: metadata.cause,\n });\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Serialization\n// ─────────────────────────────────────────────────────────────────────────────\n\nclass SerializationOutError extends SerializationError {\n private constructor(input: SerializationErrorOptions) {\n super(input);\n }\n\n static failure(\n category: SerializationFailureCategory,\n metadata: Omit<SerializationErrorMetadata, \"direction\" | \"category\"> & {\n cause?: unknown;\n },\n ): SerializationOutError {\n return new SerializationOutError({\n message: SerializationMessages.message(\"serialize\", category),\n code: SerializationCodes.code(\"serialize\", category),\n category,\n direction: \"serialize\",\n metadata,\n cause: metadata.cause,\n });\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Codes + Messages helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\nclass SerializationCodes {\n static code(\n direction: SerializationDirection,\n category: SerializationFailureCategory,\n ): string {\n return serializationErrorCode(direction, category);\n }\n}\n\nclass SerializationMessages {\n static message(\n direction: SerializationDirection,\n category: SerializationFailureCategory,\n ): string {\n if (direction === \"deserialize\") {\n if (category === \"invalid_json\") {\n return \"Invalid payload: malformed JSON\";\n }\n if (category === \"schema_version_missing\") {\n return \"Invalid payload: schemaVersion is missing\";\n }\n if (category === \"schema_version_unsupported\") {\n return \"Invalid payload: schemaVersion is not supported\";\n }\n if (category === \"invalid_shape\") {\n return \"Invalid payload: incompatible shape\";\n }\n if (category === \"mapping_not_implemented\") {\n return \"Unsupported payload: mapping not implemented\";\n }\n if (category === \"contract_mismatch\") {\n return \"Payload does not match the expected contract\";\n }\n return \"Failed to parse incoming payload\";\n }\n\n if (category === \"stringify_failed\") {\n return \"Failed to serialize the response\";\n }\n if (category === \"contract_mismatch\") {\n return \"Response does not match the expected contract\";\n }\n return \"Failed to build the response\";\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Utilities\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction safePreview(value: unknown, limit = 240): string | undefined {\n try {\n const serialized =\n typeof value === \"string\" ? value : JSON.stringify(value);\n return serialized.length > limit\n ? `${serialized.slice(0, limit)}…`\n : serialized;\n } catch {\n return undefined;\n }\n}\n\nexport {\n safePreview,\n SerializationCodes,\n SerializationError,\n SerializationInError as DeserializationError,\n SerializationInError,\n SerializationMessages,\n SerializationOutError,\n};\nexport type {\n SerializationBoundary,\n SerializationDirection,\n SerializationErrorMetadata,\n SerializationFailureCategory,\n};\n","import { AppError } from \"./app-error.js\";\nimport { ErrorCodes } from \"./error-codes.js\";\nimport type { AppErrorOptions } from \"./types.js\";\n\ntype TemporalKind = \"expired\" | \"not_yet_valid\";\n\ntype TemporalPrecision = \"EXACT\" | \"ESTIMATED\" | \"UNKNOWN\" | \"APPROXIMATE\";\n\ntype TemporalErrorMetadata = {\n resourceType: string;\n resourceId?: string;\n operation?: string;\n validFromIso?: string | null;\n validUntilIso?: string | null;\n evaluatedAtIso: string;\n policyId?: string;\n precision?: TemporalPrecision;\n hint?: string;\n details?: string;\n correlationId?: string;\n requestId?: string;\n commandId?: string;\n};\n\ntype TemporalErrorOptions = {\n message: string;\n code: string;\n kind: TemporalKind;\n metadata: TemporalErrorMetadata;\n} & AppErrorOptions;\n\nabstract class TemporalError extends AppError {\n public readonly kind: TemporalKind;\n public readonly resourceType: string;\n public readonly evaluatedAtIso: string;\n\n protected constructor(input: TemporalErrorOptions) {\n super(input.message, input.code, {\n ...input,\n metadata: {\n kind: input.kind,\n ...input.metadata,\n },\n });\n\n this.kind = input.kind;\n this.resourceType = input.metadata.resourceType;\n this.evaluatedAtIso = input.metadata.evaluatedAtIso;\n Object.freeze(this);\n }\n}\n\ntype TemporalCreationInput = TemporalErrorMetadata &\n Partial<Omit<AppErrorOptions, \"metadata\">> & {\n cause?: unknown;\n };\n\nclass ExpiredError extends TemporalError {\n private constructor(input: TemporalErrorOptions) {\n super(input);\n }\n\n static detected(input: TemporalCreationInput): ExpiredError {\n return new ExpiredError({\n message: \"The validity of the resource/action has expired\",\n code: ErrorCodes.temporal.expired,\n kind: \"expired\",\n metadata: {\n ...input,\n hint:\n input.hint ??\n \"The window has expired. Request a new link or try again within the valid period.\",\n },\n cause: input.cause,\n type: input.type,\n severity: input.severity,\n correlationId: input.correlationId,\n requestId: input.requestId,\n commandId: input.commandId,\n createdAtIso: input.createdAtIso,\n publicMessage: input.publicMessage,\n });\n }\n}\n\nclass NotYetValidError extends TemporalError {\n private constructor(input: TemporalErrorOptions) {\n super(input);\n }\n\n static detected(input: TemporalCreationInput): NotYetValidError {\n return new NotYetValidError({\n message: \"The resource/action is not yet valid\",\n code: ErrorCodes.temporal.notYetValid,\n kind: \"not_yet_valid\",\n metadata: {\n ...input,\n hint:\n input.hint ??\n \"Not yet within the valid period. Try again later.\",\n },\n cause: input.cause,\n type: input.type,\n severity: input.severity,\n correlationId: input.correlationId,\n requestId: input.requestId,\n commandId: input.commandId,\n createdAtIso: input.createdAtIso,\n publicMessage: input.publicMessage,\n });\n }\n}\n\nfunction evaluateTemporalWindow(input: {\n validFromIso?: string | null;\n validUntilIso?: string | null;\n evaluatedAtIso: string;\n}): { expired: boolean; notYetValid: boolean } | null {\n const evaluatedMs = Date.parse(input.evaluatedAtIso);\n if (Number.isNaN(evaluatedMs)) return null;\n\n let notYetValid = false;\n\n if (input.validFromIso) {\n const fromMs = Date.parse(input.validFromIso);\n if (!Number.isNaN(fromMs) && evaluatedMs < fromMs) {\n notYetValid = true;\n }\n }\n\n if (input.validUntilIso) {\n const untilMs = Date.parse(input.validUntilIso);\n if (!Number.isNaN(untilMs) && evaluatedMs > untilMs) {\n return { expired: true, notYetValid: false };\n }\n }\n\n return { expired: false, notYetValid };\n}\n\nexport {\n evaluateTemporalWindow,\n ExpiredError,\n NotYetValidError,\n TemporalError,\n};\nexport type { TemporalErrorMetadata, TemporalKind, TemporalPrecision };\n","import { ValidationCode } from \"../exceptions/validation-code.js\";\nimport { ValidationField } from \"../exceptions/validation-field.js\";\n\nimport { AppError } from \"./app-error.js\";\nimport { ErrorCodes } from \"./error-codes.js\";\nimport type { AppErrorOptions } from \"./types.js\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// ValidationError\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Raised when a single input fails a validation rule — the canonical\n * \"this field is wrong, and here is why\" error.\n *\n * It pins the offending `field` and a machine-readable `validationCode` into\n * the metadata (merged ahead of any caller-supplied metadata) so an API layer\n * can map the failure straight onto a form field without parsing the message.\n * The fixed {@link ErrorCodes.validation} code lets callers catch all\n * validation failures uniformly while still distinguishing the specific rule\n * through `validationCode`.\n */\nclass ValidationError extends AppError {\n /**\n * @param field - The input that failed validation; surfaced as `metadata.field`.\n * @param code - The specific rule that was violated; surfaced as `metadata.validationCode`.\n * @param message - The developer-facing description of the failure.\n * @param options - Optional cause, correlation ids, and extra metadata\n * (merged over the field/code metadata, never overwriting it by accident).\n */\n constructor(\n field: ValidationField,\n code: ValidationCode,\n message: string,\n options?: AppErrorOptions,\n ) {\n const baseMetadata = {\n field: field.value,\n validationCode: code.value,\n };\n const mergedMetadata = options?.metadata\n ? { ...baseMetadata, ...options.metadata }\n : baseMetadata;\n\n super(message, ErrorCodes.validation, {\n ...options,\n metadata: mergedMetadata,\n });\n }\n}\n\nexport { ValidationError };\n"],"mappings":"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"}
package/meta.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": "2",
3
3
  "name": "erp-core",
4
- "version": "1.0.9",
4
+ "version": "1.0.11",
5
5
  "description": "Núcleo arquitetural para ERP em TypeScript — entidades, value objects, erros tipados e policies declaráveis sobre clean architecture.",
6
6
  "compatibility": {
7
7
  "engines": {
@@ -65,13 +65,17 @@
65
65
  "mapPolicyEvaluationError"
66
66
  ],
67
67
  "changelog": [
68
- "1.0.0 - Registro inicial do boilerplate com primitives tipadas para import direto, CLI e fluxo full-control.",
69
- "1.0.1 - Corrige exemplos de consumo no README: import direto usa o nome npm com escopo e o argumento do `cullet fc` é o nome do kit no registry.",
70
- "1.0.2 - Declara explicitamente os lints de arquitetura em camadas; o catálogo passa a ser neutro de arquitetura.",
71
- "1.0.3 - Ajuste de descrição do pacote.",
72
- "1.0.4 - `ConditionEvaluatorV1` rejeita `and` vazio com `EMPTY_AND_CONDITION` em vez de avaliar como `true`.",
73
- "1.0.5 - Amplia a cobertura de testes internos (mapeamento de erros de policy, catálogos de erro, `AppError.toJSON`, repositório de definitions); sem mudanças de API pública.",
74
- "1.0.6 - Endurece utilitários recursivos (json-safe, deepFreeze, hashing) contra ciclos e aperta contratos de corretude (semver, `Entity`, condition evaluator)."
68
+ "1.0.1 - Corrige os exemplos de consumo nos READMEs dos kits: o import direto usa o nome npm com escopo (`@cullet/<kit>`) e o argumento do `npx cullet fc` é o nome do kit no registry (`erp-core`), não o nome com escopo. Adiciona a nota explicando o que o `fc` faz no `erp-core`.",
69
+ "1.0.2 - erp-core declara explicitamente os lints de arquitetura em camadas; o catálogo passa a ser neutro de arquitetura.",
70
+ "1.0.3 - Reescreve a descrição do pacote para refletir a entrega dupla do cullet — kits de biblioteca importáveis e kits de tooling copy-first via CLI — e a deixa consistente entre package.json e a saída do `cullet --help`. Só cullet entra (o package.json raiz é private, não publica). O reformat não precisa de changeset: a tarball publicada leva dist/ buildado, cuja saída não muda com a reformatação do src/.",
71
+ "1.0.4 - fix(erp-core): return an error when an AND node has no child conditions",
72
+ "1.0.5 - Expand internal test coverage for previously untested or thinly-tested units: policy error mapping and policy-evaluation error kinds (`INVALID_POLICY_KEY`, `POLICY_DEFINITION_NOT_FOUND`), the conflict/serialization/idempotency error catalogs, `AppError.toJSON`, `RequestedBy`, `PolicyKey`, policy semver comparison, and the in-memory policy definition repository's eligibility filtering. No runtime or public API changes — spec files are excluded from the published package.",
73
+ "1.0.6 - Harden recursive utilities and tighten a few correctness contracts",
74
+ "1.0.7 - Make the kit source nodenext-safe so the full-control copy (`npx cullet fc erp-core`) compiles and runs beyond a bundler.",
75
+ "1.0.8 - Align kit metadata with what the package actually ships and fix doc/packaging gaps. No runtime or public API changes.",
76
+ "1.0.9 - Harden erp-core invariants and error serialization",
77
+ "1.0.10 - Stop the `meta.json` `changelog` from drifting and clarify the `ValueObject` freeze contract.",
78
+ "1.0.11 - Document the public API surface with TSDoc."
75
79
  ],
76
80
  "deprecated": false
77
81
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cullet/erp-core",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
4
  "description": "Núcleo arquitetural para ERP em TypeScript — entidades, value objects, erros tipados e policies declaráveis sobre clean architecture.",
5
5
  "type": "module",
6
6
  "repository": {
@@ -3,6 +3,14 @@ import { assertValidAggregateVersion } from "../shared/aggregate-version.js";
3
3
  import { assertValidDate, cloneDate } from "../shared/temporal-guards.js";
4
4
  import { type ContractVersion, version } from "../versioning/version.js";
5
5
 
6
+ /**
7
+ * The minimal persisted shape needed to reconstitute an {@link Entity}.
8
+ *
9
+ * This is the contract between storage and the domain: a repository maps a row
10
+ * (or document) onto these four fields and hands them to a subclass constructor.
11
+ * `aggregateVersion` travels with the state so optimistic-concurrency checks
12
+ * survive a round-trip through the database.
13
+ */
6
14
  interface EntityState<TIdentifier> {
7
15
  readonly id: TIdentifier;
8
16
  readonly createdAt: Date;
@@ -10,6 +18,20 @@ interface EntityState<TIdentifier> {
10
18
  readonly aggregateVersion: number;
11
19
  }
12
20
 
21
+ /**
22
+ * Base class for domain entities — objects defined by a stable identity rather
23
+ * than by their attributes. Two entities are "the same" when their `id`
24
+ * matches, even if every other field differs; this is the opposite of a
25
+ * {@link ValueObject}, which is defined entirely by its contents.
26
+ *
27
+ * The class owns the bookkeeping common to every aggregate root: a creation
28
+ * timestamp that never changes, a last-modified timestamp, and an
29
+ * `aggregateVersion` counter used for optimistic concurrency control. All three
30
+ * are validated on construction and the dates are defensively cloned, so an
31
+ * entity can never be built into — or leak — an inconsistent temporal state.
32
+ *
33
+ * @typeParam TIdentifier - The identity type (e.g. a branded string id or a VO).
34
+ */
13
35
  @version("1.0")
14
36
  abstract class Entity<TIdentifier> {
15
37
  declare public static readonly CONTRACT_VERSION: ContractVersion;
@@ -19,6 +41,20 @@ abstract class Entity<TIdentifier> {
19
41
  private _updatedAt: Date;
20
42
  private _aggregateVersion: number;
21
43
 
44
+ /**
45
+ * Reconstitutes an entity from its persisted {@link EntityState}.
46
+ *
47
+ * Validates the temporal invariants up front so an invalid entity is
48
+ * impossible to construct: both dates must be valid, the aggregate version
49
+ * must be a non-negative integer, and `updatedAt` may not predate
50
+ * `createdAt`. Both dates are cloned on the way in so a later mutation of
51
+ * the caller's `Date` objects cannot reach into the entity's internal state.
52
+ *
53
+ * Declared `protected` because entities are reconstituted through a
54
+ * subclass factory, never instantiated directly by application code.
55
+ *
56
+ * @throws {InvariantViolationException} When `updatedAt` is earlier than `createdAt`.
57
+ */
22
58
  protected constructor(state: EntityState<TIdentifier>) {
23
59
  assertValidDate("createdAt", state.createdAt);
24
60
  assertValidDate("updatedAt", state.updatedAt);
@@ -36,26 +72,61 @@ abstract class Entity<TIdentifier> {
36
72
  this._aggregateVersion = state.aggregateVersion;
37
73
  }
38
74
 
75
+ /** The entity's stable identity — the basis for equality between entities. */
39
76
  public get id(): TIdentifier {
40
77
  return this._id;
41
78
  }
42
79
 
80
+ /**
81
+ * When the entity was first created.
82
+ *
83
+ * Returns a clone so callers cannot mutate the entity's internal `Date`;
84
+ * the value is fixed at construction and never changes thereafter.
85
+ */
43
86
  public get createdAt(): Date {
44
87
  return cloneDate(this._createdAt);
45
88
  }
46
89
 
90
+ /**
91
+ * When the entity was last modified.
92
+ *
93
+ * Returns a clone for the same encapsulation reason as {@link createdAt};
94
+ * the underlying value advances only through {@link markAsModified}.
95
+ */
47
96
  public get updatedAt(): Date {
48
97
  return cloneDate(this._updatedAt);
49
98
  }
50
99
 
100
+ /**
101
+ * Monotonic counter incremented on every mutation, used for optimistic
102
+ * concurrency control: a writer reads this value, and the persistence layer
103
+ * rejects the write if the stored version has moved on in the meantime.
104
+ */
51
105
  public get aggregateVersion(): number {
52
106
  return this._aggregateVersion;
53
107
  }
54
108
 
109
+ /**
110
+ * The schema/contract version stamped on this entity type by the
111
+ * `@version` decorator — used to detect and migrate state persisted under
112
+ * an older shape.
113
+ */
55
114
  public get contractVersion(): ContractVersion {
56
115
  return Entity.CONTRACT_VERSION;
57
116
  }
58
117
 
118
+ /**
119
+ * The single seam through which an entity records a mutation: it advances
120
+ * `updatedAt` and bumps {@link aggregateVersion} by one. Subclasses must
121
+ * call this from every state-changing method so the version counter stays
122
+ * an accurate optimistic-lock token.
123
+ *
124
+ * @param updatedAt - The modification instant; defaults to now. Validated
125
+ * and required not to predate `createdAt`, preserving the same invariant
126
+ * the constructor enforces.
127
+ * @returns The new aggregate version after the increment.
128
+ * @throws {InvariantViolationException} When `updatedAt` is earlier than `createdAt`.
129
+ */
59
130
  protected markAsModified(updatedAt: Date = new Date()): number {
60
131
  assertValidDate("updatedAt", updatedAt);
61
132
 
@@ -1,29 +1,80 @@
1
1
  import { type DeepReadonly, makeImmutable } from "../shared/immutable.js";
2
2
  import { type ContractVersion, version } from "../versioning/version.js";
3
3
 
4
+ /**
5
+ * Base class for value objects — domain concepts defined entirely by their
6
+ * contents, with no identity of their own. Two value objects are
7
+ * interchangeable when they hold equal data, which is the opposite of an
8
+ * {@link Entity} (compared by id). Money, a CPF, a date range: replacing one
9
+ * instance with an equal one changes nothing about the model.
10
+ *
11
+ * Immutability is the defining guarantee here. The wrapped `value` is
12
+ * deep-frozen on construction, so a value object can be shared freely without
13
+ * any risk of a consumer mutating shared state. Subclasses seal the instance
14
+ * itself with {@link finalize} once their own fields are set.
15
+ *
16
+ * @typeParam T - The shape of the wrapped data.
17
+ * @typeParam P - The primitive form produced by {@link toPrimitive} / {@link toJSON}.
18
+ */
4
19
  @version("1.0")
5
20
  abstract class ValueObject<T, P> {
6
21
  declare public static readonly CONTRACT_VERSION: ContractVersion;
22
+
23
+ /** The wrapped data, deep-frozen so it can never be mutated after construction. */
7
24
  public readonly value: DeepReadonly<T>;
8
25
 
26
+ /**
27
+ * Wraps `value`, deep-freezing it so the value object is immutable from the
28
+ * moment it exists. Declared `protected` because value objects are built
29
+ * through a validating subclass factory, never instantiated directly.
30
+ */
9
31
  protected constructor(value: T) {
10
32
  this.value = makeImmutable(value);
11
33
  }
12
34
 
35
+ /**
36
+ * The schema/contract version stamped on this value-object type by the
37
+ * `@version` decorator — used to detect state persisted under an older shape.
38
+ */
13
39
  public get contractVersion(): ContractVersion {
14
40
  return ValueObject.CONTRACT_VERSION;
15
41
  }
16
42
 
43
+ /**
44
+ * Freezes the instance shell, blocking reassignment of any own field.
45
+ *
46
+ * `value` is already deep-frozen by the constructor, so the wrapped data is
47
+ * immutable regardless. The instance itself is NOT frozen automatically
48
+ * because a subclass may still need to assign its own fields after
49
+ * `super(value)` runs. Call `finalize()` at the very end of the subclass
50
+ * constructor (after all fields are set) to make the whole value object
51
+ * immutable.
52
+ */
17
53
  protected finalize(): void {
18
54
  Object.freeze(this);
19
55
  }
20
56
 
57
+ /**
58
+ * Hook for `JSON.stringify`. Delegates to {@link toPrimitive} so a value
59
+ * object serializes to its primitive form rather than exposing the internal
60
+ * `value` wrapper.
61
+ */
21
62
  public toJSON(): P {
22
63
  return this.toPrimitive();
23
64
  }
24
65
 
66
+ /**
67
+ * Compares this value object with another by content. Because value objects
68
+ * carry no identity, subclasses implement equality over the wrapped data
69
+ * (typically the primitive form), so two independently constructed instances
70
+ * holding the same data are considered equal.
71
+ */
25
72
  public abstract equals(other: this): boolean;
26
73
 
74
+ /**
75
+ * Projects the value object down to a plain, serializable primitive form —
76
+ * the representation suitable for persistence, transport, or comparison.
77
+ */
27
78
  public abstract toPrimitive(): P;
28
79
  }
29
80