@meshconnect/web-link-sdk 3.13.0 → 3.14.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.
@@ -0,0 +1,96 @@
1
+ import { appendQueryParam } from './url';
2
+ /**
3
+ * Default origin for the standalone backup deposit widget (OR-449): the production
4
+ * Cloudflare Worker. It is under the `meshconnect.com` zone but served by
5
+ * Cloudflare, not Azure, so it shares no failure domain with the primary Mesh API
6
+ * (design doc §5C) — if the core API is down the widget still loads. Matches the
7
+ * React Native SDK's default. Override per-call via `openLinkBackup`'s
8
+ * `widgetOrigin` option for staging, demo, or self-host. Money path: this origin
9
+ * serves the deposit-address UI during an outage.
10
+ */
11
+ export var DEFAULT_BACKUP_WIDGET_ORIGIN = 'https://backup.meshconnect.com';
12
+ /**
13
+ * The `type` the backup widget's message bridge requires on the config it
14
+ * receives. The widget matches `event.data.type === 'meshBackupConfig'` and
15
+ * drops any message without it, so the config must be delivered as
16
+ * `{ type: BACKUP_CONFIG_MESSAGE_TYPE, payload: MeshBackupConfig }`.
17
+ */
18
+ export var BACKUP_CONFIG_MESSAGE_TYPE = 'meshBackupConfig';
19
+ /**
20
+ * JIT-over-bridge RPC message types (OR-452). An address-less destination is
21
+ * resolved by the widget invoking the host's `onAddressInit`/`onStatusPoll`
22
+ * callbacks over this same postMessage bridge, correlated by `callId` — the
23
+ * widget never calls a client HTTP endpoint and holds no token.
24
+ *
25
+ * - Widget → host: `{ type: JIT_REQUEST_MESSAGE_TYPE, payload: MeshBackupJitRequestPayload }`
26
+ * - Host → widget: `{ type: JIT_RESPONSE_MESSAGE_TYPE, payload: MeshBackupJitResponsePayload }`
27
+ *
28
+ * ⚠️ KEEP IN SYNC with `mesh-backup-widget`'s `src/bridge/contract.ts` — the
29
+ * string values and payload shapes are the frozen cross-repo contract.
30
+ */
31
+ export var JIT_REQUEST_MESSAGE_TYPE = 'meshBackupJitRequest';
32
+ export var JIT_RESPONSE_MESSAGE_TYPE = 'meshBackupJitResponse';
33
+ /**
34
+ * How long to wait for the Tier-1 widget's ready handshake (its `loaded`
35
+ * message) after the iframe starts loading the backup origin, before treating
36
+ * the origin as unreachable and cascading to the bundled Tier-2 assets.
37
+ *
38
+ * On the web this is the **authoritative** Tier-1 failure signal: a cross-origin
39
+ * iframe does not reliably fire a load `error` event for a network/DNS failure
40
+ * (and `onload` fires even for an error page), so a served-but-broken, hung, or
41
+ * captive-portal-intercepted origin is only caught by the absence of the ready
42
+ * handshake. 5000 ms absorbs a slow mobile network with margin (the widget shell
43
+ * is ~24 KB on a CDN) while keeping the degraded-path UX acceptable. Per-SDK
44
+ * tunable constant (design §5H).
45
+ */
46
+ export var TIER1_READY_TIMEOUT_MS = 5000;
47
+ /**
48
+ * Fail-closed safety net for Tier 2: the bundled assets load from a local `blob:`
49
+ * URL, so they should complete the ready handshake near-instantly.
50
+ * If they somehow do not within this window, the flow exits with an error rather
51
+ * than sitting on a blank screen (design §5A/§5H — never a blank QR). Deliberately
52
+ * generous because a Tier-2 timeout should be effectively unreachable.
53
+ */
54
+ export var TIER2_READY_TIMEOUT_MS = 8000;
55
+ /** URL parameter carrying the per-open session nonce (query for Tier 1, fragment
56
+ * for the Tier-2 `blob:` URL). KEEP IN SYNC with `mesh-backup-widget`'s
57
+ * `src/bridge/sessionNonce.ts`. */
58
+ export var SESSION_NONCE_PARAM = 'sid';
59
+ /**
60
+ * A fresh, unguessable nonce for one backup open (128 bits, hex). Navigating an
61
+ * embedded iframe keeps its `WindowProxy` and Tier-1 sessions share an origin, so
62
+ * `event.source` + origin alone can't tell the current open's messages from ones
63
+ * the previous document queued before a reopen; the widget echoes this value as
64
+ * `sid` on every message and the SDK drops any that don't match.
65
+ */
66
+ export function createSessionNonce() {
67
+ var bytes = new Uint8Array(16);
68
+ crypto.getRandomValues(bytes);
69
+ return Array.from(bytes, function (b) { return b.toString(16).padStart(2, '0'); }).join('');
70
+ }
71
+ /**
72
+ * Builds the URL the backup-widget iframe loads. Unlike the primary path there
73
+ * is no link token to decode — the widget is a static SPA at `origin` and is
74
+ * hydrated with the `MeshBackupConfig` over the message bridge after load. Only
75
+ * non-sensitive display hints are carried on the URL; the deposit config never
76
+ * appears in it.
77
+ *
78
+ * A trailing slash on `origin` is normalised away so params attach cleanly.
79
+ */
80
+ export function buildBackupWidgetUrl(origin, params) {
81
+ // Trim trailing slashes with an index walk, not `/\/+$/` — the anchored `+`
82
+ // backtracks super-linearly (Sonar S8786) on a run of slashes before a non-slash.
83
+ var sliceEnd = origin.length;
84
+ while (sliceEnd > 0 && origin[sliceEnd - 1] === '/')
85
+ sliceEnd -= 1;
86
+ var url = origin.slice(0, sliceEnd);
87
+ url = appendQueryParam(url, 'platform', params.platform);
88
+ url = appendQueryParam(url, 'sdkVersion', params.sdkVersion);
89
+ if (params.theme) {
90
+ url = appendQueryParam(url, 'theme', params.theme);
91
+ }
92
+ if (params.sessionNonce) {
93
+ url = appendQueryParam(url, SESSION_NONCE_PARAM, params.sessionNonce);
94
+ }
95
+ return url;
96
+ }
@@ -0,0 +1,55 @@
1
+ /** Which redundancy tier the backup flow is currently serving (design §5H). */
2
+ export type BackupTier = 'tier1' | 'tier2';
3
+ /**
4
+ * Why Tier 1 was abandoned. `loadError` = a hard iframe load failure on the
5
+ * backup-origin document; `readyTimeout` = the widget did not complete its ready
6
+ * handshake within {@link TIER1_READY_TIMEOUT_MS} (the authoritative signal on
7
+ * web, where a cross-origin iframe rarely fires a load `error`).
8
+ */
9
+ export type BackupTierFallbackReason = 'loadError' | 'readyTimeout';
10
+ export interface BackupTierControllerCallbacks {
11
+ /**
12
+ * Called exactly once, on the Tier-1 → Tier-2 transition, so the caller can
13
+ * swap the iframe to the bundled assets and emit the `backupTierChanged` event.
14
+ */
15
+ onFallback: (reason: BackupTierFallbackReason) => void;
16
+ /**
17
+ * Called if Tier 2 itself never becomes ready — the bundled assets are local so
18
+ * this should be unreachable, but it is the fail-closed safety net that surfaces
19
+ * an error instead of a blank screen (design §5A/§5H).
20
+ */
21
+ onTier2Unavailable: () => void;
22
+ }
23
+ export interface BackupTierController {
24
+ /** The tier to render right now. */
25
+ getTier: () => BackupTier;
26
+ /**
27
+ * Arm the Tier-1 ready-handshake timeout. Call once, right after the Tier-1
28
+ * iframe starts loading. No-op once ready or already cascaded.
29
+ */
30
+ start: () => void;
31
+ /** Call when the current surface completes its ready handshake (its `loaded`). */
32
+ markReady: () => void;
33
+ /**
34
+ * Call on a hard load error on the current surface. In Tier 1 (before ready)
35
+ * this cascades to Tier 2; in Tier 2 it fails closed. After Tier 1 is ready it
36
+ * is ignored (a mid-session blip must not discard the funnel).
37
+ */
38
+ reportLoadError: () => void;
39
+ /** Clear any pending timer (call on teardown). */
40
+ destroy: () => void;
41
+ }
42
+ /**
43
+ * Tier-1 → Tier-2 cascade state machine for the backup deposit flow (design §5H),
44
+ * as a framework-agnostic controller (the web SDK is imperative — no React). A
45
+ * direct port of the RN `useBackupTier` hook's semantics.
46
+ *
47
+ * The flow initializes in Tier 1 (widget loaded from the independent backup
48
+ * origin). If the origin is unreachable — a hard load error, or the widget never
49
+ * completes its ready handshake within {@link TIER1_READY_TIMEOUT_MS} — the SDK
50
+ * falls back to the bundled Tier-2 assets and re-delivers the same config. The
51
+ * cascade is **monotonic and single-shot**: Tier 1 is attempted once per session
52
+ * and, once in Tier 2, the flow stays there (no flap back). If Tier 2 itself
53
+ * never becomes ready, the caller fails closed rather than showing a blank QR.
54
+ */
55
+ export declare function createBackupTierController(callbacks: BackupTierControllerCallbacks): BackupTierController;
@@ -0,0 +1,84 @@
1
+ import { TIER1_READY_TIMEOUT_MS, TIER2_READY_TIMEOUT_MS } from './backup';
2
+ /**
3
+ * Tier-1 → Tier-2 cascade state machine for the backup deposit flow (design §5H),
4
+ * as a framework-agnostic controller (the web SDK is imperative — no React). A
5
+ * direct port of the RN `useBackupTier` hook's semantics.
6
+ *
7
+ * The flow initializes in Tier 1 (widget loaded from the independent backup
8
+ * origin). If the origin is unreachable — a hard load error, or the widget never
9
+ * completes its ready handshake within {@link TIER1_READY_TIMEOUT_MS} — the SDK
10
+ * falls back to the bundled Tier-2 assets and re-delivers the same config. The
11
+ * cascade is **monotonic and single-shot**: Tier 1 is attempted once per session
12
+ * and, once in Tier 2, the flow stays there (no flap back). If Tier 2 itself
13
+ * never becomes ready, the caller fails closed rather than showing a blank QR.
14
+ */
15
+ export function createBackupTierController(callbacks) {
16
+ var tier = 'tier1';
17
+ var ready = false;
18
+ // Single-shot latch: once we leave Tier 1 it can never be re-entered, and a
19
+ // second trigger of any kind is a no-op.
20
+ var cascaded = false;
21
+ // Fail-closed latch: Tier 2 can be reported unavailable by both a load error
22
+ // and the safety timeout, but the host must only be exited once.
23
+ var failedClosed = false;
24
+ var timer = null;
25
+ var clearTimer = function () {
26
+ if (timer) {
27
+ clearTimeout(timer);
28
+ timer = null;
29
+ }
30
+ };
31
+ var failClosed = function () {
32
+ if (failedClosed)
33
+ return;
34
+ failedClosed = true;
35
+ clearTimer();
36
+ callbacks.onTier2Unavailable();
37
+ };
38
+ var cascadeToTier2 = function (reason) {
39
+ // Monotonic + single-shot: only ever from a not-yet-ready Tier 1.
40
+ if (cascaded || tier !== 'tier1' || ready)
41
+ return;
42
+ cascaded = true;
43
+ clearTimer();
44
+ tier = 'tier2';
45
+ ready = false;
46
+ callbacks.onFallback(reason);
47
+ // Fail-closed safety net: the bundled assets are local, so Tier 2 should
48
+ // become ready almost instantly; if it does not, surface an error.
49
+ timer = setTimeout(function () {
50
+ timer = null;
51
+ if (!ready)
52
+ failClosed();
53
+ }, TIER2_READY_TIMEOUT_MS);
54
+ };
55
+ return {
56
+ getTier: function () { return tier; },
57
+ start: function () {
58
+ if (ready || cascaded)
59
+ return;
60
+ clearTimer();
61
+ timer = setTimeout(function () {
62
+ timer = null;
63
+ cascadeToTier2('readyTimeout');
64
+ }, TIER1_READY_TIMEOUT_MS);
65
+ },
66
+ markReady: function () {
67
+ ready = true;
68
+ // Whichever tier just handshook is healthy — cancel its pending timer.
69
+ clearTimer();
70
+ },
71
+ reportLoadError: function () {
72
+ if (tier === 'tier1') {
73
+ // Immediate cascade — do not wait out the ready timeout (design §5H).
74
+ cascadeToTier2('loadError');
75
+ }
76
+ else if (!ready) {
77
+ // Tier 2 (local assets) failing to load is effectively impossible; if it
78
+ // happens, fail closed rather than reload into the same failure.
79
+ failClosed();
80
+ }
81
+ },
82
+ destroy: clearTimer
83
+ };
84
+ }
@@ -1,6 +1,6 @@
1
1
  import { LinkPayload, TransferFinishedPayload } from './types';
