@tokenflight/swap 0.2.0-rc.1 → 0.3.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/active-bridge-DTyKObda.js +1 -0
- package/dist/bridge-C9uFKAdS.js +1 -0
- package/dist/bridge.d.ts +597 -0
- package/dist/bridge.js +1 -0
- package/dist/iframe.d.ts +354 -0
- package/dist/iframe.js +1 -0
- package/dist/register-defaults-lIJMUU-P.js +1 -0
- package/dist/register-widget-DQAzucnZ.js +5 -0
- package/dist/swap.css +1 -1
- package/dist/tokenflight-swap.d.ts +74 -56
- package/dist/tokenflight-swap.js +2 -2
- package/dist/tokenflight-swap.umd.cjs +6 -4
- package/dist/widget.d.ts +8 -3
- package/dist/widget.js +1 -1
- package/package.json +10 -2
- package/dist/register-widget-BBJXAjbv.js +0 -3
- /package/dist/{en-US-qDDiLksN.js → en-US-ChmhdVUe.js} +0 -0
- /package/dist/{ja-JP-C_ZBjfPb.js → ja-JP-BAX9fLqV.js} +0 -0
- /package/dist/{ko-KR-BHIB7ZQf.js → ko-KR-jwhmhUqJ.js} +0 -0
- /package/dist/{zh-CN-DpZbMBLR.js → zh-CN-fKcRI4Y8.js} +0 -0
- /package/dist/{zh-TW-CtmyKF1W.js → zh-TW-gFEUAIR6.js} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e=null;function t(t){e=t}function n(){return e}export{t as n,n as t};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e=1,t=0;function n(e,n){return{type:`tf:${e}`,protocolVersion:1,seq:++t,payload:n}}function r(e){if(typeof e!=`object`||!e)return null;let t=e;return typeof t.type!=`string`||!t.type.startsWith(`tf:`)||t.protocolVersion!==1||typeof t.seq!=`number`||!(`payload`in t)?null:e}function i(e,t){return e.type===t}var a=new Set;function o(){return crypto.randomUUID()}function s(e){if(a.has(e))return!1;if(a.add(e),a.size>1e4){let e=[...a];for(let t=0;t<5e3;t++)a.delete(e[t])}return!0}var c=[[/user (rejected|denied|cancelled|refused)/i,`USER_REJECTED`],[/chain.*switch|switch.*chain|network.*change/i,`CHAIN_SWITCH_FAILED`],[/insufficient.*funds|not enough/i,`INSUFFICIENT_FUNDS`],[/timed?\s*out|timeout/i,`TIMEOUT`]];function l(e){for(let[t,n]of c)if(t.test(e))return n;return`UNKNOWN`}function u(e){if(e instanceof Error){let t=e,n=t.code;return{code:typeof n==`string`?n:l(e.message),message:e.message,details:t.details}}if(typeof e==`string`)return{code:l(e),message:e};if(typeof e==`object`&&e){let t=e;return{code:typeof t.code==`string`?t.code:`UNKNOWN`,message:typeof t.message==`string`?t.message:String(e),details:t.details}}return{code:`UNKNOWN`,message:String(e)}}function d(e){let t=Error(e.message);return t.code=e.code,e.details!==void 0&&(t.details=e.details),t}var f,p=`https://embed.tokenflight.ai/widget`,m=15e3,h=500,g=class e{constructor(e){if(this.listeners=new Map,this.ready=!1,this.destroyed=!1,this.readyTimer=null,this.popup=null,this.popupPollTimer=null,this.popupOrderId=null,this.popupMessageHandler=null,this.handleMessage=e=>{if(this.destroyed||e.origin!==this.widgetOrigin||e.source!==this.iframe.contentWindow)return;let t=r(e.data);t&&(i(t,`tf:ready`)?this.handleReady(t.payload.version,t.payload.protocolVersion):i(t,`tf:signRequest`)?this.handleSignRequest(t.payload.requestId,t.payload.action,t.payload.timeoutMs):i(t,`tf:connectWallet`)?this.handleConnectWallet(t.payload.chainType):i(t,`tf:disconnectWallet`)?this.handleDisconnectWallet():i(t,`tf:event`)?this.handleWidgetEvent(t.payload.name,t.payload.data):i(t,`tf:resize`)?this.handleResize(t.payload.height):i(t,`tf:preOpenPopup`)?this.handlePreOpenPopup():i(t,`tf:navigatePopup`)&&this.navigatePopup(t.payload.url,t.payload.orderId))},this.options=e,this.wallet=e.wallet,typeof e.container==`string`){let t=document.querySelector(e.container);if(!t)throw Error(`TokenFlightBridge: container "${e.container}" not found`);this.container=t}else this.container=e.container;let t=e.iframeSrc??p,n=typeof window<`u`?window.location.href:void 0;this.widgetOrigin=new URL(t,n).origin,this.iframe=document.createElement(`iframe`),this.iframe.src=t,this.iframe.style.display=`block`,this.iframe.style.width=`100%`,this.iframe.style.height=`600px`,this.iframe.style.minWidth=`375px`,this.iframe.style.colorScheme=`normal`,this.iframe.style.borderRadius=`var(--tf-radius-xl, 20px)`,this.iframe.style.overflow=`hidden`,e.config.noBackground||(this.iframe.style.background=`var(--tf-bg, #0d0f14)`),e.config.noBorder?this.iframe.style.border=`none`:(this.iframe.style.border=`1px solid var(--tf-border, #252a38)`,this.iframe.style.boxShadow=`var(--tf-shadow-lg, none)`),this.iframe.setAttribute(`allow`,`camera;microphone;payment;clipboard-write`),this.iframe.setAttribute(`title`,`TokenFlight Widget`),this.container.appendChild(this.iframe),window.addEventListener(`message`,this.handleMessage),this.walletHandler=e=>{this.sendWalletState(e.type)},this.subscribeWalletEvents();let a=e.readyTimeout??m;this.readyTimer=setTimeout(()=>{!this.ready&&!this.destroyed&&e.onLoadError?.(Error(`TokenFlightBridge: widget did not send tf:ready within timeout`))},a)}setConfig(e){this.postToIframe(n(`setConfig`,e)),e.noBackground!==void 0&&(this.iframe.style.background=e.noBackground?``:`var(--tf-bg, #0d0f14)`),e.noBorder!==void 0&&(this.iframe.style.border=e.noBorder?`none`:`1px solid var(--tf-border, #252a38)`,this.iframe.style.boxShadow=e.noBorder?`none`:`var(--tf-shadow-lg, none)`)}setStyle(e){this.postToIframe(n(`setStyle`,e))}setWallet(e){this.unsubscribeWalletEvents(),this.wallet=e,this.subscribeWalletEvents(),this.sendWalletState()}on(e,t){let n=this.listeners.get(e);n||(n=new Set,this.listeners.set(e,n)),n.add(t)}off(e,t){this.listeners.get(e)?.delete(t)}destroy(){this.destroyed||(this.destroyed=!0,this.readyTimer&&(clearTimeout(this.readyTimer),this.readyTimer=null),window.removeEventListener(`message`,this.handleMessage),this.unsubscribeWalletEvents(),this.closePopup(),this.iframe.remove(),this.listeners.clear())}async handleReady(e,t){if(t!==1){this.options.onLoadError?.(Error(`TokenFlightBridge: protocol version mismatch (bridge=1, widget=${t})`));return}this.ready=!0,this.readyTimer&&(clearTimeout(this.readyTimer),this.readyTimer=null);let r=this.wallet?.isConnected()??!1,i=null;if(r&&this.wallet)try{i=await this.wallet.getAddress()}catch{}this.postToIframe(n(`init`,{config:this.options.config,style:this.options.style,walletAddress:i,connected:r})),this.options.onReady?.(e),this.emit(`ready`,{version:e})}async handleSignRequest(e,t,r){if(!this.wallet){this.postToIframe(n(`signResult`,{requestId:e,error:{code:`ADAPTER_ERROR`,message:`No wallet adapter configured`}}));return}try{let r=await this.wallet.executeWalletAction(t);this.postToIframe(n(`signResult`,{requestId:e,result:r}))}catch(t){this.postToIframe(n(`signResult`,{requestId:e,error:u(t)}))}}async handleConnectWallet(e){if(this.wallet)try{await this.wallet.connect(e)}catch{}}async handleDisconnectWallet(){if(this.wallet)try{await this.wallet.disconnect()}catch{}}handleWidgetEvent(e,t){let n=_[e];n&&this.emit(n,t)}handleResize(e){this.iframe.style.height=`${e}px`,this.emit(`resize`,{height:e})}handlePreOpenPopup(){this.closePopup(),this.popup=window.open(`about:blank`,`tf-payment`,`width=500,height=700`)}navigatePopup(e,t){if(!this.popup||this.popup.closed){this.postToIframe(n(`fiatPopupClosed`,{orderId:t}));return}try{let r=new URL(e);if(r.protocol!==`https:`&&r.protocol!==`http:`){this.postToIframe(n(`fiatPopupClosed`,{orderId:t}));return}}catch{this.postToIframe(n(`fiatPopupClosed`,{orderId:t}));return}this.popup.location.href=e,this.popupOrderId=t,this.installPopupMessageHandler(),this.popupPollTimer=setInterval(()=>{this.popup?.closed&&(this.closePopup(),this.postToIframe(n(`fiatPopupClosed`,{orderId:this.popupOrderId??t})),this.popupOrderId=null)},h)}installPopupMessageHandler(){if(this.popupMessageHandler)return;let e,t=this.options.config.fiatApiEndpoint;if(!t)return;try{e=new URL(t).origin}catch{return}let r=new Set([`widget_ready`,`order_completed`,`order_failed`,`widget_close`]);this.popupMessageHandler=t=>{if(this.destroyed||t.origin!==e)return;let i=t.data;if(!i||i.type!==`FIAT_WIDGET_EVENT`||typeof i.event!=`string`||!r.has(i.event))return;let a=this.popupOrderId;a&&(typeof i.orderId==`string`&&i.orderId!==a||this.postToIframe(n(`fiatProviderEvent`,{orderId:a,event:i.event,provider:typeof i.provider==`string`?i.provider:void 0,data:i.data??void 0})))},window.addEventListener(`message`,this.popupMessageHandler)}closePopup(){this.popupPollTimer&&(clearInterval(this.popupPollTimer),this.popupPollTimer=null),this.popupMessageHandler&&(window.removeEventListener(`message`,this.popupMessageHandler),this.popupMessageHandler=null),this.popup&&!this.popup.closed&&this.popup.close(),this.popup=null}subscribeWalletEvents(){if(this.wallet)for(let t of e.WALLET_EVENTS)this.wallet.on(t,this.walletHandler)}unsubscribeWalletEvents(){if(this.wallet)for(let t of e.WALLET_EVENTS)this.wallet.off(t,this.walletHandler)}async sendWalletState(e){if(!this.wallet)return;let t=this.wallet.isConnected(),r=null;if(t)try{r=await this.wallet.getAddress()}catch{}this.postToIframe(n(`walletState`,{connected:t,address:r,event:e}))}postToIframe(e){this.destroyed||this.iframe.contentWindow?.postMessage(e,this.widgetOrigin)}emit(e,t){let n=this.listeners.get(e);if(n)for(let e of n)try{e(t)}catch{}}};f=g,f.WALLET_EVENTS=[`connect`,`disconnect`,`chainChanged`,`accountsChanged`];var _={swapComplete:`swapComplete`,error:`error`,fiatOrderCreated:`fiatOrderCreated`,fiatOrderCompleted:`fiatOrderCompleted`};function v(e){return new g(e)}export{o as a,r as c,n as i,u as l,v as n,d as o,s as r,i as s,g as t,e as u};
|
package/dist/bridge.d.ts
ADDED
|
@@ -0,0 +1,597 @@
|
|
|
1
|
+
export declare interface BridgeEventMap {
|
|
2
|
+
ready: {
|
|
3
|
+
version: string;
|
|
4
|
+
};
|
|
5
|
+
swapComplete: {
|
|
6
|
+
orderId: string;
|
|
7
|
+
txHash?: string;
|
|
8
|
+
};
|
|
9
|
+
error: {
|
|
10
|
+
code: string;
|
|
11
|
+
message: string;
|
|
12
|
+
details?: unknown;
|
|
13
|
+
};
|
|
14
|
+
fiatOrderCreated: {
|
|
15
|
+
orderId: string;
|
|
16
|
+
widgetUrl: string;
|
|
17
|
+
};
|
|
18
|
+
fiatOrderCompleted: {
|
|
19
|
+
orderId: string;
|
|
20
|
+
status: string;
|
|
21
|
+
txHash?: string;
|
|
22
|
+
};
|
|
23
|
+
resize: {
|
|
24
|
+
height: number;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export declare type BridgeEventName = keyof BridgeEventMap;
|
|
29
|
+
|
|
30
|
+
export declare interface BridgeOptions {
|
|
31
|
+
/** Mount point — CSS selector or HTMLElement. */
|
|
32
|
+
container: string | HTMLElement;
|
|
33
|
+
/** Wallet adapter running on the host page. */
|
|
34
|
+
wallet?: IWalletAdapter;
|
|
35
|
+
/** Widget configuration. */
|
|
36
|
+
config: WidgetConfig;
|
|
37
|
+
/** Style overrides (CSS variables, custom CSS, remote stylesheet). */
|
|
38
|
+
style?: StyleOverrides;
|
|
39
|
+
/** Iframe source URL. Defaults to latest hosted widget. */
|
|
40
|
+
iframeSrc?: string;
|
|
41
|
+
/** Called when the widget iframe fails to load. */
|
|
42
|
+
onLoadError?: (error: Error) => void;
|
|
43
|
+
/** Called when the widget iframe is ready. */
|
|
44
|
+
onReady?: (version: string) => void;
|
|
45
|
+
/** Timeout in ms for waiting for tf:ready (default: 15000). */
|
|
46
|
+
readyTimeout?: number;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Chain type for multi-chain support */
|
|
50
|
+
declare type ChainType = "evm" | "solana";
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Consume a request ID (one-time use). Returns `true` if the ID was valid
|
|
54
|
+
* and not yet consumed, `false` if already consumed or unknown.
|
|
55
|
+
*/
|
|
56
|
+
export declare function consumeRequestId(id: string): boolean;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Create a typed bridge message envelope.
|
|
60
|
+
*
|
|
61
|
+
* ```ts
|
|
62
|
+
* const msg = createMessage("init", { config, walletAddress });
|
|
63
|
+
* // → { type: "tf:init", protocolVersion: 1, seq: 1, payload: { ... } }
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export declare function createMessage<T extends string, P>(type: T, payload: P): TfMessageEnvelope<T, P>;
|
|
67
|
+
|
|
68
|
+
/** Generate a unique request ID using crypto.randomUUID(). */
|
|
69
|
+
export declare function createRequestId(): string;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Create a new TokenFlight bridge instance.
|
|
73
|
+
*
|
|
74
|
+
* ```ts
|
|
75
|
+
* const bridge = createTokenFlightBridge({
|
|
76
|
+
* container: '#widget',
|
|
77
|
+
* wallet: adapter,
|
|
78
|
+
* config: { theme: 'dark', fromToken: '...' },
|
|
79
|
+
* });
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
export declare function createTokenFlightBridge(options: BridgeOptions): TokenFlightBridge;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Custom color overrides — keys are CSS variable names.
|
|
86
|
+
* Typed keys provide autocomplete; arbitrary `--tf-*` strings are also accepted.
|
|
87
|
+
*
|
|
88
|
+
* ```ts
|
|
89
|
+
* customColors: {
|
|
90
|
+
* "--tf-primary": "#FF6B00",
|
|
91
|
+
* "--tf-bg": "#1A1A2E",
|
|
92
|
+
* "--tf-button-radius": "4px",
|
|
93
|
+
* "--tf-widget-max-width": "480px",
|
|
94
|
+
* }
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
declare type CustomColors = Partial<Record<TfCssVar, string>> & Record<string, string>;
|
|
98
|
+
|
|
99
|
+
/** Reconstruct an Error from a SerializedError. */
|
|
100
|
+
export declare function deserializeError(err: SerializedError): Error & {
|
|
101
|
+
code: string;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
/** EVM wallet action via EIP-1193 */
|
|
105
|
+
declare interface EvmWalletAction {
|
|
106
|
+
type: "eip1193_request";
|
|
107
|
+
chainId: number;
|
|
108
|
+
method: string;
|
|
109
|
+
params: unknown[];
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Iframe-embed bridge integration for the fiat popup. When the widget is
|
|
114
|
+
* embedded as an iframe via `@tokenflight/swap/bridge`, the host page owns the
|
|
115
|
+
* payment popup (to avoid 3-level iframe nesting through the wrapper page).
|
|
116
|
+
* The widget delegates `window.open` to the host and consumes popup-closed
|
|
117
|
+
* notifications + forwarded provider events via callback registries.
|
|
118
|
+
*/
|
|
119
|
+
declare interface FiatIframeBridge {
|
|
120
|
+
/** Synchronously ask the host to pre-open a blank popup in the user-gesture chain. */
|
|
121
|
+
requestPreOpenPopup: () => void;
|
|
122
|
+
/** Ask the host to navigate the pre-opened popup to the wrapper URL. */
|
|
123
|
+
requestNavigatePopup: (url: string, orderId: string) => void;
|
|
124
|
+
/**
|
|
125
|
+
* Subscribe to popup-closed notifications forwarded from the host bridge.
|
|
126
|
+
* Returns an unsubscribe function. The handler receives the orderId the host
|
|
127
|
+
* was tracking; checkout state filters out stale closures by comparing it
|
|
128
|
+
* against the current `orderId()` signal.
|
|
129
|
+
*/
|
|
130
|
+
onPopupClosed: (handler: (closedOrderId: string) => void) => () => void;
|
|
131
|
+
/**
|
|
132
|
+
* Subscribe to provider terminal events forwarded from the host bridge.
|
|
133
|
+
* Returns an unsubscribe function. The host installs its own
|
|
134
|
+
* `FIAT_WIDGET_EVENT` listener (origin-validated against `fiatApiEndpoint`)
|
|
135
|
+
* and forwards matched events here so the widget's `paymentOutcome` signal
|
|
136
|
+
* can be driven exactly the same way as in non-iframe mode.
|
|
137
|
+
*/
|
|
138
|
+
onProviderEvent: (handler: (event: ForwardedFiatProviderEvent) => void) => () => void;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Payload of a forwarded provider event (extracted from the message envelope). */
|
|
142
|
+
declare type FiatProviderEventPayload = TfFiatProviderEventMessage["payload"];
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Forwarded provider terminal event payload — mirrors the postMessage event
|
|
146
|
+
* the wrapper page would dispatch directly in non-iframe mode. The host bridge
|
|
147
|
+
* unpacks `FIAT_WIDGET_EVENT` postMessages on its own window and re-broadcasts
|
|
148
|
+
* them as this shape via `tf:fiatProviderEvent`.
|
|
149
|
+
*/
|
|
150
|
+
declare interface ForwardedFiatProviderEvent {
|
|
151
|
+
orderId: string;
|
|
152
|
+
event: "widget_ready" | "order_completed" | "order_failed" | "widget_close";
|
|
153
|
+
provider?: string;
|
|
154
|
+
data?: Record<string, unknown>;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Get the host page origin from the referrer or document.referrer.
|
|
159
|
+
* Returns null if not in iframe mode or origin cannot be determined.
|
|
160
|
+
*/
|
|
161
|
+
export declare function getHostOrigin(): string | null;
|
|
162
|
+
|
|
163
|
+
/** Union of all Host → iframe messages. */
|
|
164
|
+
export declare type HostToIframeMessage = TfInitMessage | TfSetConfigMessage | TfSetStyleMessage | TfWalletStateMessage | TfSignResultMessage | TfFiatPopupClosedMessage | TfFiatProviderEventMessage;
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Wallet adapter that runs inside the widget iframe and proxies all
|
|
168
|
+
* wallet operations to the host page's real adapter via postMessage.
|
|
169
|
+
*/
|
|
170
|
+
export declare class IframeBridgeWalletAdapter implements IWalletAdapter {
|
|
171
|
+
readonly name = "IframeBridge";
|
|
172
|
+
readonly supportedActionTypes: WalletActionType[];
|
|
173
|
+
private connected;
|
|
174
|
+
private address;
|
|
175
|
+
private chainType;
|
|
176
|
+
private lastWalletSeq;
|
|
177
|
+
private readonly hostOrigin;
|
|
178
|
+
private readonly eventListeners;
|
|
179
|
+
private readonly pendingRequests;
|
|
180
|
+
private pendingConnect;
|
|
181
|
+
private pendingDisconnect;
|
|
182
|
+
private destroyed;
|
|
183
|
+
constructor(hostOrigin: string);
|
|
184
|
+
connect(chainType?: ChainType): Promise<void>;
|
|
185
|
+
disconnect(): Promise<void>;
|
|
186
|
+
isConnected(_chainType?: ChainType): boolean;
|
|
187
|
+
getAddress(_chainType?: ChainType): Promise<string | null>;
|
|
188
|
+
executeWalletAction(action: WalletAction): Promise<WalletActionResult>;
|
|
189
|
+
on(event: WalletEventType, handler: (event: WalletEvent) => void): void;
|
|
190
|
+
off(event: WalletEventType, handler: (event: WalletEvent) => void): void;
|
|
191
|
+
destroy(): void;
|
|
192
|
+
/** Set initial wallet state from tf:init payload. */
|
|
193
|
+
setInitialState(connected: boolean, address: string | null, chainType?: ChainType): void;
|
|
194
|
+
private handleMessage;
|
|
195
|
+
private handleWalletState;
|
|
196
|
+
private handleSignResult;
|
|
197
|
+
private postToHost;
|
|
198
|
+
private emit;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Runs inside the widget iframe. Listens for postMessage from the host Bridge
|
|
203
|
+
* and orchestrates config application and wallet adapter setup.
|
|
204
|
+
*
|
|
205
|
+
* Returns the IframeBridgeWalletAdapter that should be passed to the widget
|
|
206
|
+
* as its wallet adapter.
|
|
207
|
+
*/
|
|
208
|
+
export declare class IframeReceiver {
|
|
209
|
+
readonly walletAdapter: IframeBridgeWalletAdapter;
|
|
210
|
+
private readonly hostOrigin;
|
|
211
|
+
private readonly callbacks;
|
|
212
|
+
private destroyed;
|
|
213
|
+
private resizeObserver;
|
|
214
|
+
private lastReportedHeight;
|
|
215
|
+
/** Subscribers to forwarded popup-closed events (set by useFiatCheckout in bridge mode). */
|
|
216
|
+
private readonly popupClosedHandlers;
|
|
217
|
+
/** Subscribers to forwarded provider terminal events (also useFiatCheckout). */
|
|
218
|
+
private readonly providerEventHandlers;
|
|
219
|
+
constructor(hostOrigin: string, callbacks: IframeReceiverCallbacks);
|
|
220
|
+
/**
|
|
221
|
+
* Returns the {@link FiatIframeBridge} accessor object that
|
|
222
|
+
* `useFiatCheckout` consumes. Methods are bound to this receiver instance.
|
|
223
|
+
*/
|
|
224
|
+
getFiatBridge(): FiatIframeBridge;
|
|
225
|
+
/** Start observing widget root for height changes → tf:resize. */
|
|
226
|
+
observeResize(element: HTMLElement): void;
|
|
227
|
+
/** Emit a widget event to the host (e.g. swapComplete). */
|
|
228
|
+
emitEvent(name: string, data: unknown): void;
|
|
229
|
+
/** Request the host to pre-open a popup (fiat flow). */
|
|
230
|
+
requestPreOpenPopup(): void;
|
|
231
|
+
/** Request the host to navigate the popup to a URL (fiat flow). */
|
|
232
|
+
requestNavigatePopup(url: string, orderId: string): void;
|
|
233
|
+
/** Clean up all listeners and observers. */
|
|
234
|
+
destroy(): void;
|
|
235
|
+
private handleMessage;
|
|
236
|
+
private handleInit;
|
|
237
|
+
private postToHost;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export declare interface IframeReceiverCallbacks {
|
|
241
|
+
/** Called on tf:init — apply initial config to the widget. */
|
|
242
|
+
onInit: (config: WidgetConfig, style?: StyleOverrides) => void;
|
|
243
|
+
/** Called on tf:setConfig — apply config update. */
|
|
244
|
+
onConfigUpdate: (config: Partial<WidgetConfig>) => void;
|
|
245
|
+
/** Called on tf:setStyle — apply style overrides. */
|
|
246
|
+
onStyleUpdate: (style: StyleOverrides) => void;
|
|
247
|
+
/** Called on tf:fiatPopupClosed — used by fiat checkout in iframe mode. */
|
|
248
|
+
onFiatPopupClosed?: (orderId: string) => void;
|
|
249
|
+
/**
|
|
250
|
+
* Called on tf:fiatProviderEvent — host bridge forwards a provider terminal
|
|
251
|
+
* event from the popup wrapper page so the widget can drive `paymentOutcome`.
|
|
252
|
+
*/
|
|
253
|
+
onFiatProviderEvent?: (event: FiatProviderEventPayload) => void;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/** Union of all iframe → Host messages. */
|
|
257
|
+
export declare type IframeToHostMessage = TfReadyMessage | TfSignRequestMessage | TfConnectWalletMessage | TfDisconnectWalletMessage | TfEventMessage | TfResizeMessage | TfPreOpenPopupMessage | TfNavigatePopupMessage;
|
|
258
|
+
|
|
259
|
+
/** Check if the current window is running inside an iframe. */
|
|
260
|
+
export declare function isIframeMode(): boolean;
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Type guard: check if a message has a specific type.
|
|
264
|
+
*/
|
|
265
|
+
export declare function isMessageType<T extends TfBridgeMessage["type"]>(msg: TfBridgeMessage, type: T): msg is Extract<TfBridgeMessage, {
|
|
266
|
+
type: T;
|
|
267
|
+
}>;
|
|
268
|
+
|
|
269
|
+
/** Wallet adapter interface that all adapters must implement */
|
|
270
|
+
declare interface IWalletAdapter {
|
|
271
|
+
/** Human-readable name */
|
|
272
|
+
readonly name: string;
|
|
273
|
+
/** Icon URL */
|
|
274
|
+
readonly icon?: string;
|
|
275
|
+
/** Supported action types */
|
|
276
|
+
readonly supportedActionTypes: WalletActionType[];
|
|
277
|
+
/** Optional: supported chain IDs — when set, the widget only shows tokens on these chains */
|
|
278
|
+
readonly supportedChainIds?: number[];
|
|
279
|
+
/** Connect the wallet */
|
|
280
|
+
connect(chainType?: ChainType): Promise<void>;
|
|
281
|
+
/** Disconnect the wallet */
|
|
282
|
+
disconnect(): Promise<void>;
|
|
283
|
+
/** Check if connected */
|
|
284
|
+
isConnected(chainType?: ChainType): boolean;
|
|
285
|
+
/** Get the current address */
|
|
286
|
+
getAddress(chainType?: ChainType): Promise<string | null>;
|
|
287
|
+
/** Execute a wallet action */
|
|
288
|
+
executeWalletAction(action: WalletAction): Promise<WalletActionResult>;
|
|
289
|
+
/** Optional: sign a message */
|
|
290
|
+
signMessage?(message: string, chainType?: ChainType): Promise<string>;
|
|
291
|
+
/** Optional: open the wallet's native account/connected modal */
|
|
292
|
+
openAccountModal?(): Promise<void>;
|
|
293
|
+
/** Optional: clean up internal subscriptions and watchers */
|
|
294
|
+
destroy?(): void;
|
|
295
|
+
/** Subscribe to wallet events */
|
|
296
|
+
on(event: WalletEventType, handler: (event: WalletEvent) => void): void;
|
|
297
|
+
/** Unsubscribe from wallet events */
|
|
298
|
+
off(event: WalletEventType, handler: (event: WalletEvent) => void): void;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Validate and parse a raw postMessage data object as a bridge message.
|
|
303
|
+
* Returns `null` if the data is not a valid bridge message.
|
|
304
|
+
*/
|
|
305
|
+
export declare function parseMessage(data: unknown): TfBridgeMessage | null;
|
|
306
|
+
|
|
307
|
+
export declare interface SerializedError {
|
|
308
|
+
code: string;
|
|
309
|
+
message: string;
|
|
310
|
+
details?: unknown;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/** Serialize any error value into a structured object safe for postMessage. */
|
|
314
|
+
export declare function serializeError(err: unknown): SerializedError;
|
|
315
|
+
|
|
316
|
+
/** Solana sign and send transaction action */
|
|
317
|
+
declare interface SolanaSignAndSendAction {
|
|
318
|
+
type: "solana_signAndSendTransaction";
|
|
319
|
+
transaction: string;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/** Solana sign transaction action */
|
|
323
|
+
declare interface SolanaSignTransactionAction {
|
|
324
|
+
type: "solana_signTransaction";
|
|
325
|
+
transaction: string;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
export declare interface StyleOverrides {
|
|
329
|
+
/** CSS custom property overrides (only --tf-* keys accepted). */
|
|
330
|
+
vars?: Partial<Record<TfCssVar, string>> & Record<string, string>;
|
|
331
|
+
/** Raw CSS string injected into <style> inside the widget Shadow DOM.
|
|
332
|
+
* Use [part="..."] selectors. @import rules are stripped. Max 50 KB. */
|
|
333
|
+
css?: string;
|
|
334
|
+
/** URL to an external stylesheet loaded via <link> inside the widget.
|
|
335
|
+
* Must be HTTPS. */
|
|
336
|
+
cssUrl?: string;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/** Supported locale identifiers. Accepts any string for forward-compat; known values get bundled translations. */
|
|
340
|
+
declare type SupportedLocale = "en-US" | "zh-CN" | "zh-TW" | "ja-JP" | "ko-KR" | (string & {});
|
|
341
|
+
|
|
342
|
+
/** Payment methods available in swap widget */
|
|
343
|
+
declare type SwapPayMethod = "crypto" | "card";
|
|
344
|
+
|
|
345
|
+
/** Current protocol version. Bumped on breaking message format changes. */
|
|
346
|
+
export declare const TF_PROTOCOL_VERSION = 1;
|
|
347
|
+
|
|
348
|
+
/** Union of all bridge messages (both directions). */
|
|
349
|
+
export declare type TfBridgeMessage = HostToIframeMessage | IframeToHostMessage;
|
|
350
|
+
|
|
351
|
+
/** Request host to trigger wallet connection. */
|
|
352
|
+
export declare type TfConnectWalletMessage = TfMessageEnvelope<"connectWallet", {
|
|
353
|
+
chainType?: ChainType;
|
|
354
|
+
}>;
|
|
355
|
+
|
|
356
|
+
/** All first-party CSS custom properties exposed for theming. */
|
|
357
|
+
declare type TfCssVar = "--tf-bg" | "--tf-bg-secondary" | "--tf-bg-elevated" | "--tf-surface" | "--tf-surface-hover" | "--tf-input-bg" | "--tf-glass" | "--tf-text" | "--tf-text-secondary" | "--tf-text-tertiary" | "--tf-text-on-primary" | "--tf-border" | "--tf-border-light" | "--tf-primary" | "--tf-primary-alpha" | "--tf-primary-light" | "--tf-primary-glow" | "--tf-success" | "--tf-success-bg" | "--tf-error" | "--tf-error-bg" | "--tf-error-alpha" | "--tf-warning" | "--tf-warning-bg" | "--tf-shadow" | "--tf-shadow-lg" | "--tf-skeleton" | "--tf-radius-xs" | "--tf-radius-sm" | "--tf-radius" | "--tf-radius-lg" | "--tf-radius-xl" | "--tf-button-radius" | "--tf-widget-max-width" | "--tf-font-family" | "--tf-font-family-mono" | "--tf-font-size" | "--tf-line-height" | "--tf-font-sm" | "--tf-font-base" | "--tf-font-md" | "--tf-font-lg" | "--tf-font-xl" | "--tf-font-heading" | "--tf-font-amount" | "--tf-font-amount-lg" | "--tf-font-amount-sm";
|
|
358
|
+
|
|
359
|
+
/** Request host to disconnect wallet. */
|
|
360
|
+
export declare type TfDisconnectWalletMessage = TfMessageEnvelope<"disconnectWallet", Record<string, never>>;
|
|
361
|
+
|
|
362
|
+
/** Widget events (swapComplete, error, etc.). */
|
|
363
|
+
export declare type TfEventMessage = TfMessageEnvelope<"event", {
|
|
364
|
+
name: string;
|
|
365
|
+
data: unknown;
|
|
366
|
+
}>;
|
|
367
|
+
|
|
368
|
+
/** Notify widget that the fiat popup was closed by the user. */
|
|
369
|
+
export declare type TfFiatPopupClosedMessage = TfMessageEnvelope<"fiatPopupClosed", {
|
|
370
|
+
orderId: string;
|
|
371
|
+
}>;
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Forward a fiat provider terminal event from the host bridge to the widget.
|
|
375
|
+
*
|
|
376
|
+
* In iframe-embed mode the payment popup is opened by the host page, so the
|
|
377
|
+
* provider's wrapper script (`fiat.hyperstream.dev`) posts `FIAT_WIDGET_EVENT`
|
|
378
|
+
* messages to the host's `window.opener` — never to the widget iframe. The
|
|
379
|
+
* host bridge listens for those events (origin-validated against the widget
|
|
380
|
+
* config's `fiatApiEndpoint`, filtered by the active popup's orderId) and
|
|
381
|
+
* forwards them as this message so `useFiatCheckout` can drive the
|
|
382
|
+
* `paymentOutcome` signal exactly the same way it does in non-iframe mode.
|
|
383
|
+
*/
|
|
384
|
+
export declare type TfFiatProviderEventMessage = TfMessageEnvelope<"fiatProviderEvent", {
|
|
385
|
+
orderId: string;
|
|
386
|
+
/** Provider event name as forwarded by the wrapper bridge. */
|
|
387
|
+
event: "widget_ready" | "order_completed" | "order_failed" | "widget_close";
|
|
388
|
+
/** Provider id (e.g. "transak"). */
|
|
389
|
+
provider?: string;
|
|
390
|
+
/** Optional event-specific payload (failedReason, providerStatus, etc.). */
|
|
391
|
+
data?: Record<string, unknown>;
|
|
392
|
+
}>;
|
|
393
|
+
|
|
394
|
+
/** Initial config + wallet state, sent after tf:ready. */
|
|
395
|
+
export declare type TfInitMessage = TfMessageEnvelope<"init", {
|
|
396
|
+
config: WidgetConfig;
|
|
397
|
+
style?: StyleOverrides;
|
|
398
|
+
walletAddress?: string | null;
|
|
399
|
+
chainType?: ChainType;
|
|
400
|
+
connected?: boolean;
|
|
401
|
+
}>;
|
|
402
|
+
|
|
403
|
+
export declare interface TfMessageEnvelope<T extends string = string, P = unknown> {
|
|
404
|
+
type: `tf:${T}`;
|
|
405
|
+
protocolVersion: typeof TF_PROTOCOL_VERSION;
|
|
406
|
+
/** Monotonically increasing per sender — used for ordering & staleness detection. */
|
|
407
|
+
seq: number;
|
|
408
|
+
payload: P;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/** Request host to navigate the pre-opened popup to a fiat payment URL. */
|
|
412
|
+
export declare type TfNavigatePopupMessage = TfMessageEnvelope<"navigatePopup", {
|
|
413
|
+
url: string;
|
|
414
|
+
orderId: string;
|
|
415
|
+
}>;
|
|
416
|
+
|
|
417
|
+
/** Request host to pre-open a blank popup (must be in user gesture context). */
|
|
418
|
+
export declare type TfPreOpenPopupMessage = TfMessageEnvelope<"preOpenPopup", Record<string, never>>;
|
|
419
|
+
|
|
420
|
+
/** Widget loaded and ready. */
|
|
421
|
+
export declare type TfReadyMessage = TfMessageEnvelope<"ready", {
|
|
422
|
+
version: string;
|
|
423
|
+
protocolVersion: number;
|
|
424
|
+
}>;
|
|
425
|
+
|
|
426
|
+
/** Suggested iframe height for responsive layout. */
|
|
427
|
+
export declare type TfResizeMessage = TfMessageEnvelope<"resize", {
|
|
428
|
+
height: number;
|
|
429
|
+
}>;
|
|
430
|
+
|
|
431
|
+
/** Dynamic config update. */
|
|
432
|
+
export declare type TfSetConfigMessage = TfMessageEnvelope<"setConfig", Partial<WidgetConfig>>;
|
|
433
|
+
|
|
434
|
+
/** Dynamic style update. */
|
|
435
|
+
export declare type TfSetStyleMessage = TfMessageEnvelope<"setStyle", StyleOverrides>;
|
|
436
|
+
|
|
437
|
+
/** Request host to sign a transaction. */
|
|
438
|
+
export declare type TfSignRequestMessage = TfMessageEnvelope<"signRequest", {
|
|
439
|
+
requestId: string;
|
|
440
|
+
action: WalletAction;
|
|
441
|
+
timeoutMs?: number;
|
|
442
|
+
}>;
|
|
443
|
+
|
|
444
|
+
/** Response to a signing request. */
|
|
445
|
+
export declare type TfSignResultMessage = TfMessageEnvelope<"signResult", {
|
|
446
|
+
requestId: string;
|
|
447
|
+
result?: WalletActionResult;
|
|
448
|
+
error?: SerializedError;
|
|
449
|
+
}>;
|
|
450
|
+
|
|
451
|
+
/** Wallet state change (connect, disconnect, address change). */
|
|
452
|
+
export declare type TfWalletStateMessage = TfMessageEnvelope<"walletState", {
|
|
453
|
+
connected: boolean;
|
|
454
|
+
address: string | null;
|
|
455
|
+
chainType?: ChainType;
|
|
456
|
+
event?: WalletEventType;
|
|
457
|
+
}>;
|
|
458
|
+
|
|
459
|
+
/** Visual theme mode. */
|
|
460
|
+
declare type Theme = "light" | "dark" | "auto";
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Bridge that connects a host page's wallet adapter to a TokenFlight widget
|
|
464
|
+
* running inside an iframe via postMessage.
|
|
465
|
+
*
|
|
466
|
+
* ```ts
|
|
467
|
+
* const bridge = createTokenFlightBridge({
|
|
468
|
+
* container: '#swap-widget',
|
|
469
|
+
* wallet: adapter,
|
|
470
|
+
* config: { fromToken: '...', toToken: '...' },
|
|
471
|
+
* });
|
|
472
|
+
* bridge.on('swapComplete', (data) => { ... });
|
|
473
|
+
* bridge.destroy();
|
|
474
|
+
* ```
|
|
475
|
+
*/
|
|
476
|
+
export declare class TokenFlightBridge {
|
|
477
|
+
readonly iframe: HTMLIFrameElement;
|
|
478
|
+
private readonly container;
|
|
479
|
+
private wallet;
|
|
480
|
+
private readonly options;
|
|
481
|
+
private readonly listeners;
|
|
482
|
+
private readonly walletHandler;
|
|
483
|
+
private widgetOrigin;
|
|
484
|
+
private ready;
|
|
485
|
+
private destroyed;
|
|
486
|
+
private readyTimer;
|
|
487
|
+
private popup;
|
|
488
|
+
private popupPollTimer;
|
|
489
|
+
private popupOrderId;
|
|
490
|
+
/** Window listener forwarding FIAT_WIDGET_EVENT messages → tf:fiatProviderEvent. */
|
|
491
|
+
private popupMessageHandler;
|
|
492
|
+
constructor(options: BridgeOptions);
|
|
493
|
+
/** Update widget configuration without iframe reload. */
|
|
494
|
+
setConfig(config: Partial<WidgetConfig>): void;
|
|
495
|
+
/** Update style overrides. */
|
|
496
|
+
setStyle(style: StyleOverrides): void;
|
|
497
|
+
/** Set or replace the wallet adapter (supports deferred setup). */
|
|
498
|
+
setWallet(adapter: IWalletAdapter | undefined): void;
|
|
499
|
+
/** Subscribe to a widget event. */
|
|
500
|
+
on<K extends BridgeEventName>(event: K, handler: (data: BridgeEventMap[K]) => void): void;
|
|
501
|
+
/** Unsubscribe from a widget event. */
|
|
502
|
+
off<K extends BridgeEventName>(event: K, handler: (data: BridgeEventMap[K]) => void): void;
|
|
503
|
+
/** Remove iframe, clean up listeners, close popup if open. */
|
|
504
|
+
destroy(): void;
|
|
505
|
+
private handleMessage;
|
|
506
|
+
private handleReady;
|
|
507
|
+
private handleSignRequest;
|
|
508
|
+
private handleConnectWallet;
|
|
509
|
+
private handleDisconnectWallet;
|
|
510
|
+
private handleWidgetEvent;
|
|
511
|
+
private handleResize;
|
|
512
|
+
private handlePreOpenPopup;
|
|
513
|
+
/** Called internally when the widget wants to navigate the pre-opened popup. */
|
|
514
|
+
private navigatePopup;
|
|
515
|
+
/**
|
|
516
|
+
* Subscribe to provider terminal events arriving on the host window from
|
|
517
|
+
* the popup's wrapper page. Origin-validated against the widget config's
|
|
518
|
+
* `fiatApiEndpoint`; filtered by the active `popupOrderId`. Drops messages
|
|
519
|
+
* that don't match the expected `FiatWidgetEvent` shape.
|
|
520
|
+
*/
|
|
521
|
+
private installPopupMessageHandler;
|
|
522
|
+
private closePopup;
|
|
523
|
+
private static readonly WALLET_EVENTS;
|
|
524
|
+
private subscribeWalletEvents;
|
|
525
|
+
private unsubscribeWalletEvents;
|
|
526
|
+
private sendWalletState;
|
|
527
|
+
private postToIframe;
|
|
528
|
+
private emit;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* Flexible token identifier supporting:
|
|
533
|
+
* - Direct object: { chainId: 1, address: "0x..." }
|
|
534
|
+
* - CAIP-10 string: "eip155:1:0x..."
|
|
535
|
+
* - JSON string: '{"chainId":1,"address":"0x..."}'
|
|
536
|
+
*/
|
|
537
|
+
declare type TokenIdentifier = string | TokenTarget;
|
|
538
|
+
|
|
539
|
+
/** Token target as chain + address pair */
|
|
540
|
+
declare interface TokenTarget {
|
|
541
|
+
chainId: number;
|
|
542
|
+
address: string;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/** Union of all wallet action types */
|
|
546
|
+
declare type WalletAction = EvmWalletAction | SolanaSignTransactionAction | SolanaSignAndSendAction;
|
|
547
|
+
|
|
548
|
+
/** Result of executing a wallet action */
|
|
549
|
+
declare interface WalletActionResult {
|
|
550
|
+
success: boolean;
|
|
551
|
+
data?: unknown;
|
|
552
|
+
error?: string;
|
|
553
|
+
txHash?: string;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
/** Wallet action types */
|
|
557
|
+
declare type WalletActionType = "eip1193_request" | "solana_signTransaction" | "solana_signAndSendTransaction";
|
|
558
|
+
|
|
559
|
+
/** Well-known error codes for wallet operations. */
|
|
560
|
+
export declare type WalletErrorCode = "USER_REJECTED" | "CHAIN_SWITCH_FAILED" | "INSUFFICIENT_FUNDS" | "TIMEOUT" | "ADAPTER_ERROR" | "UNKNOWN";
|
|
561
|
+
|
|
562
|
+
/** Wallet event payload */
|
|
563
|
+
declare interface WalletEvent {
|
|
564
|
+
type: WalletEventType;
|
|
565
|
+
data?: unknown;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/** Wallet event types */
|
|
569
|
+
declare type WalletEventType = "connect" | "disconnect" | "chainChanged" | "accountsChanged";
|
|
570
|
+
|
|
571
|
+
export declare interface WidgetConfig {
|
|
572
|
+
apiEndpoint?: string;
|
|
573
|
+
fiatApiEndpoint?: string;
|
|
574
|
+
theme?: Theme;
|
|
575
|
+
locale?: SupportedLocale;
|
|
576
|
+
customColors?: CustomColors;
|
|
577
|
+
fromToken?: TokenIdentifier;
|
|
578
|
+
toToken?: TokenIdentifier | TokenIdentifier[];
|
|
579
|
+
tradeType?: "EXACT_INPUT" | "EXACT_OUTPUT";
|
|
580
|
+
amount?: string;
|
|
581
|
+
recipient?: string;
|
|
582
|
+
methods?: SwapPayMethod[];
|
|
583
|
+
defaultPayMethod?: SwapPayMethod;
|
|
584
|
+
fiatCurrency?: string;
|
|
585
|
+
fromTokens?: TokenIdentifier[];
|
|
586
|
+
toTokens?: TokenIdentifier[];
|
|
587
|
+
titleText?: string;
|
|
588
|
+
titleImageUrl?: string;
|
|
589
|
+
hideTitle?: boolean;
|
|
590
|
+
hidePoweredBy?: boolean;
|
|
591
|
+
noBackground?: boolean;
|
|
592
|
+
noBorder?: boolean;
|
|
593
|
+
lockFromToken?: boolean;
|
|
594
|
+
lockToToken?: boolean;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
export { }
|
package/dist/bridge.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{n as e}from"./active-bridge-DTyKObda.js";import{a as t,c as n,i as r,l as i,n as a,o,r as s,s as c,t as l,u}from"./bridge-C9uFKAdS.js";var d=12e4,f=6e4,p=class{constructor(e){this.name=`IframeBridge`,this.supportedActionTypes=[`eip1193_request`,`solana_signTransaction`,`solana_signAndSendTransaction`],this.connected=!1,this.address=null,this.lastWalletSeq=0,this.eventListeners=new Map,this.pendingRequests=new Map,this.pendingConnect=null,this.pendingDisconnect=null,this.destroyed=!1,this.handleMessage=e=>{if(this.destroyed||e.origin!==this.hostOrigin)return;let t=n(e.data);t&&(c(t,`tf:walletState`)?this.handleWalletState(t.payload,t.seq):c(t,`tf:signResult`)&&this.handleSignResult(t.payload.requestId,t.payload.result,t.payload.error))},this.hostOrigin=e,window.addEventListener(`message`,this.handleMessage)}async connect(e){return this.postToHost(r(`connectWallet`,{chainType:e})),new Promise((e,t)=>{this.pendingConnect={resolve:e,reject:t},setTimeout(()=>{this.pendingConnect&&(this.pendingConnect.reject(Error(`Wallet connection timed out`)),this.pendingConnect=null)},f)})}async disconnect(){return this.postToHost(r(`disconnectWallet`,{})),new Promise((e,t)=>{this.pendingDisconnect={resolve:e,reject:t},setTimeout(()=>{this.pendingDisconnect&&(this.pendingDisconnect.reject(Error(`Wallet disconnect timed out`)),this.pendingDisconnect=null)},f)})}isConnected(e){return this.connected}async getAddress(e){return this.address}async executeWalletAction(e){let n=t();return new Promise((t,i)=>{let a=setTimeout(()=>{this.pendingRequests.delete(n),i(Error(`Wallet action timed out`))},d);this.pendingRequests.set(n,{resolve:t,reject:i,timer:a}),this.postToHost(r(`signRequest`,{requestId:n,action:e}))})}on(e,t){let n=this.eventListeners.get(e);n||(n=new Set,this.eventListeners.set(e,n)),n.add(t)}off(e,t){this.eventListeners.get(e)?.delete(t)}destroy(){if(!this.destroyed){this.destroyed=!0,window.removeEventListener(`message`,this.handleMessage);for(let[,e]of this.pendingRequests)clearTimeout(e.timer),e.reject(Error(`Bridge destroyed`));this.pendingRequests.clear(),this.pendingConnect&&(this.pendingConnect.reject(Error(`Bridge destroyed`)),this.pendingConnect=null),this.pendingDisconnect&&(this.pendingDisconnect.reject(Error(`Bridge destroyed`)),this.pendingDisconnect=null),this.eventListeners.clear()}}setInitialState(e,t,n){this.connected=e,this.address=t,this.chainType=n}handleWalletState(e,t){if(t<=this.lastWalletSeq)return;this.lastWalletSeq=t;let n=this.connected;this.connected=e.connected,this.address=e.address,e.chainType&&(this.chainType=e.chainType),e.connected&&this.pendingConnect&&(this.pendingConnect.resolve(),this.pendingConnect=null),!e.connected&&this.pendingDisconnect&&(this.pendingDisconnect.resolve(),this.pendingDisconnect=null),e.event?this.emit(e.event,{type:e.event,data:e}):e.connected&&!n?this.emit(`connect`,{type:`connect`,data:e}):!e.connected&&n?this.emit(`disconnect`,{type:`disconnect`,data:e}):e.connected&&this.emit(`accountsChanged`,{type:`accountsChanged`,data:e})}handleSignResult(e,t,n){let r=this.pendingRequests.get(e);r&&(this.pendingRequests.delete(e),clearTimeout(r.timer),n?r.reject(o(n)):t?r.resolve(t):r.reject(Error(`Invalid sign result: missing both result and error`)))}postToHost(e){this.destroyed||typeof window>`u`||!window.parent||window.parent.postMessage(e,this.hostOrigin)}emit(e,t){let n=this.eventListeners.get(e);if(n)for(let e of n)try{e(t)}catch{}}},m=`__TF_VERSION__`,h=class{constructor(t,i){this.destroyed=!1,this.resizeObserver=null,this.lastReportedHeight=0,this.popupClosedHandlers=new Set,this.providerEventHandlers=new Set,this.handleMessage=e=>{if(this.destroyed||e.origin!==this.hostOrigin)return;let t=n(e.data);if(t){if(c(t,`tf:init`))this.handleInit(t.payload);else if(c(t,`tf:setConfig`))this.callbacks.onConfigUpdate(t.payload);else if(c(t,`tf:setStyle`))this.callbacks.onStyleUpdate(t.payload);else if(c(t,`tf:fiatPopupClosed`)){let e=t.payload.orderId;this.callbacks.onFiatPopupClosed?.(e);for(let t of this.popupClosedHandlers)t(e)}else if(c(t,`tf:fiatProviderEvent`)){let e=t.payload;this.callbacks.onFiatProviderEvent?.(e);for(let t of this.providerEventHandlers)t(e)}}},this.hostOrigin=t,this.callbacks=i,this.walletAdapter=new p(t),window.addEventListener(`message`,this.handleMessage),e(this.getFiatBridge()),this.postToHost(r(`ready`,{version:m,protocolVersion:1}))}getFiatBridge(){return{requestPreOpenPopup:()=>this.requestPreOpenPopup(),requestNavigatePopup:(e,t)=>this.requestNavigatePopup(e,t),onPopupClosed:e=>(this.popupClosedHandlers.add(e),()=>this.popupClosedHandlers.delete(e)),onProviderEvent:e=>(this.providerEventHandlers.add(e),()=>this.providerEventHandlers.delete(e))}}observeResize(e){this.resizeObserver=new ResizeObserver(e=>{let t=e[0];if(!t)return;let n=Math.ceil(t.borderBoxSize?.[0]?.blockSize??t.contentRect.height);Math.abs(n-this.lastReportedHeight)<2||(this.lastReportedHeight=n,this.postToHost(r(`resize`,{height:n})))}),this.resizeObserver.observe(e)}emitEvent(e,t){this.postToHost(r(`event`,{name:e,data:t}))}requestPreOpenPopup(){this.postToHost(r(`preOpenPopup`,{}))}requestNavigatePopup(e,t){this.postToHost(r(`navigatePopup`,{url:e,orderId:t}))}destroy(){this.destroyed||(this.destroyed=!0,window.removeEventListener(`message`,this.handleMessage),this.walletAdapter.destroy(),this.popupClosedHandlers.clear(),this.providerEventHandlers.clear(),e(null),this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null))}handleInit(e){this.walletAdapter.setInitialState(e.connected??!1,e.walletAddress??null,e.chainType),this.callbacks.onInit(e.config,e.style)}postToHost(e){this.destroyed||window.parent.postMessage(e,this.hostOrigin)}};function g(){try{return window!==window.top}catch{return!0}}function _(){if(!g())return null;try{if(document.referrer)return new URL(document.referrer).origin}catch{}return null}export{p as IframeBridgeWalletAdapter,h as IframeReceiver,u as TF_PROTOCOL_VERSION,l as TokenFlightBridge,s as consumeRequestId,r as createMessage,t as createRequestId,a as createTokenFlightBridge,o as deserializeError,_ as getHostOrigin,g as isIframeMode,c as isMessageType,n as parseMessage,i as serializeError};
|