@tagadapay/headless-sdk 1.19.0 → 1.20.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/CHANGELOG.md +193 -0
  2. package/dist/core/helpers/cryptoOnchain.d.ts +83 -0
  3. package/dist/core/helpers/cryptoOnchain.d.ts.map +1 -0
  4. package/dist/core/helpers/cryptoOnchain.js +247 -0
  5. package/dist/core/helpers/cryptoOnchain.js.map +1 -0
  6. package/dist/core/helpers/oceanpayment.d.ts +33 -0
  7. package/dist/core/helpers/oceanpayment.d.ts.map +1 -0
  8. package/dist/core/helpers/oceanpayment.js +111 -0
  9. package/dist/core/helpers/oceanpayment.js.map +1 -0
  10. package/dist/core/http.d.ts.map +1 -1
  11. package/dist/core/http.js +3 -0
  12. package/dist/core/http.js.map +1 -1
  13. package/dist/core/index.d.ts +4 -2
  14. package/dist/core/index.d.ts.map +1 -1
  15. package/dist/core/index.js +2 -0
  16. package/dist/core/index.js.map +1 -1
  17. package/dist/core/modules/payment.d.ts +66 -1
  18. package/dist/core/modules/payment.d.ts.map +1 -1
  19. package/dist/core/modules/payment.js +297 -2
  20. package/dist/core/modules/payment.js.map +1 -1
  21. package/dist/core/modules/portal/types.d.ts +10 -1
  22. package/dist/core/modules/portal/types.d.ts.map +1 -1
  23. package/dist/core/modules/rx.d.ts +43 -0
  24. package/dist/core/modules/rx.d.ts.map +1 -1
  25. package/dist/core/modules/rx.js +13 -0
  26. package/dist/core/modules/rx.js.map +1 -1
  27. package/dist/core/types.d.ts +159 -0
  28. package/dist/core/types.d.ts.map +1 -1
  29. package/dist/core/version.d.ts +1 -1
  30. package/dist/core/version.js +1 -1
  31. package/dist/pixels/pixelMapping.d.ts.map +1 -1
  32. package/dist/pixels/pixelMapping.js +9 -1
  33. package/dist/pixels/pixelMapping.js.map +1 -1
  34. package/dist/react/hooks/useCryptoOnchainPayment.d.ts +40 -0
  35. package/dist/react/hooks/useCryptoOnchainPayment.d.ts.map +1 -0
  36. package/dist/react/hooks/useCryptoOnchainPayment.js +77 -0
  37. package/dist/react/hooks/useCryptoOnchainPayment.js.map +1 -0
  38. package/dist/react/hooks/usePayment.d.ts.map +1 -1
  39. package/dist/react/hooks/usePayment.js +3 -0
  40. package/dist/react/hooks/usePayment.js.map +1 -1
  41. package/dist/react/index.d.ts +4 -1
  42. package/dist/react/index.d.ts.map +1 -1
  43. package/dist/react/index.js +2 -0
  44. package/dist/react/index.js.map +1 -1
  45. package/dist/tagada-headless-commerce.min.js +1 -1
  46. package/dist/tagada-headless-react.min.js +2 -2
  47. package/dist/tagada-headless-react.min.js.map +4 -4
  48. package/dist/tagada-headless.js +626 -9
  49. package/dist/tagada-headless.min.js +2 -2
  50. package/dist/tagada-headless.min.js.map +4 -4
  51. package/dist/tagada-pixels.min.js +2 -2
  52. package/dist/tagada-pixels.min.js.map +3 -3
  53. package/package.json +3 -2