2
- export type LinkEventType = IntegrationConnected | IntegrationConnectionError | TransferCompleted | IntegrationSelected | CredentialsEntered | TransferStarted | TransferPreviewed | TransferPreviewError | TransferExecutionError | TransferConfigureError | PageLoaded | IntegrationMfaRequired | IntegrationMfaEntered | IntegrationOAuthStarted | IntegrationAccountSelectionRequired | TransferAssetSelected | TransferNetworkSelected | TransferAmountEntered | TransferMfaRequired | TransferMfaEntered | TransferKycRequired | TransferInitiated | TransferExecuted | TransferNoEligibleAssets | WalletMessageSigned | DoneEvent | CloseEvent | VerifyWalletRejected | VerifyDonePage | SDKinjectedWalletProviders | LegalTermsViewed | SeeWhatHappenedClicked | FundingOptionsUpdated | FundingOptionsViewed | GasIncreaseWarning | ExecuteFundingStep | LinkTransferQrGenerated | HomePageMethodSelected | ConnectionUnavailable | ConnectionDeclined | TransferDeclined | DefiWalletError | HomePageLoaded;
3
- declare const LINK_EVENT_TYPE_KEYS: readonly ["integrationConnected", "integrationConnectionError", "integrationMfaRequired", "integrationMfaEntered", "integrationOAuthStarted", "integrationAccountSelectionRequired", "transferCompleted", "integrationSelected", "credentialsEntered", "transferStarted", "transferPreviewed", "transferPreviewError", "transferExecutionError", "transferConfigureError", "pageLoaded", "transferAssetSelected", "transferNetworkSelected", "transferAmountEntered", "transferMfaRequired", "transferMfaEntered", "transferKycRequired", "transferExecuted", "transferInitiated", "transferNoEligibleAssets", "walletMessageSigned", "verifyDonePage", "verifyWalletRejected", "connectionDeclined", "connectionUnavailable", "transferDeclined", "done", "close", "SDKinjectedWalletProviders", "legalTermsViewed", "seeWhatHappenedClicked", "executeFundingStep", "fundingOptionsUpdated", "fundingOptionsViewed", "gasIncreaseWarning", "linkTransferQRGenerated", "methodSelected", "defiWalletError", "homePageLoaded"];
2
+ export type LinkEventType = IntegrationConnected | IntegrationConnectionError | TransferCompleted | IntegrationSelected | CredentialsEntered | TransferStarted | TransferPreviewed | TransferPreviewError | TransferExecutionError | TransferConfigureError | PageLoaded | IntegrationMfaRequired | IntegrationMfaEntered | IntegrationOAuthStarted | IntegrationAccountSelectionRequired | TransferAssetSelected | TransferNetworkSelected | TransferAmountEntered | TransferMfaRequired | TransferMfaEntered | TransferKycRequired | TransferInitiated | TransferExecuted | TransferNoEligibleAssets | WalletMessageSigned | DoneEvent | CloseEvent | VerifyWalletRejected | VerifyDonePage | SDKinjectedWalletProviders | LegalTermsViewed | SeeWhatHappenedClicked | FundingOptionsUpdated | FundingOptionsViewed | GasIncreaseWarning | ExecuteFundingStep | LinkTransferQrGenerated | HomePageMethodSelected | ConnectionUnavailable | ConnectionDeclined | TransferDeclined | DefiWalletError | HomePageLoaded | BackupTierChanged | WithdrawalRequested;
3
+ declare const LINK_EVENT_TYPE_KEYS: readonly ["integrationConnected", "integrationConnectionError", "integrationMfaRequired", "integrationMfaEntered", "integrationOAuthStarted", "integrationAccountSelectionRequired", "transferCompleted", "integrationSelected", "credentialsEntered", "transferStarted", "transferPreviewed", "transferPreviewError", "transferExecutionError", "transferConfigureError", "pageLoaded", "transferAssetSelected", "transferNetworkSelected", "transferAmountEntered", "transferMfaRequired", "transferMfaEntered", "transferKycRequired", "transferExecuted", "transferInitiated", "transferNoEligibleAssets", "walletMessageSigned", "verifyDonePage", "verifyWalletRejected", "connectionDeclined", "connectionUnavailable", "transferDeclined", "done", "close", "SDKinjectedWalletProviders", "legalTermsViewed", "seeWhatHappenedClicked", "executeFundingStep", "fundingOptionsUpdated", "fundingOptionsViewed", "gasIncreaseWarning", "linkTransferQRGenerated", "methodSelected", "defiWalletError", "homePageLoaded", "backupTierChanged", "withdrawalRequested"];
4
4
  export type LinkEventTypeKeys = (typeof LINK_EVENT_TYPE_KEYS)[number];
