@fun-xyz/fiat-contract 0.24.0 → 0.25.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
@@ -133,31 +133,38 @@ cause is unknown. Refetch the table at `expiresAt`, on `refreshLimits: true`, an
133
133
  a `REQUOTE`. The schemas hold the table's invariants: each method once, sorted, non-overlapping
134
134
  intervals, at least one provider each and none twice, and a reason only on an empty method.
135
135
 
136
- `ROUTING_ENDPOINTS.quote` (`POST /fiat/routing/quote`) takes the `POST /fiat/quote` body plus the
137
- interval's first `provider`, never `routingOverrides`, and answers the same `FiatStepResponse`. A
138
- refusal is a `FiatRoutingQuoteErrorBody`, and it decides whether to quote the interval's next
139
- provider:
136
+ `ROUTING_ENDPOINTS.quote` (`POST /fiat/routing/quote`) takes the `POST /fiat/quote` body
137
+ (`FiatRoutingQuoteTerms`), never `routingOverrides`, plus one of two forms:
138
+
139
+ - `providers`: the interval's providers, best first. The backend prices them in order, falls
140
+ through on the refusals marked "next provider" below, and answers the first that prices or the
141
+ last provider's refusal.
142
+ - `provider`: one provider only. The client falls through itself.
143
+
144
+ It answers the same `FiatStepResponse`, whose `provider` names the one that priced. A refusal is a
145
+ `FiatRoutingQuoteErrorBody`, and it decides whether the next provider may still price:
140
146
 
141
147
  | Status | `errorCode` | Then |
142
148
  | --- | --- | --- |
143
- | 404 | `FiatNoRouteError`, `reason` `NO_CANDIDATE`, `PROVIDER_DECLINED`, `PROVIDER_OUTAGE` or `KYC_REJECTED` | quote the next provider |
144
- | 400 | `FiatNoRouteError`, `reason: USER_LIMIT`, `code: LIMITS_EXCEEDED`, `recovery: REQUOTE` | quote the next provider |
145
- | 400 | `FiatAmountBelowMinimumError` (`minFiatAmount`) or `FiatAmountAboveMaximumError` (`maxFiatAmount`) | quote the next provider |
149
+ | 404 | `FiatNoRouteError`, `reason` `NO_CANDIDATE`, `PROVIDER_DECLINED`, `PROVIDER_OUTAGE` or `KYC_REJECTED` | next provider |
150
+ | 400 | `FiatNoRouteError`, `reason: USER_LIMIT`, `code: LIMITS_EXCEEDED`, `recovery: REQUOTE` | next provider |
151
+ | 400 | `FiatAmountBelowMinimumError` (`minFiatAmount`) or `FiatAmountAboveMaximumError` (`maxFiatAmount`) | next provider |
146
152
  | 400 | `InvalidParameterError`: a bad request, an asset Fun cannot deliver, or no verified email | stop |
147
153
  | 401, 5xx | any other: a missing or invalid identity assertion, or a server error | stop |
148
154
 
149
- Every fall-through refusal is the named provider's alone, because the route prices only that
150
- provider: `KYC_REJECTED` there means that provider refused the buyer's identity, not every provider.
151
- With no provider left in the interval, refetch the table. The table route refuses with a
155
+ Every fall-through refusal is that provider's alone, because each attempt prices only one provider:
156
+ `KYC_REJECTED` there means that provider refused the buyer's identity, not every provider. With no
157
+ provider left in the interval, refetch the table. The table route refuses with a
152
158
  `FiatRoutingTableErrorBody`: a 429 `TooManyRequestsError` with `retryAfterSeconds` when the
153
159
  per-login budget is spent, or a 400 or 5xx as above. The quote route has no rate limit of its own.
154
160
 
155
161
  Both routes take geo under the `POST /fiat/quote` rules: a known `CountryCode`, a `UsStateCode`
156
162
  region for a US buyer, and an empty `region` or `ip` read as absent. The quote route's `geo` is the
157
163
  Fun geo endpoint's response forwarded as is. The request schemas are strict like every schema here,
158
- so a client sends only the declared keys and no blank strings. `provider` is one of the five
159
- providers the backend routes (`RoutingProvider`). The quote route is temporary: `POST /fiat/next`
160
- replaces it for each provider that moves there.
164
+ so a client sends only the declared keys and no blank strings. `provider` and each `providers`
165
+ entry are one of the five providers the backend routes (`RoutingProvider`), `providers` with no
166
+ duplicates. The quote route is temporary: `POST /fiat/next` replaces it for each provider that
167
+ moves there.
161
168
 
