@fun-xyz/fiat-contract 0.8.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 CHANGED
@@ -33,7 +33,9 @@ Source of truth: [Fiat Client Contract](https://app.notion.com/p/3b9fc3b2a002815
33
33
  [Fiat Frontend — State Machine & Screen Map](https://app.notion.com/p/3bbfc3b2a00281c994c2cebd17b1d6d3)
34
34
  (✅ Decisions · per-screen State details · Event bindings per flow state), plus
35
35
  [Fiat KYC — User Flow & API Interfaces](https://app.notion.com/p/3cefc3b2a00281c88e7fe771f0c64332)
36
- for quote-bound KYC states and endpoints.
36
+ for quote-bound KYC states and endpoints, and
37
+ [Fiat Routing Engine — Provider Selection, Ranking & Commit](https://app.notion.com/p/3d1fc3b2a00281f2b604c20869ac420a)
38
+ for quote-screen limits, provider auth channels, and blocked reasons.
37
39
  Tracking: [Headless Fiat Onramp](https://linear.app/funxyz/project/headless-fiat-onramp-0147f4102399) ·
38
40
  this package is [ENG-5268](https://linear.app/funxyz/issue/ENG-5268).
39
41
 
@@ -57,6 +59,10 @@ this package is [ENG-5268](https://linear.app/funxyz/issue/ENG-5268).
57
59
  6. **Surface kind names the renderer; provider selects the adapter.** Sumsub capture is
58
60
  `{ kind: 'KYC_SDK', provider: 'SUMSUB' }`. It is not `URL_EMBED`: the client mounts an SDK,
59
61
  not a URL or iframe.
62
+ 7. **Quote-screen bounds are explicit exact-money strings.** `QUOTE.limits` carries the minimum and
63
+ current routing maximum; clients do not infer either from provider metadata or floating point.
64
+ 8. **Provider auth is capability-shaped.** SMS uses `SMS_OTP`; provider-owned auth uses
65
+ `PROVIDER_RENDERED` with an optional `AUTH_COMPONENT` surface rather than provider-specific channels.
60
66
 
61
67
  ## Versioning — the package version IS the table version
62
68
 
@@ -1,5 +1,5 @@
1
1
  // package.json
2
- var version = "0.8.0";
2
+ var version = "0.9.0";
3
3
 
4
4
  // src/table.ts
5
5
  var TABLE_VERSION = version;
@@ -105,6 +105,8 @@ var TRANSITION_TABLE = {
105
105
  ],
106
106
  mayReturn: [
107
107
  "SESSION_AUTH",
108
+ "QUOTE",
109
+ "PAYMENT/CAPTURE",
108
110
  ...KYC_ANY,
109
111
  "ORDER/AWAITING_CONFIRMATION",
110
112
  "PENDING_ORDER"
@@ -498,4 +500,4 @@ export {
498
500
  tableEntry,
499
501
  isTerminal
500
502
  };
501
- //# sourceMappingURL=chunk-LVVQ46YG.mjs.map
503
+ //# sourceMappingURL=chunk-5QGVY5Z4.mjs.map
package/dist/index.js CHANGED
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  AuthChallengeSchema: () => AuthChallengeSchema,
24
+ BlockedReasonSchema: () => BlockedReasonSchema,
24
25
  BlockedStateSchema: () => BlockedStateSchema,
25
26
  COUNTRY_NAMES: () => COUNTRY_NAMES,
26
27
  COUNTRY_TO_CURRENCY: () => COUNTRY_TO_CURRENCY,
@@ -65,6 +66,7 @@ __export(index_exports, {
65
66
  PaymentInstructStateSchema: () => PaymentInstructStateSchema,
66
67
  PendingOrderStateSchema: () => PendingOrderStateSchema,
67
68
  PollSpecSchema: () => PollSpecSchema,
69
+ QuoteLimitsSchema: () => QuoteLimitsSchema,
68
70
  QuoteSchema: () => QuoteSchema,
69
71
  QuoteStateSchema: () => QuoteStateSchema,
70
72
  RecoverySchema: () => RecoverySchema,
@@ -387,7 +389,15 @@ var HTTP_VERBS = ["GET", "POST"];
387
389
  var ENDPOINT_PATTERN = /^(GET|POST) \/fiat\/[^\s]*$/;
388
390
  var $endpoint = import_zod.z.string().regex(ENDPOINT_PATTERN, 'endpoint must read "<GET|POST> /fiat/\u2026"');
389
391
  var FiatEndpointSchema = $endpoint;
390
- var $provider = import_zod.z.enum(["TRANSAK", "SWAPPED", "BANXA", "MOONPAY", "STRIPE"]);
392
+ var $provider = import_zod.z.enum([
393
+ "TRANSAK",
394
+ "SWAPPED",
395
+ "BANXA",
396
+ "MOONPAY",
397
+ "STRIPE",
398
+ "COINBASE",
399
+ "CROSSMINT"
400
+ ]);
391
401
  var FiatProviderSchema = $provider;
392
402
  var $kycProvider = import_zod.z.enum(["SUMSUB"]);
393
403
  var KYCProviderSchema = $kycProvider;
@@ -454,6 +464,8 @@ var $quote = obj({
454
464
  expiresAt: import_zod.z.string()
455
465
  });
456
466
  var QuoteSchema = $quote;
467
+ var $quoteLimits = obj({ min: import_zod.z.string(), max: import_zod.z.string() });
468
+ var QuoteLimitsSchema = $quoteLimits;
457
469
  var $instrument = obj({ brandLabel: import_zod.z.string(), last4: import_zod.z.string() });
458
470
  var InstrumentSchema = $instrument;
459
471
  var $orderRef = obj({
@@ -484,7 +496,14 @@ var $refund = obj({
484
496
  expectedBy: import_zod.z.string()
485
497
  });
486
498
  var RefundSchema = $refund;
487
- var $surfaceKind = import_zod.z.enum(["URL_REDIRECT", "KYC_SDK", "PCI_COMPONENT", "PAY_SHEET", "ACH_COMPONENT"]);
499
+ var $surfaceKind = import_zod.z.enum([
500
+ "URL_REDIRECT",
501
+ "KYC_SDK",
502
+ "PCI_COMPONENT",
503
+ "PAY_SHEET",
504
+ "ACH_COMPONENT",
505
+ "AUTH_COMPONENT"
506
+ ]);
488
507
  var SurfaceKindSchema = $surfaceKind;
489
508
  var $surface = obj({
490
509
  kind: $surfaceKind,
@@ -629,6 +648,8 @@ var AuthChallengeSchema = $authChallenge;
629
648
  var $quoteState = obj({
630
649
  kind: import_zod.z.literal("QUOTE"),
631
650
  quote: $quote,
651
+ limits: $quoteLimits,
652
+ helper: import_zod.z.string().optional(),
632
653
  /** Present when the provider's component is the primary CTA, inline on the entry screen. */
633
654
  surface: $surface.optional(),
634
655
  error: $failureReason.optional()
@@ -642,7 +663,8 @@ var $funAuthState = obj({
642
663
  var FunAuthStateSchema = $funAuthState;
643
664
  var $sessionAuthState = obj({
644
665
  kind: import_zod.z.literal("SESSION_AUTH"),
645
- channel: import_zod.z.literal("EMAIL_OTP"),
666
+ channel: import_zod.z.enum(["EMAIL_OTP", "SMS_OTP", "PROVIDER_RENDERED"]),
667
+ surface: $surface.optional(),
646
668
  error: $failureReason.optional()
647
669
  });
648
670
  var SessionAuthStateSchema = $sessionAuthState;
@@ -678,9 +700,16 @@ var $pendingOrderState = obj({
678
700
  error: $failureReason.optional()
679
701
  });
680
702
  var PendingOrderStateSchema = $pendingOrderState;
703
+ var $blockedReason = import_zod.z.enum([
704
+ "REGION_UNSUPPORTED",
705
+ "ASSET_UNSUPPORTED",
706
+ "ALL_PROVIDERS_DECLINED",
707
+ "AMOUNT_UNSERVABLE"
708
+ ]);
709
+ var BlockedReasonSchema = $blockedReason;
681
710
  var $blockedState = obj({
682
711
  kind: import_zod.z.literal("BLOCKED"),
683
- reason: import_zod.z.string(),
712
+ reason: $blockedReason,
684
713
  retryAfter: import_zod.z.string().nullable().optional(),
685
714
  error: $failureReason.optional()
686
715
  });
@@ -743,7 +772,7 @@ var $stepResponse = obj({
743
772
  var FiatStepResponseSchema = $stepResponse;
744
773
 
745
774
  // package.json
746
- var version = "0.8.0";
775
+ var version = "0.9.0";
747
776
 
748
777
  // src/table.ts
749
778
  var TABLE_VERSION = version;
@@ -849,6 +878,8 @@ var TRANSITION_TABLE = {
849
878
  ],
850
879
  mayReturn: [
851
880
  "SESSION_AUTH",
881
+ "QUOTE",
882
+ "PAYMENT/CAPTURE",
852
883
  ...KYC_ANY,
853
884
  "ORDER/AWAITING_CONFIRMATION",
854
885
  "PENDING_ORDER"
@@ -1233,6 +1264,10 @@ var FIXTURE_DATA = {
1233
1264
  "screen-01-quote": {
1234
1265
  "state": {
1235
1266
  "kind": "QUOTE",
1267
+ "limits": {
1268
+ "min": "1.00",
1269
+ "max": "3000.00"
1270
+ },
1236
1271
  "quote": {
1237
1272
  "quoteRef": "q_8f2",
1238
1273
  "fiat": {
@@ -1277,6 +1312,10 @@ var FIXTURE_DATA = {
1277
1312
  "screen-01b-quote-with-pay-sheet": {
1278
1313
  "state": {
1279
1314
  "kind": "QUOTE",
1315
+ "limits": {
1316
+ "min": "1.00",
1317
+ "max": "3000.00"
1318
+ },
1280
1319
  "quote": {
1281
1320
  "quoteRef": "q_8f2",
1282
1321
  "fiat": {
@@ -1788,6 +1827,10 @@ var FIXTURE_DATA = {
1788
1827
  "worked-example-01-quote": {
1789
1828
  "state": {
1790
1829
  "kind": "QUOTE",
1830
+ "limits": {
1831
+ "min": "1.00",
1832
+ "max": "3000.00"
1833
+ },
1791
1834
  "quote": {
1792
1835
  "quoteRef": "q_8f2",
1793
1836
  "fiat": {
package/dist/index.mjs CHANGED
@@ -12,7 +12,7 @@ import {
12
12
  tableEntry,
13
13
  unofferedEndpoints,
14
14
  unreachableStates
15
- } from "./chunk-LVVQ46YG.mjs";
15
+ } from "./chunk-5QGVY5Z4.mjs";
16
16
 
17
17
  // src/codes.ts
18
18
  var COUNTRY_CURRENCY_LIST = [
@@ -295,7 +295,15 @@ var HTTP_VERBS = ["GET", "POST"];
295
295
  var ENDPOINT_PATTERN = /^(GET|POST) \/fiat\/[^\s]*$/;
296
296
  var $endpoint = z.string().regex(ENDPOINT_PATTERN, 'endpoint must read "<GET|POST> /fiat/\u2026"');
297
297
  var FiatEndpointSchema = $endpoint;
298
- var $provider = z.enum(["TRANSAK", "SWAPPED", "BANXA", "MOONPAY", "STRIPE"]);
298
+ var $provider = z.enum([
299
+ "TRANSAK",
300
+ "SWAPPED",
301
+ "BANXA",
302
+ "MOONPAY",
303
+ "STRIPE",
304
+ "COINBASE",
305
+ "CROSSMINT"
306
+ ]);
299
307
  var FiatProviderSchema = $provider;
300
308
  var $kycProvider = z.enum(["SUMSUB"]);
301
309
  var KYCProviderSchema = $kycProvider;
@@ -362,6 +370,8 @@ var $quote = obj({
362
370
  expiresAt: z.string()
363
371
  });
364
372
  var QuoteSchema = $quote;
373
+ var $quoteLimits = obj({ min: z.string(), max: z.string() });
374
+ var QuoteLimitsSchema = $quoteLimits;
365
375
  var $instrument = obj({ brandLabel: z.string(), last4: z.string() });
366
376
  var InstrumentSchema = $instrument;
367
377
  var $orderRef = obj({
@@ -392,7 +402,14 @@ var $refund = obj({
392
402
  expectedBy: z.string()
393
403
  });
394
404
  var RefundSchema = $refund;
395
- var $surfaceKind = z.enum(["URL_REDIRECT", "KYC_SDK", "PCI_COMPONENT", "PAY_SHEET", "ACH_COMPONENT"]);
405
+ var $surfaceKind = z.enum([
406
+ "URL_REDIRECT",
407
+ "KYC_SDK",
408
+ "PCI_COMPONENT",
409
+ "PAY_SHEET",
410
+ "ACH_COMPONENT",
411
+ "AUTH_COMPONENT"
412
+ ]);
396
413
  var SurfaceKindSchema = $surfaceKind;
397
414
  var $surface = obj({
398
415
  kind: $surfaceKind,
@@ -537,6 +554,8 @@ var AuthChallengeSchema = $authChallenge;
537
554
  var $quoteState = obj({
538
555
  kind: z.literal("QUOTE"),
539
556
  quote: $quote,
557
+ limits: $quoteLimits,
558
+ helper: z.string().optional(),
540
559
  /** Present when the provider's component is the primary CTA, inline on the entry screen. */
541
560
  surface: $surface.optional(),
542
561
  error: $failureReason.optional()
@@ -550,7 +569,8 @@ var $funAuthState = obj({
550
569
  var FunAuthStateSchema = $funAuthState;
551
570
  var $sessionAuthState = obj({
552
571
  kind: z.literal("SESSION_AUTH"),
553
- channel: z.literal("EMAIL_OTP"),
572
+ channel: z.enum(["EMAIL_OTP", "SMS_OTP", "PROVIDER_RENDERED"]),
573
+ surface: $surface.optional(),
554
574
  error: $failureReason.optional()
555
575
  });
556
576
  var SessionAuthStateSchema = $sessionAuthState;
@@ -586,9 +606,16 @@ var $pendingOrderState = obj({
586
606
  error: $failureReason.optional()
587
607
  });
588
608
  var PendingOrderStateSchema = $pendingOrderState;
609
+ var $blockedReason = z.enum([
610
+ "REGION_UNSUPPORTED",
611
+ "ASSET_UNSUPPORTED",
612
+ "ALL_PROVIDERS_DECLINED",
613
+ "AMOUNT_UNSERVABLE"
614
+ ]);
615
+ var BlockedReasonSchema = $blockedReason;
589
616
  var $blockedState = obj({
590
617
  kind: z.literal("BLOCKED"),
591
- reason: z.string(),
618
+ reason: $blockedReason,
592
619
  retryAfter: z.string().nullable().optional(),
593
620
  error: $failureReason.optional()
594
621
  });
@@ -655,6 +682,10 @@ var FIXTURE_DATA = {
655
682
  "screen-01-quote": {
656
683
  "state": {
657
684
  "kind": "QUOTE",
685
+ "limits": {
686
+ "min": "1.00",
687
+ "max": "3000.00"
688
+ },
658
689
  "quote": {
659
690
  "quoteRef": "q_8f2",
660
691
  "fiat": {
@@ -699,6 +730,10 @@ var FIXTURE_DATA = {
699
730
  "screen-01b-quote-with-pay-sheet": {
700
731
  "state": {
701
732
  "kind": "QUOTE",
733
+ "limits": {
734
+ "min": "1.00",
735
+ "max": "3000.00"
736
+ },
702
737
  "quote": {
703
738
  "quoteRef": "q_8f2",
704
739
  "fiat": {
@@ -1210,6 +1245,10 @@ var FIXTURE_DATA = {
1210
1245
  "worked-example-01-quote": {
1211
1246
  "state": {
1212
1247
  "kind": "QUOTE",
1248
+ "limits": {
1249
+ "min": "1.00",
1250
+ "max": "3000.00"
1251
+ },
1213
1252
  "quote": {
1214
1253
  "quoteRef": "q_8f2",
1215
1254
  "fiat": {
@@ -1652,6 +1691,7 @@ function assertAllFixtures() {
1652
1691
  }
1653
1692
  export {
1654
1693
  AuthChallengeSchema,
1694
+ BlockedReasonSchema,
1655
1695
  BlockedStateSchema,
1656
1696
  COUNTRY_NAMES,
1657
1697
  COUNTRY_TO_CURRENCY,
@@ -1696,6 +1736,7 @@ export {
1696
1736
  PaymentInstructStateSchema,
1697
1737
  PendingOrderStateSchema,
1698
1738
  PollSpecSchema,
1739
+ QuoteLimitsSchema,
1699
1740
  QuoteSchema,
1700
1741
  QuoteStateSchema,
1701
1742
  RecoverySchema,
package/dist/schemas.d.ts CHANGED
@@ -27,7 +27,7 @@
27
27
  * They are module-private, so none of it reaches the published declarations.
28
28
  */
29
29
  import { z } from 'zod';
30
- import type { CryptoAmount, FailureReason, FeeLine, FiatEndpoint, FieldSpec, FlowState, FormDescriptor, FormField, FormFieldType, Instructions, InstructionField, Instrument, JsonValue, FiatAmount, OrderRef, OrderStatus, OrderSummary, PollSpec, FiatProvider, Quote, Recovery, Refund, ReportSpec, SelectOption, StatusHistoryEntry, FiatStepResponse, Surface, SurfaceKind, SurfaceProvider, KYCProvider, Transition, TransitionInputs, TransitionParams, Tx } from './types';
30
+ import type { BlockedReason, CryptoAmount, FailureReason, FeeLine, FiatEndpoint, FieldSpec, FlowState, FormDescriptor, FormField, FormFieldType, Instructions, InstructionField, Instrument, JsonValue, FiatAmount, OrderRef, OrderStatus, OrderSummary, PollSpec, FiatProvider, Quote, QuoteLimits, Recovery, Refund, ReportSpec, SelectOption, StatusHistoryEntry, FiatStepResponse, Surface, SurfaceKind, SurfaceProvider, KYCProvider, Transition, TransitionInputs, TransitionParams, Tx } from './types';
31
31
  export declare const JsonSchema: z.ZodType<JsonValue>;
32
32
  export declare const HTTP_VERBS: readonly ["GET", "POST"];
33
33
  /** `"POST /fiat/session/verify"`, `"GET /fiat/orders/o_31c"` — the verb rides the string. */
@@ -43,6 +43,7 @@ export declare const FiatAmountSchema: z.ZodType<FiatAmount>;
43
43
  export declare const CryptoAmountSchema: z.ZodType<CryptoAmount>;
44
44
  export declare const FeeLineSchema: z.ZodType<FeeLine>;
45
45
  export declare const QuoteSchema: z.ZodType<Quote>;
46
+ export declare const QuoteLimitsSchema: z.ZodType<QuoteLimits>;
46
47
  export declare const InstrumentSchema: z.ZodType<Instrument>;
47
48
  export declare const OrderRefSchema: z.ZodType<OrderRef>;
48
49
  export declare const OrderSummarySchema: z.ZodType<OrderSummary>;
@@ -84,6 +85,7 @@ export declare const KycCaptureStateSchema: z.ZodType<State<'KYC', 'CAPTURE'>>;
84
85
  export declare const KycInputRequiredStateSchema: z.ZodType<State<'KYC', 'INPUT_REQUIRED'>>;
85
86
  export declare const KycNoActionRequiredStateSchema: z.ZodType<State<'KYC', 'NO_ACTION_REQUIRED'>>;
86
87
  export declare const PendingOrderStateSchema: z.ZodType<State<'PENDING_ORDER'>>;
88
+ export declare const BlockedReasonSchema: z.ZodType<BlockedReason>;
87
89
  export declare const BlockedStateSchema: z.ZodType<State<'BLOCKED'>>;
88
90
  export declare const PaymentCaptureStateSchema: z.ZodType<State<'PAYMENT', 'CAPTURE'>>;
89
91
  export declare const PaymentInstructStateSchema: z.ZodType<State<'PAYMENT', 'INSTRUCT'>>;
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.8.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"
package/dist/table.mjs CHANGED
@@ -11,7 +11,7 @@ import {
11
11
  tableEntry,
12
12
  unofferedEndpoints,
13
13
  unreachableStates
14
- } from "./chunk-LVVQ46YG.mjs";
14
+ } from "./chunk-5QGVY5Z4.mjs";
15
15
  export {
16
16
  DOCUMENTED_ENDPOINTS,
17
17
  STATE_KEYS,
package/dist/types.d.ts CHANGED
@@ -61,7 +61,7 @@ export type FiatEndpoint = 'GET /fiat/payment-methods' | 'POST /fiat/quote' | 'P
61
61
  * Routing metadata, not sequencing policy. Reserved values may be emitted only after their adapter
62
62
  * and conformance fixture land.
63
63
  */
64
- export type FiatProvider = 'TRANSAK' | 'SWAPPED' | 'BANXA' | 'MOONPAY' | 'STRIPE';
64
+ export type FiatProvider = 'TRANSAK' | 'SWAPPED' | 'BANXA' | 'MOONPAY' | 'STRIPE' | 'COINBASE' | 'CROSSMINT';
65
65
  /**
66
66
  * The order status vocabulary. Monotonic ranks, no backwards moves. Terminal outcomes are
67
67
  * OrderStatus, never FlowState kinds.
@@ -151,6 +151,11 @@ export interface Quote {
151
151
  paymentMethod: PaymentMethodCategory;
152
152
  expiresAt: string;
153
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
+ }
154
159
  /** Deferred to the credit-card iteration (FE doc port ledger) — optional wherever it appears. */
155
160
  export interface Instrument {
156
161
  brandLabel: string;
@@ -195,7 +200,7 @@ export interface Refund {
195
200
  expectedBy: string;
196
201
  }
197
202
  /** What the user sees, and therefore where it can be placed. */
198
- export type SurfaceKind = 'URL_REDIRECT' | 'KYC_SDK' | 'PCI_COMPONENT' | 'PAY_SHEET' | 'ACH_COMPONENT';
203
+ export type SurfaceKind = 'URL_REDIRECT' | 'KYC_SDK' | 'PCI_COMPONENT' | 'PAY_SHEET' | 'ACH_COMPONENT' | 'AUTH_COMPONENT';
199
204
  /**
200
205
  * Identity vendors Fun verifies into. Its own axis rather than a `FiatProvider` value, because
201
206
  * Fun is the KYC-of-record in its own tenant — an identity surface is never the onramp's to mint.
@@ -424,6 +429,8 @@ export type FlowState =
424
429
  {
425
430
  kind: 'QUOTE';
426
431
  quote: Quote;
432
+ limits: QuoteLimits;
433
+ helper?: string;
427
434
  surface?: Surface;
428
435
  error?: FailureReason;
429
436
  } | {
@@ -432,7 +439,8 @@ export type FlowState =
432
439
  error?: FailureReason;
433
440
  } | {
434
441
  kind: 'SESSION_AUTH';
435
- channel: 'EMAIL_OTP';
442
+ channel: 'EMAIL_OTP' | 'SMS_OTP' | 'PROVIDER_RENDERED';
443
+ surface?: Surface;
436
444
  error?: FailureReason;
437
445
  }
438
446
  /** Pre-order KYC states carry the routed quote so the entry screen can keep price visible. */
@@ -485,11 +493,7 @@ export type FlowState =
485
493
  error?: FailureReason;
486
494
  } | {
487
495
  kind: 'BLOCKED';
488
- /**
489
- * Observed value: `REGION_UNSUPPORTED` (FE doc Screen 16). The contract types this as
490
- * `string`; no enum is published, so none is invented here.
491
- */
492
- reason: string;
496
+ reason: BlockedReason;
493
497
  /** `null` renders "no comeback date" (FE doc Screen 16 emits it explicitly). */
494
498
  retryAfter?: string | null;
495
499
  error?: FailureReason;
@@ -527,6 +531,7 @@ export type FlowState =
527
531
  error?: FailureReason;
528
532
  };
529
533
  export type FlowStateKind = FlowState['kind'];
534
+ export type BlockedReason = 'REGION_UNSUPPORTED' | 'ASSET_UNSUPPORTED' | 'ALL_PROVIDERS_DECLINED' | 'AMOUNT_UNSERVABLE';
530
535
  /**
531
536
  * Every `/fiat/*` response. `transitions: []` = nothing the wizard can do; whether the *flow*
532
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.8.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": {