@cowprotocol/widget-lib 2.3.0 → 3.1.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/IframeCowEventEmitter.d.ts +1 -1
- package/README.md +2 -2
- package/const.d.ts +1 -0
- package/cowSwapWidget.constants.d.ts +11 -0
- package/cowSwapWidget.d.ts +1 -0
- package/index.cjs +1 -1
- package/index.d.ts +2 -0
- package/index.js +215 -175
- package/package.json +3 -3
- package/types.d.ts +16 -1
- package/urlUtils.d.ts +14 -0
|
@@ -4,7 +4,7 @@ export declare class IframeCowEventEmitter {
|
|
|
4
4
|
private eventEmitter;
|
|
5
5
|
private listeners;
|
|
6
6
|
private widgetListener;
|
|
7
|
-
constructor(contentWindow: Window, iframeOrigin: string, listeners?: CowWidgetEventListeners);
|
|
7
|
+
constructor(contentWindow: Window, iframeOrigin: string, iframeWindow: Window, listeners?: CowWidgetEventListeners);
|
|
8
8
|
stopListeningIframe(): void;
|
|
9
9
|
updateListeners(listeners?: CowWidgetEventListeners): void;
|
|
10
10
|
}
|
package/README.md
CHANGED
|
@@ -6,11 +6,11 @@ look and much more!
|
|
|
6
6
|
|
|
7
7
|
## Live example
|
|
8
8
|
|
|
9
|
-
See the widget in action in the [widget configurator](https://widget.cow.
|
|
9
|
+
See the widget in action in the [widget configurator](https://widget.cow.fi)
|
|
10
10
|
|
|
11
11
|
## Docs
|
|
12
12
|
|
|
13
|
-
You can find a detailed description of all widget parameters in the [documentation](https://docs.cow.
|
|
13
|
+
You can find a detailed description of all widget parameters in the [documentation](https://docs.cow.fi/cow-protocol/tutorials/widget)
|
|
14
14
|
|
|
15
15
|
## Quick start
|
|
16
16
|
|
package/const.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const COWSWAP_ORIGIN = "https://swap.cow.fi";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Iframe sandbox allowlist for the embedded CoW Swap app.
|
|
3
|
+
* - allow-scripts + allow-same-origin: required for the SPA, storage, and same-origin API calls.
|
|
4
|
+
* - allow-forms: trade inputs and similar controls.
|
|
5
|
+
* - allow-popups + allow-popups-to-escape-sandbox: wallet connect / WalletConnect windows.
|
|
6
|
+
*/
|
|
7
|
+
export declare const WIDGET_IFRAME_SANDBOX = "allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox";
|
|
8
|
+
/** Limits referrer leakage when the widget is embedded on third-party origins. */
|
|
9
|
+
export declare const WIDGET_IFRAME_REFERRER_POLICY = "strict-origin-when-cross-origin";
|
|
10
|
+
/** Permissions policy features delegated to the widget iframe (see HTML `allow` attribute). */
|
|
11
|
+
export declare const WIDGET_IFRAME_ALLOW = "clipboard-read; clipboard-write";
|
package/cowSwapWidget.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { CowSwapWidgetParams, CowSwapWidgetProps, EthereumProvider } from './typ
|
|
|
4
4
|
* Callback function signature for updating the CoW Swap Widget.
|
|
5
5
|
*/
|
|
6
6
|
export interface CowSwapWidgetHandler {
|
|
7
|
+
iframe: HTMLIFrameElement;
|
|
7
8
|
updateParams: (params: CowSwapWidgetParams) => void;
|
|
8
9
|
updateListeners: (newListeners?: CowWidgetEventListeners) => void;
|
|
9
10
|
updateProvider: (newProvider?: EthereumProvider) => void;
|
package/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const S=require("@cowprotocol/iframe-transport"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const S=require("@cowprotocol/iframe-transport"),G=require("@cowprotocol/events"),N="allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox",v="strict-origin-when-cross-origin",U="clipboard-read; clipboard-write";var c=(e=>(e.ACTIVATE="ACTIVATE",e.READY="READY",e.UPDATE_HEIGHT="UPDATE_HEIGHT",e.SET_FULL_HEIGHT="SET_FULL_HEIGHT",e.EMIT_COW_EVENT="EMIT_COW_EVENT",e.PROVIDER_RPC_REQUEST="PROVIDER_RPC_REQUEST",e.INTERCEPT_WINDOW_OPEN="INTERCEPT_WINDOW_OPEN",e.PROCESS_HOOK="PROCESS_HOOK",e))(c||{}),O=(e=>(e.UPDATE_PARAMS="UPDATE_PARAMS",e.UPDATE_APP_DATA="UPDATE_APP_DATA",e.PROVIDER_RPC_RESPONSE="PROVIDER_RPC_RESPONSE",e.PROVIDER_ON_EVENT="PROVIDER_ON_EVENT",e.HOOK_RESULT="HOOK_RESULT",e))(O||{}),p=(e=>(e.ON_BEFORE_APPROVAL="ON_BEFORE_APPROVAL",e.ON_BEFORE_TRADE="ON_BEFORE_TRADE",e.ON_BEFORE_WRAP_UNWRAP="ON_BEFORE_WRAP_UNWRAP",e.ON_BEFORE_ORDER_CANCEL="ON_BEFORE_ORDER_CANCEL",e.ON_BEFORE_ORDERS_CANCEL="ON_BEFORE_ORDERS_CANCEL",e))(p||{}),h=(e=>(e.SWAP="swap",e.LIMIT="limit",e.ADVANCED="advanced",e.YIELD="yield",e))(h||{});const $=["primary","background","paper","text","danger","warning","alert","info","success"],d=new S.IframeTransport("cowSwapWidget");class j{constructor(t,n,o,r=[]){this.contentWindow=t,this.updateListeners(r),this.widgetListener=d.listenToMessageFromWindow(this.contentWindow,o,c.EMIT_COW_EVENT,i=>this.eventEmitter.emit(i.event,i.payload),n)}eventEmitter=new G.SimpleCowEventEmitter;listeners=[];widgetListener;stopListeningIframe(){d.stopListeningWindowListener(this.contentWindow,this.widgetListener)}updateListeners(t){for(const n of this.listeners)this.eventEmitter.off(n);this.listeners=t||[];for(const n of this.listeners)this.eventEmitter.on(n)}}class x{constructor(t,n){this.appWindow=t,this.iframeWidow=n,this.forwardSdkMessage=o=>{Q(o.data)&&(typeof window<"u"&&o.origin===window.location.origin||(K(o.data)?this.appWindow.parent.postMessage(o.data,"*"):Y(o.data)&&this.iframeWidow.postMessage(o.data,"*")))},this.startListening()}forwardSdkMessage;startListening(){this.appWindow.addEventListener("message",this.forwardSdkMessage)}stopListening(){this.appWindow.removeEventListener("message",this.forwardSdkMessage)}}function Q(e){return typeof e=="object"&&e!==null&&"id"in e&&typeof e.id=="string"}function K(e){return"method"in e&&typeof e.method=="string"&&"params"in e&&"env"in e&&typeof e.env=="object"&&e.env!==null&&"sdkVersion"in e.env}function Y(e){return"success"in e&&typeof e.success=="boolean"&&"version"in e&&typeof e.version=="string"}function X(e="Default",t="#1c5dbf",...n){console.debug(`%c [COW][${e}]`,`font-weight: bold; color: ${t}`,...n)}function z(...e){process.env.NODE_ENV!=="test"&&X("Widget","#47aba8",...e)}const F="https://swap.cow.fi";function b(e){return!!(e&&typeof e=="object")}const W="_",J="CoW Swap widget: invalid baseUrl.",H=!1;function Z(e){return e==="localhost"||e==="127.0.0.1"||e==="::1"||e.endsWith(".localhost")}function g(e,t){const n=`${J} ${e}`;if(t)throw new Error(n);return console.error("[CoW Widget]",n),F}function y(e,t=H){const n=typeof e=="string"?e.trim():"";if(!n)return F;let o;try{o=new URL(n)}catch{return g(`Not a valid URL: ${JSON.stringify(n)}`,t)}if(o.username||o.password)return g("Userinfo (username/password) in URL is not allowed.",t);const r=o.protocol==="https:",i=o.protocol==="http:"&&Z(o.hostname);if(!r&&!i)return g(`Use https, or http only on localhost / 127.0.0.1 / ::1 / *.localhost (got ${o.protocol}//${o.hostname}).`,t);const u=o.pathname==="/"||o.pathname===""?"":o.pathname.replace(/\/+$/,"");return`${o.origin}${u}`}function q(e){const t=y(e.baseUrl),n=B(e);return t+"/#"+n+"?"+M(e)}function B(e){const{chainId:t=1,sell:n,buy:o,tradeType:r=h.SWAP}=e,i=[n?.asset||W,o?.asset||W].map(encodeURIComponent).join("/");return`/${t}/widget/${r}/${i}`}function M(e){const t=new URLSearchParams;return re(oe(ne(te(ee(t,e),e),e),e),e)}function ee(e,t){const{sell:n,buy:o}=t;return n?.amount&&e.append("sellAmount",n.amount),o?.amount&&e.append("buyAmount",o.amount),e}function te(e,t){const n=t.theme;return n?(b(n)?(e.append("palette",encodeURIComponent(JSON.stringify(n))),e.append("theme",n.baseTheme)):(e.append("palette","null"),e.append("theme",n)),e):(e.append("palette","null"),e)}function ne(e,t){return t.targetChainId&&e.append("targetChainId",t.targetChainId.toString()),e}function oe(e,t){return t.locale&&e.append("lng",t.locale),e}function re(e,t){return ie(t.hooks)?e.append("hooksEnabled","true"):e.delete("hooksEnabled"),e}function ie(e){return!!e&&Object.values(e).some(Boolean)}const V="640px",se="450px",ae=20,de={iframe:document.createElement("iframe"),updateParams:()=>{},updateListeners:()=>{},updateProvider:()=>{},destroy:()=>{}};function le(e,t){const{params:n,provider:o,listeners:r,onReady:i}=t;let u=o,f=n;if(typeof window>"u")return de;const l=ce(n),s=ue(l);z("Resolved trusted iframe origin",{iframeOrigin:s});const w=[];i&&w.push(pe(l.contentWindow||window,s,i)),e.innerHTML="",e.appendChild(l);const{contentWindow:a}=l;if(!a)throw console.error("Iframe does not contain a window",l),new Error("Iframe does not contain a window!");w.push(Ee(a,s,n.appCode)),w.push(...Re(l,s,n.height,n.maxHeight));let T=null;function L(){a&&(T&&window.removeEventListener("message",T),!f.disableWindowOpen&&(T=fe(s,a),w.push(T)))}let A=null;function I(){a&&(A&&window.removeEventListener("message",A),A=Ae(a,s,f.hooks),w.push(A))}L(),I();const m=new j(window,s,a,r);let P=C(a,s,null,u);l.addEventListener("load",()=>{D(a,s,f,u)});const k=new x(window,a);return{iframe:l,updateParams:E=>{f=E,D(a,s,f,u),L(),I()},updateListeners:E=>m.updateListeners(E),updateProvider:E=>{u=E,P=C(a,s,P,E)},destroy:()=>{P.disconnect(),m.stopListeningIframe(),w.forEach(E=>window.removeEventListener("message",E)),k.stopListening(),e.removeChild(l)}}}function C(e,t,n,o){n&&n.disconnect();const r=n||new S.IframeRpcProviderBridge(e,t);return o&&r.onConnect(o),r}function ce(e){const{width:t=se,height:n=V}=e,o=document.createElement("iframe");return o.src=q(e),o.width=t,o.height=n,o.style.border="0",o.setAttribute("sandbox",N),o.referrerPolicy=v,o.allow=U,o}function ue(e){return new URL(e.src).origin}function D(e,t,n,o){const r=!!o,i=B(n),u=M(n).toString(),{theme:f,hooks:l,...s}=n;d.postMessageToWindow(e,O.UPDATE_PARAMS,{urlParams:{pathname:i,search:u},appParams:s,hasProvider:r},t)}function Ee(e,t,n){return d.listenToMessageFromWindow(window,e,c.ACTIVATE,()=>{d.postMessageToWindow(e,O.UPDATE_APP_DATA,{metaData:n?{appCode:n}:void 0},t)},t)}function pe(e,t,n){let o=!1;return d.listenToMessageFromWindow(window,e,c.READY,()=>{o||(o=!0,n())},t)}function fe(e,t){return d.listenToMessageFromWindow(window,t,c.INTERCEPT_WINDOW_OPEN,({href:n,rel:o,target:r})=>{const i=we(n.toString(),e);i&&_e(i)&&window.open(i,r,o)},e)}function we(e,t){const n=e.trim();if(!n)return null;try{return new URL(n,t).toString()}catch{return null}}function _e(e){try{const t=new URL(e).protocol;return t==="http:"||t==="https:"}catch{return!1}}function Re(e,t,n=V,o){return e.contentWindow?[d.listenToMessageFromWindow(window,e.contentWindow,c.UPDATE_HEIGHT,r=>{const i=r.height?r.height+ae:void 0;e.style.height=i?`${o?Math.min(i,o):i}px`:n},t),d.listenToMessageFromWindow(window,e.contentWindow,c.SET_FULL_HEIGHT,({isUpToSmall:r})=>{e.style.height=r?n:`${o||document.body.offsetHeight}px`},t)]:[]}const Oe={[p.ON_BEFORE_APPROVAL]:(e,t)=>t?.onBeforeApproval?t.onBeforeApproval(e):!0,[p.ON_BEFORE_TRADE]:(e,t)=>t?.onBeforeTrade?t.onBeforeTrade(e):!0,[p.ON_BEFORE_WRAP_UNWRAP]:(e,t)=>t?.onBeforeWrapOrUnwrap?t.onBeforeWrapOrUnwrap(e):!0,[p.ON_BEFORE_ORDER_CANCEL]:(e,t)=>t?.onBeforeOrderCancel?t.onBeforeOrderCancel(e):!0,[p.ON_BEFORE_ORDERS_CANCEL]:(e,t)=>t?.onBeforeOrdersCancel?t.onBeforeOrdersCancel(e):!0};function Te(e,t){return Oe[e.event](e.payload,t)}function Ae(e,t,n){return d.listenToMessageFromWindow(window,e,c.PROCESS_HOOK,async o=>{let r=!1;try{r=await Te(o,n)}catch{}d.postMessageToWindow(e,O.HOOK_RESULT,{id:o.id,result:r},t)},t)}const he=Object.values(h);function Pe(e,t,n){if(_(e)){const o=e[n];return R(o)?o[t]:o}if(R(e)){const o=e[t];return _(o)?o[n]:o}return e}function _(e){return typeof e!="object"?!1:Object.keys(e).every(t=>he.includes(t))}const ge=/^\d+$/;function R(e){return typeof e!="object"?!1:Object.keys(e).every(t=>ge.test(t))}function Le(e){return _(e)?Object.values(e).flatMap(t=>R(t)?Object.values(t):[t]):R(e)?Object.values(e).flatMap(t=>_(t)?Object.values(t):[t]):[e]}exports.SHOULD_THROW_IF_INVALID_URL=H;exports.TradeType=h;exports.WIDGET_IFRAME_ALLOW=U;exports.WIDGET_IFRAME_REFERRER_POLICY=v;exports.WIDGET_IFRAME_SANDBOX=N;exports.WIDGET_PALETTE_COLORS=$;exports.WidgetHookEvents=p;exports.WidgetMethodsEmit=c;exports.WidgetMethodsListen=O;exports.createCowSwapWidget=le;exports.isCowSwapWidgetPalette=b;exports.isPerNetworkConfig=R;exports.isPerTradeTypeConfig=_;exports.resolveFlexibleConfig=Pe;exports.resolveFlexibleConfigValues=Le;exports.sanitizeWidgetBaseUrl=y;exports.widgetIframeTransport=d;
|
package/index.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
export { createCowSwapWidget } from './cowSwapWidget';
|
|
2
|
+
export { WIDGET_IFRAME_ALLOW, WIDGET_IFRAME_REFERRER_POLICY, WIDGET_IFRAME_SANDBOX } from './cowSwapWidget.constants';
|
|
2
3
|
export { widgetIframeTransport } from './widgetIframeTransport';
|
|
3
4
|
export type { CowSwapWidgetHandler } from './cowSwapWidget';
|
|
4
5
|
export { resolveFlexibleConfigValues } from './resolveFlexibleConfigValues';
|
|
6
|
+
export { sanitizeWidgetBaseUrl, SHOULD_THROW_IF_INVALID_URL } from './urlUtils';
|
|
5
7
|
export * from './types';
|
|
6
8
|
export * from './themeUtils';
|
|
7
9
|
export * from './flexibleConfig';
|
package/index.js
CHANGED
|
@@ -1,29 +1,30 @@
|
|
|
1
|
-
import { IframeTransport as
|
|
2
|
-
import { SimpleCowEventEmitter as
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import { IframeTransport as b, IframeRpcProviderBridge as F } from "@cowprotocol/iframe-transport";
|
|
2
|
+
import { SimpleCowEventEmitter as y } from "@cowprotocol/events";
|
|
3
|
+
const B = "allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox", M = "strict-origin-when-cross-origin", V = "clipboard-read; clipboard-write";
|
|
4
|
+
var p = /* @__PURE__ */ ((e) => (e.ACTIVATE = "ACTIVATE", e.READY = "READY", e.UPDATE_HEIGHT = "UPDATE_HEIGHT", e.SET_FULL_HEIGHT = "SET_FULL_HEIGHT", e.EMIT_COW_EVENT = "EMIT_COW_EVENT", e.PROVIDER_RPC_REQUEST = "PROVIDER_RPC_REQUEST", e.INTERCEPT_WINDOW_OPEN = "INTERCEPT_WINDOW_OPEN", e.PROCESS_HOOK = "PROCESS_HOOK", e))(p || {}), h = /* @__PURE__ */ ((e) => (e.UPDATE_PARAMS = "UPDATE_PARAMS", e.UPDATE_APP_DATA = "UPDATE_APP_DATA", e.PROVIDER_RPC_RESPONSE = "PROVIDER_RPC_RESPONSE", e.PROVIDER_ON_EVENT = "PROVIDER_ON_EVENT", e.HOOK_RESULT = "HOOK_RESULT", e))(h || {}), w = /* @__PURE__ */ ((e) => (e.ON_BEFORE_APPROVAL = "ON_BEFORE_APPROVAL", e.ON_BEFORE_TRADE = "ON_BEFORE_TRADE", e.ON_BEFORE_WRAP_UNWRAP = "ON_BEFORE_WRAP_UNWRAP", e.ON_BEFORE_ORDER_CANCEL = "ON_BEFORE_ORDER_CANCEL", e.ON_BEFORE_ORDERS_CANCEL = "ON_BEFORE_ORDERS_CANCEL", e))(w || {}), m = /* @__PURE__ */ ((e) => (e.SWAP = "swap", e.LIMIT = "limit", e.ADVANCED = "advanced", e.YIELD = "yield", e))(m || {});
|
|
5
|
+
const ge = ["primary", "background", "paper", "text", "danger", "warning", "alert", "info", "success"], d = new b("cowSwapWidget");
|
|
6
|
+
class k {
|
|
7
|
+
constructor(t, n, o, r = []) {
|
|
8
|
+
this.contentWindow = t, this.updateListeners(r), this.widgetListener = d.listenToMessageFromWindow(this.contentWindow, o, p.EMIT_COW_EVENT, (i) => this.eventEmitter.emit(i.event, i.payload), n);
|
|
8
9
|
}
|
|
9
|
-
eventEmitter = new
|
|
10
|
+
eventEmitter = new y();
|
|
10
11
|
listeners = [];
|
|
11
12
|
widgetListener;
|
|
12
13
|
stopListeningIframe() {
|
|
13
|
-
|
|
14
|
+
d.stopListeningWindowListener(this.contentWindow, this.widgetListener);
|
|
14
15
|
}
|
|
15
|
-
updateListeners(
|
|
16
|
-
for (const
|
|
17
|
-
this.eventEmitter.off(
|
|
18
|
-
this.listeners =
|
|
19
|
-
for (const
|
|
20
|
-
this.eventEmitter.on(
|
|
16
|
+
updateListeners(t) {
|
|
17
|
+
for (const n of this.listeners)
|
|
18
|
+
this.eventEmitter.off(n);
|
|
19
|
+
this.listeners = t || [];
|
|
20
|
+
for (const n of this.listeners)
|
|
21
|
+
this.eventEmitter.on(n);
|
|
21
22
|
}
|
|
22
23
|
}
|
|
23
|
-
class
|
|
24
|
-
constructor(
|
|
25
|
-
this.appWindow =
|
|
26
|
-
|
|
24
|
+
class $ {
|
|
25
|
+
constructor(t, n) {
|
|
26
|
+
this.appWindow = t, this.iframeWidow = n, this.forwardSdkMessage = (o) => {
|
|
27
|
+
G(o.data) && (typeof window < "u" && o.origin === window.location.origin || (j(o.data) ? this.appWindow.parent.postMessage(o.data, "*") : x(o.data) && this.iframeWidow.postMessage(o.data, "*")));
|
|
27
28
|
}, this.startListening();
|
|
28
29
|
}
|
|
29
30
|
forwardSdkMessage;
|
|
@@ -34,66 +35,95 @@ class H {
|
|
|
34
35
|
this.appWindow.removeEventListener("message", this.forwardSdkMessage);
|
|
35
36
|
}
|
|
36
37
|
}
|
|
37
|
-
function
|
|
38
|
+
function G(e) {
|
|
38
39
|
return typeof e == "object" && e !== null && "id" in e && typeof e.id == "string";
|
|
39
40
|
}
|
|
40
|
-
function
|
|
41
|
+
function j(e) {
|
|
41
42
|
return "method" in e && typeof e.method == "string" && "params" in e && "env" in e && typeof e.env == "object" && e.env !== null && "sdkVersion" in e.env;
|
|
42
43
|
}
|
|
43
|
-
function
|
|
44
|
+
function x(e) {
|
|
44
45
|
return "success" in e && typeof e.success == "boolean" && "version" in e && typeof e.version == "string";
|
|
45
46
|
}
|
|
46
|
-
function
|
|
47
|
-
console.debug(`%c [COW][${e}]`, `font-weight: bold; color: ${
|
|
47
|
+
function Q(e = "Default", t = "#1c5dbf", ...n) {
|
|
48
|
+
console.debug(`%c [COW][${e}]`, `font-weight: bold; color: ${t}`, ...n);
|
|
48
49
|
}
|
|
49
|
-
function
|
|
50
|
-
|
|
50
|
+
function K(...e) {
|
|
51
|
+
process.env.NODE_ENV !== "test" && Q("Widget", "#47aba8", ...e);
|
|
51
52
|
}
|
|
52
|
-
|
|
53
|
+
const S = "https://swap.cow.fi";
|
|
54
|
+
function Y(e) {
|
|
53
55
|
return !!(e && typeof e == "object");
|
|
54
56
|
}
|
|
55
|
-
const C = "_";
|
|
56
|
-
function
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
const C = "_", X = "CoW Swap widget: invalid baseUrl.", J = !1;
|
|
58
|
+
function z(e) {
|
|
59
|
+
return e === "localhost" || e === "127.0.0.1" || e === "::1" || e.endsWith(".localhost");
|
|
60
|
+
}
|
|
61
|
+
function P(e, t) {
|
|
62
|
+
const n = `${X} ${e}`;
|
|
63
|
+
if (t)
|
|
64
|
+
throw new Error(n);
|
|
65
|
+
return console.error("[CoW Widget]", n), S;
|
|
66
|
+
}
|
|
67
|
+
function Z(e, t = J) {
|
|
68
|
+
const n = typeof e == "string" ? e.trim() : "";
|
|
69
|
+
if (!n)
|
|
70
|
+
return S;
|
|
71
|
+
let o;
|
|
72
|
+
try {
|
|
73
|
+
o = new URL(n);
|
|
74
|
+
} catch {
|
|
75
|
+
return P(`Not a valid URL: ${JSON.stringify(n)}`, t);
|
|
76
|
+
}
|
|
77
|
+
if (o.username || o.password)
|
|
78
|
+
return P("Userinfo (username/password) in URL is not allowed.", t);
|
|
79
|
+
const r = o.protocol === "https:", i = o.protocol === "http:" && z(o.hostname);
|
|
80
|
+
if (!r && !i)
|
|
81
|
+
return P(`Use https, or http only on localhost / 127.0.0.1 / ::1 / *.localhost (got ${o.protocol}//${o.hostname}).`, t);
|
|
82
|
+
const l = o.pathname === "/" || o.pathname === "" ? "" : o.pathname.replace(/\/+$/, "");
|
|
83
|
+
return `${o.origin}${l}`;
|
|
59
84
|
}
|
|
60
|
-
function
|
|
85
|
+
function q(e) {
|
|
86
|
+
const t = Z(e.baseUrl), n = N(e);
|
|
87
|
+
return t + "/#" + n + "?" + v(e);
|
|
88
|
+
}
|
|
89
|
+
function N(e) {
|
|
61
90
|
const {
|
|
62
|
-
chainId:
|
|
63
|
-
sell:
|
|
91
|
+
chainId: t = 1,
|
|
92
|
+
sell: n,
|
|
64
93
|
buy: o,
|
|
65
|
-
tradeType: r =
|
|
66
|
-
} = e,
|
|
67
|
-
return `/${
|
|
94
|
+
tradeType: r = m.SWAP
|
|
95
|
+
} = e, i = [n?.asset || C, o?.asset || C].map(encodeURIComponent).join("/");
|
|
96
|
+
return `/${t}/widget/${r}/${i}`;
|
|
68
97
|
}
|
|
69
|
-
function
|
|
70
|
-
const
|
|
71
|
-
return
|
|
98
|
+
function v(e) {
|
|
99
|
+
const t = new URLSearchParams();
|
|
100
|
+
return re(oe(ne(te(ee(t, e), e), e), e), e);
|
|
72
101
|
}
|
|
73
|
-
function
|
|
102
|
+
function ee(e, t) {
|
|
74
103
|
const {
|
|
75
|
-
sell:
|
|
104
|
+
sell: n,
|
|
76
105
|
buy: o
|
|
77
|
-
} =
|
|
78
|
-
return
|
|
106
|
+
} = t;
|
|
107
|
+
return n?.amount && e.append("sellAmount", n.amount), o?.amount && e.append("buyAmount", o.amount), e;
|
|
79
108
|
}
|
|
80
|
-
function
|
|
81
|
-
const
|
|
82
|
-
return
|
|
109
|
+
function te(e, t) {
|
|
110
|
+
const n = t.theme;
|
|
111
|
+
return n ? (Y(n) ? (e.append("palette", encodeURIComponent(JSON.stringify(n))), e.append("theme", n.baseTheme)) : (e.append("palette", "null"), e.append("theme", n)), e) : (e.append("palette", "null"), e);
|
|
83
112
|
}
|
|
84
|
-
function
|
|
85
|
-
return
|
|
113
|
+
function ne(e, t) {
|
|
114
|
+
return t.targetChainId && e.append("targetChainId", t.targetChainId.toString()), e;
|
|
86
115
|
}
|
|
87
|
-
function
|
|
88
|
-
return
|
|
116
|
+
function oe(e, t) {
|
|
117
|
+
return t.locale && e.append("lng", t.locale), e;
|
|
89
118
|
}
|
|
90
|
-
function
|
|
91
|
-
return
|
|
119
|
+
function re(e, t) {
|
|
120
|
+
return ie(t.hooks) ? e.append("hooksEnabled", "true") : e.delete("hooksEnabled"), e;
|
|
92
121
|
}
|
|
93
|
-
function
|
|
122
|
+
function ie(e) {
|
|
94
123
|
return !!e && Object.values(e).some(Boolean);
|
|
95
124
|
}
|
|
96
|
-
const
|
|
125
|
+
const U = "640px", se = "450px", ae = 20, de = {
|
|
126
|
+
iframe: document.createElement("iframe"),
|
|
97
127
|
updateParams: () => {
|
|
98
128
|
},
|
|
99
129
|
updateListeners: () => {
|
|
@@ -103,190 +133,200 @@ const N = "640px", J = "450px", X = 20, z = {
|
|
|
103
133
|
destroy: () => {
|
|
104
134
|
}
|
|
105
135
|
};
|
|
106
|
-
function
|
|
136
|
+
function Le(e, t) {
|
|
107
137
|
const {
|
|
108
|
-
params:
|
|
138
|
+
params: n,
|
|
109
139
|
provider: o,
|
|
110
140
|
listeners: r,
|
|
111
|
-
onReady:
|
|
112
|
-
} =
|
|
113
|
-
let
|
|
114
|
-
if (typeof window > "u") return
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
iframeOrigin:
|
|
141
|
+
onReady: i
|
|
142
|
+
} = t;
|
|
143
|
+
let l = o, E = n;
|
|
144
|
+
if (typeof window > "u") return de;
|
|
145
|
+
const c = ce(n), s = le(c);
|
|
146
|
+
K("Resolved trusted iframe origin", {
|
|
147
|
+
iframeOrigin: s
|
|
118
148
|
});
|
|
119
149
|
const f = [];
|
|
120
|
-
|
|
150
|
+
i && f.push(pe(c.contentWindow || window, s, i)), e.innerHTML = "", e.appendChild(c);
|
|
121
151
|
const {
|
|
122
|
-
contentWindow:
|
|
123
|
-
} =
|
|
124
|
-
if (!
|
|
125
|
-
throw console.error("Iframe does not contain a window",
|
|
126
|
-
f.push(
|
|
152
|
+
contentWindow: a
|
|
153
|
+
} = c;
|
|
154
|
+
if (!a)
|
|
155
|
+
throw console.error("Iframe does not contain a window", c), new Error("Iframe does not contain a window!");
|
|
156
|
+
f.push(ue(a, s, n.appCode)), f.push(..._e(c, s, n.height, n.maxHeight));
|
|
127
157
|
let _ = null;
|
|
128
|
-
function
|
|
129
|
-
|
|
158
|
+
function g() {
|
|
159
|
+
a && (_ && window.removeEventListener("message", _), !E.disableWindowOpen && (_ = Ee(s, a), f.push(_)));
|
|
130
160
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
161
|
+
let O = null;
|
|
162
|
+
function L() {
|
|
163
|
+
a && (O && window.removeEventListener("message", O), O = Te(a, s, E.hooks), f.push(O));
|
|
164
|
+
}
|
|
165
|
+
g(), L();
|
|
166
|
+
const I = new k(window, s, a, r);
|
|
167
|
+
let A = W(a, s, null, l);
|
|
168
|
+
c.addEventListener("load", () => {
|
|
169
|
+
D(a, s, E, l);
|
|
136
170
|
});
|
|
137
|
-
const
|
|
171
|
+
const H = new $(window, a);
|
|
138
172
|
return {
|
|
139
|
-
|
|
140
|
-
|
|
173
|
+
iframe: c,
|
|
174
|
+
updateParams: (u) => {
|
|
175
|
+
E = u, D(a, s, E, l), g(), L();
|
|
141
176
|
},
|
|
142
|
-
updateListeners: (
|
|
143
|
-
updateProvider: (
|
|
144
|
-
|
|
177
|
+
updateListeners: (u) => I.updateListeners(u),
|
|
178
|
+
updateProvider: (u) => {
|
|
179
|
+
l = u, A = W(a, s, A, u);
|
|
145
180
|
},
|
|
146
181
|
destroy: () => {
|
|
147
|
-
|
|
182
|
+
A.disconnect(), I.stopListeningIframe(), f.forEach((u) => window.removeEventListener("message", u)), H.stopListening(), e.removeChild(c);
|
|
148
183
|
}
|
|
149
184
|
};
|
|
150
185
|
}
|
|
151
|
-
function
|
|
152
|
-
|
|
153
|
-
const r =
|
|
186
|
+
function W(e, t, n, o) {
|
|
187
|
+
n && n.disconnect();
|
|
188
|
+
const r = n || new F(e, t);
|
|
154
189
|
return o && r.onConnect(o), r;
|
|
155
190
|
}
|
|
156
|
-
function
|
|
191
|
+
function ce(e) {
|
|
157
192
|
const {
|
|
158
|
-
width:
|
|
159
|
-
height:
|
|
193
|
+
width: t = se,
|
|
194
|
+
height: n = U
|
|
160
195
|
} = e, o = document.createElement("iframe");
|
|
161
|
-
return o.src =
|
|
196
|
+
return o.src = q(e), o.width = t, o.height = n, o.style.border = "0", o.setAttribute("sandbox", B), o.referrerPolicy = M, o.allow = V, o;
|
|
162
197
|
}
|
|
163
|
-
function
|
|
198
|
+
function le(e) {
|
|
164
199
|
return new URL(e.src).origin;
|
|
165
200
|
}
|
|
166
|
-
function
|
|
167
|
-
const r = !!o,
|
|
168
|
-
theme:
|
|
169
|
-
hooks:
|
|
170
|
-
...
|
|
171
|
-
} =
|
|
172
|
-
|
|
201
|
+
function D(e, t, n, o) {
|
|
202
|
+
const r = !!o, i = N(n), l = v(n).toString(), {
|
|
203
|
+
theme: E,
|
|
204
|
+
hooks: c,
|
|
205
|
+
...s
|
|
206
|
+
} = n;
|
|
207
|
+
d.postMessageToWindow(e, h.UPDATE_PARAMS, {
|
|
173
208
|
urlParams: {
|
|
174
|
-
pathname:
|
|
175
|
-
search:
|
|
209
|
+
pathname: i,
|
|
210
|
+
search: l
|
|
176
211
|
},
|
|
177
|
-
appParams:
|
|
212
|
+
appParams: s,
|
|
178
213
|
hasProvider: r
|
|
179
|
-
},
|
|
214
|
+
}, t);
|
|
180
215
|
}
|
|
181
|
-
function
|
|
182
|
-
return
|
|
183
|
-
|
|
184
|
-
metaData:
|
|
185
|
-
appCode:
|
|
216
|
+
function ue(e, t, n) {
|
|
217
|
+
return d.listenToMessageFromWindow(window, e, p.ACTIVATE, () => {
|
|
218
|
+
d.postMessageToWindow(e, h.UPDATE_APP_DATA, {
|
|
219
|
+
metaData: n ? {
|
|
220
|
+
appCode: n
|
|
186
221
|
} : void 0
|
|
187
|
-
},
|
|
188
|
-
},
|
|
222
|
+
}, t);
|
|
223
|
+
}, t);
|
|
189
224
|
}
|
|
190
|
-
function
|
|
225
|
+
function pe(e, t, n) {
|
|
191
226
|
let o = !1;
|
|
192
|
-
return
|
|
193
|
-
o || (o = !0,
|
|
194
|
-
},
|
|
227
|
+
return d.listenToMessageFromWindow(window, e, p.READY, () => {
|
|
228
|
+
o || (o = !0, n());
|
|
229
|
+
}, t);
|
|
195
230
|
}
|
|
196
|
-
function
|
|
197
|
-
return
|
|
231
|
+
function Ee(e, t) {
|
|
232
|
+
return d.listenToMessageFromWindow(window, t, p.INTERCEPT_WINDOW_OPEN, ({
|
|
198
233
|
href: n,
|
|
199
|
-
rel:
|
|
200
|
-
target:
|
|
234
|
+
rel: o,
|
|
235
|
+
target: r
|
|
201
236
|
}) => {
|
|
202
|
-
const
|
|
203
|
-
|
|
237
|
+
const i = fe(n.toString(), e);
|
|
238
|
+
i && we(i) && window.open(i, r, o);
|
|
204
239
|
}, e);
|
|
205
240
|
}
|
|
206
|
-
function
|
|
207
|
-
const
|
|
208
|
-
if (!
|
|
241
|
+
function fe(e, t) {
|
|
242
|
+
const n = e.trim();
|
|
243
|
+
if (!n)
|
|
209
244
|
return null;
|
|
210
245
|
try {
|
|
211
|
-
return new URL(
|
|
246
|
+
return new URL(n, t).toString();
|
|
212
247
|
} catch {
|
|
213
248
|
return null;
|
|
214
249
|
}
|
|
215
250
|
}
|
|
216
|
-
function
|
|
251
|
+
function we(e) {
|
|
217
252
|
try {
|
|
218
|
-
const
|
|
219
|
-
return
|
|
253
|
+
const t = new URL(e).protocol;
|
|
254
|
+
return t === "http:" || t === "https:";
|
|
220
255
|
} catch {
|
|
221
256
|
return !1;
|
|
222
257
|
}
|
|
223
258
|
}
|
|
224
|
-
function
|
|
225
|
-
return [
|
|
226
|
-
const
|
|
227
|
-
e.style.height =
|
|
228
|
-
},
|
|
259
|
+
function _e(e, t, n = U, o) {
|
|
260
|
+
return e.contentWindow ? [d.listenToMessageFromWindow(window, e.contentWindow, p.UPDATE_HEIGHT, (r) => {
|
|
261
|
+
const i = r.height ? r.height + ae : void 0;
|
|
262
|
+
e.style.height = i ? `${o ? Math.min(i, o) : i}px` : n;
|
|
263
|
+
}, t), d.listenToMessageFromWindow(window, e.contentWindow, p.SET_FULL_HEIGHT, ({
|
|
229
264
|
isUpToSmall: r
|
|
230
265
|
}) => {
|
|
231
|
-
e.style.height = r ?
|
|
232
|
-
},
|
|
233
|
-
}
|
|
234
|
-
const
|
|
235
|
-
[
|
|
236
|
-
[
|
|
237
|
-
[
|
|
238
|
-
[
|
|
239
|
-
[
|
|
266
|
+
e.style.height = r ? n : `${o || document.body.offsetHeight}px`;
|
|
267
|
+
}, t)] : [];
|
|
268
|
+
}
|
|
269
|
+
const Oe = {
|
|
270
|
+
[w.ON_BEFORE_APPROVAL]: (e, t) => t?.onBeforeApproval ? t.onBeforeApproval(e) : !0,
|
|
271
|
+
[w.ON_BEFORE_TRADE]: (e, t) => t?.onBeforeTrade ? t.onBeforeTrade(e) : !0,
|
|
272
|
+
[w.ON_BEFORE_WRAP_UNWRAP]: (e, t) => t?.onBeforeWrapOrUnwrap ? t.onBeforeWrapOrUnwrap(e) : !0,
|
|
273
|
+
[w.ON_BEFORE_ORDER_CANCEL]: (e, t) => t?.onBeforeOrderCancel ? t.onBeforeOrderCancel(e) : !0,
|
|
274
|
+
[w.ON_BEFORE_ORDERS_CANCEL]: (e, t) => t?.onBeforeOrdersCancel ? t.onBeforeOrdersCancel(e) : !0
|
|
240
275
|
};
|
|
241
|
-
function
|
|
242
|
-
return
|
|
276
|
+
function Re(e, t) {
|
|
277
|
+
return Oe[e.event](e.payload, t);
|
|
243
278
|
}
|
|
244
|
-
function
|
|
245
|
-
return
|
|
279
|
+
function Te(e, t, n) {
|
|
280
|
+
return d.listenToMessageFromWindow(window, e, p.PROCESS_HOOK, async (o) => {
|
|
246
281
|
let r = !1;
|
|
247
282
|
try {
|
|
248
|
-
r = await
|
|
283
|
+
r = await Re(o, n);
|
|
249
284
|
} catch {
|
|
250
285
|
}
|
|
251
|
-
|
|
286
|
+
d.postMessageToWindow(e, h.HOOK_RESULT, {
|
|
252
287
|
id: o.id,
|
|
253
288
|
result: r
|
|
254
|
-
},
|
|
255
|
-
},
|
|
289
|
+
}, t);
|
|
290
|
+
}, t);
|
|
256
291
|
}
|
|
257
|
-
const
|
|
258
|
-
function
|
|
259
|
-
if (O(e)) {
|
|
260
|
-
const o = e[t];
|
|
261
|
-
return R(o) ? o[n] : o;
|
|
262
|
-
}
|
|
292
|
+
const he = Object.values(m);
|
|
293
|
+
function Ie(e, t, n) {
|
|
263
294
|
if (R(e)) {
|
|
264
295
|
const o = e[n];
|
|
265
|
-
return
|
|
296
|
+
return T(o) ? o[t] : o;
|
|
297
|
+
}
|
|
298
|
+
if (T(e)) {
|
|
299
|
+
const o = e[t];
|
|
300
|
+
return R(o) ? o[n] : o;
|
|
266
301
|
}
|
|
267
302
|
return e;
|
|
268
303
|
}
|
|
269
|
-
function O(e) {
|
|
270
|
-
return typeof e != "object" ? !1 : Object.keys(e).every((n) => ue.includes(n));
|
|
271
|
-
}
|
|
272
|
-
const ce = /^\d+$/;
|
|
273
304
|
function R(e) {
|
|
274
|
-
return typeof e != "object" ? !1 : Object.keys(e).every((
|
|
305
|
+
return typeof e != "object" ? !1 : Object.keys(e).every((t) => he.includes(t));
|
|
306
|
+
}
|
|
307
|
+
const Ae = /^\d+$/;
|
|
308
|
+
function T(e) {
|
|
309
|
+
return typeof e != "object" ? !1 : Object.keys(e).every((t) => Ae.test(t));
|
|
275
310
|
}
|
|
276
|
-
function
|
|
277
|
-
return
|
|
311
|
+
function Ce(e) {
|
|
312
|
+
return R(e) ? Object.values(e).flatMap((t) => T(t) ? Object.values(t) : [t]) : T(e) ? Object.values(e).flatMap((t) => R(t) ? Object.values(t) : [t]) : [e];
|
|
278
313
|
}
|
|
279
314
|
export {
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
315
|
+
J as SHOULD_THROW_IF_INVALID_URL,
|
|
316
|
+
m as TradeType,
|
|
317
|
+
V as WIDGET_IFRAME_ALLOW,
|
|
318
|
+
M as WIDGET_IFRAME_REFERRER_POLICY,
|
|
319
|
+
B as WIDGET_IFRAME_SANDBOX,
|
|
320
|
+
ge as WIDGET_PALETTE_COLORS,
|
|
321
|
+
w as WidgetHookEvents,
|
|
322
|
+
p as WidgetMethodsEmit,
|
|
323
|
+
h as WidgetMethodsListen,
|
|
324
|
+
Le as createCowSwapWidget,
|
|
325
|
+
Y as isCowSwapWidgetPalette,
|
|
326
|
+
T as isPerNetworkConfig,
|
|
327
|
+
R as isPerTradeTypeConfig,
|
|
328
|
+
Ie as resolveFlexibleConfig,
|
|
329
|
+
Ce as resolveFlexibleConfigValues,
|
|
330
|
+
Z as sanitizeWidgetBaseUrl,
|
|
331
|
+
d as widgetIframeTransport
|
|
292
332
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cowprotocol/widget-lib",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.1.1",
|
|
4
4
|
"description": "CoW Swap Widget Library. Allows you to easily embed a CoW Swap widget on your website.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"@cowprotocol/cow-sdk": "8.1.0",
|
|
19
|
-
"@cowprotocol/events": "^4.2.
|
|
20
|
-
"@cowprotocol/iframe-transport": "^2.1
|
|
19
|
+
"@cowprotocol/events": "^4.2.1",
|
|
20
|
+
"@cowprotocol/iframe-transport": "^2.2.1"
|
|
21
21
|
},
|
|
22
22
|
"exports": {
|
|
23
23
|
".": {
|
package/types.d.ts
CHANGED
|
@@ -227,9 +227,19 @@ export interface CowSwapWidgetParams {
|
|
|
227
227
|
/**
|
|
228
228
|
* The base url of the widget implementation
|
|
229
229
|
* The parameter can have the URL directly, or an object with the environment property,
|
|
230
|
-
* The base URL will default to the production environment if not specified, so it will use https://swap.cow.
|
|
230
|
+
* The base URL will default to the production environment if not specified, so it will use https://swap.cow.fi by default.
|
|
231
|
+
*
|
|
232
|
+
* For security, values are validated before loading the iframe: only `https` origins are accepted,
|
|
233
|
+
* except `http` on local dev hosts (localhost, 127.0.0.1, ::1, *.localhost). Invalid URLs
|
|
234
|
+
* (unparsable, credentials, or disallowed scheme/host) either throw or log and fall back to the
|
|
235
|
+
* production host, depending on `SHOULD_THROW_IF_INVALID_URL` exported from `@cowprotocol/widget-lib`.
|
|
231
236
|
*/
|
|
232
237
|
baseUrl?: string;
|
|
238
|
+
/**
|
|
239
|
+
* Overrides the origin trusted for postMessage communication with the widget iframe.
|
|
240
|
+
* Defaults to the origin derived from `baseUrl` / iframe src.
|
|
241
|
+
*/
|
|
242
|
+
trustedOrigin?: string;
|
|
233
243
|
/**
|
|
234
244
|
* Sell token, and optionally the amount.
|
|
235
245
|
*/
|
|
@@ -290,6 +300,11 @@ export interface CowSwapWidgetParams {
|
|
|
290
300
|
* Defaults to false.
|
|
291
301
|
*/
|
|
292
302
|
disableToastMessages?: boolean;
|
|
303
|
+
/**
|
|
304
|
+
* When `true`, the host page will not use `window.open` to open links requested by the widget.
|
|
305
|
+
* Defaults to `false`.
|
|
306
|
+
*/
|
|
307
|
+
disableWindowOpen?: boolean;
|
|
293
308
|
/**
|
|
294
309
|
* Option to hide the logo in the widget.
|
|
295
310
|
*/
|
package/urlUtils.d.ts
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
import { CowSwapWidgetParams } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* When `true`, invalid `baseUrl` values throw and stop widget creation.
|
|
4
|
+
* When `false`, invalid values are reported with `console.error` and the iframe falls back to the production host.
|
|
5
|
+
*/
|
|
6
|
+
export declare const SHOULD_THROW_IF_INVALID_URL = false;
|
|
7
|
+
/**
|
|
8
|
+
* Normalizes `baseUrl` for the widget iframe `src` and rejects unsafe values.
|
|
9
|
+
* - Omits or blank `baseUrl` → production default (https://swap.cow.fi).
|
|
10
|
+
* - Allows `https:` for any host (self-hosted / staging).
|
|
11
|
+
* - Allows `http:` only on local dev loopback hostnames.
|
|
12
|
+
* @param throwIfInvalid Overrides {@link SHOULD_THROW_IF_INVALID_URL} (e.g. for unit tests).
|
|
13
|
+
* @throws {Error} When validation fails and `throwIfInvalid` is true (see {@link SHOULD_THROW_IF_INVALID_URL}).
|
|
14
|
+
*/
|
|
15
|
+
export declare function sanitizeWidgetBaseUrl(baseUrl: string | undefined, throwIfInvalid?: boolean): string;
|
|
2
16
|
export declare function buildWidgetUrl(params: Partial<CowSwapWidgetParams>): string;
|
|
3
17
|
export declare function buildWidgetPath(params: Partial<CowSwapWidgetParams>): string;
|
|
4
18
|
export declare function buildWidgetUrlQuery(params: Partial<CowSwapWidgetParams>): URLSearchParams;
|