@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.
@@ -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.finance)
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.finance/cow-protocol/tutorials/widget)
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";
@@ -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"),b=require("@cowprotocol/events");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||{}),T=(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))(T||{}),E=(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))(E||{}),P=(e=>(e.SWAP="swap",e.LIMIT="limit",e.ADVANCED="advanced",e.YIELD="yield",e))(P||{});const U=["primary","background","paper","text","danger","warning","alert","info","success"],s=new S.IframeTransport("cowSwapWidget");class y{constructor(t,n,o=[]){this.contentWindow=t,this.updateListeners(o),this.widgetListener=s.listenToMessageFromWindow(this.contentWindow,c.EMIT_COW_EVENT,r=>this.eventEmitter.emit(r.event,r.payload),n)}eventEmitter=new b.SimpleCowEventEmitter;listeners=[];widgetListener;stopListeningIframe(){s.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 H{constructor(t,n){this.appWindow=t,this.iframeWidow=n,this.forwardSdkMessage=o=>{F(o.data)&&(typeof window<"u"&&o.origin===window.location.origin||(B(o.data)?this.appWindow.parent.postMessage(o.data,"*"):M(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 F(e){return typeof e=="object"&&e!==null&&"id"in e&&typeof e.id=="string"}function B(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 M(e){return"success"in e&&typeof e.success=="boolean"&&"version"in e&&typeof e.version=="string"}function V(e="Default",t="#1c5dbf",...n){console.debug(`%c [COW][${e}]`,`font-weight: bold; color: ${t}`,...n)}function k(...e){V("Widget","#47aba8",...e)}function v(e){return!!(e&&typeof e=="object")}const C="_";function j(e){const t=typeof e.baseUrl=="string"?e.baseUrl:"https://swap.cow.finance",n=I(e);return t+"/#"+n+"?"+W(e)}function I(e){const{chainId:t=1,sell:n,buy:o,tradeType:r=P.SWAP}=e,a=[n?.asset||C,o?.asset||C].map(encodeURIComponent).join("/");return`/${t}/widget/${r}/${a}`}function W(e){const t=new URLSearchParams;return K($(Q(x(G(t,e),e),e),e),e)}function G(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 x(e,t){const n=t.theme;return n?(v(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 Q(e,t){return t.targetChainId&&e.append("targetChainId",t.targetChainId.toString()),e}function $(e,t){return t.locale&&e.append("lng",t.locale),e}function K(e,t){return Y(t.hooks)?e.append("hooksEnabled","true"):e.delete("hooksEnabled"),e}function Y(e){return!!e&&Object.values(e).some(Boolean)}const N="640px",J="450px",X=20,z={updateParams:()=>{},updateListeners:()=>{},updateProvider:()=>{},destroy:()=>{}};function Z(e,t){const{params:n,provider:o,listeners:r,onReady:a}=t;let f=o,w=n;if(typeof window>"u")return z;const d=q(n),i=ee(d);k("Resolved trusted iframe origin",{iframeOrigin:i});const p=[];a&&p.push(ne(d.contentWindow||window,i,a)),e.innerHTML="",e.appendChild(d);const{contentWindow:u}=d;if(!u)throw console.error("Iframe does not contain a window",d),new Error("Iframe does not contain a window!");p.push(te(u,i,n.appCode)),p.push(...se(d,i,n.height,n.maxHeight)),p.push(oe(i));let R=null;function A(){u&&(R&&window.removeEventListener("message",R),R=ue(u,i,w.hooks),p.push(R))}A();const g=new y(window,i,r);let h=m(u,i,null,f);d.addEventListener("load",()=>{L(u,i,w,f)});const D=new H(window,u);return{updateParams:l=>{w=l,L(u,i,w,f),A()},updateListeners:l=>g.updateListeners(l),updateProvider:l=>{f=l,h=m(u,i,h,l)},destroy:()=>{h.disconnect(),g.stopListeningIframe(),p.forEach(l=>window.removeEventListener("message",l)),D.stopListening(),e.removeChild(d)}}}function m(e,t,n,o){n&&n.disconnect();const r=n||new S.IframeRpcProviderBridge(e,t);return o&&r.onConnect(o),r}function q(e){const{width:t=J,height:n=N}=e,o=document.createElement("iframe");return o.src=j(e),o.width=t,o.height=n,o.style.border="0",o.allow="clipboard-read; clipboard-write",o}function ee(e){return new URL(e.src).origin}function L(e,t,n,o){const r=!!o,a=I(n),f=W(n).toString(),{theme:w,hooks:d,...i}=n;s.postMessageToWindow(e,T.UPDATE_PARAMS,{urlParams:{pathname:a,search:f},appParams:i,hasProvider:r},t)}function te(e,t,n){return s.listenToMessageFromWindow(window,c.ACTIVATE,()=>{s.postMessageToWindow(e,T.UPDATE_APP_DATA,{metaData:n?{appCode:n}:void 0},t)},t)}function ne(e,t,n){let o=!1;return s.listenToMessageFromWindow(window,c.READY,()=>{o||(o=!0,n())},t)}function oe(e){return s.listenToMessageFromWindow(window,c.INTERCEPT_WINDOW_OPEN,({href:t,rel:n,target:o})=>{const r=re(t.toString(),e);r&&ie(r)&&window.open(r,o,n)},e)}function re(e,t){const n=e.trim();if(!n)return null;try{return new URL(n,t).toString()}catch{return null}}function ie(e){try{const t=new URL(e).protocol;return t==="http:"||t==="https:"}catch{return!1}}function se(e,t,n=N,o){return[s.listenToMessageFromWindow(window,c.UPDATE_HEIGHT,r=>{const a=r.height?r.height+X:void 0;e.style.height=a?`${o?Math.min(a,o):a}px`:n},t),s.listenToMessageFromWindow(window,c.SET_FULL_HEIGHT,({isUpToSmall:r})=>{e.style.height=r?n:`${o||document.body.offsetHeight}px`},t)]}const ae={[E.ON_BEFORE_APPROVAL]:(e,t)=>t?.onBeforeApproval?t.onBeforeApproval(e):!0,[E.ON_BEFORE_TRADE]:(e,t)=>t?.onBeforeTrade?t.onBeforeTrade(e):!0,[E.ON_BEFORE_WRAP_UNWRAP]:(e,t)=>t?.onBeforeWrapOrUnwrap?t.onBeforeWrapOrUnwrap(e):!0,[E.ON_BEFORE_ORDER_CANCEL]:(e,t)=>t?.onBeforeOrderCancel?t.onBeforeOrderCancel(e):!0,[E.ON_BEFORE_ORDERS_CANCEL]:(e,t)=>t?.onBeforeOrdersCancel?t.onBeforeOrdersCancel(e):!0};function de(e,t){return ae[e.event](e.payload,t)}function ue(e,t,n){return s.listenToMessageFromWindow(window,c.PROCESS_HOOK,async o=>{let r=!1;try{r=await de(o,n)}catch{}s.postMessageToWindow(e,T.HOOK_RESULT,{id:o.id,result:r},t)},t)}const ce=Object.values(P);function le(e,t,n){if(_(e)){const o=e[n];return O(o)?o[t]:o}if(O(e)){const o=e[t];return _(o)?o[n]:o}return e}function _(e){return typeof e!="object"?!1:Object.keys(e).every(t=>ce.includes(t))}const Ee=/^\d+$/;function O(e){return typeof e!="object"?!1:Object.keys(e).every(t=>Ee.test(t))}function fe(e){return _(e)?Object.values(e).flatMap(t=>O(t)?Object.values(t):[t]):O(e)?Object.values(e).flatMap(t=>_(t)?Object.values(t):[t]):[e]}exports.TradeType=P;exports.WIDGET_PALETTE_COLORS=U;exports.WidgetHookEvents=E;exports.WidgetMethodsEmit=c;exports.WidgetMethodsListen=T;exports.createCowSwapWidget=Z;exports.isCowSwapWidgetPalette=v;exports.isPerNetworkConfig=O;exports.isPerTradeTypeConfig=_;exports.resolveFlexibleConfig=le;exports.resolveFlexibleConfigValues=fe;exports.widgetIframeTransport=s;
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 D, IframeRpcProviderBridge as W } from "@cowprotocol/iframe-transport";
2
- import { SimpleCowEventEmitter as U } from "@cowprotocol/events";
3
- var l = /* @__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))(l || {}), T = /* @__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))(T || {}), p = /* @__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))(p || {}), A = /* @__PURE__ */ ((e) => (e.SWAP = "swap", e.LIMIT = "limit", e.ADVANCED = "advanced", e.YIELD = "yield", e))(A || {});
4
- const fe = ["primary", "background", "paper", "text", "danger", "warning", "alert", "info", "success"], s = new D("cowSwapWidget");
5
- class b {
6
- constructor(n, t, o = []) {
7
- this.contentWindow = n, this.updateListeners(o), this.widgetListener = s.listenToMessageFromWindow(this.contentWindow, l.EMIT_COW_EVENT, (r) => this.eventEmitter.emit(r.event, r.payload), t);
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 U();
10
+ eventEmitter = new y();
10
11
  listeners = [];
11
12
  widgetListener;
12
13
  stopListeningIframe() {
13
- s.stopListeningWindowListener(this.contentWindow, this.widgetListener);
14
+ d.stopListeningWindowListener(this.contentWindow, this.widgetListener);
14
15
  }
15
- updateListeners(n) {
16
- for (const t of this.listeners)
17
- this.eventEmitter.off(t);
18
- this.listeners = n || [];
19
- for (const t of this.listeners)
20
- this.eventEmitter.on(t);
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 H {
24
- constructor(n, t) {
25
- this.appWindow = n, this.iframeWidow = t, this.forwardSdkMessage = (o) => {
26
- y(o.data) && (typeof window < "u" && o.origin === window.location.origin || (B(o.data) ? this.appWindow.parent.postMessage(o.data, "*") : F(o.data) && this.iframeWidow.postMessage(o.data, "*")));
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 y(e) {
38
+ function G(e) {
38
39
  return typeof e == "object" && e !== null && "id" in e && typeof e.id == "string";
39
40
  }
40
- function B(e) {
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 F(e) {
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 M(e = "Default", n = "#1c5dbf", ...t) {
47
- console.debug(`%c [COW][${e}]`, `font-weight: bold; color: ${n}`, ...t);
47
+ function Q(e = "Default", t = "#1c5dbf", ...n) {
48
+ console.debug(`%c [COW][${e}]`, `font-weight: bold; color: ${t}`, ...n);
48
49
  }
49
- function V(...e) {
50
- M("Widget", "#47aba8", ...e);
50
+ function K(...e) {
51
+ process.env.NODE_ENV !== "test" && Q("Widget", "#47aba8", ...e);
51
52
  }
52
- function k(e) {
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 j(e) {
57
- const n = typeof e.baseUrl == "string" ? e.baseUrl : "https://swap.cow.finance", t = S(e);
58
- return n + "/#" + t + "?" + I(e);
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 S(e) {
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: n = 1,
63
- sell: t,
91
+ chainId: t = 1,
92
+ sell: n,
64
93
  buy: o,
65
- tradeType: r = A.SWAP
66
- } = e, a = [t?.asset || C, o?.asset || C].map(encodeURIComponent).join("/");
67
- return `/${n}/widget/${r}/${a}`;
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 I(e) {
70
- const n = new URLSearchParams();
71
- return K($(Q(x(G(n, e), e), e), e), e);
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 G(e, n) {
102
+ function ee(e, t) {
74
103
  const {
75
- sell: t,
104
+ sell: n,
76
105
  buy: o
77
- } = n;
78
- return t?.amount && e.append("sellAmount", t.amount), o?.amount && e.append("buyAmount", o.amount), e;
106
+ } = t;
107
+ return n?.amount && e.append("sellAmount", n.amount), o?.amount && e.append("buyAmount", o.amount), e;
79
108
  }
80
- function x(e, n) {
81
- const t = n.theme;
82
- return t ? (k(t) ? (e.append("palette", encodeURIComponent(JSON.stringify(t))), e.append("theme", t.baseTheme)) : (e.append("palette", "null"), e.append("theme", t)), e) : (e.append("palette", "null"), e);
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 Q(e, n) {
85
- return n.targetChainId && e.append("targetChainId", n.targetChainId.toString()), e;
113
+ function ne(e, t) {
114
+ return t.targetChainId && e.append("targetChainId", t.targetChainId.toString()), e;
86
115
  }
87
- function $(e, n) {
88
- return n.locale && e.append("lng", n.locale), e;
116
+ function oe(e, t) {
117
+ return t.locale && e.append("lng", t.locale), e;
89
118
  }
90
- function K(e, n) {
91
- return Y(n.hooks) ? e.append("hooksEnabled", "true") : e.delete("hooksEnabled"), e;
119
+ function re(e, t) {
120
+ return ie(t.hooks) ? e.append("hooksEnabled", "true") : e.delete("hooksEnabled"), e;
92
121
  }
93
- function Y(e) {
122
+ function ie(e) {
94
123
  return !!e && Object.values(e).some(Boolean);
95
124
  }
96
- const N = "640px", J = "450px", X = 20, z = {
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 pe(e, n) {
136
+ function Le(e, t) {
107
137
  const {
108
- params: t,
138
+ params: n,
109
139
  provider: o,
110
140
  listeners: r,
111
- onReady: a
112
- } = n;
113
- let E = o, w = t;
114
- if (typeof window > "u") return z;
115
- const d = Z(t), i = q(d);
116
- V("Resolved trusted iframe origin", {
117
- iframeOrigin: i
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
- a && f.push(ne(d.contentWindow || window, i, a)), e.innerHTML = "", e.appendChild(d);
150
+ i && f.push(pe(c.contentWindow || window, s, i)), e.innerHTML = "", e.appendChild(c);
121
151
  const {
122
- contentWindow: u
123
- } = d;
124
- if (!u)
125
- throw console.error("Iframe does not contain a window", d), new Error("Iframe does not contain a window!");
126
- f.push(ee(u, i, t.appCode)), f.push(...ie(d, i, t.height, t.maxHeight)), f.push(te(i));
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 h() {
129
- u && (_ && window.removeEventListener("message", _), _ = de(u, i, w.hooks), f.push(_));
158
+ function g() {
159
+ a && (_ && window.removeEventListener("message", _), !E.disableWindowOpen && (_ = Ee(s, a), f.push(_)));
130
160
  }
131
- h();
132
- const m = new b(window, i, r);
133
- let P = g(u, i, null, E);
134
- d.addEventListener("load", () => {
135
- L(u, i, w, E);
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 v = new H(window, u);
171
+ const H = new $(window, a);
138
172
  return {
139
- updateParams: (c) => {
140
- w = c, L(u, i, w, E), h();
173
+ iframe: c,
174
+ updateParams: (u) => {
175
+ E = u, D(a, s, E, l), g(), L();
141
176
  },
142
- updateListeners: (c) => m.updateListeners(c),
143
- updateProvider: (c) => {
144
- E = c, P = g(u, i, P, c);
177
+ updateListeners: (u) => I.updateListeners(u),
178
+ updateProvider: (u) => {
179
+ l = u, A = W(a, s, A, u);
145
180
  },
146
181
  destroy: () => {
147
- P.disconnect(), m.stopListeningIframe(), f.forEach((c) => window.removeEventListener("message", c)), v.stopListening(), e.removeChild(d);
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 g(e, n, t, o) {
152
- t && t.disconnect();
153
- const r = t || new W(e, n);
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 Z(e) {
191
+ function ce(e) {
157
192
  const {
158
- width: n = J,
159
- height: t = N
193
+ width: t = se,
194
+ height: n = U
160
195
  } = e, o = document.createElement("iframe");
161
- return o.src = j(e), o.width = n, o.height = t, o.style.border = "0", o.allow = "clipboard-read; clipboard-write", o;
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 q(e) {
198
+ function le(e) {
164
199
  return new URL(e.src).origin;
165
200
  }
166
- function L(e, n, t, o) {
167
- const r = !!o, a = S(t), E = I(t).toString(), {
168
- theme: w,
169
- hooks: d,
170
- ...i
171
- } = t;
172
- s.postMessageToWindow(e, T.UPDATE_PARAMS, {
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: a,
175
- search: E
209
+ pathname: i,
210
+ search: l
176
211
  },
177
- appParams: i,
212
+ appParams: s,
178
213
  hasProvider: r
179
- }, n);
214
+ }, t);
180
215
  }
181
- function ee(e, n, t) {
182
- return s.listenToMessageFromWindow(window, l.ACTIVATE, () => {
183
- s.postMessageToWindow(e, T.UPDATE_APP_DATA, {
184
- metaData: t ? {
185
- appCode: t
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
- }, n);
188
- }, n);
222
+ }, t);
223
+ }, t);
189
224
  }
190
- function ne(e, n, t) {
225
+ function pe(e, t, n) {
191
226
  let o = !1;
192
- return s.listenToMessageFromWindow(window, l.READY, () => {
193
- o || (o = !0, t());
194
- }, n);
227
+ return d.listenToMessageFromWindow(window, e, p.READY, () => {
228
+ o || (o = !0, n());
229
+ }, t);
195
230
  }
196
- function te(e) {
197
- return s.listenToMessageFromWindow(window, l.INTERCEPT_WINDOW_OPEN, ({
231
+ function Ee(e, t) {
232
+ return d.listenToMessageFromWindow(window, t, p.INTERCEPT_WINDOW_OPEN, ({
198
233
  href: n,
199
- rel: t,
200
- target: o
234
+ rel: o,
235
+ target: r
201
236
  }) => {
202
- const r = oe(n.toString(), e);
203
- r && re(r) && window.open(r, o, t);
237
+ const i = fe(n.toString(), e);
238
+ i && we(i) && window.open(i, r, o);
204
239
  }, e);
205
240
  }
206
- function oe(e, n) {
207
- const t = e.trim();
208
- if (!t)
241
+ function fe(e, t) {
242
+ const n = e.trim();
243
+ if (!n)
209
244
  return null;
210
245
  try {
211
- return new URL(t, n).toString();
246
+ return new URL(n, t).toString();
212
247
  } catch {
213
248
  return null;
214
249
  }
215
250
  }
216
- function re(e) {
251
+ function we(e) {
217
252
  try {
218
- const n = new URL(e).protocol;
219
- return n === "http:" || n === "https:";
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 ie(e, n, t = N, o) {
225
- return [s.listenToMessageFromWindow(window, l.UPDATE_HEIGHT, (r) => {
226
- const a = r.height ? r.height + X : void 0;
227
- e.style.height = a ? `${o ? Math.min(a, o) : a}px` : t;
228
- }, n), s.listenToMessageFromWindow(window, l.SET_FULL_HEIGHT, ({
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 ? t : `${o || document.body.offsetHeight}px`;
232
- }, n)];
233
- }
234
- const se = {
235
- [p.ON_BEFORE_APPROVAL]: (e, n) => n?.onBeforeApproval ? n.onBeforeApproval(e) : !0,
236
- [p.ON_BEFORE_TRADE]: (e, n) => n?.onBeforeTrade ? n.onBeforeTrade(e) : !0,
237
- [p.ON_BEFORE_WRAP_UNWRAP]: (e, n) => n?.onBeforeWrapOrUnwrap ? n.onBeforeWrapOrUnwrap(e) : !0,
238
- [p.ON_BEFORE_ORDER_CANCEL]: (e, n) => n?.onBeforeOrderCancel ? n.onBeforeOrderCancel(e) : !0,
239
- [p.ON_BEFORE_ORDERS_CANCEL]: (e, n) => n?.onBeforeOrdersCancel ? n.onBeforeOrdersCancel(e) : !0
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 ae(e, n) {
242
- return se[e.event](e.payload, n);
276
+ function Re(e, t) {
277
+ return Oe[e.event](e.payload, t);
243
278
  }
244
- function de(e, n, t) {
245
- return s.listenToMessageFromWindow(window, l.PROCESS_HOOK, async (o) => {
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 ae(o, t);
283
+ r = await Re(o, n);
249
284
  } catch {
250
285
  }
251
- s.postMessageToWindow(e, T.HOOK_RESULT, {
286
+ d.postMessageToWindow(e, h.HOOK_RESULT, {
252
287
  id: o.id,
253
288
  result: r
254
- }, n);
255
- }, n);
289
+ }, t);
290
+ }, t);
256
291
  }
257
- const ue = Object.values(A);
258
- function we(e, n, t) {
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 O(o) ? o[t] : o;
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((n) => ce.test(n));
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 _e(e) {
277
- return O(e) ? Object.values(e).flatMap((n) => R(n) ? Object.values(n) : [n]) : R(e) ? Object.values(e).flatMap((n) => O(n) ? Object.values(n) : [n]) : [e];
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
- A as TradeType,
281
- fe as WIDGET_PALETTE_COLORS,
282
- p as WidgetHookEvents,
283
- l as WidgetMethodsEmit,
284
- T as WidgetMethodsListen,
285
- pe as createCowSwapWidget,
286
- k as isCowSwapWidgetPalette,
287
- R as isPerNetworkConfig,
288
- O as isPerTradeTypeConfig,
289
- we as resolveFlexibleConfig,
290
- _e as resolveFlexibleConfigValues,
291
- s as widgetIframeTransport
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": "2.3.0",
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.0",
20
- "@cowprotocol/iframe-transport": "^2.1.0"
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.finance by default.
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;