@cowprotocol/widget-lib 3.0.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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 CHANGED
@@ -1 +1 @@
1
- export declare const COWSWAP_ORIGIN = "https://swap.cow.finance";
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 L=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 L.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)}const j="https://swap.cow.finance";function I(e){return!!(e&&typeof e=="object")}const C="_";function G(e){const t=typeof e.baseUrl=="string"?e.baseUrl:j,n=W(e);return t+"/#"+n+"?"+v(e)}function W(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 v(e){const t=new URLSearchParams;return Y(K($(Q(x(t,e),e),e),e),e)}function x(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 Q(e,t){const n=t.theme;return n?(I(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 $(e,t){return t.targetChainId&&e.append("targetChainId",t.targetChainId.toString()),e}function K(e,t){return t.locale&&e.append("lng",t.locale),e}function Y(e,t){return J(t.hooks)?e.append("hooksEnabled","true"):e.delete("hooksEnabled"),e}function J(e){return!!e&&Object.values(e).some(Boolean)}const N="640px",X="450px",z=20,Z={updateParams:()=>{},updateListeners:()=>{},updateProvider:()=>{},destroy:()=>{}};function q(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=ee(n),i=te(d);k("Resolved trusted iframe origin",{iframeOrigin:i});const p=[];a&&p.push(oe(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(ne(u,i,n.appCode)),p.push(...ae(d,i,n.height,n.maxHeight)),p.push(re(i));let R=null;function h(){u&&(R&&window.removeEventListener("message",R),R=ce(u,i,w.hooks),p.push(R))}h();const g=new y(window,i,r);let A=m(u,i,null,f);d.addEventListener("load",()=>{S(u,i,w,f)});const D=new H(window,u);return{updateParams:l=>{w=l,S(u,i,w,f),h()},updateListeners:l=>g.updateListeners(l),updateProvider:l=>{f=l,A=m(u,i,A,l)},destroy:()=>{A.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 L.IframeRpcProviderBridge(e,t);return o&&r.onConnect(o),r}function ee(e){const{width:t=X,height:n=N}=e,o=document.createElement("iframe");return o.src=G(e),o.width=t,o.height=n,o.style.border="0",o.allow="clipboard-read; clipboard-write",o}function te(e){return new URL(e.src).origin}function S(e,t,n,o){const r=!!o,a=W(n),f=v(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 ne(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 oe(e,t,n){let o=!1;return s.listenToMessageFromWindow(window,c.READY,()=>{o||(o=!0,n())},t)}function re(e){return s.listenToMessageFromWindow(window,c.INTERCEPT_WINDOW_OPEN,({href:t,rel:n,target:o})=>{const r=ie(t.toString(),e);r&&se(r)&&window.open(r,o,n)},e)}function ie(e,t){const n=e.trim();if(!n)return null;try{return new URL(n,t).toString()}catch{return null}}function se(e){try{const t=new URL(e).protocol;return t==="http:"||t==="https:"}catch{return!1}}function ae(e,t,n=N,o){return[s.listenToMessageFromWindow(window,c.UPDATE_HEIGHT,r=>{const a=r.height?r.height+z: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 de={[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 ue(e,t){return de[e.event](e.payload,t)}function ce(e,t,n){return s.listenToMessageFromWindow(window,c.PROCESS_HOOK,async o=>{let r=!1;try{r=await ue(o,n)}catch{}s.postMessageToWindow(e,T.HOOK_RESULT,{id:o.id,result:r},t)},t)}const le=Object.values(P);function Ee(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=>le.includes(t))}const fe=/^\d+$/;function O(e){return typeof e!="object"?!1:Object.keys(e).every(t=>fe.test(t))}function pe(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=q;exports.isCowSwapWidgetPalette=I;exports.isPerNetworkConfig=O;exports.isPerTradeTypeConfig=_;exports.resolveFlexibleConfig=Ee;exports.resolveFlexibleConfigValues=pe;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 { widgetIframeTransport } from './widgetIframeTransport';
2
+ export { WIDGET_IFRAME_ALLOW, WIDGET_IFRAME_REFERRER_POLICY, WIDGET_IFRAME_SANDBOX } from './cowSwapWidget.constants';
3
3
  export type { CowSwapWidgetHandler } from './cowSwapWidget';
4
4
  export { resolveFlexibleConfigValues } from './resolveFlexibleConfigValues';
5
+ export { sanitizeWidgetBaseUrl, SHOULD_THROW_IF_INVALID_URL } from './urlUtils';
6
+ export { widgetIframeTransport } from './widgetIframeTransport';
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 v, IframeRpcProviderBridge as D } 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 pe = ["primary", "background", "paper", "text", "danger", "warning", "alert", "info", "success"], s = new v("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,67 +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
- const k = "https://swap.cow.finance";
53
- function j(e) {
53
+ const S = "https://swap.cow.fi";
54
+ function Y(e) {
54
55
  return !!(e && typeof e == "object");
55
56
  }
56
- const m = "_";
57
- function G(e) {
58
- const n = typeof e.baseUrl == "string" ? e.baseUrl : k, t = I(e);
59
- return n + "/#" + t + "?" + S(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}`;
60
84
  }
61
- function I(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) {
62
90
  const {
63
- chainId: n = 1,
64
- sell: t,
91
+ chainId: t = 1,
92
+ sell: n,
65
93
  buy: o,
66
- tradeType: r = A.SWAP
67
- } = e, a = [t?.asset || m, o?.asset || m].map(encodeURIComponent).join("/");
68
- 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}`;
69
97
  }
70
- function S(e) {
71
- const n = new URLSearchParams();
72
- return Y(K($(Q(x(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);
73
101
  }
74
- function x(e, n) {
102
+ function ee(e, t) {
75
103
  const {
76
- sell: t,
104
+ sell: n,
77
105
  buy: o
78
- } = n;
79
- 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;
80
108
  }
81
- function Q(e, n) {
82
- const t = n.theme;
83
- return t ? (j(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);
84
112
  }
85
- function $(e, n) {
86
- 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;
87
115
  }
88
- function K(e, n) {
89
- return n.locale && e.append("lng", n.locale), e;
116
+ function oe(e, t) {
117
+ return t.locale && e.append("lng", t.locale), e;
90
118
  }
91
- function Y(e, n) {
92
- return J(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;
93
121
  }
94
- function J(e) {
122
+ function ie(e) {
95
123
  return !!e && Object.values(e).some(Boolean);
96
124
  }
97
- const N = "640px", X = "450px", z = 20, Z = {
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 we(e, n) {
136
+ function Le(e, t) {
108
137
  const {
109
- params: t,
138
+ params: n,
110
139
  provider: o,
111
140
  listeners: r,
112
- onReady: a
113
- } = n;
114
- let E = o, w = t;
115
- if (typeof window > "u") return Z;
116
- const d = q(t), i = ee(d);
117
- V("Resolved trusted iframe origin", {
118
- 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
119
148
  });
120
149
  const f = [];
121
- a && f.push(te(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);
122
151
  const {
123
- contentWindow: c
124
- } = d;
125
- if (!c)
126
- throw console.error("Iframe does not contain a window", d), new Error("Iframe does not contain a window!");
127
- f.push(ne(c, i, t.appCode)), f.push(...se(d, i, t.height, t.maxHeight)), f.push(oe(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));
128
157
  let _ = null;
129
- function h() {
130
- c && (_ && window.removeEventListener("message", _), _ = ce(c, i, w.hooks), f.push(_));
158
+ function g() {
159
+ a && (_ && window.removeEventListener("message", _), !E.disableWindowOpen && (_ = Ee(s, a), f.push(_)));
131
160
  }
132
- h();
133
- const C = new b(window, i, r);
134
- let P = g(c, i, null, E);
135
- d.addEventListener("load", () => {
136
- L(c, 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);
137
170
  });
138
- const W = new H(window, c);
171
+ const H = new $(window, a);
139
172
  return {
173
+ iframe: c,
140
174
  updateParams: (u) => {
141
- w = u, L(c, i, w, E), h();
175
+ E = u, D(a, s, E, l), g(), L();
142
176
  },
143
- updateListeners: (u) => C.updateListeners(u),
177
+ updateListeners: (u) => I.updateListeners(u),
144
178
  updateProvider: (u) => {
145
- E = u, P = g(c, i, P, u);
179
+ l = u, A = W(a, s, A, u);
146
180
  },
147
181
  destroy: () => {
148
- P.disconnect(), C.stopListeningIframe(), f.forEach((u) => window.removeEventListener("message", u)), W.stopListening(), e.removeChild(d);
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 g(e, n, t, o) {
153
- t && t.disconnect();
154
- const r = t || new D(e, n);
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 q(e) {
191
+ function ce(e) {
158
192
  const {
159
- width: n = X,
160
- height: t = N
193
+ width: t = se,
194
+ height: n = U
161
195
  } = e, o = document.createElement("iframe");
162
- return o.src = G(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;
163
197
  }
164
- function ee(e) {
198
+ function le(e) {
165
199
  return new URL(e.src).origin;
166
200
  }
167
- function L(e, n, t, o) {
168
- const r = !!o, a = I(t), E = S(t).toString(), {
169
- theme: w,
170
- hooks: d,
171
- ...i
172
- } = t;
173
- 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, {
174
208
  urlParams: {
175
- pathname: a,
176
- search: E
209
+ pathname: i,
210
+ search: l
177
211
  },
178
- appParams: i,
212
+ appParams: s,
179
213
  hasProvider: r
180
- }, n);
214
+ }, t);
181
215
  }
182
- function ne(e, n, t) {
183
- return s.listenToMessageFromWindow(window, l.ACTIVATE, () => {
184
- s.postMessageToWindow(e, T.UPDATE_APP_DATA, {
185
- metaData: t ? {
186
- 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
187
221
  } : void 0
188
- }, n);
189
- }, n);
222
+ }, t);
223
+ }, t);
190
224
  }
191
- function te(e, n, t) {
225
+ function pe(e, t, n) {
192
226
  let o = !1;
193
- return s.listenToMessageFromWindow(window, l.READY, () => {
194
- o || (o = !0, t());
195
- }, n);
227
+ return d.listenToMessageFromWindow(window, e, p.READY, () => {
228
+ o || (o = !0, n());
229
+ }, t);
196
230
  }
197
- function oe(e) {
198
- return s.listenToMessageFromWindow(window, l.INTERCEPT_WINDOW_OPEN, ({
231
+ function Ee(e, t) {
232
+ return d.listenToMessageFromWindow(window, t, p.INTERCEPT_WINDOW_OPEN, ({
199
233
  href: n,
200
- rel: t,
201
- target: o
234
+ rel: o,
235
+ target: r
202
236
  }) => {
203
- const r = re(n.toString(), e);
204
- r && ie(r) && window.open(r, o, t);
237
+ const i = fe(n.toString(), e);
238
+ i && we(i) && window.open(i, r, o);
205
239
  }, e);
206
240
  }
207
- function re(e, n) {
208
- const t = e.trim();
209
- if (!t)
241
+ function fe(e, t) {
242
+ const n = e.trim();
243
+ if (!n)
210
244
  return null;
211
245
  try {
212
- return new URL(t, n).toString();
246
+ return new URL(n, t).toString();
213
247
  } catch {
214
248
  return null;
215
249
  }
216
250
  }
217
- function ie(e) {
251
+ function we(e) {
218
252
  try {
219
- const n = new URL(e).protocol;
220
- return n === "http:" || n === "https:";
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 se(e, n, t = N, o) {
226
- return [s.listenToMessageFromWindow(window, l.UPDATE_HEIGHT, (r) => {
227
- const a = r.height ? r.height + z : void 0;
228
- e.style.height = a ? `${o ? Math.min(a, o) : a}px` : t;
229
- }, 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, ({
230
264
  isUpToSmall: r
231
265
  }) => {
232
- e.style.height = r ? t : `${o || document.body.offsetHeight}px`;
233
- }, n)];
234
- }
235
- const ae = {
236
- [p.ON_BEFORE_APPROVAL]: (e, n) => n?.onBeforeApproval ? n.onBeforeApproval(e) : !0,
237
- [p.ON_BEFORE_TRADE]: (e, n) => n?.onBeforeTrade ? n.onBeforeTrade(e) : !0,
238
- [p.ON_BEFORE_WRAP_UNWRAP]: (e, n) => n?.onBeforeWrapOrUnwrap ? n.onBeforeWrapOrUnwrap(e) : !0,
239
- [p.ON_BEFORE_ORDER_CANCEL]: (e, n) => n?.onBeforeOrderCancel ? n.onBeforeOrderCancel(e) : !0,
240
- [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
241
275
  };
242
- function de(e, n) {
243
- return ae[e.event](e.payload, n);
276
+ function Re(e, t) {
277
+ return Oe[e.event](e.payload, t);
244
278
  }
245
- function ce(e, n, t) {
246
- 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) => {
247
281
  let r = !1;
248
282
  try {
249
- r = await de(o, t);
283
+ r = await Re(o, n);
250
284
  } catch {
251
285
  }
252
- s.postMessageToWindow(e, T.HOOK_RESULT, {
286
+ d.postMessageToWindow(e, h.HOOK_RESULT, {
253
287
  id: o.id,
254
288
  result: r
255
- }, n);
256
- }, n);
289
+ }, t);
290
+ }, t);
257
291
  }
258
- const ue = Object.values(A);
259
- function _e(e, n, t) {
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 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;
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((n) => le.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));
276
310
  }
277
- function Oe(e) {
278
- 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];
279
313
  }
280
314
  export {
281
- A as TradeType,
282
- pe as WIDGET_PALETTE_COLORS,
283
- p as WidgetHookEvents,
284
- l as WidgetMethodsEmit,
285
- T as WidgetMethodsListen,
286
- we as createCowSwapWidget,
287
- j as isCowSwapWidgetPalette,
288
- R as isPerNetworkConfig,
289
- O as isPerTradeTypeConfig,
290
- _e as resolveFlexibleConfig,
291
- Oe as resolveFlexibleConfigValues,
292
- 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
293
332
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cowprotocol/widget-lib",
3
- "version": "3.0.0",
3
+ "version": "4.0.0",
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",
@@ -15,9 +15,9 @@
15
15
  "access": "public"
16
16
  },
17
17
  "dependencies": {
18
- "@cowprotocol/cow-sdk": "8.1.0",
19
- "@cowprotocol/events": "^4.2.0",
20
- "@cowprotocol/iframe-transport": "^2.1.0"
18
+ "@cowprotocol/cow-sdk": "9.0.0",
19
+ "@cowprotocol/events": "^4.3.0",
20
+ "@cowprotocol/iframe-transport": "^2.2.2"
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;