@fun-xyz/fiat-contract 0.15.0 → 0.17.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
@@ -85,6 +85,13 @@ this package is [ENG-5268](https://linear.app/funxyz/issue/ENG-5268).
85
85
  is present, and PAY must never be exposed without real current economics.
86
86
  15. **KYC may precede pricing.** Provider auth or activation may legitimately defer pricing, so a
87
87
  KYC state may omit `quote`. A real `Quote` still requires `quoteRef`, and PAY is never quote-less.
88
+ 16. **Correction text never decides retry.** A correctable provider rejection returns
89
+ `KYC{CAPTURE}` and may carry `correctionReason` for display. Clients decide that retry is allowed
90
+ from the state and its transitions; provider-authored text is never a branch key.
91
+ 17. **Prepared payment is inert until promotion.** `FiatStepResponse.preparedPayment` may warm a
92
+ provider-owned payment surface while auth or KYC continues, but its `CLIENT_SURFACE` transition
93
+ is not active yet. A client exposes it only after a later response makes the same `quoteRef`
94
+ executable; the prepared surface provider must match the response provider.
88
95
 
89
96
  ## KYC SDK hints, results, and client delivery
90
97
 
@@ -1,5 +1,5 @@
1
1
  // package.json
2
- var version = "0.15.0";
2
+ var version = "0.17.0";
3
3
 
4
4
  // src/table.ts
5
5
  var TABLE_VERSION = version;
@@ -514,4 +514,4 @@ export {
514
514
  tableEntry,
515
515
  isTerminal
516
516
  };
517
- //# sourceMappingURL=chunk-CXYGWKAG.mjs.map
517
+ //# sourceMappingURL=chunk-TXRBC2P2.mjs.map
package/dist/index.js CHANGED
@@ -67,9 +67,11 @@ __export(index_exports, {
67
67
  PAYMENT_METHOD_CATEGORIES: () => PAYMENT_METHOD_CATEGORIES,
68
68
  PaymentCaptureStateSchema: () => PaymentCaptureStateSchema,
69
69
  PaymentInstructStateSchema: () => PaymentInstructStateSchema,
70
+ PaymentSurfaceSchema: () => PaymentSurfaceSchema,
70
71
  PendingOrderStateSchema: () => PendingOrderStateSchema,
71
72
  PollSpecSchema: () => PollSpecSchema,
72
73
  PreferredIdentityDocumentSchema: () => PreferredIdentityDocumentSchema,
74
+ PreparedPaymentSchema: () => PreparedPaymentSchema,
73
75
  QuoteLimitRangeSchema: () => QuoteLimitRangeSchema,
74
76
  QuoteLimitsSchema: () => QuoteLimitsSchema,
75
77
  QuoteSchema: () => QuoteSchema,
@@ -671,6 +673,13 @@ var $surface = import_zod.z.union([
671
673
  })
672
674
  ]);
673
675
  var SurfaceSchema = $surface;
676
+ var $paymentSurface = obj({
677
+ ...$surfaceBase,
678
+ kind: import_zod.z.enum(["URL_REDIRECT", "PCI_COMPONENT", "PAY_SHEET", "ACH_COMPONENT"]),
679
+ provider: $provider,
680
+ delivery: $clientExecutedDelivery.optional()
681
+ });
682
+ var PaymentSurfaceSchema = $paymentSurface;
674
683
  var $instructionField = obj({
675
684
  id: import_zod.z.string(),
676
685
  labelFallback: import_zod.z.string(),
@@ -798,6 +807,11 @@ var $kycSdkResult = import_zod.z.union([
798
807
  obj({ outcome: import_zod.z.literal("FAILED"), errorType: import_zod.z.string().trim().min(1) })
799
808
  ]);
800
809
  var KycSdkResultReportSchema = $kycSdkResult;
810
+ var $clientSurfaceTransition = obj({
811
+ id: import_zod.z.string(),
812
+ mode: import_zod.z.literal("CLIENT_SURFACE"),
813
+ report: $reportSpec
814
+ });
801
815
  var $transition = import_zod.z.union([
802
816
  obj({
803
817
  id: import_zod.z.string(),
@@ -808,9 +822,15 @@ var $transition = import_zod.z.union([
808
822
  labelFallback: import_zod.z.string().optional()
809
823
  }),
810
824
  obj({ id: import_zod.z.string(), mode: import_zod.z.literal("AWAIT"), poll: $pollSpec }),
811
- obj({ id: import_zod.z.string(), mode: import_zod.z.literal("CLIENT_SURFACE"), report: $reportSpec })
825
+ $clientSurfaceTransition
812
826
  ]);
813
827
  var TransitionSchema = $transition;
828
+ var $preparedPayment = obj({
829
+ quoteRef: import_zod.z.string().trim().min(1),
830
+ surface: $paymentSurface,
831
+ transition: $clientSurfaceTransition
832
+ });
833
+ var PreparedPaymentSchema = $preparedPayment;
814
834
  var $authChallenge = import_zod.z.record(import_zod.z.string(), JsonSchema);
815
835
  var AuthChallengeSchema = $authChallenge;
816
836
  var $quoteState = obj({
@@ -841,6 +861,7 @@ var $kycCaptureState = obj({
841
861
  phase: import_zod.z.literal("CAPTURE"),
842
862
  quote: $quote.optional(),
843
863
  surface: $surface,
864
+ correctionReason: import_zod.z.string().min(1).max(1024).optional(),
844
865
  error: $failureReason.optional()
845
866
  });
846
867
  var KycCaptureStateSchema = $kycCaptureState;
@@ -936,6 +957,7 @@ var $providerBoundStepResponse = obj({
936
957
  state: $providerBoundFlowState,
937
958
  provider: $provider,
938
959
  transitions: import_zod.z.array($transition),
960
+ preparedPayment: $preparedPayment.optional(),
939
961
  routingSessionRef: import_zod.z.string().optional(),
940
962
  providerAuthToken: obj({
941
963
  clientSecret: import_zod.z.string(),
@@ -943,6 +965,14 @@ var $providerBoundStepResponse = obj({
943
965
  }).optional(),
944
966
  orderId: import_zod.z.string().optional(),
945
967
  refreshLimits: import_zod.z.literal(true).optional()
968
+ }).superRefine((response, context) => {
969
+ if (response.preparedPayment !== void 0 && response.preparedPayment.surface.provider !== response.provider) {
970
+ context.addIssue({
971
+ code: "custom",
972
+ path: ["preparedPayment", "surface", "provider"],
973
+ message: "preparedPayment.surface.provider must match the response provider"
974
+ });
975
+ }
946
976
  });
947
977
  var $blockedStepResponse = obj({
948
978
  state: $blockedState,
@@ -960,7 +990,7 @@ var $stepResponse = import_zod.z.union([$providerBoundStepResponse, $blockedStep
960
990
  var FiatStepResponseSchema = $stepResponse;
961
991
 
962
992
  // package.json
963
- var version = "0.15.0";
993
+ var version = "0.17.0";
964
994
 
965
995
  // src/table.ts
966
996
  var TABLE_VERSION = version;
@@ -1790,7 +1820,8 @@ var FIXTURE_DATA = {
1790
1820
  }
1791
1821
  },
1792
1822
  "expiresAt": "\u2026"
1793
- }
1823
+ },
1824
+ "correctionReason": "The image is too blurry. Upload a clearer photo of this document."
1794
1825
  },
1795
1826
  "provider": "TRANSAK",
1796
1827
  "transitions": [
@@ -2254,7 +2285,10 @@ var FIXTURES = [
2254
2285
  docRef: "Fiat KYC \xB7 embedded Sumsub WebSDK",
2255
2286
  screen: 8,
2256
2287
  stateKey: "KYC/CAPTURE",
2257
- notes: ["The client mounts the Sumsub adapter; no URL or iframe is emitted."]
2288
+ notes: [
2289
+ "The client mounts the Sumsub adapter; no URL or iframe is emitted.",
2290
+ "A retry may carry provider-authored correctionReason display text; clients never branch on it."
2291
+ ]
2258
2292
  },
2259
2293
  {
2260
2294
  id: "screen-09-kyc-in-review",
package/dist/index.mjs CHANGED
@@ -12,7 +12,7 @@ import {
12
12
  tableEntry,
13
13
  unofferedEndpoints,
14
14
  unreachableStates
15
- } from "./chunk-CXYGWKAG.mjs";
15
+ } from "./chunk-TXRBC2P2.mjs";
16
16
 
17
17
  // src/codes.ts
18
18
  var US_STATE_CODES = [
@@ -568,6 +568,13 @@ var $surface = z.union([
568
568
  })
569
569
  ]);
570
570
  var SurfaceSchema = $surface;
571
+ var $paymentSurface = obj({
572
+ ...$surfaceBase,
573
+ kind: z.enum(["URL_REDIRECT", "PCI_COMPONENT", "PAY_SHEET", "ACH_COMPONENT"]),
574
+ provider: $provider,
575
+ delivery: $clientExecutedDelivery.optional()
576
+ });
577
+ var PaymentSurfaceSchema = $paymentSurface;
571
578
  var $instructionField = obj({
572
579
  id: z.string(),
573
580
  labelFallback: z.string(),
@@ -695,6 +702,11 @@ var $kycSdkResult = z.union([
695
702
  obj({ outcome: z.literal("FAILED"), errorType: z.string().trim().min(1) })
696
703
  ]);
697
704
  var KycSdkResultReportSchema = $kycSdkResult;
705
+ var $clientSurfaceTransition = obj({
706
+ id: z.string(),
707
+ mode: z.literal("CLIENT_SURFACE"),
708
+ report: $reportSpec
709
+ });
698
710
  var $transition = z.union([
699
711
  obj({
700
712
  id: z.string(),
@@ -705,9 +717,15 @@ var $transition = z.union([
705
717
  labelFallback: z.string().optional()
706
718
  }),
707
719
  obj({ id: z.string(), mode: z.literal("AWAIT"), poll: $pollSpec }),
708
- obj({ id: z.string(), mode: z.literal("CLIENT_SURFACE"), report: $reportSpec })
720
+ $clientSurfaceTransition
709
721
  ]);
710
722
  var TransitionSchema = $transition;
723
+ var $preparedPayment = obj({
724
+ quoteRef: z.string().trim().min(1),
725
+ surface: $paymentSurface,
726
+ transition: $clientSurfaceTransition
727
+ });
728
+ var PreparedPaymentSchema = $preparedPayment;
711
729
  var $authChallenge = z.record(z.string(), JsonSchema);
712
730
  var AuthChallengeSchema = $authChallenge;
713
731
  var $quoteState = obj({
@@ -738,6 +756,7 @@ var $kycCaptureState = obj({
738
756
  phase: z.literal("CAPTURE"),
739
757
  quote: $quote.optional(),
740
758
  surface: $surface,
759
+ correctionReason: z.string().min(1).max(1024).optional(),
741
760
  error: $failureReason.optional()
742
761
  });
743
762
  var KycCaptureStateSchema = $kycCaptureState;
@@ -833,6 +852,7 @@ var $providerBoundStepResponse = obj({
833
852
  state: $providerBoundFlowState,
834
853
  provider: $provider,
835
854
  transitions: z.array($transition),
855
+ preparedPayment: $preparedPayment.optional(),
836
856
  routingSessionRef: z.string().optional(),
837
857
  providerAuthToken: obj({
838
858
  clientSecret: z.string(),
@@ -840,6 +860,14 @@ var $providerBoundStepResponse = obj({
840
860
  }).optional(),
841
861
  orderId: z.string().optional(),
842
862
  refreshLimits: z.literal(true).optional()
863
+ }).superRefine((response, context) => {
864
+ if (response.preparedPayment !== void 0 && response.preparedPayment.surface.provider !== response.provider) {
865
+ context.addIssue({
866
+ code: "custom",
867
+ path: ["preparedPayment", "surface", "provider"],
868
+ message: "preparedPayment.surface.provider must match the response provider"
869
+ });
870
+ }
843
871
  });
844
872
  var $blockedStepResponse = obj({
845
873
  state: $blockedState,
@@ -1185,7 +1213,8 @@ var FIXTURE_DATA = {
1185
1213
  }
1186
1214
  },
1187
1215
  "expiresAt": "\u2026"
1188
- }
1216
+ },
1217
+ "correctionReason": "The image is too blurry. Upload a clearer photo of this document."
1189
1218
  },
1190
1219
  "provider": "TRANSAK",
1191
1220
  "transitions": [
@@ -1649,7 +1678,10 @@ var FIXTURES = [
1649
1678
  docRef: "Fiat KYC \xB7 embedded Sumsub WebSDK",
1650
1679
  screen: 8,
1651
1680
  stateKey: "KYC/CAPTURE",
1652
- notes: ["The client mounts the Sumsub adapter; no URL or iframe is emitted."]
1681
+ notes: [
1682
+ "The client mounts the Sumsub adapter; no URL or iframe is emitted.",
1683
+ "A retry may carry provider-authored correctionReason display text; clients never branch on it."
1684
+ ]
1653
1685
  },
1654
1686
  {
1655
1687
  id: "screen-09-kyc-in-review",
@@ -1964,9 +1996,11 @@ export {
1964
1996
  PAYMENT_METHOD_CATEGORIES,
1965
1997
  PaymentCaptureStateSchema,
1966
1998
  PaymentInstructStateSchema,
1999
+ PaymentSurfaceSchema,
1967
2000
  PendingOrderStateSchema,
1968
2001
  PollSpecSchema,
1969
2002
  PreferredIdentityDocumentSchema,
2003
+ PreparedPaymentSchema,
1970
2004
  QuoteLimitRangeSchema,
1971
2005
  QuoteLimitsSchema,
1972
2006
  QuoteSchema,
package/dist/schemas.d.ts CHANGED
@@ -28,7 +28,7 @@
28
28
  */
29
29
  import { z } from 'zod';
30
30
  import type { UsStateCode } from './codes';
31
- import type { BlockedReason, CryptoAmount, FailureReason, FeeLine, FiatAmount, FiatEndpoint, FiatProvider, FiatStepResponse, FieldSpec, FlowState, FormDescriptor, FormField, FormFieldType, InstructionField, Instructions, Instrument, JsonValue, KYCProvider, OrderRef, OrderStatus, OrderSummary, PollSpec, Quote, QuoteLimitRange, QuoteLimits, Recovery, Refund, ReportSpec, SelectOption, StatusHistoryEntry, Surface, PreferredIdentityDocument, ClientExecutedDelivery, KycSdkResultReport, SurfaceKind, SurfaceProvider, TermsAcceptance, Transition, TransitionInputs, TransitionParams, Tx } from './types';
31
+ import type { BlockedReason, CryptoAmount, FailureReason, FeeLine, FiatAmount, FiatEndpoint, FiatProvider, FiatStepResponse, FieldSpec, FlowState, FormDescriptor, FormField, FormFieldType, InstructionField, Instructions, Instrument, JsonValue, KYCProvider, OrderRef, OrderStatus, OrderSummary, PollSpec, PreparedPayment, PaymentSurface, Quote, QuoteLimitRange, QuoteLimits, Recovery, Refund, ReportSpec, SelectOption, StatusHistoryEntry, Surface, PreferredIdentityDocument, ClientExecutedDelivery, KycSdkResultReport, SurfaceKind, SurfaceProvider, TermsAcceptance, Transition, TransitionInputs, TransitionParams, Tx } from './types';
32
32
  export declare const JsonSchema: z.ZodType<JsonValue>;
33
33
  export declare const HTTP_VERBS: readonly ["GET", "POST"];
34
34
  /** `"POST /fiat/session/verify"`, `"GET /fiat/orders/o_31c"` — the verb rides the string. */
@@ -59,6 +59,7 @@ export declare const STANDARD_KYC_FIELD_IDS: readonly ["LEGAL_FIRST_NAME", "LEGA
59
59
  export declare const KYC_ACKNOWLEDGEMENT_FIELD_IDS: readonly ["RISK_ACKNOWLEDGEMENT", "COOLING_OFF_ACKNOWLEDGEMENT", "TERMS_ACCEPTANCE"];
60
60
  export declare const ClientExecutedDeliverySchema: z.ZodType<ClientExecutedDelivery>;
61
61
  export declare const SurfaceSchema: z.ZodType<Surface>;
62
+ export declare const PaymentSurfaceSchema: z.ZodType<PaymentSurface>;
62
63
  export declare const InstructionFieldSchema: z.ZodType<InstructionField>;
63
64
  export declare const InstructionsSchema: z.ZodType<Instructions>;
64
65
  export declare const SelectOptionSchema: z.ZodType<SelectOption>;
@@ -80,6 +81,7 @@ export declare const PollSpecSchema: z.ZodType<PollSpec>;
80
81
  export declare const ReportSpecSchema: z.ZodType<ReportSpec>;
81
82
  export declare const KycSdkResultReportSchema: z.ZodType<KycSdkResultReport>;
82
83
  export declare const TransitionSchema: z.ZodType<Transition>;
84
+ export declare const PreparedPaymentSchema: z.ZodType<PreparedPayment>;
83
85
  export declare const AuthChallengeSchema: z.ZodType<Record<string, JsonValue>>;
84
86
  /** `Extract` keeps each per-state export pinned to the union member it validates. */
85
87
  type State<K extends FlowState['kind'], P = never> = [P] extends [never] ? Extract<FlowState, {
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.15.0";
39
+ var version = "0.17.0";
40
40
 
41
41
  // src/table.ts
42
42
  var TABLE_VERSION = version;
package/dist/table.mjs CHANGED
@@ -11,7 +11,7 @@ import {
11
11
  tableEntry,
12
12
  unofferedEndpoints,
13
13
  unreachableStates
14
- } from "./chunk-CXYGWKAG.mjs";
14
+ } from "./chunk-TXRBC2P2.mjs";
15
15
  export {
16
16
  DOCUMENTED_ENDPOINTS,
17
17
  STATE_KEYS,
package/dist/types.d.ts CHANGED
@@ -293,6 +293,12 @@ export type Surface = (SurfaceBase & {
293
293
  /** Adapter-owned submission mechanics; the shared contract declares only the safe source. */
294
294
  delivery?: ClientExecutedDelivery;
295
295
  });
296
+ /** Provider-owned surfaces that can execute a payment after the quote becomes executable. */
297
+ export type PaymentSurfaceKind = 'URL_REDIRECT' | 'PCI_COMPONENT' | 'PAY_SHEET' | 'ACH_COMPONENT';
298
+ export type PaymentSurface = Surface & {
299
+ kind: PaymentSurfaceKind;
300
+ provider: FiatProvider;
301
+ };
296
302
  export interface InstructionField {
297
303
  id: string;
298
304
  labelFallback: string;
@@ -506,6 +512,20 @@ export type Transition = {
506
512
  mode: 'CLIENT_SURFACE';
507
513
  report: ReportSpec;
508
514
  };
515
+ /**
516
+ * A payment surface prepared ahead of the flow state that may execute it.
517
+ *
518
+ * This is inert response metadata, not an active transition. A client may warm the surface while
519
+ * completing auth or KYC, but must expose or report it only after a later response makes the same
520
+ * quote executable. `quoteRef` is explicit so that promotion never relies on provider-owned params.
521
+ */
522
+ export interface PreparedPayment {
523
+ quoteRef: string;
524
+ surface: PaymentSurface;
525
+ transition: Extract<Transition, {
526
+ mode: 'CLIENT_SURFACE';
527
+ }>;
528
+ }
509
529
  /**
510
530
  * TODO(open-decision): shape owned by the auth spike (contract §Auth & ref binding, item 5).
511
531
  * `FUN_AUTH` never renders in fomo (identity is ambient), so nothing in either doc constrains
@@ -553,6 +573,11 @@ export type FlowState =
553
573
  phase: 'CAPTURE';
554
574
  quote?: Quote;
555
575
  surface: Surface;
576
+ /**
577
+ * Provider-authored guidance for correcting the previous verification attempt. Display-only:
578
+ * clients must use the state and transitions, never this text, to decide whether retry is allowed.
579
+ */
580
+ correctionReason?: string;
556
581
  error?: FailureReason;
557
582
  } | {
558
583
  kind: 'KYC';
@@ -687,6 +712,8 @@ export type FiatStepResponse = (FiatStepResponseBase & {
687
712
  kind: 'BLOCKED';
688
713
  }>;
689
714
  provider: FiatProvider;
715
+ /** Optional future payment artifact; never one of this response's currently active transitions. */
716
+ preparedPayment?: PreparedPayment;
690
717
  });
691
718
  export {};
692
719
  //# sourceMappingURL=types.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fun-xyz/fiat-contract",
3
- "version": "0.15.0",
3
+ "version": "0.17.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": {