@hanzo/pay 0.1.0 → 0.1.1

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
@@ -68,7 +68,11 @@ charge is a server call you make with it.
68
68
  ignored: `color-scheme` inherits into the cross-origin iframe and the UA paints
69
69
  form controls over whatever the SDK declared. One rule fixes it, and it has to
70
70
  be in the sheet before the card attaches — so `terminal()` puts it there rather
71
- than leaving a stylesheet you can forget to import.
71
+ than leaving a stylesheet you can forget to import. It carries the FOCUS RING
72
+ too, for the mirror-image reason: a ring is drawn outside the field, and
73
+ everything Square will style for you stops at the field's edge. Call `pin()`
74
+ yourself only if you drive `payments.card()` directly instead of taking a
75
+ `Terminal`.
72
76
  - **`attempt()` fits Square's ruler.** An `idempotency_key` over 45 characters is
73
77
  rejected before authorization. A 36-char UUID under a `topup:<org>:` wrapper is
74
78
  49, which failed every card charge for one org and read as "charge failed".
@@ -95,6 +99,18 @@ Run `legible()` over a brand palette before shipping it. A reviewer looking at a
95
99
  dark mock cannot tell 2.6:1 from 4.4:1, and the focus ring is a WCAG 2.4.11
96
100
  requirement rather than a preference.
97
101
 
102
+ **Set `field` and `border` to what your own inputs COMPOSITE to, measured in a
103
+ browser.** The card strip lands in a column of your fields and is read as one of
104
+ them or as a foreign object; there is no third outcome. Ours shipped on `--card`
105
+ and its hairline — real tokens, for a card — so the strip rendered a lighter
106
+ ground behind a fainter edge than every field above it.
107
+
108
+ **`ring` is the one focus indicator, and the box does not move.** `pin()` draws it
109
+ around the container as an outline, so it is the same ring your page already puts
110
+ on its own controls; `style()` therefore paints the FOCUSED hairline the resting
111
+ colour, because Square spends that value twice (the border and a `::before` ring
112
+ one pixel outside it) and any other value is a second ring inside the first.
113
+
98
114
  ## Native setup
99
115
 
100
116
  `@hanzo/pay/native` needs `react-native-square-in-app-payments` and the native
