@cowprotocol/widget-lib 3.0.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 -1
- 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 +213 -174
- 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
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const COWSWAP_ORIGIN = "https://swap.cow.
|
|
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
|
|
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,67 +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
|
-
const
|
|
53
|
-
function
|
|
53
|
+
const S = "https://swap.cow.fi";
|
|
54
|
+
function Y(e) {
|
|
54
55
|
return !!(e && typeof e == "object");
|
|
55
56
|
}
|
|
56
|
-
const
|
|
57
|
-
function
|
|
58
|
-
|
|
59
|
-
|
|
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}`;
|
|
60
84
|
}
|
|
61
|
-
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) {
|
|
62
90
|
const {
|
|
63
|
-
chainId:
|
|
64
|
-
sell:
|
|
91
|
+
chainId: t = 1,
|
|
92
|
+
sell: n,
|
|
65
93
|
buy: o,
|
|
66
|
-
tradeType: r =
|
|
67
|
-
} = e,
|
|
68
|
-
return `/${
|
|
94
|
+
tradeType: r = m.SWAP
|
|
95
|
+
} = e, i = [n?.asset || C, o?.asset || C].map(encodeURIComponent).join("/");
|
|
96
|
+
return `/${t}/widget/${r}/${i}`;
|
|
69
97
|
}
|
|
70
|
-
function
|
|
71
|
-
const
|
|
72
|
-
return
|
|
98
|
+
function v(e) {
|
|
99
|
+
const t = new URLSearchParams();
|
|
100
|
+
return re(oe(ne(te(ee(t, e), e), e), e), e);
|
|
73
101
|
}
|
|
74
|
-
function
|
|
102
|
+
function ee(e, t) {
|
|
75
103
|
const {
|
|
76
|
-
sell:
|
|
104
|
+
sell: n,
|
|
77
105
|
buy: o
|
|
78
|
-
} =
|
|
79
|
-
return
|
|
106
|
+
} = t;
|
|
107
|
+
return n?.amount && e.append("sellAmount", n.amount), o?.amount && e.append("buyAmount", o.amount), e;
|
|
80
108
|
}
|
|
81
|
-
function
|
|
82
|
-
const
|
|
83
|
-
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);
|
|
84
112
|
}
|
|
85
|
-
function
|
|
86
|
-
return
|
|
113
|
+
function ne(e, t) {
|
|
114
|
+
return t.targetChainId && e.append("targetChainId", t.targetChainId.toString()), e;
|
|
87
115
|
}
|
|
88
|
-
function
|
|
89
|
-
return
|
|
116
|
+
function oe(e, t) {
|
|
117
|
+
return t.locale && e.append("lng", t.locale), e;
|
|
90
118
|
}
|
|
91
|
-
function
|
|
92
|
-
return
|
|
119
|
+
function re(e, t) {
|
|
120
|
+
return ie(t.hooks) ? e.append("hooksEnabled", "true") : e.delete("hooksEnabled"), e;
|
|
93
121
|
}
|
|
94
|
-
function
|
|
122
|
+
function ie(e) {
|
|
95
123
|
return !!e && Object.values(e).some(Boolean);
|
|
96
124
|
}
|
|
97
|
-
const
|
|
125
|
+
const U = "640px", se = "450px", ae = 20, de = {
|
|
126
|
+
iframe: document.createElement("iframe"),
|
|
98
127
|
updateParams: () => {
|
|
99
128
|
},
|
|
100
129
|
updateListeners: () => {
|
|
@@ -104,190 +133,200 @@ const N = "640px", X = "450px", z = 20, Z = {
|
|
|
104
133
|
destroy: () => {
|
|
105
134
|
}
|
|
106
135
|
};
|
|
107
|
-
function
|
|
136
|
+
function Le(e, t) {
|
|
108
137
|
const {
|
|
109
|
-
params:
|
|
138
|
+
params: n,
|
|
110
139
|
provider: o,
|
|
111
140
|
listeners: r,
|
|
112
|
-
onReady:
|
|
113
|
-
} =
|
|
114
|
-
let
|
|
115
|
-
if (typeof window > "u") return
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
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
|
|
119
148
|
});
|
|
120
149
|
const f = [];
|
|
121
|
-
|
|
150
|
+
i && f.push(pe(c.contentWindow || window, s, i)), e.innerHTML = "", e.appendChild(c);
|
|
122
151
|
const {
|
|
123
|
-
contentWindow:
|
|
124
|
-
} =
|
|
125
|
-
if (!
|
|
126
|
-
throw console.error("Iframe does not contain a window",
|
|
127
|
-
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));
|
|
128
157
|
let _ = null;
|
|
129
|
-
function
|
|
130
|
-
|
|
158
|
+
function g() {
|
|
159
|
+
a && (_ && window.removeEventListener("message", _), !E.disableWindowOpen && (_ = Ee(s, a), f.push(_)));
|
|
131
160
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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);
|
|
137
170
|
});
|
|
138
|
-
const
|
|
171
|
+
const H = new $(window, a);
|
|
139
172
|
return {
|
|
173
|
+
iframe: c,
|
|
140
174
|
updateParams: (u) => {
|
|
141
|
-
|
|
175
|
+
E = u, D(a, s, E, l), g(), L();
|
|
142
176
|
},
|
|
143
|
-
updateListeners: (u) =>
|
|
177
|
+
updateListeners: (u) => I.updateListeners(u),
|
|
144
178
|
updateProvider: (u) => {
|
|
145
|
-
|
|
179
|
+
l = u, A = W(a, s, A, u);
|
|
146
180
|
},
|
|
147
181
|
destroy: () => {
|
|
148
|
-
|
|
182
|
+
A.disconnect(), I.stopListeningIframe(), f.forEach((u) => window.removeEventListener("message", u)), H.stopListening(), e.removeChild(c);
|
|
149
183
|
}
|
|
150
184
|
};
|
|
151
185
|
}
|
|
152
|
-
function
|
|
153
|
-
|
|
154
|
-
const r =
|
|
186
|
+
function W(e, t, n, o) {
|
|
187
|
+
n && n.disconnect();
|
|
188
|
+
const r = n || new F(e, t);
|
|
155
189
|
return o && r.onConnect(o), r;
|
|
156
190
|
}
|
|
157
|
-
function
|
|
191
|
+
function ce(e) {
|
|
158
192
|
const {
|
|
159
|
-
width:
|
|
160
|
-
height:
|
|
193
|
+
width: t = se,
|
|
194
|
+
height: n = U
|
|
161
195
|
} = e, o = document.createElement("iframe");
|
|
162
|
-
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;
|
|
163
197
|
}
|
|
164
|
-
function
|
|
198
|
+
function le(e) {
|
|
165
199
|
return new URL(e.src).origin;
|
|
166
200
|
}
|
|
167
|
-
function
|
|
168
|
-
const r = !!o,
|
|
169
|
-
theme:
|
|
170
|
-
hooks:
|
|
171
|
-
...
|
|
172
|
-
} =
|
|
173
|
-
|
|
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, {
|
|
174
208
|
urlParams: {
|
|
175
|
-
pathname:
|
|
176
|
-
search:
|
|
209
|
+
pathname: i,
|
|
210
|
+
search: l
|
|
177
211
|
},
|
|
178
|
-
appParams:
|
|
212
|
+
appParams: s,
|
|
179
213
|
hasProvider: r
|
|
180
|
-
},
|
|
214
|
+
}, t);
|
|
181
215
|
}
|
|
182
|
-
function
|
|
183
|
-
return
|
|
184
|
-
|
|
185
|
-
metaData:
|
|
186
|
-
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
|
|
187
221
|
} : void 0
|
|
188
|
-
},
|
|
189
|
-
},
|
|
222
|
+
}, t);
|
|
223
|
+
}, t);
|
|
190
224
|
}
|
|
191
|
-
function
|
|
225
|
+
function pe(e, t, n) {
|
|
192
226
|
let o = !1;
|
|
193
|
-
return
|
|
194
|
-
o || (o = !0,
|
|
195
|
-
},
|
|
227
|
+
return d.listenToMessageFromWindow(window, e, p.READY, () => {
|
|
228
|
+
o || (o = !0, n());
|
|
229
|
+
}, t);
|
|
196
230
|
}
|
|
197
|
-
function
|
|
198
|
-
return
|
|
231
|
+
function Ee(e, t) {
|
|
232
|
+
return d.listenToMessageFromWindow(window, t, p.INTERCEPT_WINDOW_OPEN, ({
|
|
199
233
|
href: n,
|
|
200
|
-
rel:
|
|
201
|
-
target:
|
|
234
|
+
rel: o,
|
|
235
|
+
target: r
|
|
202
236
|
}) => {
|
|
203
|
-
const
|
|
204
|
-
|
|
237
|
+
const i = fe(n.toString(), e);
|
|
238
|
+
i && we(i) && window.open(i, r, o);
|
|
205
239
|
}, e);
|
|
206
240
|
}
|
|
207
|
-
function
|
|
208
|
-
const
|
|
209
|
-
if (!
|
|
241
|
+
function fe(e, t) {
|
|
242
|
+
const n = e.trim();
|
|
243
|
+
if (!n)
|
|
210
244
|
return null;
|
|
211
245
|
try {
|
|
212
|
-
return new URL(
|
|
246
|
+
return new URL(n, t).toString();
|
|
213
247
|
} catch {
|
|
214
248
|
return null;
|
|
215
249
|
}
|
|
216
250
|
}
|
|
217
|
-
function
|
|
251
|
+
function we(e) {
|
|
218
252
|
try {
|
|
219
|
-
const
|
|
220
|
-
return
|
|
253
|
+
const t = new URL(e).protocol;
|
|
254
|
+
return t === "http:" || t === "https:";
|
|
221
255
|
} catch {
|
|
222
256
|
return !1;
|
|
223
257
|
}
|
|
224
258
|
}
|
|
225
|
-
function
|
|
226
|
-
return [
|
|
227
|
-
const
|
|
228
|
-
e.style.height =
|
|
229
|
-
},
|
|
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, ({
|
|
230
264
|
isUpToSmall: r
|
|
231
265
|
}) => {
|
|
232
|
-
e.style.height = r ?
|
|
233
|
-
},
|
|
234
|
-
}
|
|
235
|
-
const
|
|
236
|
-
[
|
|
237
|
-
[
|
|
238
|
-
[
|
|
239
|
-
[
|
|
240
|
-
[
|
|
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
|
|
241
275
|
};
|
|
242
|
-
function
|
|
243
|
-
return
|
|
276
|
+
function Re(e, t) {
|
|
277
|
+
return Oe[e.event](e.payload, t);
|
|
244
278
|
}
|
|
245
|
-
function
|
|
246
|
-
return
|
|
279
|
+
function Te(e, t, n) {
|
|
280
|
+
return d.listenToMessageFromWindow(window, e, p.PROCESS_HOOK, async (o) => {
|
|
247
281
|
let r = !1;
|
|
248
282
|
try {
|
|
249
|
-
r = await
|
|
283
|
+
r = await Re(o, n);
|
|
250
284
|
} catch {
|
|
251
285
|
}
|
|
252
|
-
|
|
286
|
+
d.postMessageToWindow(e, h.HOOK_RESULT, {
|
|
253
287
|
id: o.id,
|
|
254
288
|
result: r
|
|
255
|
-
},
|
|
256
|
-
},
|
|
289
|
+
}, t);
|
|
290
|
+
}, t);
|
|
257
291
|
}
|
|
258
|
-
const
|
|
259
|
-
function
|
|
260
|
-
if (O(e)) {
|
|
261
|
-
const o = e[t];
|
|
262
|
-
return R(o) ? o[n] : o;
|
|
263
|
-
}
|
|
292
|
+
const he = Object.values(m);
|
|
293
|
+
function Ie(e, t, n) {
|
|
264
294
|
if (R(e)) {
|
|
265
295
|
const o = e[n];
|
|
266
|
-
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;
|
|
267
301
|
}
|
|
268
302
|
return e;
|
|
269
303
|
}
|
|
270
|
-
function O(e) {
|
|
271
|
-
return typeof e != "object" ? !1 : Object.keys(e).every((n) => ue.includes(n));
|
|
272
|
-
}
|
|
273
|
-
const le = /^\d+$/;
|
|
274
304
|
function R(e) {
|
|
275
|
-
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));
|
|
276
310
|
}
|
|
277
|
-
function
|
|
278
|
-
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];
|
|
279
313
|
}
|
|
280
314
|
export {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
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
|
|
293
332
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cowprotocol/widget-lib",
|
|
3
|
-
"version": "3.
|
|
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;
|