@usethrottle/payment-methods 0.1.2 → 0.1.4

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.
@@ -26,6 +26,7 @@ function Gr4vyAddCard({ payload, theme, onAdded, onCancel, onError }) {
26
26
  token: payload.embedToken,
27
27
  amount: payload.amount,
28
28
  currency: payload.currency,
29
+ country: payload.country ?? "US",
29
30
  merchantAccountId: payload.merchantAccountId,
30
31
  intent: "capture",
31
32
  paymentSource: "recurring",
@@ -92,4 +93,4 @@ export {
92
93
  Gr4vyAddCard_default as default,
93
94
  resolveComponent
94
95
  };
95
- //# sourceMappingURL=Gr4vyAddCard-735735DS.js.map
96
+ //# sourceMappingURL=Gr4vyAddCard-AAVXD6GM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/Gr4vyAddCard.tsx"],"sourcesContent":["/**\n * Gr4vyAddCard — lazy-loaded vault-only embed wrapper.\n *\n * THIS FILE MUST ONLY BE LOADED VIA React.lazy(() => import('./Gr4vyAddCard'))\n * from PaymentMethods.tsx. Never import it at the module top-level of any file\n * that is part of the server bundle — @gr4vy/embed-react touches `window` at\n * module evaluation time and will throw `ReferenceError: window is not defined`\n * in SSR contexts.\n */\nimport React, { useRef } from 'react';\nimport Gr4vyEmbedImport, { type EmbedInstance } from '@gr4vy/embed-react';\nimport type { EmbedPayload, PaymentMethodsTheme } from './types';\n\n/**\n * `@gr4vy/embed-react` is a CommonJS package (no `module`/`exports`/`type`\n * fields), so a consumer's bundler resolves `import Gr4vy from '@gr4vy/embed-react'`\n * differently depending on its CJS↔ESM interop: some hand back the component\n * directly, others hand back the module namespace `{ default: <component> }`.\n * Rendering the namespace object throws \"Element type is invalid … got: object\".\n * Unwrap `.default` until we reach an actual React element type (a function\n * component, or a forwardRef/memo object carrying `$$typeof`).\n */\nexport function resolveComponent(mod: unknown): React.ComponentType<Record<string, unknown>> {\n let x: any = mod;\n while (x && typeof x === 'object' && !x.$$typeof && x.default) x = x.default;\n return x as React.ComponentType<Record<string, unknown>>;\n}\nconst Gr4vyEmbed = resolveComponent(Gr4vyEmbedImport);\n\ninterface Gr4vyTransaction {\n id: string;\n status: string;\n paymentMethod?: { id?: string };\n}\n\nexport interface Gr4vyAddCardProps {\n payload: EmbedPayload;\n theme?: PaymentMethodsTheme;\n onAdded: (paymentMethodId?: string) => void;\n onCancel: () => void;\n onError: (err: unknown) => void;\n}\n\nexport function Gr4vyAddCard({ payload, theme, onAdded, onCancel, onError }: Gr4vyAddCardProps) {\n const embedRef = useRef<EmbedInstance>(null);\n\n const colors = theme\n ? {\n ...(theme.colorPrimary !== undefined ? { primary: theme.colorPrimary } : {}),\n ...(theme.colorText !== undefined ? { text: theme.colorText } : {}),\n ...(theme.colorBorder !== undefined ? { inputBorder: theme.colorBorder } : {}),\n }\n : {};\n const gr4vyTheme = Object.keys(colors).length ? { colors } : undefined;\n\n return (\n <div>\n <Gr4vyEmbed\n ref={embedRef}\n gr4vyId={payload.gr4vyId}\n environment={payload.environment}\n token={payload.embedToken}\n amount={payload.amount}\n currency={payload.currency}\n country={payload.country ?? 'US'}\n merchantAccountId={payload.merchantAccountId}\n intent=\"capture\"\n paymentSource=\"recurring\"\n store={true}\n display=\"addOnly\"\n {...(payload.buyerExternalIdentifier\n ? { buyerExternalIdentifier: payload.buyerExternalIdentifier }\n : {})}\n {...(gr4vyTheme !== undefined ? { theme: gr4vyTheme } : {})}\n onComplete={(txn: Gr4vyTransaction) => {\n onAdded(txn.paymentMethod?.id);\n }}\n onEvent={(eventName: string, data: unknown) => {\n if (eventName === 'transactionFailed') {\n onError(data);\n }\n }}\n />\n\n <button\n type=\"button\"\n onClick={() => {\n embedRef.current?.submit();\n }}\n style={{\n marginTop: '12px',\n padding: '8px 16px',\n backgroundColor: theme?.colorPrimary ?? '#1D56E8',\n color: '#fff',\n border: 'none',\n borderRadius: '8px',\n fontSize: '14px',\n fontWeight: 600,\n cursor: 'pointer',\n width: '100%',\n }}\n >\n Save card\n </button>\n\n <button\n type=\"button\"\n onClick={onCancel}\n style={{\n marginTop: '8px',\n padding: '8px 16px',\n backgroundColor: 'transparent',\n color: theme?.colorText ?? '#111827',\n border: `1px solid ${theme?.colorBorder ?? '#E5E7EB'}`,\n borderRadius: '8px',\n fontSize: '14px',\n cursor: 'pointer',\n width: '100%',\n }}\n >\n Cancel\n </button>\n </div>\n );\n}\n\nexport default Gr4vyAddCard;\n"],"mappings":";AASA,SAAgB,cAAc;AAC9B,OAAO,sBAA8C;AA8CjD,SACE,KADF;AAlCG,SAAS,iBAAiB,KAA4D;AAC3F,MAAI,IAAS;AACb,SAAO,KAAK,OAAO,MAAM,YAAY,CAAC,EAAE,YAAY,EAAE,QAAS,KAAI,EAAE;AACrE,SAAO;AACT;AACA,IAAM,aAAa,iBAAiB,gBAAgB;AAgB7C,SAAS,aAAa,EAAE,SAAS,OAAO,SAAS,UAAU,QAAQ,GAAsB;AAC9F,QAAM,WAAW,OAAsB,IAAI;AAE3C,QAAM,SAAS,QACX;AAAA,IACE,GAAI,MAAM,iBAAiB,SAAY,EAAE,SAAS,MAAM,aAAa,IAAI,CAAC;AAAA,IAC1E,GAAI,MAAM,cAAc,SAAY,EAAE,MAAM,MAAM,UAAU,IAAI,CAAC;AAAA,IACjE,GAAI,MAAM,gBAAgB,SAAY,EAAE,aAAa,MAAM,YAAY,IAAI,CAAC;AAAA,EAC9E,IACA,CAAC;AACL,QAAM,aAAa,OAAO,KAAK,MAAM,EAAE,SAAS,EAAE,OAAO,IAAI;AAE7D,SACE,qBAAC,SACC;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,SAAS,QAAQ;AAAA,QACjB,aAAa,QAAQ;AAAA,QACrB,OAAO,QAAQ;AAAA,QACf,QAAQ,QAAQ;AAAA,QAChB,UAAU,QAAQ;AAAA,QAClB,SAAS,QAAQ,WAAW;AAAA,QAC5B,mBAAmB,QAAQ;AAAA,QAC3B,QAAO;AAAA,QACP,eAAc;AAAA,QACd,OAAO;AAAA,QACP,SAAQ;AAAA,QACP,GAAI,QAAQ,0BACT,EAAE,yBAAyB,QAAQ,wBAAwB,IAC3D,CAAC;AAAA,QACJ,GAAI,eAAe,SAAY,EAAE,OAAO,WAAW,IAAI,CAAC;AAAA,QACzD,YAAY,CAAC,QAA0B;AACrC,kBAAQ,IAAI,eAAe,EAAE;AAAA,QAC/B;AAAA,QACA,SAAS,CAAC,WAAmB,SAAkB;AAC7C,cAAI,cAAc,qBAAqB;AACrC,oBAAQ,IAAI;AAAA,UACd;AAAA,QACF;AAAA;AAAA,IACF;AAAA,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS,MAAM;AACb,mBAAS,SAAS,OAAO;AAAA,QAC3B;AAAA,QACA,OAAO;AAAA,UACL,WAAW;AAAA,UACX,SAAS;AAAA,UACT,iBAAiB,OAAO,gBAAgB;AAAA,UACxC,OAAO;AAAA,UACP,QAAQ;AAAA,UACR,cAAc;AAAA,UACd,UAAU;AAAA,UACV,YAAY;AAAA,UACZ,QAAQ;AAAA,UACR,OAAO;AAAA,QACT;AAAA,QACD;AAAA;AAAA,IAED;AAAA,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS;AAAA,QACT,OAAO;AAAA,UACL,WAAW;AAAA,UACX,SAAS;AAAA,UACT,iBAAiB;AAAA,UACjB,OAAO,OAAO,aAAa;AAAA,UAC3B,QAAQ,aAAa,OAAO,eAAe,SAAS;AAAA,UACpD,cAAc;AAAA,UACd,UAAU;AAAA,UACV,QAAQ;AAAA,UACR,OAAO;AAAA,QACT;AAAA,QACD;AAAA;AAAA,IAED;AAAA,KACF;AAEJ;AAEA,IAAO,uBAAQ;","names":[]}
@@ -46,4 +46,4 @@ export {
46
46
  DEFAULT_BASE_URL,
47
47
  request
48
48
  };
49
- //# sourceMappingURL=chunk-RXWPYJQI.js.map
49
+ //# sourceMappingURL=chunk-XNNVEEVF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts","../src/types.ts","../src/request.ts"],"sourcesContent":["import { ThrottleError } from '@usethrottle/errors';\n\nexport class ThrottlePaymentMethodsError extends ThrottleError {\n constructor(args: { code: string; message: string; statusCode: number; details?: unknown }) {\n super(args);\n this.name = 'ThrottlePaymentMethodsError';\n }\n}\n\nexport { ThrottleError, isThrottleError } from '@usethrottle/errors';\n","export interface SavedCard {\n id: string;\n methodType: string;\n cardBrand: string | null;\n cardLastFour: string | null;\n cardExpMonth: number | null;\n cardExpYear: number | null;\n isDefault: boolean;\n}\n\nexport interface EmbedPayload {\n embedToken: string;\n checkoutSessionId: string;\n amount: number;\n currency: string;\n gr4vyId: string;\n merchantAccountId?: string;\n environment: 'sandbox' | 'production';\n /**\n * The buyer the embed JWT is pinned to. The add-only vault embed is a\n * recurring/store flow, so Gr4vy asserts the `<Gr4vyEmbed buyerExternalIdentifier>`\n * prop equals the JWT's value — the component MUST forward this or the embed\n * renders no card fields. Always present on the add-only embed payload.\n */\n buyerExternalIdentifier?: string;\n /** ISO country code the embed session was minted for. The Gr4vy embed requires\n * a `country` string at init (\"undefined must be a string ISO country code\").\n * Defaults to 'US' in the component when absent. */\n country?: string;\n hostedUrl?: string;\n embedUrl?: string;\n}\n\nexport interface MintedClientToken {\n token: string;\n expiresAt: string;\n}\n\nexport interface PaymentMethodsTheme {\n colorPrimary?: string;\n colorText?: string;\n colorBorder?: string;\n borderRadius?: string;\n}\n\nexport const DEFAULT_BASE_URL = 'https://api.usethrottle.dev';\n","import { ThrottlePaymentMethodsError } from './errors';\n\nexport async function request(input: {\n method: string;\n path: string;\n baseUrl: string;\n headers?: Record<string, string>;\n body?: unknown;\n}): Promise<any> {\n const res = await fetch(`${input.baseUrl}${input.path}`, {\n method: input.method,\n headers: {\n ...(input.body !== undefined ? { 'Content-Type': 'application/json' } : {}),\n ...(input.headers ?? {}),\n },\n ...(input.body !== undefined ? { body: JSON.stringify(input.body) } : {}),\n });\n const text = await res.text();\n let parsed: any = {};\n try {\n parsed = text ? JSON.parse(text) : {};\n } catch {\n // Non-JSON body (e.g. an HTML 502/503 gateway page). Leave parsed as {} so\n // the non-2xx branch below still throws a typed ThrottlePaymentMethodsError\n // (code 'request_failed') rather than leaking a raw SyntaxError.\n }\n if (!res.ok) {\n const e = parsed?.error ?? {};\n throw new ThrottlePaymentMethodsError({\n code: e.code ?? 'request_failed',\n message: e.message ?? `Request failed with ${res.status}`,\n statusCode: res.status,\n details: e.details,\n });\n }\n return parsed;\n}\n"],"mappings":";AAAA,SAAS,qBAAqB;AAS9B,SAAS,iBAAAA,gBAAe,uBAAuB;AAPxC,IAAM,8BAAN,cAA0C,cAAc;AAAA,EAC7D,YAAY,MAAgF;AAC1F,UAAM,IAAI;AACV,SAAK,OAAO;AAAA,EACd;AACF;;;ACsCO,IAAM,mBAAmB;;;AC3ChC,eAAsB,QAAQ,OAMb;AACf,QAAM,MAAM,MAAM,MAAM,GAAG,MAAM,OAAO,GAAG,MAAM,IAAI,IAAI;AAAA,IACvD,QAAQ,MAAM;AAAA,IACd,SAAS;AAAA,MACP,GAAI,MAAM,SAAS,SAAY,EAAE,gBAAgB,mBAAmB,IAAI,CAAC;AAAA,MACzE,GAAI,MAAM,WAAW,CAAC;AAAA,IACxB;AAAA,IACA,GAAI,MAAM,SAAS,SAAY,EAAE,MAAM,KAAK,UAAU,MAAM,IAAI,EAAE,IAAI,CAAC;AAAA,EACzE,CAAC;AACD,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,MAAI,SAAc,CAAC;AACnB,MAAI;AACF,aAAS,OAAO,KAAK,MAAM,IAAI,IAAI,CAAC;AAAA,EACtC,QAAQ;AAAA,EAIR;AACA,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,IAAI,QAAQ,SAAS,CAAC;AAC5B,UAAM,IAAI,4BAA4B;AAAA,MACpC,MAAM,EAAE,QAAQ;AAAA,MAChB,SAAS,EAAE,WAAW,uBAAuB,IAAI,MAAM;AAAA,MACvD,YAAY,IAAI;AAAA,MAChB,SAAS,EAAE;AAAA,IACb,CAAC;AAAA,EACH;AACA,SAAO;AACT;","names":["ThrottleError"]}
package/dist/index.cjs CHANGED
@@ -60,6 +60,7 @@ function Gr4vyAddCard({ payload, theme, onAdded, onCancel, onError }) {
60
60
  token: payload.embedToken,
61
61
  amount: payload.amount,
62
62
  currency: payload.currency,
63
+ country: payload.country ?? "US",
63
64
  merchantAccountId: payload.merchantAccountId,
64
65
  intent: "capture",
65
66
  paymentSource: "recurring",
@@ -321,6 +322,18 @@ function formatCard(card) {
321
322
  }
322
323
  return brandPart;
323
324
  }
325
+ function toReadableMessage(err) {
326
+ if (err instanceof Error && err.message) return err.message;
327
+ if (err && typeof err === "object") {
328
+ const o = err;
329
+ if (typeof o.message === "string" && o.message) return o.message;
330
+ if (o.code != null) {
331
+ return `Your card couldn't be saved (${String(o.code)}). Please double-check the details and try again.`;
332
+ }
333
+ }
334
+ if (typeof err === "string" && err) return err;
335
+ return "Your card couldn't be saved. Please double-check the details and try again.";
336
+ }
324
337
  function PaymentMethods({ clientToken, baseUrl, theme, onChange }) {
325
338
  const { cards, isLoading, error, setDefault, remove, addCard, refetch } = usePaymentMethods({
326
339
  clientToken,
@@ -364,8 +377,7 @@ function PaymentMethods({ clientToken, baseUrl, theme, onChange }) {
364
377
  setExternalError(null);
365
378
  setAddCardPayload(payload);
366
379
  } catch (err) {
367
- const message = err instanceof Error ? err.message : String(err);
368
- setExternalError(new Error(message));
380
+ setExternalError(new Error(toReadableMessage(err)));
369
381
  }
370
382
  };
371
383
  if (isLoading) {
@@ -478,9 +490,7 @@ function PaymentMethods({ clientToken, baseUrl, theme, onChange }) {
478
490
  },
479
491
  onCancel: () => setAddCardPayload(null),
480
492
  onError: (err) => {
481
- const message = err instanceof Error ? err.message : String(err);
482
- setExternalError(new Error(message));
483
- setAddCardPayload(null);
493
+ setExternalError(new Error(toReadableMessage(err)));
484
494
  }
485
495
  }
486
496
  )
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/Gr4vyAddCard.tsx","../src/index.tsx","../src/errors.ts","../src/types.ts","../src/request.ts","../src/client.ts","../src/usePaymentMethods.ts","../src/PaymentMethods.tsx"],"sourcesContent":["/**\n * Gr4vyAddCard — lazy-loaded vault-only embed wrapper.\n *\n * THIS FILE MUST ONLY BE LOADED VIA React.lazy(() => import('./Gr4vyAddCard'))\n * from PaymentMethods.tsx. Never import it at the module top-level of any file\n * that is part of the server bundle — @gr4vy/embed-react touches `window` at\n * module evaluation time and will throw `ReferenceError: window is not defined`\n * in SSR contexts.\n */\nimport React, { useRef } from 'react';\nimport Gr4vyEmbedImport, { type EmbedInstance } from '@gr4vy/embed-react';\nimport type { EmbedPayload, PaymentMethodsTheme } from './types';\n\n/**\n * `@gr4vy/embed-react` is a CommonJS package (no `module`/`exports`/`type`\n * fields), so a consumer's bundler resolves `import Gr4vy from '@gr4vy/embed-react'`\n * differently depending on its CJS↔ESM interop: some hand back the component\n * directly, others hand back the module namespace `{ default: <component> }`.\n * Rendering the namespace object throws \"Element type is invalid … got: object\".\n * Unwrap `.default` until we reach an actual React element type (a function\n * component, or a forwardRef/memo object carrying `$$typeof`).\n */\nexport function resolveComponent(mod: unknown): React.ComponentType<Record<string, unknown>> {\n let x: any = mod;\n while (x && typeof x === 'object' && !x.$$typeof && x.default) x = x.default;\n return x as React.ComponentType<Record<string, unknown>>;\n}\nconst Gr4vyEmbed = resolveComponent(Gr4vyEmbedImport);\n\ninterface Gr4vyTransaction {\n id: string;\n status: string;\n paymentMethod?: { id?: string };\n}\n\nexport interface Gr4vyAddCardProps {\n payload: EmbedPayload;\n theme?: PaymentMethodsTheme;\n onAdded: (paymentMethodId?: string) => void;\n onCancel: () => void;\n onError: (err: unknown) => void;\n}\n\nexport function Gr4vyAddCard({ payload, theme, onAdded, onCancel, onError }: Gr4vyAddCardProps) {\n const embedRef = useRef<EmbedInstance>(null);\n\n const colors = theme\n ? {\n ...(theme.colorPrimary !== undefined ? { primary: theme.colorPrimary } : {}),\n ...(theme.colorText !== undefined ? { text: theme.colorText } : {}),\n ...(theme.colorBorder !== undefined ? { inputBorder: theme.colorBorder } : {}),\n }\n : {};\n const gr4vyTheme = Object.keys(colors).length ? { colors } : undefined;\n\n return (\n <div>\n <Gr4vyEmbed\n ref={embedRef}\n gr4vyId={payload.gr4vyId}\n environment={payload.environment}\n token={payload.embedToken}\n amount={payload.amount}\n currency={payload.currency}\n merchantAccountId={payload.merchantAccountId}\n intent=\"capture\"\n paymentSource=\"recurring\"\n store={true}\n display=\"addOnly\"\n {...(payload.buyerExternalIdentifier\n ? { buyerExternalIdentifier: payload.buyerExternalIdentifier }\n : {})}\n {...(gr4vyTheme !== undefined ? { theme: gr4vyTheme } : {})}\n onComplete={(txn: Gr4vyTransaction) => {\n onAdded(txn.paymentMethod?.id);\n }}\n onEvent={(eventName: string, data: unknown) => {\n if (eventName === 'transactionFailed') {\n onError(data);\n }\n }}\n />\n\n <button\n type=\"button\"\n onClick={() => {\n embedRef.current?.submit();\n }}\n style={{\n marginTop: '12px',\n padding: '8px 16px',\n backgroundColor: theme?.colorPrimary ?? '#1D56E8',\n color: '#fff',\n border: 'none',\n borderRadius: '8px',\n fontSize: '14px',\n fontWeight: 600,\n cursor: 'pointer',\n width: '100%',\n }}\n >\n Save card\n </button>\n\n <button\n type=\"button\"\n onClick={onCancel}\n style={{\n marginTop: '8px',\n padding: '8px 16px',\n backgroundColor: 'transparent',\n color: theme?.colorText ?? '#111827',\n border: `1px solid ${theme?.colorBorder ?? '#E5E7EB'}`,\n borderRadius: '8px',\n fontSize: '14px',\n cursor: 'pointer',\n width: '100%',\n }}\n >\n Cancel\n </button>\n </div>\n );\n}\n\nexport default Gr4vyAddCard;\n","export { ThrottlePaymentMethodsError, ThrottleError, isThrottleError } from './errors';\nexport type { SavedCard, EmbedPayload, MintedClientToken, PaymentMethodsTheme } from './types';\nexport { DEFAULT_BASE_URL } from './types';\nexport { createPaymentMethods } from './client';\nexport type { PaymentMethodsClient } from './client';\nexport { usePaymentMethods } from './usePaymentMethods';\nexport type { UsePaymentMethodsOpts, UsePaymentMethodsResult } from './usePaymentMethods';\nexport { PaymentMethods } from './PaymentMethods';\nexport type { PaymentMethodsProps } from './PaymentMethods';\n","import { ThrottleError } from '@usethrottle/errors';\n\nexport class ThrottlePaymentMethodsError extends ThrottleError {\n constructor(args: { code: string; message: string; statusCode: number; details?: unknown }) {\n super(args);\n this.name = 'ThrottlePaymentMethodsError';\n }\n}\n\nexport { ThrottleError, isThrottleError } from '@usethrottle/errors';\n","export interface SavedCard {\n id: string;\n methodType: string;\n cardBrand: string | null;\n cardLastFour: string | null;\n cardExpMonth: number | null;\n cardExpYear: number | null;\n isDefault: boolean;\n}\n\nexport interface EmbedPayload {\n embedToken: string;\n checkoutSessionId: string;\n amount: number;\n currency: string;\n gr4vyId: string;\n merchantAccountId?: string;\n environment: 'sandbox' | 'production';\n /**\n * The buyer the embed JWT is pinned to. The add-only vault embed is a\n * recurring/store flow, so Gr4vy asserts the `<Gr4vyEmbed buyerExternalIdentifier>`\n * prop equals the JWT's value — the component MUST forward this or the embed\n * renders no card fields. Always present on the add-only embed payload.\n */\n buyerExternalIdentifier?: string;\n hostedUrl?: string;\n embedUrl?: string;\n}\n\nexport interface MintedClientToken {\n token: string;\n expiresAt: string;\n}\n\nexport interface PaymentMethodsTheme {\n colorPrimary?: string;\n colorText?: string;\n colorBorder?: string;\n borderRadius?: string;\n}\n\nexport const DEFAULT_BASE_URL = 'https://api.usethrottle.dev';\n","import { ThrottlePaymentMethodsError } from './errors';\n\nexport async function request(input: {\n method: string;\n path: string;\n baseUrl: string;\n headers?: Record<string, string>;\n body?: unknown;\n}): Promise<any> {\n const res = await fetch(`${input.baseUrl}${input.path}`, {\n method: input.method,\n headers: {\n ...(input.body !== undefined ? { 'Content-Type': 'application/json' } : {}),\n ...(input.headers ?? {}),\n },\n ...(input.body !== undefined ? { body: JSON.stringify(input.body) } : {}),\n });\n const text = await res.text();\n let parsed: any = {};\n try {\n parsed = text ? JSON.parse(text) : {};\n } catch {\n // Non-JSON body (e.g. an HTML 502/503 gateway page). Leave parsed as {} so\n // the non-2xx branch below still throws a typed ThrottlePaymentMethodsError\n // (code 'request_failed') rather than leaking a raw SyntaxError.\n }\n if (!res.ok) {\n const e = parsed?.error ?? {};\n throw new ThrottlePaymentMethodsError({\n code: e.code ?? 'request_failed',\n message: e.message ?? `Request failed with ${res.status}`,\n statusCode: res.status,\n details: e.details,\n });\n }\n return parsed;\n}\n","import { request } from './request';\nimport { DEFAULT_BASE_URL } from './types';\nimport type { SavedCard, EmbedPayload } from './types';\n\nexport interface PaymentMethodsClient {\n list(): Promise<SavedCard[]>;\n setDefault(id: string): Promise<SavedCard>;\n remove(id: string): Promise<{ id: string }>;\n startAddCard(): Promise<EmbedPayload>;\n}\n\nexport function createPaymentMethods(opts: {\n clientToken: string;\n baseUrl?: string;\n}): PaymentMethodsClient {\n const baseUrl = opts.baseUrl ?? DEFAULT_BASE_URL;\n const headers = { 'X-Throttle-PM-Token': opts.clientToken };\n\n return {\n async list() {\n const parsed = await request({ method: 'GET', path: '/api/v1/me/payment-methods', baseUrl, headers });\n return parsed.data as SavedCard[];\n },\n\n async setDefault(id: string) {\n const parsed = await request({\n method: 'PATCH',\n path: `/api/v1/me/payment-methods/${encodeURIComponent(id)}`,\n baseUrl,\n headers,\n body: { isDefault: true },\n });\n return parsed.data as SavedCard;\n },\n\n async remove(id: string) {\n const parsed = await request({\n method: 'DELETE',\n path: `/api/v1/me/payment-methods/${encodeURIComponent(id)}`,\n baseUrl,\n headers,\n });\n return parsed.data as { id: string };\n },\n\n async startAddCard() {\n const parsed = await request({\n method: 'POST',\n path: '/api/v1/me/payment-methods/embed-token',\n baseUrl,\n headers,\n });\n return parsed.data as EmbedPayload;\n },\n };\n}\n","import { useEffect, useMemo, useRef, useState } from 'react';\nimport { createPaymentMethods } from './client';\nimport { ThrottlePaymentMethodsError } from './errors';\nimport type { EmbedPayload, SavedCard } from './types';\n\nexport interface UsePaymentMethodsOpts {\n clientToken: string;\n baseUrl?: string;\n}\n\nexport interface UsePaymentMethodsResult {\n cards: SavedCard[];\n isLoading: boolean;\n error: ThrottlePaymentMethodsError | null;\n setDefault(id: string): Promise<void>;\n remove(id: string): Promise<void>;\n addCard(): Promise<EmbedPayload>;\n refetch(): Promise<void>;\n}\n\nfunction toPaymentMethodsError(err: unknown): ThrottlePaymentMethodsError {\n if (err instanceof ThrottlePaymentMethodsError) return err;\n const message = err instanceof Error ? err.message : String(err);\n return new ThrottlePaymentMethodsError({ code: 'unknown_error', message, statusCode: 0 });\n}\n\nexport function usePaymentMethods(opts: UsePaymentMethodsOpts): UsePaymentMethodsResult {\n const { clientToken, baseUrl } = opts;\n\n const client = useMemo(\n () => createPaymentMethods({ clientToken, baseUrl }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [clientToken, baseUrl],\n );\n\n const [cards, setCards] = useState<SavedCard[]>([]);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<ThrottlePaymentMethodsError | null>(null);\n const genRef = useRef(0);\n\n const refetch = useMemo(\n () => async () => {\n const myGen = genRef.current;\n try {\n const data = await client.list();\n if (genRef.current !== myGen) return;\n setCards(data);\n setError(null);\n } catch (err) {\n if (genRef.current !== myGen) return;\n setError(toPaymentMethodsError(err));\n }\n },\n [client],\n );\n\n useEffect(() => {\n const myGen = ++genRef.current;\n\n (async () => {\n setIsLoading(true);\n try {\n const data = await client.list();\n if (genRef.current !== myGen) return;\n setCards(data);\n setError(null);\n } catch (err) {\n if (genRef.current !== myGen) return;\n setError(toPaymentMethodsError(err));\n } finally {\n if (genRef.current === myGen) {\n setIsLoading(false);\n }\n }\n })();\n }, [client]);\n\n const setDefault = async (id: string): Promise<void> => {\n try {\n await client.setDefault(id);\n await refetch();\n } catch (err) {\n const pmErr = toPaymentMethodsError(err);\n setError(pmErr);\n throw pmErr;\n }\n };\n\n const remove = async (id: string): Promise<void> => {\n try {\n await client.remove(id);\n await refetch();\n } catch (err) {\n const pmErr = toPaymentMethodsError(err);\n setError(pmErr);\n throw pmErr;\n }\n };\n\n const addCard = async (): Promise<EmbedPayload> => {\n return client.startAddCard();\n };\n\n return { cards, isLoading, error, setDefault, remove, addCard, refetch };\n}\n","import React, { Suspense, useEffect, useRef, useState } from 'react';\nimport { usePaymentMethods } from './usePaymentMethods';\nimport type { EmbedPayload, SavedCard, PaymentMethodsTheme } from './types';\n\n// Lazy import — keeps @gr4vy/embed-react out of the eager bundle (SSR-safe).\n// Do NOT hoist this to a top-level import; React.lazy is the only safe path.\nconst LazyGr4vyAddCard = React.lazy(() =>\n import('./Gr4vyAddCard').then((m) => ({ default: m.Gr4vyAddCard })),\n);\n\nexport interface PaymentMethodsProps {\n clientToken: string;\n baseUrl?: string;\n theme?: PaymentMethodsTheme;\n onChange?: (cards: SavedCard[]) => void;\n}\n\nfunction formatCard(card: SavedCard): string {\n const brand = card.cardBrand ? card.cardBrand.toUpperCase() : 'Card';\n const last4 = card.cardLastFour ? `•••• ${card.cardLastFour}` : '••••';\n const brandPart = `${brand} ${last4}`;\n\n if (card.cardExpMonth != null && card.cardExpYear != null) {\n const mm = String(card.cardExpMonth).padStart(2, '0');\n const yy = String(card.cardExpYear).slice(-2);\n return `${brandPart} · ${mm}/${yy}`;\n }\n return brandPart;\n}\n\nexport function PaymentMethods({ clientToken, baseUrl, theme, onChange }: PaymentMethodsProps) {\n const { cards, isLoading, error, setDefault, remove, addCard, refetch } = usePaymentMethods({\n clientToken,\n baseUrl,\n });\n\n const [busyId, setBusyId] = useState<string | null>(null);\n const [addCardPayload, setAddCardPayload] = useState<EmbedPayload | null>(null);\n const [externalError, setExternalError] = useState<Error | null>(null);\n\n const onChangeRef = useRef(onChange);\n useEffect(() => { onChangeRef.current = onChange; });\n useEffect(() => { if (!isLoading) onChangeRef.current?.(cards); }, [cards, isLoading]);\n\n const primary = theme?.colorPrimary ?? '#1D56E8';\n const colorText = theme?.colorText ?? '#111827';\n const colorBorder = theme?.colorBorder ?? '#E5E7EB';\n const borderRadius = theme?.borderRadius ?? '8px';\n\n const handleSetDefault = async (id: string) => {\n setBusyId(id);\n try {\n await setDefault(id);\n } catch {\n // error is already set in the hook\n } finally {\n setBusyId(null);\n }\n };\n\n const handleRemove = async (id: string) => {\n setBusyId(id);\n try {\n await remove(id);\n } catch {\n // error is already set in the hook\n } finally {\n setBusyId(null);\n }\n };\n\n const handleAddCard = async () => {\n try {\n const payload = await addCard();\n setExternalError(null);\n setAddCardPayload(payload);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n setExternalError(new Error(message));\n }\n };\n\n if (isLoading) {\n return (\n <div role=\"status\" aria-label=\"Loading payment methods\" style={{ color: colorText }}>\n Loading…\n </div>\n );\n }\n\n const displayError = externalError ?? error;\n\n return (\n <div style={{ color: colorText, fontFamily: 'inherit' }}>\n {displayError && (\n <div\n role=\"alert\"\n style={{\n color: '#DC2626',\n marginBottom: '12px',\n padding: '8px 12px',\n border: `1px solid #FCA5A5`,\n borderRadius,\n fontSize: '14px',\n }}\n >\n {displayError.message}\n </div>\n )}\n\n <ul style={{ listStyle: 'none', margin: 0, padding: 0 }}>\n {cards.map((card) => {\n const isBusy = busyId === card.id;\n return (\n <li\n key={card.id}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '12px',\n padding: '12px',\n border: `1px solid ${colorBorder}`,\n borderRadius,\n marginBottom: '8px',\n }}\n >\n <span style={{ flex: 1, fontSize: '14px' }}>{formatCard(card)}</span>\n\n {card.isDefault ? (\n <span\n style={{\n backgroundColor: primary,\n color: '#fff',\n fontSize: '12px',\n fontWeight: 600,\n padding: '2px 8px',\n borderRadius: '999px',\n }}\n >\n Default\n </span>\n ) : (\n <>\n <button\n type=\"button\"\n disabled={isBusy}\n onClick={() => handleSetDefault(card.id)}\n style={{\n fontSize: '13px',\n padding: '4px 10px',\n border: `1px solid ${colorBorder}`,\n borderRadius,\n background: 'transparent',\n cursor: isBusy ? 'not-allowed' : 'pointer',\n opacity: isBusy ? 0.5 : 1,\n }}\n >\n Make default\n </button>\n <button\n type=\"button\"\n disabled={isBusy}\n onClick={() => handleRemove(card.id)}\n style={{\n fontSize: '13px',\n padding: '4px 10px',\n border: `1px solid #FCA5A5`,\n borderRadius,\n background: 'transparent',\n color: '#DC2626',\n cursor: isBusy ? 'not-allowed' : 'pointer',\n opacity: isBusy ? 0.5 : 1,\n }}\n >\n Remove\n </button>\n </>\n )}\n </li>\n );\n })}\n </ul>\n\n {addCardPayload ? (\n <Suspense\n fallback={\n <div role=\"status\" style={{ color: colorText, marginTop: '12px' }}>\n Loading…\n </div>\n }\n >\n <LazyGr4vyAddCard\n payload={addCardPayload}\n theme={theme}\n onAdded={async (paymentMethodId) => {\n void paymentMethodId;\n await refetch();\n setExternalError(null);\n setAddCardPayload(null);\n }}\n onCancel={() => setAddCardPayload(null)}\n onError={(err) => {\n const message = err instanceof Error ? (err as Error).message : String(err);\n setExternalError(new Error(message));\n setAddCardPayload(null);\n }}\n />\n </Suspense>\n ) : (\n <button\n type=\"button\"\n onClick={handleAddCard}\n style={{\n marginTop: '12px',\n padding: '8px 16px',\n backgroundColor: primary,\n color: '#fff',\n border: 'none',\n borderRadius,\n fontSize: '14px',\n fontWeight: 600,\n cursor: 'pointer',\n }}\n >\n + Add card\n </button>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":["import_react","Gr4vyEmbedImport","import_errors","import_react","import_jsx_runtime","React"]}
1
+ {"version":3,"sources":["../src/Gr4vyAddCard.tsx","../src/index.tsx","../src/errors.ts","../src/types.ts","../src/request.ts","../src/client.ts","../src/usePaymentMethods.ts","../src/PaymentMethods.tsx"],"sourcesContent":["/**\n * Gr4vyAddCard — lazy-loaded vault-only embed wrapper.\n *\n * THIS FILE MUST ONLY BE LOADED VIA React.lazy(() => import('./Gr4vyAddCard'))\n * from PaymentMethods.tsx. Never import it at the module top-level of any file\n * that is part of the server bundle — @gr4vy/embed-react touches `window` at\n * module evaluation time and will throw `ReferenceError: window is not defined`\n * in SSR contexts.\n */\nimport React, { useRef } from 'react';\nimport Gr4vyEmbedImport, { type EmbedInstance } from '@gr4vy/embed-react';\nimport type { EmbedPayload, PaymentMethodsTheme } from './types';\n\n/**\n * `@gr4vy/embed-react` is a CommonJS package (no `module`/`exports`/`type`\n * fields), so a consumer's bundler resolves `import Gr4vy from '@gr4vy/embed-react'`\n * differently depending on its CJS↔ESM interop: some hand back the component\n * directly, others hand back the module namespace `{ default: <component> }`.\n * Rendering the namespace object throws \"Element type is invalid … got: object\".\n * Unwrap `.default` until we reach an actual React element type (a function\n * component, or a forwardRef/memo object carrying `$$typeof`).\n */\nexport function resolveComponent(mod: unknown): React.ComponentType<Record<string, unknown>> {\n let x: any = mod;\n while (x && typeof x === 'object' && !x.$$typeof && x.default) x = x.default;\n return x as React.ComponentType<Record<string, unknown>>;\n}\nconst Gr4vyEmbed = resolveComponent(Gr4vyEmbedImport);\n\ninterface Gr4vyTransaction {\n id: string;\n status: string;\n paymentMethod?: { id?: string };\n}\n\nexport interface Gr4vyAddCardProps {\n payload: EmbedPayload;\n theme?: PaymentMethodsTheme;\n onAdded: (paymentMethodId?: string) => void;\n onCancel: () => void;\n onError: (err: unknown) => void;\n}\n\nexport function Gr4vyAddCard({ payload, theme, onAdded, onCancel, onError }: Gr4vyAddCardProps) {\n const embedRef = useRef<EmbedInstance>(null);\n\n const colors = theme\n ? {\n ...(theme.colorPrimary !== undefined ? { primary: theme.colorPrimary } : {}),\n ...(theme.colorText !== undefined ? { text: theme.colorText } : {}),\n ...(theme.colorBorder !== undefined ? { inputBorder: theme.colorBorder } : {}),\n }\n : {};\n const gr4vyTheme = Object.keys(colors).length ? { colors } : undefined;\n\n return (\n <div>\n <Gr4vyEmbed\n ref={embedRef}\n gr4vyId={payload.gr4vyId}\n environment={payload.environment}\n token={payload.embedToken}\n amount={payload.amount}\n currency={payload.currency}\n country={payload.country ?? 'US'}\n merchantAccountId={payload.merchantAccountId}\n intent=\"capture\"\n paymentSource=\"recurring\"\n store={true}\n display=\"addOnly\"\n {...(payload.buyerExternalIdentifier\n ? { buyerExternalIdentifier: payload.buyerExternalIdentifier }\n : {})}\n {...(gr4vyTheme !== undefined ? { theme: gr4vyTheme } : {})}\n onComplete={(txn: Gr4vyTransaction) => {\n onAdded(txn.paymentMethod?.id);\n }}\n onEvent={(eventName: string, data: unknown) => {\n if (eventName === 'transactionFailed') {\n onError(data);\n }\n }}\n />\n\n <button\n type=\"button\"\n onClick={() => {\n embedRef.current?.submit();\n }}\n style={{\n marginTop: '12px',\n padding: '8px 16px',\n backgroundColor: theme?.colorPrimary ?? '#1D56E8',\n color: '#fff',\n border: 'none',\n borderRadius: '8px',\n fontSize: '14px',\n fontWeight: 600,\n cursor: 'pointer',\n width: '100%',\n }}\n >\n Save card\n </button>\n\n <button\n type=\"button\"\n onClick={onCancel}\n style={{\n marginTop: '8px',\n padding: '8px 16px',\n backgroundColor: 'transparent',\n color: theme?.colorText ?? '#111827',\n border: `1px solid ${theme?.colorBorder ?? '#E5E7EB'}`,\n borderRadius: '8px',\n fontSize: '14px',\n cursor: 'pointer',\n width: '100%',\n }}\n >\n Cancel\n </button>\n </div>\n );\n}\n\nexport default Gr4vyAddCard;\n","export { ThrottlePaymentMethodsError, ThrottleError, isThrottleError } from './errors';\nexport type { SavedCard, EmbedPayload, MintedClientToken, PaymentMethodsTheme } from './types';\nexport { DEFAULT_BASE_URL } from './types';\nexport { createPaymentMethods } from './client';\nexport type { PaymentMethodsClient } from './client';\nexport { usePaymentMethods } from './usePaymentMethods';\nexport type { UsePaymentMethodsOpts, UsePaymentMethodsResult } from './usePaymentMethods';\nexport { PaymentMethods } from './PaymentMethods';\nexport type { PaymentMethodsProps } from './PaymentMethods';\n","import { ThrottleError } from '@usethrottle/errors';\n\nexport class ThrottlePaymentMethodsError extends ThrottleError {\n constructor(args: { code: string; message: string; statusCode: number; details?: unknown }) {\n super(args);\n this.name = 'ThrottlePaymentMethodsError';\n }\n}\n\nexport { ThrottleError, isThrottleError } from '@usethrottle/errors';\n","export interface SavedCard {\n id: string;\n methodType: string;\n cardBrand: string | null;\n cardLastFour: string | null;\n cardExpMonth: number | null;\n cardExpYear: number | null;\n isDefault: boolean;\n}\n\nexport interface EmbedPayload {\n embedToken: string;\n checkoutSessionId: string;\n amount: number;\n currency: string;\n gr4vyId: string;\n merchantAccountId?: string;\n environment: 'sandbox' | 'production';\n /**\n * The buyer the embed JWT is pinned to. The add-only vault embed is a\n * recurring/store flow, so Gr4vy asserts the `<Gr4vyEmbed buyerExternalIdentifier>`\n * prop equals the JWT's value — the component MUST forward this or the embed\n * renders no card fields. Always present on the add-only embed payload.\n */\n buyerExternalIdentifier?: string;\n /** ISO country code the embed session was minted for. The Gr4vy embed requires\n * a `country` string at init (\"undefined must be a string ISO country code\").\n * Defaults to 'US' in the component when absent. */\n country?: string;\n hostedUrl?: string;\n embedUrl?: string;\n}\n\nexport interface MintedClientToken {\n token: string;\n expiresAt: string;\n}\n\nexport interface PaymentMethodsTheme {\n colorPrimary?: string;\n colorText?: string;\n colorBorder?: string;\n borderRadius?: string;\n}\n\nexport const DEFAULT_BASE_URL = 'https://api.usethrottle.dev';\n","import { ThrottlePaymentMethodsError } from './errors';\n\nexport async function request(input: {\n method: string;\n path: string;\n baseUrl: string;\n headers?: Record<string, string>;\n body?: unknown;\n}): Promise<any> {\n const res = await fetch(`${input.baseUrl}${input.path}`, {\n method: input.method,\n headers: {\n ...(input.body !== undefined ? { 'Content-Type': 'application/json' } : {}),\n ...(input.headers ?? {}),\n },\n ...(input.body !== undefined ? { body: JSON.stringify(input.body) } : {}),\n });\n const text = await res.text();\n let parsed: any = {};\n try {\n parsed = text ? JSON.parse(text) : {};\n } catch {\n // Non-JSON body (e.g. an HTML 502/503 gateway page). Leave parsed as {} so\n // the non-2xx branch below still throws a typed ThrottlePaymentMethodsError\n // (code 'request_failed') rather than leaking a raw SyntaxError.\n }\n if (!res.ok) {\n const e = parsed?.error ?? {};\n throw new ThrottlePaymentMethodsError({\n code: e.code ?? 'request_failed',\n message: e.message ?? `Request failed with ${res.status}`,\n statusCode: res.status,\n details: e.details,\n });\n }\n return parsed;\n}\n","import { request } from './request';\nimport { DEFAULT_BASE_URL } from './types';\nimport type { SavedCard, EmbedPayload } from './types';\n\nexport interface PaymentMethodsClient {\n list(): Promise<SavedCard[]>;\n setDefault(id: string): Promise<SavedCard>;\n remove(id: string): Promise<{ id: string }>;\n startAddCard(): Promise<EmbedPayload>;\n}\n\nexport function createPaymentMethods(opts: {\n clientToken: string;\n baseUrl?: string;\n}): PaymentMethodsClient {\n const baseUrl = opts.baseUrl ?? DEFAULT_BASE_URL;\n const headers = { 'X-Throttle-PM-Token': opts.clientToken };\n\n return {\n async list() {\n const parsed = await request({ method: 'GET', path: '/api/v1/me/payment-methods', baseUrl, headers });\n return parsed.data as SavedCard[];\n },\n\n async setDefault(id: string) {\n const parsed = await request({\n method: 'PATCH',\n path: `/api/v1/me/payment-methods/${encodeURIComponent(id)}`,\n baseUrl,\n headers,\n body: { isDefault: true },\n });\n return parsed.data as SavedCard;\n },\n\n async remove(id: string) {\n const parsed = await request({\n method: 'DELETE',\n path: `/api/v1/me/payment-methods/${encodeURIComponent(id)}`,\n baseUrl,\n headers,\n });\n return parsed.data as { id: string };\n },\n\n async startAddCard() {\n const parsed = await request({\n method: 'POST',\n path: '/api/v1/me/payment-methods/embed-token',\n baseUrl,\n headers,\n });\n return parsed.data as EmbedPayload;\n },\n };\n}\n","import { useEffect, useMemo, useRef, useState } from 'react';\nimport { createPaymentMethods } from './client';\nimport { ThrottlePaymentMethodsError } from './errors';\nimport type { EmbedPayload, SavedCard } from './types';\n\nexport interface UsePaymentMethodsOpts {\n clientToken: string;\n baseUrl?: string;\n}\n\nexport interface UsePaymentMethodsResult {\n cards: SavedCard[];\n isLoading: boolean;\n error: ThrottlePaymentMethodsError | null;\n setDefault(id: string): Promise<void>;\n remove(id: string): Promise<void>;\n addCard(): Promise<EmbedPayload>;\n refetch(): Promise<void>;\n}\n\nfunction toPaymentMethodsError(err: unknown): ThrottlePaymentMethodsError {\n if (err instanceof ThrottlePaymentMethodsError) return err;\n const message = err instanceof Error ? err.message : String(err);\n return new ThrottlePaymentMethodsError({ code: 'unknown_error', message, statusCode: 0 });\n}\n\nexport function usePaymentMethods(opts: UsePaymentMethodsOpts): UsePaymentMethodsResult {\n const { clientToken, baseUrl } = opts;\n\n const client = useMemo(\n () => createPaymentMethods({ clientToken, baseUrl }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [clientToken, baseUrl],\n );\n\n const [cards, setCards] = useState<SavedCard[]>([]);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<ThrottlePaymentMethodsError | null>(null);\n const genRef = useRef(0);\n\n const refetch = useMemo(\n () => async () => {\n const myGen = genRef.current;\n try {\n const data = await client.list();\n if (genRef.current !== myGen) return;\n setCards(data);\n setError(null);\n } catch (err) {\n if (genRef.current !== myGen) return;\n setError(toPaymentMethodsError(err));\n }\n },\n [client],\n );\n\n useEffect(() => {\n const myGen = ++genRef.current;\n\n (async () => {\n setIsLoading(true);\n try {\n const data = await client.list();\n if (genRef.current !== myGen) return;\n setCards(data);\n setError(null);\n } catch (err) {\n if (genRef.current !== myGen) return;\n setError(toPaymentMethodsError(err));\n } finally {\n if (genRef.current === myGen) {\n setIsLoading(false);\n }\n }\n })();\n }, [client]);\n\n const setDefault = async (id: string): Promise<void> => {\n try {\n await client.setDefault(id);\n await refetch();\n } catch (err) {\n const pmErr = toPaymentMethodsError(err);\n setError(pmErr);\n throw pmErr;\n }\n };\n\n const remove = async (id: string): Promise<void> => {\n try {\n await client.remove(id);\n await refetch();\n } catch (err) {\n const pmErr = toPaymentMethodsError(err);\n setError(pmErr);\n throw pmErr;\n }\n };\n\n const addCard = async (): Promise<EmbedPayload> => {\n return client.startAddCard();\n };\n\n return { cards, isLoading, error, setDefault, remove, addCard, refetch };\n}\n","import React, { Suspense, useEffect, useRef, useState } from 'react';\nimport { usePaymentMethods } from './usePaymentMethods';\nimport type { EmbedPayload, SavedCard, PaymentMethodsTheme } from './types';\n\n// Lazy import — keeps @gr4vy/embed-react out of the eager bundle (SSR-safe).\n// Do NOT hoist this to a top-level import; React.lazy is the only safe path.\nconst LazyGr4vyAddCard = React.lazy(() =>\n import('./Gr4vyAddCard').then((m) => ({ default: m.Gr4vyAddCard })),\n);\n\nexport interface PaymentMethodsProps {\n clientToken: string;\n baseUrl?: string;\n theme?: PaymentMethodsTheme;\n onChange?: (cards: SavedCard[]) => void;\n}\n\nfunction formatCard(card: SavedCard): string {\n const brand = card.cardBrand ? card.cardBrand.toUpperCase() : 'Card';\n const last4 = card.cardLastFour ? `•••• ${card.cardLastFour}` : '••••';\n const brandPart = `${brand} ${last4}`;\n\n if (card.cardExpMonth != null && card.cardExpYear != null) {\n const mm = String(card.cardExpMonth).padStart(2, '0');\n const yy = String(card.cardExpYear).slice(-2);\n return `${brandPart} · ${mm}/${yy}`;\n }\n return brandPart;\n}\n\n/**\n * Extract a human-readable message from anything thrown/emitted. The Gr4vy embed\n * emits a plain object on `transactionFailed` (e.g. { code, message }), not an\n * Error — `String(obj)` would render \"[object Object]\", so pull `.message`/`.code`.\n */\nexport function toReadableMessage(err: unknown): string {\n if (err instanceof Error && err.message) return err.message;\n if (err && typeof err === 'object') {\n const o = err as Record<string, unknown>;\n if (typeof o.message === 'string' && o.message) return o.message;\n if (o.code != null) {\n return `Your card couldn't be saved (${String(o.code)}). Please double-check the details and try again.`;\n }\n }\n if (typeof err === 'string' && err) return err;\n return \"Your card couldn't be saved. Please double-check the details and try again.\";\n}\n\nexport function PaymentMethods({ clientToken, baseUrl, theme, onChange }: PaymentMethodsProps) {\n const { cards, isLoading, error, setDefault, remove, addCard, refetch } = usePaymentMethods({\n clientToken,\n baseUrl,\n });\n\n const [busyId, setBusyId] = useState<string | null>(null);\n const [addCardPayload, setAddCardPayload] = useState<EmbedPayload | null>(null);\n const [externalError, setExternalError] = useState<Error | null>(null);\n\n const onChangeRef = useRef(onChange);\n useEffect(() => { onChangeRef.current = onChange; });\n useEffect(() => { if (!isLoading) onChangeRef.current?.(cards); }, [cards, isLoading]);\n\n const primary = theme?.colorPrimary ?? '#1D56E8';\n const colorText = theme?.colorText ?? '#111827';\n const colorBorder = theme?.colorBorder ?? '#E5E7EB';\n const borderRadius = theme?.borderRadius ?? '8px';\n\n const handleSetDefault = async (id: string) => {\n setBusyId(id);\n try {\n await setDefault(id);\n } catch {\n // error is already set in the hook\n } finally {\n setBusyId(null);\n }\n };\n\n const handleRemove = async (id: string) => {\n setBusyId(id);\n try {\n await remove(id);\n } catch {\n // error is already set in the hook\n } finally {\n setBusyId(null);\n }\n };\n\n const handleAddCard = async () => {\n try {\n const payload = await addCard();\n setExternalError(null);\n setAddCardPayload(payload);\n } catch (err) {\n setExternalError(new Error(toReadableMessage(err)));\n }\n };\n\n if (isLoading) {\n return (\n <div role=\"status\" aria-label=\"Loading payment methods\" style={{ color: colorText }}>\n Loading…\n </div>\n );\n }\n\n const displayError = externalError ?? error;\n\n return (\n <div style={{ color: colorText, fontFamily: 'inherit' }}>\n {displayError && (\n <div\n role=\"alert\"\n style={{\n color: '#DC2626',\n marginBottom: '12px',\n padding: '8px 12px',\n border: `1px solid #FCA5A5`,\n borderRadius,\n fontSize: '14px',\n }}\n >\n {displayError.message}\n </div>\n )}\n\n <ul style={{ listStyle: 'none', margin: 0, padding: 0 }}>\n {cards.map((card) => {\n const isBusy = busyId === card.id;\n return (\n <li\n key={card.id}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '12px',\n padding: '12px',\n border: `1px solid ${colorBorder}`,\n borderRadius,\n marginBottom: '8px',\n }}\n >\n <span style={{ flex: 1, fontSize: '14px' }}>{formatCard(card)}</span>\n\n {card.isDefault ? (\n <span\n style={{\n backgroundColor: primary,\n color: '#fff',\n fontSize: '12px',\n fontWeight: 600,\n padding: '2px 8px',\n borderRadius: '999px',\n }}\n >\n Default\n </span>\n ) : (\n <>\n <button\n type=\"button\"\n disabled={isBusy}\n onClick={() => handleSetDefault(card.id)}\n style={{\n fontSize: '13px',\n padding: '4px 10px',\n border: `1px solid ${colorBorder}`,\n borderRadius,\n background: 'transparent',\n cursor: isBusy ? 'not-allowed' : 'pointer',\n opacity: isBusy ? 0.5 : 1,\n }}\n >\n Make default\n </button>\n <button\n type=\"button\"\n disabled={isBusy}\n onClick={() => handleRemove(card.id)}\n style={{\n fontSize: '13px',\n padding: '4px 10px',\n border: `1px solid #FCA5A5`,\n borderRadius,\n background: 'transparent',\n color: '#DC2626',\n cursor: isBusy ? 'not-allowed' : 'pointer',\n opacity: isBusy ? 0.5 : 1,\n }}\n >\n Remove\n </button>\n </>\n )}\n </li>\n );\n })}\n </ul>\n\n {addCardPayload ? (\n <Suspense\n fallback={\n <div role=\"status\" style={{ color: colorText, marginTop: '12px' }}>\n Loading…\n </div>\n }\n >\n <LazyGr4vyAddCard\n payload={addCardPayload}\n theme={theme}\n onAdded={async (paymentMethodId) => {\n void paymentMethodId;\n await refetch();\n setExternalError(null);\n setAddCardPayload(null);\n }}\n onCancel={() => setAddCardPayload(null)}\n onError={(err) => {\n // Show the real reason and KEEP the embed open so the buyer can\n // fix the card and retry without re-opening the form.\n setExternalError(new Error(toReadableMessage(err)));\n }}\n />\n </Suspense>\n ) : (\n <button\n type=\"button\"\n onClick={handleAddCard}\n style={{\n marginTop: '12px',\n padding: '8px 16px',\n backgroundColor: primary,\n color: '#fff',\n border: 'none',\n borderRadius,\n fontSize: '14px',\n fontWeight: 600,\n cursor: 'pointer',\n }}\n >\n + Add card\n </button>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":["import_react","Gr4vyEmbedImport","import_errors","import_react","import_jsx_runtime","React"]}
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { ThrottleError } from '@usethrottle/errors';
2
2
  export { ThrottleError, isThrottleError } from '@usethrottle/errors';
3
- import { S as SavedCard, E as EmbedPayload, P as PaymentMethodsTheme } from './types-Cs3nqt_3.cjs';
4
- export { D as DEFAULT_BASE_URL, M as MintedClientToken } from './types-Cs3nqt_3.cjs';
3
+ import { S as SavedCard, E as EmbedPayload, P as PaymentMethodsTheme } from './types-D610pEVD.cjs';
4
+ export { D as DEFAULT_BASE_URL, M as MintedClientToken } from './types-D610pEVD.cjs';
5
5
  import * as react_jsx_runtime from 'react/jsx-runtime';
6
6
 
7
7
  declare class ThrottlePaymentMethodsError extends ThrottleError {
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { ThrottleError } from '@usethrottle/errors';
2
2
  export { ThrottleError, isThrottleError } from '@usethrottle/errors';
3
- import { S as SavedCard, E as EmbedPayload, P as PaymentMethodsTheme } from './types-Cs3nqt_3.js';
4
- export { D as DEFAULT_BASE_URL, M as MintedClientToken } from './types-Cs3nqt_3.js';
3
+ import { S as SavedCard, E as EmbedPayload, P as PaymentMethodsTheme } from './types-D610pEVD.js';
4
+ export { D as DEFAULT_BASE_URL, M as MintedClientToken } from './types-D610pEVD.js';
5
5
  import * as react_jsx_runtime from 'react/jsx-runtime';
6
6
 
7
7
  declare class ThrottlePaymentMethodsError extends ThrottleError {
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  ThrottlePaymentMethodsError,
5
5
  isThrottleError,
6
6
  request
7
- } from "./chunk-RXWPYJQI.js";
7
+ } from "./chunk-XNNVEEVF.js";
8
8
 
9
9
  // src/client.ts
10
10
  function createPaymentMethods(opts) {
@@ -128,7 +128,7 @@ function usePaymentMethods(opts) {
128
128
  import React, { Suspense, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
129
129
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
130
130
  var LazyGr4vyAddCard = React.lazy(
131
- () => import("./Gr4vyAddCard-735735DS.js").then((m) => ({ default: m.Gr4vyAddCard }))
131
+ () => import("./Gr4vyAddCard-AAVXD6GM.js").then((m) => ({ default: m.Gr4vyAddCard }))
132
132
  );
133
133
  function formatCard(card) {
134
134
  const brand = card.cardBrand ? card.cardBrand.toUpperCase() : "Card";
@@ -141,6 +141,18 @@ function formatCard(card) {
141
141
  }
142
142
  return brandPart;
143
143
  }
144
+ function toReadableMessage(err) {
145
+ if (err instanceof Error && err.message) return err.message;
146
+ if (err && typeof err === "object") {
147
+ const o = err;
148
+ if (typeof o.message === "string" && o.message) return o.message;
149
+ if (o.code != null) {
150
+ return `Your card couldn't be saved (${String(o.code)}). Please double-check the details and try again.`;
151
+ }
152
+ }
153
+ if (typeof err === "string" && err) return err;
154
+ return "Your card couldn't be saved. Please double-check the details and try again.";
155
+ }
144
156
  function PaymentMethods({ clientToken, baseUrl, theme, onChange }) {
145
157
  const { cards, isLoading, error, setDefault, remove, addCard, refetch } = usePaymentMethods({
146
158
  clientToken,
@@ -184,8 +196,7 @@ function PaymentMethods({ clientToken, baseUrl, theme, onChange }) {
184
196
  setExternalError(null);
185
197
  setAddCardPayload(payload);
186
198
  } catch (err) {
187
- const message = err instanceof Error ? err.message : String(err);
188
- setExternalError(new Error(message));
199
+ setExternalError(new Error(toReadableMessage(err)));
189
200
  }
190
201
  };
191
202
  if (isLoading) {
@@ -298,9 +309,7 @@ function PaymentMethods({ clientToken, baseUrl, theme, onChange }) {
298
309
  },
299
310
  onCancel: () => setAddCardPayload(null),
300
311
  onError: (err) => {
301
- const message = err instanceof Error ? err.message : String(err);
302
- setExternalError(new Error(message));
303
- setAddCardPayload(null);
312
+ setExternalError(new Error(toReadableMessage(err)));
304
313
  }
305
314
  }
306
315
  )
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts","../src/usePaymentMethods.ts","../src/PaymentMethods.tsx"],"sourcesContent":["import { request } from './request';\nimport { DEFAULT_BASE_URL } from './types';\nimport type { SavedCard, EmbedPayload } from './types';\n\nexport interface PaymentMethodsClient {\n list(): Promise<SavedCard[]>;\n setDefault(id: string): Promise<SavedCard>;\n remove(id: string): Promise<{ id: string }>;\n startAddCard(): Promise<EmbedPayload>;\n}\n\nexport function createPaymentMethods(opts: {\n clientToken: string;\n baseUrl?: string;\n}): PaymentMethodsClient {\n const baseUrl = opts.baseUrl ?? DEFAULT_BASE_URL;\n const headers = { 'X-Throttle-PM-Token': opts.clientToken };\n\n return {\n async list() {\n const parsed = await request({ method: 'GET', path: '/api/v1/me/payment-methods', baseUrl, headers });\n return parsed.data as SavedCard[];\n },\n\n async setDefault(id: string) {\n const parsed = await request({\n method: 'PATCH',\n path: `/api/v1/me/payment-methods/${encodeURIComponent(id)}`,\n baseUrl,\n headers,\n body: { isDefault: true },\n });\n return parsed.data as SavedCard;\n },\n\n async remove(id: string) {\n const parsed = await request({\n method: 'DELETE',\n path: `/api/v1/me/payment-methods/${encodeURIComponent(id)}`,\n baseUrl,\n headers,\n });\n return parsed.data as { id: string };\n },\n\n async startAddCard() {\n const parsed = await request({\n method: 'POST',\n path: '/api/v1/me/payment-methods/embed-token',\n baseUrl,\n headers,\n });\n return parsed.data as EmbedPayload;\n },\n };\n}\n","import { useEffect, useMemo, useRef, useState } from 'react';\nimport { createPaymentMethods } from './client';\nimport { ThrottlePaymentMethodsError } from './errors';\nimport type { EmbedPayload, SavedCard } from './types';\n\nexport interface UsePaymentMethodsOpts {\n clientToken: string;\n baseUrl?: string;\n}\n\nexport interface UsePaymentMethodsResult {\n cards: SavedCard[];\n isLoading: boolean;\n error: ThrottlePaymentMethodsError | null;\n setDefault(id: string): Promise<void>;\n remove(id: string): Promise<void>;\n addCard(): Promise<EmbedPayload>;\n refetch(): Promise<void>;\n}\n\nfunction toPaymentMethodsError(err: unknown): ThrottlePaymentMethodsError {\n if (err instanceof ThrottlePaymentMethodsError) return err;\n const message = err instanceof Error ? err.message : String(err);\n return new ThrottlePaymentMethodsError({ code: 'unknown_error', message, statusCode: 0 });\n}\n\nexport function usePaymentMethods(opts: UsePaymentMethodsOpts): UsePaymentMethodsResult {\n const { clientToken, baseUrl } = opts;\n\n const client = useMemo(\n () => createPaymentMethods({ clientToken, baseUrl }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [clientToken, baseUrl],\n );\n\n const [cards, setCards] = useState<SavedCard[]>([]);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<ThrottlePaymentMethodsError | null>(null);\n const genRef = useRef(0);\n\n const refetch = useMemo(\n () => async () => {\n const myGen = genRef.current;\n try {\n const data = await client.list();\n if (genRef.current !== myGen) return;\n setCards(data);\n setError(null);\n } catch (err) {\n if (genRef.current !== myGen) return;\n setError(toPaymentMethodsError(err));\n }\n },\n [client],\n );\n\n useEffect(() => {\n const myGen = ++genRef.current;\n\n (async () => {\n setIsLoading(true);\n try {\n const data = await client.list();\n if (genRef.current !== myGen) return;\n setCards(data);\n setError(null);\n } catch (err) {\n if (genRef.current !== myGen) return;\n setError(toPaymentMethodsError(err));\n } finally {\n if (genRef.current === myGen) {\n setIsLoading(false);\n }\n }\n })();\n }, [client]);\n\n const setDefault = async (id: string): Promise<void> => {\n try {\n await client.setDefault(id);\n await refetch();\n } catch (err) {\n const pmErr = toPaymentMethodsError(err);\n setError(pmErr);\n throw pmErr;\n }\n };\n\n const remove = async (id: string): Promise<void> => {\n try {\n await client.remove(id);\n await refetch();\n } catch (err) {\n const pmErr = toPaymentMethodsError(err);\n setError(pmErr);\n throw pmErr;\n }\n };\n\n const addCard = async (): Promise<EmbedPayload> => {\n return client.startAddCard();\n };\n\n return { cards, isLoading, error, setDefault, remove, addCard, refetch };\n}\n","import React, { Suspense, useEffect, useRef, useState } from 'react';\nimport { usePaymentMethods } from './usePaymentMethods';\nimport type { EmbedPayload, SavedCard, PaymentMethodsTheme } from './types';\n\n// Lazy import — keeps @gr4vy/embed-react out of the eager bundle (SSR-safe).\n// Do NOT hoist this to a top-level import; React.lazy is the only safe path.\nconst LazyGr4vyAddCard = React.lazy(() =>\n import('./Gr4vyAddCard').then((m) => ({ default: m.Gr4vyAddCard })),\n);\n\nexport interface PaymentMethodsProps {\n clientToken: string;\n baseUrl?: string;\n theme?: PaymentMethodsTheme;\n onChange?: (cards: SavedCard[]) => void;\n}\n\nfunction formatCard(card: SavedCard): string {\n const brand = card.cardBrand ? card.cardBrand.toUpperCase() : 'Card';\n const last4 = card.cardLastFour ? `•••• ${card.cardLastFour}` : '••••';\n const brandPart = `${brand} ${last4}`;\n\n if (card.cardExpMonth != null && card.cardExpYear != null) {\n const mm = String(card.cardExpMonth).padStart(2, '0');\n const yy = String(card.cardExpYear).slice(-2);\n return `${brandPart} · ${mm}/${yy}`;\n }\n return brandPart;\n}\n\nexport function PaymentMethods({ clientToken, baseUrl, theme, onChange }: PaymentMethodsProps) {\n const { cards, isLoading, error, setDefault, remove, addCard, refetch } = usePaymentMethods({\n clientToken,\n baseUrl,\n });\n\n const [busyId, setBusyId] = useState<string | null>(null);\n const [addCardPayload, setAddCardPayload] = useState<EmbedPayload | null>(null);\n const [externalError, setExternalError] = useState<Error | null>(null);\n\n const onChangeRef = useRef(onChange);\n useEffect(() => { onChangeRef.current = onChange; });\n useEffect(() => { if (!isLoading) onChangeRef.current?.(cards); }, [cards, isLoading]);\n\n const primary = theme?.colorPrimary ?? '#1D56E8';\n const colorText = theme?.colorText ?? '#111827';\n const colorBorder = theme?.colorBorder ?? '#E5E7EB';\n const borderRadius = theme?.borderRadius ?? '8px';\n\n const handleSetDefault = async (id: string) => {\n setBusyId(id);\n try {\n await setDefault(id);\n } catch {\n // error is already set in the hook\n } finally {\n setBusyId(null);\n }\n };\n\n const handleRemove = async (id: string) => {\n setBusyId(id);\n try {\n await remove(id);\n } catch {\n // error is already set in the hook\n } finally {\n setBusyId(null);\n }\n };\n\n const handleAddCard = async () => {\n try {\n const payload = await addCard();\n setExternalError(null);\n setAddCardPayload(payload);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n setExternalError(new Error(message));\n }\n };\n\n if (isLoading) {\n return (\n <div role=\"status\" aria-label=\"Loading payment methods\" style={{ color: colorText }}>\n Loading…\n </div>\n );\n }\n\n const displayError = externalError ?? error;\n\n return (\n <div style={{ color: colorText, fontFamily: 'inherit' }}>\n {displayError && (\n <div\n role=\"alert\"\n style={{\n color: '#DC2626',\n marginBottom: '12px',\n padding: '8px 12px',\n border: `1px solid #FCA5A5`,\n borderRadius,\n fontSize: '14px',\n }}\n >\n {displayError.message}\n </div>\n )}\n\n <ul style={{ listStyle: 'none', margin: 0, padding: 0 }}>\n {cards.map((card) => {\n const isBusy = busyId === card.id;\n return (\n <li\n key={card.id}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '12px',\n padding: '12px',\n border: `1px solid ${colorBorder}`,\n borderRadius,\n marginBottom: '8px',\n }}\n >\n <span style={{ flex: 1, fontSize: '14px' }}>{formatCard(card)}</span>\n\n {card.isDefault ? (\n <span\n style={{\n backgroundColor: primary,\n color: '#fff',\n fontSize: '12px',\n fontWeight: 600,\n padding: '2px 8px',\n borderRadius: '999px',\n }}\n >\n Default\n </span>\n ) : (\n <>\n <button\n type=\"button\"\n disabled={isBusy}\n onClick={() => handleSetDefault(card.id)}\n style={{\n fontSize: '13px',\n padding: '4px 10px',\n border: `1px solid ${colorBorder}`,\n borderRadius,\n background: 'transparent',\n cursor: isBusy ? 'not-allowed' : 'pointer',\n opacity: isBusy ? 0.5 : 1,\n }}\n >\n Make default\n </button>\n <button\n type=\"button\"\n disabled={isBusy}\n onClick={() => handleRemove(card.id)}\n style={{\n fontSize: '13px',\n padding: '4px 10px',\n border: `1px solid #FCA5A5`,\n borderRadius,\n background: 'transparent',\n color: '#DC2626',\n cursor: isBusy ? 'not-allowed' : 'pointer',\n opacity: isBusy ? 0.5 : 1,\n }}\n >\n Remove\n </button>\n </>\n )}\n </li>\n );\n })}\n </ul>\n\n {addCardPayload ? (\n <Suspense\n fallback={\n <div role=\"status\" style={{ color: colorText, marginTop: '12px' }}>\n Loading…\n </div>\n }\n >\n <LazyGr4vyAddCard\n payload={addCardPayload}\n theme={theme}\n onAdded={async (paymentMethodId) => {\n void paymentMethodId;\n await refetch();\n setExternalError(null);\n setAddCardPayload(null);\n }}\n onCancel={() => setAddCardPayload(null)}\n onError={(err) => {\n const message = err instanceof Error ? (err as Error).message : String(err);\n setExternalError(new Error(message));\n setAddCardPayload(null);\n }}\n />\n </Suspense>\n ) : (\n <button\n type=\"button\"\n onClick={handleAddCard}\n style={{\n marginTop: '12px',\n padding: '8px 16px',\n backgroundColor: primary,\n color: '#fff',\n border: 'none',\n borderRadius,\n fontSize: '14px',\n fontWeight: 600,\n cursor: 'pointer',\n }}\n >\n + Add card\n </button>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":["useEffect","useRef","useState","useState","useRef","useEffect"]}
1
+ {"version":3,"sources":["../src/client.ts","../src/usePaymentMethods.ts","../src/PaymentMethods.tsx"],"sourcesContent":["import { request } from './request';\nimport { DEFAULT_BASE_URL } from './types';\nimport type { SavedCard, EmbedPayload } from './types';\n\nexport interface PaymentMethodsClient {\n list(): Promise<SavedCard[]>;\n setDefault(id: string): Promise<SavedCard>;\n remove(id: string): Promise<{ id: string }>;\n startAddCard(): Promise<EmbedPayload>;\n}\n\nexport function createPaymentMethods(opts: {\n clientToken: string;\n baseUrl?: string;\n}): PaymentMethodsClient {\n const baseUrl = opts.baseUrl ?? DEFAULT_BASE_URL;\n const headers = { 'X-Throttle-PM-Token': opts.clientToken };\n\n return {\n async list() {\n const parsed = await request({ method: 'GET', path: '/api/v1/me/payment-methods', baseUrl, headers });\n return parsed.data as SavedCard[];\n },\n\n async setDefault(id: string) {\n const parsed = await request({\n method: 'PATCH',\n path: `/api/v1/me/payment-methods/${encodeURIComponent(id)}`,\n baseUrl,\n headers,\n body: { isDefault: true },\n });\n return parsed.data as SavedCard;\n },\n\n async remove(id: string) {\n const parsed = await request({\n method: 'DELETE',\n path: `/api/v1/me/payment-methods/${encodeURIComponent(id)}`,\n baseUrl,\n headers,\n });\n return parsed.data as { id: string };\n },\n\n async startAddCard() {\n const parsed = await request({\n method: 'POST',\n path: '/api/v1/me/payment-methods/embed-token',\n baseUrl,\n headers,\n });\n return parsed.data as EmbedPayload;\n },\n };\n}\n","import { useEffect, useMemo, useRef, useState } from 'react';\nimport { createPaymentMethods } from './client';\nimport { ThrottlePaymentMethodsError } from './errors';\nimport type { EmbedPayload, SavedCard } from './types';\n\nexport interface UsePaymentMethodsOpts {\n clientToken: string;\n baseUrl?: string;\n}\n\nexport interface UsePaymentMethodsResult {\n cards: SavedCard[];\n isLoading: boolean;\n error: ThrottlePaymentMethodsError | null;\n setDefault(id: string): Promise<void>;\n remove(id: string): Promise<void>;\n addCard(): Promise<EmbedPayload>;\n refetch(): Promise<void>;\n}\n\nfunction toPaymentMethodsError(err: unknown): ThrottlePaymentMethodsError {\n if (err instanceof ThrottlePaymentMethodsError) return err;\n const message = err instanceof Error ? err.message : String(err);\n return new ThrottlePaymentMethodsError({ code: 'unknown_error', message, statusCode: 0 });\n}\n\nexport function usePaymentMethods(opts: UsePaymentMethodsOpts): UsePaymentMethodsResult {\n const { clientToken, baseUrl } = opts;\n\n const client = useMemo(\n () => createPaymentMethods({ clientToken, baseUrl }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [clientToken, baseUrl],\n );\n\n const [cards, setCards] = useState<SavedCard[]>([]);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<ThrottlePaymentMethodsError | null>(null);\n const genRef = useRef(0);\n\n const refetch = useMemo(\n () => async () => {\n const myGen = genRef.current;\n try {\n const data = await client.list();\n if (genRef.current !== myGen) return;\n setCards(data);\n setError(null);\n } catch (err) {\n if (genRef.current !== myGen) return;\n setError(toPaymentMethodsError(err));\n }\n },\n [client],\n );\n\n useEffect(() => {\n const myGen = ++genRef.current;\n\n (async () => {\n setIsLoading(true);\n try {\n const data = await client.list();\n if (genRef.current !== myGen) return;\n setCards(data);\n setError(null);\n } catch (err) {\n if (genRef.current !== myGen) return;\n setError(toPaymentMethodsError(err));\n } finally {\n if (genRef.current === myGen) {\n setIsLoading(false);\n }\n }\n })();\n }, [client]);\n\n const setDefault = async (id: string): Promise<void> => {\n try {\n await client.setDefault(id);\n await refetch();\n } catch (err) {\n const pmErr = toPaymentMethodsError(err);\n setError(pmErr);\n throw pmErr;\n }\n };\n\n const remove = async (id: string): Promise<void> => {\n try {\n await client.remove(id);\n await refetch();\n } catch (err) {\n const pmErr = toPaymentMethodsError(err);\n setError(pmErr);\n throw pmErr;\n }\n };\n\n const addCard = async (): Promise<EmbedPayload> => {\n return client.startAddCard();\n };\n\n return { cards, isLoading, error, setDefault, remove, addCard, refetch };\n}\n","import React, { Suspense, useEffect, useRef, useState } from 'react';\nimport { usePaymentMethods } from './usePaymentMethods';\nimport type { EmbedPayload, SavedCard, PaymentMethodsTheme } from './types';\n\n// Lazy import — keeps @gr4vy/embed-react out of the eager bundle (SSR-safe).\n// Do NOT hoist this to a top-level import; React.lazy is the only safe path.\nconst LazyGr4vyAddCard = React.lazy(() =>\n import('./Gr4vyAddCard').then((m) => ({ default: m.Gr4vyAddCard })),\n);\n\nexport interface PaymentMethodsProps {\n clientToken: string;\n baseUrl?: string;\n theme?: PaymentMethodsTheme;\n onChange?: (cards: SavedCard[]) => void;\n}\n\nfunction formatCard(card: SavedCard): string {\n const brand = card.cardBrand ? card.cardBrand.toUpperCase() : 'Card';\n const last4 = card.cardLastFour ? `•••• ${card.cardLastFour}` : '••••';\n const brandPart = `${brand} ${last4}`;\n\n if (card.cardExpMonth != null && card.cardExpYear != null) {\n const mm = String(card.cardExpMonth).padStart(2, '0');\n const yy = String(card.cardExpYear).slice(-2);\n return `${brandPart} · ${mm}/${yy}`;\n }\n return brandPart;\n}\n\n/**\n * Extract a human-readable message from anything thrown/emitted. The Gr4vy embed\n * emits a plain object on `transactionFailed` (e.g. { code, message }), not an\n * Error — `String(obj)` would render \"[object Object]\", so pull `.message`/`.code`.\n */\nexport function toReadableMessage(err: unknown): string {\n if (err instanceof Error && err.message) return err.message;\n if (err && typeof err === 'object') {\n const o = err as Record<string, unknown>;\n if (typeof o.message === 'string' && o.message) return o.message;\n if (o.code != null) {\n return `Your card couldn't be saved (${String(o.code)}). Please double-check the details and try again.`;\n }\n }\n if (typeof err === 'string' && err) return err;\n return \"Your card couldn't be saved. Please double-check the details and try again.\";\n}\n\nexport function PaymentMethods({ clientToken, baseUrl, theme, onChange }: PaymentMethodsProps) {\n const { cards, isLoading, error, setDefault, remove, addCard, refetch } = usePaymentMethods({\n clientToken,\n baseUrl,\n });\n\n const [busyId, setBusyId] = useState<string | null>(null);\n const [addCardPayload, setAddCardPayload] = useState<EmbedPayload | null>(null);\n const [externalError, setExternalError] = useState<Error | null>(null);\n\n const onChangeRef = useRef(onChange);\n useEffect(() => { onChangeRef.current = onChange; });\n useEffect(() => { if (!isLoading) onChangeRef.current?.(cards); }, [cards, isLoading]);\n\n const primary = theme?.colorPrimary ?? '#1D56E8';\n const colorText = theme?.colorText ?? '#111827';\n const colorBorder = theme?.colorBorder ?? '#E5E7EB';\n const borderRadius = theme?.borderRadius ?? '8px';\n\n const handleSetDefault = async (id: string) => {\n setBusyId(id);\n try {\n await setDefault(id);\n } catch {\n // error is already set in the hook\n } finally {\n setBusyId(null);\n }\n };\n\n const handleRemove = async (id: string) => {\n setBusyId(id);\n try {\n await remove(id);\n } catch {\n // error is already set in the hook\n } finally {\n setBusyId(null);\n }\n };\n\n const handleAddCard = async () => {\n try {\n const payload = await addCard();\n setExternalError(null);\n setAddCardPayload(payload);\n } catch (err) {\n setExternalError(new Error(toReadableMessage(err)));\n }\n };\n\n if (isLoading) {\n return (\n <div role=\"status\" aria-label=\"Loading payment methods\" style={{ color: colorText }}>\n Loading…\n </div>\n );\n }\n\n const displayError = externalError ?? error;\n\n return (\n <div style={{ color: colorText, fontFamily: 'inherit' }}>\n {displayError && (\n <div\n role=\"alert\"\n style={{\n color: '#DC2626',\n marginBottom: '12px',\n padding: '8px 12px',\n border: `1px solid #FCA5A5`,\n borderRadius,\n fontSize: '14px',\n }}\n >\n {displayError.message}\n </div>\n )}\n\n <ul style={{ listStyle: 'none', margin: 0, padding: 0 }}>\n {cards.map((card) => {\n const isBusy = busyId === card.id;\n return (\n <li\n key={card.id}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '12px',\n padding: '12px',\n border: `1px solid ${colorBorder}`,\n borderRadius,\n marginBottom: '8px',\n }}\n >\n <span style={{ flex: 1, fontSize: '14px' }}>{formatCard(card)}</span>\n\n {card.isDefault ? (\n <span\n style={{\n backgroundColor: primary,\n color: '#fff',\n fontSize: '12px',\n fontWeight: 600,\n padding: '2px 8px',\n borderRadius: '999px',\n }}\n >\n Default\n </span>\n ) : (\n <>\n <button\n type=\"button\"\n disabled={isBusy}\n onClick={() => handleSetDefault(card.id)}\n style={{\n fontSize: '13px',\n padding: '4px 10px',\n border: `1px solid ${colorBorder}`,\n borderRadius,\n background: 'transparent',\n cursor: isBusy ? 'not-allowed' : 'pointer',\n opacity: isBusy ? 0.5 : 1,\n }}\n >\n Make default\n </button>\n <button\n type=\"button\"\n disabled={isBusy}\n onClick={() => handleRemove(card.id)}\n style={{\n fontSize: '13px',\n padding: '4px 10px',\n border: `1px solid #FCA5A5`,\n borderRadius,\n background: 'transparent',\n color: '#DC2626',\n cursor: isBusy ? 'not-allowed' : 'pointer',\n opacity: isBusy ? 0.5 : 1,\n }}\n >\n Remove\n </button>\n </>\n )}\n </li>\n );\n })}\n </ul>\n\n {addCardPayload ? (\n <Suspense\n fallback={\n <div role=\"status\" style={{ color: colorText, marginTop: '12px' }}>\n Loading…\n </div>\n }\n >\n <LazyGr4vyAddCard\n payload={addCardPayload}\n theme={theme}\n onAdded={async (paymentMethodId) => {\n void paymentMethodId;\n await refetch();\n setExternalError(null);\n setAddCardPayload(null);\n }}\n onCancel={() => setAddCardPayload(null)}\n onError={(err) => {\n // Show the real reason and KEEP the embed open so the buyer can\n // fix the card and retry without re-opening the form.\n setExternalError(new Error(toReadableMessage(err)));\n }}\n />\n </Suspense>\n ) : (\n <button\n type=\"button\"\n onClick={handleAddCard}\n style={{\n marginTop: '12px',\n padding: '8px 16px',\n backgroundColor: primary,\n color: '#fff',\n border: 'none',\n borderRadius,\n fontSize: '14px',\n fontWeight: 600,\n cursor: 'pointer',\n }}\n >\n + Add card\n </button>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":["useEffect","useRef","useState","useState","useRef","useEffect"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/server.ts","../src/errors.ts","../src/request.ts","../src/types.ts"],"sourcesContent":["/**\n * Server-only entry for @usethrottle/payment-methods.\n *\n * NOTE: No `startAddCard` here — adding a card is inherently a browser flow.\n * The backend's role is to mint a short-lived client token via `mintClientToken`;\n * the browser then passes that token to <PaymentMethods/> (or the headless client)\n * to initiate the card-add UI. The server cannot initiate the Gr4vy embed flow.\n *\n * MUST NOT import React or @gr4vy/embed-react. Only ./request, ./types, ./errors.\n */\n\nimport { request } from './request';\nimport type { MintedClientToken, SavedCard } from './types';\nimport { DEFAULT_BASE_URL } from './types';\n\ninterface ServerOpts {\n apiKey: string;\n customerId: string;\n baseUrl?: string;\n environmentId?: string;\n}\n\nfunction authHeaders(opts: Pick<ServerOpts, 'apiKey' | 'environmentId'>): Record<string, string> {\n return {\n 'X-API-Key': opts.apiKey,\n ...(opts.environmentId ? { 'X-Throttle-Environment-Id': opts.environmentId } : {}),\n };\n}\n\nexport async function mintClientToken(opts: ServerOpts): Promise<MintedClientToken> {\n const parsed = await request({\n method: 'POST',\n path: '/api/v1/payment-methods/client-token',\n baseUrl: opts.baseUrl ?? DEFAULT_BASE_URL,\n headers: authHeaders(opts),\n body: { customerId: opts.customerId },\n });\n return parsed.data as MintedClientToken;\n}\n\nexport function createServerPaymentMethods(opts: ServerOpts): {\n list(): Promise<SavedCard[]>;\n setDefault(id: string): Promise<SavedCard>;\n remove(id: string): Promise<{ id: string }>;\n} {\n const base = opts.baseUrl ?? DEFAULT_BASE_URL;\n const prefix = `/api/v1/customers/${encodeURIComponent(opts.customerId)}/payment-methods`;\n const headers = authHeaders(opts);\n\n return {\n async list() {\n const parsed = await request({ method: 'GET', path: prefix, baseUrl: base, headers });\n return parsed.data as SavedCard[];\n },\n async setDefault(id: string) {\n const parsed = await request({\n method: 'PATCH',\n path: `${prefix}/${encodeURIComponent(id)}`,\n baseUrl: base,\n headers,\n body: { isDefault: true },\n });\n return parsed.data as SavedCard;\n },\n async remove(id: string) {\n const parsed = await request({\n method: 'DELETE',\n path: `${prefix}/${encodeURIComponent(id)}`,\n baseUrl: base,\n headers,\n });\n return parsed.data as { id: string };\n },\n };\n}\n","import { ThrottleError } from '@usethrottle/errors';\n\nexport class ThrottlePaymentMethodsError extends ThrottleError {\n constructor(args: { code: string; message: string; statusCode: number; details?: unknown }) {\n super(args);\n this.name = 'ThrottlePaymentMethodsError';\n }\n}\n\nexport { ThrottleError, isThrottleError } from '@usethrottle/errors';\n","import { ThrottlePaymentMethodsError } from './errors';\n\nexport async function request(input: {\n method: string;\n path: string;\n baseUrl: string;\n headers?: Record<string, string>;\n body?: unknown;\n}): Promise<any> {\n const res = await fetch(`${input.baseUrl}${input.path}`, {\n method: input.method,\n headers: {\n ...(input.body !== undefined ? { 'Content-Type': 'application/json' } : {}),\n ...(input.headers ?? {}),\n },\n ...(input.body !== undefined ? { body: JSON.stringify(input.body) } : {}),\n });\n const text = await res.text();\n let parsed: any = {};\n try {\n parsed = text ? JSON.parse(text) : {};\n } catch {\n // Non-JSON body (e.g. an HTML 502/503 gateway page). Leave parsed as {} so\n // the non-2xx branch below still throws a typed ThrottlePaymentMethodsError\n // (code 'request_failed') rather than leaking a raw SyntaxError.\n }\n if (!res.ok) {\n const e = parsed?.error ?? {};\n throw new ThrottlePaymentMethodsError({\n code: e.code ?? 'request_failed',\n message: e.message ?? `Request failed with ${res.status}`,\n statusCode: res.status,\n details: e.details,\n });\n }\n return parsed;\n}\n","export interface SavedCard {\n id: string;\n methodType: string;\n cardBrand: string | null;\n cardLastFour: string | null;\n cardExpMonth: number | null;\n cardExpYear: number | null;\n isDefault: boolean;\n}\n\nexport interface EmbedPayload {\n embedToken: string;\n checkoutSessionId: string;\n amount: number;\n currency: string;\n gr4vyId: string;\n merchantAccountId?: string;\n environment: 'sandbox' | 'production';\n /**\n * The buyer the embed JWT is pinned to. The add-only vault embed is a\n * recurring/store flow, so Gr4vy asserts the `<Gr4vyEmbed buyerExternalIdentifier>`\n * prop equals the JWT's value — the component MUST forward this or the embed\n * renders no card fields. Always present on the add-only embed payload.\n */\n buyerExternalIdentifier?: string;\n hostedUrl?: string;\n embedUrl?: string;\n}\n\nexport interface MintedClientToken {\n token: string;\n expiresAt: string;\n}\n\nexport interface PaymentMethodsTheme {\n colorPrimary?: string;\n colorText?: string;\n colorBorder?: string;\n borderRadius?: string;\n}\n\nexport const DEFAULT_BASE_URL = 'https://api.usethrottle.dev';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,oBAA8B;AAS9B,IAAAA,iBAA+C;AAPxC,IAAM,8BAAN,cAA0C,4BAAc;AAAA,EAC7D,YAAY,MAAgF;AAC1F,UAAM,IAAI;AACV,SAAK,OAAO;AAAA,EACd;AACF;;;ACLA,eAAsB,QAAQ,OAMb;AACf,QAAM,MAAM,MAAM,MAAM,GAAG,MAAM,OAAO,GAAG,MAAM,IAAI,IAAI;AAAA,IACvD,QAAQ,MAAM;AAAA,IACd,SAAS;AAAA,MACP,GAAI,MAAM,SAAS,SAAY,EAAE,gBAAgB,mBAAmB,IAAI,CAAC;AAAA,MACzE,GAAI,MAAM,WAAW,CAAC;AAAA,IACxB;AAAA,IACA,GAAI,MAAM,SAAS,SAAY,EAAE,MAAM,KAAK,UAAU,MAAM,IAAI,EAAE,IAAI,CAAC;AAAA,EACzE,CAAC;AACD,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,MAAI,SAAc,CAAC;AACnB,MAAI;AACF,aAAS,OAAO,KAAK,MAAM,IAAI,IAAI,CAAC;AAAA,EACtC,QAAQ;AAAA,EAIR;AACA,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,IAAI,QAAQ,SAAS,CAAC;AAC5B,UAAM,IAAI,4BAA4B;AAAA,MACpC,MAAM,EAAE,QAAQ;AAAA,MAChB,SAAS,EAAE,WAAW,uBAAuB,IAAI,MAAM;AAAA,MACvD,YAAY,IAAI;AAAA,MAChB,SAAS,EAAE;AAAA,IACb,CAAC;AAAA,EACH;AACA,SAAO;AACT;;;ACKO,IAAM,mBAAmB;;;AHnBhC,SAAS,YAAY,MAA4E;AAC/F,SAAO;AAAA,IACL,aAAa,KAAK;AAAA,IAClB,GAAI,KAAK,gBAAgB,EAAE,6BAA6B,KAAK,cAAc,IAAI,CAAC;AAAA,EAClF;AACF;AAEA,eAAsB,gBAAgB,MAA8C;AAClF,QAAM,SAAS,MAAM,QAAQ;AAAA,IAC3B,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,SAAS,KAAK,WAAW;AAAA,IACzB,SAAS,YAAY,IAAI;AAAA,IACzB,MAAM,EAAE,YAAY,KAAK,WAAW;AAAA,EACtC,CAAC;AACD,SAAO,OAAO;AAChB;AAEO,SAAS,2BAA2B,MAIzC;AACA,QAAM,OAAO,KAAK,WAAW;AAC7B,QAAM,SAAS,qBAAqB,mBAAmB,KAAK,UAAU,CAAC;AACvE,QAAM,UAAU,YAAY,IAAI;AAEhC,SAAO;AAAA,IACL,MAAM,OAAO;AACX,YAAM,SAAS,MAAM,QAAQ,EAAE,QAAQ,OAAO,MAAM,QAAQ,SAAS,MAAM,QAAQ,CAAC;AACpF,aAAO,OAAO;AAAA,IAChB;AAAA,IACA,MAAM,WAAW,IAAY;AAC3B,YAAM,SAAS,MAAM,QAAQ;AAAA,QAC3B,QAAQ;AAAA,QACR,MAAM,GAAG,MAAM,IAAI,mBAAmB,EAAE,CAAC;AAAA,QACzC,SAAS;AAAA,QACT;AAAA,QACA,MAAM,EAAE,WAAW,KAAK;AAAA,MAC1B,CAAC;AACD,aAAO,OAAO;AAAA,IAChB;AAAA,IACA,MAAM,OAAO,IAAY;AACvB,YAAM,SAAS,MAAM,QAAQ;AAAA,QAC3B,QAAQ;AAAA,QACR,MAAM,GAAG,MAAM,IAAI,mBAAmB,EAAE,CAAC;AAAA,QACzC,SAAS;AAAA,QACT;AAAA,MACF,CAAC;AACD,aAAO,OAAO;AAAA,IAChB;AAAA,EACF;AACF;","names":["import_errors"]}
1
+ {"version":3,"sources":["../src/server.ts","../src/errors.ts","../src/request.ts","../src/types.ts"],"sourcesContent":["/**\n * Server-only entry for @usethrottle/payment-methods.\n *\n * NOTE: No `startAddCard` here — adding a card is inherently a browser flow.\n * The backend's role is to mint a short-lived client token via `mintClientToken`;\n * the browser then passes that token to <PaymentMethods/> (or the headless client)\n * to initiate the card-add UI. The server cannot initiate the Gr4vy embed flow.\n *\n * MUST NOT import React or @gr4vy/embed-react. Only ./request, ./types, ./errors.\n */\n\nimport { request } from './request';\nimport type { MintedClientToken, SavedCard } from './types';\nimport { DEFAULT_BASE_URL } from './types';\n\ninterface ServerOpts {\n apiKey: string;\n customerId: string;\n baseUrl?: string;\n environmentId?: string;\n}\n\nfunction authHeaders(opts: Pick<ServerOpts, 'apiKey' | 'environmentId'>): Record<string, string> {\n return {\n 'X-API-Key': opts.apiKey,\n ...(opts.environmentId ? { 'X-Throttle-Environment-Id': opts.environmentId } : {}),\n };\n}\n\nexport async function mintClientToken(opts: ServerOpts): Promise<MintedClientToken> {\n const parsed = await request({\n method: 'POST',\n path: '/api/v1/payment-methods/client-token',\n baseUrl: opts.baseUrl ?? DEFAULT_BASE_URL,\n headers: authHeaders(opts),\n body: { customerId: opts.customerId },\n });\n return parsed.data as MintedClientToken;\n}\n\nexport function createServerPaymentMethods(opts: ServerOpts): {\n list(): Promise<SavedCard[]>;\n setDefault(id: string): Promise<SavedCard>;\n remove(id: string): Promise<{ id: string }>;\n} {\n const base = opts.baseUrl ?? DEFAULT_BASE_URL;\n const prefix = `/api/v1/customers/${encodeURIComponent(opts.customerId)}/payment-methods`;\n const headers = authHeaders(opts);\n\n return {\n async list() {\n const parsed = await request({ method: 'GET', path: prefix, baseUrl: base, headers });\n return parsed.data as SavedCard[];\n },\n async setDefault(id: string) {\n const parsed = await request({\n method: 'PATCH',\n path: `${prefix}/${encodeURIComponent(id)}`,\n baseUrl: base,\n headers,\n body: { isDefault: true },\n });\n return parsed.data as SavedCard;\n },\n async remove(id: string) {\n const parsed = await request({\n method: 'DELETE',\n path: `${prefix}/${encodeURIComponent(id)}`,\n baseUrl: base,\n headers,\n });\n return parsed.data as { id: string };\n },\n };\n}\n","import { ThrottleError } from '@usethrottle/errors';\n\nexport class ThrottlePaymentMethodsError extends ThrottleError {\n constructor(args: { code: string; message: string; statusCode: number; details?: unknown }) {\n super(args);\n this.name = 'ThrottlePaymentMethodsError';\n }\n}\n\nexport { ThrottleError, isThrottleError } from '@usethrottle/errors';\n","import { ThrottlePaymentMethodsError } from './errors';\n\nexport async function request(input: {\n method: string;\n path: string;\n baseUrl: string;\n headers?: Record<string, string>;\n body?: unknown;\n}): Promise<any> {\n const res = await fetch(`${input.baseUrl}${input.path}`, {\n method: input.method,\n headers: {\n ...(input.body !== undefined ? { 'Content-Type': 'application/json' } : {}),\n ...(input.headers ?? {}),\n },\n ...(input.body !== undefined ? { body: JSON.stringify(input.body) } : {}),\n });\n const text = await res.text();\n let parsed: any = {};\n try {\n parsed = text ? JSON.parse(text) : {};\n } catch {\n // Non-JSON body (e.g. an HTML 502/503 gateway page). Leave parsed as {} so\n // the non-2xx branch below still throws a typed ThrottlePaymentMethodsError\n // (code 'request_failed') rather than leaking a raw SyntaxError.\n }\n if (!res.ok) {\n const e = parsed?.error ?? {};\n throw new ThrottlePaymentMethodsError({\n code: e.code ?? 'request_failed',\n message: e.message ?? `Request failed with ${res.status}`,\n statusCode: res.status,\n details: e.details,\n });\n }\n return parsed;\n}\n","export interface SavedCard {\n id: string;\n methodType: string;\n cardBrand: string | null;\n cardLastFour: string | null;\n cardExpMonth: number | null;\n cardExpYear: number | null;\n isDefault: boolean;\n}\n\nexport interface EmbedPayload {\n embedToken: string;\n checkoutSessionId: string;\n amount: number;\n currency: string;\n gr4vyId: string;\n merchantAccountId?: string;\n environment: 'sandbox' | 'production';\n /**\n * The buyer the embed JWT is pinned to. The add-only vault embed is a\n * recurring/store flow, so Gr4vy asserts the `<Gr4vyEmbed buyerExternalIdentifier>`\n * prop equals the JWT's value — the component MUST forward this or the embed\n * renders no card fields. Always present on the add-only embed payload.\n */\n buyerExternalIdentifier?: string;\n /** ISO country code the embed session was minted for. The Gr4vy embed requires\n * a `country` string at init (\"undefined must be a string ISO country code\").\n * Defaults to 'US' in the component when absent. */\n country?: string;\n hostedUrl?: string;\n embedUrl?: string;\n}\n\nexport interface MintedClientToken {\n token: string;\n expiresAt: string;\n}\n\nexport interface PaymentMethodsTheme {\n colorPrimary?: string;\n colorText?: string;\n colorBorder?: string;\n borderRadius?: string;\n}\n\nexport const DEFAULT_BASE_URL = 'https://api.usethrottle.dev';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,oBAA8B;AAS9B,IAAAA,iBAA+C;AAPxC,IAAM,8BAAN,cAA0C,4BAAc;AAAA,EAC7D,YAAY,MAAgF;AAC1F,UAAM,IAAI;AACV,SAAK,OAAO;AAAA,EACd;AACF;;;ACLA,eAAsB,QAAQ,OAMb;AACf,QAAM,MAAM,MAAM,MAAM,GAAG,MAAM,OAAO,GAAG,MAAM,IAAI,IAAI;AAAA,IACvD,QAAQ,MAAM;AAAA,IACd,SAAS;AAAA,MACP,GAAI,MAAM,SAAS,SAAY,EAAE,gBAAgB,mBAAmB,IAAI,CAAC;AAAA,MACzE,GAAI,MAAM,WAAW,CAAC;AAAA,IACxB;AAAA,IACA,GAAI,MAAM,SAAS,SAAY,EAAE,MAAM,KAAK,UAAU,MAAM,IAAI,EAAE,IAAI,CAAC;AAAA,EACzE,CAAC;AACD,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,MAAI,SAAc,CAAC;AACnB,MAAI;AACF,aAAS,OAAO,KAAK,MAAM,IAAI,IAAI,CAAC;AAAA,EACtC,QAAQ;AAAA,EAIR;AACA,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,IAAI,QAAQ,SAAS,CAAC;AAC5B,UAAM,IAAI,4BAA4B;AAAA,MACpC,MAAM,EAAE,QAAQ;AAAA,MAChB,SAAS,EAAE,WAAW,uBAAuB,IAAI,MAAM;AAAA,MACvD,YAAY,IAAI;AAAA,MAChB,SAAS,EAAE;AAAA,IACb,CAAC;AAAA,EACH;AACA,SAAO;AACT;;;ACSO,IAAM,mBAAmB;;;AHvBhC,SAAS,YAAY,MAA4E;AAC/F,SAAO;AAAA,IACL,aAAa,KAAK;AAAA,IAClB,GAAI,KAAK,gBAAgB,EAAE,6BAA6B,KAAK,cAAc,IAAI,CAAC;AAAA,EAClF;AACF;AAEA,eAAsB,gBAAgB,MAA8C;AAClF,QAAM,SAAS,MAAM,QAAQ;AAAA,IAC3B,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,SAAS,KAAK,WAAW;AAAA,IACzB,SAAS,YAAY,IAAI;AAAA,IACzB,MAAM,EAAE,YAAY,KAAK,WAAW;AAAA,EACtC,CAAC;AACD,SAAO,OAAO;AAChB;AAEO,SAAS,2BAA2B,MAIzC;AACA,QAAM,OAAO,KAAK,WAAW;AAC7B,QAAM,SAAS,qBAAqB,mBAAmB,KAAK,UAAU,CAAC;AACvE,QAAM,UAAU,YAAY,IAAI;AAEhC,SAAO;AAAA,IACL,MAAM,OAAO;AACX,YAAM,SAAS,MAAM,QAAQ,EAAE,QAAQ,OAAO,MAAM,QAAQ,SAAS,MAAM,QAAQ,CAAC;AACpF,aAAO,OAAO;AAAA,IAChB;AAAA,IACA,MAAM,WAAW,IAAY;AAC3B,YAAM,SAAS,MAAM,QAAQ;AAAA,QAC3B,QAAQ;AAAA,QACR,MAAM,GAAG,MAAM,IAAI,mBAAmB,EAAE,CAAC;AAAA,QACzC,SAAS;AAAA,QACT;AAAA,QACA,MAAM,EAAE,WAAW,KAAK;AAAA,MAC1B,CAAC;AACD,aAAO,OAAO;AAAA,IAChB;AAAA,IACA,MAAM,OAAO,IAAY;AACvB,YAAM,SAAS,MAAM,QAAQ;AAAA,QAC3B,QAAQ;AAAA,QACR,MAAM,GAAG,MAAM,IAAI,mBAAmB,EAAE,CAAC;AAAA,QACzC,SAAS;AAAA,QACT;AAAA,MACF,CAAC;AACD,aAAO,OAAO;AAAA,IAChB;AAAA,EACF;AACF;","names":["import_errors"]}
package/dist/server.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { S as SavedCard, M as MintedClientToken } from './types-Cs3nqt_3.cjs';
1
+ import { S as SavedCard, M as MintedClientToken } from './types-D610pEVD.cjs';
2
2
 
3
3
  /**
4
4
  * Server-only entry for @usethrottle/payment-methods.
package/dist/server.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { S as SavedCard, M as MintedClientToken } from './types-Cs3nqt_3.js';
1
+ import { S as SavedCard, M as MintedClientToken } from './types-D610pEVD.js';
2
2
 
3
3
  /**
4
4
  * Server-only entry for @usethrottle/payment-methods.
package/dist/server.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  DEFAULT_BASE_URL,
3
3
  request
4
- } from "./chunk-RXWPYJQI.js";
4
+ } from "./chunk-XNNVEEVF.js";
5
5
 
6
6
  // src/server.ts
7
7
  function authHeaders(opts) {
@@ -22,6 +22,10 @@ interface EmbedPayload {
22
22
  * renders no card fields. Always present on the add-only embed payload.
23
23
  */
24
24
  buyerExternalIdentifier?: string;
25
+ /** ISO country code the embed session was minted for. The Gr4vy embed requires
26
+ * a `country` string at init ("undefined must be a string ISO country code").
27
+ * Defaults to 'US' in the component when absent. */
28
+ country?: string;
25
29
  hostedUrl?: string;
26
30
  embedUrl?: string;
27
31
  }
@@ -22,6 +22,10 @@ interface EmbedPayload {
22
22
  * renders no card fields. Always present on the add-only embed payload.
23
23
  */
24
24
  buyerExternalIdentifier?: string;
25
+ /** ISO country code the embed session was minted for. The Gr4vy embed requires
26
+ * a `country` string at init ("undefined must be a string ISO country code").
27
+ * Defaults to 'US' in the component when absent. */
28
+ country?: string;
25
29
  hostedUrl?: string;
26
30
  embedUrl?: string;
27
31
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usethrottle/payment-methods",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Drop-in saved-card wallet (list, add, set default, remove) for Throttle storefronts — headless core + React component.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/Gr4vyAddCard.tsx"],"sourcesContent":["/**\n * Gr4vyAddCard — lazy-loaded vault-only embed wrapper.\n *\n * THIS FILE MUST ONLY BE LOADED VIA React.lazy(() => import('./Gr4vyAddCard'))\n * from PaymentMethods.tsx. Never import it at the module top-level of any file\n * that is part of the server bundle — @gr4vy/embed-react touches `window` at\n * module evaluation time and will throw `ReferenceError: window is not defined`\n * in SSR contexts.\n */\nimport React, { useRef } from 'react';\nimport Gr4vyEmbedImport, { type EmbedInstance } from '@gr4vy/embed-react';\nimport type { EmbedPayload, PaymentMethodsTheme } from './types';\n\n/**\n * `@gr4vy/embed-react` is a CommonJS package (no `module`/`exports`/`type`\n * fields), so a consumer's bundler resolves `import Gr4vy from '@gr4vy/embed-react'`\n * differently depending on its CJS↔ESM interop: some hand back the component\n * directly, others hand back the module namespace `{ default: <component> }`.\n * Rendering the namespace object throws \"Element type is invalid … got: object\".\n * Unwrap `.default` until we reach an actual React element type (a function\n * component, or a forwardRef/memo object carrying `$$typeof`).\n */\nexport function resolveComponent(mod: unknown): React.ComponentType<Record<string, unknown>> {\n let x: any = mod;\n while (x && typeof x === 'object' && !x.$$typeof && x.default) x = x.default;\n return x as React.ComponentType<Record<string, unknown>>;\n}\nconst Gr4vyEmbed = resolveComponent(Gr4vyEmbedImport);\n\ninterface Gr4vyTransaction {\n id: string;\n status: string;\n paymentMethod?: { id?: string };\n}\n\nexport interface Gr4vyAddCardProps {\n payload: EmbedPayload;\n theme?: PaymentMethodsTheme;\n onAdded: (paymentMethodId?: string) => void;\n onCancel: () => void;\n onError: (err: unknown) => void;\n}\n\nexport function Gr4vyAddCard({ payload, theme, onAdded, onCancel, onError }: Gr4vyAddCardProps) {\n const embedRef = useRef<EmbedInstance>(null);\n\n const colors = theme\n ? {\n ...(theme.colorPrimary !== undefined ? { primary: theme.colorPrimary } : {}),\n ...(theme.colorText !== undefined ? { text: theme.colorText } : {}),\n ...(theme.colorBorder !== undefined ? { inputBorder: theme.colorBorder } : {}),\n }\n : {};\n const gr4vyTheme = Object.keys(colors).length ? { colors } : undefined;\n\n return (\n <div>\n <Gr4vyEmbed\n ref={embedRef}\n gr4vyId={payload.gr4vyId}\n environment={payload.environment}\n token={payload.embedToken}\n amount={payload.amount}\n currency={payload.currency}\n merchantAccountId={payload.merchantAccountId}\n intent=\"capture\"\n paymentSource=\"recurring\"\n store={true}\n display=\"addOnly\"\n {...(payload.buyerExternalIdentifier\n ? { buyerExternalIdentifier: payload.buyerExternalIdentifier }\n : {})}\n {...(gr4vyTheme !== undefined ? { theme: gr4vyTheme } : {})}\n onComplete={(txn: Gr4vyTransaction) => {\n onAdded(txn.paymentMethod?.id);\n }}\n onEvent={(eventName: string, data: unknown) => {\n if (eventName === 'transactionFailed') {\n onError(data);\n }\n }}\n />\n\n <button\n type=\"button\"\n onClick={() => {\n embedRef.current?.submit();\n }}\n style={{\n marginTop: '12px',\n padding: '8px 16px',\n backgroundColor: theme?.colorPrimary ?? '#1D56E8',\n color: '#fff',\n border: 'none',\n borderRadius: '8px',\n fontSize: '14px',\n fontWeight: 600,\n cursor: 'pointer',\n width: '100%',\n }}\n >\n Save card\n </button>\n\n <button\n type=\"button\"\n onClick={onCancel}\n style={{\n marginTop: '8px',\n padding: '8px 16px',\n backgroundColor: 'transparent',\n color: theme?.colorText ?? '#111827',\n border: `1px solid ${theme?.colorBorder ?? '#E5E7EB'}`,\n borderRadius: '8px',\n fontSize: '14px',\n cursor: 'pointer',\n width: '100%',\n }}\n >\n Cancel\n </button>\n </div>\n );\n}\n\nexport default Gr4vyAddCard;\n"],"mappings":";AASA,SAAgB,cAAc;AAC9B,OAAO,sBAA8C;AA8CjD,SACE,KADF;AAlCG,SAAS,iBAAiB,KAA4D;AAC3F,MAAI,IAAS;AACb,SAAO,KAAK,OAAO,MAAM,YAAY,CAAC,EAAE,YAAY,EAAE,QAAS,KAAI,EAAE;AACrE,SAAO;AACT;AACA,IAAM,aAAa,iBAAiB,gBAAgB;AAgB7C,SAAS,aAAa,EAAE,SAAS,OAAO,SAAS,UAAU,QAAQ,GAAsB;AAC9F,QAAM,WAAW,OAAsB,IAAI;AAE3C,QAAM,SAAS,QACX;AAAA,IACE,GAAI,MAAM,iBAAiB,SAAY,EAAE,SAAS,MAAM,aAAa,IAAI,CAAC;AAAA,IAC1E,GAAI,MAAM,cAAc,SAAY,EAAE,MAAM,MAAM,UAAU,IAAI,CAAC;AAAA,IACjE,GAAI,MAAM,gBAAgB,SAAY,EAAE,aAAa,MAAM,YAAY,IAAI,CAAC;AAAA,EAC9E,IACA,CAAC;AACL,QAAM,aAAa,OAAO,KAAK,MAAM,EAAE,SAAS,EAAE,OAAO,IAAI;AAE7D,SACE,qBAAC,SACC;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,SAAS,QAAQ;AAAA,QACjB,aAAa,QAAQ;AAAA,QACrB,OAAO,QAAQ;AAAA,QACf,QAAQ,QAAQ;AAAA,QAChB,UAAU,QAAQ;AAAA,QAClB,mBAAmB,QAAQ;AAAA,QAC3B,QAAO;AAAA,QACP,eAAc;AAAA,QACd,OAAO;AAAA,QACP,SAAQ;AAAA,QACP,GAAI,QAAQ,0BACT,EAAE,yBAAyB,QAAQ,wBAAwB,IAC3D,CAAC;AAAA,QACJ,GAAI,eAAe,SAAY,EAAE,OAAO,WAAW,IAAI,CAAC;AAAA,QACzD,YAAY,CAAC,QAA0B;AACrC,kBAAQ,IAAI,eAAe,EAAE;AAAA,QAC/B;AAAA,QACA,SAAS,CAAC,WAAmB,SAAkB;AAC7C,cAAI,cAAc,qBAAqB;AACrC,oBAAQ,IAAI;AAAA,UACd;AAAA,QACF;AAAA;AAAA,IACF;AAAA,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS,MAAM;AACb,mBAAS,SAAS,OAAO;AAAA,QAC3B;AAAA,QACA,OAAO;AAAA,UACL,WAAW;AAAA,UACX,SAAS;AAAA,UACT,iBAAiB,OAAO,gBAAgB;AAAA,UACxC,OAAO;AAAA,UACP,QAAQ;AAAA,UACR,cAAc;AAAA,UACd,UAAU;AAAA,UACV,YAAY;AAAA,UACZ,QAAQ;AAAA,UACR,OAAO;AAAA,QACT;AAAA,QACD;AAAA;AAAA,IAED;AAAA,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS;AAAA,QACT,OAAO;AAAA,UACL,WAAW;AAAA,UACX,SAAS;AAAA,UACT,iBAAiB;AAAA,UACjB,OAAO,OAAO,aAAa;AAAA,UAC3B,QAAQ,aAAa,OAAO,eAAe,SAAS;AAAA,UACpD,cAAc;AAAA,UACd,UAAU;AAAA,UACV,QAAQ;AAAA,UACR,OAAO;AAAA,QACT;AAAA,QACD;AAAA;AAAA,IAED;AAAA,KACF;AAEJ;AAEA,IAAO,uBAAQ;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/types.ts","../src/request.ts"],"sourcesContent":["import { ThrottleError } from '@usethrottle/errors';\n\nexport class ThrottlePaymentMethodsError extends ThrottleError {\n constructor(args: { code: string; message: string; statusCode: number; details?: unknown }) {\n super(args);\n this.name = 'ThrottlePaymentMethodsError';\n }\n}\n\nexport { ThrottleError, isThrottleError } from '@usethrottle/errors';\n","export interface SavedCard {\n id: string;\n methodType: string;\n cardBrand: string | null;\n cardLastFour: string | null;\n cardExpMonth: number | null;\n cardExpYear: number | null;\n isDefault: boolean;\n}\n\nexport interface EmbedPayload {\n embedToken: string;\n checkoutSessionId: string;\n amount: number;\n currency: string;\n gr4vyId: string;\n merchantAccountId?: string;\n environment: 'sandbox' | 'production';\n /**\n * The buyer the embed JWT is pinned to. The add-only vault embed is a\n * recurring/store flow, so Gr4vy asserts the `<Gr4vyEmbed buyerExternalIdentifier>`\n * prop equals the JWT's value — the component MUST forward this or the embed\n * renders no card fields. Always present on the add-only embed payload.\n */\n buyerExternalIdentifier?: string;\n hostedUrl?: string;\n embedUrl?: string;\n}\n\nexport interface MintedClientToken {\n token: string;\n expiresAt: string;\n}\n\nexport interface PaymentMethodsTheme {\n colorPrimary?: string;\n colorText?: string;\n colorBorder?: string;\n borderRadius?: string;\n}\n\nexport const DEFAULT_BASE_URL = 'https://api.usethrottle.dev';\n","import { ThrottlePaymentMethodsError } from './errors';\n\nexport async function request(input: {\n method: string;\n path: string;\n baseUrl: string;\n headers?: Record<string, string>;\n body?: unknown;\n}): Promise<any> {\n const res = await fetch(`${input.baseUrl}${input.path}`, {\n method: input.method,\n headers: {\n ...(input.body !== undefined ? { 'Content-Type': 'application/json' } : {}),\n ...(input.headers ?? {}),\n },\n ...(input.body !== undefined ? { body: JSON.stringify(input.body) } : {}),\n });\n const text = await res.text();\n let parsed: any = {};\n try {\n parsed = text ? JSON.parse(text) : {};\n } catch {\n // Non-JSON body (e.g. an HTML 502/503 gateway page). Leave parsed as {} so\n // the non-2xx branch below still throws a typed ThrottlePaymentMethodsError\n // (code 'request_failed') rather than leaking a raw SyntaxError.\n }\n if (!res.ok) {\n const e = parsed?.error ?? {};\n throw new ThrottlePaymentMethodsError({\n code: e.code ?? 'request_failed',\n message: e.message ?? `Request failed with ${res.status}`,\n statusCode: res.status,\n details: e.details,\n });\n }\n return parsed;\n}\n"],"mappings":";AAAA,SAAS,qBAAqB;AAS9B,SAAS,iBAAAA,gBAAe,uBAAuB;AAPxC,IAAM,8BAAN,cAA0C,cAAc;AAAA,EAC7D,YAAY,MAAgF;AAC1F,UAAM,IAAI;AACV,SAAK,OAAO;AAAA,EACd;AACF;;;ACkCO,IAAM,mBAAmB;;;ACvChC,eAAsB,QAAQ,OAMb;AACf,QAAM,MAAM,MAAM,MAAM,GAAG,MAAM,OAAO,GAAG,MAAM,IAAI,IAAI;AAAA,IACvD,QAAQ,MAAM;AAAA,IACd,SAAS;AAAA,MACP,GAAI,MAAM,SAAS,SAAY,EAAE,gBAAgB,mBAAmB,IAAI,CAAC;AAAA,MACzE,GAAI,MAAM,WAAW,CAAC;AAAA,IACxB;AAAA,IACA,GAAI,MAAM,SAAS,SAAY,EAAE,MAAM,KAAK,UAAU,MAAM,IAAI,EAAE,IAAI,CAAC;AAAA,EACzE,CAAC;AACD,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,MAAI,SAAc,CAAC;AACnB,MAAI;AACF,aAAS,OAAO,KAAK,MAAM,IAAI,IAAI,CAAC;AAAA,EACtC,QAAQ;AAAA,EAIR;AACA,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,IAAI,QAAQ,SAAS,CAAC;AAC5B,UAAM,IAAI,4BAA4B;AAAA,MACpC,MAAM,EAAE,QAAQ;AAAA,MAChB,SAAS,EAAE,WAAW,uBAAuB,IAAI,MAAM;AAAA,MACvD,YAAY,IAAI;AAAA,MAChB,SAAS,EAAE;AAAA,IACb,CAAC;AAAA,EACH;AACA,SAAO;AACT;","names":["ThrottleError"]}