@tagadapay/headless-sdk 1.8.0-rc.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/README.md +216 -1
  2. package/dist/core/client.d.ts +68 -0
  3. package/dist/core/client.d.ts.map +1 -0
  4. package/dist/core/client.js +73 -0
  5. package/dist/core/client.js.map +1 -0
  6. package/dist/core/errors.d.ts +53 -0
  7. package/dist/core/errors.d.ts.map +1 -0
  8. package/dist/core/errors.js +58 -0
  9. package/dist/core/errors.js.map +1 -0
  10. package/dist/core/helpers/autocomplete.d.ts +89 -0
  11. package/dist/core/helpers/autocomplete.d.ts.map +1 -0
  12. package/dist/core/helpers/autocomplete.js +186 -0
  13. package/dist/core/helpers/autocomplete.js.map +1 -0
  14. package/dist/core/helpers/countries.d.ts +45 -0
  15. package/dist/core/helpers/countries.d.ts.map +1 -0
  16. package/dist/core/helpers/countries.js +65 -0
  17. package/dist/core/helpers/countries.js.map +1 -0
  18. package/dist/core/helpers/currency.d.ts +26 -0
  19. package/dist/core/helpers/currency.d.ts.map +1 -0
  20. package/dist/core/helpers/currency.js +72 -0
  21. package/dist/core/helpers/currency.js.map +1 -0
  22. package/dist/core/helpers/index.d.ts +6 -0
  23. package/dist/core/helpers/index.d.ts.map +1 -0
  24. package/dist/core/helpers/index.js +6 -0
  25. package/dist/core/helpers/index.js.map +1 -0
  26. package/dist/core/helpers/iso3166.d.ts +28 -0
  27. package/dist/core/helpers/iso3166.d.ts.map +1 -0
  28. package/dist/core/helpers/iso3166.js +84 -0
  29. package/dist/core/helpers/iso3166.js.map +1 -0
  30. package/dist/core/helpers/walletContact.d.ts +67 -0
  31. package/dist/core/helpers/walletContact.d.ts.map +1 -0
  32. package/dist/core/helpers/walletContact.js +71 -0
  33. package/dist/core/helpers/walletContact.js.map +1 -0
  34. package/dist/core/http.d.ts +27 -0
  35. package/dist/core/http.d.ts.map +1 -0
  36. package/dist/core/http.js +125 -0
  37. package/dist/core/http.js.map +1 -0
  38. package/dist/core/index.d.ts +15 -0
  39. package/dist/core/index.d.ts.map +1 -0
  40. package/dist/core/index.js +13 -0
  41. package/dist/core/index.js.map +1 -0
  42. package/dist/core/modules/catalog.d.ts +27 -0
  43. package/dist/core/modules/catalog.d.ts.map +1 -0
  44. package/dist/core/modules/catalog.js +38 -0
  45. package/dist/core/modules/catalog.js.map +1 -0
  46. package/dist/core/modules/checkout.d.ts +268 -0
  47. package/dist/core/modules/checkout.d.ts.map +1 -0
  48. package/dist/core/modules/checkout.js +470 -0
  49. package/dist/core/modules/checkout.js.map +1 -0
  50. package/dist/core/modules/customer.d.ts +33 -0
  51. package/dist/core/modules/customer.d.ts.map +1 -0
  52. package/dist/core/modules/customer.js +53 -0
  53. package/dist/core/modules/customer.js.map +1 -0
  54. package/dist/core/modules/funnel.d.ts +38 -0
  55. package/dist/core/modules/funnel.d.ts.map +1 -0
  56. package/dist/core/modules/funnel.js +143 -0
  57. package/dist/core/modules/funnel.js.map +1 -0
  58. package/dist/core/modules/offers.d.ts +137 -0
  59. package/dist/core/modules/offers.d.ts.map +1 -0
  60. package/dist/core/modules/offers.js +141 -0
  61. package/dist/core/modules/offers.js.map +1 -0
  62. package/dist/core/modules/payment.d.ts +353 -0
  63. package/dist/core/modules/payment.d.ts.map +1 -0
  64. package/dist/core/modules/payment.js +784 -0
  65. package/dist/core/modules/payment.js.map +1 -0
  66. package/dist/core/modules/rx.d.ts +162 -0
  67. package/dist/core/modules/rx.d.ts.map +1 -0
  68. package/dist/core/modules/rx.js +46 -0
  69. package/dist/core/modules/rx.js.map +1 -0
  70. package/dist/core/types.d.ts +532 -0
  71. package/dist/core/types.d.ts.map +1 -0
  72. package/dist/core/types.js +5 -0
  73. package/dist/core/types.js.map +1 -0
  74. package/dist/index.d.ts.map +1 -0
  75. package/dist/index.js.map +1 -0
  76. package/dist/react/hooks/useCatalog.d.ts +25 -0
  77. package/dist/react/hooks/useCatalog.d.ts.map +1 -0
  78. package/dist/react/hooks/useCatalog.js +58 -0
  79. package/dist/react/hooks/useCatalog.js.map +1 -0
  80. package/dist/react/hooks/useCheckout.d.ts +58 -0
  81. package/dist/react/hooks/useCheckout.d.ts.map +1 -0
  82. package/dist/react/hooks/useCheckout.js +177 -0
  83. package/dist/react/hooks/useCheckout.js.map +1 -0
  84. package/dist/react/hooks/useCustomer.d.ts +28 -0
  85. package/dist/react/hooks/useCustomer.d.ts.map +1 -0
  86. package/dist/react/hooks/useCustomer.js +77 -0
  87. package/dist/react/hooks/useCustomer.js.map +1 -0
  88. package/dist/react/hooks/useGoogleAutocomplete.d.ts +26 -0
  89. package/dist/react/hooks/useGoogleAutocomplete.d.ts.map +1 -0
  90. package/dist/react/hooks/useGoogleAutocomplete.js +70 -0
  91. package/dist/react/hooks/useGoogleAutocomplete.js.map +1 -0
  92. package/dist/react/hooks/useISOData.d.ts +23 -0
  93. package/dist/react/hooks/useISOData.d.ts.map +1 -0
  94. package/dist/react/hooks/useISOData.js +63 -0
  95. package/dist/react/hooks/useISOData.js.map +1 -0
  96. package/dist/react/hooks/useOffers.d.ts +134 -0
  97. package/dist/react/hooks/useOffers.d.ts.map +1 -0
  98. package/dist/react/hooks/useOffers.js +171 -0
  99. package/dist/react/hooks/useOffers.js.map +1 -0
  100. package/dist/react/hooks/usePayment.d.ts +117 -0
  101. package/dist/react/hooks/usePayment.d.ts.map +1 -0
  102. package/dist/react/hooks/usePayment.js +233 -0
  103. package/dist/react/hooks/usePayment.js.map +1 -0
  104. package/dist/react/hooks/useRx.d.ts +64 -0
  105. package/dist/react/hooks/useRx.d.ts.map +1 -0
  106. package/dist/react/hooks/useRx.js +145 -0
  107. package/dist/react/hooks/useRx.js.map +1 -0
  108. package/dist/react/index.d.ts +22 -0
  109. package/dist/react/index.d.ts.map +1 -0
  110. package/dist/react/index.js +12 -0
  111. package/dist/react/index.js.map +1 -0
  112. package/dist/react/internal/redirectGuard.d.ts +9 -0
  113. package/dist/react/internal/redirectGuard.d.ts.map +1 -0
  114. package/dist/react/internal/redirectGuard.js +25 -0
  115. package/dist/react/internal/redirectGuard.js.map +1 -0
  116. package/dist/react/provider.d.ts +31 -0
  117. package/dist/react/provider.d.ts.map +1 -0
  118. package/dist/react/provider.js +32 -0
  119. package/dist/react/provider.js.map +1 -0
  120. package/dist/stripe/StripeExpressButton.d.ts +30 -0
  121. package/dist/stripe/StripeExpressButton.d.ts.map +1 -0
  122. package/dist/stripe/StripeExpressButton.js +32 -0
  123. package/dist/stripe/StripeExpressButton.js.map +1 -0
  124. package/dist/stripe/StripeExpressCheckout.d.ts +109 -0
  125. package/dist/stripe/StripeExpressCheckout.d.ts.map +1 -0
  126. package/dist/stripe/StripeExpressCheckout.js +242 -0
  127. package/dist/stripe/StripeExpressCheckout.js.map +1 -0
  128. package/dist/stripe/index.d.ts +8 -0
  129. package/dist/stripe/index.d.ts.map +1 -0
  130. package/dist/stripe/index.js +15 -0
  131. package/dist/stripe/index.js.map +1 -0
  132. package/dist/stripe/useStripeExpress.d.ts +54 -0
  133. package/dist/stripe/useStripeExpress.d.ts.map +1 -0
  134. package/dist/stripe/useStripeExpress.js +125 -0
  135. package/dist/stripe/useStripeExpress.js.map +1 -0
  136. package/dist/tagada-headless-react.min.js +8 -0
  137. package/dist/tagada-headless-react.min.js.map +7 -0
  138. package/dist/tagada-headless.js +2423 -0
  139. package/dist/tagada-headless.min.js +8 -0
  140. package/dist/tagada-headless.min.js.map +7 -0
  141. package/package.json +79 -73
