@fun-xyz/fiat-contract 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -11
- package/dist/{chunk-OGNYHIOE.mjs → chunk-5QGVY5Z4.mjs} +33 -24
- package/dist/fixtures/index.d.ts +3 -4
- package/dist/index.js +262 -96
- package/dist/index.mjs +231 -74
- package/dist/schemas.d.ts +3 -1
- package/dist/table.d.ts +2 -3
- package/dist/table.js +32 -23
- package/dist/table.mjs +1 -1
- package/dist/types.d.ts +23 -23
- package/package.json +1 -1
package/dist/table.js
CHANGED
|
@@ -36,7 +36,7 @@ __export(table_exports, {
|
|
|
36
36
|
module.exports = __toCommonJS(table_exports);
|
|
37
37
|
|
|
38
38
|
// package.json
|
|
39
|
-
var version = "0.
|
|
39
|
+
var version = "0.9.0";
|
|
40
40
|
|
|
41
41
|
// src/table.ts
|
|
42
42
|
var TABLE_VERSION = version;
|
|
@@ -142,6 +142,8 @@ var TRANSITION_TABLE = {
|
|
|
142
142
|
],
|
|
143
143
|
mayReturn: [
|
|
144
144
|
"SESSION_AUTH",
|
|
145
|
+
"QUOTE",
|
|
146
|
+
"PAYMENT/CAPTURE",
|
|
145
147
|
...KYC_ANY,
|
|
146
148
|
"ORDER/AWAITING_CONFIRMATION",
|
|
147
149
|
"PENDING_ORDER"
|
|
@@ -162,21 +164,23 @@ var TRANSITION_TABLE = {
|
|
|
162
164
|
{
|
|
163
165
|
id: "capture",
|
|
164
166
|
mode: "CLIENT_SURFACE",
|
|
165
|
-
endpoint: "
|
|
166
|
-
note:
|
|
167
|
+
endpoint: "POST /fiat/kyc/capture",
|
|
168
|
+
note: "Reports SDK submission; provider eligibility is re-evaluated through quote orchestration."
|
|
167
169
|
}
|
|
168
170
|
],
|
|
169
171
|
mayReturn: [
|
|
172
|
+
"KYC/CAPTURE",
|
|
170
173
|
"KYC/INPUT_REQUIRED",
|
|
171
174
|
"KYC/NO_ACTION_REQUIRED:IN_REVIEW",
|
|
172
175
|
"KYC/NO_ACTION_REQUIRED:ON_HOLD",
|
|
173
176
|
"KYC/NO_ACTION_REQUIRED:REJECTED",
|
|
177
|
+
"QUOTE",
|
|
178
|
+
"PAYMENT/CAPTURE",
|
|
179
|
+
"PAYMENT/INSTRUCT",
|
|
174
180
|
"ORDER/AWAITING_CONFIRMATION"
|
|
175
181
|
],
|
|
176
182
|
terminal: false,
|
|
177
|
-
notes: [
|
|
178
|
-
"Dropped from v1 (no UK headless-module coverage) \u2014 FE Screen 8 is a tombstone. Kind retained as vocabulary; the handshake (supportedStepKinds) keeps the backend from routing v1 SDKs here."
|
|
179
|
-
]
|
|
183
|
+
notes: ["Carries the handshake-gated KYC_SDK surface; provider selects the identity-vendor adapter."]
|
|
180
184
|
},
|
|
181
185
|
"KYC/INPUT_REQUIRED": {
|
|
182
186
|
key: "KYC/INPUT_REQUIRED",
|
|
@@ -188,16 +192,20 @@ var TRANSITION_TABLE = {
|
|
|
188
192
|
{ id: "submit_round", mode: "SUBMIT", endpoint: "POST /fiat/kyc/form" }
|
|
189
193
|
],
|
|
190
194
|
mayReturn: [
|
|
195
|
+
"KYC/CAPTURE",
|
|
191
196
|
"KYC/INPUT_REQUIRED",
|
|
192
197
|
"KYC/NO_ACTION_REQUIRED:IN_REVIEW",
|
|
193
198
|
"KYC/NO_ACTION_REQUIRED:ON_HOLD",
|
|
194
199
|
"KYC/NO_ACTION_REQUIRED:REJECTED",
|
|
200
|
+
"QUOTE",
|
|
201
|
+
"PAYMENT/CAPTURE",
|
|
202
|
+
"PAYMENT/INSTRUCT",
|
|
195
203
|
"ORDER/AWAITING_CONFIRMATION"
|
|
196
204
|
],
|
|
197
205
|
terminal: false,
|
|
198
206
|
notes: [
|
|
199
207
|
"One POST per round; conditional requirements may open another round.",
|
|
200
|
-
"FILE fields
|
|
208
|
+
"FILE fields use POST /fiat/kyc/document to obtain or report a direct provider/vendor upload; document bytes never transit Fun. The harness owns this auxiliary path, not a transition.",
|
|
201
209
|
"Hosted KYC links arrive as HOSTED_LINK form fields, not as a Surface."
|
|
202
210
|
]
|
|
203
211
|
},
|
|
@@ -208,12 +216,16 @@ var TRANSITION_TABLE = {
|
|
|
208
216
|
reason: "IN_REVIEW",
|
|
209
217
|
screens: [9],
|
|
210
218
|
docStatus: "SPECIFIED",
|
|
211
|
-
allowedTransitions: [{ id: "poll", mode: "AWAIT", endpoint: "GET /fiat/
|
|
219
|
+
allowedTransitions: [{ id: "poll", mode: "AWAIT", endpoint: "GET /fiat/quotes/:quoteRef" }],
|
|
212
220
|
mayReturn: [
|
|
213
221
|
"KYC/NO_ACTION_REQUIRED:IN_REVIEW",
|
|
222
|
+
"KYC/CAPTURE",
|
|
214
223
|
"KYC/INPUT_REQUIRED",
|
|
215
224
|
"KYC/NO_ACTION_REQUIRED:ON_HOLD",
|
|
216
225
|
"KYC/NO_ACTION_REQUIRED:REJECTED",
|
|
226
|
+
"QUOTE",
|
|
227
|
+
"PAYMENT/CAPTURE",
|
|
228
|
+
"PAYMENT/INSTRUCT",
|
|
217
229
|
"ORDER/AWAITING_CONFIRMATION"
|
|
218
230
|
],
|
|
219
231
|
terminal: false,
|
|
@@ -243,20 +255,11 @@ var TRANSITION_TABLE = {
|
|
|
243
255
|
reason: "REJECTED",
|
|
244
256
|
screens: [11],
|
|
245
257
|
docStatus: "SPECIFIED",
|
|
246
|
-
allowedTransitions: [
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
mode: "SUBMIT",
|
|
250
|
-
endpoint: "GET /fiat/kyc",
|
|
251
|
-
when: "an escalation round is offered",
|
|
252
|
-
note: "TODO(open-decision): placeholder shape \u2014 the FE doc flags that a GET carrying params is not a real request shape, and OQ7 owns which rejections escalate. FE doc open question 7."
|
|
253
|
-
}
|
|
254
|
-
],
|
|
255
|
-
mayReturn: KYC_ANY,
|
|
256
|
-
terminal: false,
|
|
258
|
+
allowedTransitions: [],
|
|
259
|
+
mayReturn: [],
|
|
260
|
+
terminal: true,
|
|
257
261
|
notes: [
|
|
258
|
-
"
|
|
259
|
-
"TODO(open-decision): contract OQ7 \u2014 terminal vs escalating rejections are not enumerated."
|
|
262
|
+
"Only explicit non-retryable outcomes reach REJECTED. Correctable failures return CAPTURE or INPUT_REQUIRED; provider-specific declines re-route before becoming user rejection."
|
|
260
263
|
]
|
|
261
264
|
},
|
|
262
265
|
PENDING_ORDER: {
|
|
@@ -418,8 +421,10 @@ var DOCUMENTED_ENDPOINTS = [
|
|
|
418
421
|
"POST /fiat/payment-session",
|
|
419
422
|
"POST /fiat/session",
|
|
420
423
|
"POST /fiat/session/verify",
|
|
421
|
-
"GET /fiat/
|
|
424
|
+
"GET /fiat/quotes/:quoteRef",
|
|
422
425
|
"POST /fiat/kyc/form",
|
|
426
|
+
"POST /fiat/kyc/capture",
|
|
427
|
+
"POST /fiat/kyc/sdk-token",
|
|
423
428
|
"POST /fiat/kyc/document",
|
|
424
429
|
"POST /fiat/instruments",
|
|
425
430
|
"POST /fiat/orders",
|
|
@@ -431,13 +436,17 @@ var DOCUMENTED_ENDPOINTS = [
|
|
|
431
436
|
"POST /fiat/orders/:id/surface-result"
|
|
432
437
|
];
|
|
433
438
|
var UNOFFERED_ENDPOINTS = [
|
|
439
|
+
{
|
|
440
|
+
endpoint: "POST /fiat/kyc/sdk-token",
|
|
441
|
+
reason: "SDK token refresh is adapter-driven rather than a flow transition."
|
|
442
|
+
},
|
|
434
443
|
{
|
|
435
444
|
endpoint: "GET /fiat/payment-methods",
|
|
436
445
|
reason: "Discovery, called before any flow state exists \u2014 there is no state to hang it off."
|
|
437
446
|
},
|
|
438
447
|
{
|
|
439
448
|
endpoint: "POST /fiat/kyc/document",
|
|
440
|
-
reason: "FILE fields
|
|
449
|
+
reason: "FILE fields use it for a direct provider/vendor upload handshake and completion report; the harness owns that auxiliary path and it is not a transition (see KYC/INPUT_REQUIRED notes)."
|
|
441
450
|
},
|
|
442
451
|
{
|
|
443
452
|
endpoint: "POST /fiat/instruments",
|
package/dist/table.mjs
CHANGED
package/dist/types.d.ts
CHANGED
|
@@ -56,19 +56,12 @@ export type HttpVerb = 'GET' | 'POST';
|
|
|
56
56
|
* cannot express "no slash", so `GET /fiat/orders/${string}` also admits sub-paths. Precision at
|
|
57
57
|
* that level is the table's job (`allowedTransitions` + `endpointMatches`), not the type's.
|
|
58
58
|
*/
|
|
59
|
-
export type FiatEndpoint = 'GET /fiat/payment-methods' | 'POST /fiat/quote' | 'POST /fiat/auth' | 'POST /fiat/payment-session' | 'POST /fiat/session' | 'POST /fiat/session/verify' |
|
|
59
|
+
export type FiatEndpoint = 'GET /fiat/payment-methods' | 'POST /fiat/quote' | 'POST /fiat/auth' | 'POST /fiat/payment-session' | 'POST /fiat/session' | 'POST /fiat/session/verify' | `GET /fiat/quotes/${string}` | 'POST /fiat/kyc/form' | 'POST /fiat/kyc/capture' | 'POST /fiat/kyc/sdk-token' | 'POST /fiat/kyc/document' | 'POST /fiat/instruments' | 'POST /fiat/orders' | `GET /fiat/orders/${string}` | `GET /fiat/orders/${string}/instructions` | `POST /fiat/orders/${string}/confirm-payment` | `POST /fiat/orders/${string}/reference` | `POST /fiat/orders/${string}/cancel` | `POST /fiat/orders/${string}/surface-result`;
|
|
60
60
|
/**
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
* TODO(open-decision): the docs name only Transak as a v1 provider for the headless flow
|
|
64
|
-
* (contract §Decisions 3; Swapped-headless does not exist yet, Banxa is Tradeoff #4).
|
|
65
|
-
* `SWAPPED` added at fun-backend's request (2026-08-17) so its legacy fops payment-provider id
|
|
66
|
-
* has one shared vocabulary instead of a second fun-backend-local enum — it never appears as a
|
|
67
|
-
* `FiatStepResponse.provider` value since Swapped's fops flow doesn't emit this response.
|
|
68
|
-
* `BANXA` added at 0.7 (Provider Landscape: Tier 1). A vendor name here is a routing key only —
|
|
69
|
-
* it never decides which fields exist, which is what keeps provider churn out of this package.
|
|
61
|
+
* Routing metadata, not sequencing policy. Reserved values may be emitted only after their adapter
|
|
62
|
+
* and conformance fixture land.
|
|
70
63
|
*/
|
|
71
|
-
export type FiatProvider = 'TRANSAK' | 'SWAPPED' | 'BANXA';
|
|
64
|
+
export type FiatProvider = 'TRANSAK' | 'SWAPPED' | 'BANXA' | 'MOONPAY' | 'STRIPE' | 'COINBASE' | 'CROSSMINT';
|
|
72
65
|
/**
|
|
73
66
|
* The order status vocabulary. Monotonic ranks, no backwards moves. Terminal outcomes are
|
|
74
67
|
* OrderStatus, never FlowState kinds.
|
|
@@ -158,6 +151,11 @@ export interface Quote {
|
|
|
158
151
|
paymentMethod: PaymentMethodCategory;
|
|
159
152
|
expiresAt: string;
|
|
160
153
|
}
|
|
154
|
+
/** Input bounds for the quote screen. Decimal strings in the quote currency. */
|
|
155
|
+
export interface QuoteLimits {
|
|
156
|
+
min: string;
|
|
157
|
+
max: string;
|
|
158
|
+
}
|
|
161
159
|
/** Deferred to the credit-card iteration (FE doc port ledger) — optional wherever it appears. */
|
|
162
160
|
export interface Instrument {
|
|
163
161
|
brandLabel: string;
|
|
@@ -202,7 +200,7 @@ export interface Refund {
|
|
|
202
200
|
expectedBy: string;
|
|
203
201
|
}
|
|
204
202
|
/** What the user sees, and therefore where it can be placed. */
|
|
205
|
-
export type SurfaceKind = 'URL_REDIRECT' | '
|
|
203
|
+
export type SurfaceKind = 'URL_REDIRECT' | 'KYC_SDK' | 'PCI_COMPONENT' | 'PAY_SHEET' | 'ACH_COMPONENT' | 'AUTH_COMPONENT';
|
|
206
204
|
/**
|
|
207
205
|
* Identity vendors Fun verifies into. Its own axis rather than a `FiatProvider` value, because
|
|
208
206
|
* Fun is the KYC-of-record in its own tenant — an identity surface is never the onramp's to mint.
|
|
@@ -431,6 +429,8 @@ export type FlowState =
|
|
|
431
429
|
{
|
|
432
430
|
kind: 'QUOTE';
|
|
433
431
|
quote: Quote;
|
|
432
|
+
limits: QuoteLimits;
|
|
433
|
+
helper?: string;
|
|
434
434
|
surface?: Surface;
|
|
435
435
|
error?: FailureReason;
|
|
436
436
|
} | {
|
|
@@ -439,23 +439,27 @@ export type FlowState =
|
|
|
439
439
|
error?: FailureReason;
|
|
440
440
|
} | {
|
|
441
441
|
kind: 'SESSION_AUTH';
|
|
442
|
-
channel: 'EMAIL_OTP';
|
|
442
|
+
channel: 'EMAIL_OTP' | 'SMS_OTP' | 'PROVIDER_RENDERED';
|
|
443
|
+
surface?: Surface;
|
|
443
444
|
error?: FailureReason;
|
|
444
445
|
}
|
|
445
|
-
/**
|
|
446
|
+
/** Pre-order KYC states carry the routed quote so the entry screen can keep price visible. */
|
|
446
447
|
| {
|
|
447
448
|
kind: 'KYC';
|
|
448
449
|
phase: 'CAPTURE';
|
|
450
|
+
quote: Quote;
|
|
449
451
|
surface: Surface;
|
|
450
452
|
error?: FailureReason;
|
|
451
453
|
} | {
|
|
452
454
|
kind: 'KYC';
|
|
453
455
|
phase: 'INPUT_REQUIRED';
|
|
456
|
+
quote: Quote;
|
|
454
457
|
form: FormDescriptor;
|
|
455
458
|
error?: FailureReason;
|
|
456
459
|
} | {
|
|
457
460
|
kind: 'KYC';
|
|
458
461
|
phase: 'NO_ACTION_REQUIRED';
|
|
462
|
+
quote: Quote;
|
|
459
463
|
/**
|
|
460
464
|
* Note the deliberate name collision (Charles's nit, review 2026-08-14): `ON_HOLD` appears
|
|
461
465
|
* here as a KYC reason *and* in `OrderStatus`. They are different things and both names come
|
|
@@ -470,10 +474,9 @@ export type FlowState =
|
|
|
470
474
|
reason: 'IN_REVIEW' | 'ON_HOLD' | 'REJECTED';
|
|
471
475
|
retryAfter?: string;
|
|
472
476
|
/**
|
|
473
|
-
*
|
|
474
|
-
*
|
|
475
|
-
*
|
|
476
|
-
* TODO(open-decision): contract OQ7 — which rejections escalate vs terminate.
|
|
477
|
+
* REJECTED is reserved for an explicit non-retryable outcome and renders in place — it
|
|
478
|
+
* never routes through `ORDER{CREATED, FAILED}`. Correctable outcomes return CAPTURE or
|
|
479
|
+
* INPUT_REQUIRED; a provider-specific decline is handled by quote rerouting first.
|
|
477
480
|
*/
|
|
478
481
|
failureReason?: FailureReason;
|
|
479
482
|
error?: FailureReason;
|
|
@@ -490,11 +493,7 @@ export type FlowState =
|
|
|
490
493
|
error?: FailureReason;
|
|
491
494
|
} | {
|
|
492
495
|
kind: 'BLOCKED';
|
|
493
|
-
|
|
494
|
-
* Observed value: `REGION_UNSUPPORTED` (FE doc Screen 16). The contract types this as
|
|
495
|
-
* `string`; no enum is published, so none is invented here.
|
|
496
|
-
*/
|
|
497
|
-
reason: string;
|
|
496
|
+
reason: BlockedReason;
|
|
498
497
|
/** `null` renders "no comeback date" (FE doc Screen 16 emits it explicitly). */
|
|
499
498
|
retryAfter?: string | null;
|
|
500
499
|
error?: FailureReason;
|
|
@@ -532,6 +531,7 @@ export type FlowState =
|
|
|
532
531
|
error?: FailureReason;
|
|
533
532
|
};
|
|
534
533
|
export type FlowStateKind = FlowState['kind'];
|
|
534
|
+
export type BlockedReason = 'REGION_UNSUPPORTED' | 'ASSET_UNSUPPORTED' | 'ALL_PROVIDERS_DECLINED' | 'AMOUNT_UNSERVABLE';
|
|
535
535
|
/**
|
|
536
536
|
* Every `/fiat/*` response. `transitions: []` = nothing the wizard can do; whether the *flow*
|
|
537
537
|
* is over is read from the table (`terminal`), never from array emptiness (ON_HOLD is the proof).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fun-xyz/fiat-contract",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Published conformance contract for Fun's headless fiat onramp: FlowState/Transition types, zod schemas, the transition table as data, recorded fixtures, assertion helpers.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|