@flopay/shared 1.3.2 → 1.3.3
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 +12 -0
- package/dist/index.cjs +54 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +79 -2
- package/dist/index.d.ts +79 -2
- package/dist/index.mjs +49 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -188,6 +188,18 @@ Country-aware postcode format validation, a **faithful mirror of the billing API
|
|
|
188
188
|
| `getPostalCodeExample(country)` | The example postcode the backend embeds in its 400 message (US `12345 or 12345-6789`, GB `SW1A 1AA`, CA `A1A 1A1`, …), or `undefined` when there is none. Kept verbatim in sync with the backend's `POSTAL_CODE_EXAMPLES` so the SDK's inline hint and the server's rejection message never contradict |
|
|
189
189
|
| `getStateFromPostalCode(country, postalCode)` | Derives a US state / CA province code from a postcode for AVS enrichment; `null` for other countries or a malformed code |
|
|
190
190
|
|
|
191
|
+
### Idempotency Helpers
|
|
192
|
+
|
|
193
|
+
Primitives for the stable checkout-create `Idempotency-Key` (TeamFloPay/backend#972). `@flopay/js` and `@flopay/react` use these automatically; import them only if you build your own create flow.
|
|
194
|
+
|
|
195
|
+
| Export | Description |
|
|
196
|
+
|--------|-------------|
|
|
197
|
+
| `IDEMPOTENCY_KEY_HEADER` | The header name (`'Idempotency-Key'`) the SDK sends on `POST /v1/checkouts/sessions`. Optional on the backend — absent means the legacy, non-idempotent path. |
|
|
198
|
+
| `MAX_IDEMPOTENCY_KEY_LENGTH` | `255` — the documented max length a supplied key may have. |
|
|
199
|
+
| `IDEMPOTENCY_IN_PROGRESS_CODE` | Backend `code` (`'IdempotencyKeyInProgress'`) marking a **retryable** in-progress replay: retry with the *same* key. Distinct from a payload-conflict (`409`), which is non-retryable. |
|
|
200
|
+
| `generateIdempotencyKey()` | Returns a cryptographically random, high-entropy key (`crypto.randomUUID()`, else 16 random bytes). Returns `undefined` when no secure RNG exists, so callers omit the header rather than emit a weak key. Never derived from request data. |
|
|
201
|
+
| `resolveIdempotencyKey(supplied?)` | Returns a supplied key unchanged after validating it is non-empty and ≤ `MAX_IDEMPOTENCY_KEY_LENGTH` (throws `FloPayError('validation_error')` otherwise, never echoing the value), or a freshly generated key when none is supplied. |
|
|
202
|
+
|
|
191
203
|
```ts
|
|
192
204
|
import { isPostalCodeSupported, isValidPostalCode, getPostalCodeExample } from '@flopay/shared';
|
|
193
205
|
|
package/dist/index.cjs
CHANGED
|
@@ -58,6 +58,9 @@ __export(index_exports, {
|
|
|
58
58
|
FloPayError: () => FloPayError,
|
|
59
59
|
GLASS_DARK_APPEARANCE: () => GLASS_DARK_APPEARANCE,
|
|
60
60
|
GLASS_LIGHT_APPEARANCE: () => GLASS_LIGHT_APPEARANCE,
|
|
61
|
+
IDEMPOTENCY_IN_PROGRESS_CODE: () => IDEMPOTENCY_IN_PROGRESS_CODE,
|
|
62
|
+
IDEMPOTENCY_KEY_HEADER: () => IDEMPOTENCY_KEY_HEADER,
|
|
63
|
+
MAX_IDEMPOTENCY_KEY_LENGTH: () => MAX_IDEMPOTENCY_KEY_LENGTH,
|
|
61
64
|
MODERN_DARK_APPEARANCE: () => MODERN_DARK_APPEARANCE,
|
|
62
65
|
MODERN_LIGHT_APPEARANCE: () => MODERN_LIGHT_APPEARANCE,
|
|
63
66
|
NIGHT_APPEARANCE: () => NIGHT_APPEARANCE,
|
|
@@ -81,6 +84,7 @@ __export(index_exports, {
|
|
|
81
84
|
filterStripeMethodsByCountry: () => filterStripeMethodsByCountry,
|
|
82
85
|
filterStripeMethodsByCurrency: () => filterStripeMethodsByCurrency,
|
|
83
86
|
foldIntoProducts: () => foldIntoProducts,
|
|
87
|
+
generateIdempotencyKey: () => generateIdempotencyKey,
|
|
84
88
|
getConfiguredBillingApiUrl: () => getConfiguredBillingApiUrl,
|
|
85
89
|
getCountryByCode: () => getCountryByCode,
|
|
86
90
|
getCurrencyByCountry: () => getCurrencyByCountry,
|
|
@@ -107,6 +111,7 @@ __export(index_exports, {
|
|
|
107
111
|
resolveAVSConfig: () => resolveAVSConfig,
|
|
108
112
|
resolveBillingApiUrl: () => resolveBillingApiUrl,
|
|
109
113
|
resolveButtonsLayoutTheme: () => resolveButtonsLayoutTheme,
|
|
114
|
+
resolveIdempotencyKey: () => resolveIdempotencyKey,
|
|
110
115
|
resolveSessionCurrency: () => resolveSessionCurrency,
|
|
111
116
|
resolveStripeMethodBrandVariant: () => resolveStripeMethodBrandVariant,
|
|
112
117
|
resolveTheme: () => resolveTheme,
|
|
@@ -196,7 +201,7 @@ var PAYMENT_METHOD_LOGOS = {
|
|
|
196
201
|
};
|
|
197
202
|
|
|
198
203
|
// src/constants.ts
|
|
199
|
-
var SDK_VERSION = "1.3.
|
|
204
|
+
var SDK_VERSION = "1.3.3";
|
|
200
205
|
var FLO_SDK_VERSION_HEADER = "x-flo-sdk-version";
|
|
201
206
|
var BILLING_API_URL_STAGING = "https://api.stage.flopay.com";
|
|
202
207
|
var BILLING_API_URL_PRODUCTION = "https://api.flopay.com";
|
|
@@ -2274,6 +2279,49 @@ function isValidSecretKey(key) {
|
|
|
2274
2279
|
function isSetupIntentClientSecret(clientSecret) {
|
|
2275
2280
|
return typeof clientSecret === "string" && clientSecret.startsWith("seti_");
|
|
2276
2281
|
}
|
|
2282
|
+
|
|
2283
|
+
// src/idempotency.ts
|
|
2284
|
+
var IDEMPOTENCY_KEY_HEADER = "Idempotency-Key";
|
|
2285
|
+
var MAX_IDEMPOTENCY_KEY_LENGTH = 255;
|
|
2286
|
+
var IDEMPOTENCY_IN_PROGRESS_CODE = "IdempotencyKeyInProgress";
|
|
2287
|
+
function getSecureRandomSource() {
|
|
2288
|
+
const source = globalThis.crypto;
|
|
2289
|
+
if (!source) return void 0;
|
|
2290
|
+
if (typeof source.randomUUID === "function" || typeof source.getRandomValues === "function") {
|
|
2291
|
+
return source;
|
|
2292
|
+
}
|
|
2293
|
+
return void 0;
|
|
2294
|
+
}
|
|
2295
|
+
function generateIdempotencyKey() {
|
|
2296
|
+
const source = getSecureRandomSource();
|
|
2297
|
+
if (!source) return void 0;
|
|
2298
|
+
if (typeof source.randomUUID === "function") {
|
|
2299
|
+
return source.randomUUID();
|
|
2300
|
+
}
|
|
2301
|
+
const bytes = new Uint8Array(16);
|
|
2302
|
+
source.getRandomValues(bytes);
|
|
2303
|
+
return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
2304
|
+
}
|
|
2305
|
+
function resolveIdempotencyKey(supplied) {
|
|
2306
|
+
if (supplied === void 0) {
|
|
2307
|
+
return generateIdempotencyKey();
|
|
2308
|
+
}
|
|
2309
|
+
if (typeof supplied !== "string" || supplied.trim() === "") {
|
|
2310
|
+
throw new FloPayError(
|
|
2311
|
+
"idempotencyKey must be a non-empty string identifying exactly one checkout creation.",
|
|
2312
|
+
"validation_error",
|
|
2313
|
+
{ code: "InvalidIdempotencyKey", param: "idempotencyKey" }
|
|
2314
|
+
);
|
|
2315
|
+
}
|
|
2316
|
+
if (supplied.length > MAX_IDEMPOTENCY_KEY_LENGTH) {
|
|
2317
|
+
throw new FloPayError(
|
|
2318
|
+
`idempotencyKey must be at most ${MAX_IDEMPOTENCY_KEY_LENGTH} characters.`,
|
|
2319
|
+
"validation_error",
|
|
2320
|
+
{ code: "InvalidIdempotencyKey", param: "idempotencyKey" }
|
|
2321
|
+
);
|
|
2322
|
+
}
|
|
2323
|
+
return supplied;
|
|
2324
|
+
}
|
|
2277
2325
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2278
2326
|
0 && (module.exports = {
|
|
2279
2327
|
BILLING_API_URL,
|
|
@@ -2304,6 +2352,9 @@ function isSetupIntentClientSecret(clientSecret) {
|
|
|
2304
2352
|
FloPayError,
|
|
2305
2353
|
GLASS_DARK_APPEARANCE,
|
|
2306
2354
|
GLASS_LIGHT_APPEARANCE,
|
|
2355
|
+
IDEMPOTENCY_IN_PROGRESS_CODE,
|
|
2356
|
+
IDEMPOTENCY_KEY_HEADER,
|
|
2357
|
+
MAX_IDEMPOTENCY_KEY_LENGTH,
|
|
2307
2358
|
MODERN_DARK_APPEARANCE,
|
|
2308
2359
|
MODERN_LIGHT_APPEARANCE,
|
|
2309
2360
|
NIGHT_APPEARANCE,
|
|
@@ -2327,6 +2378,7 @@ function isSetupIntentClientSecret(clientSecret) {
|
|
|
2327
2378
|
filterStripeMethodsByCountry,
|
|
2328
2379
|
filterStripeMethodsByCurrency,
|
|
2329
2380
|
foldIntoProducts,
|
|
2381
|
+
generateIdempotencyKey,
|
|
2330
2382
|
getConfiguredBillingApiUrl,
|
|
2331
2383
|
getCountryByCode,
|
|
2332
2384
|
getCurrencyByCountry,
|
|
@@ -2353,6 +2405,7 @@ function isSetupIntentClientSecret(clientSecret) {
|
|
|
2353
2405
|
resolveAVSConfig,
|
|
2354
2406
|
resolveBillingApiUrl,
|
|
2355
2407
|
resolveButtonsLayoutTheme,
|
|
2408
|
+
resolveIdempotencyKey,
|
|
2356
2409
|
resolveSessionCurrency,
|
|
2357
2410
|
resolveStripeMethodBrandVariant,
|
|
2358
2411
|
resolveTheme,
|