162
169
  **MoonPay (`./moonpay`).** MoonPay runs on the shared `POST /fiat/next` (`MOONPAY_ENDPOINTS.next`).
163
170
  Every `/next` body is a `FiatNextRequest`: `provider`, `geo` (a `FiatGeo`, the geo endpoint's
@@ -1,5 +1,5 @@
1
1
  // package.json
2
- var version = "0.24.0";
2
+ var version = "0.25.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-IPOPANXS.mjs.map
517
+ //# sourceMappingURL=chunk-LHCED3AP.mjs.map
@@ -8,4 +8,4 @@ var ROUTING_ENDPOINTS = {
8
8
  export {
9
9
  ROUTING_ENDPOINTS
10
10
  };
11
- //# sourceMappingURL=chunk-5UEPWL7B.mjs.map
11
+ //# sourceMappingURL=chunk-WEXD7UEE.mjs.map
package/dist/index.js CHANGED
@@ -47,6 +47,7 @@ __export(index_exports, {
47
47
  FiatProviderSchema: () => FiatProviderSchema,
48
48
  FiatRoutingQuoteErrorBodySchema: () => FiatRoutingQuoteErrorBodySchema,
49
49
  FiatRoutingQuoteRequestSchema: () => FiatRoutingQuoteRequestSchema,
50
+ FiatRoutingQuoteTermsSchema: () => FiatRoutingQuoteTermsSchema,
50
51
  FiatRoutingTableErrorBodySchema: () => FiatRoutingTableErrorBodySchema,
51
52
  FiatRoutingTableQuerySchema: () => FiatRoutingTableQuerySchema,
52
53
  FiatRoutingTableResponseSchema: () => FiatRoutingTableResponseSchema,
@@ -1088,8 +1089,7 @@ var $routingTableResponse = obj({
1088
1089
  methods: import_zod.z.array($routingTableMethod).refine((methods) => hasUniqueIds(methods.map((entry) => entry.method)), "each method is listed once")
1089
1090
  });
1090
1091
  var FiatRoutingTableResponseSchema = $routingTableResponse;
1091
- var $routingQuoteRequest = obj({
1092
- provider: $routingProvider,
1092
+ var $routingQuoteTermsShape = {
1093
1093
  fiatCurrency: import_zod.z.enum(FIAT_CURRENCY_CODES),
1094
1094
  fiatAmount: $decimalAmount.refine((amount) => Number(amount) > 0, "must be positive"),
1095
1095
  cryptoCurrencyCode: $nonBlank,
@@ -1100,7 +1100,16 @@ var $routingQuoteRequest = obj({
1100
1100
  { message: US_REGION_REQUIRED, path: ["region"] }
1101
1101
  ),
1102
1102
  prepareSessionAuth: import_zod.z.boolean().optional()
1103
- });
1103
+ };
1104
+ var $routingQuoteTerms = obj($routingQuoteTermsShape);
1105
+ var FiatRoutingQuoteTermsSchema = $routingQuoteTerms;
1106
+ var $routingQuoteRequest = import_zod.z.union([
1107
+ obj({
1108
+ ...$routingQuoteTermsShape,
1109
+ providers: import_zod.z.array($routingProvider).min(1).refine((providers) => hasUniqueIds(providers), "each provider is listed once")
1110
+ }),
1111
+ obj({ ...$routingQuoteTermsShape, provider: $routingProvider })
1112
+ ]);
1104
1113
  var FiatRoutingQuoteRequestSchema = $routingQuoteRequest;
1105
1114
  var $routingServiceableRange = obj({ min: $money, max: $money, userMax: $money.nullable().optional() });
1106
1115
  var $noRouteFields = {
@@ -1200,7 +1209,7 @@ var $stepResponse = import_zod.z.union([$providerBoundStepResponse, $blockedStep
1200
1209
  var FiatStepResponseSchema = $stepResponse;
1201
1210
 
1202
1211
  // package.json
1203
- var version = "0.24.0";
1212
+ var version = "0.25.0";
1204
1213
 
1205
1214
  // src/table.ts
1206
1215
  var TABLE_VERSION = version;
package/dist/index.mjs CHANGED
@@ -12,7 +12,7 @@ import {
12
12
  tableEntry,
13
13
  unofferedEndpoints,
14
14
  unreachableStates
15
- } from "./chunk-IPOPANXS.mjs";
15
+ } from "./chunk-LHCED3AP.mjs";
16
16
  import {
17
17
  MOONPAY_ENDPOINTS
18
18
  } from "./chunk-T5JAYOWY.mjs";
@@ -24,7 +24,7 @@ import {
24
24
  } from "./chunk-CRNKRIKR.mjs";
25
25
  import {
26
26
  ROUTING_ENDPOINTS
27
- } from "./chunk-5UEPWL7B.mjs";
27
+ } from "./chunk-WEXD7UEE.mjs";
28
28
 
29
29
  // src/codes.ts
30
30
  var US_STATE_CODES = [
@@ -953,8 +953,7 @@ var $routingTableResponse = obj({
953
953
  methods: z.array($routingTableMethod).refine((methods) => hasUniqueIds(methods.map((entry) => entry.method)), "each method is listed once")
954
954
  });
955
955
  var FiatRoutingTableResponseSchema = $routingTableResponse;
956
- var $routingQuoteRequest = obj({
957
- provider: $routingProvider,
956
+ var $routingQuoteTermsShape = {
958
957
  fiatCurrency: z.enum(FIAT_CURRENCY_CODES),
959
958
  fiatAmount: $decimalAmount.refine((amount) => Number(amount) > 0, "must be positive"),
960
959
  cryptoCurrencyCode: $nonBlank,
@@ -965,7 +964,16 @@ var $routingQuoteRequest = obj({
965
964
  { message: US_REGION_REQUIRED, path: ["region"] }
966
965
  ),
967
966
  prepareSessionAuth: z.boolean().optional()
968
- });
967
+ };
968
+ var $routingQuoteTerms = obj($routingQuoteTermsShape);
969
+ var FiatRoutingQuoteTermsSchema = $routingQuoteTerms;
970
+ var $routingQuoteRequest = z.union([
971
+ obj({
972
+ ...$routingQuoteTermsShape,
973
+ providers: z.array($routingProvider).min(1).refine((providers) => hasUniqueIds(providers), "each provider is listed once")
974
+ }),
975
+ obj({ ...$routingQuoteTermsShape, provider: $routingProvider })
976
+ ]);
969
977
  var FiatRoutingQuoteRequestSchema = $routingQuoteRequest;
970
978
  var $routingServiceableRange = obj({ min: $money, max: $money, userMax: $money.nullable().optional() });
971
979
  var $noRouteFields = {
@@ -2287,6 +2295,7 @@ export {
2287
2295
  FiatProviderSchema,
2288
2296
  FiatRoutingQuoteErrorBodySchema,
2289
2297
  FiatRoutingQuoteRequestSchema,
2298
+ FiatRoutingQuoteTermsSchema,
2290
2299
  FiatRoutingTableErrorBodySchema,
2291
2300
  FiatRoutingTableQuerySchema,
2292
2301
  FiatRoutingTableResponseSchema,
package/dist/routing.d.ts CHANGED
@@ -82,13 +82,8 @@ export interface FiatRoutingTableResponse {
82
82
  /** In request order, duplicates removed. */
83
83
  methods: RoutingTableMethod[];
84
84
  }
85
- /**
86
- * The `POST /fiat/quote` body plus the one `provider` to price, which is the interval's first
87
- * provider, and never `routingOverrides`. The response is the same `FiatStepResponse` as
88
- * `POST /fiat/quote`; a refusal is a `FiatRoutingQuoteErrorBody`.
89
- */
90
- export interface FiatRoutingQuoteRequest {
91
- provider: RoutingProvider;
85
+ /** The `POST /fiat/quote` body without `routingOverrides`: everything but which providers to price. */
86
+ export interface FiatRoutingQuoteTerms {
92
87
  fiatCurrency: FiatCurrencyCode;
93
88
  /** A positive decimal string with no leading zero, exponent or sign (`"20"`, `"20.5"`). */
94
89
  fiatAmount: string;
@@ -107,6 +102,25 @@ export interface FiatRoutingQuoteRequest {
107
102
  };
108
103
  prepareSessionAuth?: boolean;
109
104
  }
105
+ /**
106
+ * `POST /fiat/routing/quote`: the terms plus which providers to price, in one of two forms.
107
+ *
108
+ * - `providers`: the interval's providers, best first. The backend prices the first, and falls
109
+ * through to the next on a refusal that is that provider's alone (a `FiatNoRouteError` of any
110
+ * `reason`, or either amount error), as the client did before. It answers the first provider that
111
+ * prices, or the last provider's refusal. Any other refusal stops at once.
112
+ * - `provider`: one provider only, with no fall-through. Kept for clients that fall through themselves.
113
+ *
114
+ * The response is the same `FiatStepResponse` as `POST /fiat/quote`, and its `provider` names the
115
+ * one that priced. A refusal is a `FiatRoutingQuoteErrorBody`.
116
+ */
117
+ export type FiatRoutingQuoteRequest = FiatRoutingQuoteTerms & ({
118
+ providers: RoutingProvider[];
119
+ provider?: never;
120
+ } | {
121
+ provider: RoutingProvider;
122
+ providers?: never;
123
+ });
110
124
  /** One serviceable range of the named provider. `userMax` is this buyer's own ceiling inside it, `null` when unmeasured. */
111
125
  export interface RoutingServiceableRange {
112
126
  min: FiatAmount;
@@ -160,8 +174,9 @@ export type RoutingFaultErrorBody = ErrorBodyFields & {
160
174
  export type FiatRoutingTableErrorBody = RoutingRateLimitedErrorBody | RoutingFaultErrorBody;
161
175
  /**
162
176
  * `POST /fiat/routing/quote` refusals. A `FiatNoRouteError` (any `reason`) or either amount error is
163
- * the named provider's alone: quote the interval's next provider. Anything else stops the fall-through:
164
- * a validation or auth refusal, a 5xx, or no provider left to try.
177
+ * the named provider's alone, so the next provider may still price: with `providers` the backend
178
+ * tries it, with `provider` the client does. Anything else stops the fall-through: a validation or
179
+ * auth refusal, a 5xx, or no provider left to try.
165
180
  */
166
181
  export type FiatRoutingQuoteErrorBody = RoutingNoRouteErrorBody | RoutingAmountErrorBody | RoutingFaultErrorBody;
167
182
  export {};
package/dist/routing.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ROUTING_ENDPOINTS
3
- } from "./chunk-5UEPWL7B.mjs";
3
+ } from "./chunk-WEXD7UEE.mjs";
4
4
  export {
5
5
  ROUTING_ENDPOINTS
6
6
  };
package/dist/schemas.d.ts CHANGED
@@ -30,7 +30,7 @@ import { z } from 'zod';
30
30
  import type { UsStateCode } from './codes';
31
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, KycFieldId, ClientExecutedDelivery, KycSdkResultReport, SurfaceKind, SurfaceProvider, TermsAcceptance, Transition, TransitionInputs, TransitionParams, Tx, FiatGeo, FiatNextRequest } from './types';
32
32
  import type { FiatTermsErrorBody, FiatTermsRequest, FiatTermsResponse, TermsDocument, TermsDocumentAcceptance } from './terms';
33
- import type { FiatRoutingQuoteErrorBody, FiatRoutingQuoteRequest, FiatRoutingTableErrorBody, FiatRoutingTableQuery, FiatRoutingTableResponse } from './routing';
33
+ import type { FiatRoutingQuoteErrorBody, FiatRoutingQuoteRequest, FiatRoutingQuoteTerms, FiatRoutingTableErrorBody, FiatRoutingTableQuery, FiatRoutingTableResponse } from './routing';
34
34
  export declare const JsonSchema: z.ZodType<JsonValue>;
35
35
  export declare const HTTP_VERBS: readonly ["GET", "POST"];
36
36
  /** `"POST /fiat/session/verify"`, `"GET /fiat/orders/o_31c"` — the verb rides the string. */
@@ -114,6 +114,7 @@ export declare const FiatTermsResponseSchema: z.ZodType<FiatTermsResponse>;
114
114
  export declare const FiatTermsErrorBodySchema: z.ZodType<FiatTermsErrorBody>;
115
115
  export declare const FiatRoutingTableQuerySchema: z.ZodType<FiatRoutingTableQuery>;
116
116
  export declare const FiatRoutingTableResponseSchema: z.ZodType<FiatRoutingTableResponse>;
117
+ export declare const FiatRoutingQuoteTermsSchema: z.ZodType<FiatRoutingQuoteTerms>;
117
118
  export declare const FiatRoutingQuoteRequestSchema: z.ZodType<FiatRoutingQuoteRequest>;
118
119
  export declare const FiatRoutingTableErrorBodySchema: z.ZodType<FiatRoutingTableErrorBody>;
119
120
  export declare const FiatRoutingQuoteErrorBodySchema: z.ZodType<FiatRoutingQuoteErrorBody>;
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.24.0";
39
+ var version = "0.25.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-IPOPANXS.mjs";
14
+ } from "./chunk-LHCED3AP.mjs";
15
15
  export {
16
16
  DOCUMENTED_ENDPOINTS,
17
17
  STATE_KEYS,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fun-xyz/fiat-contract",
3
- "version": "0.24.0",
3
+ "version": "0.25.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": {