@fun-xyz/fiat-contract 0.7.0 → 0.8.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 +14 -11
- package/dist/{chunk-OGNYHIOE.mjs → chunk-LVVQ46YG.mjs} +31 -24
- package/dist/fixtures/index.d.ts +3 -4
- package/dist/index.js +217 -94
- package/dist/index.mjs +188 -72
- package/dist/table.d.ts +2 -3
- package/dist/table.js +30 -23
- package/dist/table.mjs +1 -1
- package/dist/types.d.ts +12 -17
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
tableEntry,
|
|
13
13
|
unofferedEndpoints,
|
|
14
14
|
unreachableStates
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-LVVQ46YG.mjs";
|
|
16
16
|
|
|
17
17
|
// src/codes.ts
|
|
18
18
|
var COUNTRY_CURRENCY_LIST = [
|
|
@@ -295,7 +295,7 @@ 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"]);
|
|
298
|
+
var $provider = z.enum(["TRANSAK", "SWAPPED", "BANXA", "MOONPAY", "STRIPE"]);
|
|
299
299
|
var FiatProviderSchema = $provider;
|
|
300
300
|
var $kycProvider = z.enum(["SUMSUB"]);
|
|
301
301
|
var KYCProviderSchema = $kycProvider;
|
|
@@ -392,7 +392,7 @@ var $refund = obj({
|
|
|
392
392
|
expectedBy: z.string()
|
|
393
393
|
});
|
|
394
394
|
var RefundSchema = $refund;
|
|
395
|
-
var $surfaceKind = z.enum(["URL_REDIRECT", "
|
|
395
|
+
var $surfaceKind = z.enum(["URL_REDIRECT", "KYC_SDK", "PCI_COMPONENT", "PAY_SHEET", "ACH_COMPONENT"]);
|
|
396
396
|
var SurfaceKindSchema = $surfaceKind;
|
|
397
397
|
var $surface = obj({
|
|
398
398
|
kind: $surfaceKind,
|
|
@@ -557,6 +557,7 @@ var SessionAuthStateSchema = $sessionAuthState;
|
|
|
557
557
|
var $kycCaptureState = obj({
|
|
558
558
|
kind: z.literal("KYC"),
|
|
559
559
|
phase: z.literal("CAPTURE"),
|
|
560
|
+
quote: $quote,
|
|
560
561
|
surface: $surface,
|
|
561
562
|
error: $failureReason.optional()
|
|
562
563
|
});
|
|
@@ -564,6 +565,7 @@ var KycCaptureStateSchema = $kycCaptureState;
|
|
|
564
565
|
var $kycInputRequiredState = obj({
|
|
565
566
|
kind: z.literal("KYC"),
|
|
566
567
|
phase: z.literal("INPUT_REQUIRED"),
|
|
568
|
+
quote: $quote,
|
|
567
569
|
form: $formDescriptor,
|
|
568
570
|
error: $failureReason.optional()
|
|
569
571
|
});
|
|
@@ -571,6 +573,7 @@ var KycInputRequiredStateSchema = $kycInputRequiredState;
|
|
|
571
573
|
var $kycNoActionRequiredState = obj({
|
|
572
574
|
kind: z.literal("KYC"),
|
|
573
575
|
phase: z.literal("NO_ACTION_REQUIRED"),
|
|
576
|
+
quote: $quote,
|
|
574
577
|
reason: z.enum(["IN_REVIEW", "ON_HOLD", "REJECTED"]),
|
|
575
578
|
retryAfter: z.string().optional(),
|
|
576
579
|
failureReason: $failureReason.optional(),
|
|
@@ -778,45 +781,43 @@ var FIXTURE_DATA = {
|
|
|
778
781
|
"state": {
|
|
779
782
|
"kind": "KYC",
|
|
780
783
|
"phase": "INPUT_REQUIRED",
|
|
784
|
+
"quote": {
|
|
785
|
+
"quoteRef": "q_8f2",
|
|
786
|
+
"fiat": {
|
|
787
|
+
"currency": "GBP",
|
|
788
|
+
"amount": "100.00"
|
|
789
|
+
},
|
|
790
|
+
"crypto": {
|
|
791
|
+
"currency": "USDC",
|
|
792
|
+
"network": "polygon",
|
|
793
|
+
"amount": "98.41"
|
|
794
|
+
},
|
|
795
|
+
"rate": "0.9841",
|
|
796
|
+
"totalFee": "1.59",
|
|
797
|
+
"feeBreakdown": [
|
|
798
|
+
{
|
|
799
|
+
"id": "provider_fee",
|
|
800
|
+
"labelFallback": "Processing fee",
|
|
801
|
+
"amount": "1.59"
|
|
802
|
+
}
|
|
803
|
+
],
|
|
804
|
+
"paymentMethod": "bank_transfer",
|
|
805
|
+
"expiresAt": "\u2026"
|
|
806
|
+
},
|
|
781
807
|
"form": {
|
|
782
|
-
"formId": "
|
|
808
|
+
"formId": "kyc_q_8f2_1",
|
|
783
809
|
"fields": [
|
|
784
810
|
{
|
|
785
|
-
"id": "
|
|
811
|
+
"id": "tin",
|
|
786
812
|
"type": "TEXT",
|
|
787
|
-
"labelFallback": "
|
|
813
|
+
"labelFallback": "Tax ID",
|
|
788
814
|
"required": true
|
|
789
815
|
},
|
|
790
816
|
{
|
|
791
|
-
"id": "
|
|
792
|
-
"type": "
|
|
793
|
-
"labelFallback": "
|
|
794
|
-
"required": true
|
|
795
|
-
},
|
|
796
|
-
{
|
|
797
|
-
"id": "country",
|
|
798
|
-
"type": "COUNTRY",
|
|
799
|
-
"labelFallback": "Country",
|
|
817
|
+
"id": "address",
|
|
818
|
+
"type": "TEXT",
|
|
819
|
+
"labelFallback": "Home address",
|
|
800
820
|
"required": true
|
|
801
|
-
},
|
|
802
|
-
{
|
|
803
|
-
"id": "sourceOfFunds",
|
|
804
|
-
"type": "SELECT",
|
|
805
|
-
"labelFallback": "Source of funds",
|
|
806
|
-
"required": true,
|
|
807
|
-
"options": [
|
|
808
|
-
{
|
|
809
|
-
"id": "salary",
|
|
810
|
-
"labelFallback": "Salary"
|
|
811
|
-
}
|
|
812
|
-
]
|
|
813
|
-
},
|
|
814
|
-
{
|
|
815
|
-
"id": "idProof",
|
|
816
|
-
"type": "HOSTED_LINK",
|
|
817
|
-
"labelFallback": "Verify your ID",
|
|
818
|
-
"required": true,
|
|
819
|
-
"url": "\u2026"
|
|
820
821
|
}
|
|
821
822
|
]
|
|
822
823
|
}
|
|
@@ -828,7 +829,8 @@ var FIXTURE_DATA = {
|
|
|
828
829
|
"mode": "SUBMIT",
|
|
829
830
|
"endpoint": "POST /fiat/kyc/form",
|
|
830
831
|
"params": {
|
|
831
|
-
"
|
|
832
|
+
"quoteRef": "q_8f2",
|
|
833
|
+
"formId": "kyc_q_8f2_1"
|
|
832
834
|
},
|
|
833
835
|
"inputs": {
|
|
834
836
|
"values": {
|
|
@@ -913,11 +915,84 @@ var FIXTURE_DATA = {
|
|
|
913
915
|
}
|
|
914
916
|
]
|
|
915
917
|
},
|
|
918
|
+
"screen-08-kyc-capture": {
|
|
919
|
+
"state": {
|
|
920
|
+
"kind": "KYC",
|
|
921
|
+
"phase": "CAPTURE",
|
|
922
|
+
"quote": {
|
|
923
|
+
"quoteRef": "q_8f2",
|
|
924
|
+
"fiat": {
|
|
925
|
+
"currency": "GBP",
|
|
926
|
+
"amount": "100.00"
|
|
927
|
+
},
|
|
928
|
+
"crypto": {
|
|
929
|
+
"currency": "USDC",
|
|
930
|
+
"network": "polygon",
|
|
931
|
+
"amount": "98.41"
|
|
932
|
+
},
|
|
933
|
+
"rate": "0.9841",
|
|
934
|
+
"totalFee": "1.59",
|
|
935
|
+
"feeBreakdown": [
|
|
936
|
+
{
|
|
937
|
+
"id": "provider_fee",
|
|
938
|
+
"labelFallback": "Processing fee",
|
|
939
|
+
"amount": "1.59"
|
|
940
|
+
}
|
|
941
|
+
],
|
|
942
|
+
"paymentMethod": "bank_transfer",
|
|
943
|
+
"expiresAt": "\u2026"
|
|
944
|
+
},
|
|
945
|
+
"surface": {
|
|
946
|
+
"kind": "KYC_SDK",
|
|
947
|
+
"provider": "SUMSUB",
|
|
948
|
+
"params": {
|
|
949
|
+
"accessToken": "eyJ\u2026"
|
|
950
|
+
},
|
|
951
|
+
"expiresAt": "\u2026"
|
|
952
|
+
}
|
|
953
|
+
},
|
|
954
|
+
"provider": "TRANSAK",
|
|
955
|
+
"transitions": [
|
|
956
|
+
{
|
|
957
|
+
"id": "capture",
|
|
958
|
+
"mode": "CLIENT_SURFACE",
|
|
959
|
+
"report": {
|
|
960
|
+
"endpoint": "POST /fiat/kyc/capture",
|
|
961
|
+
"params": {
|
|
962
|
+
"quoteRef": "q_8f2"
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
]
|
|
967
|
+
},
|
|
916
968
|
"screen-09-kyc-in-review": {
|
|
917
969
|
"state": {
|
|
918
970
|
"kind": "KYC",
|
|
919
971
|
"phase": "NO_ACTION_REQUIRED",
|
|
920
|
-
"reason": "IN_REVIEW"
|
|
972
|
+
"reason": "IN_REVIEW",
|
|
973
|
+
"quote": {
|
|
974
|
+
"quoteRef": "q_8f2",
|
|
975
|
+
"fiat": {
|
|
976
|
+
"currency": "GBP",
|
|
977
|
+
"amount": "100.00"
|
|
978
|
+
},
|
|
979
|
+
"crypto": {
|
|
980
|
+
"currency": "USDC",
|
|
981
|
+
"network": "polygon",
|
|
982
|
+
"amount": "98.41"
|
|
983
|
+
},
|
|
984
|
+
"rate": "0.9841",
|
|
985
|
+
"totalFee": "1.59",
|
|
986
|
+
"feeBreakdown": [
|
|
987
|
+
{
|
|
988
|
+
"id": "provider_fee",
|
|
989
|
+
"labelFallback": "Processing fee",
|
|
990
|
+
"amount": "1.59"
|
|
991
|
+
}
|
|
992
|
+
],
|
|
993
|
+
"paymentMethod": "bank_transfer",
|
|
994
|
+
"expiresAt": "\u2026"
|
|
995
|
+
}
|
|
921
996
|
},
|
|
922
997
|
"provider": "TRANSAK",
|
|
923
998
|
"transitions": [
|
|
@@ -925,10 +1000,7 @@ var FIXTURE_DATA = {
|
|
|
925
1000
|
"id": "poll",
|
|
926
1001
|
"mode": "AWAIT",
|
|
927
1002
|
"poll": {
|
|
928
|
-
"endpoint": "GET /fiat/
|
|
929
|
-
"params": {
|
|
930
|
-
"quoteRef": "q_8f2"
|
|
931
|
-
},
|
|
1003
|
+
"endpoint": "GET /fiat/quotes/q_8f2",
|
|
932
1004
|
"intervalMs": 3e3,
|
|
933
1005
|
"backoffFactor": 1.5,
|
|
934
1006
|
"maxIntervalMs": 1e4,
|
|
@@ -942,28 +1014,70 @@ var FIXTURE_DATA = {
|
|
|
942
1014
|
"kind": "KYC",
|
|
943
1015
|
"phase": "NO_ACTION_REQUIRED",
|
|
944
1016
|
"reason": "ON_HOLD",
|
|
945
|
-
"retryAfter": "2026-08-20T09:00:00Z"
|
|
1017
|
+
"retryAfter": "2026-08-20T09:00:00Z",
|
|
1018
|
+
"quote": {
|
|
1019
|
+
"quoteRef": "q_8f2",
|
|
1020
|
+
"fiat": {
|
|
1021
|
+
"currency": "GBP",
|
|
1022
|
+
"amount": "100.00"
|
|
1023
|
+
},
|
|
1024
|
+
"crypto": {
|
|
1025
|
+
"currency": "USDC",
|
|
1026
|
+
"network": "polygon",
|
|
1027
|
+
"amount": "98.41"
|
|
1028
|
+
},
|
|
1029
|
+
"rate": "0.9841",
|
|
1030
|
+
"totalFee": "1.59",
|
|
1031
|
+
"feeBreakdown": [
|
|
1032
|
+
{
|
|
1033
|
+
"id": "provider_fee",
|
|
1034
|
+
"labelFallback": "Processing fee",
|
|
1035
|
+
"amount": "1.59"
|
|
1036
|
+
}
|
|
1037
|
+
],
|
|
1038
|
+
"paymentMethod": "bank_transfer",
|
|
1039
|
+
"expiresAt": "\u2026"
|
|
1040
|
+
}
|
|
946
1041
|
},
|
|
947
1042
|
"provider": "TRANSAK",
|
|
948
1043
|
"transitions": []
|
|
949
1044
|
},
|
|
950
|
-
"screen-11-kyc-rejected
|
|
1045
|
+
"screen-11-kyc-rejected": {
|
|
951
1046
|
"state": {
|
|
952
1047
|
"kind": "KYC",
|
|
953
1048
|
"phase": "NO_ACTION_REQUIRED",
|
|
954
|
-
"reason": "REJECTED"
|
|
1049
|
+
"reason": "REJECTED",
|
|
1050
|
+
"quote": {
|
|
1051
|
+
"quoteRef": "q_8f2",
|
|
1052
|
+
"fiat": {
|
|
1053
|
+
"currency": "GBP",
|
|
1054
|
+
"amount": "100.00"
|
|
1055
|
+
},
|
|
1056
|
+
"crypto": {
|
|
1057
|
+
"currency": "USDC",
|
|
1058
|
+
"network": "polygon",
|
|
1059
|
+
"amount": "98.41"
|
|
1060
|
+
},
|
|
1061
|
+
"rate": "0.9841",
|
|
1062
|
+
"totalFee": "1.59",
|
|
1063
|
+
"feeBreakdown": [
|
|
1064
|
+
{
|
|
1065
|
+
"id": "provider_fee",
|
|
1066
|
+
"labelFallback": "Processing fee",
|
|
1067
|
+
"amount": "1.59"
|
|
1068
|
+
}
|
|
1069
|
+
],
|
|
1070
|
+
"paymentMethod": "bank_transfer",
|
|
1071
|
+
"expiresAt": "\u2026"
|
|
1072
|
+
},
|
|
1073
|
+
"failureReason": {
|
|
1074
|
+
"category": "KYC_REJECTED",
|
|
1075
|
+
"retryable": false,
|
|
1076
|
+
"recovery": "CONTACT_SUPPORT"
|
|
1077
|
+
}
|
|
955
1078
|
},
|
|
956
1079
|
"provider": "TRANSAK",
|
|
957
|
-
"transitions": [
|
|
958
|
-
{
|
|
959
|
-
"id": "escalate",
|
|
960
|
-
"mode": "SUBMIT",
|
|
961
|
-
"endpoint": "GET /fiat/kyc",
|
|
962
|
-
"params": {
|
|
963
|
-
"tier": "escalated"
|
|
964
|
-
}
|
|
965
|
-
}
|
|
966
|
-
]
|
|
1080
|
+
"transitions": []
|
|
967
1081
|
},
|
|
968
1082
|
"screen-12-pending-order": {
|
|
969
1083
|
"state": {
|
|
@@ -1241,8 +1355,8 @@ var FIXTURES = [
|
|
|
1241
1355
|
{
|
|
1242
1356
|
id: "screen-03-kyc-input-required",
|
|
1243
1357
|
file: "screen-03-kyc-input-required.json",
|
|
1244
|
-
source: "
|
|
1245
|
-
docRef: "
|
|
1358
|
+
source: "KYC_DOC",
|
|
1359
|
+
docRef: "Fiat KYC \xB7 L1 input round",
|
|
1246
1360
|
screen: 3,
|
|
1247
1361
|
stateKey: "KYC/INPUT_REQUIRED",
|
|
1248
1362
|
notes: ["Carries the FORM_VALUES input spec \u2014 the no-double-carry case of the accepted split."]
|
|
@@ -1270,34 +1384,40 @@ var FIXTURES = [
|
|
|
1270
1384
|
"TODO(open-decision): report target per card topology is a Transak ask (contract Flow A)."
|
|
1271
1385
|
]
|
|
1272
1386
|
},
|
|
1387
|
+
{
|
|
1388
|
+
id: "screen-08-kyc-capture",
|
|
1389
|
+
file: "screen-08-kyc-capture.json",
|
|
1390
|
+
source: "KYC_DOC",
|
|
1391
|
+
docRef: "Fiat KYC \xB7 embedded Sumsub WebSDK",
|
|
1392
|
+
screen: 8,
|
|
1393
|
+
stateKey: "KYC/CAPTURE",
|
|
1394
|
+
notes: ["The client mounts the Sumsub adapter; no URL or iframe is emitted."]
|
|
1395
|
+
},
|
|
1273
1396
|
{
|
|
1274
1397
|
id: "screen-09-kyc-in-review",
|
|
1275
1398
|
file: "screen-09-kyc-in-review.json",
|
|
1276
|
-
source: "
|
|
1277
|
-
docRef: "
|
|
1399
|
+
source: "KYC_DOC",
|
|
1400
|
+
docRef: "Fiat KYC \xB7 pending quote",
|
|
1278
1401
|
screen: 9,
|
|
1279
1402
|
stateKey: "KYC/NO_ACTION_REQUIRED:IN_REVIEW"
|
|
1280
1403
|
},
|
|
1281
1404
|
{
|
|
1282
1405
|
id: "screen-10-kyc-on-hold",
|
|
1283
1406
|
file: "screen-10-kyc-on-hold.json",
|
|
1284
|
-
source: "
|
|
1285
|
-
docRef: "
|
|
1407
|
+
source: "KYC_DOC",
|
|
1408
|
+
docRef: "Fiat KYC \xB7 verification on hold",
|
|
1286
1409
|
screen: 10,
|
|
1287
1410
|
stateKey: "KYC/NO_ACTION_REQUIRED:ON_HOLD",
|
|
1288
1411
|
notes: ["transitions: [] and NOT terminal \u2014 the fixture that proves terminality is table data."]
|
|
1289
1412
|
},
|
|
1290
1413
|
{
|
|
1291
|
-
id: "screen-11-kyc-rejected
|
|
1292
|
-
file: "screen-11-kyc-rejected
|
|
1293
|
-
source: "
|
|
1294
|
-
docRef: "
|
|
1414
|
+
id: "screen-11-kyc-rejected",
|
|
1415
|
+
file: "screen-11-kyc-rejected.json",
|
|
1416
|
+
source: "KYC_DOC",
|
|
1417
|
+
docRef: "Fiat KYC \xB7 non-retryable rejection",
|
|
1295
1418
|
screen: 11,
|
|
1296
1419
|
stateKey: "KYC/NO_ACTION_REQUIRED:REJECTED",
|
|
1297
|
-
notes: [
|
|
1298
|
-
"TODO(open-decision): the escalation transition is a flagged placeholder \u2014 a GET carrying params is not a real request shape (FE doc Screen 11 + open question 7).",
|
|
1299
|
-
"The terminal REJECTED variant (failureReason + transitions []) is described in prose, not published as JSON \u2014 no fixture."
|
|
1300
|
-
]
|
|
1420
|
+
notes: ["Only an explicit non-retryable provider or identity-vendor outcome reaches this state."]
|
|
1301
1421
|
},
|
|
1302
1422
|
{
|
|
1303
1423
|
id: "screen-12-pending-order",
|
|
@@ -1342,7 +1462,7 @@ var FIXTURES = [
|
|
|
1342
1462
|
docRef: "Screen 16 \xB7 Not available",
|
|
1343
1463
|
screen: 16,
|
|
1344
1464
|
stateKey: "BLOCKED",
|
|
1345
|
-
notes: ["
|
|
1465
|
+
notes: ["A flatly terminal availability state; explicit non-retryable KYC rejection is terminal too."]
|
|
1346
1466
|
},
|
|
1347
1467
|
{
|
|
1348
1468
|
id: "worked-example-01-quote",
|
|
@@ -1374,10 +1494,6 @@ var FIXTURE_COVERAGE_GAPS = [
|
|
|
1374
1494
|
{
|
|
1375
1495
|
stateKey: "FUN_AUTH",
|
|
1376
1496
|
reason: "No step response exists in either doc \u2014 shape owned by the auth spike, and FUN_AUTH never renders in fomo. TODO(open-decision): contract \xA7Auth & ref binding, item 5."
|
|
1377
|
-
},
|
|
1378
|
-
{
|
|
1379
|
-
stateKey: "KYC/CAPTURE",
|
|
1380
|
-
reason: "Dropped from v1 (FE Screen 8 tombstone, no UK module coverage); no step response was ever published. Kind retained as handshake-gated vocabulary."
|
|
1381
1497
|
}
|
|
1382
1498
|
];
|
|
1383
1499
|
var fixtureMeta = (id) => {
|
package/dist/table.d.ts
CHANGED
|
@@ -42,8 +42,7 @@ export type StateKey = 'QUOTE' | 'FUN_AUTH' | 'SESSION_AUTH' | 'KYC/CAPTURE' | '
|
|
|
42
42
|
export declare const TERMINAL_ORDER_STATUSES: readonly ["SETTLED", "EXPIRED", "CANCELLED", "FAILED", "REFUNDED"];
|
|
43
43
|
export type TerminalOrderStatus = (typeof TERMINAL_ORDER_STATUSES)[number];
|
|
44
44
|
/**
|
|
45
|
-
* Endpoint template as written in the docs
|
|
46
|
-
* `"POST /fiat/orders/:id/cancel"` matches the emitted `"POST /fiat/orders/o_31c/cancel"`.
|
|
45
|
+
* Endpoint template as written in the docs. Named `:` segments match one emitted path segment.
|
|
47
46
|
*/
|
|
48
47
|
export type EndpointTemplate = FiatEndpoint;
|
|
49
48
|
export interface AllowedTransition {
|
|
@@ -91,7 +90,7 @@ export declare const STATE_KEYS: StateKey[];
|
|
|
91
90
|
* named by the table (QUOTE's capture-first entry) while the doc's endpoint table still lists no
|
|
92
91
|
* session-minting call for that rail.
|
|
93
92
|
*/
|
|
94
|
-
export declare const DOCUMENTED_ENDPOINTS: readonly ["GET /fiat/payment-methods", "POST /fiat/quote", "POST /fiat/auth", "POST /fiat/payment-session", "POST /fiat/session", "POST /fiat/session/verify", "GET /fiat/
|
|
93
|
+
export declare const DOCUMENTED_ENDPOINTS: readonly ["GET /fiat/payment-methods", "POST /fiat/quote", "POST /fiat/auth", "POST /fiat/payment-session", "POST /fiat/session", "POST /fiat/session/verify", "GET /fiat/quotes/:quoteRef", "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/:id", "GET /fiat/orders/:id/instructions", "POST /fiat/orders/:id/confirm-payment", "POST /fiat/orders/:id/reference", "POST /fiat/orders/:id/cancel", "POST /fiat/orders/:id/surface-result"];
|
|
95
94
|
/**
|
|
96
95
|
* Documented endpoints no flow state offers, and why. Declared so an endpoint nothing can reach is
|
|
97
96
|
* visible instead of silent — the table test asserts the unoffered set equals exactly these.
|
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.8.0";
|
|
40
40
|
|
|
41
41
|
// src/table.ts
|
|
42
42
|
var TABLE_VERSION = version;
|
|
@@ -162,21 +162,23 @@ var TRANSITION_TABLE = {
|
|
|
162
162
|
{
|
|
163
163
|
id: "capture",
|
|
164
164
|
mode: "CLIENT_SURFACE",
|
|
165
|
-
endpoint: "
|
|
166
|
-
note:
|
|
165
|
+
endpoint: "POST /fiat/kyc/capture",
|
|
166
|
+
note: "Reports SDK submission; provider eligibility is re-evaluated through quote orchestration."
|
|
167
167
|
}
|
|
168
168
|
],
|
|
169
169
|
mayReturn: [
|
|
170
|
+
"KYC/CAPTURE",
|
|
170
171
|
"KYC/INPUT_REQUIRED",
|
|
171
172
|
"KYC/NO_ACTION_REQUIRED:IN_REVIEW",
|
|
172
173
|
"KYC/NO_ACTION_REQUIRED:ON_HOLD",
|
|
173
174
|
"KYC/NO_ACTION_REQUIRED:REJECTED",
|
|
175
|
+
"QUOTE",
|
|
176
|
+
"PAYMENT/CAPTURE",
|
|
177
|
+
"PAYMENT/INSTRUCT",
|
|
174
178
|
"ORDER/AWAITING_CONFIRMATION"
|
|
175
179
|
],
|
|
176
180
|
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
|
-
]
|
|
181
|
+
notes: ["Carries the handshake-gated KYC_SDK surface; provider selects the identity-vendor adapter."]
|
|
180
182
|
},
|
|
181
183
|
"KYC/INPUT_REQUIRED": {
|
|
182
184
|
key: "KYC/INPUT_REQUIRED",
|
|
@@ -188,16 +190,20 @@ var TRANSITION_TABLE = {
|
|
|
188
190
|
{ id: "submit_round", mode: "SUBMIT", endpoint: "POST /fiat/kyc/form" }
|
|
189
191
|
],
|
|
190
192
|
mayReturn: [
|
|
193
|
+
"KYC/CAPTURE",
|
|
191
194
|
"KYC/INPUT_REQUIRED",
|
|
192
195
|
"KYC/NO_ACTION_REQUIRED:IN_REVIEW",
|
|
193
196
|
"KYC/NO_ACTION_REQUIRED:ON_HOLD",
|
|
194
197
|
"KYC/NO_ACTION_REQUIRED:REJECTED",
|
|
198
|
+
"QUOTE",
|
|
199
|
+
"PAYMENT/CAPTURE",
|
|
200
|
+
"PAYMENT/INSTRUCT",
|
|
195
201
|
"ORDER/AWAITING_CONFIRMATION"
|
|
196
202
|
],
|
|
197
203
|
terminal: false,
|
|
198
204
|
notes: [
|
|
199
205
|
"One POST per round; conditional requirements may open another round.",
|
|
200
|
-
"FILE fields
|
|
206
|
+
"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
207
|
"Hosted KYC links arrive as HOSTED_LINK form fields, not as a Surface."
|
|
202
208
|
]
|
|
203
209
|
},
|
|
@@ -208,12 +214,16 @@ var TRANSITION_TABLE = {
|
|
|
208
214
|
reason: "IN_REVIEW",
|
|
209
215
|
screens: [9],
|
|
210
216
|
docStatus: "SPECIFIED",
|
|
211
|
-
allowedTransitions: [{ id: "poll", mode: "AWAIT", endpoint: "GET /fiat/
|
|
217
|
+
allowedTransitions: [{ id: "poll", mode: "AWAIT", endpoint: "GET /fiat/quotes/:quoteRef" }],
|
|
212
218
|
mayReturn: [
|
|
213
219
|
"KYC/NO_ACTION_REQUIRED:IN_REVIEW",
|
|
220
|
+
"KYC/CAPTURE",
|
|
214
221
|
"KYC/INPUT_REQUIRED",
|
|
215
222
|
"KYC/NO_ACTION_REQUIRED:ON_HOLD",
|
|
216
223
|
"KYC/NO_ACTION_REQUIRED:REJECTED",
|
|
224
|
+
"QUOTE",
|
|
225
|
+
"PAYMENT/CAPTURE",
|
|
226
|
+
"PAYMENT/INSTRUCT",
|
|
217
227
|
"ORDER/AWAITING_CONFIRMATION"
|
|
218
228
|
],
|
|
219
229
|
terminal: false,
|
|
@@ -243,20 +253,11 @@ var TRANSITION_TABLE = {
|
|
|
243
253
|
reason: "REJECTED",
|
|
244
254
|
screens: [11],
|
|
245
255
|
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,
|
|
256
|
+
allowedTransitions: [],
|
|
257
|
+
mayReturn: [],
|
|
258
|
+
terminal: true,
|
|
257
259
|
notes: [
|
|
258
|
-
"
|
|
259
|
-
"TODO(open-decision): contract OQ7 \u2014 terminal vs escalating rejections are not enumerated."
|
|
260
|
+
"Only explicit non-retryable outcomes reach REJECTED. Correctable failures return CAPTURE or INPUT_REQUIRED; provider-specific declines re-route before becoming user rejection."
|
|
260
261
|
]
|
|
261
262
|
},
|
|
262
263
|
PENDING_ORDER: {
|
|
@@ -418,8 +419,10 @@ var DOCUMENTED_ENDPOINTS = [
|
|
|
418
419
|
"POST /fiat/payment-session",
|
|
419
420
|
"POST /fiat/session",
|
|
420
421
|
"POST /fiat/session/verify",
|
|
421
|
-
"GET /fiat/
|
|
422
|
+
"GET /fiat/quotes/:quoteRef",
|
|
422
423
|
"POST /fiat/kyc/form",
|
|
424
|
+
"POST /fiat/kyc/capture",
|
|
425
|
+
"POST /fiat/kyc/sdk-token",
|
|
423
426
|
"POST /fiat/kyc/document",
|
|
424
427
|
"POST /fiat/instruments",
|
|
425
428
|
"POST /fiat/orders",
|
|
@@ -431,13 +434,17 @@ var DOCUMENTED_ENDPOINTS = [
|
|
|
431
434
|
"POST /fiat/orders/:id/surface-result"
|
|
432
435
|
];
|
|
433
436
|
var UNOFFERED_ENDPOINTS = [
|
|
437
|
+
{
|
|
438
|
+
endpoint: "POST /fiat/kyc/sdk-token",
|
|
439
|
+
reason: "SDK token refresh is adapter-driven rather than a flow transition."
|
|
440
|
+
},
|
|
434
441
|
{
|
|
435
442
|
endpoint: "GET /fiat/payment-methods",
|
|
436
443
|
reason: "Discovery, called before any flow state exists \u2014 there is no state to hang it off."
|
|
437
444
|
},
|
|
438
445
|
{
|
|
439
446
|
endpoint: "POST /fiat/kyc/document",
|
|
440
|
-
reason: "FILE fields
|
|
447
|
+
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
448
|
},
|
|
442
449
|
{
|
|
443
450
|
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';
|
|
72
65
|
/**
|
|
73
66
|
* The order status vocabulary. Monotonic ranks, no backwards moves. Terminal outcomes are
|
|
74
67
|
* OrderStatus, never FlowState kinds.
|
|
@@ -202,7 +195,7 @@ export interface Refund {
|
|
|
202
195
|
expectedBy: string;
|
|
203
196
|
}
|
|
204
197
|
/** What the user sees, and therefore where it can be placed. */
|
|
205
|
-
export type SurfaceKind = 'URL_REDIRECT' | '
|
|
198
|
+
export type SurfaceKind = 'URL_REDIRECT' | 'KYC_SDK' | 'PCI_COMPONENT' | 'PAY_SHEET' | 'ACH_COMPONENT';
|
|
206
199
|
/**
|
|
207
200
|
* Identity vendors Fun verifies into. Its own axis rather than a `FiatProvider` value, because
|
|
208
201
|
* Fun is the KYC-of-record in its own tenant — an identity surface is never the onramp's to mint.
|
|
@@ -442,20 +435,23 @@ export type FlowState =
|
|
|
442
435
|
channel: 'EMAIL_OTP';
|
|
443
436
|
error?: FailureReason;
|
|
444
437
|
}
|
|
445
|
-
/**
|
|
438
|
+
/** Pre-order KYC states carry the routed quote so the entry screen can keep price visible. */
|
|
446
439
|
| {
|
|
447
440
|
kind: 'KYC';
|
|
448
441
|
phase: 'CAPTURE';
|
|
442
|
+
quote: Quote;
|
|
449
443
|
surface: Surface;
|
|
450
444
|
error?: FailureReason;
|
|
451
445
|
} | {
|
|
452
446
|
kind: 'KYC';
|
|
453
447
|
phase: 'INPUT_REQUIRED';
|
|
448
|
+
quote: Quote;
|
|
454
449
|
form: FormDescriptor;
|
|
455
450
|
error?: FailureReason;
|
|
456
451
|
} | {
|
|
457
452
|
kind: 'KYC';
|
|
458
453
|
phase: 'NO_ACTION_REQUIRED';
|
|
454
|
+
quote: Quote;
|
|
459
455
|
/**
|
|
460
456
|
* Note the deliberate name collision (Charles's nit, review 2026-08-14): `ON_HOLD` appears
|
|
461
457
|
* here as a KYC reason *and* in `OrderStatus`. They are different things and both names come
|
|
@@ -470,10 +466,9 @@ export type FlowState =
|
|
|
470
466
|
reason: 'IN_REVIEW' | 'ON_HOLD' | 'REJECTED';
|
|
471
467
|
retryAfter?: string;
|
|
472
468
|
/**
|
|
473
|
-
*
|
|
474
|
-
*
|
|
475
|
-
*
|
|
476
|
-
* TODO(open-decision): contract OQ7 — which rejections escalate vs terminate.
|
|
469
|
+
* REJECTED is reserved for an explicit non-retryable outcome and renders in place — it
|
|
470
|
+
* never routes through `ORDER{CREATED, FAILED}`. Correctable outcomes return CAPTURE or
|
|
471
|
+
* INPUT_REQUIRED; a provider-specific decline is handled by quote rerouting first.
|
|
477
472
|
*/
|
|
478
473
|
failureReason?: FailureReason;
|
|
479
474
|
error?: FailureReason;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fun-xyz/fiat-contract",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.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": {
|