5
5
  export declare function isLinkEventTypeKey(key: string): key is LinkEventTypeKeys;
6
6
  interface LinkEventBase {
@@ -318,4 +318,25 @@ export interface HomePageMethodSelected {
318
318
  export interface HomePageLoaded extends LinkEventBase {
319
319
  type: 'homePageLoaded';
320
320
  }
321
+ /**
322
+ * Emitted once when the backup deposit flow cascades from Tier 1 (the widget
323
+ * loaded from the independent backup origin) to Tier 2 (the SDK-bundled offline
324
+ * widget), because the backup origin was unreachable (design §5H). Lets clients
325
+ * measure the real fallback rate.
326
+ */
327
+ export interface BackupTierChanged extends LinkEventBase {
328
+ type: 'backupTierChanged';
329
+ payload: {
330
+ from: 'tier1';
331
+ to: 'tier2';
332
+ reason: 'loadError' | 'readyTimeout';
333
+ };
334
+ }
335
+ export interface WithdrawalRequested extends LinkEventBase {
336
+ type: 'withdrawalRequested';
337
+ payload: {
338
+ transferId: string;
339
+ status: string;
340
+ };
341
+ }
321
342
  export {};
@@ -41,7 +41,9 @@ var LINK_EVENT_TYPE_KEYS = [
41
41
  'linkTransferQRGenerated',
42
42
  'methodSelected',
43
43
  'defiWalletError',
44
- 'homePageLoaded'
44
+ 'homePageLoaded',
45
+ 'backupTierChanged',
46
+ 'withdrawalRequested'
45
47
  ];
46
48
  export function isLinkEventTypeKey(key) {
47
49
  return LINK_EVENT_TYPE_KEYS.includes(key);
package/utils/types.d.ts CHANGED
@@ -8,6 +8,17 @@ export interface Link {
8
8
  * @param customIframeId - Optional custom ID for the existing iframe element. If not provided, a new iframe element will be created
9
9
  */
10
10
  openLink: (linkToken: string, customIframeId?: string) => void;
11
+ /**
12
+ * Opens the standalone backup deposit widget for use when the primary Mesh API
13
+ * is unavailable. Unlike {@link openLink} there is no link token — the widget is
14
+ * a static SPA served from an independent origin, hydrated with `session` over
15
+ * the message bridge after it loads. The host event contract
16
+ * (`onIntegrationConnected` / `onTransferFinished` / `onEvent` / `onExit`) is
17
+ * unchanged, so the same handlers passed to `createLink` apply to both paths.
18
+ * @param session - Backup deposit configuration, assembled server-side (canonical shape: OR-446).
19
+ * @param options - Optional `widgetOrigin` (defaults to `DEFAULT_BACKUP_WIDGET_ORIGIN`) and `customIframeId` for embedded mode.
20
+ */
21
+ openLinkBackup: (session: MeshBackupConfig, options?: MeshBackupOptions) => void;
11
22
  /**
12
23
  * A function to close Link UI popup
13
24
  */
@@ -17,6 +28,112 @@ export interface Link {
17
28
  */
18
29
  closeLinkRequested: () => void;
19
30
  }
31
+ /**
32
+ * A single deposit destination offered by the backup widget. When `address` is
33
+ * omitted it is resolved at runtime via the host's `onAddressInit` /
34
+ * `onStatusPoll` callbacks (see {@link LinkOptions}) — so those callbacks are
35
+ * required whenever any destination omits `address`.
36
+ */
37
+ export interface MeshBackupDestination {
38
+ /** Mesh network id for this destination. */
39
+ networkId: string;
40
+ /** Token symbol (e.g. `USDC`). */
41
+ symbol: string;
42
+ /** Static deposit address. Omit to resolve just-in-time via the JIT callbacks. */
43
+ address?: string;
44
+ /** Destination tag / memo, for networks that require one (e.g. XRP). */
45
+ addressTag?: string;
46
+ }
47
+ /**
48
+ * Configuration handed to the backup deposit widget. Assemble this server-side
49
+ * (destinations should not be built in untrusted client code) and pass it to
50
+ * {@link Link.openLinkBackup}; it is delivered to the widget over the message
51
+ * bridge after the widget loads. Canonical shape: OR-446 (updated OR-452 — there
52
+ * is no `jit` block or token; JIT is resolved through host callbacks).
53
+ */
54
+ export interface MeshBackupConfig {
55
+ /** The client's Mesh client id. */
56
+ clientId: string;
57
+ /**
58
+ * The client's end-user identifier. Used for analytics — it is **not** an
59
+ * authentication credential.
60
+ */
61
+ userId: string;
62
+ /** Deposit destinations to offer. At least one is required. */
63
+ destinations: MeshBackupDestination[];
64
+ /**
65
+ * Preselect a token symbol, skipping the token-select screen. Must match one
66
+ * of the destination symbols; an unknown symbol falls back to token select.
67
+ */
68
+ preselectedSymbol?: string;
69
+ }
70
+ /**
71
+ * The state an {@link LinkOptions.onStatusPoll} poll reports back. `pending`
72
+ * ⇒ the widget polls again; `ready` ⇒ the widget renders the deposit address
73
+ * (after its own echo + format fail-closed checks); `failed` ⇒ the widget
74
+ * surfaces an error.
75
+ */
76
+ export type MeshBackupJitStatus = 'pending' | 'ready' | 'failed';
77
+ /**
78
+ * What {@link LinkOptions.onStatusPoll} resolves to, as a discriminated union so
79
+ * a `ready` result cannot type-check without an `address`. On `ready`, `address`
80
+ * must be a valid deposit address for the requested network and `addressTag` is
81
+ * required for memo-chain networks (XRP, XLM, …), omitted otherwise. For a given
82
+ * `(symbol, networkId)` the resolved address/tag MUST be idempotent — always
83
+ * return the same one.
84
+ */
85
+ export type MeshBackupStatusResult = {
86
+ status: 'pending';
87
+ } | {
88
+ status: 'failed';
89
+ } | {
90
+ status: 'ready';
91
+ address: string;
92
+ addressTag?: string;
93
+ };
94
+ /** The two JIT calls the widget can make over the bridge (client spec §5/§6). */
95
+ export type MeshBackupJitMethod = 'addressInit' | 'statusPoll';
96
+ /**
97
+ * Widget → host JIT RPC request payload (OR-452). Correlated to the host's async
98
+ * response by `callId`. Mirrors `mesh-backup-widget`'s `BackupJitRequestPayload`.
99
+ */
100
+ export interface MeshBackupJitRequestPayload {
101
+ callId: string;
102
+ method: MeshBackupJitMethod;
103
+ symbol: string;
104
+ networkId: string;
105
+ }
106
+ /**
107
+ * Host → widget JIT RPC response payload (OR-452). `ok: true` with a `result`
108
+ * (for `statusPoll`) means the host callback resolved; `ok: false` with an
109
+ * `error` means it threw/rejected (or the callback was not provided). Mirrors
110
+ * `mesh-backup-widget`'s `BackupJitResponsePayload`.
111
+ */
112
+ export interface MeshBackupJitResponsePayload {
113
+ callId: string;
114
+ ok: boolean;
115
+ result?: MeshBackupStatusResult;
116
+ error?: string;
117
+ }
118
+ /**
119
+ * Optional arguments to {@link Link.openLinkBackup}.
120
+ */
121
+ export interface MeshBackupOptions {
122
+ /**
123
+ * Origin serving the standalone backup widget. Defaults to
124
+ * `DEFAULT_BACKUP_WIDGET_ORIGIN`. Override for staging, demo, or self-hosting.
125
+ * The widget served there must echo the per-open session nonce (`sid`) on its
126
+ * messages (mesh-backup-widget with the session-nonce bridge); an older build's
127
+ * messages are ignored and the flow falls back to the bundled Tier-2 widget.
128
+ */
129
+ widgetOrigin?: string;
130
+ /**
131
+ * Custom ID for an existing iframe element, mirroring {@link Link.openLink}'s
132
+ * embedded-mode param. Required when `createLink` was called with
133
+ * `renderType: 'embedded'`.
134
+ */
135
+ customIframeId?: string;
136
+ }
20
137
  export interface AccountToken {
21
138
  account: Account;
22
139
  accessToken: string;
@@ -108,10 +225,10 @@ export interface LinkOptions {
108
225
  */
109
226
  clientId?: string;
110
227
  /**
111
- * A callback function that is called when an integration is successfully connected.
228
+ * (Optional) A callback function that is called when an integration is successfully connected.
112
229
  * It receives a payload of type `LinkPayload`.
113
230
  */
114
- onIntegrationConnected: (payload: LinkPayload) => void;
231
+ onIntegrationConnected?: (payload: LinkPayload) => void;
115
232
  /**
116
233
  * (Optional) A callback function that is called when the Front iframe is closed.
117
234
  */
@@ -150,6 +267,24 @@ export interface LinkOptions {
150
267
  * - 'embedded': renders inside a client-supplied iframe for a more native UI experience. Requires `customIframeId` in `openLink`.
151
268
  */
152
269
  renderType?: 'overlay' | 'embedded';
270
+ /**
271
+ * (Backup flow only) Called once when the user confirms a token/network for a
272
+ * destination that omits `address`, to kick off just-in-time address
273
+ * generation against your own backend (with your own session). The return
274
+ * value is ignored — the widget moves straight to polling {@link onStatusPoll}
275
+ * — but a thrown error / rejected promise is treated as a generation failure.
276
+ * Required whenever any backup destination omits `address`.
277
+ */
278
+ onAddressInit?: (symbol: string, networkId: string) => void | Promise<unknown>;
279
+ /**
280
+ * (Backup flow only) Polled (~every 2–3s) after {@link onAddressInit} until it
281
+ * resolves `ready` or `failed`. Resolve to `{ status: 'ready', address, addressTag? }`
282
+ * once the address is available; `{ status: 'pending' }` to be polled again; or
283
+ * `{ status: 'failed' }` to abort. For a given `(symbol, networkId)` the
284
+ * resolved address MUST be idempotent. Required whenever any backup destination
285
+ * omits `address`.
286
+ */
287
+ onStatusPoll?: (symbol: string, networkId: string) => Promise<MeshBackupStatusResult>;
153
288
  }
154
289
  export interface LinkStyle {
155
290
  ir: number;
@@ -1 +1 @@
1
- export declare const sdkVersion = "3.13.0";
1
+ export declare const sdkVersion = "3.14.1";
package/utils/version.js CHANGED
@@ -1 +1 @@
1
- export var sdkVersion = '3.13.0';
1
+ export var sdkVersion = '3.14.1';