@fun-xyz/fiat-contract 0.6.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/dist/index.mjs CHANGED
@@ -5,10 +5,14 @@ import {
5
5
  TABLE_VERSION,
6
6
  TERMINAL_ORDER_STATUSES,
7
7
  TRANSITION_TABLE,
8
+ UNOFFERED_ENDPOINTS,
9
+ UNREACHABLE_STATES,
8
10
  isTerminal,
9
11
  stateKey,
10
- tableEntry
11
- } from "./chunk-EHYDQU4T.mjs";
12
+ tableEntry,
13
+ unofferedEndpoints,
14
+ unreachableStates
15
+ } from "./chunk-LVVQ46YG.mjs";
12
16
 
13
17
  // src/codes.ts
14
18
  var COUNTRY_CURRENCY_LIST = [
@@ -291,8 +295,12 @@ var HTTP_VERBS = ["GET", "POST"];
291
295
  var ENDPOINT_PATTERN = /^(GET|POST) \/fiat\/[^\s]*$/;
292
296
  var $endpoint = z.string().regex(ENDPOINT_PATTERN, 'endpoint must read "<GET|POST> /fiat/\u2026"');
293
297
  var FiatEndpointSchema = $endpoint;
294
- var $provider = z.enum(["TRANSAK", "SWAPPED"]);
298
+ var $provider = z.enum(["TRANSAK", "SWAPPED", "BANXA", "MOONPAY", "STRIPE"]);
295
299
  var FiatProviderSchema = $provider;
300
+ var $kycProvider = z.enum(["SUMSUB"]);
301
+ var KYCProviderSchema = $kycProvider;
302
+ var $surfaceProvider = z.enum([...$provider.options, ...$kycProvider.options]);
303
+ var SurfaceProviderSchema = $surfaceProvider;
296
304
  var $orderStatus = z.enum([
297
305
  "CREATING",
298
306
  "AWAITING_PAYMENT",
@@ -384,13 +392,22 @@ var $refund = obj({
384
392
  expectedBy: z.string()
385
393
  });
386
394
  var RefundSchema = $refund;
387
- var $surface = z.union([
388
- obj({ kind: z.literal("URL_REDIRECT"), url: z.string() }),
389
- obj({ kind: z.literal("URL_EMBED"), url: z.string() }),
390
- obj({ kind: z.literal("PCI_COMPONENT"), session: z.string() }),
391
- obj({ kind: z.literal("PAY_SHEET"), session: z.string() }),
392
- obj({ kind: z.literal("ACH_COMPONENT"), session: z.string() })
393
- ]);
395
+ var $surfaceKind = z.enum(["URL_REDIRECT", "KYC_SDK", "PCI_COMPONENT", "PAY_SHEET", "ACH_COMPONENT"]);
396
+ var SurfaceKindSchema = $surfaceKind;
397
+ var $surface = obj({
398
+ kind: $surfaceKind,
399
+ provider: $surfaceProvider,
400
+ /**
401
+ * The one deliberate non-strict leaf in the contract. Provider inputs are the adapter's
402
+ * vocabulary, so typing them here would drag every provider field change through a contract
403
+ * release and both consumers — and a normalised `environment` could only be lossy across
404
+ * Transak's four values and Banxa's two. Both ends narrow instead: fun-backend emits from a
405
+ * typed provider session, the client adapter validates with its own schema, and a recorded
406
+ * fixture per `(provider, kind)` keeps the two honest.
407
+ */
408
+ params: z.record(z.string(), JsonSchema),
409
+ expiresAt: z.string().optional()
410
+ });
394
411
  var SurfaceSchema = $surface;
395
412
  var $instructionField = obj({
396
413
  id: z.string(),
@@ -520,6 +537,8 @@ var AuthChallengeSchema = $authChallenge;
520
537
  var $quoteState = obj({
521
538
  kind: z.literal("QUOTE"),
522
539
  quote: $quote,
540
+ /** Present when the provider's component is the primary CTA, inline on the entry screen. */
541
+ surface: $surface.optional(),
523
542
  error: $failureReason.optional()
524
543
  });
525
544
  var QuoteStateSchema = $quoteState;
@@ -538,6 +557,7 @@ var SessionAuthStateSchema = $sessionAuthState;
538
557
  var $kycCaptureState = obj({
539
558
  kind: z.literal("KYC"),
540
559
  phase: z.literal("CAPTURE"),
560
+ quote: $quote,
541
561
  surface: $surface,
542
562
  error: $failureReason.optional()
543
563
  });
@@ -545,6 +565,7 @@ var KycCaptureStateSchema = $kycCaptureState;
545
565
  var $kycInputRequiredState = obj({
546
566
  kind: z.literal("KYC"),
547
567
  phase: z.literal("INPUT_REQUIRED"),
568
+ quote: $quote,
548
569
  form: $formDescriptor,
549
570
  error: $failureReason.optional()
550
571
  });
@@ -552,6 +573,7 @@ var KycInputRequiredStateSchema = $kycInputRequiredState;
552
573
  var $kycNoActionRequiredState = obj({
553
574
  kind: z.literal("KYC"),
554
575
  phase: z.literal("NO_ACTION_REQUIRED"),
576
+ quote: $quote,
555
577
  reason: z.enum(["IN_REVIEW", "ON_HOLD", "REJECTED"]),
556
578
  retryAfter: z.string().optional(),
557
579
  failureReason: $failureReason.optional(),
@@ -674,6 +696,64 @@ var FIXTURE_DATA = {
674
696
  }
675
697
  ]
676
698
  },
699
+ "screen-01b-quote-with-pay-sheet": {
700
+ "state": {
701
+ "kind": "QUOTE",
702
+ "quote": {
703
+ "quoteRef": "q_8f2",
704
+ "fiat": {
705
+ "currency": "GBP",
706
+ "amount": "100.00"
707
+ },
708
+ "crypto": {
709
+ "currency": "USDC",
710
+ "network": "polygon",
711
+ "amount": "98.41"
712
+ },
713
+ "rate": "0.9841",
714
+ "totalFee": "1.59",
715
+ "feeBreakdown": [
716
+ {
717
+ "id": "provider_fee",
718
+ "labelFallback": "Processing fee",
719
+ "amount": "1.09"
720
+ },
721
+ {
722
+ "id": "network_fee",
723
+ "labelFallback": "Network fee",
724
+ "amount": "0.50"
725
+ }
726
+ ],
727
+ "paymentMethod": "bank_transfer",
728
+ "expiresAt": "\u2026"
729
+ },
730
+ "surface": {
731
+ "kind": "PAY_SHEET",
732
+ "provider": "TRANSAK",
733
+ "params": {
734
+ "sessionId": "txs_\u2026",
735
+ "environment": "STAGING"
736
+ }
737
+ }
738
+ },
739
+ "provider": "TRANSAK",
740
+ "transitions": [
741
+ {
742
+ "id": "capture",
743
+ "mode": "CLIENT_SURFACE",
744
+ "report": {
745
+ "endpoint": "POST /fiat/orders",
746
+ "params": {
747
+ "quoteRef": "q_8f2",
748
+ "depositAddress": "\u2026"
749
+ },
750
+ "expects": [
751
+ "paymentAuthorisationId"
752
+ ]
753
+ }
754
+ }
755
+ ]
756
+ },
677
757
  "screen-02-session-auth": {
678
758
  "state": {
679
759
  "kind": "SESSION_AUTH",
@@ -701,45 +781,43 @@ var FIXTURE_DATA = {
701
781
  "state": {
702
782
  "kind": "KYC",
703
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
+ },
704
807
  "form": {
705
- "formId": "personal_details",
808
+ "formId": "kyc_q_8f2_1",
706
809
  "fields": [
707
810
  {
708
- "id": "firstName",
811
+ "id": "tin",
709
812
  "type": "TEXT",
710
- "labelFallback": "First name",
813
+ "labelFallback": "Tax ID",
711
814
  "required": true
712
815
  },
713
816
  {
714
- "id": "dob",
715
- "type": "DATE",
716
- "labelFallback": "Date of birth",
717
- "required": true
718
- },
719
- {
720
- "id": "country",
721
- "type": "COUNTRY",
722
- "labelFallback": "Country",
817
+ "id": "address",
818
+ "type": "TEXT",
819
+ "labelFallback": "Home address",
723
820
  "required": true
724
- },
725
- {
726
- "id": "sourceOfFunds",
727
- "type": "SELECT",
728
- "labelFallback": "Source of funds",
729
- "required": true,
730
- "options": [
731
- {
732
- "id": "salary",
733
- "labelFallback": "Salary"
734
- }
735
- ]
736
- },
737
- {
738
- "id": "idProof",
739
- "type": "HOSTED_LINK",
740
- "labelFallback": "Verify your ID",
741
- "required": true,
742
- "url": "\u2026"
743
821
  }
744
822
  ]
745
823
  }
@@ -751,7 +829,8 @@ var FIXTURE_DATA = {
751
829
  "mode": "SUBMIT",
752
830
  "endpoint": "POST /fiat/kyc/form",
753
831
  "params": {
754
- "formId": "personal_details"
832
+ "quoteRef": "q_8f2",
833
+ "formId": "kyc_q_8f2_1"
755
834
  },
756
835
  "inputs": {
757
836
  "values": {
@@ -812,7 +891,11 @@ var FIXTURE_DATA = {
812
891
  "phase": "CAPTURE",
813
892
  "surface": {
814
893
  "kind": "PCI_COMPONENT",
815
- "session": "eyJ\u2026"
894
+ "provider": "TRANSAK",
895
+ "params": {
896
+ "sessionId": "eyJ\u2026",
897
+ "environment": "STAGING"
898
+ }
816
899
  }
817
900
  },
818
901
  "provider": "TRANSAK",
@@ -832,11 +915,84 @@ var FIXTURE_DATA = {
832
915
  }
833
916
  ]
834
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
+ },
835
968
  "screen-09-kyc-in-review": {
836
969
  "state": {
837
970
  "kind": "KYC",
838
971
  "phase": "NO_ACTION_REQUIRED",
839
- "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
+ }
840
996
  },
841
997
  "provider": "TRANSAK",
842
998
  "transitions": [
@@ -844,10 +1000,7 @@ var FIXTURE_DATA = {
844
1000
  "id": "poll",
845
1001
  "mode": "AWAIT",
846
1002
  "poll": {
847
- "endpoint": "GET /fiat/kyc",
848
- "params": {
849
- "quoteRef": "q_8f2"
850
- },
1003
+ "endpoint": "GET /fiat/quotes/q_8f2",
851
1004
  "intervalMs": 3e3,
852
1005
  "backoffFactor": 1.5,
853
1006
  "maxIntervalMs": 1e4,
@@ -861,28 +1014,70 @@ var FIXTURE_DATA = {
861
1014
  "kind": "KYC",
862
1015
  "phase": "NO_ACTION_REQUIRED",
863
1016
  "reason": "ON_HOLD",
864
- "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
+ }
865
1041
  },
866
1042
  "provider": "TRANSAK",
867
1043
  "transitions": []
868
1044
  },
869
- "screen-11-kyc-rejected-escalation": {
1045
+ "screen-11-kyc-rejected": {
870
1046
  "state": {
871
1047
  "kind": "KYC",
872
1048
  "phase": "NO_ACTION_REQUIRED",
873
- "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
+ }
874
1078
  },
875
1079
  "provider": "TRANSAK",
876
- "transitions": [
877
- {
878
- "id": "escalate",
879
- "mode": "SUBMIT",
880
- "endpoint": "GET /fiat/kyc",
881
- "params": {
882
- "tier": "escalated"
883
- }
884
- }
885
- ]
1080
+ "transitions": []
886
1081
  },
887
1082
  "screen-12-pending-order": {
888
1083
  "state": {
@@ -1137,6 +1332,18 @@ var FIXTURES = [
1137
1332
  screen: 1,
1138
1333
  stateKey: "QUOTE"
1139
1334
  },
1335
+ {
1336
+ id: "screen-01b-quote-with-pay-sheet",
1337
+ file: "screen-01b-quote-with-pay-sheet.json",
1338
+ source: "CONTRACT_DOC",
1339
+ docRef: "Fiat Contract 0.7 \xA7The contract diff \xB7 example envelopes",
1340
+ screen: 1,
1341
+ stateKey: "QUOTE",
1342
+ notes: [
1343
+ "The 0.7 single-screen shape: the quote carries its own PAY_SHEET, so the provider component is the primary CTA rather than something a later state reveals.",
1344
+ "Quote payload is screen-01-quote verbatim; only the surface and the transition differ."
1345
+ ]
1346
+ },
1140
1347
  {
1141
1348
  id: "screen-02-session-auth",
1142
1349
  file: "screen-02-session-auth.json",
@@ -1148,8 +1355,8 @@ var FIXTURES = [
1148
1355
  {
1149
1356
  id: "screen-03-kyc-input-required",
1150
1357
  file: "screen-03-kyc-input-required.json",
1151
- source: "FE_DOC",
1152
- docRef: "Screen 3 \xB7 Identity form (KYC)",
1358
+ source: "KYC_DOC",
1359
+ docRef: "Fiat KYC \xB7 L1 input round",
1153
1360
  screen: 3,
1154
1361
  stateKey: "KYC/INPUT_REQUIRED",
1155
1362
  notes: ["Carries the FORM_VALUES input spec \u2014 the no-double-carry case of the accepted split."]
@@ -1177,34 +1384,40 @@ var FIXTURES = [
1177
1384
  "TODO(open-decision): report target per card topology is a Transak ask (contract Flow A)."
1178
1385
  ]
1179
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
+ },
1180
1396
  {
1181
1397
  id: "screen-09-kyc-in-review",
1182
1398
  file: "screen-09-kyc-in-review.json",
1183
- source: "FE_DOC",
1184
- docRef: "Screen 9 \xB7 Verifying identity",
1399
+ source: "KYC_DOC",
1400
+ docRef: "Fiat KYC \xB7 pending quote",
1185
1401
  screen: 9,
1186
1402
  stateKey: "KYC/NO_ACTION_REQUIRED:IN_REVIEW"
1187
1403
  },
1188
1404
  {
1189
1405
  id: "screen-10-kyc-on-hold",
1190
1406
  file: "screen-10-kyc-on-hold.json",
1191
- source: "FE_DOC",
1192
- docRef: "Screen 10 \xB7 Verification on hold",
1407
+ source: "KYC_DOC",
1408
+ docRef: "Fiat KYC \xB7 verification on hold",
1193
1409
  screen: 10,
1194
1410
  stateKey: "KYC/NO_ACTION_REQUIRED:ON_HOLD",
1195
1411
  notes: ["transitions: [] and NOT terminal \u2014 the fixture that proves terminality is table data."]
1196
1412
  },
1197
1413
  {
1198
- id: "screen-11-kyc-rejected-escalation",
1199
- file: "screen-11-kyc-rejected-escalation.json",
1200
- source: "FE_DOC",
1201
- docRef: "Screen 11 \xB7 Verification unsuccessful",
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",
1202
1418
  screen: 11,
1203
1419
  stateKey: "KYC/NO_ACTION_REQUIRED:REJECTED",
1204
- notes: [
1205
- "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).",
1206
- "The terminal REJECTED variant (failureReason + transitions []) is described in prose, not published as JSON \u2014 no fixture."
1207
- ]
1420
+ notes: ["Only an explicit non-retryable provider or identity-vendor outcome reaches this state."]
1208
1421
  },
1209
1422
  {
1210
1423
  id: "screen-12-pending-order",
@@ -1249,7 +1462,7 @@ var FIXTURES = [
1249
1462
  docRef: "Screen 16 \xB7 Not available",
1250
1463
  screen: 16,
1251
1464
  stateKey: "BLOCKED",
1252
- notes: ["The only flatly terminal state entry in the table."]
1465
+ notes: ["A flatly terminal availability state; explicit non-retryable KYC rejection is terminal too."]
1253
1466
  },
1254
1467
  {
1255
1468
  id: "worked-example-01-quote",
@@ -1281,10 +1494,6 @@ var FIXTURE_COVERAGE_GAPS = [
1281
1494
  {
1282
1495
  stateKey: "FUN_AUTH",
1283
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."
1284
- },
1285
- {
1286
- stateKey: "KYC/CAPTURE",
1287
- reason: "Dropped from v1 (FE Screen 8 tombstone, no UK module coverage); no step response was ever published. Kind retained as handshake-gated vocabulary."
1288
1497
  }
1289
1498
  ];
1290
1499
  var fixtureMeta = (id) => {
@@ -1374,6 +1583,16 @@ function checkLegalEmission(state, transitions) {
1374
1583
  `${entry.key} is terminal (table) and must carry transitions: [] \u2014 got ${transitions.length}`
1375
1584
  );
1376
1585
  }
1586
+ const surfaceTargets = new Set(
1587
+ transitions.filter((t) => t.mode === "CLIENT_SURFACE").map((t) => t.report.endpoint)
1588
+ );
1589
+ for (const transition of transitions) {
1590
+ if (transition.mode === "SUBMIT" && surfaceTargets.has(transition.endpoint)) {
1591
+ issues.push(
1592
+ `transition "${transition.id}": SUBMIT ${transition.endpoint} coexists with a CLIENT_SURFACE reporting to it`
1593
+ );
1594
+ }
1595
+ }
1377
1596
  for (const transition of transitions) {
1378
1597
  issues.push(...bodyKeyIssues(transition));
1379
1598
  if (transition.mode === "CLIENT_SURFACE" && !("surface" in state)) {
@@ -1463,6 +1682,7 @@ export {
1463
1682
  InstructionsSchema,
1464
1683
  InstrumentSchema,
1465
1684
  JsonSchema,
1685
+ KYCProviderSchema,
1466
1686
  KycCaptureStateSchema,
1467
1687
  KycInputRequiredStateSchema,
1468
1688
  KycNoActionRequiredStateSchema,
@@ -1485,6 +1705,8 @@ export {
1485
1705
  SelectOptionSchema,
1486
1706
  SessionAuthStateSchema,
1487
1707
  StatusHistoryEntrySchema,
1708
+ SurfaceKindSchema,
1709
+ SurfaceProviderSchema,
1488
1710
  SurfaceSchema,
1489
1711
  TABLE_VERSION,
1490
1712
  TERMINAL_ORDER_STATUSES,
@@ -1493,6 +1715,8 @@ export {
1493
1715
  TransitionParamsSchema,
1494
1716
  TransitionSchema,
1495
1717
  TxSchema,
1718
+ UNOFFERED_ENDPOINTS,
1719
+ UNREACHABLE_STATES,
1496
1720
  assertAllFixtures,
1497
1721
  assertFiatStepResponse,
1498
1722
  assertFixture,
@@ -1507,6 +1731,8 @@ export {
1507
1731
  looksLikeFieldSpec,
1508
1732
  stateKey,
1509
1733
  tableEntry,
1734
+ unofferedEndpoints,
1735
+ unreachableStates,
1510
1736
  walkTable
1511
1737
  };
1512
1738
  //# sourceMappingURL=index.mjs.map
package/dist/schemas.d.ts CHANGED
@@ -27,13 +27,15 @@
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, Transition, TransitionInputs, TransitionParams, Tx } from './types';
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';
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. */
34
34
  export declare const ENDPOINT_PATTERN: RegExp;
35
35
  export declare const FiatEndpointSchema: z.ZodType<FiatEndpoint>;
36
36
  export declare const FiatProviderSchema: z.ZodType<FiatProvider>;
37
+ export declare const KYCProviderSchema: z.ZodType<KYCProvider>;
38
+ export declare const SurfaceProviderSchema: z.ZodType<SurfaceProvider>;
37
39
  export declare const OrderStatusSchema: z.ZodType<OrderStatus>;
38
40
  export declare const RecoverySchema: z.ZodType<Recovery>;
39
41
  export declare const FailureReasonSchema: z.ZodType<FailureReason>;
@@ -47,6 +49,7 @@ export declare const OrderSummarySchema: z.ZodType<OrderSummary>;
47
49
  export declare const StatusHistoryEntrySchema: z.ZodType<StatusHistoryEntry>;
48
50
  export declare const TxSchema: z.ZodType<Tx>;
49
51
  export declare const RefundSchema: z.ZodType<Refund>;
52
+ export declare const SurfaceKindSchema: z.ZodType<SurfaceKind>;
50
53
  export declare const SurfaceSchema: z.ZodType<Surface>;
51
54
  export declare const InstructionFieldSchema: z.ZodType<InstructionField>;
52
55
  export declare const InstructionsSchema: z.ZodType<Instructions>;
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 `:id` stands for an order id, so
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 {
@@ -84,10 +83,45 @@ export interface TableEntry {
84
83
  export declare const TRANSITION_TABLE: Readonly<Record<StateKey, TableEntry>>;
85
84
  export declare const STATE_KEYS: StateKey[];
86
85
  /**
87
- * The `/fiat/*` surface as enumerated in contract §Endpoints. Informational data — emissions are
88
- * checked against each state's `allowedTransitions`, not against this list.
86
+ * The `/fiat/*` surface. Informational data — emissions are checked against each state's
87
+ * `allowedTransitions`, not against this list.
88
+ *
89
+ * Sourced from contract §Endpoints, with one deliberate divergence: `POST /fiat/payment-session` is
90
+ * named by the table (QUOTE's capture-first entry) while the doc's endpoint table still lists no
91
+ * session-minting call for that rail.
92
+ */
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"];
94
+ /**
95
+ * Documented endpoints no flow state offers, and why. Declared so an endpoint nothing can reach is
96
+ * visible instead of silent — the table test asserts the unoffered set equals exactly these.
97
+ */
98
+ export declare const UNOFFERED_ENDPOINTS: readonly {
99
+ endpoint: EndpointTemplate;
100
+ reason: string;
101
+ }[];
102
+ /**
103
+ * States entered out-of-band rather than by returning from a call. Declared so an unreachable state
104
+ * is visible instead of silent — the table test asserts reachability from QUOTE equals (all state
105
+ * keys − these).
106
+ */
107
+ export declare const UNREACHABLE_STATES: readonly {
108
+ stateKey: StateKey;
109
+ reason: string;
110
+ }[];
111
+ /**
112
+ * The live answer to what `UNOFFERED_ENDPOINTS` declares: documented endpoints that no state's
113
+ * `allowedTransitions` names. The table test asserts the two agree, so a new orphan and a stale
114
+ * declaration both fail.
115
+ */
116
+ export declare function unofferedEndpoints(): readonly EndpointTemplate[];
117
+ /**
118
+ * The live answer to what `UNREACHABLE_STATES` declares: states no `mayReturn` path reaches from
119
+ * `QUOTE`, the flow's entry. The table test asserts the two agree.
120
+ *
121
+ * `mayReturn` is the only edge set the contract publishes, so it is the only graph there is to walk
122
+ * — a state absent from every one of them cannot be arrived at by following the contract.
89
123
  */
90
- export declare const DOCUMENTED_ENDPOINTS: readonly ["GET /fiat/payment-methods", "POST /fiat/quote", "POST /fiat/auth", "POST /fiat/session", "POST /fiat/session/verify", "GET /fiat/kyc", "POST /fiat/kyc/form", "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"];
124
+ export declare function unreachableStates(from?: StateKey): readonly StateKey[];
91
125
  /** State → its table key. The one place kind/phase/reason is flattened. */
92
126
  export declare function stateKey(state: FlowState): StateKey;
93
127
  export declare const tableEntry: (state: FlowState) => TableEntry;