@@ -20,12 +20,12 @@ var REACH = {
20
20
  // src/palette.ts
21
21
  var PALETTE = {
22
22
  dark: {
23
- field: "#0a0a0a",
24
- // --card
25
- border: "#232323",
26
- // --white-10 over --card
27
- borderFocus: "#787878",
28
- // --white-45 over --card — 4.4:1 on #0a0a0a
23
+ field: "#000000",
24
+ // --color-black — the ground the checkout column sits on
25
+ border: "#333333",
26
+ // --ink-20 over that ground (an input's resting edge)
27
+ ring: "#fafafa",
28
+ // --primary — the page's own focus ring, 19.6:1 on #000000
29
29
  text: "#ededed",
30
30
  // --foreground
31
31
  placeholder: "#888888",
@@ -35,11 +35,11 @@ var PALETTE = {
35
35
  },
36
36
  light: {
37
37
  field: "#ffffff",
38
- // --background
39
- border: "#e5e5e5",
40
- // --border (neutral-200)
41
- borderFocus: "#737373",
42
- // --neutral-500 — 4.7:1 on #ffffff
38
+ // --color-black under .light
39
+ border: "#cecece",
40
+ // --ink-20 over white
41
+ ring: "#0a0a0a",
42
+ // --primary under .light
43
43
  text: "#0a0a0a",
44
44
  // --foreground
45
45
  placeholder: "#525252",
@@ -66,8 +66,8 @@ function legible(p) {
66
66
  ["text on field", p.text, p.field, 4.5],
67
67
  // A placeholder that is merely present, not legible, is a label nobody reads.
68
68
  ["placeholder on field", p.placeholder, p.field, 4.5],
69
- // Non-text contrast: this border IS the focus indicator (WCAG 2.4.11).
70
- ["borderFocus on field", p.borderFocus, p.field, 3],
69
+ // Non-text contrast: this IS the focus indicator (WCAG 2.4.11).
70
+ ["ring on field", p.ring, p.field, 3],
71
71
  // The error hue carries both text and a border, so it is held to the lower
72
72
  // non-text floor — it is never the only signal, the border moves too.
73
73
  ["error on field", p.error, p.field, 3]
@@ -83,5 +83,5 @@ exports.cancelled = cancelled;
83
83
  exports.legible = legible;
84
84
  exports.luminance = luminance;
85
85
  exports.ratio = ratio;
86
- //# sourceMappingURL=chunk-64AUOMEL.cjs.map
87
- //# sourceMappingURL=chunk-64AUOMEL.cjs.map
86
+ //# sourceMappingURL=chunk-AJAETCMO.cjs.map
87
+ //# sourceMappingURL=chunk-AJAETCMO.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/terminal.ts","../src/palette.ts"],"names":[],"mappings":";;;AAuJO,IAAM,SAAA,GAAN,cAAwB,KAAA,CAAM;AAAA,EAC1B,MAAA;AAAA,EACT,YAAY,MAAA,EAAgB;AAC1B,IAAA,KAAA,CAAM,CAAA,EAAG,MAAM,CAAA,cAAA,CAAgB,CAAA;AAC/B,IAAA,IAAA,CAAK,IAAA,GAAO,WAAA;AACZ,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAAA,EAChB;AACF;AAGO,SAAS,UAAU,CAAA,EAA4B;AACpD,EAAA,OAAO,CAAA,YAAa,SAAA;AACtB;AAuBO,IAAM,KAAA,GAAqD;AAAA,EAChE,KAAK,CAAC,MAAA,EAAQ,aAAa,YAAA,EAAc,UAAA,EAAY,OAAO,MAAM,CAAA;AAAA,EAClE,MAAA,EAAQ,CAAC,MAAA,EAAQ,WAAA,EAAa,cAAc,MAAM;AACpD;;;ACpHO,IAAM,OAAA,GAAkC;AAAA,EAC7C,IAAA,EAAM;AAAA,IACJ,KAAA,EAAO,SAAA;AAAA;AAAA,IACP,MAAA,EAAQ,SAAA;AAAA;AAAA,IACR,IAAA,EAAM,SAAA;AAAA;AAAA,IACN,IAAA,EAAM,SAAA;AAAA;AAAA,IACN,WAAA,EAAa,SAAA;AAAA;AAAA,IACb,KAAA,EAAO;AAAA;AAAA,GACT;AAAA,EACA,KAAA,EAAO;AAAA,IACL,KAAA,EAAO,SAAA;AAAA;AAAA,IACP,MAAA,EAAQ,SAAA;AAAA;AAAA,IACR,IAAA,EAAM,SAAA;AAAA;AAAA,IACN,IAAA,EAAM,SAAA;AAAA;AAAA,IACN,WAAA,EAAa,SAAA;AAAA;AAAA,IACb,KAAA,EAAO;AAAA;AAAA;AAEX;AAGO,IAAM,GAAA,GAAM;AAGZ,SAAS,UAAU,GAAA,EAAqB;AAC7C,EAAA,MAAM,CAAA,GAAI,CAAC,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM;AAC7B,IAAA,MAAM,CAAA,GAAI,SAAS,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA,GAAI,CAAC,CAAA,EAAG,EAAE,CAAA,GAAI,GAAA;AAC9C,IAAA,OAAO,KAAK,OAAA,GAAU,CAAA,GAAI,KAAA,GAAA,CAAA,CAAU,CAAA,GAAI,SAAS,KAAA,KAAU,GAAA;AAAA,EAC7D,CAAC,CAAA;AACD,EAAA,OAAO,MAAA,GAAS,CAAA,CAAE,CAAC,CAAA,GAAI,MAAA,GAAS,EAAE,CAAC,CAAA,GAAI,MAAA,GAAS,CAAA,CAAE,CAAC,CAAA;AACrD;AAGO,SAAS,KAAA,CAAM,GAAW,CAAA,EAAmB;AAClD,EAAA,MAAM,CAAC,CAAA,EAAG,CAAC,CAAA,GAAI,CAAC,UAAU,CAAC,CAAA,EAAG,SAAA,CAAU,CAAC,CAAC,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,IAAI,CAAC,CAAA;AAChE,EAAA,OAAA,CAAQ,CAAA,GAAI,SAAS,CAAA,GAAI,IAAA,CAAA;AAC3B;AAkBO,SAAS,QAAQ,CAAA,EAAqB;AAC3C,EAAA,MAAM,KAAA,GAAiD;AAAA;AAAA,IAErD,CAAC,eAAA,EAAiB,CAAA,CAAE,IAAA,EAAM,CAAA,CAAE,OAAO,GAAG,CAAA;AAAA;AAAA,IAEtC,CAAC,sBAAA,EAAwB,CAAA,CAAE,WAAA,EAAa,CAAA,CAAE,OAAO,GAAG,CAAA;AAAA;AAAA,IAEpD,CAAC,eAAA,EAAiB,CAAA,CAAE,IAAA,EAAM,CAAA,CAAE,OAAO,CAAC,CAAA;AAAA;AAAA;AAAA,IAGpC,CAAC,gBAAA,EAAkB,CAAA,CAAE,KAAA,EAAO,CAAA,CAAE,OAAO,CAAC;AAAA,GACxC;AACA,EAAA,OAAO,KAAA,CACJ,GAAA,CAAI,CAAC,CAAC,IAAA,EAAM,GAAG,CAAA,EAAG,KAAK,CAAA,MAAO,EAAE,IAAA,EAAM,KAAA,EAAO,MAAM,CAAA,EAAG,CAAC,CAAA,EAAG,KAAA,EAAM,CAAE,CAAA,CAClE,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,KAAA,GAAQ,CAAA,CAAE,KAAK,CAAA;AACpC","file":"chunk-AJAETCMO.cjs","sourcesContent":["// What a checkout asks for, what it gets back, and the one thing that turns the\n// first into the second. Platform-agnostic: no DOM, no react-native, no Square.\n//\n// THIS PACKAGE NEVER MOVES MONEY. Every rail below ends at a single-use token,\n// and the charge is a server call the host makes with that token. Nothing here\n// completes a payment, which is why the noun is `Tender` — an OFFER of payment,\n// the term Square's own Orders API uses — and not `Charge`, which would name\n// something this code cannot do.\n\n/**\n * A Square rail.\n *\n * `gift` is a Square gift card, which tokenizes like a card but through its own\n * constructor on both platforms. Non-Square rails a host may also offer (wire,\n * crypto, another processor) are deliberately absent: this package knows Square,\n * and a host that knows more merges its own set with what `offers()` returns.\n */\nexport type Method = 'card' | 'apple_pay' | 'google_pay' | 'cash_app' | 'ach' | 'gift'\n\n/**\n * Money as a DECIMAL STRING, never a number.\n *\n * `0.1 + 0.2` is `0.30000000000000004`, and a float that reaches a payment\n * processor as a total is a rounding error someone is charged. Square's own\n * paymentRequest takes `amount` as a string for this reason; so does this.\n */\nexport interface Money {\n /** Decimal string in major units, e.g. `\"12.00\"`. Never a float. */\n amount: string\n /** ISO 4217, e.g. `\"USD\"`. */\n currency: string\n}\n\n/** An offer of payment: what is being paid, where, and what the buyer is shown. */\nexport interface Tender {\n total: Money\n /** ISO 3166-1 alpha-2 of the MERCHANT, e.g. `\"US\"`. Square keys wallets off it. */\n country: string\n /** The line the wallet sheet shows the buyer, e.g. `\"Hanzo AI credit\"`. */\n label: string\n}\n\n/**\n * A single-use payment token, and the only thing any rail here produces.\n *\n * It is single-use in the strict sense: spending it — charging it OR vaulting it\n * — consumes it. A flow that needs both a charge and a card-on-file must\n * tokenize TWICE; sharing one token between the two fails with the card already\n * accepted, which reads as a decline.\n */\nexport interface Token {\n value: string\n method: Method\n /** Present when the rail reported it. Absent means never reported, not empty. */\n card?: { brand?: string; last4?: string; expMonth?: number; expYear?: number }\n}\n\n/**\n * Rail-specific facts a `Tender` cannot carry, because only one rail needs each.\n * Every field is ignored by the rails it does not belong to.\n */\nexport interface Detail {\n /**\n * ACH only (web), and REQUIRED there: Square matches it against the bank\n * record. Collected from the buyer rather than derived from the account,\n * because the account holder and the person paying are not always the same\n * name.\n */\n name?: string\n /**\n * Card and gift only. Passed straight to Square as verification details —\n * `{ intent, amount, currencyCode, billingContact, customerInitiated,\n * sellerKeyedIn }` — which is how SCA is satisfied in mandated regions.\n * Opaque on purpose: Square owns this shape, and re-declaring it here would\n * be a second copy to drift.\n */\n verify?: Record<string, unknown>\n /**\n * NATIVE ONLY, and the one real asymmetry between the platforms.\n *\n * Square's native card sheet is a state machine, not a form: it STAYS OPEN\n * after minting the token, showing a spinner, until it is told whether the\n * charge worked. Told yes, it closes. Told no, it shows the message ON the\n * sheet with the card still entered, so the buyer retries in place instead of\n * being dropped back to a checkout with an empty form and a decline notice.\n *\n * That is a better decline experience than the web can offer, and it exists\n * only if the host charges DURING the sheet — which is what this is. Given the\n * token, run the server call; return to close the sheet, throw to keep it open\n * with the thrown message shown.\n *\n * Omit it and the sheet closes as soon as the token exists, which is what the\n * web does. Nothing hangs either way.\n *\n * The web backend ignores this: its card fields are a page element with no\n * sheet to hold open.\n */\n charge?(token: Token): Promise<void>\n}\n\n/**\n * The one interface both backends satisfy: web (Square Web Payments SDK) and\n * native (Square In-App Payments SDK). A host writes against this and the\n * platform picks the implementation — see `./web` and `./native`.\n */\nexport interface Terminal {\n /**\n * Which methods can REALLY complete a payment here, right now.\n *\n * Asked of the SDK, never inferred from a user-agent string: the answer depends\n * on the browser or device, on the buyer's saved cards, AND on whether the\n * merchant account has the rail switched on. A picker listing a wallet the\n * platform cannot use is a dead end with a logo on it.\n *\n * Takes the tender because the answer depends on it — Square binds the total\n * into the wallet it builds, so this is asked at the point of payment with the\n * real amount rather than cached at boot.\n */\n offers(tender: Tender): Promise<Method[]>\n\n /**\n * Draw the rails that render INLINE into the page, and nothing else.\n *\n * Absent on native, and that absence is the honest signal: native card entry\n * is a modal the OS presents, so there is no element to place and nothing for\n * a caller to position. A host writes `terminal.mount?.(…)` and the native\n * build correctly does nothing.\n */\n mount?(method: Method, target: string): Promise<void>\n\n /**\n * Tokenize. Resolves with a token, or rejects.\n *\n * A buyer who dismisses the sheet has not failed — `collect` rejects with a\n * `Cancelled` (see below), which a caller distinguishes from a real failure so\n * it does not show an error for a decision.\n */\n collect(method: Method, tender: Tender, detail?: Detail): Promise<Token>\n\n /** Tear down every element and listener this terminal owns. */\n release(): Promise<void>\n}\n\n/**\n * The buyer dismissed the sheet. NOT an error to show anyone.\n *\n * Every rail signals this differently — Square's web tokenize resolves with\n * `status: 'CANCEL'`, Apple Pay on native calls a cancel callback, Google Pay\n * rejects with its own code — and a caller that cannot tell them apart shows\n * \"payment failed\" to someone who simply changed their mind.\n */\nexport class Cancelled extends Error {\n readonly method: Method\n constructor(method: Method) {\n super(`${method} was cancelled`)\n this.name = 'Cancelled'\n this.method = method\n }\n}\n\n/** True for the one rejection that means \"the buyer said no\", on any platform. */\nexport function cancelled(e: unknown): e is Cancelled {\n return e instanceof Cancelled\n}\n\n/**\n * The rails each platform's Square SDK can even ATTEMPT.\n *\n * This is a fact about the SDKs, not about a merchant account, and the two do not\n * agree: Square's In-App Payments SDK ships no Cash App Pay and no ACH — its\n * whole exported surface is card entry, gift card entry, Apple Pay, Google Pay\n * and buyer verification. Offering either on a phone would be a button that\n * cannot resolve.\n *\n * `offers()` intersects this with what the SDK says it can build, so a rail\n * missing here is absent from the picker rather than present and dead.\n *\n * THIS IS REACH, NOT POLICY, and the difference has already been mistaken once.\n * A host may decline a rail this table lists, for reasons that have nothing to\n * do with tokenizing: hanzoai/pay does not offer ACH on Square, because its\n * top-up endpoint credits the balance as soon as the charge call succeeds while\n * an ACH debit settles days later — so it would credit unsettled money. The SDK\n * reaches ACH perfectly well. Deciding not to use it is the host's call and does\n * not belong here; deleting `ach` below would instead tell every other host that\n * the rail does not exist.\n */\nexport const REACH: Record<'web' | 'native', readonly Method[]> = {\n web: ['card', 'apple_pay', 'google_pay', 'cash_app', 'ach', 'gift'],\n native: ['card', 'apple_pay', 'google_pay', 'gift'],\n}\n","// The card field's colours — the ONE place this package writes a colour down.\n//\n// Everything else on a checkout is styled from the host's own tokens, so a theme\n// change is a class on <html> and no JS is involved. The card fields cannot work\n// that way, and the reason is the same on both platforms for different causes:\n//\n// web Square renders the fields in a CROSS-ORIGIN iframe, which cannot read\n// our custom properties. The only channel is the style object handed to\n// `payments.card({ style })`, and it takes literal values.\n// native Square renders the fields in a NATIVE view. There is no CSS at all;\n// the only channel is `SQIPCardEntry.setIOSCardEntryTheme`, which takes\n// {r,g,b,a} components.\n//\n// So the literals are unavoidable on both. What is avoidable is having them\n// scattered, or drifting from the palette they mirror, or disagreeing between web\n// and native — hence ONE table here, rendered per platform by each backend\n// (`style()` in ./web, `theme()` in ./native). A brand supplies its own table and\n// gets both renderings for free.\n//\n// Every value is an OPAQUE hex. Square validates style values against its own\n// allowlist and rejects what it cannot parse, and an alpha channel over a surface\n// we do not control is a guess about what is behind it anyway. Alpha rungs of a\n// design ladder (white/10, white/40) are therefore composited onto the field's\n// own ground here, which is what the eye sees regardless.\n\n/** The two grounds a checkout can sit on. Dark is the default. */\nexport type Theme = 'dark' | 'light'\n\n// A PALETTE IS ONE SURFACE, and `field` + `text` are the pair that makes it\n// readable. They have forked twice in production, in both directions: once as a\n// white ground under near-white ink (`field: 'transparent'`, so Square's own\n// white showed through), and once as near-black ink placed on this ground on the\n// belief that the ground was still white. Both shipped a card number the customer\n// could not see while typing it. Neither is a judgement call — `legible()` below\n// measures the pair, and the first of those two states measures 1.0 against a 4.5\n// floor. Change a ground and its ink in one edit, and let the check say whether\n// the result can be read.\nexport interface Palette {\n /** The field's own ground. */\n field: string\n /**\n * The hairline — at rest AND on focus. The box deliberately does not move when\n * the buyer arrives in it: `ring` is the one thing that says so, and a border\n * that changed colour underneath it would be a second indicator for the same\n * event. See `ring`.\n */\n border: string\n /**\n * THE focus indicator, drawn AROUND the field rather than on it (`pin()`), so\n * it is the same ring the host draws on its own inputs — one look for every\n * control on the page. Deliberately >= 3:1 on `field` (WCAG 2.4.11).\n */\n ring: string\n /** Typed characters. */\n text: string\n /** Placeholder text. */\n placeholder: string\n /** Validation text, icon and border. One error hue. */\n error: string\n}\n\n// Both columns are @hanzo/design's own values, not new ones. The dark column is\n// the palette `:root` publishes; the light column is what `.light` inverts it to.\n// Composited alphas are noted where the token is a rung rather than a hex.\n//\n// EVERY VALUE HERE IS WHAT A CHECKOUT'S OWN INPUT COMPOSITES TO, measured in a\n// browser rather than reasoned about — because that is the only claim this table\n// can make that matters. `field`/`border` were `--card`/`--white-10-over-card`,\n// which are real tokens for a CARD; an input is not a card, and the strip\n// therefore rendered a lighter ground (#0a0a0a) behind a fainter hairline\n// (#232323) than the fields stacked above it (#000000 / #333333). One row was\n// visibly a different control from its neighbours, which is exactly what a buyer\n// reads as \"this part isn't part of the form\".\nexport const PALETTE: Record<Theme, Palette> = {\n dark: {\n field: '#000000', // --color-black — the ground the checkout column sits on\n border: '#333333', // --ink-20 over that ground (an input's resting edge)\n ring: '#fafafa', // --primary — the page's own focus ring, 19.6:1 on #000000\n text: '#ededed', // --foreground\n placeholder: '#888888', // --muted-foreground\n error: '#fca5a5', // --state-error-text (red-300), legible on black\n },\n light: {\n field: '#ffffff', // --color-black under .light\n border: '#cecece', // --ink-20 over white\n ring: '#0a0a0a', // --primary under .light\n text: '#0a0a0a', // --foreground\n placeholder: '#525252', // --muted-foreground\n error: '#ef4444', // --state-error (red-500), legible on white\n },\n}\n\n/** `#rrggbb`, lowercase. The only form Square accepts on both platforms. */\nexport const HEX = /^#[0-9a-f]{6}$/\n\n/** Relative luminance, WCAG 2.x. */\nexport function luminance(hex: string): number {\n const c = [1, 3, 5].map((i) => {\n const v = parseInt(hex.slice(i, i + 2), 16) / 255\n return v <= 0.03928 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4\n })\n return 0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2]\n}\n\n/** Contrast ratio between two opaque hexes, 1..21. Order does not matter. */\nexport function ratio(a: string, b: string): number {\n const [x, y] = [luminance(a), luminance(b)].sort((m, n) => n - m)\n return (x + 0.05) / (y + 0.05)\n}\n\n/** One failed contrast pair: what was measured, against what floor. */\nexport interface Fault {\n pair: string\n ratio: number\n floor: number\n}\n\n/**\n * Every contrast pair in a palette that a customer must be able to read, with\n * the WCAG floor each is held to.\n *\n * This is exported rather than kept in a test because a BRAND supplying its own\n * table needs the same check, and the failure it catches is invisible in review:\n * a reviewer looking at a dark mock cannot tell 2.6:1 from 4.4:1, and the focus\n * ring is a WCAG 2.4.11 requirement rather than a preference.\n */\nexport function legible(p: Palette): Fault[] {\n const pairs: Array<[string, string, string, number]> = [\n // The typed card number, at AA for body text.\n ['text on field', p.text, p.field, 4.5],\n // A placeholder that is merely present, not legible, is a label nobody reads.\n ['placeholder on field', p.placeholder, p.field, 4.5],\n // Non-text contrast: this IS the focus indicator (WCAG 2.4.11).\n ['ring on field', p.ring, p.field, 3],\n // The error hue carries both text and a border, so it is held to the lower\n // non-text floor — it is never the only signal, the border moves too.\n ['error on field', p.error, p.field, 3],\n ]\n return pairs\n .map(([pair, a, b, floor]) => ({ pair, ratio: ratio(a, b), floor }))\n .filter((f) => f.ratio < f.floor)\n}\n"]}
@@ -18,12 +18,12 @@ var REACH = {
18
18
  // src/palette.ts
19
19
  var PALETTE = {
20
20
  dark: {
21
- field: "#0a0a0a",
22
- // --card
23
- border: "#232323",
24
- // --white-10 over --card
25
- borderFocus: "#787878",
26
- // --white-45 over --card — 4.4:1 on #0a0a0a
21
+ field: "#000000",
22
+ // --color-black — the ground the checkout column sits on
23
+ border: "#333333",
24
+ // --ink-20 over that ground (an input's resting edge)
25
+ ring: "#fafafa",
26
+ // --primary — the page's own focus ring, 19.6:1 on #000000
27
27
  text: "#ededed",
28
28
  // --foreground
29
29
  placeholder: "#888888",
@@ -33,11 +33,11 @@ var PALETTE = {
33
33
  },
34
34
  light: {
35
35
  field: "#ffffff",
36
- // --background
37
- border: "#e5e5e5",
38
- // --border (neutral-200)
39
- borderFocus: "#737373",
40
- // --neutral-500 — 4.7:1 on #ffffff
36
+ // --color-black under .light
37
+ border: "#cecece",
38
+ // --ink-20 over white
39
+ ring: "#0a0a0a",
40
+ // --primary under .light
41
41
  text: "#0a0a0a",
42
42
  // --foreground
43
43
  placeholder: "#525252",
@@ -64,8 +64,8 @@ function legible(p) {
64
64
  ["text on field", p.text, p.field, 4.5],
65
65
  // A placeholder that is merely present, not legible, is a label nobody reads.
66
66
  ["placeholder on field", p.placeholder, p.field, 4.5],
67
- // Non-text contrast: this border IS the focus indicator (WCAG 2.4.11).
68
- ["borderFocus on field", p.borderFocus, p.field, 3],
67
+ // Non-text contrast: this IS the focus indicator (WCAG 2.4.11).
68
+ ["ring on field", p.ring, p.field, 3],
69
69
  // The error hue carries both text and a border, so it is held to the lower
70
70
  // non-text floor — it is never the only signal, the border moves too.
71
71
  ["error on field", p.error, p.field, 3]
@@ -74,5 +74,5 @@ function legible(p) {
74
74
  }
75
75
 
76
76
  export { Cancelled, HEX, PALETTE, REACH, cancelled, legible, luminance, ratio };
77
- //# sourceMappingURL=chunk-DXK2QDTX.js.map
78
- //# sourceMappingURL=chunk-DXK2QDTX.js.map
77
+ //# sourceMappingURL=chunk-IYAU5BMM.js.map
78
+ //# sourceMappingURL=chunk-IYAU5BMM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/terminal.ts","../src/palette.ts"],"names":[],"mappings":"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","file":"chunk-IYAU5BMM.js","sourcesContent":["// What a checkout asks for, what it gets back, and the one thing that turns the\n// first into the second. Platform-agnostic: no DOM, no react-native, no Square.\n//\n// THIS PACKAGE NEVER MOVES MONEY. Every rail below ends at a single-use token,\n// and the charge is a server call the host makes with that token. Nothing here\n// completes a payment, which is why the noun is `Tender` — an OFFER of payment,\n// the term Square's own Orders API uses — and not `Charge`, which would name\n// something this code cannot do.\n\n/**\n * A Square rail.\n *\n * `gift` is a Square gift card, which tokenizes like a card but through its own\n * constructor on both platforms. Non-Square rails a host may also offer (wire,\n * crypto, another processor) are deliberately absent: this package knows Square,\n * and a host that knows more merges its own set with what `offers()` returns.\n */\nexport type Method = 'card' | 'apple_pay' | 'google_pay' | 'cash_app' | 'ach' | 'gift'\n\n/**\n * Money as a DECIMAL STRING, never a number.\n *\n * `0.1 + 0.2` is `0.30000000000000004`, and a float that reaches a payment\n * processor as a total is a rounding error someone is charged. Square's own\n * paymentRequest takes `amount` as a string for this reason; so does this.\n */\nexport interface Money {\n /** Decimal string in major units, e.g. `\"12.00\"`. Never a float. */\n amount: string\n /** ISO 4217, e.g. `\"USD\"`. */\n currency: string\n}\n\n/** An offer of payment: what is being paid, where, and what the buyer is shown. */\nexport interface Tender {\n total: Money\n /** ISO 3166-1 alpha-2 of the MERCHANT, e.g. `\"US\"`. Square keys wallets off it. */\n country: string\n /** The line the wallet sheet shows the buyer, e.g. `\"Hanzo AI credit\"`. */\n label: string\n}\n\n/**\n * A single-use payment token, and the only thing any rail here produces.\n *\n * It is single-use in the strict sense: spending it — charging it OR vaulting it\n * — consumes it. A flow that needs both a charge and a card-on-file must\n * tokenize TWICE; sharing one token between the two fails with the card already\n * accepted, which reads as a decline.\n */\nexport interface Token {\n value: string\n method: Method\n /** Present when the rail reported it. Absent means never reported, not empty. */\n card?: { brand?: string; last4?: string; expMonth?: number; expYear?: number }\n}\n\n/**\n * Rail-specific facts a `Tender` cannot carry, because only one rail needs each.\n * Every field is ignored by the rails it does not belong to.\n */\nexport interface Detail {\n /**\n * ACH only (web), and REQUIRED there: Square matches it against the bank\n * record. Collected from the buyer rather than derived from the account,\n * because the account holder and the person paying are not always the same\n * name.\n */\n name?: string\n /**\n * Card and gift only. Passed straight to Square as verification details —\n * `{ intent, amount, currencyCode, billingContact, customerInitiated,\n * sellerKeyedIn }` — which is how SCA is satisfied in mandated regions.\n * Opaque on purpose: Square owns this shape, and re-declaring it here would\n * be a second copy to drift.\n */\n verify?: Record<string, unknown>\n /**\n * NATIVE ONLY, and the one real asymmetry between the platforms.\n *\n * Square's native card sheet is a state machine, not a form: it STAYS OPEN\n * after minting the token, showing a spinner, until it is told whether the\n * charge worked. Told yes, it closes. Told no, it shows the message ON the\n * sheet with the card still entered, so the buyer retries in place instead of\n * being dropped back to a checkout with an empty form and a decline notice.\n *\n * That is a better decline experience than the web can offer, and it exists\n * only if the host charges DURING the sheet — which is what this is. Given the\n * token, run the server call; return to close the sheet, throw to keep it open\n * with the thrown message shown.\n *\n * Omit it and the sheet closes as soon as the token exists, which is what the\n * web does. Nothing hangs either way.\n *\n * The web backend ignores this: its card fields are a page element with no\n * sheet to hold open.\n */\n charge?(token: Token): Promise<void>\n}\n\n/**\n * The one interface both backends satisfy: web (Square Web Payments SDK) and\n * native (Square In-App Payments SDK). A host writes against this and the\n * platform picks the implementation — see `./web` and `./native`.\n */\nexport interface Terminal {\n /**\n * Which methods can REALLY complete a payment here, right now.\n *\n * Asked of the SDK, never inferred from a user-agent string: the answer depends\n * on the browser or device, on the buyer's saved cards, AND on whether the\n * merchant account has the rail switched on. A picker listing a wallet the\n * platform cannot use is a dead end with a logo on it.\n *\n * Takes the tender because the answer depends on it — Square binds the total\n * into the wallet it builds, so this is asked at the point of payment with the\n * real amount rather than cached at boot.\n */\n offers(tender: Tender): Promise<Method[]>\n\n /**\n * Draw the rails that render INLINE into the page, and nothing else.\n *\n * Absent on native, and that absence is the honest signal: native card entry\n * is a modal the OS presents, so there is no element to place and nothing for\n * a caller to position. A host writes `terminal.mount?.(…)` and the native\n * build correctly does nothing.\n */\n mount?(method: Method, target: string): Promise<void>\n\n /**\n * Tokenize. Resolves with a token, or rejects.\n *\n * A buyer who dismisses the sheet has not failed — `collect` rejects with a\n * `Cancelled` (see below), which a caller distinguishes from a real failure so\n * it does not show an error for a decision.\n */\n collect(method: Method, tender: Tender, detail?: Detail): Promise<Token>\n\n /** Tear down every element and listener this terminal owns. */\n release(): Promise<void>\n}\n\n/**\n * The buyer dismissed the sheet. NOT an error to show anyone.\n *\n * Every rail signals this differently — Square's web tokenize resolves with\n * `status: 'CANCEL'`, Apple Pay on native calls a cancel callback, Google Pay\n * rejects with its own code — and a caller that cannot tell them apart shows\n * \"payment failed\" to someone who simply changed their mind.\n */\nexport class Cancelled extends Error {\n readonly method: Method\n constructor(method: Method) {\n super(`${method} was cancelled`)\n this.name = 'Cancelled'\n this.method = method\n }\n}\n\n/** True for the one rejection that means \"the buyer said no\", on any platform. */\nexport function cancelled(e: unknown): e is Cancelled {\n return e instanceof Cancelled\n}\n\n/**\n * The rails each platform's Square SDK can even ATTEMPT.\n *\n * This is a fact about the SDKs, not about a merchant account, and the two do not\n * agree: Square's In-App Payments SDK ships no Cash App Pay and no ACH — its\n * whole exported surface is card entry, gift card entry, Apple Pay, Google Pay\n * and buyer verification. Offering either on a phone would be a button that\n * cannot resolve.\n *\n * `offers()` intersects this with what the SDK says it can build, so a rail\n * missing here is absent from the picker rather than present and dead.\n *\n * THIS IS REACH, NOT POLICY, and the difference has already been mistaken once.\n * A host may decline a rail this table lists, for reasons that have nothing to\n * do with tokenizing: hanzoai/pay does not offer ACH on Square, because its\n * top-up endpoint credits the balance as soon as the charge call succeeds while\n * an ACH debit settles days later — so it would credit unsettled money. The SDK\n * reaches ACH perfectly well. Deciding not to use it is the host's call and does\n * not belong here; deleting `ach` below would instead tell every other host that\n * the rail does not exist.\n */\nexport const REACH: Record<'web' | 'native', readonly Method[]> = {\n web: ['card', 'apple_pay', 'google_pay', 'cash_app', 'ach', 'gift'],\n native: ['card', 'apple_pay', 'google_pay', 'gift'],\n}\n","// The card field's colours — the ONE place this package writes a colour down.\n//\n// Everything else on a checkout is styled from the host's own tokens, so a theme\n// change is a class on <html> and no JS is involved. The card fields cannot work\n// that way, and the reason is the same on both platforms for different causes:\n//\n// web Square renders the fields in a CROSS-ORIGIN iframe, which cannot read\n// our custom properties. The only channel is the style object handed to\n// `payments.card({ style })`, and it takes literal values.\n// native Square renders the fields in a NATIVE view. There is no CSS at all;\n// the only channel is `SQIPCardEntry.setIOSCardEntryTheme`, which takes\n// {r,g,b,a} components.\n//\n// So the literals are unavoidable on both. What is avoidable is having them\n// scattered, or drifting from the palette they mirror, or disagreeing between web\n// and native — hence ONE table here, rendered per platform by each backend\n// (`style()` in ./web, `theme()` in ./native). A brand supplies its own table and\n// gets both renderings for free.\n//\n// Every value is an OPAQUE hex. Square validates style values against its own\n// allowlist and rejects what it cannot parse, and an alpha channel over a surface\n// we do not control is a guess about what is behind it anyway. Alpha rungs of a\n// design ladder (white/10, white/40) are therefore composited onto the field's\n// own ground here, which is what the eye sees regardless.\n\n/** The two grounds a checkout can sit on. Dark is the default. */\nexport type Theme = 'dark' | 'light'\n\n// A PALETTE IS ONE SURFACE, and `field` + `text` are the pair that makes it\n// readable. They have forked twice in production, in both directions: once as a\n// white ground under near-white ink (`field: 'transparent'`, so Square's own\n// white showed through), and once as near-black ink placed on this ground on the\n// belief that the ground was still white. Both shipped a card number the customer\n// could not see while typing it. Neither is a judgement call — `legible()` below\n// measures the pair, and the first of those two states measures 1.0 against a 4.5\n// floor. Change a ground and its ink in one edit, and let the check say whether\n// the result can be read.\nexport interface Palette {\n /** The field's own ground. */\n field: string\n /**\n * The hairline — at rest AND on focus. The box deliberately does not move when\n * the buyer arrives in it: `ring` is the one thing that says so, and a border\n * that changed colour underneath it would be a second indicator for the same\n * event. See `ring`.\n */\n border: string\n /**\n * THE focus indicator, drawn AROUND the field rather than on it (`pin()`), so\n * it is the same ring the host draws on its own inputs — one look for every\n * control on the page. Deliberately >= 3:1 on `field` (WCAG 2.4.11).\n */\n ring: string\n /** Typed characters. */\n text: string\n /** Placeholder text. */\n placeholder: string\n /** Validation text, icon and border. One error hue. */\n error: string\n}\n\n// Both columns are @hanzo/design's own values, not new ones. The dark column is\n// the palette `:root` publishes; the light column is what `.light` inverts it to.\n// Composited alphas are noted where the token is a rung rather than a hex.\n//\n// EVERY VALUE HERE IS WHAT A CHECKOUT'S OWN INPUT COMPOSITES TO, measured in a\n// browser rather than reasoned about — because that is the only claim this table\n// can make that matters. `field`/`border` were `--card`/`--white-10-over-card`,\n// which are real tokens for a CARD; an input is not a card, and the strip\n// therefore rendered a lighter ground (#0a0a0a) behind a fainter hairline\n// (#232323) than the fields stacked above it (#000000 / #333333). One row was\n// visibly a different control from its neighbours, which is exactly what a buyer\n// reads as \"this part isn't part of the form\".\nexport const PALETTE: Record<Theme, Palette> = {\n dark: {\n field: '#000000', // --color-black — the ground the checkout column sits on\n border: '#333333', // --ink-20 over that ground (an input's resting edge)\n ring: '#fafafa', // --primary — the page's own focus ring, 19.6:1 on #000000\n text: '#ededed', // --foreground\n placeholder: '#888888', // --muted-foreground\n error: '#fca5a5', // --state-error-text (red-300), legible on black\n },\n light: {\n field: '#ffffff', // --color-black under .light\n border: '#cecece', // --ink-20 over white\n ring: '#0a0a0a', // --primary under .light\n text: '#0a0a0a', // --foreground\n placeholder: '#525252', // --muted-foreground\n error: '#ef4444', // --state-error (red-500), legible on white\n },\n}\n\n/** `#rrggbb`, lowercase. The only form Square accepts on both platforms. */\nexport const HEX = /^#[0-9a-f]{6}$/\n\n/** Relative luminance, WCAG 2.x. */\nexport function luminance(hex: string): number {\n const c = [1, 3, 5].map((i) => {\n const v = parseInt(hex.slice(i, i + 2), 16) / 255\n return v <= 0.03928 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4\n })\n return 0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2]\n}\n\n/** Contrast ratio between two opaque hexes, 1..21. Order does not matter. */\nexport function ratio(a: string, b: string): number {\n const [x, y] = [luminance(a), luminance(b)].sort((m, n) => n - m)\n return (x + 0.05) / (y + 0.05)\n}\n\n/** One failed contrast pair: what was measured, against what floor. */\nexport interface Fault {\n pair: string\n ratio: number\n floor: number\n}\n\n/**\n * Every contrast pair in a palette that a customer must be able to read, with\n * the WCAG floor each is held to.\n *\n * This is exported rather than kept in a test because a BRAND supplying its own\n * table needs the same check, and the failure it catches is invisible in review:\n * a reviewer looking at a dark mock cannot tell 2.6:1 from 4.4:1, and the focus\n * ring is a WCAG 2.4.11 requirement rather than a preference.\n */\nexport function legible(p: Palette): Fault[] {\n const pairs: Array<[string, string, string, number]> = [\n // The typed card number, at AA for body text.\n ['text on field', p.text, p.field, 4.5],\n // A placeholder that is merely present, not legible, is a label nobody reads.\n ['placeholder on field', p.placeholder, p.field, 4.5],\n // Non-text contrast: this IS the focus indicator (WCAG 2.4.11).\n ['ring on field', p.ring, p.field, 3],\n // The error hue carries both text and a border, so it is held to the lower\n // non-text floor — it is never the only signal, the border moves too.\n ['error on field', p.error, p.field, 3],\n ]\n return pairs\n .map(([pair, a, b, floor]) => ({ pair, ratio: ratio(a, b), floor }))\n .filter((f) => f.ratio < f.floor)\n}\n"]}
package/dist/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunk64AUOMEL_cjs = require('./chunk-64AUOMEL.cjs');
3
+ var chunkAJAETCMO_cjs = require('./chunk-AJAETCMO.cjs');
4
4
 
5
5
  // src/attempt.ts
6
6
  var LIMIT = 45;
@@ -26,35 +26,35 @@ function clamp(key, reserved = 25) {
26
26
 
27
27
  Object.defineProperty(exports, "Cancelled", {
28
28
  enumerable: true,
29
- get: function () { return chunk64AUOMEL_cjs.Cancelled; }
29
+ get: function () { return chunkAJAETCMO_cjs.Cancelled; }
30
30
  });
31
31
  Object.defineProperty(exports, "HEX", {
32
32
  enumerable: true,
33
- get: function () { return chunk64AUOMEL_cjs.HEX; }
33
+ get: function () { return chunkAJAETCMO_cjs.HEX; }
34
34
  });
35
35
  Object.defineProperty(exports, "PALETTE", {
36
36
  enumerable: true,
37
- get: function () { return chunk64AUOMEL_cjs.PALETTE; }
37
+ get: function () { return chunkAJAETCMO_cjs.PALETTE; }
38
38
  });
39
39
  Object.defineProperty(exports, "REACH", {
40
40
  enumerable: true,
41
- get: function () { return chunk64AUOMEL_cjs.REACH; }
41
+ get: function () { return chunkAJAETCMO_cjs.REACH; }
42
42
  });
43
43
  Object.defineProperty(exports, "cancelled", {
44
44
  enumerable: true,
45
- get: function () { return chunk64AUOMEL_cjs.cancelled; }
45
+ get: function () { return chunkAJAETCMO_cjs.cancelled; }
46
46
  });
47
47
  Object.defineProperty(exports, "legible", {
48
48
  enumerable: true,
49
- get: function () { return chunk64AUOMEL_cjs.legible; }
49
+ get: function () { return chunkAJAETCMO_cjs.legible; }
50
50
  });
51
51
  Object.defineProperty(exports, "luminance", {
52
52
  enumerable: true,
53
- get: function () { return chunk64AUOMEL_cjs.luminance; }
53
+ get: function () { return chunkAJAETCMO_cjs.luminance; }
54
54
  });
55
55
  Object.defineProperty(exports, "ratio", {
56
56
  enumerable: true,
57
- get: function () { return chunk64AUOMEL_cjs.ratio; }
57
+ get: function () { return chunkAJAETCMO_cjs.ratio; }
58
58
  });
59
59
  exports.CEILING = CEILING;
60
60
  exports.FLOOR = FLOOR;
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { Cancelled, HEX, PALETTE, REACH, cancelled, legible, luminance, ratio } from './chunk-DXK2QDTX.js';
1
+ export { Cancelled, HEX, PALETTE, REACH, cancelled, legible, luminance, ratio } from './chunk-IYAU5BMM.js';
2
2
 
3
3
  // src/attempt.ts
4
4
  var LIMIT = 45;
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunk64AUOMEL_cjs = require('../chunk-64AUOMEL.cjs');
3
+ var chunkAJAETCMO_cjs = require('../chunk-AJAETCMO.cjs');
4
4
  var reactNativeSquareInAppPayments = require('react-native-square-in-app-payments');
5
5
 
6
6
  // src/native/theme.ts
@@ -18,9 +18,10 @@ function appearance(p, theme) {
18
18
  backgroundColor: colour(p.field),
19
19
  textColor: colour(p.text),
20
20
  placeholderTextColor: colour(p.placeholder),
21
- // The caret and the active field's accent — the native equivalent of the
22
- // focused hairline, and the same value for the same reason.
23
- tintColor: colour(p.borderFocus),
21
+ // The caret and the active field's accent — the native rendering of the same
22
+ // focus colour the web backend draws a ring in, and the same value for the
23
+ // same reason.
24
+ tintColor: colour(p.ring),
24
25
  messageColor: colour(p.placeholder),
25
26
  errorColor: colour(p.error),
26
27
  saveButtonTextColor: colour(p.text),
@@ -82,10 +83,10 @@ var Native = class {
82
83
  if (await reactNativeSquareInAppPayments.SQIPGooglePay.canUseGooglePay()) out.push("google_pay");
83
84
  } catch {
84
85
  }
85
- return out.filter((m) => chunk64AUOMEL_cjs.REACH.native.includes(m));
86
+ return out.filter((m) => chunkAJAETCMO_cjs.REACH.native.includes(m));
86
87
  }
87
88
  collect(method, tender, detail) {
88
- if (!chunk64AUOMEL_cjs.REACH.native.includes(method)) {
89
+ if (!chunkAJAETCMO_cjs.REACH.native.includes(method)) {
89
90
  return Promise.reject(new Error(`${method} is not a rail this SDK has`));
90
91
  }
91
92
  if (method === "card" || method === "gift") return this.sheet(method, detail);
@@ -118,7 +119,7 @@ var Native = class {
118
119
  }
119
120
  return { success: true, onCardEntryComplete: () => resolve(t) };
120
121
  };
121
- const onCancel = () => reject(new chunk64AUOMEL_cjs.Cancelled(method));
122
+ const onCancel = () => reject(new chunkAJAETCMO_cjs.Cancelled(method));
122
123
  if (method === "gift") reactNativeSquareInAppPayments.SQIPCardEntry.startGiftCardEntryFlow(onNonce, onCancel);
123
124
  else reactNativeSquareInAppPayments.SQIPCardEntry.startCardEntryFlow(false, onNonce, onCancel);
124
125
  });
@@ -160,7 +161,7 @@ var Native = class {
160
161
  // silently be `any`.
161
162
  (state, errorMessage) => {
162
163
  if (state === reactNativeSquareInAppPayments.ApplePayNonceSuccessState.Succeeded && settled) resolve(settled);
163
- else if (state === reactNativeSquareInAppPayments.ApplePayNonceSuccessState.Canceled) reject(new chunk64AUOMEL_cjs.Cancelled("apple_pay"));
164
+ else if (state === reactNativeSquareInAppPayments.ApplePayNonceSuccessState.Canceled) reject(new chunkAJAETCMO_cjs.Cancelled("apple_pay"));
164
165
  else reject(new Error(errorMessage || "Apple Pay could not be completed"));
165
166
  }
166
167
  );
@@ -192,7 +193,7 @@ var Native = class {
192
193
  resolve(t);
193
194
  },
194
195
  (e) => reject(new Error(e.message)),
195
- () => reject(new chunk64AUOMEL_cjs.Cancelled("google_pay"))
196
+ () => reject(new chunkAJAETCMO_cjs.Cancelled("google_pay"))
196
197
  );
197
198
  });
198
199
  }
@@ -209,7 +210,7 @@ async function terminal(config) {
209
210
  }
210
211
  reactNativeSquareInAppPayments.SQIPCore.setSquareApplicationId(config.applicationId);
211
212
  reactNativeSquareInAppPayments.SQIPCardEntry.setIOSCardEntryTheme(
212
- appearance(config.palette ?? chunk64AUOMEL_cjs.PALETTE.dark, config.theme ?? "dark")
213
+ appearance(config.palette ?? chunkAJAETCMO_cjs.PALETTE.dark, config.theme ?? "dark")
213
214
  );
214
215
  if (config.appleMerchantId) reactNativeSquareInAppPayments.SQIPApplePay.initializeApplePay(config.appleMerchantId);
215
216
  reactNativeSquareInAppPayments.SQIPGooglePay.initializeGooglePay(
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/native/theme.ts","../../src/native/terminal.ts"],"names":["Brand","SQIPApplePay","SQIPGooglePay","REACH","Cancelled","SQIPCardEntry","ApplePayNonceSuccessState","GooglePayPriceStatus","SQIPCore","PALETTE","GooglePayEnvironment"],"mappings":"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","file":"index.cjs","sourcesContent":["// A `Palette` rendered as the In-App Payments SDK's theme.\n//\n// Same table as the web backend paints the iframe with, so a card field looks\n// the same on a phone as it does in a browser without anyone maintaining two\n// sets of colours. The SDK takes {r,g,b,a} components rather than CSS, which is\n// the entire difference.\n\nimport type { Palette, Theme } from '../palette'\n\n/** The SDK's colour, 0-255 per channel with an optional 0-1 alpha. */\nexport interface Colour {\n r: number\n g: number\n b: number\n a?: number\n}\n\n/**\n * `SQIPCardEntry.setIOSCardEntryTheme`'s argument, as much of it as a palette can\n * answer for. Structurally assignable to the plugin's own `ThemeType`.\n */\nexport interface Appearance {\n backgroundColor?: Colour\n textColor?: Colour\n placeholderTextColor?: Colour\n tintColor?: Colour\n messageColor?: Colour\n errorColor?: Colour\n saveButtonTextColor?: Colour\n keyboardAppearance?: 'Light' | 'Dark'\n}\n\n/** `#rrggbb` -> components. Throws rather than guessing: a silent 0,0,0 is black. */\nexport function colour(hex: string): Colour {\n if (!/^#[0-9a-fA-F]{6}$/.test(hex)) throw new Error(`not an opaque hex colour: ${hex}`)\n return {\n r: parseInt(hex.slice(1, 3), 16),\n g: parseInt(hex.slice(3, 5), 16),\n b: parseInt(hex.slice(5, 7), 16),\n a: 1,\n }\n}\n\n/**\n * The native card sheet's appearance for `p`.\n *\n * TWO HONEST GAPS, both properties of the SDK rather than of this mapping:\n *\n * `border` has no counterpart. iOS draws its own field separators and exposes\n * no colour for them, so the palette's hairline is simply unused here. It is\n * not dropped by oversight and must not be mapped onto something else that\n * happens to accept a colour.\n *\n * THIS IS iOS ONLY. The setter is named for the platform it configures, and\n * Android's card entry is themed through native XML styles at build time —\n * there is no runtime channel to it at all. An Android build gets Square's\n * default sheet unless the app ships the corresponding style resource.\n *\n * `keyboardAppearance` is included because it is the one that gets noticed: a\n * light keyboard sliding up under a black sheet is the most visible seam on the\n * screen, and it is a single word to get right.\n */\nexport function appearance(p: Palette, theme: Theme): Appearance {\n return {\n backgroundColor: colour(p.field),\n textColor: colour(p.text),\n placeholderTextColor: colour(p.placeholder),\n // The caret and the active field's accent — the native equivalent of the\n // focused hairline, and the same value for the same reason.\n tintColor: colour(p.borderFocus),\n messageColor: colour(p.placeholder),\n errorColor: colour(p.error),\n saveButtonTextColor: colour(p.text),\n keyboardAppearance: theme === 'dark' ? 'Dark' : 'Light',\n }\n}\n","// Square's In-App Payments SDK behind the same `Terminal` interface the web\n// backend satisfies.\n//\n// The two SDKs are not parallel and this file is where that stops being the\n// host's problem:\n//\n// The web SDK hands back objects you attach and tokenize. This one exposes\n// NAMESPACES OF CALLBACK FUNCTIONS that present native UI — so every rail here\n// is a callback trio (success / failure / cancel) wrapped into one promise.\n//\n// There is nothing to mount. Card entry is a sheet the OS presents, so\n// `mount` is absent rather than a no-op, which is the honest signal to a host\n// that there is no element to position.\n//\n// Card entry is a STATE MACHINE, not a form: the sheet stays open after\n// minting the token and is told, afterwards, whether the charge worked. See\n// `Detail.charge`.\n//\n// Cash App Pay and ACH are absent from `REACH.native` because this SDK has no\n// such rail — not because they are unfinished.\n\nimport {\n SQIPApplePay,\n SQIPCardEntry,\n SQIPCore,\n SQIPGooglePay,\n Brand,\n GooglePayEnvironment,\n GooglePayPriceStatus,\n ApplePayNonceSuccessState,\n type ApplePayNonceSuccessResult,\n type CardDetails,\n type ErrorDetails,\n type NonceSuccessResult,\n} from 'react-native-square-in-app-payments'\n\nimport {\n type Detail,\n type Method,\n type Tender,\n type Terminal,\n type Token,\n Cancelled,\n REACH,\n} from '../terminal'\nimport { type Palette, PALETTE, type Theme } from '../palette'\nimport { appearance } from './theme'\n\nexport interface Config {\n applicationId: string\n locationId: string\n /** `'sandbox'` tokenizes against Square's sandbox. Anything else is production. */\n environment?: string\n /**\n * The Apple merchant id (`merchant.com.example`) from the app's entitlements.\n * Apple Pay is simply not offered without one — there is nothing to fall back\n * to, and a button that cannot open a sheet is worse than no button.\n */\n appleMerchantId?: string\n /** The card sheet's colours. Defaults to @hanzo/design's dark table. */\n palette?: Palette\n /** Chooses the keyboard's own appearance under the sheet. Defaults to dark. */\n theme?: Theme\n}\n\n/** The plugin's numeric brand enum, as the string the web SDK already reports. */\nconst BRAND: Partial<Record<Brand, string>> = {\n [Brand.VISA]: 'VISA',\n [Brand.MASTERCARD]: 'MASTERCARD',\n [Brand.AMERICAN_EXPRESS]: 'AMERICAN_EXPRESS',\n [Brand.DISCOVER]: 'DISCOVER',\n [Brand.DISCOVER_DINERS]: 'DISCOVER_DINERS',\n [Brand.JCB]: 'JCB',\n [Brand.CHINA_UNION_PAY]: 'CHINA_UNION_PAY',\n [Brand.SQUARE_GIFT_CARD]: 'SQUARE_GIFT_CARD',\n}\n\nfunction token(method: Method, d: CardDetails): Token {\n if (!d.nonce) throw new Error(`${method} returned no token`)\n return {\n value: d.nonce,\n method,\n card: d.card\n ? {\n brand: d.card.brand === undefined ? undefined : BRAND[d.card.brand],\n last4: d.card.lastFourDigits,\n expMonth: d.card.expirationMonth,\n expYear: d.card.expirationYear,\n }\n : undefined,\n }\n}\n\nclass Native implements Terminal {\n constructor(private readonly config: Config) {}\n\n /**\n * What this DEVICE can pay with.\n *\n * Card and gift entry are always available — they are Square's own sheets and\n * need no wallet, no saved card and no capability beyond the SDK being linked.\n * The two wallets are asked, because both can be missing for reasons no\n * user-agent string would reveal: no card in Wallet, no Play Services, a\n * merchant id the app was not signed for.\n *\n * The tender is unused here. Native availability does not depend on the\n * amount, unlike the web SDK, where the total is bound into the wallet object\n * at construction — the interface carries it for the platform that needs it.\n */\n async offers(_tender: Tender): Promise<Method[]> {\n const out: Method[] = ['card', 'gift']\n if (this.config.appleMerchantId) {\n try {\n if (await SQIPApplePay.canUseApplePay()) out.push('apple_pay')\n } catch {\n // Not offerable on this device. Say nothing, show nothing.\n }\n }\n try {\n if (await SQIPGooglePay.canUseGooglePay()) out.push('google_pay')\n } catch {\n // Likewise.\n }\n return out.filter((m) => REACH.native.includes(m))\n }\n\n collect(method: Method, tender: Tender, detail?: Detail): Promise<Token> {\n if (!REACH.native.includes(method)) {\n return Promise.reject(new Error(`${method} is not a rail this SDK has`))\n }\n if (method === 'card' || method === 'gift') return this.sheet(method, detail)\n if (method === 'apple_pay') return this.apple(tender, detail)\n return this.google(tender, detail)\n }\n\n /**\n * Card and gift entry: one sheet, held open until the charge is known.\n *\n * The promise deliberately stays PENDING while the buyer retries. A declined\n * card returns `{ success: false }`, which keeps Square's sheet up with the\n * message shown and the card still entered — resolving or rejecting here would\n * settle a payment the buyer is still in the middle of making.\n */\n private sheet(method: 'card' | 'gift', detail?: Detail): Promise<Token> {\n return new Promise<Token>((resolve, reject) => {\n const onNonce = async (d: CardDetails): Promise<NonceSuccessResult> => {\n let t: Token\n try {\n t = token(method, d)\n } catch (e) {\n return { success: false, errorMessage: message(e) }\n }\n if (detail?.charge) {\n try {\n await detail.charge(t)\n } catch (e) {\n // Stay on the sheet so the buyer can correct the card in place.\n return { success: false, errorMessage: message(e) }\n }\n }\n // `onCardEntryComplete` fires once the sheet has actually closed, so the\n // host's next screen never renders behind a dismissing modal.\n return { success: true, onCardEntryComplete: () => resolve(t) }\n }\n const onCancel = () => reject(new Cancelled(method))\n if (method === 'gift') SQIPCardEntry.startGiftCardEntryFlow(onNonce, onCancel)\n // `false` collects no postal code: the billing address belongs to the\n // payer and the host's own checkout already owns it, so asking again\n // inside the sheet is a second answer to one question.\n else SQIPCardEntry.startCardEntryFlow(false, onNonce, onCancel)\n })\n }\n\n private apple(tender: Tender, detail?: Detail): Promise<Token> {\n return new Promise<Token>((resolve, reject) => {\n let settled: Token | null = null\n void SQIPApplePay.requestApplePayNonce(\n {\n price: tender.total.amount,\n summaryLabel: tender.label,\n countryCode: tender.country,\n currencyCode: tender.total.currency,\n },\n async (d: CardDetails): Promise<ApplePayNonceSuccessResult> => {\n let t: Token\n try {\n t = token('apple_pay', d)\n } catch (e) {\n return { state: ApplePayNonceSuccessState.Failure, errorMessage: message(e) }\n }\n if (detail?.charge) {\n try {\n await detail.charge(t)\n } catch (e) {\n // Apple's sheet shows its own failure state and then closes; there\n // is no retry-in-place here the way there is for card entry.\n return { state: ApplePayNonceSuccessState.Failure, errorMessage: message(e) }\n }\n }\n settled = t\n return { state: ApplePayNonceSuccessState.Succeeded }\n },\n (e: ErrorDetails) => reject(new Error(e.message)),\n // The completion callback is the ONLY place that knows how the sheet\n // ended, so it is the one that settles the promise.\n //\n // Annotated because `requestApplePayNonce` is overloaded and its\n // DEPRECATED signature takes a bare `() => void` here — TypeScript picks\n // that one and infers nothing, so the two arguments this needs would\n // silently be `any`.\n (state: ApplePayNonceSuccessState, errorMessage?: string) => {\n if (state === ApplePayNonceSuccessState.Succeeded && settled) resolve(settled)\n else if (state === ApplePayNonceSuccessState.Canceled) reject(new Cancelled('apple_pay'))\n else reject(new Error(errorMessage || 'Apple Pay could not be completed'))\n },\n )\n })\n }\n\n private google(tender: Tender, detail?: Detail): Promise<Token> {\n return new Promise<Token>((resolve, reject) => {\n void SQIPGooglePay.requestGooglePayNonce(\n {\n price: tender.total.amount,\n currencyCode: tender.total.currency,\n // FINAL, because this total is what the host will charge. Quoting it\n // as estimated invites Google to show a \"price may change\" sheet for a\n // price that will not.\n priceStatus: GooglePayPriceStatus.TotalPriceStatusFinal,\n },\n (d: CardDetails) => {\n let t: Token\n try {\n t = token('google_pay', d)\n } catch (e) {\n reject(e)\n return\n }\n // Google Pay's sheet has already closed by the time this fires, so a\n // charge failure here is the host's to show on its own screen.\n if (detail?.charge) {\n detail.charge(t).then(() => resolve(t), reject)\n return\n }\n resolve(t)\n },\n (e: ErrorDetails) => reject(new Error(e.message)),\n () => reject(new Cancelled('google_pay')),\n )\n })\n }\n\n /** Nothing is held open between payments — every native rail is a sheet per call. */\n async release(): Promise<void> {}\n}\n\nfunction message(e: unknown): string {\n return e instanceof Error ? e.message : 'payment failed'\n}\n\n/**\n * A terminal for this device.\n *\n * Configuration is GLOBAL to the SDK — `setSquareApplicationId`,\n * `initializeApplePay` and `initializeGooglePay` set process-wide state rather\n * than returning handles — so this applies it and returns a thin object over it.\n * Two terminals with different application ids cannot coexist; the last one\n * built wins. That is the SDK's shape, not a choice made here.\n */\nexport async function terminal(config: Config): Promise<Terminal> {\n if (!config.applicationId || !config.locationId) {\n throw new Error('Square is not configured for this build')\n }\n SQIPCore.setSquareApplicationId(config.applicationId)\n SQIPCardEntry.setIOSCardEntryTheme(\n appearance(config.palette ?? PALETTE.dark, config.theme ?? 'dark'),\n )\n if (config.appleMerchantId) SQIPApplePay.initializeApplePay(config.appleMerchantId)\n SQIPGooglePay.initializeGooglePay(\n config.locationId,\n (config.environment ?? 'production').toLowerCase() === 'sandbox'\n ? GooglePayEnvironment.EnvironmentTest\n : GooglePayEnvironment.EnvironmentProduction,\n )\n return new Native(config)\n}\n"]}
1
+ {"version":3,"sources":["../../src/native/theme.ts","../../src/native/terminal.ts"],"names":["Brand","SQIPApplePay","SQIPGooglePay","REACH","Cancelled","SQIPCardEntry","ApplePayNonceSuccessState","GooglePayPriceStatus","SQIPCore","PALETTE","GooglePayEnvironment"],"mappings":"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","file":"index.cjs","sourcesContent":["// A `Palette` rendered as the In-App Payments SDK's theme.\n//\n// Same table as the web backend paints the iframe with, so a card field looks\n// the same on a phone as it does in a browser without anyone maintaining two\n// sets of colours. The SDK takes {r,g,b,a} components rather than CSS, which is\n// the entire difference.\n\nimport type { Palette, Theme } from '../palette'\n\n/** The SDK's colour, 0-255 per channel with an optional 0-1 alpha. */\nexport interface Colour {\n r: number\n g: number\n b: number\n a?: number\n}\n\n/**\n * `SQIPCardEntry.setIOSCardEntryTheme`'s argument, as much of it as a palette can\n * answer for. Structurally assignable to the plugin's own `ThemeType`.\n */\nexport interface Appearance {\n backgroundColor?: Colour\n textColor?: Colour\n placeholderTextColor?: Colour\n tintColor?: Colour\n messageColor?: Colour\n errorColor?: Colour\n saveButtonTextColor?: Colour\n keyboardAppearance?: 'Light' | 'Dark'\n}\n\n/** `#rrggbb` -> components. Throws rather than guessing: a silent 0,0,0 is black. */\nexport function colour(hex: string): Colour {\n if (!/^#[0-9a-fA-F]{6}$/.test(hex)) throw new Error(`not an opaque hex colour: ${hex}`)\n return {\n r: parseInt(hex.slice(1, 3), 16),\n g: parseInt(hex.slice(3, 5), 16),\n b: parseInt(hex.slice(5, 7), 16),\n a: 1,\n }\n}\n\n/**\n * The native card sheet's appearance for `p`.\n *\n * TWO HONEST GAPS, both properties of the SDK rather than of this mapping:\n *\n * `border` has no counterpart. iOS draws its own field separators and exposes\n * no colour for them, so the palette's hairline is simply unused here. It is\n * not dropped by oversight and must not be mapped onto something else that\n * happens to accept a colour.\n *\n * THIS IS iOS ONLY. The setter is named for the platform it configures, and\n * Android's card entry is themed through native XML styles at build time —\n * there is no runtime channel to it at all. An Android build gets Square's\n * default sheet unless the app ships the corresponding style resource.\n *\n * `keyboardAppearance` is included because it is the one that gets noticed: a\n * light keyboard sliding up under a black sheet is the most visible seam on the\n * screen, and it is a single word to get right.\n */\nexport function appearance(p: Palette, theme: Theme): Appearance {\n return {\n backgroundColor: colour(p.field),\n textColor: colour(p.text),\n placeholderTextColor: colour(p.placeholder),\n // The caret and the active field's accent — the native rendering of the same\n // focus colour the web backend draws a ring in, and the same value for the\n // same reason.\n tintColor: colour(p.ring),\n messageColor: colour(p.placeholder),\n errorColor: colour(p.error),\n saveButtonTextColor: colour(p.text),\n keyboardAppearance: theme === 'dark' ? 'Dark' : 'Light',\n }\n}\n","// Square's In-App Payments SDK behind the same `Terminal` interface the web\n// backend satisfies.\n//\n// The two SDKs are not parallel and this file is where that stops being the\n// host's problem:\n//\n// The web SDK hands back objects you attach and tokenize. This one exposes\n// NAMESPACES OF CALLBACK FUNCTIONS that present native UI — so every rail here\n// is a callback trio (success / failure / cancel) wrapped into one promise.\n//\n// There is nothing to mount. Card entry is a sheet the OS presents, so\n// `mount` is absent rather than a no-op, which is the honest signal to a host\n// that there is no element to position.\n//\n// Card entry is a STATE MACHINE, not a form: the sheet stays open after\n// minting the token and is told, afterwards, whether the charge worked. See\n// `Detail.charge`.\n//\n// Cash App Pay and ACH are absent from `REACH.native` because this SDK has no\n// such rail — not because they are unfinished.\n\nimport {\n SQIPApplePay,\n SQIPCardEntry,\n SQIPCore,\n SQIPGooglePay,\n Brand,\n GooglePayEnvironment,\n GooglePayPriceStatus,\n ApplePayNonceSuccessState,\n type ApplePayNonceSuccessResult,\n type CardDetails,\n type ErrorDetails,\n type NonceSuccessResult,\n} from 'react-native-square-in-app-payments'\n\nimport {\n type Detail,\n type Method,\n type Tender,\n type Terminal,\n type Token,\n Cancelled,\n REACH,\n} from '../terminal'\nimport { type Palette, PALETTE, type Theme } from '../palette'\nimport { appearance } from './theme'\n\nexport interface Config {\n applicationId: string\n locationId: string\n /** `'sandbox'` tokenizes against Square's sandbox. Anything else is production. */\n environment?: string\n /**\n * The Apple merchant id (`merchant.com.example`) from the app's entitlements.\n * Apple Pay is simply not offered without one — there is nothing to fall back\n * to, and a button that cannot open a sheet is worse than no button.\n */\n appleMerchantId?: string\n /** The card sheet's colours. Defaults to @hanzo/design's dark table. */\n palette?: Palette\n /** Chooses the keyboard's own appearance under the sheet. Defaults to dark. */\n theme?: Theme\n}\n\n/** The plugin's numeric brand enum, as the string the web SDK already reports. */\nconst BRAND: Partial<Record<Brand, string>> = {\n [Brand.VISA]: 'VISA',\n [Brand.MASTERCARD]: 'MASTERCARD',\n [Brand.AMERICAN_EXPRESS]: 'AMERICAN_EXPRESS',\n [Brand.DISCOVER]: 'DISCOVER',\n [Brand.DISCOVER_DINERS]: 'DISCOVER_DINERS',\n [Brand.JCB]: 'JCB',\n [Brand.CHINA_UNION_PAY]: 'CHINA_UNION_PAY',\n [Brand.SQUARE_GIFT_CARD]: 'SQUARE_GIFT_CARD',\n}\n\nfunction token(method: Method, d: CardDetails): Token {\n if (!d.nonce) throw new Error(`${method} returned no token`)\n return {\n value: d.nonce,\n method,\n card: d.card\n ? {\n brand: d.card.brand === undefined ? undefined : BRAND[d.card.brand],\n last4: d.card.lastFourDigits,\n expMonth: d.card.expirationMonth,\n expYear: d.card.expirationYear,\n }\n : undefined,\n }\n}\n\nclass Native implements Terminal {\n constructor(private readonly config: Config) {}\n\n /**\n * What this DEVICE can pay with.\n *\n * Card and gift entry are always available — they are Square's own sheets and\n * need no wallet, no saved card and no capability beyond the SDK being linked.\n * The two wallets are asked, because both can be missing for reasons no\n * user-agent string would reveal: no card in Wallet, no Play Services, a\n * merchant id the app was not signed for.\n *\n * The tender is unused here. Native availability does not depend on the\n * amount, unlike the web SDK, where the total is bound into the wallet object\n * at construction — the interface carries it for the platform that needs it.\n */\n async offers(_tender: Tender): Promise<Method[]> {\n const out: Method[] = ['card', 'gift']\n if (this.config.appleMerchantId) {\n try {\n if (await SQIPApplePay.canUseApplePay()) out.push('apple_pay')\n } catch {\n // Not offerable on this device. Say nothing, show nothing.\n }\n }\n try {\n if (await SQIPGooglePay.canUseGooglePay()) out.push('google_pay')\n } catch {\n // Likewise.\n }\n return out.filter((m) => REACH.native.includes(m))\n }\n\n collect(method: Method, tender: Tender, detail?: Detail): Promise<Token> {\n if (!REACH.native.includes(method)) {\n return Promise.reject(new Error(`${method} is not a rail this SDK has`))\n }\n if (method === 'card' || method === 'gift') return this.sheet(method, detail)\n if (method === 'apple_pay') return this.apple(tender, detail)\n return this.google(tender, detail)\n }\n\n /**\n * Card and gift entry: one sheet, held open until the charge is known.\n *\n * The promise deliberately stays PENDING while the buyer retries. A declined\n * card returns `{ success: false }`, which keeps Square's sheet up with the\n * message shown and the card still entered — resolving or rejecting here would\n * settle a payment the buyer is still in the middle of making.\n */\n private sheet(method: 'card' | 'gift', detail?: Detail): Promise<Token> {\n return new Promise<Token>((resolve, reject) => {\n const onNonce = async (d: CardDetails): Promise<NonceSuccessResult> => {\n let t: Token\n try {\n t = token(method, d)\n } catch (e) {\n return { success: false, errorMessage: message(e) }\n }\n if (detail?.charge) {\n try {\n await detail.charge(t)\n } catch (e) {\n // Stay on the sheet so the buyer can correct the card in place.\n return { success: false, errorMessage: message(e) }\n }\n }\n // `onCardEntryComplete` fires once the sheet has actually closed, so the\n // host's next screen never renders behind a dismissing modal.\n return { success: true, onCardEntryComplete: () => resolve(t) }\n }\n const onCancel = () => reject(new Cancelled(method))\n if (method === 'gift') SQIPCardEntry.startGiftCardEntryFlow(onNonce, onCancel)\n // `false` collects no postal code: the billing address belongs to the\n // payer and the host's own checkout already owns it, so asking again\n // inside the sheet is a second answer to one question.\n else SQIPCardEntry.startCardEntryFlow(false, onNonce, onCancel)\n })\n }\n\n private apple(tender: Tender, detail?: Detail): Promise<Token> {\n return new Promise<Token>((resolve, reject) => {\n let settled: Token | null = null\n void SQIPApplePay.requestApplePayNonce(\n {\n price: tender.total.amount,\n summaryLabel: tender.label,\n countryCode: tender.country,\n currencyCode: tender.total.currency,\n },\n async (d: CardDetails): Promise<ApplePayNonceSuccessResult> => {\n let t: Token\n try {\n t = token('apple_pay', d)\n } catch (e) {\n return { state: ApplePayNonceSuccessState.Failure, errorMessage: message(e) }\n }\n if (detail?.charge) {\n try {\n await detail.charge(t)\n } catch (e) {\n // Apple's sheet shows its own failure state and then closes; there\n // is no retry-in-place here the way there is for card entry.\n return { state: ApplePayNonceSuccessState.Failure, errorMessage: message(e) }\n }\n }\n settled = t\n return { state: ApplePayNonceSuccessState.Succeeded }\n },\n (e: ErrorDetails) => reject(new Error(e.message)),\n // The completion callback is the ONLY place that knows how the sheet\n // ended, so it is the one that settles the promise.\n //\n // Annotated because `requestApplePayNonce` is overloaded and its\n // DEPRECATED signature takes a bare `() => void` here — TypeScript picks\n // that one and infers nothing, so the two arguments this needs would\n // silently be `any`.\n (state: ApplePayNonceSuccessState, errorMessage?: string) => {\n if (state === ApplePayNonceSuccessState.Succeeded && settled) resolve(settled)\n else if (state === ApplePayNonceSuccessState.Canceled) reject(new Cancelled('apple_pay'))\n else reject(new Error(errorMessage || 'Apple Pay could not be completed'))\n },\n )\n })\n }\n\n private google(tender: Tender, detail?: Detail): Promise<Token> {\n return new Promise<Token>((resolve, reject) => {\n void SQIPGooglePay.requestGooglePayNonce(\n {\n price: tender.total.amount,\n currencyCode: tender.total.currency,\n // FINAL, because this total is what the host will charge. Quoting it\n // as estimated invites Google to show a \"price may change\" sheet for a\n // price that will not.\n priceStatus: GooglePayPriceStatus.TotalPriceStatusFinal,\n },\n (d: CardDetails) => {\n let t: Token\n try {\n t = token('google_pay', d)\n } catch (e) {\n reject(e)\n return\n }\n // Google Pay's sheet has already closed by the time this fires, so a\n // charge failure here is the host's to show on its own screen.\n if (detail?.charge) {\n detail.charge(t).then(() => resolve(t), reject)\n return\n }\n resolve(t)\n },\n (e: ErrorDetails) => reject(new Error(e.message)),\n () => reject(new Cancelled('google_pay')),\n )\n })\n }\n\n /** Nothing is held open between payments — every native rail is a sheet per call. */\n async release(): Promise<void> {}\n}\n\nfunction message(e: unknown): string {\n return e instanceof Error ? e.message : 'payment failed'\n}\n\n/**\n * A terminal for this device.\n *\n * Configuration is GLOBAL to the SDK — `setSquareApplicationId`,\n * `initializeApplePay` and `initializeGooglePay` set process-wide state rather\n * than returning handles — so this applies it and returns a thin object over it.\n * Two terminals with different application ids cannot coexist; the last one\n * built wins. That is the SDK's shape, not a choice made here.\n */\nexport async function terminal(config: Config): Promise<Terminal> {\n if (!config.applicationId || !config.locationId) {\n throw new Error('Square is not configured for this build')\n }\n SQIPCore.setSquareApplicationId(config.applicationId)\n SQIPCardEntry.setIOSCardEntryTheme(\n appearance(config.palette ?? PALETTE.dark, config.theme ?? 'dark'),\n )\n if (config.appleMerchantId) SQIPApplePay.initializeApplePay(config.appleMerchantId)\n SQIPGooglePay.initializeGooglePay(\n config.locationId,\n (config.environment ?? 'production').toLowerCase() === 'sandbox'\n ? GooglePayEnvironment.EnvironmentTest\n : GooglePayEnvironment.EnvironmentProduction,\n )\n return new Native(config)\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { PALETTE, REACH, Cancelled } from '../chunk-DXK2QDTX.js';
1
+ import { PALETTE, REACH, Cancelled } from '../chunk-IYAU5BMM.js';
2
2
  import { Brand, SQIPCore, SQIPCardEntry, SQIPApplePay, SQIPGooglePay, GooglePayEnvironment, ApplePayNonceSuccessState, GooglePayPriceStatus } from 'react-native-square-in-app-payments';
3
3
 
4
4
  // src/native/theme.ts
@@ -16,9 +16,10 @@ function appearance(p, theme) {
16
16
  backgroundColor: colour(p.field),
17
17
  textColor: colour(p.text),
18
18
  placeholderTextColor: colour(p.placeholder),
19
- // The caret and the active field's accent — the native equivalent of the
20
- // focused hairline, and the same value for the same reason.
21
- tintColor: colour(p.borderFocus),
19
+ // The caret and the active field's accent — the native rendering of the same
20
+ // focus colour the web backend draws a ring in, and the same value for the
21
+ // same reason.
22
+ tintColor: colour(p.ring),
22
23
  messageColor: colour(p.placeholder),
23
24
  errorColor: colour(p.error),
24
25
  saveButtonTextColor: colour(p.text),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/native/theme.ts","../../src/native/terminal.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// A `Palette` rendered as the In-App Payments SDK's theme.\n//\n// Same table as the web backend paints the iframe with, so a card field looks\n// the same on a phone as it does in a browser without anyone maintaining two\n// sets of colours. The SDK takes {r,g,b,a} components rather than CSS, which is\n// the entire difference.\n\nimport type { Palette, Theme } from '../palette'\n\n/** The SDK's colour, 0-255 per channel with an optional 0-1 alpha. */\nexport interface Colour {\n r: number\n g: number\n b: number\n a?: number\n}\n\n/**\n * `SQIPCardEntry.setIOSCardEntryTheme`'s argument, as much of it as a palette can\n * answer for. Structurally assignable to the plugin's own `ThemeType`.\n */\nexport interface Appearance {\n backgroundColor?: Colour\n textColor?: Colour\n placeholderTextColor?: Colour\n tintColor?: Colour\n messageColor?: Colour\n errorColor?: Colour\n saveButtonTextColor?: Colour\n keyboardAppearance?: 'Light' | 'Dark'\n}\n\n/** `#rrggbb` -> components. Throws rather than guessing: a silent 0,0,0 is black. */\nexport function colour(hex: string): Colour {\n if (!/^#[0-9a-fA-F]{6}$/.test(hex)) throw new Error(`not an opaque hex colour: ${hex}`)\n return {\n r: parseInt(hex.slice(1, 3), 16),\n g: parseInt(hex.slice(3, 5), 16),\n b: parseInt(hex.slice(5, 7), 16),\n a: 1,\n }\n}\n\n/**\n * The native card sheet's appearance for `p`.\n *\n * TWO HONEST GAPS, both properties of the SDK rather than of this mapping:\n *\n * `border` has no counterpart. iOS draws its own field separators and exposes\n * no colour for them, so the palette's hairline is simply unused here. It is\n * not dropped by oversight and must not be mapped onto something else that\n * happens to accept a colour.\n *\n * THIS IS iOS ONLY. The setter is named for the platform it configures, and\n * Android's card entry is themed through native XML styles at build time —\n * there is no runtime channel to it at all. An Android build gets Square's\n * default sheet unless the app ships the corresponding style resource.\n *\n * `keyboardAppearance` is included because it is the one that gets noticed: a\n * light keyboard sliding up under a black sheet is the most visible seam on the\n * screen, and it is a single word to get right.\n */\nexport function appearance(p: Palette, theme: Theme): Appearance {\n return {\n backgroundColor: colour(p.field),\n textColor: colour(p.text),\n placeholderTextColor: colour(p.placeholder),\n // The caret and the active field's accent — the native equivalent of the\n // focused hairline, and the same value for the same reason.\n tintColor: colour(p.borderFocus),\n messageColor: colour(p.placeholder),\n errorColor: colour(p.error),\n saveButtonTextColor: colour(p.text),\n keyboardAppearance: theme === 'dark' ? 'Dark' : 'Light',\n }\n}\n","// Square's In-App Payments SDK behind the same `Terminal` interface the web\n// backend satisfies.\n//\n// The two SDKs are not parallel and this file is where that stops being the\n// host's problem:\n//\n// The web SDK hands back objects you attach and tokenize. This one exposes\n// NAMESPACES OF CALLBACK FUNCTIONS that present native UI — so every rail here\n// is a callback trio (success / failure / cancel) wrapped into one promise.\n//\n// There is nothing to mount. Card entry is a sheet the OS presents, so\n// `mount` is absent rather than a no-op, which is the honest signal to a host\n// that there is no element to position.\n//\n// Card entry is a STATE MACHINE, not a form: the sheet stays open after\n// minting the token and is told, afterwards, whether the charge worked. See\n// `Detail.charge`.\n//\n// Cash App Pay and ACH are absent from `REACH.native` because this SDK has no\n// such rail — not because they are unfinished.\n\nimport {\n SQIPApplePay,\n SQIPCardEntry,\n SQIPCore,\n SQIPGooglePay,\n Brand,\n GooglePayEnvironment,\n GooglePayPriceStatus,\n ApplePayNonceSuccessState,\n type ApplePayNonceSuccessResult,\n type CardDetails,\n type ErrorDetails,\n type NonceSuccessResult,\n} from 'react-native-square-in-app-payments'\n\nimport {\n type Detail,\n type Method,\n type Tender,\n type Terminal,\n type Token,\n Cancelled,\n REACH,\n} from '../terminal'\nimport { type Palette, PALETTE, type Theme } from '../palette'\nimport { appearance } from './theme'\n\nexport interface Config {\n applicationId: string\n locationId: string\n /** `'sandbox'` tokenizes against Square's sandbox. Anything else is production. */\n environment?: string\n /**\n * The Apple merchant id (`merchant.com.example`) from the app's entitlements.\n * Apple Pay is simply not offered without one — there is nothing to fall back\n * to, and a button that cannot open a sheet is worse than no button.\n */\n appleMerchantId?: string\n /** The card sheet's colours. Defaults to @hanzo/design's dark table. */\n palette?: Palette\n /** Chooses the keyboard's own appearance under the sheet. Defaults to dark. */\n theme?: Theme\n}\n\n/** The plugin's numeric brand enum, as the string the web SDK already reports. */\nconst BRAND: Partial<Record<Brand, string>> = {\n [Brand.VISA]: 'VISA',\n [Brand.MASTERCARD]: 'MASTERCARD',\n [Brand.AMERICAN_EXPRESS]: 'AMERICAN_EXPRESS',\n [Brand.DISCOVER]: 'DISCOVER',\n [Brand.DISCOVER_DINERS]: 'DISCOVER_DINERS',\n [Brand.JCB]: 'JCB',\n [Brand.CHINA_UNION_PAY]: 'CHINA_UNION_PAY',\n [Brand.SQUARE_GIFT_CARD]: 'SQUARE_GIFT_CARD',\n}\n\nfunction token(method: Method, d: CardDetails): Token {\n if (!d.nonce) throw new Error(`${method} returned no token`)\n return {\n value: d.nonce,\n method,\n card: d.card\n ? {\n brand: d.card.brand === undefined ? undefined : BRAND[d.card.brand],\n last4: d.card.lastFourDigits,\n expMonth: d.card.expirationMonth,\n expYear: d.card.expirationYear,\n }\n : undefined,\n }\n}\n\nclass Native implements Terminal {\n constructor(private readonly config: Config) {}\n\n /**\n * What this DEVICE can pay with.\n *\n * Card and gift entry are always available — they are Square's own sheets and\n * need no wallet, no saved card and no capability beyond the SDK being linked.\n * The two wallets are asked, because both can be missing for reasons no\n * user-agent string would reveal: no card in Wallet, no Play Services, a\n * merchant id the app was not signed for.\n *\n * The tender is unused here. Native availability does not depend on the\n * amount, unlike the web SDK, where the total is bound into the wallet object\n * at construction — the interface carries it for the platform that needs it.\n */\n async offers(_tender: Tender): Promise<Method[]> {\n const out: Method[] = ['card', 'gift']\n if (this.config.appleMerchantId) {\n try {\n if (await SQIPApplePay.canUseApplePay()) out.push('apple_pay')\n } catch {\n // Not offerable on this device. Say nothing, show nothing.\n }\n }\n try {\n if (await SQIPGooglePay.canUseGooglePay()) out.push('google_pay')\n } catch {\n // Likewise.\n }\n return out.filter((m) => REACH.native.includes(m))\n }\n\n collect(method: Method, tender: Tender, detail?: Detail): Promise<Token> {\n if (!REACH.native.includes(method)) {\n return Promise.reject(new Error(`${method} is not a rail this SDK has`))\n }\n if (method === 'card' || method === 'gift') return this.sheet(method, detail)\n if (method === 'apple_pay') return this.apple(tender, detail)\n return this.google(tender, detail)\n }\n\n /**\n * Card and gift entry: one sheet, held open until the charge is known.\n *\n * The promise deliberately stays PENDING while the buyer retries. A declined\n * card returns `{ success: false }`, which keeps Square's sheet up with the\n * message shown and the card still entered — resolving or rejecting here would\n * settle a payment the buyer is still in the middle of making.\n */\n private sheet(method: 'card' | 'gift', detail?: Detail): Promise<Token> {\n return new Promise<Token>((resolve, reject) => {\n const onNonce = async (d: CardDetails): Promise<NonceSuccessResult> => {\n let t: Token\n try {\n t = token(method, d)\n } catch (e) {\n return { success: false, errorMessage: message(e) }\n }\n if (detail?.charge) {\n try {\n await detail.charge(t)\n } catch (e) {\n // Stay on the sheet so the buyer can correct the card in place.\n return { success: false, errorMessage: message(e) }\n }\n }\n // `onCardEntryComplete` fires once the sheet has actually closed, so the\n // host's next screen never renders behind a dismissing modal.\n return { success: true, onCardEntryComplete: () => resolve(t) }\n }\n const onCancel = () => reject(new Cancelled(method))\n if (method === 'gift') SQIPCardEntry.startGiftCardEntryFlow(onNonce, onCancel)\n // `false` collects no postal code: the billing address belongs to the\n // payer and the host's own checkout already owns it, so asking again\n // inside the sheet is a second answer to one question.\n else SQIPCardEntry.startCardEntryFlow(false, onNonce, onCancel)\n })\n }\n\n private apple(tender: Tender, detail?: Detail): Promise<Token> {\n return new Promise<Token>((resolve, reject) => {\n let settled: Token | null = null\n void SQIPApplePay.requestApplePayNonce(\n {\n price: tender.total.amount,\n summaryLabel: tender.label,\n countryCode: tender.country,\n currencyCode: tender.total.currency,\n },\n async (d: CardDetails): Promise<ApplePayNonceSuccessResult> => {\n let t: Token\n try {\n t = token('apple_pay', d)\n } catch (e) {\n return { state: ApplePayNonceSuccessState.Failure, errorMessage: message(e) }\n }\n if (detail?.charge) {\n try {\n await detail.charge(t)\n } catch (e) {\n // Apple's sheet shows its own failure state and then closes; there\n // is no retry-in-place here the way there is for card entry.\n return { state: ApplePayNonceSuccessState.Failure, errorMessage: message(e) }\n }\n }\n settled = t\n return { state: ApplePayNonceSuccessState.Succeeded }\n },\n (e: ErrorDetails) => reject(new Error(e.message)),\n // The completion callback is the ONLY place that knows how the sheet\n // ended, so it is the one that settles the promise.\n //\n // Annotated because `requestApplePayNonce` is overloaded and its\n // DEPRECATED signature takes a bare `() => void` here — TypeScript picks\n // that one and infers nothing, so the two arguments this needs would\n // silently be `any`.\n (state: ApplePayNonceSuccessState, errorMessage?: string) => {\n if (state === ApplePayNonceSuccessState.Succeeded && settled) resolve(settled)\n else if (state === ApplePayNonceSuccessState.Canceled) reject(new Cancelled('apple_pay'))\n else reject(new Error(errorMessage || 'Apple Pay could not be completed'))\n },\n )\n })\n }\n\n private google(tender: Tender, detail?: Detail): Promise<Token> {\n return new Promise<Token>((resolve, reject) => {\n void SQIPGooglePay.requestGooglePayNonce(\n {\n price: tender.total.amount,\n currencyCode: tender.total.currency,\n // FINAL, because this total is what the host will charge. Quoting it\n // as estimated invites Google to show a \"price may change\" sheet for a\n // price that will not.\n priceStatus: GooglePayPriceStatus.TotalPriceStatusFinal,\n },\n (d: CardDetails) => {\n let t: Token\n try {\n t = token('google_pay', d)\n } catch (e) {\n reject(e)\n return\n }\n // Google Pay's sheet has already closed by the time this fires, so a\n // charge failure here is the host's to show on its own screen.\n if (detail?.charge) {\n detail.charge(t).then(() => resolve(t), reject)\n return\n }\n resolve(t)\n },\n (e: ErrorDetails) => reject(new Error(e.message)),\n () => reject(new Cancelled('google_pay')),\n )\n })\n }\n\n /** Nothing is held open between payments — every native rail is a sheet per call. */\n async release(): Promise<void> {}\n}\n\nfunction message(e: unknown): string {\n return e instanceof Error ? e.message : 'payment failed'\n}\n\n/**\n * A terminal for this device.\n *\n * Configuration is GLOBAL to the SDK — `setSquareApplicationId`,\n * `initializeApplePay` and `initializeGooglePay` set process-wide state rather\n * than returning handles — so this applies it and returns a thin object over it.\n * Two terminals with different application ids cannot coexist; the last one\n * built wins. That is the SDK's shape, not a choice made here.\n */\nexport async function terminal(config: Config): Promise<Terminal> {\n if (!config.applicationId || !config.locationId) {\n throw new Error('Square is not configured for this build')\n }\n SQIPCore.setSquareApplicationId(config.applicationId)\n SQIPCardEntry.setIOSCardEntryTheme(\n appearance(config.palette ?? PALETTE.dark, config.theme ?? 'dark'),\n )\n if (config.appleMerchantId) SQIPApplePay.initializeApplePay(config.appleMerchantId)\n SQIPGooglePay.initializeGooglePay(\n config.locationId,\n (config.environment ?? 'production').toLowerCase() === 'sandbox'\n ? GooglePayEnvironment.EnvironmentTest\n : GooglePayEnvironment.EnvironmentProduction,\n )\n return new Native(config)\n}\n"]}
1
+ {"version":3,"sources":["../../src/native/theme.ts","../../src/native/terminal.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// A `Palette` rendered as the In-App Payments SDK's theme.\n//\n// Same table as the web backend paints the iframe with, so a card field looks\n// the same on a phone as it does in a browser without anyone maintaining two\n// sets of colours. The SDK takes {r,g,b,a} components rather than CSS, which is\n// the entire difference.\n\nimport type { Palette, Theme } from '../palette'\n\n/** The SDK's colour, 0-255 per channel with an optional 0-1 alpha. */\nexport interface Colour {\n r: number\n g: number\n b: number\n a?: number\n}\n\n/**\n * `SQIPCardEntry.setIOSCardEntryTheme`'s argument, as much of it as a palette can\n * answer for. Structurally assignable to the plugin's own `ThemeType`.\n */\nexport interface Appearance {\n backgroundColor?: Colour\n textColor?: Colour\n placeholderTextColor?: Colour\n tintColor?: Colour\n messageColor?: Colour\n errorColor?: Colour\n saveButtonTextColor?: Colour\n keyboardAppearance?: 'Light' | 'Dark'\n}\n\n/** `#rrggbb` -> components. Throws rather than guessing: a silent 0,0,0 is black. */\nexport function colour(hex: string): Colour {\n if (!/^#[0-9a-fA-F]{6}$/.test(hex)) throw new Error(`not an opaque hex colour: ${hex}`)\n return {\n r: parseInt(hex.slice(1, 3), 16),\n g: parseInt(hex.slice(3, 5), 16),\n b: parseInt(hex.slice(5, 7), 16),\n a: 1,\n }\n}\n\n/**\n * The native card sheet's appearance for `p`.\n *\n * TWO HONEST GAPS, both properties of the SDK rather than of this mapping:\n *\n * `border` has no counterpart. iOS draws its own field separators and exposes\n * no colour for them, so the palette's hairline is simply unused here. It is\n * not dropped by oversight and must not be mapped onto something else that\n * happens to accept a colour.\n *\n * THIS IS iOS ONLY. The setter is named for the platform it configures, and\n * Android's card entry is themed through native XML styles at build time —\n * there is no runtime channel to it at all. An Android build gets Square's\n * default sheet unless the app ships the corresponding style resource.\n *\n * `keyboardAppearance` is included because it is the one that gets noticed: a\n * light keyboard sliding up under a black sheet is the most visible seam on the\n * screen, and it is a single word to get right.\n */\nexport function appearance(p: Palette, theme: Theme): Appearance {\n return {\n backgroundColor: colour(p.field),\n textColor: colour(p.text),\n placeholderTextColor: colour(p.placeholder),\n // The caret and the active field's accent — the native rendering of the same\n // focus colour the web backend draws a ring in, and the same value for the\n // same reason.\n tintColor: colour(p.ring),\n messageColor: colour(p.placeholder),\n errorColor: colour(p.error),\n saveButtonTextColor: colour(p.text),\n keyboardAppearance: theme === 'dark' ? 'Dark' : 'Light',\n }\n}\n","// Square's In-App Payments SDK behind the same `Terminal` interface the web\n// backend satisfies.\n//\n// The two SDKs are not parallel and this file is where that stops being the\n// host's problem:\n//\n// The web SDK hands back objects you attach and tokenize. This one exposes\n// NAMESPACES OF CALLBACK FUNCTIONS that present native UI — so every rail here\n// is a callback trio (success / failure / cancel) wrapped into one promise.\n//\n// There is nothing to mount. Card entry is a sheet the OS presents, so\n// `mount` is absent rather than a no-op, which is the honest signal to a host\n// that there is no element to position.\n//\n// Card entry is a STATE MACHINE, not a form: the sheet stays open after\n// minting the token and is told, afterwards, whether the charge worked. See\n// `Detail.charge`.\n//\n// Cash App Pay and ACH are absent from `REACH.native` because this SDK has no\n// such rail — not because they are unfinished.\n\nimport {\n SQIPApplePay,\n SQIPCardEntry,\n SQIPCore,\n SQIPGooglePay,\n Brand,\n GooglePayEnvironment,\n GooglePayPriceStatus,\n ApplePayNonceSuccessState,\n type ApplePayNonceSuccessResult,\n type CardDetails,\n type ErrorDetails,\n type NonceSuccessResult,\n} from 'react-native-square-in-app-payments'\n\nimport {\n type Detail,\n type Method,\n type Tender,\n type Terminal,\n type Token,\n Cancelled,\n REACH,\n} from '../terminal'\nimport { type Palette, PALETTE, type Theme } from '../palette'\nimport { appearance } from './theme'\n\nexport interface Config {\n applicationId: string\n locationId: string\n /** `'sandbox'` tokenizes against Square's sandbox. Anything else is production. */\n environment?: string\n /**\n * The Apple merchant id (`merchant.com.example`) from the app's entitlements.\n * Apple Pay is simply not offered without one — there is nothing to fall back\n * to, and a button that cannot open a sheet is worse than no button.\n */\n appleMerchantId?: string\n /** The card sheet's colours. Defaults to @hanzo/design's dark table. */\n palette?: Palette\n /** Chooses the keyboard's own appearance under the sheet. Defaults to dark. */\n theme?: Theme\n}\n\n/** The plugin's numeric brand enum, as the string the web SDK already reports. */\nconst BRAND: Partial<Record<Brand, string>> = {\n [Brand.VISA]: 'VISA',\n [Brand.MASTERCARD]: 'MASTERCARD',\n [Brand.AMERICAN_EXPRESS]: 'AMERICAN_EXPRESS',\n [Brand.DISCOVER]: 'DISCOVER',\n [Brand.DISCOVER_DINERS]: 'DISCOVER_DINERS',\n [Brand.JCB]: 'JCB',\n [Brand.CHINA_UNION_PAY]: 'CHINA_UNION_PAY',\n [Brand.SQUARE_GIFT_CARD]: 'SQUARE_GIFT_CARD',\n}\n\nfunction token(method: Method, d: CardDetails): Token {\n if (!d.nonce) throw new Error(`${method} returned no token`)\n return {\n value: d.nonce,\n method,\n card: d.card\n ? {\n brand: d.card.brand === undefined ? undefined : BRAND[d.card.brand],\n last4: d.card.lastFourDigits,\n expMonth: d.card.expirationMonth,\n expYear: d.card.expirationYear,\n }\n : undefined,\n }\n}\n\nclass Native implements Terminal {\n constructor(private readonly config: Config) {}\n\n /**\n * What this DEVICE can pay with.\n *\n * Card and gift entry are always available — they are Square's own sheets and\n * need no wallet, no saved card and no capability beyond the SDK being linked.\n * The two wallets are asked, because both can be missing for reasons no\n * user-agent string would reveal: no card in Wallet, no Play Services, a\n * merchant id the app was not signed for.\n *\n * The tender is unused here. Native availability does not depend on the\n * amount, unlike the web SDK, where the total is bound into the wallet object\n * at construction — the interface carries it for the platform that needs it.\n */\n async offers(_tender: Tender): Promise<Method[]> {\n const out: Method[] = ['card', 'gift']\n if (this.config.appleMerchantId) {\n try {\n if (await SQIPApplePay.canUseApplePay()) out.push('apple_pay')\n } catch {\n // Not offerable on this device. Say nothing, show nothing.\n }\n }\n try {\n if (await SQIPGooglePay.canUseGooglePay()) out.push('google_pay')\n } catch {\n // Likewise.\n }\n return out.filter((m) => REACH.native.includes(m))\n }\n\n collect(method: Method, tender: Tender, detail?: Detail): Promise<Token> {\n if (!REACH.native.includes(method)) {\n return Promise.reject(new Error(`${method} is not a rail this SDK has`))\n }\n if (method === 'card' || method === 'gift') return this.sheet(method, detail)\n if (method === 'apple_pay') return this.apple(tender, detail)\n return this.google(tender, detail)\n }\n\n /**\n * Card and gift entry: one sheet, held open until the charge is known.\n *\n * The promise deliberately stays PENDING while the buyer retries. A declined\n * card returns `{ success: false }`, which keeps Square's sheet up with the\n * message shown and the card still entered — resolving or rejecting here would\n * settle a payment the buyer is still in the middle of making.\n */\n private sheet(method: 'card' | 'gift', detail?: Detail): Promise<Token> {\n return new Promise<Token>((resolve, reject) => {\n const onNonce = async (d: CardDetails): Promise<NonceSuccessResult> => {\n let t: Token\n try {\n t = token(method, d)\n } catch (e) {\n return { success: false, errorMessage: message(e) }\n }\n if (detail?.charge) {\n try {\n await detail.charge(t)\n } catch (e) {\n // Stay on the sheet so the buyer can correct the card in place.\n return { success: false, errorMessage: message(e) }\n }\n }\n // `onCardEntryComplete` fires once the sheet has actually closed, so the\n // host's next screen never renders behind a dismissing modal.\n return { success: true, onCardEntryComplete: () => resolve(t) }\n }\n const onCancel = () => reject(new Cancelled(method))\n if (method === 'gift') SQIPCardEntry.startGiftCardEntryFlow(onNonce, onCancel)\n // `false` collects no postal code: the billing address belongs to the\n // payer and the host's own checkout already owns it, so asking again\n // inside the sheet is a second answer to one question.\n else SQIPCardEntry.startCardEntryFlow(false, onNonce, onCancel)\n })\n }\n\n private apple(tender: Tender, detail?: Detail): Promise<Token> {\n return new Promise<Token>((resolve, reject) => {\n let settled: Token | null = null\n void SQIPApplePay.requestApplePayNonce(\n {\n price: tender.total.amount,\n summaryLabel: tender.label,\n countryCode: tender.country,\n currencyCode: tender.total.currency,\n },\n async (d: CardDetails): Promise<ApplePayNonceSuccessResult> => {\n let t: Token\n try {\n t = token('apple_pay', d)\n } catch (e) {\n return { state: ApplePayNonceSuccessState.Failure, errorMessage: message(e) }\n }\n if (detail?.charge) {\n try {\n await detail.charge(t)\n } catch (e) {\n // Apple's sheet shows its own failure state and then closes; there\n // is no retry-in-place here the way there is for card entry.\n return { state: ApplePayNonceSuccessState.Failure, errorMessage: message(e) }\n }\n }\n settled = t\n return { state: ApplePayNonceSuccessState.Succeeded }\n },\n (e: ErrorDetails) => reject(new Error(e.message)),\n // The completion callback is the ONLY place that knows how the sheet\n // ended, so it is the one that settles the promise.\n //\n // Annotated because `requestApplePayNonce` is overloaded and its\n // DEPRECATED signature takes a bare `() => void` here — TypeScript picks\n // that one and infers nothing, so the two arguments this needs would\n // silently be `any`.\n (state: ApplePayNonceSuccessState, errorMessage?: string) => {\n if (state === ApplePayNonceSuccessState.Succeeded && settled) resolve(settled)\n else if (state === ApplePayNonceSuccessState.Canceled) reject(new Cancelled('apple_pay'))\n else reject(new Error(errorMessage || 'Apple Pay could not be completed'))\n },\n )\n })\n }\n\n private google(tender: Tender, detail?: Detail): Promise<Token> {\n return new Promise<Token>((resolve, reject) => {\n void SQIPGooglePay.requestGooglePayNonce(\n {\n price: tender.total.amount,\n currencyCode: tender.total.currency,\n // FINAL, because this total is what the host will charge. Quoting it\n // as estimated invites Google to show a \"price may change\" sheet for a\n // price that will not.\n priceStatus: GooglePayPriceStatus.TotalPriceStatusFinal,\n },\n (d: CardDetails) => {\n let t: Token\n try {\n t = token('google_pay', d)\n } catch (e) {\n reject(e)\n return\n }\n // Google Pay's sheet has already closed by the time this fires, so a\n // charge failure here is the host's to show on its own screen.\n if (detail?.charge) {\n detail.charge(t).then(() => resolve(t), reject)\n return\n }\n resolve(t)\n },\n (e: ErrorDetails) => reject(new Error(e.message)),\n () => reject(new Cancelled('google_pay')),\n )\n })\n }\n\n /** Nothing is held open between payments — every native rail is a sheet per call. */\n async release(): Promise<void> {}\n}\n\nfunction message(e: unknown): string {\n return e instanceof Error ? e.message : 'payment failed'\n}\n\n/**\n * A terminal for this device.\n *\n * Configuration is GLOBAL to the SDK — `setSquareApplicationId`,\n * `initializeApplePay` and `initializeGooglePay` set process-wide state rather\n * than returning handles — so this applies it and returns a thin object over it.\n * Two terminals with different application ids cannot coexist; the last one\n * built wins. That is the SDK's shape, not a choice made here.\n */\nexport async function terminal(config: Config): Promise<Terminal> {\n if (!config.applicationId || !config.locationId) {\n throw new Error('Square is not configured for this build')\n }\n SQIPCore.setSquareApplicationId(config.applicationId)\n SQIPCardEntry.setIOSCardEntryTheme(\n appearance(config.palette ?? PALETTE.dark, config.theme ?? 'dark'),\n )\n if (config.appleMerchantId) SQIPApplePay.initializeApplePay(config.appleMerchantId)\n SQIPGooglePay.initializeGooglePay(\n config.locationId,\n (config.environment ?? 'production').toLowerCase() === 'sandbox'\n ? GooglePayEnvironment.EnvironmentTest\n : GooglePayEnvironment.EnvironmentProduction,\n )\n return new Native(config)\n}\n"]}