@@ -0,0 +1,30 @@
1
+ import React from 'react';
2
+ import type { UseStripeExpressOptions } from './useStripeExpress.js';
3
+ export type StripeExpressButtonProps = UseStripeExpressOptions & {
4
+ /** CSS class for the wrapper div. */
5
+ className?: string;
6
+ /** Inline style for the wrapper div. */
7
+ style?: React.CSSProperties;
8
+ };
9
+ /**
10
+ * Drop-in React component that renders Stripe Express Checkout buttons
11
+ * (Apple Pay, Google Pay, Link, etc.).
12
+ *
13
+ * Internally uses `useStripeExpress` which handles the full flow:
14
+ * discover config -> load Stripe -> mount ECE -> confirm -> poll -> callbacks.
15
+ *
16
+ * @example
17
+ * ```tsx
18
+ * import { StripeExpressButton } from '@tagadapay/headless-sdk/stripe';
19
+ *
20
+ * <StripeExpressButton
21
+ * checkoutSessionId={session.id}
22
+ * amount={totals.total}
23
+ * currency={totals.currency}
24
+ * onSuccess={() => router.push('/confirmation')}
25
+ * onError={(msg) => toast.error(msg)}
26
+ * />
27
+ * ```
28
+ */
29
+ export declare function StripeExpressButton({ className, style, ...hookOpts }: StripeExpressButtonProps): import("react/jsx-runtime.js").JSX.Element;
30
+ //# sourceMappingURL=StripeExpressButton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StripeExpressButton.d.ts","sourceRoot":"","sources":["../../src/stripe/StripeExpressButton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAErE,MAAM,MAAM,wBAAwB,GAAG,uBAAuB,GAAG;IAC/D,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wCAAwC;IACxC,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,SAAS,EACT,KAAK,EACL,GAAG,QAAQ,EACZ,EAAE,wBAAwB,8CAe1B"}
@@ -0,0 +1,32 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useStripeExpress } from './useStripeExpress.js';
3
+ /**
4
+ * Drop-in React component that renders Stripe Express Checkout buttons
5
+ * (Apple Pay, Google Pay, Link, etc.).
6
+ *
7
+ * Internally uses `useStripeExpress` which handles the full flow:
8
+ * discover config -> load Stripe -> mount ECE -> confirm -> poll -> callbacks.
9
+ *
10
+ * @example
11
+ * ```tsx
12
+ * import { StripeExpressButton } from '@tagadapay/headless-sdk/stripe';
13
+ *
14
+ * <StripeExpressButton
15
+ * checkoutSessionId={session.id}
16
+ * amount={totals.total}
17
+ * currency={totals.currency}
18
+ * onSuccess={() => router.push('/confirmation')}
19
+ * onError={(msg) => toast.error(msg)}
20
+ * />
21
+ * ```
22
+ */
23
+ export function StripeExpressButton({ className, style, ...hookOpts }) {
24
+ const { containerRef, isReady } = useStripeExpress(hookOpts);
25
+ return (_jsx("div", { ref: containerRef, className: className, style: {
26
+ visibility: isReady ? 'visible' : 'hidden',
27
+ minHeight: isReady ? undefined : 0,
28
+ overflow: isReady ? undefined : 'hidden',
29
+ ...style,
30
+ } }));
31
+ }
32
+ //# sourceMappingURL=StripeExpressButton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StripeExpressButton.js","sourceRoot":"","sources":["../../src/stripe/StripeExpressButton.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAUzD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,mBAAmB,CAAC,EAClC,SAAS,EACT,KAAK,EACL,GAAG,QAAQ,EACc;IACzB,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAE7D,OAAO,CACL,cACE,GAAG,EAAE,YAAY,EACjB,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE;YACL,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ;YAC1C,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;YAClC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ;YACxC,GAAG,KAAK;SACT,GACD,CACH,CAAC;AACJ,CAAC"}
@@ -0,0 +1,109 @@
1
+ import type { HeadlessClient } from '../core/client.js';
2
+ import type { StripeExpressOptions, PaymentStatus } from '../core/types.js';
3
+ type EventMap = {
4
+ ready: {
5
+ availablePaymentMethods: Record<string, boolean> | undefined;
6
+ };
7
+ success: {
8
+ payment: PaymentStatus;
9
+ order?: {
10
+ id: string;
11
+ checkoutSessionId?: string;
12
+ };
13
+ };
14
+ error: string;
15
+ cancel: void;
16
+ };
17
+ type EventHandler<K extends keyof EventMap> = (data: EventMap[K]) => void;
18
+ /**
19
+ * Session-based Stripe Express Checkout integration.
20
+ *
21
+ * Mounts the Stripe `ExpressCheckoutElement` (Apple Pay, Google Pay, Link,
22
+ * Klarna express) into any DOM container, wired to a Tagada
23
+ * checkout session. Drives the full flow:
24
+ * mount &rarr; wallet confirm &rarr; backend `payDirect` (`processStripeExpress`)
25
+ * &rarr; `stripe.confirmPayment` &rarr; poll payment status &rarr; emit `success`.
26
+ *
27
+ * **Session-free / partner S2S flow?** Use the lower-level primitive
28
+ * `startStripeExpressCheckout` exported from `@tagadapay/core-js`
29
+ * (also re-exported from `@tagadapay/headless-sdk/stripe`). It uses
30
+ * Stripe's older Payment Request API, stops at tokenization, and
31
+ * returns a `paymentMethodId` for partner-server-side processing.
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * import { createHeadlessClient } from '@tagadapay/headless-sdk';
36
+ * import { StripeExpressCheckout } from '@tagadapay/headless-sdk/stripe';
37
+ *
38
+ * const client = createHeadlessClient({ storeId: 'store_xxx' });
39
+ * const session = await client.checkout.loadSession(checkoutToken);
40
+ * const express = await client.payment.getExpressMethods(session.id);
41
+ *
42
+ * const ece = new StripeExpressCheckout({
43
+ * client,
44
+ * publishableKey: express.applePay?.publishableKey!,
45
+ * processorId: express.applePay?.processorId!,
46
+ * });
47
+ *
48
+ * ece.on('success', ({ payment }) => console.log('Paid!', payment.id));
49
+ * ece.on('error', (msg) => console.error(msg));
50
+ *
51
+ * await ece.mount(document.getElementById('express-container')!, {
52
+ * checkoutSessionId: session.id,
53
+ * amount: session.totals.total,
54
+ * currency: session.totals.currency,
55
+ * });
56
+ * ```
57
+ */
58
+ export declare class StripeExpressCheckout {
59
+ private stripe;
60
+ private elements;
61
+ private expressElement;
62
+ private container;
63
+ private isProcessing;
64
+ private listeners;
65
+ private readonly client;
66
+ private readonly publishableKey;
67
+ private readonly processorId;
68
+ private readonly enabledMethods;
69
+ private readonly buttonHeight;
70
+ private readonly buttonType;
71
+ private readonly emailRequired;
72
+ private readonly billingAddressRequired;
73
+ private readonly shippingAddressRequired;
74
+ constructor(opts: {
75
+ client: HeadlessClient;
76
+ } & StripeExpressOptions);
77
+ on<K extends keyof EventMap>(event: K, handler: EventHandler<K>): void;
78
+ off<K extends keyof EventMap>(event: K, handler: EventHandler<K>): void;
79
+ /**
80
+ * Load Stripe.js, create Elements, and mount the ExpressCheckoutElement.
81
+ */
82
+ mount(container: HTMLElement, opts: {
83
+ checkoutSessionId: string;
84
+ amount: number;
85
+ currency: string;
86
+ }): Promise<void>;
87
+ /**
88
+ * Update the payment amount (e.g. after a cart change).
89
+ */
90
+ updateAmount(amount: number, currency?: string): void;
91
+ /**
92
+ * Write the wallet-approved contact onto the session before the charge.
93
+ *
94
+ * `billingAddressRequired` defaults to true, so Stripe collects an address on
95
+ * every express purchase; `shippingAddressRequired` adds a delivery address
96
+ * for carts that ship. Whichever arrives is mapped and stored — a contact
97
+ * with no street line or no country maps to `undefined` and leaves the
98
+ * session untouched, so this can never blank an address already entered.
99
+ */
100
+ private syncWalletContact;
101
+ /**
102
+ * Clean up: unmount the element and release references.
103
+ */
104
+ unmount(): void;
105
+ private emit;
106
+ private extractClientSecret;
107
+ }
108
+ export {};
109
+ //# sourceMappingURL=StripeExpressCheckout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StripeExpressCheckout.d.ts","sourceRoot":"","sources":["../../src/stripe/StripeExpressCheckout.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,KAAK,EAAE,oBAAoB,EAAa,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAcvF,KAAK,QAAQ,GAAG;IACd,KAAK,EAAE;QAAE,uBAAuB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAA;KAAE,CAAC;IACxE,OAAO,EAAE;QAAE,OAAO,EAAE,aAAa,CAAC;QAAC,KAAK,CAAC,EAAE;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;IACxF,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,IAAI,CAAC;CACd,CAAC;AAEF,KAAK,YAAY,CAAC,CAAC,SAAS,MAAM,QAAQ,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;AAE1E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,qBAAa,qBAAqB;IAChC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,QAAQ,CAA+B;IAC/C,OAAO,CAAC,cAAc,CAA2C;IACjE,OAAO,CAAC,SAAS,CAA4B;IAC7C,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,SAAS,CAAwD;IAEzE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IACxC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAW;IAC1C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAU;IACxC,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAU;IACjD,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAU;gBAEtC,IAAI,EAAE;QAAE,MAAM,EAAE,cAAc,CAAA;KAAE,GAAG,oBAAoB;IAcnE,EAAE,CAAC,CAAC,SAAS,MAAM,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI;IAOtE,GAAG,CAAC,CAAC,SAAS,MAAM,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI;IAIvE;;OAEG;IACG,KAAK,CACT,SAAS,EAAE,WAAW,EACtB,IAAI,EAAE;QAAE,iBAAiB,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GACpE,OAAO,CAAC,IAAI,CAAC;IA6HhB;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI;IAOrD;;;;;;;;OAQG;YACW,iBAAiB;IAsB/B;;OAEG;IACH,OAAO,IAAI,IAAI;IASf,OAAO,CAAC,IAAI;IAIZ,OAAO,CAAC,mBAAmB;CAS5B"}
@@ -0,0 +1,242 @@
1
+ import { stripeContactToAddress } from '../core/helpers/walletContact.js';
2
+ const EXPRESS_METHOD_KEYS = ['apple_pay', 'google_pay', 'link', 'klarna_express'];
3
+ /**
4
+ * Session-based Stripe Express Checkout integration.
5
+ *
6
+ * Mounts the Stripe `ExpressCheckoutElement` (Apple Pay, Google Pay, Link,
7
+ * Klarna express) into any DOM container, wired to a Tagada
8
+ * checkout session. Drives the full flow:
9
+ * mount &rarr; wallet confirm &rarr; backend `payDirect` (`processStripeExpress`)
10
+ * &rarr; `stripe.confirmPayment` &rarr; poll payment status &rarr; emit `success`.
11
+ *
12
+ * **Session-free / partner S2S flow?** Use the lower-level primitive
13
+ * `startStripeExpressCheckout` exported from `@tagadapay/core-js`
14
+ * (also re-exported from `@tagadapay/headless-sdk/stripe`). It uses
15
+ * Stripe's older Payment Request API, stops at tokenization, and
16
+ * returns a `paymentMethodId` for partner-server-side processing.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * import { createHeadlessClient } from '@tagadapay/headless-sdk';
21
+ * import { StripeExpressCheckout } from '@tagadapay/headless-sdk/stripe';
22
+ *
23
+ * const client = createHeadlessClient({ storeId: 'store_xxx' });
24
+ * const session = await client.checkout.loadSession(checkoutToken);
25
+ * const express = await client.payment.getExpressMethods(session.id);
26
+ *
27
+ * const ece = new StripeExpressCheckout({
28
+ * client,
29
+ * publishableKey: express.applePay?.publishableKey!,
30
+ * processorId: express.applePay?.processorId!,
31
+ * });
32
+ *
33
+ * ece.on('success', ({ payment }) => console.log('Paid!', payment.id));
34
+ * ece.on('error', (msg) => console.error(msg));
35
+ *
36
+ * await ece.mount(document.getElementById('express-container')!, {
37
+ * checkoutSessionId: session.id,
38
+ * amount: session.totals.total,
39
+ * currency: session.totals.currency,
40
+ * });
41
+ * ```
42
+ */
43
+ export class StripeExpressCheckout {
44
+ constructor(opts) {
45
+ this.stripe = null;
46
+ this.elements = null;
47
+ this.expressElement = null;
48
+ this.container = null;
49
+ this.isProcessing = false;
50
+ this.listeners = {};
51
+ this.client = opts.client;
52
+ this.publishableKey = opts.publishableKey;
53
+ this.processorId = opts.processorId;
54
+ this.enabledMethods = opts.enabledMethods ?? [...EXPRESS_METHOD_KEYS];
55
+ this.buttonHeight = opts.buttonHeight ?? 48;
56
+ this.buttonType = opts.buttonType ?? 'buy';
57
+ this.emailRequired = opts.emailRequired ?? true;
58
+ this.billingAddressRequired = opts.billingAddressRequired ?? true;
59
+ // Opt-in: asking for a delivery address in the sheet changes what the buyer
60
+ // sees, so it stays off until a storefront selling physical goods says yes.
61
+ this.shippingAddressRequired = opts.shippingAddressRequired ?? false;
62
+ }
63
+ on(event, handler) {
64
+ if (!this.listeners[event]) {
65
+ this.listeners[event] = new Set();
66
+ }
67
+ this.listeners[event].add(handler);
68
+ }
69
+ off(event, handler) {
70
+ this.listeners[event]?.delete(handler);
71
+ }
72
+ /**
73
+ * Load Stripe.js, create Elements, and mount the ExpressCheckoutElement.
74
+ */
75
+ async mount(container, opts) {
76
+ this.container = container;
77
+ const { loadStripe } = await import('@stripe/stripe-js');
78
+ const stripe = await loadStripe(this.publishableKey);
79
+ if (!stripe) {
80
+ this.emit('error', 'Failed to load Stripe.js');
81
+ return;
82
+ }
83
+ this.stripe = stripe;
84
+ const amount = Math.max(Math.round(opts.amount), 1);
85
+ const currency = opts.currency.toLowerCase();
86
+ this.elements = stripe.elements({
87
+ mode: 'payment',
88
+ amount,
89
+ currency,
90
+ });
91
+ const methodEnabled = (key) => this.enabledMethods.includes(key);
92
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Stripe TS types don't expose expressCheckout overload
93
+ this.expressElement = this.elements.create('expressCheckout', {
94
+ buttonType: {
95
+ applePay: this.buttonType,
96
+ googlePay: this.buttonType,
97
+ },
98
+ buttonHeight: this.buttonHeight,
99
+ paymentMethods: {
100
+ applePay: methodEnabled('apple_pay') ? 'always' : 'never',
101
+ googlePay: methodEnabled('google_pay') ? 'always' : 'never',
102
+ link: methodEnabled('link') ? 'auto' : 'never',
103
+ klarna: methodEnabled('klarna_express') ? 'auto' : 'never',
104
+ },
105
+ emailRequired: this.emailRequired,
106
+ billingAddressRequired: this.billingAddressRequired,
107
+ shippingAddressRequired: this.shippingAddressRequired,
108
+ });
109
+ this.expressElement.on('ready', ({ availablePaymentMethods }) => {
110
+ if (availablePaymentMethods) {
111
+ this.emit('ready', { availablePaymentMethods });
112
+ }
113
+ });
114
+ this.expressElement.on('cancel', () => {
115
+ this.isProcessing = false;
116
+ this.emit('cancel', undefined);
117
+ });
118
+ this.expressElement.on('confirm', async (event) => {
119
+ if (this.isProcessing)
120
+ return;
121
+ this.isProcessing = true;
122
+ try {
123
+ const { error: submitError } = await this.elements.submit();
124
+ if (submitError) {
125
+ this.emit('error', submitError.message ?? 'Validation failed');
126
+ this.isProcessing = false;
127
+ return;
128
+ }
129
+ // The buyer approved an address inside the wallet sheet and this
130
+ // element owns that sheet, so the address is ours to persist — no
131
+ // integrator code required (#TAG-1989). Before this, `billingDetails`
132
+ // arrived on every confirm and was dropped, and the order was created
133
+ // with NULL addresses.
134
+ try {
135
+ await this.syncWalletContact(opts.checkoutSessionId, event);
136
+ }
137
+ catch {
138
+ this.emit('error', 'Could not save your address. Please try again.');
139
+ this.isProcessing = false;
140
+ return;
141
+ }
142
+ const payResult = await this.client.payment.processStripeExpress({
143
+ checkoutSessionId: opts.checkoutSessionId,
144
+ processorId: this.processorId,
145
+ paymentMethod: event.expressPaymentType,
146
+ });
147
+ const clientSecret = this.extractClientSecret(payResult);
148
+ if (!clientSecret) {
149
+ this.emit('error', 'Express checkout configuration missing — no client secret returned');
150
+ this.isProcessing = false;
151
+ return;
152
+ }
153
+ const { error: confirmError } = await this.stripe.confirmPayment({
154
+ elements: this.elements,
155
+ clientSecret,
156
+ confirmParams: { return_url: window.location.href },
157
+ redirect: 'if_required',
158
+ });
159
+ if (confirmError) {
160
+ this.emit('error', confirmError.message ?? 'Payment confirmation failed');
161
+ this.isProcessing = false;
162
+ return;
163
+ }
164
+ const paymentId = payResult.payment.id;
165
+ const status = await this.client.payment.pollPaymentStatus(paymentId);
166
+ if (status.status === 'succeeded') {
167
+ this.emit('success', { payment: status, order: status.order });
168
+ }
169
+ else {
170
+ this.emit('error', `Payment ${status.status}`);
171
+ }
172
+ }
173
+ catch (err) {
174
+ const msg = err instanceof Error ? err.message : 'Express checkout failed';
175
+ this.emit('error', msg);
176
+ }
177
+ finally {
178
+ this.isProcessing = false;
179
+ }
180
+ });
181
+ this.expressElement.mount(container);
182
+ }
183
+ /**
184
+ * Update the payment amount (e.g. after a cart change).
185
+ */
186
+ updateAmount(amount, currency) {
187
+ if (!this.elements)
188
+ return;
189
+ const update = { amount: Math.max(Math.round(amount), 1) };
190
+ if (currency)
191
+ update.currency = currency.toLowerCase();
192
+ this.elements.update(update);
193
+ }
194
+ /**
195
+ * Write the wallet-approved contact onto the session before the charge.
196
+ *
197
+ * `billingAddressRequired` defaults to true, so Stripe collects an address on
198
+ * every express purchase; `shippingAddressRequired` adds a delivery address
199
+ * for carts that ship. Whichever arrives is mapped and stored — a contact
200
+ * with no street line or no country maps to `undefined` and leaves the
201
+ * session untouched, so this can never blank an address already entered.
202
+ */
203
+ async syncWalletContact(checkoutSessionId, event) {
204
+ const billingAddress = stripeContactToAddress(event.billingDetails);
205
+ const shippingAddress = stripeContactToAddress(event.shippingAddress);
206
+ if (!billingAddress && !shippingAddress)
207
+ return;
208
+ const customer = {};
209
+ const email = event.billingDetails?.email ?? event.shippingAddress?.email;
210
+ const phone = event.billingDetails?.phone ?? event.shippingAddress?.phone;
211
+ if (email)
212
+ customer.email = email;
213
+ if (phone)
214
+ customer.phone = phone;
215
+ await this.client.checkout.updateCustomerAndAddress(checkoutSessionId, {
216
+ customer,
217
+ shippingAddress,
218
+ billingAddress,
219
+ });
220
+ }
221
+ /**
222
+ * Clean up: unmount the element and release references.
223
+ */
224
+ unmount() {
225
+ this.expressElement?.unmount();
226
+ this.expressElement = null;
227
+ this.elements = null;
228
+ this.stripe = null;
229
+ this.container = null;
230
+ this.listeners = {};
231
+ }
232
+ emit(event, data) {
233
+ this.listeners[event]?.forEach((handler) => handler(data));
234
+ }
235
+ extractClientSecret(payResult) {
236
+ return payResult.payment?.requireActionData?.metadata?.stripeExpressCheckout
237
+ ? (payResult.payment.requireActionData.metadata
238
+ .stripeExpressCheckout.clientSecret)
239
+ : undefined;
240
+ }
241
+ }
242
+ //# sourceMappingURL=StripeExpressCheckout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StripeExpressCheckout.js","sourceRoot":"","sources":["../../src/stripe/StripeExpressCheckout.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export { StripeExpressCheckout } from './StripeExpressCheckout.js';
2
+ export { useStripeExpress } from './useStripeExpress.js';
3
+ export type { UseStripeExpressOptions, UseStripeExpressReturn } from './useStripeExpress.js';
4
+ export { StripeExpressButton } from './StripeExpressButton.js';
5
+ export type { StripeExpressButtonProps } from './StripeExpressButton.js';
6
+ export type { StripeExpressOptions } from '../core/types.js';
7
+ export { startStripeExpressCheckout, isStripeExpressAvailable, type StripeExpressOptions as CoreStripeExpressOptions, type StripeExpressShippingAddress, type StripeExpressTokenResult, type StripeExpressCallbacks, } from '@tagadapay/core-js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/stripe/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAEnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,YAAY,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAE7F,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,YAAY,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAEzE,YAAY,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAO7D,OAAO,EACL,0BAA0B,EAC1B,wBAAwB,EACxB,KAAK,oBAAoB,IAAI,wBAAwB,EACrD,KAAK,4BAA4B,EACjC,KAAK,wBAAwB,EAC7B,KAAK,sBAAsB,GAC5B,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,15 @@
1
+ // ─────────────────────────────────────────────────────────────────
2
+ // Session-based Stripe Express Checkout — drives Stripe's Express
3
+ // Checkout Element (drop-in widget) wired to a checkout session.
4
+ // Used by sites built on `@tagadapay/headless-sdk`.
5
+ // ─────────────────────────────────────────────────────────────────
6
+ export { StripeExpressCheckout } from './StripeExpressCheckout.js';
7
+ export { useStripeExpress } from './useStripeExpress.js';
8
+ export { StripeExpressButton } from './StripeExpressButton.js';
9
+ // ─────────────────────────────────────────────────────────────────
10
+ // Session-free wallet tokenization — re-exported from `@tagadapay/core-js`
11
+ // for partner / S2S flows that don't use a checkout session. Stops at
12
+ // Stripe `paymentMethodId`; the partner forwards it to their server.
13
+ // ─────────────────────────────────────────────────────────────────
14
+ export { startStripeExpressCheckout, isStripeExpressAvailable, } from '@tagadapay/core-js';
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/stripe/index.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,kEAAkE;AAClE,iEAAiE;AACjE,oDAAoD;AACpD,oEAAoE;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAEnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAGzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAK/D,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,qEAAqE;AACrE,oEAAoE;AACpE,OAAO,EACL,0BAA0B,EAC1B,wBAAwB,GAKzB,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,54 @@
1
+ import type { ExpressMethods, PaymentStatus, PaymentSetupConfig } from '../core/types.js';
2
+ export interface UseStripeExpressOptions {
3
+ checkoutSessionId: string;
4
+ amount: number;
5
+ currency: string;
6
+ onSuccess?: (result: {
7
+ payment: PaymentStatus;
8
+ order?: {
9
+ id: string;
10
+ checkoutSessionId?: string;
11
+ };
12
+ }) => void;
13
+ onError?: (error: string) => void;
14
+ onCancel?: () => void;
15
+ /** Override payment setup config (skips API discovery). */
16
+ paymentSetupConfig?: PaymentSetupConfig;
17
+ }
18
+ export interface UseStripeExpressReturn {
19
+ /** Attach this ref to a <div> — the express buttons will mount inside it. */
20
+ containerRef: React.RefObject<HTMLDivElement | null>;
21
+ /** True once the Stripe element has rendered at least one wallet button. */
22
+ isReady: boolean;
23
+ /** True while a payment is being confirmed. */
24
+ isProcessing: boolean;
25
+ /** Discovered express methods (null while loading). */
26
+ expressMethods: ExpressMethods | null;
27
+ /** Update the displayed amount after cart changes. */
28
+ updateAmount: (amount: number, currency?: string) => void;
29
+ }
30
+ /**
31
+ * React hook that mounts the Stripe Express Checkout Element into a ref'd container.
32
+ *
33
+ * Handles the full lifecycle: discover config -> load Stripe -> mount ECE ->
34
+ * onConfirm -> processStripeExpress -> stripe.confirmPayment -> poll -> callbacks.
35
+ *
36
+ * @example
37
+ * ```tsx
38
+ * import { useStripeExpress } from '@tagadapay/headless-sdk/stripe';
39
+ *
40
+ * function ExpressSection({ sessionId, totals }) {
41
+ * const { containerRef, isReady } = useStripeExpress({
42
+ * checkoutSessionId: sessionId,
43
+ * amount: totals.total,
44
+ * currency: totals.currency,
45
+ * onSuccess: () => router.push('/confirmation'),
46
+ * onError: (msg) => toast.error(msg),
47
+ * });
48
+ *
49
+ * return <div ref={containerRef} style={{ display: isReady ? 'block' : 'none' }} />;
50
+ * }
51
+ * ```
52
+ */
53
+ export declare function useStripeExpress(opts: UseStripeExpressOptions): UseStripeExpressReturn;
54
+ //# sourceMappingURL=useStripeExpress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useStripeExpress.d.ts","sourceRoot":"","sources":["../../src/stripe/useStripeExpress.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAE1F,MAAM,WAAW,uBAAuB;IACtC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,aAAa,CAAC;QAAC,KAAK,CAAC,EAAE;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,KAAK,IAAI,CAAC;IAC7G,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,2DAA2D;IAC3D,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;CACzC;AAED,MAAM,WAAW,sBAAsB;IACrC,6EAA6E;IAC7E,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IACrD,4EAA4E;IAC5E,OAAO,EAAE,OAAO,CAAC;IACjB,+CAA+C;IAC/C,YAAY,EAAE,OAAO,CAAC;IACtB,uDAAuD;IACvD,cAAc,EAAE,cAAc,GAAG,IAAI,CAAC;IACtC,sDAAsD;IACtD,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3D;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,uBAAuB,GAAG,sBAAsB,CAoFtF"}
@@ -0,0 +1,125 @@
1
+ import { useState, useRef, useEffect, useCallback } from 'react';
2
+ import { useHeadlessClient } from '../react/provider.js';
3
+ import { StripeExpressCheckout } from './StripeExpressCheckout.js';
4
+ /**
5
+ * React hook that mounts the Stripe Express Checkout Element into a ref'd container.
6
+ *
7
+ * Handles the full lifecycle: discover config -> load Stripe -> mount ECE ->
8
+ * onConfirm -> processStripeExpress -> stripe.confirmPayment -> poll -> callbacks.
9
+ *
10
+ * @example
11
+ * ```tsx
12
+ * import { useStripeExpress } from '@tagadapay/headless-sdk/stripe';
13
+ *
14
+ * function ExpressSection({ sessionId, totals }) {
15
+ * const { containerRef, isReady } = useStripeExpress({
16
+ * checkoutSessionId: sessionId,
17
+ * amount: totals.total,
18
+ * currency: totals.currency,
19
+ * onSuccess: () => router.push('/confirmation'),
20
+ * onError: (msg) => toast.error(msg),
21
+ * });
22
+ *
23
+ * return <div ref={containerRef} style={{ display: isReady ? 'block' : 'none' }} />;
24
+ * }
25
+ * ```
26
+ */
27
+ export function useStripeExpress(opts) {
28
+ const client = useHeadlessClient();
29
+ const containerRef = useRef(null);
30
+ const eceRef = useRef(null);
31
+ const [isReady, setIsReady] = useState(false);
32
+ const [isProcessing, setIsProcessing] = useState(false);
33
+ const [expressMethods, setExpressMethods] = useState(null);
34
+ const callbacksRef = useRef(opts);
35
+ callbacksRef.current = opts;
36
+ const { checkoutSessionId, amount, currency, paymentSetupConfig } = opts;
37
+ useEffect(() => {
38
+ if (!checkoutSessionId || !containerRef.current)
39
+ return;
40
+ let mounted = true;
41
+ let instance = null;
42
+ const init = async () => {
43
+ const express = await client.payment.getExpressMethods(checkoutSessionId, paymentSetupConfig ? { paymentSetupConfig } : undefined);
44
+ if (!mounted)
45
+ return;
46
+ setExpressMethods(express);
47
+ const stripeMethod = findStripeExpressMethod(express);
48
+ if (!stripeMethod?.publishableKey || !stripeMethod?.processorId)
49
+ return;
50
+ instance = new StripeExpressCheckout({
51
+ client,
52
+ publishableKey: stripeMethod.publishableKey,
53
+ processorId: stripeMethod.processorId,
54
+ enabledMethods: stripeMethod.enabledMethods,
55
+ });
56
+ instance.on('ready', () => {
57
+ if (mounted)
58
+ setIsReady(true);
59
+ });
60
+ instance.on('success', (result) => {
61
+ if (mounted)
62
+ setIsProcessing(false);
63
+ callbacksRef.current.onSuccess?.(result);
64
+ });
65
+ instance.on('error', (msg) => {
66
+ if (mounted)
67
+ setIsProcessing(false);
68
+ callbacksRef.current.onError?.(msg);
69
+ });
70
+ instance.on('cancel', () => {
71
+ if (mounted)
72
+ setIsProcessing(false);
73
+ callbacksRef.current.onCancel?.();
74
+ });
75
+ eceRef.current = instance;
76
+ if (containerRef.current) {
77
+ await instance.mount(containerRef.current, {
78
+ checkoutSessionId,
79
+ amount,
80
+ currency,
81
+ });
82
+ }
83
+ };
84
+ void init();
85
+ return () => {
86
+ mounted = false;
87
+ instance?.unmount();
88
+ eceRef.current = null;
89
+ setIsReady(false);
90
+ };
91
+ }, [client, checkoutSessionId, paymentSetupConfig]); // eslint-disable-line react-hooks/exhaustive-deps
92
+ useEffect(() => {
93
+ eceRef.current?.updateAmount(amount, currency);
94
+ }, [amount, currency]);
95
+ const updateAmount = useCallback((newAmount, newCurrency) => {
96
+ eceRef.current?.updateAmount(newAmount, newCurrency);
97
+ }, []);
98
+ return { containerRef, isReady, isProcessing, expressMethods, updateAmount };
99
+ }
100
+ /**
101
+ * Find a Stripe ECE-capable method from the express methods map.
102
+ * Returns publishableKey, processorId, and list of enabled sub-methods.
103
+ */
104
+ function findStripeExpressMethod(express) {
105
+ const allMethods = [
106
+ { key: 'apple_pay', entry: express.applePay },
107
+ { key: 'google_pay', entry: express.googlePay },
108
+ { key: 'link', entry: express.link },
109
+ { key: 'klarna_express', entry: express.klarna },
110
+ ];
111
+ for (const { entry } of allMethods) {
112
+ if (entry?.publishableKey && entry.processorId) {
113
+ const enabledMethods = allMethods
114
+ .filter(({ entry: e }) => e?.available && e.publishableKey === entry.publishableKey)
115
+ .map(({ key }) => key);
116
+ return {
117
+ publishableKey: entry.publishableKey,
118
+ processorId: entry.processorId,
119
+ enabledMethods,
120
+ };
121
+ }
122
+ }
123
+ return null;
124
+ }
125
+ //# sourceMappingURL=useStripeExpress.js.map