package/CHANGELOG.md ADDED
@@ -0,0 +1,193 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@tagadapay/headless-sdk`.
4
+
5
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); the package follows
6
+ [semantic versioning](https://semver.org/): major = breaking, minor = feature, patch = fix.
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [1.20.1] — 2026-10-22
11
+
12
+ ### Added
13
+
14
+ - Every request carries `X-Tagada-SDK: headless-sdk/<version>`, so the platform can tell which SDK version a store runs. No contract change.
15
+
16
+ ### Added
17
+
18
+ - `payment.mountOceanPayment({ checkoutSessionId, container, mode?, returnUrl?, locale?, signal? })`: pay a
19
+ checkout session with the merchant's own Ocean Payment account, the way the hosted checkout does. With
20
+ Ocean's public key on the integration, Ocean's card fields render in `container`; otherwise, or with
21
+ `mode: 'redirect'`, `pay()` sends the shopper to Ocean's page and back to `returnUrl` (default: the
22
+ current page). `payment.getOceanPaymentConfig(checkoutSessionId)` tells which of the two the store runs.
23
+ - `maybeResumeFromUrl()` and `usePayment()` resume an Ocean card payment after 3-D Secure, which returns
24
+ the shopper to the page with nothing in the URL.
25
+ - On-chain crypto (`crypto_onchain`), paid from your own page with no redirect:
26
+ `payment.getCryptoOnchainOptions(checkoutSessionId)` (networks and coins),
27
+ `payment.createCryptoOnchainPayment({ checkoutSessionId, chainId, asset })` (deposit address, exact amount,
28
+ wallet URI for the QR code; call again for another coin or an expired quote) and
29
+ `payment.getCryptoOnchainStatus({ checkoutSessionId, cryptoOnchainPaymentId })`. `payment.createCryptoOnchainCheckout()`
30
+ runs the whole flow (default network and coin, status polling, quote countdown, `onPaid` once confirmed) and
31
+ `useCryptoOnchainPayment()` is its React hook. Never send `crypto_onchain` to `pay()` / `processApm()`: the API
32
+ refuses it with `422 CRYPTO_ONCHAIN_INLINE_ONLY`.
33
+
34
+ ### Fixed
35
+
36
+ - Polling a payment (`processPayment()`, `resumeAfterRedirect()`, `pollPaymentStatus()`) stops at once on
37
+ `rejected` and `error` instead of waiting the full timeout and returning `pending`.
38
+
39
+ ## [1.20.0] — 2026-10-16
40
+
41
+ ### Added
42
+
43
+ - `rx.getIntakeContext({ orderId, checkoutToken })`: resume an unfinished Rx intake after the patient
44
+ closed the tab or opened the recovery email link. Returns the Rx line (`productId`, `variantId`) and
45
+ the basics on the order (name, email, phone, shipping address), or `{ caseExists: true }` once a case
46
+ is in. Date of birth and sex at birth are never returned: ask them again before `submitCase`.
47
+
48
+ ### Fixed
49
+
50
+ - `processPayment()` and `finalize()` no longer return `status: 'failed'` for a card payment paused on
51
+ Stripe Radar (`stripe_radar` action, the Tagada-managed processor included): they create the Radar
52
+ session with Stripe.js, resume the payment and return its real outcome, like the 3DS path.
53
+
54
+ ## [1.19.0] — 2026-10-09
55
+
56
+ ### Added
57
+
58
+ - `rx.validateIntake()`: checks the patient (US address in the 50 states or DC, US phone, 5 digit ZIP,
59
+ adult) and, once filled, the intake against the clinical network rules, without creating anything.
60
+ Call it before payment.
61
+ - `isQuestionActive(question, answers, { state, sexAtBirth })` and `toIntakeAnswers(...)`: render and
62
+ send the network questionnaire exactly like Tagada's storefronts (hidden questions, "Yes" follow-ups,
63
+ pregnancy for women only, hidden defaults).
64
+ - `RxClinicalQuestion` exposes `visible`, `rules`, `important`, `critical`, `label`, `defaultValue`.
65
+
66
+ ### Changed
67
+
68
+ - `rx.submitCase()` now fails with 422 and the list of fields to fix when the patient or intake does not
69
+ meet the clinical network rules (the server enforces them for every integration). Nothing reaches the
70
+ clinician and the same order can be resubmitted.
71
+ - Docs: an empty questionnaire means the product has none; a storefront must never replace a network
72
+ questionnaire with its own quiz.
73
+
74
+ ## [1.18.0] — 2026-10-09
75
+
76
+ ### Added
77
+
78
+ - `TagadaHeadlessProviderConfigProps`: `TagadaHeadlessProvider` accepts `config` alone, without a `storeId`
79
+ prop (`config` replaces the individual props). It is the only way to pass `funnel`.
80
+
81
+ ### Changed
82
+
83
+ - **`customer.getByEmail()` rejects** with a `TagadaError` of code `not_supported`, without sending a
84
+ request, and is deprecated. It always resolved `null` before, because no route finds a customer by email
85
+ for a storefront session (the only email search needs a secret API key). Use `portal.getMe()` or
86
+ `customer.getProfile(customerId)`.
87
+
88
+ ### Fixed
89
+
90
+ - `customer.getOrders`, `getSubscriptions` and `getSubscription` call the routes that serve them
91
+ (`GET /api/v1/orders/customer/:customerId`, `GET /api/v1/subscriptions`); they always failed with a 404.
92
+ They need that customer's session (checkout session or portal login). `getOrders` slices with
93
+ `limit`/`offset` in the SDK; `getSubscriptions` returns the 20 most recent; `getSubscription` looks the
94
+ id up among them and rejects with `TagadaNotFoundError` when it is not there.
95
+ - `TagadaHeadlessProvider` keeps the same client while the config values stay equal: an inline `config`
96
+ no longer builds a new client on every render, which dropped the checkout session token and re-fetched
97
+ the tracking config. `bootstrap` is compared by content.
98
+
99
+ ## [1.17.0] — 2026-10-08
100
+
101
+ ### Added
102
+
103
+ - **`client.portal`** (`CustomerPortalModule`): the customer portal over `/api/v1/portal/*` and
104
+ `/api/v1/subscriptions/*`.
105
+ - Login: `requestCode`, `verifyCode` (the client keeps the session token).
106
+ - Reads: `getConfig` (no login), `getMe`, `getCredits`, `getOffer`.
107
+ - Cancellation: `cancelFlow`, `acceptCancelOffer`, `switchOption`.
108
+ - Subscriptions: `addToNextOrder`, `sendNow`, `reactivateSubscription`, `setSubscriptionCard`,
109
+ `setSubscriptionAddress`, `skipDate`, `unskipDate`, `retryPayment`.
110
+ - Account: `updateProfile`, `requestEmailChangeCode`, `saveAddress`, `removeAddress`,
111
+ `setDefaultAddress`, `addCard`, `removeCard`, `setDefaultPaymentMethod`.
112
+ - Purchases: `buyAgain`, `buyNow`, `joinMembership`, `acceptOffer`, `redeemCredits`, `buyCreditPack`.
113
+ A charge that needs 3DS answers `status: 'requires_action'` with a `redirectUrl`.
114
+ - `client.customer` subscription actions over the existing `/api/v1/subscriptions/*` routes:
115
+ `pauseSubscription`, `resumeSubscription`, `skipSubscription`, `rescheduleSubscription`,
116
+ `updateSubscriptionQuantity`, `changeSubscriptionFrequency`, `swapSubscriptionProduct`,
117
+ `updateSubscriptionPaymentMethod`, `cancelSubscription`.
118
+ - Type namespace `PortalTypes`: the portal data contract (store, products, options, membership, retention,
119
+ customer, orders, subscriptions, credits, portal design, REST payloads).
120
+ - Lazy own-host v2 tracking behind the R4 store switches.
121
+ - `client.experiments` facade and optional server assignment `bootstrap`.
122
+ - Snapchat `client_dedup_id` and Pinterest `event_id` for events carrying a dedup ID.
123
+
124
+ ### Changed
125
+
126
+ - `customer.updateProfile(customerId, data)` posts to the existing `/api/v1/customers/:id` route and saves
127
+ `email` only; the name and phone of a logged-in customer go through `portal.updateProfile`.
128
+
129
+ ### Preserved
130
+
131
+ - Constructor and SSR silence, opt-in tracking, existing SDK exports and v1 event payloads.
132
+
133
+ ## [1.16.0] — 2026-09-26
134
+
135
+ ### Added
136
+
137
+ - **`tagada.rx.getActivationStatus(storeId?)`** — the Tagada Rx activation status of a store: steps,
138
+ missing items, the statement descriptor review state and `payments: 'setting_up' | 'ready'`.
139
+ Defaults to the client's `storeId`. Calls the public `GET /api/public/v1/rx/activation-status`.
140
+ - Types `RxActivationStatus`, `RxActivationStepKey`, `RxActivationMissingItem`.
141
+
142
+ ### Unchanged, stated on purpose
143
+
144
+ - `RxModule` takes an optional second constructor argument (the store id); `new RxModule(http)`
145
+ keeps working.
146
+ - No new HTTP header; every existing signature and return value is identical.
147
+
148
+ ## [1.15.0] — 2026-09-22 (never published to npm; first published in 1.16.0)
149
+
150
+ ### Added
151
+
152
+ - **`tagada.track`** — report the steps and events of a funnel you code yourself: `step()`,
153
+ `event()`, `identify()`, `consent()`, `health()`. It stays inert until `track.step()` is called
154
+ once, and then fires the browser pixels bound to that step on the Tagada canvas.
155
+ - **`useStep(stepId, data?)`** from `@tagadapay/headless-sdk/react`.
156
+ - **`funnel`** client option (optional, defaults to `'main'`): the key of the funnel declared in
157
+ `tagada.funnel.ts`. Read by `track` only.
158
+ - **`@tagadapay/headless-sdk/stripe`** is now a declared export subpath. The deep file import into
159
+ `dist/stripe/index.js` keeps working unchanged.
160
+ - **`dist/tagada-pixels.min.js`** — the pixel engine as its own CDN file (`window.TagadaPixels`),
161
+ loaded on demand by `track`. The core CDN bundle does not carry it.
162
+
163
+ ### Fixed
164
+
165
+ - The `/stripe` entry no longer throws at import time when the optional peer
166
+ `@tagadapay/core-js` is absent; only calling a wallet function rejects, and the original loader
167
+ error is kept as `cause`.
168
+ - `payment.loadCoreJs` keeps the original error as `cause` as well.
169
+
170
+ ### Unchanged, stated on purpose
171
+
172
+ - No new HTTP header on any route, existing or new.
173
+ - `window.TagadaHeadless`, `window.TagadaHeadless.create` and `window.TagadaHeadlessReact` are
174
+ identical.
175
+ - Every existing signature and return value is identical, `getExpressMethods()` included.
176
+ - Nothing happens until `track.step()` is called once: an upgrade on its own sends no request.
177
+
178
+ ## [1.14.1] — 2026-09-09
179
+
180
+ ### Fixed
181
+
182
+ - **`checkout.createSessionUrl()`** — forward `discountCodes`, `metadata`, `customerMetadata`, and
183
+ `customerTags` to `createSession()` instead of dropping them on the self-hosted checkout path.
184
+ #TAG-2560
185
+
186
+ ## [1.14.0] — 2026-09-09
187
+
188
+ ### Added
189
+
190
+ - **`checkout.createSession()`** and **`useCheckout().createSession()`** — optional `discountCodes`,
191
+ `metadata`, `customerMetadata`, and `customerTags` on session init (pass-through to
192
+ `POST /api/v1/checkout/session/init`). Use when handing off from your landing page with promo
193
+ codes and affiliate attribution already attached. #TAG-2560
@@ -0,0 +1,83 @@
1
+ /**
2
+ * On-chain crypto (`crypto_onchain`): the pure rules of the inline payment and the
3
+ * `CryptoOnchainCheckout` flow. Same behaviour as the hosted (Studio) checkout's crypto panel:
4
+ * default network and coin, status phases, quote countdown, polling until paid.
5
+ */
6
+ import type { CryptoOnchainCheckoutOptions, CryptoOnchainCheckoutState, CryptoOnchainNetwork, CryptoOnchainOptionsResult, CryptoOnchainPaymentResult, CryptoOnchainPhase, CryptoOnchainSelection, CryptoOnchainStatus, CryptoOnchainStatusResult } from '../types.js';
7
+ /** `paymentSetupConfig` key and payment method name of on-chain crypto. */
8
+ export declare const CRYPTO_ONCHAIN_PAYMENT_METHOD = "crypto_onchain";
9
+ /** How often the checkout polls the status, in milliseconds. */
10
+ export declare const CRYPTO_ONCHAIN_STATUS_POLL_MS = 5000;
11
+ /** Phases after which polling stops. */
12
+ export declare const CRYPTO_ONCHAIN_FINAL_PHASES: readonly CryptoOnchainPhase[];
13
+ /** True for `crypto_onchain` in any spelling a checkout uses (`crypto-onchain`, `crypto_onchain:int_…`). */
14
+ export declare function isCryptoOnchainMethod(method: string | null | undefined): boolean;
15
+ /**
16
+ * The default pick: the first mainnet network (testnets only when nothing else is offered) and its
17
+ * first stablecoin, else its first coin. Null when no network offers a coin.
18
+ */
19
+ export declare function defaultCryptoOnchainSelection(networks: CryptoOnchainNetwork[]): CryptoOnchainSelection | null;
20
+ /** Switching network keeps the coin when the new network offers it, else takes its default coin. */
21
+ export declare function selectCryptoOnchainNetwork(networks: CryptoOnchainNetwork[], chainId: number, currentAsset: string): CryptoOnchainSelection;
22
+ /** The phase of the latest status (or of the payment as created, before the first poll). */
23
+ export declare function cryptoOnchainPhase(status: Pick<CryptoOnchainStatus, 'status' | 'paid' | 'expired'> | null): CryptoOnchainPhase;
24
+ /** Whole seconds until `expiresAt`, never negative; 0 for a missing or unparsable date. */
25
+ export declare function cryptoOnchainSecondsLeft(expiresAt: string | null, nowMs: number): number;
26
+ /** `m:ss` under an hour, `h:mm:ss` above. */
27
+ export declare function formatCryptoOnchainCountdown(seconds: number): string;
28
+ /** The three calls the flow needs; `PaymentModule` provides them. */
29
+ export interface CryptoOnchainApi {
30
+ getCryptoOnchainOptions(checkoutSessionId: string): Promise<CryptoOnchainOptionsResult>;
31
+ createCryptoOnchainPayment(opts: {
32
+ checkoutSessionId: string;
33
+ chainId: number;
34
+ asset: string;
35
+ }): Promise<CryptoOnchainPaymentResult>;
36
+ getCryptoOnchainStatus(opts: {
37
+ checkoutSessionId: string;
38
+ cryptoOnchainPaymentId: string;
39
+ }): Promise<CryptoOnchainStatusResult>;
40
+ }
41
+ /**
42
+ * The inline crypto payment of one checkout session: load the networks and coins, keep the pick,
43
+ * create (or re-quote) the payment, poll it until crypto-api confirms it and call `onPaid` once.
44
+ * Create it with `tagada.payment.createCryptoOnchainCheckout()`.
45
+ */
46
+ export declare class CryptoOnchainCheckout {
47
+ private readonly api;
48
+ private readonly options;
49
+ private state;
50
+ private readonly listeners;
51
+ private pollTimer;
52
+ private stopped;
53
+ private paidNotified;
54
+ constructor(api: CryptoOnchainApi, options: CryptoOnchainCheckoutOptions);
55
+ getState(): CryptoOnchainCheckoutState;
56
+ /** Listens to every state change; returns the unsubscribe function. */
57
+ subscribe(listener: (state: CryptoOnchainCheckoutState) => void): () => void;
58
+ /** What to show: the polled phase, or `expired` once an unpaid quote ran out (renew with `pay()`). */
59
+ getPhase(nowMs?: number): CryptoOnchainPhase;
60
+ /** Whole seconds left on the current quote. */
61
+ getSecondsLeft(nowMs?: number): number;
62
+ /** Loads the networks and coins and picks the default network and coin. */
63
+ loadOptions(): Promise<CryptoOnchainCheckoutState>;
64
+ /** Changes the pick. A new network keeps the coin when it offers it, else takes its default coin. */
65
+ select(next: {
66
+ chainId?: number;
67
+ asset?: string;
68
+ }): void;
69
+ /**
70
+ * Creates the payment for the pick (or `selection`), or re-quotes it: another coin, or a quote
71
+ * that expired. Save the customer and address on the session first. Starts polling.
72
+ */
73
+ pay(selection?: CryptoOnchainSelection): Promise<CryptoOnchainPaymentResult>;
74
+ /** Polls the status once now (the timer keeps polling until the payment is final). */
75
+ refreshStatus(): Promise<CryptoOnchainStatus | null>;
76
+ /** Polls again after `stop()`, while a payment is open (the customer came back to crypto). */
77
+ resume(): void;
78
+ /** Stops polling (unmount, or the customer chose another payment method). */
79
+ stop(): void;
80
+ private schedulePoll;
81
+ private setState;
82
+ }
83
+ //# sourceMappingURL=cryptoOnchain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cryptoOnchain.d.ts","sourceRoot":"","sources":["../../../src/core/helpers/cryptoOnchain.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,247 @@
1
+ /** `paymentSetupConfig` key and payment method name of on-chain crypto. */
2
+ export const CRYPTO_ONCHAIN_PAYMENT_METHOD = 'crypto_onchain';
3
+ /** How often the checkout polls the status, in milliseconds. */
4
+ export const CRYPTO_ONCHAIN_STATUS_POLL_MS = 5000;
5
+ /** Phases after which polling stops. */
6
+ export const CRYPTO_ONCHAIN_FINAL_PHASES = ['paid', 'underpaid', 'failed', 'expired'];
7
+ /** True for `crypto_onchain` in any spelling a checkout uses (`crypto-onchain`, `crypto_onchain:int_…`). */
8
+ export function isCryptoOnchainMethod(method) {
9
+ if (!method)
10
+ return false;
11
+ return method.trim().toLowerCase().replace(/-/g, '_').split(':')[0] === CRYPTO_ONCHAIN_PAYMENT_METHOD;
12
+ }
13
+ /**
14
+ * The default pick: the first mainnet network (testnets only when nothing else is offered) and its
15
+ * first stablecoin, else its first coin. Null when no network offers a coin.
16
+ */
17
+ export function defaultCryptoOnchainSelection(networks) {
18
+ const usable = networks.filter((network) => network.assets.length > 0);
19
+ const network = usable.find((candidate) => !candidate.testnet) ?? usable[0];
20
+ if (!network)
21
+ return null;
22
+ const asset = network.assets.find((candidate) => candidate.stable) ?? network.assets[0];
23
+ return { chainId: network.chainId, asset: asset.symbol };
24
+ }
25
+ /** Switching network keeps the coin when the new network offers it, else takes its default coin. */
26
+ export function selectCryptoOnchainNetwork(networks, chainId, currentAsset) {
27
+ const assets = networks.find((network) => network.chainId === chainId)?.assets ?? [];
28
+ const keep = assets.find((asset) => asset.symbol === currentAsset);
29
+ const fallback = assets.find((asset) => asset.stable) ?? assets[0];
30
+ return { chainId, asset: (keep ?? fallback)?.symbol ?? currentAsset };
31
+ }
32
+ /** The phase of the latest status (or of the payment as created, before the first poll). */
33
+ export function cryptoOnchainPhase(status) {
34
+ if (!status)
35
+ return 'waiting';
36
+ if (status.paid)
37
+ return 'paid';
38
+ switch (status.status) {
39
+ case 'detected':
40
+ case 'overpaid':
41
+ return 'confirming';
42
+ case 'underpaid':
43
+ return 'underpaid';
44
+ case 'failed':
45
+ return 'failed';
46
+ case 'expired':
47
+ return 'expired';
48
+ default:
49
+ return status.expired ? 'expired' : 'waiting';
50
+ }
51
+ }
52
+ /** Whole seconds until `expiresAt`, never negative; 0 for a missing or unparsable date. */
53
+ export function cryptoOnchainSecondsLeft(expiresAt, nowMs) {
54
+ if (!expiresAt)
55
+ return 0;
56
+ const end = Date.parse(expiresAt);
57
+ if (Number.isNaN(end))
58
+ return 0;
59
+ return Math.max(0, Math.floor((end - nowMs) / 1000));
60
+ }
61
+ /** `m:ss` under an hour, `h:mm:ss` above. */
62
+ export function formatCryptoOnchainCountdown(seconds) {
63
+ const s = Math.max(0, Math.floor(seconds));
64
+ const h = Math.floor(s / 3600);
65
+ const m = Math.floor((s % 3600) / 60);
66
+ const sec = String(s % 60).padStart(2, '0');
67
+ return h > 0 ? `${h}:${String(m).padStart(2, '0')}:${sec}` : `${m}:${sec}`;
68
+ }
69
+ const UNAVAILABLE = 'Crypto payments are not available right now. Choose another payment method.';
70
+ /**
71
+ * The inline crypto payment of one checkout session: load the networks and coins, keep the pick,
72
+ * create (or re-quote) the payment, poll it until crypto-api confirms it and call `onPaid` once.
73
+ * Create it with `tagada.payment.createCryptoOnchainCheckout()`.
74
+ */
75
+ export class CryptoOnchainCheckout {
76
+ constructor(api, options) {
77
+ this.api = api;
78
+ this.options = options;
79
+ this.state = {
80
+ options: 'idle',
81
+ networks: [],
82
+ selection: null,
83
+ payment: null,
84
+ paymentStatus: null,
85
+ isCreating: false,
86
+ error: null,
87
+ };
88
+ this.listeners = new Set();
89
+ this.pollTimer = null;
90
+ this.stopped = false;
91
+ this.paidNotified = false;
92
+ this.subscribe = this.subscribe.bind(this);
93
+ this.getState = this.getState.bind(this);
94
+ }
95
+ getState() {
96
+ return this.state;
97
+ }
98
+ /** Listens to every state change; returns the unsubscribe function. */
99
+ subscribe(listener) {
100
+ this.listeners.add(listener);
101
+ return () => {
102
+ this.listeners.delete(listener);
103
+ };
104
+ }
105
+ /** What to show: the polled phase, or `expired` once an unpaid quote ran out (renew with `pay()`). */
106
+ getPhase(nowMs = Date.now()) {
107
+ const { payment, paymentStatus } = this.state;
108
+ const phase = cryptoOnchainPhase(paymentStatus ?? (payment ? { status: payment.status, paid: false, expired: false } : null));
109
+ const quoteOver = payment !== null && phase === 'waiting' && cryptoOnchainSecondsLeft(payment.expiresAt, nowMs) === 0;
110
+ return quoteOver ? 'expired' : phase;
111
+ }
112
+ /** Whole seconds left on the current quote. */
113
+ getSecondsLeft(nowMs = Date.now()) {
114
+ return cryptoOnchainSecondsLeft(this.state.payment?.expiresAt ?? null, nowMs);
115
+ }
116
+ /** Loads the networks and coins and picks the default network and coin. */
117
+ async loadOptions() {
118
+ this.setState({ options: 'loading', error: null });
119
+ try {
120
+ const result = await this.api.getCryptoOnchainOptions(this.options.checkoutSessionId);
121
+ if (!result.ok) {
122
+ this.setState({ options: 'unavailable', networks: [], selection: null, error: result.message || UNAVAILABLE });
123
+ return this.state;
124
+ }
125
+ const selection = this.state.selection ?? defaultCryptoOnchainSelection(result.networks);
126
+ this.setState(selection
127
+ ? { options: 'ready', networks: result.networks, selection }
128
+ : { options: 'unavailable', networks: result.networks, selection: null, error: UNAVAILABLE });
129
+ }
130
+ catch (error) {
131
+ this.setState({ options: 'unavailable', error: messageOf(error) });
132
+ }
133
+ return this.state;
134
+ }
135
+ /** Changes the pick. A new network keeps the coin when it offers it, else takes its default coin. */
136
+ select(next) {
137
+ const current = this.state.selection;
138
+ if (next.chainId !== undefined && next.chainId !== current?.chainId) {
139
+ this.setState({ selection: selectCryptoOnchainNetwork(this.state.networks, next.chainId, next.asset ?? current?.asset ?? '') });
140
+ return;
141
+ }
142
+ if (next.asset !== undefined && current)
143
+ this.setState({ selection: { ...current, asset: next.asset } });
144
+ }
145
+ /**
146
+ * Creates the payment for the pick (or `selection`), or re-quotes it: another coin, or a quote
147
+ * that expired. Save the customer and address on the session first. Starts polling.
148
+ */
149
+ async pay(selection) {
150
+ const target = selection ?? this.state.selection;
151
+ if (!target)
152
+ return { ok: false, code: 'ASSET_NOT_AVAILABLE', message: 'Choose a network and a coin' };
153
+ if (this.state.isCreating)
154
+ return { ok: false, code: 'CHECKOUT_FAILED', message: 'A payment is already being created' };
155
+ this.setState({ isCreating: true, error: null, selection: target });
156
+ try {
157
+ const result = await this.api.createCryptoOnchainPayment({
158
+ checkoutSessionId: this.options.checkoutSessionId,
159
+ chainId: target.chainId,
160
+ asset: target.asset,
161
+ });
162
+ if (!result.ok) {
163
+ this.setState({ isCreating: false, error: result.message });
164
+ return result;
165
+ }
166
+ this.stopped = false;
167
+ this.setState({ isCreating: false, payment: result.payment, paymentStatus: null });
168
+ this.schedulePoll();
169
+ return result;
170
+ }
171
+ catch (error) {
172
+ const message = messageOf(error);
173
+ this.setState({ isCreating: false, error: message });
174
+ return { ok: false, code: 'CHECKOUT_FAILED', message };
175
+ }
176
+ }
177
+ /** Polls the status once now (the timer keeps polling until the payment is final). */
178
+ async refreshStatus() {
179
+ const payment = this.state.payment;
180
+ if (!payment)
181
+ return null;
182
+ try {
183
+ const result = await this.api.getCryptoOnchainStatus({
184
+ checkoutSessionId: this.options.checkoutSessionId,
185
+ cryptoOnchainPaymentId: payment.cryptoOnchainPaymentId,
186
+ });
187
+ // A newer quote replaced this payment while the call was in flight.
188
+ if (!result.ok || this.state.payment?.cryptoOnchainPaymentId !== payment.cryptoOnchainPaymentId)
189
+ return null;
190
+ const status = {
191
+ status: result.status,
192
+ paymentId: result.paymentId,
193
+ orderId: result.orderId,
194
+ confirmations: result.confirmations,
195
+ requiredConfirmations: result.requiredConfirmations,
196
+ txHash: result.txHash,
197
+ explorerTxUrl: result.explorerTxUrl,
198
+ paid: result.paid,
199
+ expired: result.expired,
200
+ redirectUrl: result.redirectUrl,
201
+ };
202
+ this.setState({ paymentStatus: status });
203
+ if (status.paid && !this.paidNotified) {
204
+ this.paidNotified = true;
205
+ this.options.onPaid?.(status);
206
+ }
207
+ return status;
208
+ }
209
+ catch {
210
+ // The next tick retries; the payment still settles server side.
211
+ return null;
212
+ }
213
+ }
214
+ /** Polls again after `stop()`, while a payment is open (the customer came back to crypto). */
215
+ resume() {
216
+ if (!this.state.payment || CRYPTO_ONCHAIN_FINAL_PHASES.includes(this.getPhase()))
217
+ return;
218
+ this.stopped = false;
219
+ this.schedulePoll();
220
+ }
221
+ /** Stops polling (unmount, or the customer chose another payment method). */
222
+ stop() {
223
+ this.stopped = true;
224
+ if (this.pollTimer)
225
+ clearTimeout(this.pollTimer);
226
+ this.pollTimer = null;
227
+ }
228
+ schedulePoll() {
229
+ if (this.pollTimer)
230
+ clearTimeout(this.pollTimer);
231
+ this.pollTimer = setTimeout(async () => {
232
+ this.pollTimer = null;
233
+ await this.refreshStatus();
234
+ if (!this.stopped && !CRYPTO_ONCHAIN_FINAL_PHASES.includes(this.getPhase()))
235
+ this.schedulePoll();
236
+ }, this.options.pollIntervalMs ?? CRYPTO_ONCHAIN_STATUS_POLL_MS);
237
+ }
238
+ setState(patch) {
239
+ this.state = { ...this.state, ...patch };
240
+ this.options.onChange?.(this.state);
241
+ this.listeners.forEach((listener) => listener(this.state));
242
+ }
243
+ }
244
+ function messageOf(error) {
245
+ return error instanceof Error && error.message ? error.message : UNAVAILABLE;
246
+ }
247
+ //# sourceMappingURL=cryptoOnchain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cryptoOnchain.js","sourceRoot":"","sources":["../../../src/core/helpers/cryptoOnchain.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Browser plumbing for Ocean Payment's inline card form (Oceanpayment
3
+ * Embedded SDK). Mirrors the hosted checkout's OceanPaymentPanel
4
+ * (apps/studio-app/.../PaymentMethodSelector/TakeoverPanels.tsx).
5
+ */
6
+ export interface OceanpaymentGlobal {
7
+ init: (sandbox: boolean, cssUrl: string, language: string, configuration: Record<string, unknown>) => void;
8
+ checkout: (data: Record<string, string>) => void;
9
+ }
10
+ export type OceanWindow = Window & {
11
+ Oceanpayment?: OceanpaymentGlobal;
12
+ /** Ocean's SDK calls this global — the name is fixed by the SDK. */
13
+ oceanpaymentCallBack?: (data: unknown) => void;
14
+ };
15
+ export declare const OCEAN_SDK_URL = "https://secure.oceanpayment.com/pages/js/oceanpayment.js";
16
+ /** Fixed by Ocean's SDK, which looks the container up by this id. */
17
+ export declare const OCEAN_CONTAINER_ID = "oceanpayment-element";
18
+ /** Ocean's iframe answers every checkout(); this only guards a lost message. */
19
+ export declare const OCEAN_CALLBACK_TIMEOUT_MS = 120000;
20
+ export declare function oceanLanguage(locale: string | undefined): string;
21
+ /**
22
+ * Load Ocean's SDK once per page: a second copy would deliver every result
23
+ * twice. A failed or stalled load is forgotten, so the next mount retries.
24
+ */
25
+ export declare function loadOceanSdk(): Promise<OceanpaymentGlobal>;
26
+ export declare function parkOceanPayment(paymentId: string): void;
27
+ /**
28
+ * Back from Ocean's 3-D Secure page: turn the parked payment into the
29
+ * `paymentAction` / `paymentActionStatus` / `paymentId` markers that
30
+ * `maybeResumeFromUrl()` and `usePayment()` already resume from.
31
+ */
32
+ export declare function restoreOceanPaymentReturn(): void;
33
+ //# sourceMappingURL=oceanpayment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oceanpayment.d.ts","sourceRoot":"","sources":["../../../src/core/helpers/oceanpayment.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAC3G,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC;CAClD;AAED,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG;IACjC,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAClC,oEAAoE;IACpE,oBAAoB,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CAChD,CAAC;AAEF,eAAO,MAAM,aAAa,6DAA6D,CAAC;AACxF,qEAAqE;AACrE,eAAO,MAAM,kBAAkB,yBAAyB,CAAC;AACzD,gFAAgF;AAChF,eAAO,MAAM,yBAAyB,SAAU,CAAC;AASjD,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAIhE;AAKD;;;GAGG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAwB1D;AAWD,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAMxD;AAeD;;;;GAIG;AACH,wBAAgB,yBAAyB,IAAI,IAAI,CAchD"}