@fun-xyz/fiat-contract 0.17.0 → 0.19.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
@@ -13,12 +13,13 @@ Four things, zero runtime logic beyond validation:
13
13
  | `src/table.ts` | the transition table **as data**: per state, its legal transition set, the states any call from it may return, and `terminal: boolean` |
14
14
  | `src/assert.ts` + `src/fixtures/` | `assertFiatStepResponse` · `assertLegalEmission` · `assertLegalReturn` · `walkTable` · fixture loader + 18 recorded step responses (inlined as data — no filesystem, so React Native can bundle it) |
15
15
 
16
- ## Three entry points — production vs test-time
16
+ ## Four entry points — production vs test-time
17
17
 
18
18
  | Import | Weight | Contains | Used by |
19
19
  | --- | --- | --- | --- |
20
20
  | `@fun-xyz/fiat-contract/types` | **0.1 KB** (types erase) | every type; no runtime values | production, both repos |
21
21
  | `@fun-xyz/fiat-contract/table` | **13.8 KB**, zero deps | `TRANSITION_TABLE`, `stateKey`, `tableEntry`, `isTerminal`, `walkTable`, `TABLE_VERSION`, `TERMINAL_ORDER_STATUSES`, `DOCUMENTED_ENDPOINTS`, `UNOFFERED_ENDPOINTS`, `UNREACHABLE_STATES`, `unofferedEndpoints`, `unreachableStates` | **production frontend** + backend |
22
+ | `@fun-xyz/fiat-contract/moonpay` | zero deps | the MoonPay provider-owned flow: request, response, standing and fault types, and `MOONPAY_ENDPOINTS` | **production frontend** (MoonPay adapter) + backend |
22
23
  | `@fun-xyz/fiat-contract` | 47.6 KB, needs zod | the above + 46 zod schemas + assertions + 18 fixtures | tests, and backend dev/test guards |
23
24
 
24
25
  `./table` is not a micro-optimisation. Terminality is table data a **shipped** client must read
