@flopay/shared 1.3.1 → 1.3.2

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
@@ -178,25 +178,28 @@ throw validationError('Email is required', 'email');
178
178
 
179
179
  ### Postal Code Helpers
180
180
 
181
- Country-aware postcode format validation, backed by the [`validator`](https://www.npmjs.com/package/validator) package's `isPostalCode` (the same library the billing API uses, so client and server rules agree). `@flopay/react`'s AVS block uses these to block a malformed postcode before the card is captured and to show the expected format inline.
181
+ Country-aware postcode format validation, a **faithful mirror of the billing API's own validator** — `is-valid-postal-code.validator.ts` (TeamFloPay/backend#895), same pinned [`validator`](https://www.npmjs.com/package/validator)`@13.15.35` `isPostalCode`, same country→ISO-2 normalization, same fail-open rules — so the SDK never blocks a postcode the server accepts nor opens its submit gate on one the server's `PATCH …/account` will reject with a 400. `@flopay/react`'s AVS block uses these to block a malformed postcode before the card is captured and to show the expected format inline.
182
182
 
183
183
  | Export | Description |
184
184
  |--------|-------------|
185
185
  | `getPostalCodeLabel(countryCode)` | Country-appropriate field label (`'ZIP Code'`, `'Postcode'`, `'Eircode'`, …); defaults to `'Postal Code'` |
186
- | `isPostalCodeSupported(country)` | `true` when `validator` has a postcode pattern for the (ISO 3166-1 alpha-2, case-insensitive; `UK`→`GB`) country. Unsupported / no-postcode countries return `false` |
187
- | `isValidPostalCode(country, postalCode)` | `true` when the (trimmed) postcode matches the country's format. **Fails open** unsupported / no-postcode countries always return `true`, so callers never block them. A supported country with an empty value returns `false`; check emptiness first to distinguish "required" from "malformed" |
188
- | `getPostalCodeExample(country)` | A curated example postcode for the field hint (US `12345 or 12345-6789`, GB `SW1A 1AA`, CA `A1A 1A1`, …), or `undefined` when there is no curated example |
186
+ | `isPostalCodeSupported(country)` | `true` when `validator` has a postcode pattern for the country. Normalization matches the backend: a **2-letter code is passed straight through** (so `'UK'`, not a `validator` locale, → `false`); non-2-letter names resolve via the backend's `COUNTRY_ALIASES` (`'United Kingdom'` → `GB`). Unresolvable / no-postcode countries return `false` |
187
+ | `isValidPostalCode(country, postalCode)` | `true` when the (trimmed) postcode matches the country's format. **Fails open** in exactly the backend's three cases: blank/whitespace postcode, unresolvable country, or an unsupported `validator` locale. Callers distinguish "required" (empty) from "malformed" by checking emptiness + `isPostalCodeSupported` themselves — an empty value fails open here, as it does server-side |
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
191
  ```ts
192
192
  import { isPostalCodeSupported, isValidPostalCode, getPostalCodeExample } from '@flopay/shared';
193
193
 
194
- isPostalCodeSupported('US'); // true
195
- isPostalCodeSupported('AE'); // false — UAE has no postcodes
196
- isValidPostalCode('GB', 'SW1A 1AA'); // true
197
- isValidPostalCode('GB', '12345'); // false — US shape in GB
198
- isValidPostalCode('AE', ''); // true — fail open, never blocks
199
- getPostalCodeExample('CA'); // 'A1A 1A1'
194
+ isPostalCodeSupported('US'); // true
195
+ isPostalCodeSupported('AE'); // false — UAE has no postcodes
196
+ isPostalCodeSupported('United Kingdom'); // true — full name → GB
197
+ isPostalCodeSupported('UK'); // false — 2-letter passthrough (not a validator locale)
198
+ isValidPostalCode('GB', 'SW1A 1AA'); // true
199
+ isValidPostalCode('GB', '12345'); // false — US shape in GB
200
+ isValidPostalCode('AE', ''); // true — fail open, never blocks
201
+ isValidPostalCode('US', ''); // true — blank fails open (enforce "required" separately)
202
+ getPostalCodeExample('CA'); // 'A1A 1A1'
200
203
  ```
201
204
 
202
205
  > **Runtime dependency.** Unlike the rest of `@flopay/shared`, these helpers pull in `validator` (imported via the `validator/lib/isPostalCode.js` submodule so bundlers only include the one check). It installs transitively when you depend on `@flopay/shared`.
package/dist/index.cjs CHANGED
@@ -196,7 +196,7 @@ var PAYMENT_METHOD_LOGOS = {
196
196
  };
197
197
 
198
198
  // src/constants.ts
199
- var SDK_VERSION = "1.3.1";
199
+ var SDK_VERSION = "1.3.2";
200
200
  var FLO_SDK_VERSION_HEADER = "x-flo-sdk-version";
201
201
  var BILLING_API_URL_STAGING = "https://api.stage.flopay.com";
202
202
  var BILLING_API_URL_PRODUCTION = "https://api.flopay.com";
@@ -1985,53 +1985,93 @@ if (typeof isPostalCode !== "function") {
1985
1985
  var SUPPORTED_LOCALES = new Set(
1986
1986
  mod.locales.map((code) => code.toUpperCase())
1987
1987
  );
1988
- var LOCALE_ALIASES = {
1989
- UK: "GB"
1988
+ var COUNTRY_ALIASES = {
1989
+ AUSTRALIA: "AU",
1990
+ BRAZIL: "BR",
1991
+ CANADA: "CA",
1992
+ CH: "CH",
1993
+ DENMARK: "DK",
1994
+ DE: "DE",
1995
+ DEUTSCHLAND: "DE",
1996
+ FRANCE: "FR",
1997
+ GB: "GB",
1998
+ GERMANY: "DE",
1999
+ GREATBRITAIN: "GB",
2000
+ GREAT_BRITAIN: "GB",
2001
+ INDIA: "IN",
2002
+ IRELAND: "IE",
2003
+ ITALY: "IT",
2004
+ JAPAN: "JP",
2005
+ MEXICO: "MX",
2006
+ NETHERLANDS: "NL",
2007
+ NEWZEALAND: "NZ",
2008
+ NORWAY: "NO",
2009
+ POLAND: "PL",
2010
+ PORTUGAL: "PT",
2011
+ SINGAPORE: "SG",
2012
+ SOUTHAFRICA: "ZA",
2013
+ SPAIN: "ES",
2014
+ SWEDEN: "SE",
2015
+ SWITZERLAND: "CH",
2016
+ UK: "GB",
2017
+ UNITEDKINGDOM: "GB",
2018
+ UNITEDSTATES: "US",
2019
+ US: "US",
2020
+ USA: "US",
2021
+ "UNITED STATES": "US",
2022
+ "UNITED KINGDOM": "GB",
2023
+ "GREAT BRITAIN": "GB",
2024
+ ENGLAND: "GB"
1990
2025
  };
1991
- function normalizeCountry(country) {
1992
- const upper = country.trim().toUpperCase();
1993
- return LOCALE_ALIASES[upper] ?? upper;
2026
+ function normalizeCountryToIso2(country) {
2027
+ const upper = (country ?? "").trim().toUpperCase();
2028
+ if (!upper) return null;
2029
+ if (upper.length === 2) return upper;
2030
+ return COUNTRY_ALIASES[upper] ?? null;
1994
2031
  }
1995
2032
  var POSTAL_CODE_EXAMPLES = {
1996
- US: "12345 or 12345-6789",
1997
- GB: "SW1A 1AA",
1998
- CA: "A1A 1A1",
1999
2033
  AU: "2000",
2000
- NZ: "6011",
2001
- IE: "D02 AF30",
2034
+ BR: "01000-000",
2035
+ CA: "A1A 1A1",
2036
+ CH: "8001",
2002
2037
  DE: "10115",
2003
- FR: "75008",
2004
- NL: "1011 AB",
2038
+ DK: "1050",
2005
2039
  ES: "28001",
2006
- IT: "00100",
2040
+ FR: "75008",
2041
+ GB: "SW1A 1AA",
2042
+ IE: "D02 X285",
2007
2043
  IN: "110001",
2044
+ IT: "00118",
2008
2045
  JP: "100-0001",
2009
- BR: "01310-100",
2010
- MX: "01000",
2011
- SE: "114 55",
2012
- CH: "8001",
2046
+ MX: "06500",
2047
+ NL: "1012 JS",
2048
+ NO: "0150",
2049
+ NZ: "6011",
2013
2050
  PL: "00-001",
2014
- PT: "1000-001",
2015
- SG: "570150",
2016
- ZA: "0001",
2017
- NO: "0001",
2018
- DK: "1050",
2019
- FI: "00100",
2020
- AT: "1010",
2021
- BE: "1000",
2022
- CZ: "100 00"
2051
+ PT: "1100-148",
2052
+ SE: "111 22",
2053
+ SG: "018989",
2054
+ US: "12345 or 12345-6789",
2055
+ ZA: "8001"
2023
2056
  };
2024
2057
  function isPostalCodeSupported(country) {
2025
- if (!country) return false;
2026
- return SUPPORTED_LOCALES.has(normalizeCountry(country));
2058
+ const iso2 = normalizeCountryToIso2(country);
2059
+ return iso2 !== null && SUPPORTED_LOCALES.has(iso2);
2027
2060
  }
2028
2061
  function isValidPostalCode(country, postalCode) {
2029
- if (!isPostalCodeSupported(country)) return true;
2030
- return isPostalCode(postalCode.trim(), normalizeCountry(country));
2062
+ const trimmed = (postalCode ?? "").trim();
2063
+ if (!trimmed) return true;
2064
+ const iso2 = normalizeCountryToIso2(country);
2065
+ if (iso2 === null || !SUPPORTED_LOCALES.has(iso2)) return true;
2066
+ try {
2067
+ return isPostalCode(trimmed, iso2);
2068
+ } catch {
2069
+ return true;
2070
+ }
2031
2071
  }
2032
2072
  function getPostalCodeExample(country) {
2033
- if (!country) return void 0;
2034
- return POSTAL_CODE_EXAMPLES[normalizeCountry(country)];
2073
+ const iso2 = normalizeCountryToIso2(country);
2074
+ return iso2 ? POSTAL_CODE_EXAMPLES[iso2] : void 0;
2035
2075
  }
2036
2076
 
2037
2077
  // src/checkout-payload.ts