@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.
- package/CHANGELOG.md +193 -0
- package/dist/core/helpers/cryptoOnchain.d.ts +83 -0
- package/dist/core/helpers/cryptoOnchain.d.ts.map +1 -0
- package/dist/core/helpers/cryptoOnchain.js +247 -0
- package/dist/core/helpers/cryptoOnchain.js.map +1 -0
- package/dist/core/helpers/oceanpayment.d.ts +33 -0
- package/dist/core/helpers/oceanpayment.d.ts.map +1 -0
- package/dist/core/helpers/oceanpayment.js +111 -0
- package/dist/core/helpers/oceanpayment.js.map +1 -0
- package/dist/core/http.d.ts.map +1 -1
- package/dist/core/http.js +3 -0
- package/dist/core/http.js.map +1 -1
- package/dist/core/index.d.ts +4 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +2 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/modules/payment.d.ts +66 -1
- package/dist/core/modules/payment.d.ts.map +1 -1
- package/dist/core/modules/payment.js +297 -2
- package/dist/core/modules/payment.js.map +1 -1
- package/dist/core/modules/portal/types.d.ts +10 -1
- package/dist/core/modules/portal/types.d.ts.map +1 -1
- package/dist/core/modules/rx.d.ts +43 -0
- package/dist/core/modules/rx.d.ts.map +1 -1
- package/dist/core/modules/rx.js +13 -0
- package/dist/core/modules/rx.js.map +1 -1
- package/dist/core/types.d.ts +159 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/version.d.ts +1 -1
- package/dist/core/version.js +1 -1
- package/dist/pixels/pixelMapping.d.ts.map +1 -1
- package/dist/pixels/pixelMapping.js +9 -1
- package/dist/pixels/pixelMapping.js.map +1 -1
- package/dist/react/hooks/useCryptoOnchainPayment.d.ts +40 -0
- package/dist/react/hooks/useCryptoOnchainPayment.d.ts.map +1 -0
- package/dist/react/hooks/useCryptoOnchainPayment.js +77 -0
- package/dist/react/hooks/useCryptoOnchainPayment.js.map +1 -0
- package/dist/react/hooks/usePayment.d.ts.map +1 -1
- package/dist/react/hooks/usePayment.js +3 -0
- package/dist/react/hooks/usePayment.js.map +1 -1
- package/dist/react/index.d.ts +4 -1
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +2 -0
- package/dist/react/index.js.map +1 -1
- package/dist/tagada-headless-commerce.min.js +1 -1
- package/dist/tagada-headless-react.min.js +2 -2
- package/dist/tagada-headless-react.min.js.map +4 -4
- package/dist/tagada-headless.js +626 -9
- package/dist/tagada-headless.min.js +2 -2
- package/dist/tagada-headless.min.js.map +4 -4
- package/dist/tagada-pixels.min.js +2 -2
- package/dist/tagada-pixels.min.js.map +3 -3
- 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":"AAiBA,2EAA2E;AAC3E,MAAM,CAAC,MAAM,6BAA6B,GAAG,gBAAgB,CAAC;AAE9D,gEAAgE;AAChE,MAAM,CAAC,MAAM,6BAA6B,GAAG,IAAI,CAAC;AAElD,wCAAwC;AACxC,MAAM,CAAC,MAAM,2BAA2B,GAAkC,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;AAErH,4GAA4G;AAC5G,MAAM,UAAU,qBAAqB,CAAC,MAAiC;IACrE,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC1B,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,6BAA6B,CAAC;AACxG,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,6BAA6B,CAAC,QAAgC;IAC5E,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACvE,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC;IAC5E,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IACxF,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC;AAC3D,CAAC;AAED,oGAAoG;AACpG,MAAM,UAAU,0BAA0B,CACxC,QAAgC,EAChC,OAAe,EACf,YAAoB;IAEpB,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,KAAK,OAAO,CAAC,EAAE,MAAM,IAAI,EAAE,CAAC;IACrF,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,YAAY,CAAC,CAAC;IACnE,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC;IACnE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,IAAI,IAAI,QAAQ,CAAC,EAAE,MAAM,IAAI,YAAY,EAAE,CAAC;AACxE,CAAC;AAED,4FAA4F;AAC5F,MAAM,UAAU,kBAAkB,CAChC,MAAuE;IAEvE,IAAI,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAC9B,IAAI,MAAM,CAAC,IAAI;QAAE,OAAO,MAAM,CAAC;IAC/B,QAAQ,MAAM,CAAC,MAAM,EAAE,CAAC;QACtB,KAAK,UAAU,CAAC;QAChB,KAAK,UAAU;YACb,OAAO,YAAY,CAAC;QACtB,KAAK,WAAW;YACd,OAAO,WAAW,CAAC;QACrB,KAAK,QAAQ;YACX,OAAO,QAAQ,CAAC;QAClB,KAAK,SAAS;YACZ,OAAO,SAAS,CAAC;QACnB;YACE,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAClD,CAAC;AACH,CAAC;AAED,2FAA2F;AAC3F,MAAM,UAAU,wBAAwB,CAAC,SAAwB,EAAE,KAAa;IAC9E,IAAI,CAAC,SAAS;QAAE,OAAO,CAAC,CAAC;IACzB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAClC,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC;QAAE,OAAO,CAAC,CAAC;IAChC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;AACvD,CAAC;AAED,6CAA6C;AAC7C,MAAM,UAAU,4BAA4B,CAAC,OAAe;IAC1D,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3C,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAC/B,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IACtC,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC5C,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;AAC7E,CAAC;AASD,MAAM,WAAW,GAAG,6EAA6E,CAAC;AAElG;;;;GAIG;AACH,MAAM,OAAO,qBAAqB;IAgBhC,YACmB,GAAqB,EACrB,OAAqC;QADrC,QAAG,GAAH,GAAG,CAAkB;QACrB,YAAO,GAAP,OAAO,CAA8B;QAjBhD,UAAK,GAA+B;YAC1C,OAAO,EAAE,MAAM;YACf,QAAQ,EAAE,EAAE;YACZ,SAAS,EAAE,IAAI;YACf,OAAO,EAAE,IAAI;YACb,aAAa,EAAE,IAAI;YACnB,UAAU,EAAE,KAAK;YACjB,KAAK,EAAE,IAAI;SACZ,CAAC;QAEe,cAAS,GAAG,IAAI,GAAG,EAA+C,CAAC;QAC5E,cAAS,GAAyC,IAAI,CAAC;QACvD,YAAO,GAAG,KAAK,CAAC;QAChB,iBAAY,GAAG,KAAK,CAAC;QAM3B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3C,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3C,CAAC;IAED,QAAQ;QACN,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED,uEAAuE;IACvE,SAAS,CAAC,QAAqD;QAC7D,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC7B,OAAO,GAAG,EAAE;YACV,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAClC,CAAC,CAAC;IACJ,CAAC;IAED,sGAAsG;IACtG,QAAQ,CAAC,QAAgB,IAAI,CAAC,GAAG,EAAE;QACjC,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;QAC9C,MAAM,KAAK,GAAG,kBAAkB,CAAC,aAAa,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAC9H,MAAM,SAAS,GAAG,OAAO,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,IAAI,wBAAwB,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QACtH,OAAO,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC;IACvC,CAAC;IAED,+CAA+C;IAC/C,cAAc,CAAC,QAAgB,IAAI,CAAC,GAAG,EAAE;QACvC,OAAO,wBAAwB,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,SAAS,IAAI,IAAI,EAAE,KAAK,CAAC,CAAC;IAChF,CAAC;IAED,2EAA2E;IAC3E,KAAK,CAAC,WAAW;QACf,IAAI,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACnD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,uBAAuB,CAAC,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;YACtF,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;gBACf,IAAI,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,OAAO,IAAI,WAAW,EAAE,CAAC,CAAC;gBAC/G,OAAO,IAAI,CAAC,KAAK,CAAC;YACpB,CAAC;YACD,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,IAAI,6BAA6B,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YACzF,IAAI,CAAC,QAAQ,CACX,SAAS;gBACP,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,SAAS,EAAE;gBAC5D,CAAC,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,CAC/F,CAAC;QACJ,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,IAAI,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACrE,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED,qGAAqG;IACrG,MAAM,CAAC,IAA0C;QAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC;QACrC,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,IAAI,IAAI,CAAC,OAAO,KAAK,OAAO,EAAE,OAAO,EAAE,CAAC;YACpE,IAAI,CAAC,QAAQ,CAAC,EAAE,SAAS,EAAE,0BAA0B,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,IAAI,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;YAChI,OAAO;QACT,CAAC;QACD,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO;YAAE,IAAI,CAAC,QAAQ,CAAC,EAAE,SAAS,EAAE,EAAE,GAAG,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC3G,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,GAAG,CAAC,SAAkC;QAC1C,MAAM,MAAM,GAAG,SAAS,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC;QACjD,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,qBAAqB,EAAE,OAAO,EAAE,6BAA6B,EAAE,CAAC;QACvG,IAAI,IAAI,CAAC,KAAK,CAAC,UAAU;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,oCAAoC,EAAE,CAAC;QAExH,IAAI,CAAC,QAAQ,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC;QACpE,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,0BAA0B,CAAC;gBACvD,iBAAiB,EAAE,IAAI,CAAC,OAAO,CAAC,iBAAiB;gBACjD,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,KAAK,EAAE,MAAM,CAAC,KAAK;aACpB,CAAC,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;gBACf,IAAI,CAAC,QAAQ,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;gBAC5D,OAAO,MAAM,CAAC;YAChB,CAAC;YACD,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;YACrB,IAAI,CAAC,QAAQ,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;YACnF,IAAI,CAAC,YAAY,EAAE,CAAC;YACpB,OAAO,MAAM,CAAC;QAChB,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,MAAM,OAAO,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;YACjC,IAAI,CAAC,QAAQ,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;YACrD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,CAAC;QACzD,CAAC;IACH,CAAC;IAED,sFAAsF;IACtF,KAAK,CAAC,aAAa;QACjB,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;QACnC,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QAC1B,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,sBAAsB,CAAC;gBACnD,iBAAiB,EAAE,IAAI,CAAC,OAAO,CAAC,iBAAiB;gBACjD,sBAAsB,EAAE,OAAO,CAAC,sBAAsB;aACvD,CAAC,CAAC;YACH,oEAAoE;YACpE,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,sBAAsB,KAAK,OAAO,CAAC,sBAAsB;gBAAE,OAAO,IAAI,CAAC;YAC7G,MAAM,MAAM,GAAwB;gBAClC,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,aAAa,EAAE,MAAM,CAAC,aAAa;gBACnC,qBAAqB,EAAE,MAAM,CAAC,qBAAqB;gBACnD,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,aAAa,EAAE,MAAM,CAAC,aAAa;gBACnC,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,WAAW,EAAE,MAAM,CAAC,WAAW;aAChC,CAAC;YACF,IAAI,CAAC,QAAQ,CAAC,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC,CAAC;YACzC,IAAI,MAAM,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;gBACtC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;gBACzB,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC;YAChC,CAAC;YACD,OAAO,MAAM,CAAC;QAChB,CAAC;QAAC,MAAM,CAAC;YACP,gEAAgE;YAChE,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,8FAA8F;IAC9F,MAAM;QACJ,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,2BAA2B,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YAAE,OAAO;QACzF,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,IAAI,CAAC,YAAY,EAAE,CAAC;IACtB,CAAC;IAED,6EAA6E;IAC7E,IAAI;QACF,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,IAAI,CAAC,SAAS;YAAE,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACjD,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;IACxB,CAAC;IAEO,YAAY;QAClB,IAAI,IAAI,CAAC,SAAS;YAAE,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACjD,IAAI,CAAC,SAAS,GAAG,UAAU,CAAC,KAAK,IAAI,EAAE;YACrC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;YACtB,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;YAC3B,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,2BAA2B,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAAE,IAAI,CAAC,YAAY,EAAE,CAAC;QACnG,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,cAAc,IAAI,6BAA6B,CAAC,CAAC;IACnE,CAAC;IAEO,QAAQ,CAAC,KAA0C;QACzD,IAAI,CAAC,KAAK,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,GAAG,KAAK,EAAE,CAAC;QACzC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IAC7D,CAAC;CACF;AAED,SAAS,SAAS,CAAC,KAAc;IAC/B,OAAO,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC;AAC/E,CAAC"}
|
|
@@ -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"}
|