@@ -93,6 +94,24 @@ this package is [ENG-5268](https://linear.app/funxyz/issue/ENG-5268).
93
94
  is not active yet. A client exposes it only after a later response makes the same `quoteRef`
94
95
  executable; the prepared surface provider must match the response provider.
95
96
 
97
+ ## Provider-owned flows
98
+
99
+ A provider can run its own flow instead of the shared step machine. `POST /fiat/quote` still routes
100
+ and prices. When the request's `handoffs` lists the winning provider, the response carries
101
+ `handoff: { provider }` and no transitions, and the client calls that provider's routes under
102
+ `POST /fiat/providers/{provider}/…`. The schema refuses a handoff to a provider other than the
103
+ response's own, and a handoff that still offers transitions. When the provider records terms,
104
+ `handoff.termsAcceptance.version` names the revision; the client echoes it in `start`.
105
+
106
+ MoonPay is the first (`./moonpay`). Its routes are `start`, `intent`, `kyc`, and `complete`, in
107
+ `MOONPAY_ENDPOINTS`. Only `intent` decides: it answers with a `MoonPayStanding` (`READY`, `KYC`,
108
+ `PENDING`, or `REFUSED`). `kyc` answers `{ status: 'ACCEPTED' }`, and the client then calls `intent`.
109
+ `complete` answers with the same step response as `GET /fiat/orders/:orderId`. A fault is a 4xx or
110
+ 5xx with a `MoonPayErrorBody`: the shared `errorCode`, `errorMsg` and `reqId`, plus `reason`,
111
+ `recovery`, and `fields` on a rejected KYC value. `recovery` is `RETRY` (send the same request),
112
+ `REFRESH` (call `intent` for a new standing, as after a stale form), `REQUOTE`, or `NONE`. The zod
113
+ schemas (`MoonPay*Schema`) are exported from the root only. A handoff appears only on a `QUOTE`.
114
+
96
115
  ## KYC SDK hints, results, and client delivery
97
116
 
98
117
  `KYC_SDK` is a dedicated `Surface` union member. Its optional
@@ -444,7 +463,7 @@ Dual CJS + ESM, same shape as `@funkit/fun-relay`, because the two consumers loa
444
463
  | `require()` must work | `fun-backend/apps/api-server` compiles `module: commonjs` and runs plain node — no bundler | esbuild emits `dist/index.js` (CJS) + `dist/index.mjs` (ESM); `exports` maps `require`/`import`; no `"type": "module"` |
445
464
  | Zero Node builtins | `connect-core` is React Native — Metro cannot resolve `node:fs` | fixtures are inlined as generated TS data (`src/fixtures/data.ts`), so nothing touches the filesystem; `platform: browser`, every bare import external |
446
465
  | Subpath imports must resolve without `exports` support | Metro only reads `package.json#exports` from RN 0.79 on, and `@funkit/connect-rn` accepts `react-native: >=0.74` | root compat stubs `table.js` / `types.js` (+ `.d.ts`) that re-export `dist/`. Without them Metro fails with *"Unable to resolve module"* — verified, not theorised. Resolvers that do read `exports` never see the stubs |
447
- | Production code must not pull zod or fixtures | `connect-core` ships to React Native, where Metro does not tree-shake unused exports by default | three entry points: `./types` (erased), `./table` (13.8 KB, zero deps), root (schemas + fixtures, test-time). CI asserts `require('.../table')` never loads zod |
466
+ | Production code must not pull zod or fixtures | `connect-core` ships to React Native, where Metro does not tree-shake unused exports by default | four entry points: `./types` (erased), `./table` (13.8 KB, zero deps), `./moonpay` (zero deps), root (schemas + fixtures, test-time). CI asserts `require('.../table')` and `require('.../moonpay')` never load zod |
448
467
  | `.d.ts` must not lock a zod major | Both repos run `skipLibCheck: true`, which turns a broken declaration into a silent `any` | every exported schema is annotated `z.ZodType<T>`, so declarations name only `z.ZodType`; the structural drift checks stay module-private |
449
468
 
450
469
  Declarations come from `tsc --emitDeclarationOnly`; esbuild only emits JS. The fixture `.json` files
@@ -1,5 +1,5 @@
1
1
  // package.json
2
- var version = "0.17.0";
2
+ var version = "0.19.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-TXRBC2P2.mjs.map
517
+ //# sourceMappingURL=chunk-G3GKLFI2.mjs.map
@@ -0,0 +1,12 @@
1
+ // src/providers/moonpay.ts
2
+ var MOONPAY_ENDPOINTS = {
3
+ start: "POST /fiat/providers/moonpay/start",
4
+ intent: "POST /fiat/providers/moonpay/intent",
5
+ kyc: "POST /fiat/providers/moonpay/kyc",
6
+ complete: "POST /fiat/providers/moonpay/complete"
7
+ };
8
+
9
+ export {
10
+ MOONPAY_ENDPOINTS
11
+ };
12
+ //# sourceMappingURL=chunk-YWKS7MMT.mjs.map
package/dist/index.d.ts CHANGED
@@ -10,5 +10,7 @@ export * from './codes';
10
10
  export * from './schemas';
11
11
  export * from './table';
12
12
  export * from './assert';
13
+ export * from './providers/moonpay';
14
+ export * from './providers/moonpay.schemas';
13
15
  export { FIXTURES, FIXTURE_COVERAGE_GAPS, fixtureMeta, loadFixture, loadFixtures, type FixtureMeta, type FixtureSource, type LoadedFixture, } from './fixtures/index';
14
16
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -59,6 +59,18 @@ __export(index_exports, {
59
59
  KycInputRequiredStateSchema: () => KycInputRequiredStateSchema,
60
60
  KycNoActionRequiredStateSchema: () => KycNoActionRequiredStateSchema,
61
61
  KycSdkResultReportSchema: () => KycSdkResultReportSchema,
62
+ MOONPAY_ENDPOINTS: () => MOONPAY_ENDPOINTS,
63
+ MoonPayCompleteRequestSchema: () => MoonPayCompleteRequestSchema,
64
+ MoonPayCompleteResponseSchema: () => MoonPayCompleteResponseSchema,
65
+ MoonPayErrorBodySchema: () => MoonPayErrorBodySchema,
66
+ MoonPayFaultSchema: () => MoonPayFaultSchema,
67
+ MoonPayIntentRequestSchema: () => MoonPayIntentRequestSchema,
68
+ MoonPayIntentResponseSchema: () => MoonPayIntentResponseSchema,
69
+ MoonPayKycRequestSchema: () => MoonPayKycRequestSchema,
70
+ MoonPayKycResponseSchema: () => MoonPayKycResponseSchema,
71
+ MoonPayStandingSchema: () => MoonPayStandingSchema,
72
+ MoonPayStartRequestSchema: () => MoonPayStartRequestSchema,
73
+ MoonPayStartResponseSchema: () => MoonPayStartResponseSchema,
62
74
  OrderAwaitingConfirmationStateSchema: () => OrderAwaitingConfirmationStateSchema,
63
75
  OrderCreatedStateSchema: () => OrderCreatedStateSchema,
64
76
  OrderRefSchema: () => OrderRefSchema,
@@ -958,6 +970,7 @@ var $providerBoundStepResponse = obj({
958
970
  provider: $provider,
959
971
  transitions: import_zod.z.array($transition),
960
972
  preparedPayment: $preparedPayment.optional(),
973
+ handoff: obj({ provider: $provider, termsAcceptance: obj({ version: import_zod.z.string().min(1) }).optional() }).optional(),
961
974
  routingSessionRef: import_zod.z.string().optional(),
962
975
  providerAuthToken: obj({
963
976
  clientSecret: import_zod.z.string(),
@@ -973,6 +986,27 @@ var $providerBoundStepResponse = obj({
973
986
  message: "preparedPayment.surface.provider must match the response provider"
974
987
  });
975
988
  }
989
+ if (response.handoff !== void 0 && response.handoff.provider !== response.provider) {
990
+ context.addIssue({
991
+ code: "custom",
992
+ path: ["handoff", "provider"],
993
+ message: "handoff.provider must match the response provider"
994
+ });
995
+ }
996
+ if (response.handoff !== void 0 && response.state.kind !== "QUOTE") {
997
+ context.addIssue({
998
+ code: "custom",
999
+ path: ["handoff"],
1000
+ message: "only a QUOTE response hands off to a provider"
1001
+ });
1002
+ }
1003
+ if (response.handoff !== void 0 && response.transitions.length > 0) {
1004
+ context.addIssue({
1005
+ code: "custom",
1006
+ path: ["transitions"],
1007
+ message: "a handoff response carries no transitions"
1008
+ });
1009
+ }
976
1010
  });
977
1011
  var $blockedStepResponse = obj({
978
1012
  state: $blockedState,
@@ -990,7 +1024,7 @@ var $stepResponse = import_zod.z.union([$providerBoundStepResponse, $blockedStep
990
1024
  var FiatStepResponseSchema = $stepResponse;
991
1025
 
992
1026
  // package.json
993
- var version = "0.17.0";
1027
+ var version = "0.19.0";
994
1028
 
995
1029
  // src/table.ts
996
1030
  var TABLE_VERSION = version;
@@ -2555,4 +2589,75 @@ function assertFixture(id) {
2555
2589
  function assertAllFixtures() {
2556
2590
  return FIXTURES.map((meta) => assertFixture(meta.id));
2557
2591
  }
2592
+
2593
+ // src/providers/moonpay.ts
2594
+ var MOONPAY_ENDPOINTS = {
2595
+ start: "POST /fiat/providers/moonpay/start",
2596
+ intent: "POST /fiat/providers/moonpay/intent",
2597
+ kyc: "POST /fiat/providers/moonpay/kyc",
2598
+ complete: "POST /fiat/providers/moonpay/complete"
2599
+ };
2600
+
2601
+ // src/providers/moonpay.schemas.ts
2602
+ var import_zod2 = require("zod");
2603
+ var FIAT_CURRENCY_CODES2 = Object.keys(FIAT_CURRENCY_NAMES);
2604
+ var obj2 = (shape) => import_zod2.z.object(shape).strict();
2605
+ var $nonEmpty = import_zod2.z.string().refine((value) => value.trim().length > 0, "must not be blank");
2606
+ var $startRequest = obj2({
2607
+ amount: FiatAmountSchema,
2608
+ destination: obj2({ asset: $nonEmpty, network: $nonEmpty }),
2609
+ paymentMethod: import_zod2.z.literal("apple_pay"),
2610
+ geo: obj2({ alpha2: import_zod2.z.string().regex(/^[A-Z]{2}$/), region: $nonEmpty.optional(), ip: $nonEmpty.optional() }),
2611
+ termsAcceptance: obj2({ version: $nonEmpty, acceptedAt: import_zod2.z.string().datetime({ offset: true }) })
2612
+ });
2613
+ var MoonPayStartRequestSchema = $startRequest;
2614
+ var $quoteInput = obj2({
2615
+ source: obj2({ asset: obj2({ code: import_zod2.z.enum(FIAT_CURRENCY_CODES2) }), amount: $nonEmpty }),
2616
+ destination: obj2({ asset: obj2({ code: $nonEmpty }) }),
2617
+ wallet: obj2({ address: $nonEmpty }),
2618
+ paymentMethod: obj2({ type: import_zod2.z.literal("apple_pay") }),
2619
+ feeBehavior: import_zod2.z.literal("inclusive")
2620
+ });
2621
+ var $startResponse = obj2({ sessionToken: $nonEmpty, quoteInput: $quoteInput });
2622
+ var MoonPayStartResponseSchema = $startResponse;
2623
+ var $intentRequest = obj2({ customerId: $nonEmpty, accessToken: $nonEmpty });
2624
+ var MoonPayIntentRequestSchema = $intentRequest;
2625
+ var $refusal = import_zod2.z.enum(["DOCUMENTS_REQUIRED", "FINAL_REJECTION", "CUSTOMER_MISMATCH"]);
2626
+ var $standing = import_zod2.z.discriminatedUnion("status", [
2627
+ obj2({ status: import_zod2.z.literal("READY"), orderId: $nonEmpty }),
2628
+ obj2({ status: import_zod2.z.literal("KYC"), form: FormDescriptorSchema }),
2629
+ obj2({ status: import_zod2.z.literal("PENDING"), retryAfterMs: import_zod2.z.number().int().positive().max(6e4) }),
2630
+ obj2({ status: import_zod2.z.literal("REFUSED"), reason: $refusal, recovery: import_zod2.z.enum(["REQUOTE", "NONE"]) })
2631
+ ]);
2632
+ var MoonPayStandingSchema = $standing;
2633
+ var MoonPayIntentResponseSchema = $standing;
2634
+ var $kycRequest = obj2({ formId: $nonEmpty, values: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.string()) });
2635
+ var MoonPayKycRequestSchema = $kycRequest;
2636
+ var $kycResponse = obj2({ status: import_zod2.z.literal("ACCEPTED") });
2637
+ var MoonPayKycResponseSchema = $kycResponse;
2638
+ var $completeRequest = obj2({ orderId: $nonEmpty, transactionId: $nonEmpty });
2639
+ var MoonPayCompleteRequestSchema = $completeRequest;
2640
+ var MoonPayCompleteResponseSchema = FiatStepResponseSchema;
2641
+ var $fieldError = obj2({ fieldId: $nonEmpty, message: $nonEmpty });
2642
+ var $faultFields = {
2643
+ reason: import_zod2.z.enum([
2644
+ "NOT_ELIGIBLE",
2645
+ "SESSION_BUDGET_SPENT",
2646
+ "PROVIDER_UNAVAILABLE",
2647
+ "INVALID_VALUE",
2648
+ "STALE_FORM",
2649
+ "TRANSACTION_NOT_VISIBLE",
2650
+ "WALLET_MISMATCH"
2651
+ ]),
2652
+ recovery: import_zod2.z.enum(["RETRY", "REFRESH", "REQUOTE", "NONE"]),
2653
+ fields: import_zod2.z.array($fieldError).min(1).optional()
2654
+ };
2655
+ var fieldsOnlyOnInvalidValue = (fault) => fault.reason === "INVALID_VALUE" === (fault.fields !== void 0);
2656
+ var $fault = obj2($faultFields).refine(fieldsOnlyOnInvalidValue, "fields is present exactly when reason is INVALID_VALUE");
2657
+ var MoonPayFaultSchema = $fault;
2658
+ var $errorBody = obj2({ ...$faultFields, errorCode: $nonEmpty, errorMsg: import_zod2.z.string(), reqId: import_zod2.z.string().optional() }).refine(
2659
+ fieldsOnlyOnInvalidValue,
2660
+ "fields is present exactly when reason is INVALID_VALUE"
2661
+ );
2662
+ var MoonPayErrorBodySchema = $errorBody;
2558
2663
  //# sourceMappingURL=index.js.map
package/dist/index.mjs CHANGED
@@ -12,7 +12,10 @@ import {
12
12
  tableEntry,
13
13
  unofferedEndpoints,
14
14
  unreachableStates
15
- } from "./chunk-TXRBC2P2.mjs";
15
+ } from "./chunk-G3GKLFI2.mjs";
16
+ import {
17
+ MOONPAY_ENDPOINTS
18
+ } from "./chunk-YWKS7MMT.mjs";
16
19
 
17
20
  // src/codes.ts
18
21
  var US_STATE_CODES = [
@@ -853,6 +856,7 @@ var $providerBoundStepResponse = obj({
853
856
  provider: $provider,
854
857
  transitions: z.array($transition),
855
858
  preparedPayment: $preparedPayment.optional(),
859
+ handoff: obj({ provider: $provider, termsAcceptance: obj({ version: z.string().min(1) }).optional() }).optional(),
856
860
  routingSessionRef: z.string().optional(),
857
861
  providerAuthToken: obj({
858
862
  clientSecret: z.string(),
@@ -868,6 +872,27 @@ var $providerBoundStepResponse = obj({
868
872
  message: "preparedPayment.surface.provider must match the response provider"
869
873
  });
870
874
  }
875
+ if (response.handoff !== void 0 && response.handoff.provider !== response.provider) {
876
+ context.addIssue({
877
+ code: "custom",
878
+ path: ["handoff", "provider"],
879
+ message: "handoff.provider must match the response provider"
880
+ });
881
+ }
882
+ if (response.handoff !== void 0 && response.state.kind !== "QUOTE") {
883
+ context.addIssue({
884
+ code: "custom",
885
+ path: ["handoff"],
886
+ message: "only a QUOTE response hands off to a provider"
887
+ });
888
+ }
889
+ if (response.handoff !== void 0 && response.transitions.length > 0) {
890
+ context.addIssue({
891
+ code: "custom",
892
+ path: ["transitions"],
893
+ message: "a handoff response carries no transitions"
894
+ });
895
+ }
871
896
  });
872
897
  var $blockedStepResponse = obj({
873
898
  state: $blockedState,
@@ -1948,6 +1973,69 @@ function assertFixture(id) {
1948
1973
  function assertAllFixtures() {
1949
1974
  return FIXTURES.map((meta) => assertFixture(meta.id));
1950
1975
  }
1976
+
1977
+ // src/providers/moonpay.schemas.ts
1978
+ import { z as z2 } from "zod";
1979
+ var FIAT_CURRENCY_CODES2 = Object.keys(FIAT_CURRENCY_NAMES);
1980
+ var obj2 = (shape) => z2.object(shape).strict();
1981
+ var $nonEmpty = z2.string().refine((value) => value.trim().length > 0, "must not be blank");
1982
+ var $startRequest = obj2({
1983
+ amount: FiatAmountSchema,
1984
+ destination: obj2({ asset: $nonEmpty, network: $nonEmpty }),
1985
+ paymentMethod: z2.literal("apple_pay"),
1986
+ geo: obj2({ alpha2: z2.string().regex(/^[A-Z]{2}$/), region: $nonEmpty.optional(), ip: $nonEmpty.optional() }),
1987
+ termsAcceptance: obj2({ version: $nonEmpty, acceptedAt: z2.string().datetime({ offset: true }) })
1988
+ });
1989
+ var MoonPayStartRequestSchema = $startRequest;
1990
+ var $quoteInput = obj2({
1991
+ source: obj2({ asset: obj2({ code: z2.enum(FIAT_CURRENCY_CODES2) }), amount: $nonEmpty }),
1992
+ destination: obj2({ asset: obj2({ code: $nonEmpty }) }),
1993
+ wallet: obj2({ address: $nonEmpty }),
1994
+ paymentMethod: obj2({ type: z2.literal("apple_pay") }),
1995
+ feeBehavior: z2.literal("inclusive")
1996
+ });
1997
+ var $startResponse = obj2({ sessionToken: $nonEmpty, quoteInput: $quoteInput });
1998
+ var MoonPayStartResponseSchema = $startResponse;
1999
+ var $intentRequest = obj2({ customerId: $nonEmpty, accessToken: $nonEmpty });
2000
+ var MoonPayIntentRequestSchema = $intentRequest;
2001
+ var $refusal = z2.enum(["DOCUMENTS_REQUIRED", "FINAL_REJECTION", "CUSTOMER_MISMATCH"]);
2002
+ var $standing = z2.discriminatedUnion("status", [
2003
+ obj2({ status: z2.literal("READY"), orderId: $nonEmpty }),
2004
+ obj2({ status: z2.literal("KYC"), form: FormDescriptorSchema }),
2005
+ obj2({ status: z2.literal("PENDING"), retryAfterMs: z2.number().int().positive().max(6e4) }),
2006
+ obj2({ status: z2.literal("REFUSED"), reason: $refusal, recovery: z2.enum(["REQUOTE", "NONE"]) })
2007
+ ]);
2008
+ var MoonPayStandingSchema = $standing;
2009
+ var MoonPayIntentResponseSchema = $standing;
2010
+ var $kycRequest = obj2({ formId: $nonEmpty, values: z2.record(z2.string(), z2.string()) });
2011
+ var MoonPayKycRequestSchema = $kycRequest;
2012
+ var $kycResponse = obj2({ status: z2.literal("ACCEPTED") });
2013
+ var MoonPayKycResponseSchema = $kycResponse;
2014
+ var $completeRequest = obj2({ orderId: $nonEmpty, transactionId: $nonEmpty });
2015
+ var MoonPayCompleteRequestSchema = $completeRequest;
2016
+ var MoonPayCompleteResponseSchema = FiatStepResponseSchema;
2017
+ var $fieldError = obj2({ fieldId: $nonEmpty, message: $nonEmpty });
2018
+ var $faultFields = {
2019
+ reason: z2.enum([
2020
+ "NOT_ELIGIBLE",
2021
+ "SESSION_BUDGET_SPENT",
2022
+ "PROVIDER_UNAVAILABLE",
2023
+ "INVALID_VALUE",
2024
+ "STALE_FORM",
2025
+ "TRANSACTION_NOT_VISIBLE",
2026
+ "WALLET_MISMATCH"
2027
+ ]),
2028
+ recovery: z2.enum(["RETRY", "REFRESH", "REQUOTE", "NONE"]),
2029
+ fields: z2.array($fieldError).min(1).optional()
2030
+ };
2031
+ var fieldsOnlyOnInvalidValue = (fault) => fault.reason === "INVALID_VALUE" === (fault.fields !== void 0);
2032
+ var $fault = obj2($faultFields).refine(fieldsOnlyOnInvalidValue, "fields is present exactly when reason is INVALID_VALUE");
2033
+ var MoonPayFaultSchema = $fault;
2034
+ var $errorBody = obj2({ ...$faultFields, errorCode: $nonEmpty, errorMsg: z2.string(), reqId: z2.string().optional() }).refine(
2035
+ fieldsOnlyOnInvalidValue,
2036
+ "fields is present exactly when reason is INVALID_VALUE"
2037
+ );
2038
+ var MoonPayErrorBodySchema = $errorBody;
1951
2039
  export {
1952
2040
  AuthChallengeSchema,
1953
2041
  BlockedReasonSchema,
@@ -1988,6 +2076,18 @@ export {
1988
2076
  KycInputRequiredStateSchema,
1989
2077
  KycNoActionRequiredStateSchema,
1990
2078
  KycSdkResultReportSchema,
2079
+ MOONPAY_ENDPOINTS,
2080
+ MoonPayCompleteRequestSchema,
2081
+ MoonPayCompleteResponseSchema,
2082
+ MoonPayErrorBodySchema,
2083
+ MoonPayFaultSchema,
2084
+ MoonPayIntentRequestSchema,
2085
+ MoonPayIntentResponseSchema,
2086
+ MoonPayKycRequestSchema,
2087
+ MoonPayKycResponseSchema,
2088
+ MoonPayStandingSchema,
2089
+ MoonPayStartRequestSchema,
2090
+ MoonPayStartResponseSchema,
1991
2091
  OrderAwaitingConfirmationStateSchema,
1992
2092
  OrderCreatedStateSchema,
1993
2093
  OrderRefSchema,
@@ -0,0 +1,131 @@
1
+ /**
2
+ * The MoonPay provider-owned flow: `POST /fiat/providers/moonpay/{start,intent,kyc,complete}`.
3
+ *
4
+ * Only `intent` decides what happens next. `kyc` confirms a write or rejects it with field errors,
5
+ * and the client then calls `intent` again. Identity and the deposit wallet always come from the
6
+ * verified partner assertion, never from a request body.
7
+ *
8
+ * A fault is a 4xx/5xx whose body is the shared error body plus `MoonPayFault`. A decision the user
9
+ * can act on is a 200 `MoonPayStanding`.
10
+ *
11
+ * Zero runtime dependencies, so production React Native code can import it. The zod schemas are in
12
+ * `./moonpay.schemas`, exported from the package root.
13
+ */
14
+ import type { FiatCurrencyCode } from '../codes';
15
+ import type { FiatAmount, FiatStepResponse, FormDescriptor, TermsAcceptance } from '../types';
16
+ export declare const MOONPAY_ENDPOINTS: {
17
+ readonly start: "POST /fiat/providers/moonpay/start";
18
+ readonly intent: "POST /fiat/providers/moonpay/intent";
19
+ readonly kyc: "POST /fiat/providers/moonpay/kyc";
20
+ readonly complete: "POST /fiat/providers/moonpay/complete";
21
+ };
22
+ export interface MoonPayStartRequest {
23
+ amount: FiatAmount;
24
+ /** The quote's `crypto.currency` and `crypto.network`, unchanged. */
25
+ destination: {
26
+ asset: string;
27
+ network: string;
28
+ };
29
+ paymentMethod: 'apple_pay';
30
+ /** The geo endpoint's response, as sent to `POST /fiat/quote`. `alpha2` is ISO 3166-1 alpha-2. */
31
+ geo: {
32
+ alpha2: string;
33
+ region?: string;
34
+ ip?: string;
35
+ };
36
+ /** The MoonPay terms notice on the amount screen; the tap is the acceptance. */
37
+ termsAcceptance: TermsAcceptance;
38
+ }
39
+ /**
40
+ * The parameters for the device `client.getQuote`, not a quote. The backend builds them because the
41
+ * wallet must be the verified one and MoonPay's currency codes differ by environment.
42
+ */
43
+ export interface MoonPayQuoteInput {
44
+ source: {
45
+ asset: {
46
+ code: FiatCurrencyCode;
47
+ };
48
+ amount: string;
49
+ };
50
+ destination: {
51
+ asset: {
52
+ code: string;
53
+ };
54
+ };
55
+ wallet: {
56
+ address: string;
57
+ };
58
+ paymentMethod: {
59
+ type: 'apple_pay';
60
+ };
61
+ feeBehavior: 'inclusive';
62
+ }
63
+ export interface MoonPayStartResponse {
64
+ /** The one SDK session, for the connection check, the auth frames, and the Apple Pay button. */
65
+ sessionToken: string;
66
+ quoteInput: MoonPayQuoteInput;
67
+ }
68
+ export interface MoonPayIntentRequest {
69
+ /** From the SDK's `active` connection. */
70
+ customerId: string;
71
+ /** From the SDK's `active` connection. A credential: the backend strips it from every log. */
72
+ accessToken: string;
73
+ }
74
+ export type MoonPayRefusal = 'DOCUMENTS_REQUIRED' | 'FINAL_REJECTION' | 'CUSTOMER_MISMATCH';
75
+ export type MoonPayStanding =
76
+ /** `orderId` is the `externalTransactionId` for the Apple Pay button. */
77
+ {
78
+ status: 'READY';
79
+ orderId: string;
80
+ } | {
81
+ status: 'KYC';
82
+ form: FormDescriptor;
83
+ } | {
84
+ status: 'PENDING';
85
+ retryAfterMs: number;
86
+ } | {
87
+ status: 'REFUSED';
88
+ reason: MoonPayRefusal;
89
+ recovery: 'REQUOTE' | 'NONE';
90
+ };
91
+ export type MoonPayIntentResponse = MoonPayStanding;
92
+ export interface MoonPayKycRequest {
93
+ /** From the `KYC` standing. A stale one is a 409 `STALE_FORM` with recovery `REFRESH`. */
94
+ formId: string;
95
+ /** One string per form field id. */
96
+ values: Record<string, string>;
97
+ }
98
+ /** The write landed. The client calls `intent` next. */
99
+ export interface MoonPayKycResponse {
100
+ status: 'ACCEPTED';
101
+ }
102
+ export interface MoonPayCompleteRequest {
103
+ orderId: string;
104
+ /** From the Apple Pay completion event. */
105
+ transactionId: string;
106
+ }
107
+ /** The same response as `GET /fiat/orders/:orderId`, so the shared order screen renders it. */
108
+ export type MoonPayCompleteResponse = FiatStepResponse;
109
+ /**
110
+ * `RETRY` sends the same request again. `REFRESH` calls `intent` for a new standing. `REQUOTE` goes
111
+ * back to `POST /fiat/quote`. `NONE` ends the flow.
112
+ */
113
+ export type MoonPayRecovery = 'RETRY' | 'REFRESH' | 'REQUOTE' | 'NONE';
114
+ export type MoonPayFaultReason = 'NOT_ELIGIBLE' | 'SESSION_BUDGET_SPENT' | 'PROVIDER_UNAVAILABLE' | 'INVALID_VALUE' | 'STALE_FORM' | 'TRANSACTION_NOT_VISIBLE' | 'WALLET_MISMATCH';
115
+ export interface MoonPayFieldError {
116
+ fieldId: string;
117
+ message: string;
118
+ }
119
+ /** The fields a MoonPay route adds to the shared error body. `fields` is only on `INVALID_VALUE`. */
120
+ export interface MoonPayFault {
121
+ reason: MoonPayFaultReason;
122
+ recovery: MoonPayRecovery;
123
+ fields?: MoonPayFieldError[];
124
+ }
125
+ /** A MoonPay route's 4xx/5xx body: the shared error body plus `MoonPayFault`. */
126
+ export type MoonPayErrorBody = MoonPayFault & {
127
+ errorCode: string;
128
+ errorMsg: string;
129
+ reqId?: string;
130
+ };
131
+ //# sourceMappingURL=moonpay.d.ts.map
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/providers/moonpay.ts
21
+ var moonpay_exports = {};
22
+ __export(moonpay_exports, {
23
+ MOONPAY_ENDPOINTS: () => MOONPAY_ENDPOINTS
24
+ });
25
+ module.exports = __toCommonJS(moonpay_exports);
26
+ var MOONPAY_ENDPOINTS = {
27
+ start: "POST /fiat/providers/moonpay/start",
28
+ intent: "POST /fiat/providers/moonpay/intent",
29
+ kyc: "POST /fiat/providers/moonpay/kyc",
30
+ complete: "POST /fiat/providers/moonpay/complete"
31
+ };
32
+ //# sourceMappingURL=moonpay.js.map
@@ -0,0 +1,7 @@
1
+ import {
2
+ MOONPAY_ENDPOINTS
3
+ } from "../chunk-YWKS7MMT.mjs";
4
+ export {
5
+ MOONPAY_ENDPOINTS
6
+ };
7
+ //# sourceMappingURL=moonpay.mjs.map
@@ -0,0 +1,18 @@
1
+ /**
2
+ * zod schemas for the MoonPay provider-owned flow. Test-time and backend-boundary only: exported from
3
+ * the package root, never from `./moonpay`, so the production entry stays free of zod.
4
+ */
5
+ import { z } from 'zod';
6
+ import type { MoonPayCompleteRequest, MoonPayCompleteResponse, MoonPayErrorBody, MoonPayFault, MoonPayIntentRequest, MoonPayIntentResponse, MoonPayKycRequest, MoonPayKycResponse, MoonPayStanding, MoonPayStartRequest, MoonPayStartResponse } from './moonpay';
7
+ export declare const MoonPayStartRequestSchema: z.ZodType<MoonPayStartRequest>;
8
+ export declare const MoonPayStartResponseSchema: z.ZodType<MoonPayStartResponse>;
9
+ export declare const MoonPayIntentRequestSchema: z.ZodType<MoonPayIntentRequest>;
10
+ export declare const MoonPayStandingSchema: z.ZodType<MoonPayStanding>;
11
+ export declare const MoonPayIntentResponseSchema: z.ZodType<MoonPayIntentResponse>;
12
+ export declare const MoonPayKycRequestSchema: z.ZodType<MoonPayKycRequest>;
13
+ export declare const MoonPayKycResponseSchema: z.ZodType<MoonPayKycResponse>;
14
+ export declare const MoonPayCompleteRequestSchema: z.ZodType<MoonPayCompleteRequest>;
15
+ export declare const MoonPayCompleteResponseSchema: z.ZodType<MoonPayCompleteResponse>;
16
+ export declare const MoonPayFaultSchema: z.ZodType<MoonPayFault>;
17
+ export declare const MoonPayErrorBodySchema: z.ZodType<MoonPayErrorBody>;
18
+ //# sourceMappingURL=moonpay.schemas.d.ts.map
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.17.0";
39
+ var version = "0.19.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-TXRBC2P2.mjs";
14
+ } from "./chunk-G3GKLFI2.mjs";
15
15
  export {
16
16
  DOCUMENTED_ENDPOINTS,
17
17
  STATE_KEYS,
package/dist/types.d.ts CHANGED
@@ -714,6 +714,17 @@ export type FiatStepResponse = (FiatStepResponseBase & {
714
714
  provider: FiatProvider;
715
715
  /** Optional future payment artifact; never one of this response's currently active transitions. */
716
716
  preparedPayment?: PreparedPayment;
717
+ /**
718
+ * The provider runs its own flow from here (`POST /fiat/providers/{provider}/…`). Present only
719
+ * when the request's `handoffs` named this provider; the response then carries no transitions.
720
+ */
721
+ handoff?: {
722
+ provider: FiatProvider;
723
+ /** The terms revision the provider's `start` records; echo it in `termsAcceptance.version`. */
724
+ termsAcceptance?: {
725
+ version: string;
726
+ };
727
+ };
717
728
  });
718
729
  export {};
719
730
  //# sourceMappingURL=types.d.ts.map
package/moonpay.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './dist/providers/moonpay';
package/moonpay.js ADDED
@@ -0,0 +1,2 @@
1
+ // Compat stub — see table.js. Metro before RN 0.79 resolves `@fun-xyz/fiat-contract/moonpay` by path.
2
+ module.exports = require('./dist/providers/moonpay.js');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fun-xyz/fiat-contract",
3
- "version": "0.17.0",
3
+ "version": "0.19.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": {
@@ -28,6 +28,11 @@
28
28
  "import": "./dist/table.mjs",
29
29
  "require": "./dist/table.js"
30
30
  },
31
+ "./moonpay": {
32
+ "types": "./dist/providers/moonpay.d.ts",
33
+ "import": "./dist/providers/moonpay.mjs",
34
+ "require": "./dist/providers/moonpay.js"
35
+ },
31
36
  "./package.json": "./package.json"
32
37
  },
33
38
  "files": [
@@ -36,6 +41,8 @@
36
41
  "table.d.ts",
37
42
  "types.js",
38
43
  "types.d.ts",
44
+ "moonpay.js",
45
+ "moonpay.d.ts",
39
46
  "README.md",
40
47
  "!dist/**/*.map"
41
48
  ],
@@ -75,6 +82,9 @@
75
82
  ],
76
83
  "table": [
77
84
  "./dist/table.d.ts"
85
+ ],
86
+ "moonpay": [
87
+ "./dist/providers/moonpay.d.ts"
78
88
  ]
79
89
  }
80
90
  }