@peac/adapter-core 0.12.9 → 0.12.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.
- package/README.md +7 -1
- package/dist/finality.d.ts +109 -0
- package/dist/finality.d.ts.map +1 -0
- package/dist/index.cjs +83 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +80 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
# @peac/adapter-core
|
|
2
2
|
|
|
3
|
-
Shared
|
|
3
|
+
Shared utilities for PEAC payment rail adapters and commerce mappings:
|
|
4
|
+
Result types, validators, payment-proof contracts, and the mapper-boundary
|
|
5
|
+
finality-synthesis guard. The package historically served only payment
|
|
6
|
+
rail adapters; commerce mappings (`@peac/mappings-paymentauth`,
|
|
7
|
+
`@peac/mappings-acp`, `@peac/mappings-ucp`) now also depend on it for the
|
|
8
|
+
finality guard, which lives here so a single tracked module enforces the
|
|
9
|
+
no-finality-synthesis rule consistently across rails and mappings.
|
|
4
10
|
|
|
5
11
|
## Installation
|
|
6
12
|
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mapper-boundary finality-synthesis guard.
|
|
3
|
+
*
|
|
4
|
+
* Commerce mappings preserve raw upstream artifacts and MUST NOT synthesize
|
|
5
|
+
* payment finality (authorization, capture, settlement, refund, void,
|
|
6
|
+
* chargeback) from non-payment artifacts or lifecycle states alone.
|
|
7
|
+
*
|
|
8
|
+
* This module provides the runtime guard that callers in commerce mappings
|
|
9
|
+
* use to enforce that rule at the mapper boundary. It is deliberately
|
|
10
|
+
* dependency-light and emits a stable string code via MapperBoundaryError
|
|
11
|
+
* rather than registering a new wire-level error code.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Strictness mode for commerce mappers.
|
|
15
|
+
*
|
|
16
|
+
* - `strict` - reject any synthesis attempt; reject silent fallbacks
|
|
17
|
+
* (currency='UNKNOWN', defaulted env).
|
|
18
|
+
* - `interop` - emit a deprecation warning instead of rejecting; preserves
|
|
19
|
+
* current consumer behavior. Default.
|
|
20
|
+
* - `legacy` - preserve historical behavior with no warning. Reserved for
|
|
21
|
+
* callers that have migration plans recorded elsewhere.
|
|
22
|
+
*/
|
|
23
|
+
export type StrictnessMode = 'strict' | 'interop' | 'legacy';
|
|
24
|
+
/**
|
|
25
|
+
* Stable string identifier for the mapper-boundary finality-synthesis
|
|
26
|
+
* violation. NOT a wire-level error code; consumers may switch on this
|
|
27
|
+
* value to map to caller-specific error reporting.
|
|
28
|
+
*/
|
|
29
|
+
export declare const COMMERCE_FINALITY_SYNTHESIS_CODE: "commerce.finality_synthesis_blocked";
|
|
30
|
+
export type MapperBoundaryErrorCode = typeof COMMERCE_FINALITY_SYNTHESIS_CODE;
|
|
31
|
+
export interface MapperBoundaryErrorInit {
|
|
32
|
+
code: MapperBoundaryErrorCode;
|
|
33
|
+
pointer?: string;
|
|
34
|
+
upstreamArtifactHash?: string;
|
|
35
|
+
reason?: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Error thrown by mapper-boundary guards. Plain class, no schema dependency.
|
|
39
|
+
* Carries a stable `code` and optional pointer + upstream-artifact-hash
|
|
40
|
+
* fields to help callers correlate the failure.
|
|
41
|
+
*/
|
|
42
|
+
export declare class MapperBoundaryError extends Error {
|
|
43
|
+
readonly code: MapperBoundaryErrorCode;
|
|
44
|
+
readonly pointer?: string;
|
|
45
|
+
readonly upstreamArtifactHash?: string;
|
|
46
|
+
constructor(init: MapperBoundaryErrorInit);
|
|
47
|
+
}
|
|
48
|
+
export type CommerceFinalityEvent = 'authorization' | 'capture' | 'settlement' | 'refund' | 'void' | 'chargeback';
|
|
49
|
+
export interface FinalityGuardInput {
|
|
50
|
+
/**
|
|
51
|
+
* The candidate commerce `event` value (or `undefined` if unset). When
|
|
52
|
+
* unset, the guard is a no-op.
|
|
53
|
+
*/
|
|
54
|
+
event?: string | undefined;
|
|
55
|
+
/**
|
|
56
|
+
* Whether the upstream artifact explicitly proves the claimed finality.
|
|
57
|
+
* Mappers MUST set this from a definite read of upstream-supplied data,
|
|
58
|
+
* NOT from inferred lifecycle state.
|
|
59
|
+
*/
|
|
60
|
+
hasExplicitUpstreamArtifact: boolean;
|
|
61
|
+
/**
|
|
62
|
+
* The currency code as read from upstream. Mappers MUST set this; callers
|
|
63
|
+
* MUST NOT silently fall back to `'UNKNOWN'`. In strict mode, an empty,
|
|
64
|
+
* `'UNKNOWN'`, or non-string value rejects.
|
|
65
|
+
*/
|
|
66
|
+
currency?: string;
|
|
67
|
+
/**
|
|
68
|
+
* The environment discriminant as read from upstream. Mappers MUST set
|
|
69
|
+
* this when known; callers MUST NOT silently default. In strict mode, an
|
|
70
|
+
* unset or non-`live`/`test` value rejects.
|
|
71
|
+
*/
|
|
72
|
+
env?: 'live' | 'test' | string | undefined;
|
|
73
|
+
/**
|
|
74
|
+
* Whether the env was explicitly asserted by upstream (vs defaulted).
|
|
75
|
+
*/
|
|
76
|
+
envExplicit?: boolean;
|
|
77
|
+
}
|
|
78
|
+
export interface FinalityGuardOptions {
|
|
79
|
+
mode?: StrictnessMode;
|
|
80
|
+
pointer?: string;
|
|
81
|
+
upstreamArtifactHash?: string;
|
|
82
|
+
/**
|
|
83
|
+
* Optional warning sink for `interop` mode. Defaults to a no-op.
|
|
84
|
+
*/
|
|
85
|
+
warn?: (message: string) => void;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Mapper-boundary finality-synthesis guard.
|
|
89
|
+
*
|
|
90
|
+
* Throws `MapperBoundaryError` when:
|
|
91
|
+
* - `event` is one of the finality-bearing values AND
|
|
92
|
+
* `hasExplicitUpstreamArtifact` is false (any mode).
|
|
93
|
+
* - `currency` is missing, empty, or `'UNKNOWN'` and mode is `strict`.
|
|
94
|
+
* - `env` is missing or `envExplicit` is false and mode is `strict`.
|
|
95
|
+
*
|
|
96
|
+
* In `interop` mode, the second and third conditions emit a warning via
|
|
97
|
+
* the supplied `warn` sink instead of throwing. In `legacy` mode, only
|
|
98
|
+
* the first condition throws; the second and third are silent.
|
|
99
|
+
*
|
|
100
|
+
* No-ops when `event` is unset (the common discovery / capability path).
|
|
101
|
+
*/
|
|
102
|
+
export declare function assertExplicitFinality(input: FinalityGuardInput, options?: FinalityGuardOptions): void;
|
|
103
|
+
/**
|
|
104
|
+
* Returns whether the given event is one of the finality-bearing commerce
|
|
105
|
+
* events. Useful for callers that want to short-circuit before assembling
|
|
106
|
+
* full guard input.
|
|
107
|
+
*/
|
|
108
|
+
export declare function isFinalityEvent(event: string | undefined): event is CommerceFinalityEvent;
|
|
109
|
+
//# sourceMappingURL=finality.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finality.d.ts","sourceRoot":"","sources":["../src/finality.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;;;;;;;;GASG;AACH,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE7D;;;;GAIG;AACH,eAAO,MAAM,gCAAgC,EAAG,qCAA8C,CAAC;AAE/F,MAAM,MAAM,uBAAuB,GAAG,OAAO,gCAAgC,CAAC;AAE9E,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,uBAAuB,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,QAAQ,CAAC,IAAI,EAAE,uBAAuB,CAAC;IACvC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAC;gBAE3B,IAAI,EAAE,uBAAuB;CAU1C;AAeD,MAAM,MAAM,qBAAqB,GAC7B,eAAe,GACf,SAAS,GACT,YAAY,GACZ,QAAQ,GACR,MAAM,GACN,YAAY,CAAC;AAEjB,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAE3B;;;;OAIG;IACH,2BAA2B,EAAE,OAAO,CAAC;IAErC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IAE3C;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B;;OAEG;IACH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AAQD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,kBAAkB,EACzB,OAAO,GAAE,oBAAyB,GACjC,IAAI,CA0DN;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,KAAK,IAAI,qBAAqB,CAEzF"}
|
package/dist/index.cjs
CHANGED
|
@@ -151,10 +151,93 @@ function optionalEnum(value, allowed, fieldName) {
|
|
|
151
151
|
return requireEnum(value, allowed, fieldName);
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
+
// src/finality.ts
|
|
155
|
+
var COMMERCE_FINALITY_SYNTHESIS_CODE = "commerce.finality_synthesis_blocked";
|
|
156
|
+
var MapperBoundaryError = class extends Error {
|
|
157
|
+
code;
|
|
158
|
+
pointer;
|
|
159
|
+
upstreamArtifactHash;
|
|
160
|
+
constructor(init) {
|
|
161
|
+
const message = init.reason ? `${init.code}: ${init.reason}` : `${init.code}: mapper-boundary guard rejected synthesis`;
|
|
162
|
+
super(message);
|
|
163
|
+
this.name = "MapperBoundaryError";
|
|
164
|
+
this.code = init.code;
|
|
165
|
+
this.pointer = init.pointer;
|
|
166
|
+
this.upstreamArtifactHash = init.upstreamArtifactHash;
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
var FINALITY_EVENTS = /* @__PURE__ */ new Set([
|
|
170
|
+
"authorization",
|
|
171
|
+
"capture",
|
|
172
|
+
"settlement",
|
|
173
|
+
"refund",
|
|
174
|
+
"void",
|
|
175
|
+
"chargeback"
|
|
176
|
+
]);
|
|
177
|
+
var DEFAULT_MODE = "interop";
|
|
178
|
+
function noopWarn(_message) {
|
|
179
|
+
}
|
|
180
|
+
function assertExplicitFinality(input, options = {}) {
|
|
181
|
+
const mode = options.mode ?? DEFAULT_MODE;
|
|
182
|
+
const warn = options.warn ?? noopWarn;
|
|
183
|
+
const pointer = options.pointer;
|
|
184
|
+
const upstreamArtifactHash = options.upstreamArtifactHash;
|
|
185
|
+
if (input.event !== void 0 && FINALITY_EVENTS.has(input.event)) {
|
|
186
|
+
if (!input.hasExplicitUpstreamArtifact) {
|
|
187
|
+
throw new MapperBoundaryError({
|
|
188
|
+
code: COMMERCE_FINALITY_SYNTHESIS_CODE,
|
|
189
|
+
pointer,
|
|
190
|
+
upstreamArtifactHash,
|
|
191
|
+
reason: `event=${JSON.stringify(input.event)} requires an explicit upstream payment artifact`
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
const isMissingCurrency = typeof input.currency !== "string" || input.currency.length === 0 || input.currency === "UNKNOWN";
|
|
196
|
+
if (isMissingCurrency) {
|
|
197
|
+
if (mode === "strict") {
|
|
198
|
+
throw new MapperBoundaryError({
|
|
199
|
+
code: COMMERCE_FINALITY_SYNTHESIS_CODE,
|
|
200
|
+
pointer,
|
|
201
|
+
upstreamArtifactHash,
|
|
202
|
+
reason: "currency missing or fallback (UNKNOWN); strict mode requires upstream-asserted currency"
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
if (mode === "interop") {
|
|
206
|
+
warn(
|
|
207
|
+
"commerce mapper: currency missing or fallback (UNKNOWN). Strict mode will reject this in v0.13.0+. Provide an upstream-asserted currency."
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
const envIsExplicit = input.envExplicit === true;
|
|
212
|
+
const envIsKnown = input.env === "live" || input.env === "test";
|
|
213
|
+
if (!envIsKnown || !envIsExplicit) {
|
|
214
|
+
if (mode === "strict") {
|
|
215
|
+
throw new MapperBoundaryError({
|
|
216
|
+
code: COMMERCE_FINALITY_SYNTHESIS_CODE,
|
|
217
|
+
pointer,
|
|
218
|
+
upstreamArtifactHash,
|
|
219
|
+
reason: "env missing or defaulted; strict mode requires upstream-asserted env (live|test)"
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
if (mode === "interop") {
|
|
223
|
+
warn(
|
|
224
|
+
"commerce mapper: env missing or defaulted. Strict mode will reject this in v0.13.0+. Provide an upstream-asserted env."
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
function isFinalityEvent(event) {
|
|
230
|
+
return event !== void 0 && FINALITY_EVENTS.has(event);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
exports.COMMERCE_FINALITY_SYNTHESIS_CODE = COMMERCE_FINALITY_SYNTHESIS_CODE;
|
|
234
|
+
exports.MapperBoundaryError = MapperBoundaryError;
|
|
154
235
|
exports.adapterErr = adapterErr;
|
|
236
|
+
exports.assertExplicitFinality = assertExplicitFinality;
|
|
155
237
|
exports.chain = chain;
|
|
156
238
|
exports.err = err;
|
|
157
239
|
exports.isErr = isErr;
|
|
240
|
+
exports.isFinalityEvent = isFinalityEvent;
|
|
158
241
|
exports.isOk = isOk;
|
|
159
242
|
exports.map = map;
|
|
160
243
|
exports.mapErr = mapErr;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/result.ts","../src/validators.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Result type utilities for adapter operations\n *\n * Enforces \"never throws\" invariant - all adapter functions return Result<T>.\n */\n\nimport type { AdapterError, AdapterErrorCode } from './types.js';\n\n/**\n * Result type for adapter operations\n *\n * All adapter parsing/validation functions should return this type\n * instead of throwing exceptions. This makes error handling explicit\n * and predictable.\n *\n * @example\n * function parseEvent(input: unknown): Result<Event, AdapterError> {\n * if (!input) {\n * return adapterErr('input is required', 'missing_required_field');\n * }\n * return ok({ ... });\n * }\n */\nexport type Result<T, E = AdapterError> = { ok: true; value: T } | { ok: false; error: E };\n\n/**\n * Create a success result\n */\nexport function ok<T>(value: T): Result<T, never> {\n return { ok: true, value };\n}\n\n/**\n * Create a generic error result\n */\nexport function err<E>(error: E): Result<never, E> {\n return { ok: false, error };\n}\n\n/**\n * Create an adapter error result (convenience helper)\n *\n * @param message - Human-readable error message\n * @param code - Machine-readable error code\n * @param field - Optional field name that caused the error\n */\nexport function adapterErr(\n message: string,\n code: AdapterErrorCode,\n field?: string\n): Result<never, AdapterError> {\n return err({ code, message, field });\n}\n\n/**\n * Check if result is ok (type guard)\n */\nexport function isOk<T, E>(result: Result<T, E>): result is { ok: true; value: T } {\n return result.ok;\n}\n\n/**\n * Check if result is error (type guard)\n */\nexport function isErr<T, E>(result: Result<T, E>): result is { ok: false; error: E } {\n return !result.ok;\n}\n\n/**\n * Map over a successful result\n *\n * @example\n * const result = ok(5);\n * const doubled = map(result, x => x * 2); // ok(10)\n */\nexport function map<T, U, E>(result: Result<T, E>, fn: (value: T) => U): Result<U, E> {\n return result.ok ? ok(fn(result.value)) : result;\n}\n\n/**\n * Map over an error result\n *\n * @example\n * const result = err({ message: 'oops' });\n * const mapped = mapErr(result, e => ({ ...e, prefix: 'Error: ' }));\n */\nexport function mapErr<T, E, F>(result: Result<T, E>, fn: (error: E) => F): Result<T, F> {\n return result.ok ? result : err(fn(result.error));\n}\n\n/**\n * Chain results (flatMap/bind)\n *\n * @example\n * const parseNumber = (s: string): Result<number, string> => {\n * const n = parseInt(s);\n * return isNaN(n) ? err('not a number') : ok(n);\n * };\n *\n * const result = chain(ok('42'), parseNumber); // ok(42)\n */\nexport function chain<T, U, E>(result: Result<T, E>, fn: (value: T) => Result<U, E>): Result<U, E> {\n return result.ok ? fn(result.value) : result;\n}\n\n/**\n * Unwrap a result, throwing if it's an error\n *\n * Use sparingly - prefer explicit error handling.\n *\n * @throws The error value if result is an error\n */\nexport function unwrap<T, E>(result: Result<T, E>): T {\n if (result.ok) {\n return result.value;\n }\n throw result.error;\n}\n\n/**\n * Unwrap a result with a default value for errors\n */\nexport function unwrapOr<T, E>(result: Result<T, E>, defaultValue: T): T {\n return result.ok ? result.value : defaultValue;\n}\n","/**\n * Shared validators for PEAC payment rail adapters\n *\n * These validators enforce consistent validation logic across all adapters.\n * They follow the \"never throws\" pattern using Result types.\n */\n\nimport { adapterErr, ok, type Result } from './result.js';\nimport type { AdapterError } from './types.js';\n\n/**\n * Validate required string field\n *\n * @param value - Value to validate\n * @param fieldName - Field name for error messages\n * @returns Result with string value or error\n */\nexport function requireString(value: unknown, fieldName: string): Result<string, AdapterError> {\n if (typeof value !== 'string' || value.trim() === '') {\n return adapterErr(\n `${fieldName} is required and must be a non-empty string`,\n 'missing_required_field',\n fieldName\n );\n }\n return ok(value);\n}\n\n/**\n * Validate optional string field\n *\n * @param value - Value to validate\n * @param fieldName - Field name for error messages\n * @returns Result with string value, undefined, or error\n */\nexport function optionalString(\n value: unknown,\n fieldName: string\n): Result<string | undefined, AdapterError> {\n if (value === undefined || value === null) {\n return ok(undefined);\n }\n if (typeof value !== 'string') {\n return adapterErr(`${fieldName} must be a string if provided`, 'validation_error', fieldName);\n }\n return ok(value);\n}\n\n/**\n * Validate required number field\n *\n * @param value - Value to validate\n * @param fieldName - Field name for error messages\n * @returns Result with number value or error\n */\nexport function requireNumber(value: unknown, fieldName: string): Result<number, AdapterError> {\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n return adapterErr(`${fieldName} must be a finite number`, 'validation_error', fieldName);\n }\n return ok(value);\n}\n\n/**\n * Validate amount (must be safe non-negative integer in minor units)\n *\n * @param value - Value to validate\n * @returns Result with amount or error\n */\nexport function requireAmount(value: unknown): Result<number, AdapterError> {\n if (typeof value !== 'number') {\n return adapterErr('amount must be a number', 'invalid_amount', 'amount');\n }\n if (!Number.isSafeInteger(value)) {\n return adapterErr('amount must be a safe integer', 'invalid_amount', 'amount');\n }\n if (value < 0) {\n return adapterErr('amount must be non-negative', 'invalid_amount', 'amount');\n }\n return ok(value);\n}\n\n/**\n * Validate currency code (ISO 4217, uppercase)\n *\n * @param value - Value to validate\n * @returns Result with normalized currency code or error\n */\nexport function requireCurrency(value: unknown): Result<string, AdapterError> {\n if (typeof value !== 'string') {\n return adapterErr('currency must be a string', 'invalid_currency', 'currency');\n }\n const normalized = value.toUpperCase();\n if (!/^[A-Z]{3}$/.test(normalized)) {\n return adapterErr(\n 'currency must be a valid ISO 4217 code (3 uppercase letters)',\n 'invalid_currency',\n 'currency'\n );\n }\n return ok(normalized);\n}\n\n/**\n * Validate optional network identifier (CAIP-2 format preferred)\n *\n * @param value - Value to validate\n * @returns Result with network string, undefined, or error\n */\nexport function optionalNetwork(value: unknown): Result<string | undefined, AdapterError> {\n if (value === undefined || value === null) {\n return ok(undefined);\n }\n if (typeof value !== 'string' || value.trim() === '') {\n return adapterErr(\n 'network must be a non-empty string if provided',\n 'invalid_network',\n 'network'\n );\n }\n return ok(value);\n}\n\n/**\n * Parse object safely (for webhook payloads)\n *\n * @param value - Value to validate\n * @param fieldName - Field name for error messages\n * @returns Result with object or error\n */\nexport function requireObject(\n value: unknown,\n fieldName: string = 'input'\n): Result<Record<string, unknown>, AdapterError> {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return adapterErr(`${fieldName} must be a non-null object`, 'parse_error', fieldName);\n }\n return ok(value as Record<string, unknown>);\n}\n\n/**\n * Validate optional timestamp (ISO 8601 string or Unix seconds)\n *\n * @param value - Value to validate\n * @returns Result with ISO 8601 string, undefined, or error\n */\nexport function optionalTimestamp(value: unknown): Result<string | undefined, AdapterError> {\n if (value === undefined || value === null) {\n return ok(undefined);\n }\n if (typeof value === 'string') {\n // Accept ISO 8601 strings as-is\n return ok(value);\n }\n if (typeof value === 'number' && Number.isSafeInteger(value) && value > 0) {\n // Convert Unix seconds to ISO string\n return ok(new Date(value * 1000).toISOString());\n }\n return adapterErr(\n 'timestamp must be an ISO 8601 string or Unix seconds',\n 'validation_error',\n 'timestamp'\n );\n}\n\n/**\n * Validate optional boolean field\n *\n * @param value - Value to validate\n * @param fieldName - Field name for error messages\n * @returns Result with boolean value, undefined, or error\n */\nexport function optionalBoolean(\n value: unknown,\n fieldName: string\n): Result<boolean | undefined, AdapterError> {\n if (value === undefined || value === null) {\n return ok(undefined);\n }\n if (typeof value !== 'boolean') {\n return adapterErr(`${fieldName} must be a boolean if provided`, 'validation_error', fieldName);\n }\n return ok(value);\n}\n\n/**\n * Validate enum value\n *\n * @param value - Value to validate\n * @param allowed - Array of allowed values\n * @param fieldName - Field name for error messages\n * @returns Result with validated value or error\n */\nexport function requireEnum<T extends string>(\n value: unknown,\n allowed: readonly T[],\n fieldName: string\n): Result<T, AdapterError> {\n if (typeof value !== 'string') {\n return adapterErr(`${fieldName} must be a string`, 'validation_error', fieldName);\n }\n if (!allowed.includes(value as T)) {\n return adapterErr(\n `${fieldName} must be one of: ${allowed.join(', ')}`,\n 'validation_error',\n fieldName\n );\n }\n return ok(value as T);\n}\n\n/**\n * Validate optional enum value\n *\n * @param value - Value to validate\n * @param allowed - Array of allowed values\n * @param fieldName - Field name for error messages\n * @returns Result with validated value, undefined, or error\n */\nexport function optionalEnum<T extends string>(\n value: unknown,\n allowed: readonly T[],\n fieldName: string\n): Result<T | undefined, AdapterError> {\n if (value === undefined || value === null) {\n return ok(undefined);\n }\n return requireEnum(value, allowed, fieldName);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/result.ts","../src/validators.ts","../src/finality.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Result type utilities for adapter operations\n *\n * Enforces \"never throws\" invariant - all adapter functions return Result<T>.\n */\n\nimport type { AdapterError, AdapterErrorCode } from './types.js';\n\n/**\n * Result type for adapter operations\n *\n * All adapter parsing/validation functions should return this type\n * instead of throwing exceptions. This makes error handling explicit\n * and predictable.\n *\n * @example\n * function parseEvent(input: unknown): Result<Event, AdapterError> {\n * if (!input) {\n * return adapterErr('input is required', 'missing_required_field');\n * }\n * return ok({ ... });\n * }\n */\nexport type Result<T, E = AdapterError> = { ok: true; value: T } | { ok: false; error: E };\n\n/**\n * Create a success result\n */\nexport function ok<T>(value: T): Result<T, never> {\n return { ok: true, value };\n}\n\n/**\n * Create a generic error result\n */\nexport function err<E>(error: E): Result<never, E> {\n return { ok: false, error };\n}\n\n/**\n * Create an adapter error result (convenience helper)\n *\n * @param message - Human-readable error message\n * @param code - Machine-readable error code\n * @param field - Optional field name that caused the error\n */\nexport function adapterErr(\n message: string,\n code: AdapterErrorCode,\n field?: string\n): Result<never, AdapterError> {\n return err({ code, message, field });\n}\n\n/**\n * Check if result is ok (type guard)\n */\nexport function isOk<T, E>(result: Result<T, E>): result is { ok: true; value: T } {\n return result.ok;\n}\n\n/**\n * Check if result is error (type guard)\n */\nexport function isErr<T, E>(result: Result<T, E>): result is { ok: false; error: E } {\n return !result.ok;\n}\n\n/**\n * Map over a successful result\n *\n * @example\n * const result = ok(5);\n * const doubled = map(result, x => x * 2); // ok(10)\n */\nexport function map<T, U, E>(result: Result<T, E>, fn: (value: T) => U): Result<U, E> {\n return result.ok ? ok(fn(result.value)) : result;\n}\n\n/**\n * Map over an error result\n *\n * @example\n * const result = err({ message: 'oops' });\n * const mapped = mapErr(result, e => ({ ...e, prefix: 'Error: ' }));\n */\nexport function mapErr<T, E, F>(result: Result<T, E>, fn: (error: E) => F): Result<T, F> {\n return result.ok ? result : err(fn(result.error));\n}\n\n/**\n * Chain results (flatMap/bind)\n *\n * @example\n * const parseNumber = (s: string): Result<number, string> => {\n * const n = parseInt(s);\n * return isNaN(n) ? err('not a number') : ok(n);\n * };\n *\n * const result = chain(ok('42'), parseNumber); // ok(42)\n */\nexport function chain<T, U, E>(result: Result<T, E>, fn: (value: T) => Result<U, E>): Result<U, E> {\n return result.ok ? fn(result.value) : result;\n}\n\n/**\n * Unwrap a result, throwing if it's an error\n *\n * Use sparingly - prefer explicit error handling.\n *\n * @throws The error value if result is an error\n */\nexport function unwrap<T, E>(result: Result<T, E>): T {\n if (result.ok) {\n return result.value;\n }\n throw result.error;\n}\n\n/**\n * Unwrap a result with a default value for errors\n */\nexport function unwrapOr<T, E>(result: Result<T, E>, defaultValue: T): T {\n return result.ok ? result.value : defaultValue;\n}\n","/**\n * Shared validators for PEAC payment rail adapters\n *\n * These validators enforce consistent validation logic across all adapters.\n * They follow the \"never throws\" pattern using Result types.\n */\n\nimport { adapterErr, ok, type Result } from './result.js';\nimport type { AdapterError } from './types.js';\n\n/**\n * Validate required string field\n *\n * @param value - Value to validate\n * @param fieldName - Field name for error messages\n * @returns Result with string value or error\n */\nexport function requireString(value: unknown, fieldName: string): Result<string, AdapterError> {\n if (typeof value !== 'string' || value.trim() === '') {\n return adapterErr(\n `${fieldName} is required and must be a non-empty string`,\n 'missing_required_field',\n fieldName\n );\n }\n return ok(value);\n}\n\n/**\n * Validate optional string field\n *\n * @param value - Value to validate\n * @param fieldName - Field name for error messages\n * @returns Result with string value, undefined, or error\n */\nexport function optionalString(\n value: unknown,\n fieldName: string\n): Result<string | undefined, AdapterError> {\n if (value === undefined || value === null) {\n return ok(undefined);\n }\n if (typeof value !== 'string') {\n return adapterErr(`${fieldName} must be a string if provided`, 'validation_error', fieldName);\n }\n return ok(value);\n}\n\n/**\n * Validate required number field\n *\n * @param value - Value to validate\n * @param fieldName - Field name for error messages\n * @returns Result with number value or error\n */\nexport function requireNumber(value: unknown, fieldName: string): Result<number, AdapterError> {\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n return adapterErr(`${fieldName} must be a finite number`, 'validation_error', fieldName);\n }\n return ok(value);\n}\n\n/**\n * Validate amount (must be safe non-negative integer in minor units)\n *\n * @param value - Value to validate\n * @returns Result with amount or error\n */\nexport function requireAmount(value: unknown): Result<number, AdapterError> {\n if (typeof value !== 'number') {\n return adapterErr('amount must be a number', 'invalid_amount', 'amount');\n }\n if (!Number.isSafeInteger(value)) {\n return adapterErr('amount must be a safe integer', 'invalid_amount', 'amount');\n }\n if (value < 0) {\n return adapterErr('amount must be non-negative', 'invalid_amount', 'amount');\n }\n return ok(value);\n}\n\n/**\n * Validate currency code (ISO 4217, uppercase)\n *\n * @param value - Value to validate\n * @returns Result with normalized currency code or error\n */\nexport function requireCurrency(value: unknown): Result<string, AdapterError> {\n if (typeof value !== 'string') {\n return adapterErr('currency must be a string', 'invalid_currency', 'currency');\n }\n const normalized = value.toUpperCase();\n if (!/^[A-Z]{3}$/.test(normalized)) {\n return adapterErr(\n 'currency must be a valid ISO 4217 code (3 uppercase letters)',\n 'invalid_currency',\n 'currency'\n );\n }\n return ok(normalized);\n}\n\n/**\n * Validate optional network identifier (CAIP-2 format preferred)\n *\n * @param value - Value to validate\n * @returns Result with network string, undefined, or error\n */\nexport function optionalNetwork(value: unknown): Result<string | undefined, AdapterError> {\n if (value === undefined || value === null) {\n return ok(undefined);\n }\n if (typeof value !== 'string' || value.trim() === '') {\n return adapterErr(\n 'network must be a non-empty string if provided',\n 'invalid_network',\n 'network'\n );\n }\n return ok(value);\n}\n\n/**\n * Parse object safely (for webhook payloads)\n *\n * @param value - Value to validate\n * @param fieldName - Field name for error messages\n * @returns Result with object or error\n */\nexport function requireObject(\n value: unknown,\n fieldName: string = 'input'\n): Result<Record<string, unknown>, AdapterError> {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return adapterErr(`${fieldName} must be a non-null object`, 'parse_error', fieldName);\n }\n return ok(value as Record<string, unknown>);\n}\n\n/**\n * Validate optional timestamp (ISO 8601 string or Unix seconds)\n *\n * @param value - Value to validate\n * @returns Result with ISO 8601 string, undefined, or error\n */\nexport function optionalTimestamp(value: unknown): Result<string | undefined, AdapterError> {\n if (value === undefined || value === null) {\n return ok(undefined);\n }\n if (typeof value === 'string') {\n // Accept ISO 8601 strings as-is\n return ok(value);\n }\n if (typeof value === 'number' && Number.isSafeInteger(value) && value > 0) {\n // Convert Unix seconds to ISO string\n return ok(new Date(value * 1000).toISOString());\n }\n return adapterErr(\n 'timestamp must be an ISO 8601 string or Unix seconds',\n 'validation_error',\n 'timestamp'\n );\n}\n\n/**\n * Validate optional boolean field\n *\n * @param value - Value to validate\n * @param fieldName - Field name for error messages\n * @returns Result with boolean value, undefined, or error\n */\nexport function optionalBoolean(\n value: unknown,\n fieldName: string\n): Result<boolean | undefined, AdapterError> {\n if (value === undefined || value === null) {\n return ok(undefined);\n }\n if (typeof value !== 'boolean') {\n return adapterErr(`${fieldName} must be a boolean if provided`, 'validation_error', fieldName);\n }\n return ok(value);\n}\n\n/**\n * Validate enum value\n *\n * @param value - Value to validate\n * @param allowed - Array of allowed values\n * @param fieldName - Field name for error messages\n * @returns Result with validated value or error\n */\nexport function requireEnum<T extends string>(\n value: unknown,\n allowed: readonly T[],\n fieldName: string\n): Result<T, AdapterError> {\n if (typeof value !== 'string') {\n return adapterErr(`${fieldName} must be a string`, 'validation_error', fieldName);\n }\n if (!allowed.includes(value as T)) {\n return adapterErr(\n `${fieldName} must be one of: ${allowed.join(', ')}`,\n 'validation_error',\n fieldName\n );\n }\n return ok(value as T);\n}\n\n/**\n * Validate optional enum value\n *\n * @param value - Value to validate\n * @param allowed - Array of allowed values\n * @param fieldName - Field name for error messages\n * @returns Result with validated value, undefined, or error\n */\nexport function optionalEnum<T extends string>(\n value: unknown,\n allowed: readonly T[],\n fieldName: string\n): Result<T | undefined, AdapterError> {\n if (value === undefined || value === null) {\n return ok(undefined);\n }\n return requireEnum(value, allowed, fieldName);\n}\n","/**\n * Mapper-boundary finality-synthesis guard.\n *\n * Commerce mappings preserve raw upstream artifacts and MUST NOT synthesize\n * payment finality (authorization, capture, settlement, refund, void,\n * chargeback) from non-payment artifacts or lifecycle states alone.\n *\n * This module provides the runtime guard that callers in commerce mappings\n * use to enforce that rule at the mapper boundary. It is deliberately\n * dependency-light and emits a stable string code via MapperBoundaryError\n * rather than registering a new wire-level error code.\n */\n\n/**\n * Strictness mode for commerce mappers.\n *\n * - `strict` - reject any synthesis attempt; reject silent fallbacks\n * (currency='UNKNOWN', defaulted env).\n * - `interop` - emit a deprecation warning instead of rejecting; preserves\n * current consumer behavior. Default.\n * - `legacy` - preserve historical behavior with no warning. Reserved for\n * callers that have migration plans recorded elsewhere.\n */\nexport type StrictnessMode = 'strict' | 'interop' | 'legacy';\n\n/**\n * Stable string identifier for the mapper-boundary finality-synthesis\n * violation. NOT a wire-level error code; consumers may switch on this\n * value to map to caller-specific error reporting.\n */\nexport const COMMERCE_FINALITY_SYNTHESIS_CODE = 'commerce.finality_synthesis_blocked' as const;\n\nexport type MapperBoundaryErrorCode = typeof COMMERCE_FINALITY_SYNTHESIS_CODE;\n\nexport interface MapperBoundaryErrorInit {\n code: MapperBoundaryErrorCode;\n pointer?: string;\n upstreamArtifactHash?: string;\n reason?: string;\n}\n\n/**\n * Error thrown by mapper-boundary guards. Plain class, no schema dependency.\n * Carries a stable `code` and optional pointer + upstream-artifact-hash\n * fields to help callers correlate the failure.\n */\nexport class MapperBoundaryError extends Error {\n readonly code: MapperBoundaryErrorCode;\n readonly pointer?: string;\n readonly upstreamArtifactHash?: string;\n\n constructor(init: MapperBoundaryErrorInit) {\n const message = init.reason\n ? `${init.code}: ${init.reason}`\n : `${init.code}: mapper-boundary guard rejected synthesis`;\n super(message);\n this.name = 'MapperBoundaryError';\n this.code = init.code;\n this.pointer = init.pointer;\n this.upstreamArtifactHash = init.upstreamArtifactHash;\n }\n}\n\n/**\n * Closed enum of commerce events that imply finality and therefore require\n * an explicit upstream payment artifact when present in mapper input.\n */\nconst FINALITY_EVENTS = new Set([\n 'authorization',\n 'capture',\n 'settlement',\n 'refund',\n 'void',\n 'chargeback',\n]);\n\nexport type CommerceFinalityEvent =\n | 'authorization'\n | 'capture'\n | 'settlement'\n | 'refund'\n | 'void'\n | 'chargeback';\n\nexport interface FinalityGuardInput {\n /**\n * The candidate commerce `event` value (or `undefined` if unset). When\n * unset, the guard is a no-op.\n */\n event?: string | undefined;\n\n /**\n * Whether the upstream artifact explicitly proves the claimed finality.\n * Mappers MUST set this from a definite read of upstream-supplied data,\n * NOT from inferred lifecycle state.\n */\n hasExplicitUpstreamArtifact: boolean;\n\n /**\n * The currency code as read from upstream. Mappers MUST set this; callers\n * MUST NOT silently fall back to `'UNKNOWN'`. In strict mode, an empty,\n * `'UNKNOWN'`, or non-string value rejects.\n */\n currency?: string;\n\n /**\n * The environment discriminant as read from upstream. Mappers MUST set\n * this when known; callers MUST NOT silently default. In strict mode, an\n * unset or non-`live`/`test` value rejects.\n */\n env?: 'live' | 'test' | string | undefined;\n\n /**\n * Whether the env was explicitly asserted by upstream (vs defaulted).\n */\n envExplicit?: boolean;\n}\n\nexport interface FinalityGuardOptions {\n mode?: StrictnessMode;\n pointer?: string;\n upstreamArtifactHash?: string;\n /**\n * Optional warning sink for `interop` mode. Defaults to a no-op.\n */\n warn?: (message: string) => void;\n}\n\nconst DEFAULT_MODE: StrictnessMode = 'interop';\n\nfunction noopWarn(_message: string): void {\n /* no-op */\n}\n\n/**\n * Mapper-boundary finality-synthesis guard.\n *\n * Throws `MapperBoundaryError` when:\n * - `event` is one of the finality-bearing values AND\n * `hasExplicitUpstreamArtifact` is false (any mode).\n * - `currency` is missing, empty, or `'UNKNOWN'` and mode is `strict`.\n * - `env` is missing or `envExplicit` is false and mode is `strict`.\n *\n * In `interop` mode, the second and third conditions emit a warning via\n * the supplied `warn` sink instead of throwing. In `legacy` mode, only\n * the first condition throws; the second and third are silent.\n *\n * No-ops when `event` is unset (the common discovery / capability path).\n */\nexport function assertExplicitFinality(\n input: FinalityGuardInput,\n options: FinalityGuardOptions = {}\n): void {\n const mode: StrictnessMode = options.mode ?? DEFAULT_MODE;\n const warn = options.warn ?? noopWarn;\n const pointer = options.pointer;\n const upstreamArtifactHash = options.upstreamArtifactHash;\n\n // Rule 1: finality event without explicit upstream artifact - reject in all modes.\n if (input.event !== undefined && FINALITY_EVENTS.has(input.event)) {\n if (!input.hasExplicitUpstreamArtifact) {\n throw new MapperBoundaryError({\n code: COMMERCE_FINALITY_SYNTHESIS_CODE,\n pointer,\n upstreamArtifactHash,\n reason: `event=${JSON.stringify(input.event)} requires an explicit upstream payment artifact`,\n });\n }\n }\n\n // Rule 2: silent currency fallback - reject in strict, warn in interop, silent in legacy.\n const isMissingCurrency =\n typeof input.currency !== 'string' ||\n input.currency.length === 0 ||\n input.currency === 'UNKNOWN';\n if (isMissingCurrency) {\n if (mode === 'strict') {\n throw new MapperBoundaryError({\n code: COMMERCE_FINALITY_SYNTHESIS_CODE,\n pointer,\n upstreamArtifactHash,\n reason:\n 'currency missing or fallback (UNKNOWN); strict mode requires upstream-asserted currency',\n });\n }\n if (mode === 'interop') {\n warn(\n 'commerce mapper: currency missing or fallback (UNKNOWN). Strict mode will reject this in v0.13.0+. Provide an upstream-asserted currency.'\n );\n }\n }\n\n // Rule 3: defaulted env - reject in strict, warn in interop, silent in legacy.\n const envIsExplicit = input.envExplicit === true;\n const envIsKnown = input.env === 'live' || input.env === 'test';\n if (!envIsKnown || !envIsExplicit) {\n if (mode === 'strict') {\n throw new MapperBoundaryError({\n code: COMMERCE_FINALITY_SYNTHESIS_CODE,\n pointer,\n upstreamArtifactHash,\n reason: 'env missing or defaulted; strict mode requires upstream-asserted env (live|test)',\n });\n }\n if (mode === 'interop') {\n warn(\n 'commerce mapper: env missing or defaulted. Strict mode will reject this in v0.13.0+. Provide an upstream-asserted env.'\n );\n }\n }\n}\n\n/**\n * Returns whether the given event is one of the finality-bearing commerce\n * events. Useful for callers that want to short-circuit before assembling\n * full guard input.\n */\nexport function isFinalityEvent(event: string | undefined): event is CommerceFinalityEvent {\n return event !== undefined && FINALITY_EVENTS.has(event);\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -11,4 +11,6 @@ export { type Result, ok, err, adapterErr, isOk, isErr, map, mapErr, chain, unwr
|
|
|
11
11
|
export type { AdapterError, AdapterErrorCode } from './types.js';
|
|
12
12
|
export { requireString, optionalString, requireNumber, requireAmount, requireCurrency, optionalNetwork, requireObject, optionalTimestamp, optionalBoolean, requireEnum, optionalEnum, } from './validators.js';
|
|
13
13
|
export type { NormalizedTerms, NormalizedSettlement, TermsVerification, SettlementVerification, VerificationError, PaymentProofRecord, VerificationContext, PaymentProofAdapter, CryptoVerifier, } from './payment-proof.js';
|
|
14
|
+
export { COMMERCE_FINALITY_SYNTHESIS_CODE, MapperBoundaryError, assertExplicitFinality, isFinalityEvent, } from './finality.js';
|
|
15
|
+
export type { StrictnessMode, MapperBoundaryErrorCode, MapperBoundaryErrorInit, CommerceFinalityEvent, FinalityGuardInput, FinalityGuardOptions, } from './finality.js';
|
|
14
16
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAGpF,OAAO,EACL,KAAK,MAAM,EACX,EAAE,EACF,GAAG,EACH,UAAU,EACV,IAAI,EACJ,KAAK,EACL,GAAG,EACH,MAAM,EACN,KAAK,EACL,MAAM,EACN,QAAQ,GACT,MAAM,aAAa,CAAC;AAGrB,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAGjE,OAAO,EACL,aAAa,EACb,cAAc,EACd,aAAa,EACb,aAAa,EACb,eAAe,EACf,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,WAAW,EACX,YAAY,GACb,MAAM,iBAAiB,CAAC;AAGzB,YAAY,EACV,eAAe,EACf,oBAAoB,EACpB,iBAAiB,EACjB,sBAAsB,EACtB,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,EACnB,cAAc,GACf,MAAM,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAGpF,OAAO,EACL,KAAK,MAAM,EACX,EAAE,EACF,GAAG,EACH,UAAU,EACV,IAAI,EACJ,KAAK,EACL,GAAG,EACH,MAAM,EACN,KAAK,EACL,MAAM,EACN,QAAQ,GACT,MAAM,aAAa,CAAC;AAGrB,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAGjE,OAAO,EACL,aAAa,EACb,cAAc,EACd,aAAa,EACb,aAAa,EACb,eAAe,EACf,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,WAAW,EACX,YAAY,GACb,MAAM,iBAAiB,CAAC;AAGzB,YAAY,EACV,eAAe,EACf,oBAAoB,EACpB,iBAAiB,EACjB,sBAAsB,EACtB,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,EACnB,cAAc,GACf,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,gCAAgC,EAChC,mBAAmB,EACnB,sBAAsB,EACtB,eAAe,GAChB,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,cAAc,EACd,uBAAuB,EACvB,uBAAuB,EACvB,qBAAqB,EACrB,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,eAAe,CAAC"}
|
package/dist/index.mjs
CHANGED
|
@@ -149,6 +149,85 @@ function optionalEnum(value, allowed, fieldName) {
|
|
|
149
149
|
return requireEnum(value, allowed, fieldName);
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
-
|
|
152
|
+
// src/finality.ts
|
|
153
|
+
var COMMERCE_FINALITY_SYNTHESIS_CODE = "commerce.finality_synthesis_blocked";
|
|
154
|
+
var MapperBoundaryError = class extends Error {
|
|
155
|
+
code;
|
|
156
|
+
pointer;
|
|
157
|
+
upstreamArtifactHash;
|
|
158
|
+
constructor(init) {
|
|
159
|
+
const message = init.reason ? `${init.code}: ${init.reason}` : `${init.code}: mapper-boundary guard rejected synthesis`;
|
|
160
|
+
super(message);
|
|
161
|
+
this.name = "MapperBoundaryError";
|
|
162
|
+
this.code = init.code;
|
|
163
|
+
this.pointer = init.pointer;
|
|
164
|
+
this.upstreamArtifactHash = init.upstreamArtifactHash;
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
var FINALITY_EVENTS = /* @__PURE__ */ new Set([
|
|
168
|
+
"authorization",
|
|
169
|
+
"capture",
|
|
170
|
+
"settlement",
|
|
171
|
+
"refund",
|
|
172
|
+
"void",
|
|
173
|
+
"chargeback"
|
|
174
|
+
]);
|
|
175
|
+
var DEFAULT_MODE = "interop";
|
|
176
|
+
function noopWarn(_message) {
|
|
177
|
+
}
|
|
178
|
+
function assertExplicitFinality(input, options = {}) {
|
|
179
|
+
const mode = options.mode ?? DEFAULT_MODE;
|
|
180
|
+
const warn = options.warn ?? noopWarn;
|
|
181
|
+
const pointer = options.pointer;
|
|
182
|
+
const upstreamArtifactHash = options.upstreamArtifactHash;
|
|
183
|
+
if (input.event !== void 0 && FINALITY_EVENTS.has(input.event)) {
|
|
184
|
+
if (!input.hasExplicitUpstreamArtifact) {
|
|
185
|
+
throw new MapperBoundaryError({
|
|
186
|
+
code: COMMERCE_FINALITY_SYNTHESIS_CODE,
|
|
187
|
+
pointer,
|
|
188
|
+
upstreamArtifactHash,
|
|
189
|
+
reason: `event=${JSON.stringify(input.event)} requires an explicit upstream payment artifact`
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
const isMissingCurrency = typeof input.currency !== "string" || input.currency.length === 0 || input.currency === "UNKNOWN";
|
|
194
|
+
if (isMissingCurrency) {
|
|
195
|
+
if (mode === "strict") {
|
|
196
|
+
throw new MapperBoundaryError({
|
|
197
|
+
code: COMMERCE_FINALITY_SYNTHESIS_CODE,
|
|
198
|
+
pointer,
|
|
199
|
+
upstreamArtifactHash,
|
|
200
|
+
reason: "currency missing or fallback (UNKNOWN); strict mode requires upstream-asserted currency"
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
if (mode === "interop") {
|
|
204
|
+
warn(
|
|
205
|
+
"commerce mapper: currency missing or fallback (UNKNOWN). Strict mode will reject this in v0.13.0+. Provide an upstream-asserted currency."
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
const envIsExplicit = input.envExplicit === true;
|
|
210
|
+
const envIsKnown = input.env === "live" || input.env === "test";
|
|
211
|
+
if (!envIsKnown || !envIsExplicit) {
|
|
212
|
+
if (mode === "strict") {
|
|
213
|
+
throw new MapperBoundaryError({
|
|
214
|
+
code: COMMERCE_FINALITY_SYNTHESIS_CODE,
|
|
215
|
+
pointer,
|
|
216
|
+
upstreamArtifactHash,
|
|
217
|
+
reason: "env missing or defaulted; strict mode requires upstream-asserted env (live|test)"
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
if (mode === "interop") {
|
|
221
|
+
warn(
|
|
222
|
+
"commerce mapper: env missing or defaulted. Strict mode will reject this in v0.13.0+. Provide an upstream-asserted env."
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
function isFinalityEvent(event) {
|
|
228
|
+
return event !== void 0 && FINALITY_EVENTS.has(event);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export { COMMERCE_FINALITY_SYNTHESIS_CODE, MapperBoundaryError, adapterErr, assertExplicitFinality, chain, err, isErr, isFinalityEvent, isOk, map, mapErr, ok, optionalBoolean, optionalEnum, optionalNetwork, optionalString, optionalTimestamp, requireAmount, requireCurrency, requireEnum, requireNumber, requireObject, requireString, unwrap, unwrapOr };
|
|
153
232
|
//# sourceMappingURL=index.mjs.map
|
|
154
233
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/result.ts","../src/validators.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Result type utilities for adapter operations\n *\n * Enforces \"never throws\" invariant - all adapter functions return Result<T>.\n */\n\nimport type { AdapterError, AdapterErrorCode } from './types.js';\n\n/**\n * Result type for adapter operations\n *\n * All adapter parsing/validation functions should return this type\n * instead of throwing exceptions. This makes error handling explicit\n * and predictable.\n *\n * @example\n * function parseEvent(input: unknown): Result<Event, AdapterError> {\n * if (!input) {\n * return adapterErr('input is required', 'missing_required_field');\n * }\n * return ok({ ... });\n * }\n */\nexport type Result<T, E = AdapterError> = { ok: true; value: T } | { ok: false; error: E };\n\n/**\n * Create a success result\n */\nexport function ok<T>(value: T): Result<T, never> {\n return { ok: true, value };\n}\n\n/**\n * Create a generic error result\n */\nexport function err<E>(error: E): Result<never, E> {\n return { ok: false, error };\n}\n\n/**\n * Create an adapter error result (convenience helper)\n *\n * @param message - Human-readable error message\n * @param code - Machine-readable error code\n * @param field - Optional field name that caused the error\n */\nexport function adapterErr(\n message: string,\n code: AdapterErrorCode,\n field?: string\n): Result<never, AdapterError> {\n return err({ code, message, field });\n}\n\n/**\n * Check if result is ok (type guard)\n */\nexport function isOk<T, E>(result: Result<T, E>): result is { ok: true; value: T } {\n return result.ok;\n}\n\n/**\n * Check if result is error (type guard)\n */\nexport function isErr<T, E>(result: Result<T, E>): result is { ok: false; error: E } {\n return !result.ok;\n}\n\n/**\n * Map over a successful result\n *\n * @example\n * const result = ok(5);\n * const doubled = map(result, x => x * 2); // ok(10)\n */\nexport function map<T, U, E>(result: Result<T, E>, fn: (value: T) => U): Result<U, E> {\n return result.ok ? ok(fn(result.value)) : result;\n}\n\n/**\n * Map over an error result\n *\n * @example\n * const result = err({ message: 'oops' });\n * const mapped = mapErr(result, e => ({ ...e, prefix: 'Error: ' }));\n */\nexport function mapErr<T, E, F>(result: Result<T, E>, fn: (error: E) => F): Result<T, F> {\n return result.ok ? result : err(fn(result.error));\n}\n\n/**\n * Chain results (flatMap/bind)\n *\n * @example\n * const parseNumber = (s: string): Result<number, string> => {\n * const n = parseInt(s);\n * return isNaN(n) ? err('not a number') : ok(n);\n * };\n *\n * const result = chain(ok('42'), parseNumber); // ok(42)\n */\nexport function chain<T, U, E>(result: Result<T, E>, fn: (value: T) => Result<U, E>): Result<U, E> {\n return result.ok ? fn(result.value) : result;\n}\n\n/**\n * Unwrap a result, throwing if it's an error\n *\n * Use sparingly - prefer explicit error handling.\n *\n * @throws The error value if result is an error\n */\nexport function unwrap<T, E>(result: Result<T, E>): T {\n if (result.ok) {\n return result.value;\n }\n throw result.error;\n}\n\n/**\n * Unwrap a result with a default value for errors\n */\nexport function unwrapOr<T, E>(result: Result<T, E>, defaultValue: T): T {\n return result.ok ? result.value : defaultValue;\n}\n","/**\n * Shared validators for PEAC payment rail adapters\n *\n * These validators enforce consistent validation logic across all adapters.\n * They follow the \"never throws\" pattern using Result types.\n */\n\nimport { adapterErr, ok, type Result } from './result.js';\nimport type { AdapterError } from './types.js';\n\n/**\n * Validate required string field\n *\n * @param value - Value to validate\n * @param fieldName - Field name for error messages\n * @returns Result with string value or error\n */\nexport function requireString(value: unknown, fieldName: string): Result<string, AdapterError> {\n if (typeof value !== 'string' || value.trim() === '') {\n return adapterErr(\n `${fieldName} is required and must be a non-empty string`,\n 'missing_required_field',\n fieldName\n );\n }\n return ok(value);\n}\n\n/**\n * Validate optional string field\n *\n * @param value - Value to validate\n * @param fieldName - Field name for error messages\n * @returns Result with string value, undefined, or error\n */\nexport function optionalString(\n value: unknown,\n fieldName: string\n): Result<string | undefined, AdapterError> {\n if (value === undefined || value === null) {\n return ok(undefined);\n }\n if (typeof value !== 'string') {\n return adapterErr(`${fieldName} must be a string if provided`, 'validation_error', fieldName);\n }\n return ok(value);\n}\n\n/**\n * Validate required number field\n *\n * @param value - Value to validate\n * @param fieldName - Field name for error messages\n * @returns Result with number value or error\n */\nexport function requireNumber(value: unknown, fieldName: string): Result<number, AdapterError> {\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n return adapterErr(`${fieldName} must be a finite number`, 'validation_error', fieldName);\n }\n return ok(value);\n}\n\n/**\n * Validate amount (must be safe non-negative integer in minor units)\n *\n * @param value - Value to validate\n * @returns Result with amount or error\n */\nexport function requireAmount(value: unknown): Result<number, AdapterError> {\n if (typeof value !== 'number') {\n return adapterErr('amount must be a number', 'invalid_amount', 'amount');\n }\n if (!Number.isSafeInteger(value)) {\n return adapterErr('amount must be a safe integer', 'invalid_amount', 'amount');\n }\n if (value < 0) {\n return adapterErr('amount must be non-negative', 'invalid_amount', 'amount');\n }\n return ok(value);\n}\n\n/**\n * Validate currency code (ISO 4217, uppercase)\n *\n * @param value - Value to validate\n * @returns Result with normalized currency code or error\n */\nexport function requireCurrency(value: unknown): Result<string, AdapterError> {\n if (typeof value !== 'string') {\n return adapterErr('currency must be a string', 'invalid_currency', 'currency');\n }\n const normalized = value.toUpperCase();\n if (!/^[A-Z]{3}$/.test(normalized)) {\n return adapterErr(\n 'currency must be a valid ISO 4217 code (3 uppercase letters)',\n 'invalid_currency',\n 'currency'\n );\n }\n return ok(normalized);\n}\n\n/**\n * Validate optional network identifier (CAIP-2 format preferred)\n *\n * @param value - Value to validate\n * @returns Result with network string, undefined, or error\n */\nexport function optionalNetwork(value: unknown): Result<string | undefined, AdapterError> {\n if (value === undefined || value === null) {\n return ok(undefined);\n }\n if (typeof value !== 'string' || value.trim() === '') {\n return adapterErr(\n 'network must be a non-empty string if provided',\n 'invalid_network',\n 'network'\n );\n }\n return ok(value);\n}\n\n/**\n * Parse object safely (for webhook payloads)\n *\n * @param value - Value to validate\n * @param fieldName - Field name for error messages\n * @returns Result with object or error\n */\nexport function requireObject(\n value: unknown,\n fieldName: string = 'input'\n): Result<Record<string, unknown>, AdapterError> {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return adapterErr(`${fieldName} must be a non-null object`, 'parse_error', fieldName);\n }\n return ok(value as Record<string, unknown>);\n}\n\n/**\n * Validate optional timestamp (ISO 8601 string or Unix seconds)\n *\n * @param value - Value to validate\n * @returns Result with ISO 8601 string, undefined, or error\n */\nexport function optionalTimestamp(value: unknown): Result<string | undefined, AdapterError> {\n if (value === undefined || value === null) {\n return ok(undefined);\n }\n if (typeof value === 'string') {\n // Accept ISO 8601 strings as-is\n return ok(value);\n }\n if (typeof value === 'number' && Number.isSafeInteger(value) && value > 0) {\n // Convert Unix seconds to ISO string\n return ok(new Date(value * 1000).toISOString());\n }\n return adapterErr(\n 'timestamp must be an ISO 8601 string or Unix seconds',\n 'validation_error',\n 'timestamp'\n );\n}\n\n/**\n * Validate optional boolean field\n *\n * @param value - Value to validate\n * @param fieldName - Field name for error messages\n * @returns Result with boolean value, undefined, or error\n */\nexport function optionalBoolean(\n value: unknown,\n fieldName: string\n): Result<boolean | undefined, AdapterError> {\n if (value === undefined || value === null) {\n return ok(undefined);\n }\n if (typeof value !== 'boolean') {\n return adapterErr(`${fieldName} must be a boolean if provided`, 'validation_error', fieldName);\n }\n return ok(value);\n}\n\n/**\n * Validate enum value\n *\n * @param value - Value to validate\n * @param allowed - Array of allowed values\n * @param fieldName - Field name for error messages\n * @returns Result with validated value or error\n */\nexport function requireEnum<T extends string>(\n value: unknown,\n allowed: readonly T[],\n fieldName: string\n): Result<T, AdapterError> {\n if (typeof value !== 'string') {\n return adapterErr(`${fieldName} must be a string`, 'validation_error', fieldName);\n }\n if (!allowed.includes(value as T)) {\n return adapterErr(\n `${fieldName} must be one of: ${allowed.join(', ')}`,\n 'validation_error',\n fieldName\n );\n }\n return ok(value as T);\n}\n\n/**\n * Validate optional enum value\n *\n * @param value - Value to validate\n * @param allowed - Array of allowed values\n * @param fieldName - Field name for error messages\n * @returns Result with validated value, undefined, or error\n */\nexport function optionalEnum<T extends string>(\n value: unknown,\n allowed: readonly T[],\n fieldName: string\n): Result<T | undefined, AdapterError> {\n if (value === undefined || value === null) {\n return ok(undefined);\n }\n return requireEnum(value, allowed, fieldName);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/result.ts","../src/validators.ts","../src/finality.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Result type utilities for adapter operations\n *\n * Enforces \"never throws\" invariant - all adapter functions return Result<T>.\n */\n\nimport type { AdapterError, AdapterErrorCode } from './types.js';\n\n/**\n * Result type for adapter operations\n *\n * All adapter parsing/validation functions should return this type\n * instead of throwing exceptions. This makes error handling explicit\n * and predictable.\n *\n * @example\n * function parseEvent(input: unknown): Result<Event, AdapterError> {\n * if (!input) {\n * return adapterErr('input is required', 'missing_required_field');\n * }\n * return ok({ ... });\n * }\n */\nexport type Result<T, E = AdapterError> = { ok: true; value: T } | { ok: false; error: E };\n\n/**\n * Create a success result\n */\nexport function ok<T>(value: T): Result<T, never> {\n return { ok: true, value };\n}\n\n/**\n * Create a generic error result\n */\nexport function err<E>(error: E): Result<never, E> {\n return { ok: false, error };\n}\n\n/**\n * Create an adapter error result (convenience helper)\n *\n * @param message - Human-readable error message\n * @param code - Machine-readable error code\n * @param field - Optional field name that caused the error\n */\nexport function adapterErr(\n message: string,\n code: AdapterErrorCode,\n field?: string\n): Result<never, AdapterError> {\n return err({ code, message, field });\n}\n\n/**\n * Check if result is ok (type guard)\n */\nexport function isOk<T, E>(result: Result<T, E>): result is { ok: true; value: T } {\n return result.ok;\n}\n\n/**\n * Check if result is error (type guard)\n */\nexport function isErr<T, E>(result: Result<T, E>): result is { ok: false; error: E } {\n return !result.ok;\n}\n\n/**\n * Map over a successful result\n *\n * @example\n * const result = ok(5);\n * const doubled = map(result, x => x * 2); // ok(10)\n */\nexport function map<T, U, E>(result: Result<T, E>, fn: (value: T) => U): Result<U, E> {\n return result.ok ? ok(fn(result.value)) : result;\n}\n\n/**\n * Map over an error result\n *\n * @example\n * const result = err({ message: 'oops' });\n * const mapped = mapErr(result, e => ({ ...e, prefix: 'Error: ' }));\n */\nexport function mapErr<T, E, F>(result: Result<T, E>, fn: (error: E) => F): Result<T, F> {\n return result.ok ? result : err(fn(result.error));\n}\n\n/**\n * Chain results (flatMap/bind)\n *\n * @example\n * const parseNumber = (s: string): Result<number, string> => {\n * const n = parseInt(s);\n * return isNaN(n) ? err('not a number') : ok(n);\n * };\n *\n * const result = chain(ok('42'), parseNumber); // ok(42)\n */\nexport function chain<T, U, E>(result: Result<T, E>, fn: (value: T) => Result<U, E>): Result<U, E> {\n return result.ok ? fn(result.value) : result;\n}\n\n/**\n * Unwrap a result, throwing if it's an error\n *\n * Use sparingly - prefer explicit error handling.\n *\n * @throws The error value if result is an error\n */\nexport function unwrap<T, E>(result: Result<T, E>): T {\n if (result.ok) {\n return result.value;\n }\n throw result.error;\n}\n\n/**\n * Unwrap a result with a default value for errors\n */\nexport function unwrapOr<T, E>(result: Result<T, E>, defaultValue: T): T {\n return result.ok ? result.value : defaultValue;\n}\n","/**\n * Shared validators for PEAC payment rail adapters\n *\n * These validators enforce consistent validation logic across all adapters.\n * They follow the \"never throws\" pattern using Result types.\n */\n\nimport { adapterErr, ok, type Result } from './result.js';\nimport type { AdapterError } from './types.js';\n\n/**\n * Validate required string field\n *\n * @param value - Value to validate\n * @param fieldName - Field name for error messages\n * @returns Result with string value or error\n */\nexport function requireString(value: unknown, fieldName: string): Result<string, AdapterError> {\n if (typeof value !== 'string' || value.trim() === '') {\n return adapterErr(\n `${fieldName} is required and must be a non-empty string`,\n 'missing_required_field',\n fieldName\n );\n }\n return ok(value);\n}\n\n/**\n * Validate optional string field\n *\n * @param value - Value to validate\n * @param fieldName - Field name for error messages\n * @returns Result with string value, undefined, or error\n */\nexport function optionalString(\n value: unknown,\n fieldName: string\n): Result<string | undefined, AdapterError> {\n if (value === undefined || value === null) {\n return ok(undefined);\n }\n if (typeof value !== 'string') {\n return adapterErr(`${fieldName} must be a string if provided`, 'validation_error', fieldName);\n }\n return ok(value);\n}\n\n/**\n * Validate required number field\n *\n * @param value - Value to validate\n * @param fieldName - Field name for error messages\n * @returns Result with number value or error\n */\nexport function requireNumber(value: unknown, fieldName: string): Result<number, AdapterError> {\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n return adapterErr(`${fieldName} must be a finite number`, 'validation_error', fieldName);\n }\n return ok(value);\n}\n\n/**\n * Validate amount (must be safe non-negative integer in minor units)\n *\n * @param value - Value to validate\n * @returns Result with amount or error\n */\nexport function requireAmount(value: unknown): Result<number, AdapterError> {\n if (typeof value !== 'number') {\n return adapterErr('amount must be a number', 'invalid_amount', 'amount');\n }\n if (!Number.isSafeInteger(value)) {\n return adapterErr('amount must be a safe integer', 'invalid_amount', 'amount');\n }\n if (value < 0) {\n return adapterErr('amount must be non-negative', 'invalid_amount', 'amount');\n }\n return ok(value);\n}\n\n/**\n * Validate currency code (ISO 4217, uppercase)\n *\n * @param value - Value to validate\n * @returns Result with normalized currency code or error\n */\nexport function requireCurrency(value: unknown): Result<string, AdapterError> {\n if (typeof value !== 'string') {\n return adapterErr('currency must be a string', 'invalid_currency', 'currency');\n }\n const normalized = value.toUpperCase();\n if (!/^[A-Z]{3}$/.test(normalized)) {\n return adapterErr(\n 'currency must be a valid ISO 4217 code (3 uppercase letters)',\n 'invalid_currency',\n 'currency'\n );\n }\n return ok(normalized);\n}\n\n/**\n * Validate optional network identifier (CAIP-2 format preferred)\n *\n * @param value - Value to validate\n * @returns Result with network string, undefined, or error\n */\nexport function optionalNetwork(value: unknown): Result<string | undefined, AdapterError> {\n if (value === undefined || value === null) {\n return ok(undefined);\n }\n if (typeof value !== 'string' || value.trim() === '') {\n return adapterErr(\n 'network must be a non-empty string if provided',\n 'invalid_network',\n 'network'\n );\n }\n return ok(value);\n}\n\n/**\n * Parse object safely (for webhook payloads)\n *\n * @param value - Value to validate\n * @param fieldName - Field name for error messages\n * @returns Result with object or error\n */\nexport function requireObject(\n value: unknown,\n fieldName: string = 'input'\n): Result<Record<string, unknown>, AdapterError> {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return adapterErr(`${fieldName} must be a non-null object`, 'parse_error', fieldName);\n }\n return ok(value as Record<string, unknown>);\n}\n\n/**\n * Validate optional timestamp (ISO 8601 string or Unix seconds)\n *\n * @param value - Value to validate\n * @returns Result with ISO 8601 string, undefined, or error\n */\nexport function optionalTimestamp(value: unknown): Result<string | undefined, AdapterError> {\n if (value === undefined || value === null) {\n return ok(undefined);\n }\n if (typeof value === 'string') {\n // Accept ISO 8601 strings as-is\n return ok(value);\n }\n if (typeof value === 'number' && Number.isSafeInteger(value) && value > 0) {\n // Convert Unix seconds to ISO string\n return ok(new Date(value * 1000).toISOString());\n }\n return adapterErr(\n 'timestamp must be an ISO 8601 string or Unix seconds',\n 'validation_error',\n 'timestamp'\n );\n}\n\n/**\n * Validate optional boolean field\n *\n * @param value - Value to validate\n * @param fieldName - Field name for error messages\n * @returns Result with boolean value, undefined, or error\n */\nexport function optionalBoolean(\n value: unknown,\n fieldName: string\n): Result<boolean | undefined, AdapterError> {\n if (value === undefined || value === null) {\n return ok(undefined);\n }\n if (typeof value !== 'boolean') {\n return adapterErr(`${fieldName} must be a boolean if provided`, 'validation_error', fieldName);\n }\n return ok(value);\n}\n\n/**\n * Validate enum value\n *\n * @param value - Value to validate\n * @param allowed - Array of allowed values\n * @param fieldName - Field name for error messages\n * @returns Result with validated value or error\n */\nexport function requireEnum<T extends string>(\n value: unknown,\n allowed: readonly T[],\n fieldName: string\n): Result<T, AdapterError> {\n if (typeof value !== 'string') {\n return adapterErr(`${fieldName} must be a string`, 'validation_error', fieldName);\n }\n if (!allowed.includes(value as T)) {\n return adapterErr(\n `${fieldName} must be one of: ${allowed.join(', ')}`,\n 'validation_error',\n fieldName\n );\n }\n return ok(value as T);\n}\n\n/**\n * Validate optional enum value\n *\n * @param value - Value to validate\n * @param allowed - Array of allowed values\n * @param fieldName - Field name for error messages\n * @returns Result with validated value, undefined, or error\n */\nexport function optionalEnum<T extends string>(\n value: unknown,\n allowed: readonly T[],\n fieldName: string\n): Result<T | undefined, AdapterError> {\n if (value === undefined || value === null) {\n return ok(undefined);\n }\n return requireEnum(value, allowed, fieldName);\n}\n","/**\n * Mapper-boundary finality-synthesis guard.\n *\n * Commerce mappings preserve raw upstream artifacts and MUST NOT synthesize\n * payment finality (authorization, capture, settlement, refund, void,\n * chargeback) from non-payment artifacts or lifecycle states alone.\n *\n * This module provides the runtime guard that callers in commerce mappings\n * use to enforce that rule at the mapper boundary. It is deliberately\n * dependency-light and emits a stable string code via MapperBoundaryError\n * rather than registering a new wire-level error code.\n */\n\n/**\n * Strictness mode for commerce mappers.\n *\n * - `strict` - reject any synthesis attempt; reject silent fallbacks\n * (currency='UNKNOWN', defaulted env).\n * - `interop` - emit a deprecation warning instead of rejecting; preserves\n * current consumer behavior. Default.\n * - `legacy` - preserve historical behavior with no warning. Reserved for\n * callers that have migration plans recorded elsewhere.\n */\nexport type StrictnessMode = 'strict' | 'interop' | 'legacy';\n\n/**\n * Stable string identifier for the mapper-boundary finality-synthesis\n * violation. NOT a wire-level error code; consumers may switch on this\n * value to map to caller-specific error reporting.\n */\nexport const COMMERCE_FINALITY_SYNTHESIS_CODE = 'commerce.finality_synthesis_blocked' as const;\n\nexport type MapperBoundaryErrorCode = typeof COMMERCE_FINALITY_SYNTHESIS_CODE;\n\nexport interface MapperBoundaryErrorInit {\n code: MapperBoundaryErrorCode;\n pointer?: string;\n upstreamArtifactHash?: string;\n reason?: string;\n}\n\n/**\n * Error thrown by mapper-boundary guards. Plain class, no schema dependency.\n * Carries a stable `code` and optional pointer + upstream-artifact-hash\n * fields to help callers correlate the failure.\n */\nexport class MapperBoundaryError extends Error {\n readonly code: MapperBoundaryErrorCode;\n readonly pointer?: string;\n readonly upstreamArtifactHash?: string;\n\n constructor(init: MapperBoundaryErrorInit) {\n const message = init.reason\n ? `${init.code}: ${init.reason}`\n : `${init.code}: mapper-boundary guard rejected synthesis`;\n super(message);\n this.name = 'MapperBoundaryError';\n this.code = init.code;\n this.pointer = init.pointer;\n this.upstreamArtifactHash = init.upstreamArtifactHash;\n }\n}\n\n/**\n * Closed enum of commerce events that imply finality and therefore require\n * an explicit upstream payment artifact when present in mapper input.\n */\nconst FINALITY_EVENTS = new Set([\n 'authorization',\n 'capture',\n 'settlement',\n 'refund',\n 'void',\n 'chargeback',\n]);\n\nexport type CommerceFinalityEvent =\n | 'authorization'\n | 'capture'\n | 'settlement'\n | 'refund'\n | 'void'\n | 'chargeback';\n\nexport interface FinalityGuardInput {\n /**\n * The candidate commerce `event` value (or `undefined` if unset). When\n * unset, the guard is a no-op.\n */\n event?: string | undefined;\n\n /**\n * Whether the upstream artifact explicitly proves the claimed finality.\n * Mappers MUST set this from a definite read of upstream-supplied data,\n * NOT from inferred lifecycle state.\n */\n hasExplicitUpstreamArtifact: boolean;\n\n /**\n * The currency code as read from upstream. Mappers MUST set this; callers\n * MUST NOT silently fall back to `'UNKNOWN'`. In strict mode, an empty,\n * `'UNKNOWN'`, or non-string value rejects.\n */\n currency?: string;\n\n /**\n * The environment discriminant as read from upstream. Mappers MUST set\n * this when known; callers MUST NOT silently default. In strict mode, an\n * unset or non-`live`/`test` value rejects.\n */\n env?: 'live' | 'test' | string | undefined;\n\n /**\n * Whether the env was explicitly asserted by upstream (vs defaulted).\n */\n envExplicit?: boolean;\n}\n\nexport interface FinalityGuardOptions {\n mode?: StrictnessMode;\n pointer?: string;\n upstreamArtifactHash?: string;\n /**\n * Optional warning sink for `interop` mode. Defaults to a no-op.\n */\n warn?: (message: string) => void;\n}\n\nconst DEFAULT_MODE: StrictnessMode = 'interop';\n\nfunction noopWarn(_message: string): void {\n /* no-op */\n}\n\n/**\n * Mapper-boundary finality-synthesis guard.\n *\n * Throws `MapperBoundaryError` when:\n * - `event` is one of the finality-bearing values AND\n * `hasExplicitUpstreamArtifact` is false (any mode).\n * - `currency` is missing, empty, or `'UNKNOWN'` and mode is `strict`.\n * - `env` is missing or `envExplicit` is false and mode is `strict`.\n *\n * In `interop` mode, the second and third conditions emit a warning via\n * the supplied `warn` sink instead of throwing. In `legacy` mode, only\n * the first condition throws; the second and third are silent.\n *\n * No-ops when `event` is unset (the common discovery / capability path).\n */\nexport function assertExplicitFinality(\n input: FinalityGuardInput,\n options: FinalityGuardOptions = {}\n): void {\n const mode: StrictnessMode = options.mode ?? DEFAULT_MODE;\n const warn = options.warn ?? noopWarn;\n const pointer = options.pointer;\n const upstreamArtifactHash = options.upstreamArtifactHash;\n\n // Rule 1: finality event without explicit upstream artifact - reject in all modes.\n if (input.event !== undefined && FINALITY_EVENTS.has(input.event)) {\n if (!input.hasExplicitUpstreamArtifact) {\n throw new MapperBoundaryError({\n code: COMMERCE_FINALITY_SYNTHESIS_CODE,\n pointer,\n upstreamArtifactHash,\n reason: `event=${JSON.stringify(input.event)} requires an explicit upstream payment artifact`,\n });\n }\n }\n\n // Rule 2: silent currency fallback - reject in strict, warn in interop, silent in legacy.\n const isMissingCurrency =\n typeof input.currency !== 'string' ||\n input.currency.length === 0 ||\n input.currency === 'UNKNOWN';\n if (isMissingCurrency) {\n if (mode === 'strict') {\n throw new MapperBoundaryError({\n code: COMMERCE_FINALITY_SYNTHESIS_CODE,\n pointer,\n upstreamArtifactHash,\n reason:\n 'currency missing or fallback (UNKNOWN); strict mode requires upstream-asserted currency',\n });\n }\n if (mode === 'interop') {\n warn(\n 'commerce mapper: currency missing or fallback (UNKNOWN). Strict mode will reject this in v0.13.0+. Provide an upstream-asserted currency.'\n );\n }\n }\n\n // Rule 3: defaulted env - reject in strict, warn in interop, silent in legacy.\n const envIsExplicit = input.envExplicit === true;\n const envIsKnown = input.env === 'live' || input.env === 'test';\n if (!envIsKnown || !envIsExplicit) {\n if (mode === 'strict') {\n throw new MapperBoundaryError({\n code: COMMERCE_FINALITY_SYNTHESIS_CODE,\n pointer,\n upstreamArtifactHash,\n reason: 'env missing or defaulted; strict mode requires upstream-asserted env (live|test)',\n });\n }\n if (mode === 'interop') {\n warn(\n 'commerce mapper: env missing or defaulted. Strict mode will reject this in v0.13.0+. Provide an upstream-asserted env.'\n );\n }\n }\n}\n\n/**\n * Returns whether the given event is one of the finality-bearing commerce\n * events. Useful for callers that want to short-circuit before assembling\n * full guard input.\n */\nexport function isFinalityEvent(event: string | undefined): event is CommerceFinalityEvent {\n return event !== undefined && FINALITY_EVENTS.has(event);\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peac/adapter-core",
|
|
3
|
-
"version": "0.12.
|
|
4
|
-
"description": "Shared utilities for PEAC payment rail adapters",
|
|
3
|
+
"version": "0.12.11",
|
|
4
|
+
"description": "Shared utilities for PEAC payment rail adapters and commerce mappings (Result types, validators, payment-proof contracts, mapper-boundary finality guard)",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"exports": {
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"access": "public"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@peac/kernel": "0.12.
|
|
31
|
+
"@peac/kernel": "0.12.11"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@types/node": "^22.19.11",
|