@opensea/vessel
Advanced tools
@@ -1,4 +0,4 @@ | ||
var O = Object.defineProperty; | ||
var m = (s, e, t) => e in s ? O(s, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : s[e] = t; | ||
var i = (s, e, t) => (m(s, typeof e != "symbol" ? e + "" : e, t), t); | ||
var E = Object.defineProperty; | ||
var m = (s, e, t) => e in s ? E(s, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : s[e] = t; | ||
var r = (s, e, t) => (m(s, typeof e != "symbol" ? e + "" : e, t), t); | ||
const l = /* @__PURE__ */ new Map(); | ||
@@ -53,10 +53,10 @@ function f(s, e, t) { | ||
} | ||
var r = /* @__PURE__ */ ((s) => (s.Handshake = "handshake", s.HandshakeReply = "handshake-reply", s.Message = "message", s.MessageReply = "message-reply", s.Close = "close", s))(r || {}); | ||
var i = /* @__PURE__ */ ((s) => (s.Handshake = "handshake", s.HandshakeReply = "handshake-reply", s.Message = "message", s.MessageReply = "message-reply", s.Close = "close", s))(i || {}); | ||
class h { | ||
constructor(e, t) { | ||
i(this, "type"); | ||
i(this, "id"); | ||
i(this, "from"); | ||
i(this, "operation"); | ||
i(this, "payload"); | ||
r(this, "type"); | ||
r(this, "id"); | ||
r(this, "from"); | ||
r(this, "operation"); | ||
r(this, "payload"); | ||
this.type = e, this.id = (t == null ? void 0 : t.id) ?? C(), this.from = (t == null ? void 0 : t.from) ?? w, this.operation = (t == null ? void 0 : t.operation) ?? I(), this.payload = t == null ? void 0 : t.payload; | ||
@@ -75,3 +75,3 @@ } | ||
function $(s, e = w) { | ||
if (s && typeof s == "object" && "from" in s && s.from === e && "type" in s && Object.values(r).includes(s.type) && "id" in s && "operation" in s) | ||
if (s && typeof s == "object" && "from" in s && s.from === e && "type" in s && Object.values(i).includes(s.type) && "id" in s && "operation" in s) | ||
return new h(s.type, { | ||
@@ -85,3 +85,3 @@ id: s.id, | ||
} | ||
function E(s, e, t) { | ||
function O(s, e, t) { | ||
if (e === "*" || s.origin === e) | ||
@@ -92,10 +92,11 @@ return $(s.data, t ?? w); | ||
constructor(e) { | ||
i(this, "log"); | ||
i(this, "parent", window.parent); | ||
i(this, "subscriptions"); | ||
i(this, "closed", !1); | ||
i(this, "parentOrigin"); | ||
this.parentOrigin = e.parentOrigin, this.subscriptions = { | ||
[r.Message]: [], | ||
[r.Close]: [] | ||
r(this, "log"); | ||
r(this, "parent", window.parent); | ||
r(this, "subscriptions"); | ||
r(this, "closed", !1); | ||
r(this, "parentOrigin"); | ||
r(this, "allowedOrigins", []); | ||
this.parentOrigin = "", this.allowedOrigins = e.allowedOrigins, this.subscriptions = { | ||
[i.Message]: [], | ||
[i.Close]: [] | ||
}, this.log = b({ debug: e.debug, scope: "CHILD" }), this.onMessage = this.onMessage.bind(this), window.addEventListener("message", this.onMessage, !1); | ||
@@ -105,3 +106,3 @@ } | ||
const n = this.sendMessage.bind(this); | ||
if (e === r.Close) { | ||
if (e === i.Close) { | ||
this.close(), this.subscriptions[e].forEach((o) => o(t.payload)); | ||
@@ -113,3 +114,3 @@ return; | ||
n( | ||
new h(r.MessageReply, { | ||
new h(i.MessageReply, { | ||
operation: t.operation, | ||
@@ -124,15 +125,18 @@ payload: a | ||
try { | ||
const t = E(e, this.parentOrigin); | ||
if (!t) | ||
return; | ||
switch (t.type) { | ||
case r.Handshake: | ||
this.parentOrigin = e.origin, this.sendHandshakeReply(t); | ||
if (this.allowedOrigins.includes(e.origin)) { | ||
this.parentOrigin = e.origin; | ||
const t = O(e, this.parentOrigin); | ||
if (!t) | ||
return; | ||
case r.Message: | ||
this.callSubscriptions(r.Message, t); | ||
return; | ||
case r.MessageReply: | ||
this.resolveReply(t); | ||
return; | ||
switch (t.type) { | ||
case i.Handshake: | ||
this.sendHandshakeReply(t); | ||
return; | ||
case i.Message: | ||
this.callSubscriptions(i.Message, t); | ||
return; | ||
case i.MessageReply: | ||
this.resolveReply(t); | ||
return; | ||
} | ||
} | ||
@@ -145,3 +149,3 @@ } catch (t) { | ||
this.log.info(`Received handshake from ${this.parentOrigin}`); | ||
const t = new h(r.HandshakeReply, { | ||
const t = new h(i.HandshakeReply, { | ||
operation: e.operation | ||
@@ -189,3 +193,3 @@ }); | ||
return new Promise((n, o) => { | ||
const a = new h(r.Message, { | ||
const a = new h(i.Message, { | ||
payload: e | ||
@@ -206,3 +210,3 @@ }); | ||
emit(e) { | ||
const t = new h(r.Message, { | ||
const t = new h(i.Message, { | ||
payload: e | ||
@@ -227,3 +231,3 @@ }); | ||
this.closed = !0, window.removeEventListener("message", this.onMessage); | ||
const e = new h(r.Close); | ||
const e = new h(i.Close); | ||
this.parent.postMessage(e.toObject(), this.parentOrigin); | ||
@@ -234,17 +238,17 @@ } | ||
constructor(e) { | ||
i(this, "parentFrame"); | ||
i(this, "child"); | ||
i(this, "frame"); | ||
i(this, "handshakeOperation"); | ||
i(this, "handshakeInterval"); | ||
i(this, "handshakeIntervalTimeout", 500); | ||
i(this, "handshakeActionResolverId"); | ||
i(this, "subscriptions"); | ||
i(this, "log"); | ||
i(this, "childOrigin"); | ||
i(this, "childUrl"); | ||
i(this, "connected"); | ||
r(this, "parentFrame"); | ||
r(this, "child"); | ||
r(this, "frame"); | ||
r(this, "handshakeOperation"); | ||
r(this, "handshakeInterval"); | ||
r(this, "handshakeIntervalTimeout", 500); | ||
r(this, "handshakeActionResolverId"); | ||
r(this, "subscriptions"); | ||
r(this, "log"); | ||
r(this, "childOrigin"); | ||
r(this, "childUrl"); | ||
r(this, "connected"); | ||
this.frame = e.frame, this.parentFrame = window, this.child = null, this.childUrl = e.url, this.childOrigin = H(e.url), this.connected = !1, this.handshakeOperation = null, this.handshakeInterval = null, e.handshakeIntervalTimeout && (this.handshakeIntervalTimeout = e.handshakeIntervalTimeout), this.subscriptions = { | ||
[r.Message]: [], | ||
[r.Close]: [] | ||
[i.Message]: [], | ||
[i.Close]: [] | ||
}, this.log = b({ debug: e.debug, scope: "PARENT" }), this.parentFrame.addEventListener( | ||
@@ -263,3 +267,3 @@ "message", | ||
e += 1; | ||
const n = new h(r.Handshake); | ||
const n = new h(i.Handshake); | ||
this.handshakeOperation = n.operation, this.sendMessage(n); | ||
@@ -278,3 +282,3 @@ } | ||
const n = this.sendMessage.bind(this); | ||
if (e === r.Close) { | ||
if (e === i.Close) { | ||
this.close(), this.subscriptions[e].forEach((o) => o(t.payload)); | ||
@@ -286,3 +290,3 @@ return; | ||
n( | ||
new h(r.MessageReply, { | ||
new h(i.MessageReply, { | ||
operation: t.operation, | ||
@@ -313,17 +317,17 @@ payload: a | ||
try { | ||
const t = E(e, this.childOrigin); | ||
const t = O(e, this.childOrigin); | ||
if (!t) | ||
return; | ||
switch (t.type) { | ||
case r.HandshakeReply: | ||
case i.HandshakeReply: | ||
this.handleHandshakeReply(t); | ||
break; | ||
case r.Message: | ||
this.callSubscriptions(r.Message, t); | ||
case i.Message: | ||
this.callSubscriptions(i.Message, t); | ||
break; | ||
case r.MessageReply: | ||
case i.MessageReply: | ||
this.resolveReply(t); | ||
break; | ||
case r.Close: | ||
this.callSubscriptions(r.Close, t); | ||
case i.Close: | ||
this.callSubscriptions(i.Close, t); | ||
break; | ||
@@ -358,3 +362,3 @@ default: | ||
throw new c("Child frame not found."); | ||
if (e.type !== r.Handshake && !this.connected) | ||
if (e.type !== i.Handshake && !this.connected) | ||
throw new c("Not connected to child frame."); | ||
@@ -372,3 +376,3 @@ this.child.postMessage(e.toObject(), this.childOrigin); | ||
return new Promise((n, o) => { | ||
const a = new h(r.Message, { | ||
const a = new h(i.Message, { | ||
payload: e | ||
@@ -389,3 +393,3 @@ }); | ||
emit(e) { | ||
const t = new h(r.Message, { | ||
const t = new h(i.Message, { | ||
payload: e | ||
@@ -414,3 +418,3 @@ }); | ||
close() { | ||
this.log.info("Closing frames"), this.subscriptions[r.Message] = [], this.subscriptions[r.Close] = [], this.handshakeOperation = null, this.handshakeInterval && window.clearInterval(this.handshakeInterval), p(this.handshakeActionResolverId), this.connected = !1; | ||
this.log.info("Closing frames"), this.subscriptions[i.Message] = [], this.subscriptions[i.Close] = [], this.handshakeOperation = null, this.handshakeInterval && window.clearInterval(this.handshakeInterval), p(this.handshakeActionResolverId), this.connected = !1; | ||
} | ||
@@ -426,8 +430,8 @@ } | ||
} | ||
i(y, "ParentFrame", k), i(y, "ChildFrame", v); | ||
r(y, "ParentFrame", k), r(y, "ChildFrame", v); | ||
export { | ||
v as ChildFrame, | ||
r as MessageType, | ||
i as MessageType, | ||
k as ParentFrame, | ||
y as Vessel | ||
}; |
@@ -1,1 +0,1 @@ | ||
(function(l,a){typeof exports=="object"&&typeof module<"u"?a(exports):typeof define=="function"&&define.amd?define(["exports"],a):(l=typeof globalThis<"u"?globalThis:l||self,a(l.Vessel={}))})(this,function(l){"use strict";var $=Object.defineProperty;var S=(l,a,d)=>a in l?$(l,a,{enumerable:!0,configurable:!0,writable:!0,value:d}):l[a]=d;var r=(l,a,d)=>(S(l,typeof a!="symbol"?a+"":a,d),d);const a=new Map;function d(s,e,t){const n=a.get(s);n&&(n.timeout&&clearTimeout(n.timeout),n.reject(new Error("[Vessel] Same action fired again. Keeping only latest.")),a.delete(s)),a.set(s,e),typeof t=="number"&&t>0&&(e.timeout=setTimeout(()=>{f(s),e.reject(new Error("[Vessel] Action timed out."))},t))}function f(s){const e=a.get(s);e&&(e.timeout&&clearTimeout(e.timeout),a.delete(s))}function g(s){return a.get(s)}function b(s){return`${s?`[VESSEL-${s.toUpperCase()}]:`:"[VESSEL]:"}`.trimStart()}function v(s="log",e){const t=b(e==null?void 0:e.scope);return(...n)=>{e!=null&&e.debug&&console[s](t,...n)}}function R(s){return{info:v("info",s),warn:v("warn",s),error:v("error",s)}}class p extends Error{constructor(e,t){super(`${b(t)} ${e}`),this.name="VesselError"}}let m=(s=21)=>crypto.getRandomValues(new Uint8Array(s)).reduce((e,t)=>(t&=63,t<36?e+=t.toString(36):t<62?e+=(t-26).toString(36).toUpperCase():t>62?e+="-":e+="_",e),"");const w="application/x-opensea-vessel-v1+json";function I(){return`op-${m()}`}function O(){return`msg-${m()}`}function C(s){const e=new URL(s);return`${e.protocol}//${e.host}`}var i=(s=>(s.Handshake="handshake",s.HandshakeReply="handshake-reply",s.Message="message",s.MessageReply="message-reply",s.Close="close",s))(i||{});class c{constructor(e,t){r(this,"type");r(this,"id");r(this,"from");r(this,"operation");r(this,"payload");this.type=e,this.id=(t==null?void 0:t.id)??O(),this.from=(t==null?void 0:t.from)??w,this.operation=(t==null?void 0:t.operation)??I(),this.payload=t==null?void 0:t.payload}toObject(){return{type:this.type,id:this.id,from:this.from,operation:this.operation,payload:this.payload}}}function H(s,e=w){if(s&&typeof s=="object"&&"from"in s&&s.from===e&&"type"in s&&Object.values(i).includes(s.type)&&"id"in s&&"operation"in s)return new c(s.type,{id:s.id,from:s.from,operation:s.operation,payload:s.payload});throw new p("Invalid message.")}function E(s,e,t){if(e==="*"||s.origin===e)return H(s.data,t??w)}class y{constructor(e){r(this,"log");r(this,"parent",window.parent);r(this,"subscriptions");r(this,"closed",!1);r(this,"parentOrigin");this.parentOrigin=e.parentOrigin,this.subscriptions={[i.Message]:[],[i.Close]:[]},this.log=R({debug:e.debug,scope:"CHILD"}),this.onMessage=this.onMessage.bind(this),window.addEventListener("message",this.onMessage,!1)}callSubscriptions(e,t){const n=this.sendMessage.bind(this);if(e===i.Close){this.close(),this.subscriptions[e].forEach(o=>o(t.payload));return}this.subscriptions[e].forEach(o=>{o(t.payload,h=>{n(new c(i.MessageReply,{operation:t.operation,payload:h}))})})}onMessage(e){try{const t=E(e,this.parentOrigin);if(!t)return;switch(t.type){case i.Handshake:this.parentOrigin=e.origin,this.sendHandshakeReply(t);return;case i.Message:this.callSubscriptions(i.Message,t);return;case i.MessageReply:this.resolveReply(t);return}}catch(t){this.log.error("Error parsing message from parent",t)}}sendHandshakeReply(e){this.log.info(`Received handshake from ${this.parentOrigin}`);const t=new c(i.HandshakeReply,{operation:e.operation});try{this.parent.postMessage(t.toObject(),this.parentOrigin)}catch(n){this.log.error("Error sending handshake reply",n)}}resolveReply(e){var t;this.log.info(`Received reply for action ${e.operation}`);try{const n=g(e.operation);if(n){this.log.info(`Resolving action ${e.operation}`);const{resolve:o,reject:h}=n;if(f(e.operation),(t=e.payload)!=null&&t.error){h(e.payload.error);return}o(e.payload)}}catch(n){this.log.error("Error resolving reply",n)}}sendMessage(e){if(!this.parent)throw new p("Parent frame not found.");if(this.closed)throw new p("Cannot send message, frame is closed.");this.parent.postMessage(e.toObject(),this.parentOrigin)}async send(e,t){return new Promise((n,o)=>{const h=new c(i.Message,{payload:e});d(h.operation,{resolve:n,reject:o},t);try{this.sendMessage(h)}catch(u){this.log.error("Error sending message to parent",u),o(u)}})}emit(e){const t=new c(i.Message,{payload:e});this.sendMessage(t)}on(e,t){return this.subscriptions[e].push(t),()=>{this.off.call(this,e,t)}}once(e,t){const n=this.on(e,(...o)=>{n(),t(...o)})}off(e,t){this.subscriptions[e]=this.subscriptions[e].filter(n=>n!==t)}close(){this.closed=!0,window.removeEventListener("message",this.onMessage);const e=new c(i.Close);this.parent.postMessage(e.toObject(),this.parentOrigin)}}class k{constructor(e){r(this,"parentFrame");r(this,"child");r(this,"frame");r(this,"handshakeOperation");r(this,"handshakeInterval");r(this,"handshakeIntervalTimeout",500);r(this,"handshakeActionResolverId");r(this,"subscriptions");r(this,"log");r(this,"childOrigin");r(this,"childUrl");r(this,"connected");this.frame=e.frame,this.parentFrame=window,this.child=null,this.childUrl=e.url,this.childOrigin=C(e.url),this.connected=!1,this.handshakeOperation=null,this.handshakeInterval=null,e.handshakeIntervalTimeout&&(this.handshakeIntervalTimeout=e.handshakeIntervalTimeout),this.subscriptions={[i.Message]:[],[i.Close]:[]},this.log=R({debug:e.debug,scope:"PARENT"}),this.parentFrame.addEventListener("message",this.onMessage.bind(this),!1),this.handshakeActionResolverId=I()}startHandshake(){if(this.log.info(`Sending handshake to ${this.childUrl}`),this.child=this.frame.contentWindow,!this.child)throw new Error("Child frame not found");let e=0;const t=()=>{if(this.log.info("Attempting handshake..."),this.child){e+=1;const n=new c(i.Handshake);this.handshakeOperation=n.operation,this.sendMessage(n)}};t(),this.handshakeInterval=window.setInterval(()=>{if(e>=5){this.log.warn("Handshake failed after 5 attempts. Giving up."),this.handshakeInterval&&window.clearInterval(this.handshakeInterval);return}t()},this.handshakeIntervalTimeout)}callSubscriptions(e,t){const n=this.sendMessage.bind(this);if(e===i.Close){this.close(),this.subscriptions[e].forEach(o=>o(t.payload));return}this.subscriptions[e].forEach(o=>{o(t.payload,h=>{n(new c(i.MessageReply,{operation:t.operation,payload:h}))})})}handleHandshakeReply(e){var h;if(this.log.info(`Received handshake reply from ${this.childUrl}`),e.operation!==this.handshakeOperation)throw new Error("Handshake reply operation does not match");this.handshakeInterval&&window.clearInterval(this.handshakeInterval),this.connected=!0;const t=g(this.handshakeActionResolverId);if(!t)throw new p("Handshake resolver not found");this.log.info(`Resolving action ${this.handshakeActionResolverId}`);const{resolve:n,reject:o}=t;if(f(this.handshakeActionResolverId),(h=e.payload)!=null&&h.error){o(e.payload.error);return}n(e.payload)}onMessage(e){try{const t=E(e,this.childOrigin);if(!t)return;switch(t.type){case i.HandshakeReply:this.handleHandshakeReply(t);break;case i.Message:this.callSubscriptions(i.Message,t);break;case i.MessageReply:this.resolveReply(t);break;case i.Close:this.callSubscriptions(i.Close,t);break;default:this.log.warn(`Unknown message type: ${t.type}`)}}catch(t){this.log.error("Error handling message",t)}}resolveReply(e){var t;this.log.info(`Received reply for action ${e.operation}`);try{const n=g(e.operation);if(n){this.log.info(`Resolving action ${e.operation}`);const{resolve:o,reject:h}=n;if(f(e.operation),(t=e.payload)!=null&&t.error){h(e.payload.error);return}o(e.payload)}}catch(n){this.log.error("Error resolving reply",n)}}sendMessage(e){if(!this.child)throw new p("Child frame not found.");if(e.type!==i.Handshake&&!this.connected)throw new p("Not connected to child frame.");this.child.postMessage(e.toObject(),this.childOrigin)}async send(e,t){return new Promise((n,o)=>{const h=new c(i.Message,{payload:e});d(h.operation,{resolve:n,reject:o},t);try{this.sendMessage(h)}catch(u){this.log.error("Error sending message to child",u),o(u)}})}emit(e){const t=new c(i.Message,{payload:e});this.sendMessage(t)}connect({isFrameLoaded:e=!1}={}){return new Promise((t,n)=>{this.log.info(`Connecting to child iframe ${this.childUrl}`),e?this.startHandshake():this.frame.addEventListener("load",this.startHandshake.bind(this)),d(this.handshakeActionResolverId,{resolve:t,reject:n})})}on(e,t){return this.subscriptions[e].push(t),()=>{this.off.call(this,e,t)}}once(e,t){const n=this.on(e,(...o)=>{n(),t(...o)})}off(e,t){this.subscriptions[e]=this.subscriptions[e].filter(n=>n!==t)}close(){this.log.info("Closing frames"),this.subscriptions[i.Message]=[],this.subscriptions[i.Close]=[],this.handshakeOperation=null,this.handshakeInterval&&window.clearInterval(this.handshakeInterval),f(this.handshakeActionResolverId),this.connected=!1}}class M{static createParentFrame(e){return new k(e)}static createChildFrame(e){return new y(e)}}r(M,"ParentFrame",k),r(M,"ChildFrame",y),l.ChildFrame=y,l.MessageType=i,l.ParentFrame=k,l.Vessel=M,Object.defineProperty(l,Symbol.toStringTag,{value:"Module"})}); | ||
(function(l,a){typeof exports=="object"&&typeof module<"u"?a(exports):typeof define=="function"&&define.amd?define(["exports"],a):(l=typeof globalThis<"u"?globalThis:l||self,a(l.Vessel={}))})(this,function(l){"use strict";var $=Object.defineProperty;var S=(l,a,c)=>a in l?$(l,a,{enumerable:!0,configurable:!0,writable:!0,value:c}):l[a]=c;var o=(l,a,c)=>(S(l,typeof a!="symbol"?a+"":a,c),c);const a=new Map;function c(s,e,t){const n=a.get(s);n&&(n.timeout&&clearTimeout(n.timeout),n.reject(new Error("[Vessel] Same action fired again. Keeping only latest.")),a.delete(s)),a.set(s,e),typeof t=="number"&&t>0&&(e.timeout=setTimeout(()=>{f(s),e.reject(new Error("[Vessel] Action timed out."))},t))}function f(s){const e=a.get(s);e&&(e.timeout&&clearTimeout(e.timeout),a.delete(s))}function g(s){return a.get(s)}function b(s){return`${s?`[VESSEL-${s.toUpperCase()}]:`:"[VESSEL]:"}`.trimStart()}function w(s="log",e){const t=b(e==null?void 0:e.scope);return(...n)=>{e!=null&&e.debug&&console[s](t,...n)}}function R(s){return{info:w("info",s),warn:w("warn",s),error:w("error",s)}}class p extends Error{constructor(e,t){super(`${b(t)} ${e}`),this.name="VesselError"}}let m=(s=21)=>crypto.getRandomValues(new Uint8Array(s)).reduce((e,t)=>(t&=63,t<36?e+=t.toString(36):t<62?e+=(t-26).toString(36).toUpperCase():t>62?e+="-":e+="_",e),"");const v="application/x-opensea-vessel-v1+json";function O(){return`op-${m()}`}function E(){return`msg-${m()}`}function C(s){const e=new URL(s);return`${e.protocol}//${e.host}`}var i=(s=>(s.Handshake="handshake",s.HandshakeReply="handshake-reply",s.Message="message",s.MessageReply="message-reply",s.Close="close",s))(i||{});class d{constructor(e,t){o(this,"type");o(this,"id");o(this,"from");o(this,"operation");o(this,"payload");this.type=e,this.id=(t==null?void 0:t.id)??E(),this.from=(t==null?void 0:t.from)??v,this.operation=(t==null?void 0:t.operation)??O(),this.payload=t==null?void 0:t.payload}toObject(){return{type:this.type,id:this.id,from:this.from,operation:this.operation,payload:this.payload}}}function H(s,e=v){if(s&&typeof s=="object"&&"from"in s&&s.from===e&&"type"in s&&Object.values(i).includes(s.type)&&"id"in s&&"operation"in s)return new d(s.type,{id:s.id,from:s.from,operation:s.operation,payload:s.payload});throw new p("Invalid message.")}function I(s,e,t){if(e==="*"||s.origin===e)return H(s.data,t??v)}class y{constructor(e){o(this,"log");o(this,"parent",window.parent);o(this,"subscriptions");o(this,"closed",!1);o(this,"parentOrigin");o(this,"allowedOrigins",[]);this.parentOrigin="",this.allowedOrigins=e.allowedOrigins,this.subscriptions={[i.Message]:[],[i.Close]:[]},this.log=R({debug:e.debug,scope:"CHILD"}),this.onMessage=this.onMessage.bind(this),window.addEventListener("message",this.onMessage,!1)}callSubscriptions(e,t){const n=this.sendMessage.bind(this);if(e===i.Close){this.close(),this.subscriptions[e].forEach(r=>r(t.payload));return}this.subscriptions[e].forEach(r=>{r(t.payload,h=>{n(new d(i.MessageReply,{operation:t.operation,payload:h}))})})}onMessage(e){try{if(this.allowedOrigins.includes(e.origin)){this.parentOrigin=e.origin;const t=I(e,this.parentOrigin);if(!t)return;switch(t.type){case i.Handshake:this.sendHandshakeReply(t);return;case i.Message:this.callSubscriptions(i.Message,t);return;case i.MessageReply:this.resolveReply(t);return}}}catch(t){this.log.error("Error parsing message from parent",t)}}sendHandshakeReply(e){this.log.info(`Received handshake from ${this.parentOrigin}`);const t=new d(i.HandshakeReply,{operation:e.operation});try{this.parent.postMessage(t.toObject(),this.parentOrigin)}catch(n){this.log.error("Error sending handshake reply",n)}}resolveReply(e){var t;this.log.info(`Received reply for action ${e.operation}`);try{const n=g(e.operation);if(n){this.log.info(`Resolving action ${e.operation}`);const{resolve:r,reject:h}=n;if(f(e.operation),(t=e.payload)!=null&&t.error){h(e.payload.error);return}r(e.payload)}}catch(n){this.log.error("Error resolving reply",n)}}sendMessage(e){if(!this.parent)throw new p("Parent frame not found.");if(this.closed)throw new p("Cannot send message, frame is closed.");this.parent.postMessage(e.toObject(),this.parentOrigin)}async send(e,t){return new Promise((n,r)=>{const h=new d(i.Message,{payload:e});c(h.operation,{resolve:n,reject:r},t);try{this.sendMessage(h)}catch(u){this.log.error("Error sending message to parent",u),r(u)}})}emit(e){const t=new d(i.Message,{payload:e});this.sendMessage(t)}on(e,t){return this.subscriptions[e].push(t),()=>{this.off.call(this,e,t)}}once(e,t){const n=this.on(e,(...r)=>{n(),t(...r)})}off(e,t){this.subscriptions[e]=this.subscriptions[e].filter(n=>n!==t)}close(){this.closed=!0,window.removeEventListener("message",this.onMessage);const e=new d(i.Close);this.parent.postMessage(e.toObject(),this.parentOrigin)}}class k{constructor(e){o(this,"parentFrame");o(this,"child");o(this,"frame");o(this,"handshakeOperation");o(this,"handshakeInterval");o(this,"handshakeIntervalTimeout",500);o(this,"handshakeActionResolverId");o(this,"subscriptions");o(this,"log");o(this,"childOrigin");o(this,"childUrl");o(this,"connected");this.frame=e.frame,this.parentFrame=window,this.child=null,this.childUrl=e.url,this.childOrigin=C(e.url),this.connected=!1,this.handshakeOperation=null,this.handshakeInterval=null,e.handshakeIntervalTimeout&&(this.handshakeIntervalTimeout=e.handshakeIntervalTimeout),this.subscriptions={[i.Message]:[],[i.Close]:[]},this.log=R({debug:e.debug,scope:"PARENT"}),this.parentFrame.addEventListener("message",this.onMessage.bind(this),!1),this.handshakeActionResolverId=O()}startHandshake(){if(this.log.info(`Sending handshake to ${this.childUrl}`),this.child=this.frame.contentWindow,!this.child)throw new Error("Child frame not found");let e=0;const t=()=>{if(this.log.info("Attempting handshake..."),this.child){e+=1;const n=new d(i.Handshake);this.handshakeOperation=n.operation,this.sendMessage(n)}};t(),this.handshakeInterval=window.setInterval(()=>{if(e>=5){this.log.warn("Handshake failed after 5 attempts. Giving up."),this.handshakeInterval&&window.clearInterval(this.handshakeInterval);return}t()},this.handshakeIntervalTimeout)}callSubscriptions(e,t){const n=this.sendMessage.bind(this);if(e===i.Close){this.close(),this.subscriptions[e].forEach(r=>r(t.payload));return}this.subscriptions[e].forEach(r=>{r(t.payload,h=>{n(new d(i.MessageReply,{operation:t.operation,payload:h}))})})}handleHandshakeReply(e){var h;if(this.log.info(`Received handshake reply from ${this.childUrl}`),e.operation!==this.handshakeOperation)throw new Error("Handshake reply operation does not match");this.handshakeInterval&&window.clearInterval(this.handshakeInterval),this.connected=!0;const t=g(this.handshakeActionResolverId);if(!t)throw new p("Handshake resolver not found");this.log.info(`Resolving action ${this.handshakeActionResolverId}`);const{resolve:n,reject:r}=t;if(f(this.handshakeActionResolverId),(h=e.payload)!=null&&h.error){r(e.payload.error);return}n(e.payload)}onMessage(e){try{const t=I(e,this.childOrigin);if(!t)return;switch(t.type){case i.HandshakeReply:this.handleHandshakeReply(t);break;case i.Message:this.callSubscriptions(i.Message,t);break;case i.MessageReply:this.resolveReply(t);break;case i.Close:this.callSubscriptions(i.Close,t);break;default:this.log.warn(`Unknown message type: ${t.type}`)}}catch(t){this.log.error("Error handling message",t)}}resolveReply(e){var t;this.log.info(`Received reply for action ${e.operation}`);try{const n=g(e.operation);if(n){this.log.info(`Resolving action ${e.operation}`);const{resolve:r,reject:h}=n;if(f(e.operation),(t=e.payload)!=null&&t.error){h(e.payload.error);return}r(e.payload)}}catch(n){this.log.error("Error resolving reply",n)}}sendMessage(e){if(!this.child)throw new p("Child frame not found.");if(e.type!==i.Handshake&&!this.connected)throw new p("Not connected to child frame.");this.child.postMessage(e.toObject(),this.childOrigin)}async send(e,t){return new Promise((n,r)=>{const h=new d(i.Message,{payload:e});c(h.operation,{resolve:n,reject:r},t);try{this.sendMessage(h)}catch(u){this.log.error("Error sending message to child",u),r(u)}})}emit(e){const t=new d(i.Message,{payload:e});this.sendMessage(t)}connect({isFrameLoaded:e=!1}={}){return new Promise((t,n)=>{this.log.info(`Connecting to child iframe ${this.childUrl}`),e?this.startHandshake():this.frame.addEventListener("load",this.startHandshake.bind(this)),c(this.handshakeActionResolverId,{resolve:t,reject:n})})}on(e,t){return this.subscriptions[e].push(t),()=>{this.off.call(this,e,t)}}once(e,t){const n=this.on(e,(...r)=>{n(),t(...r)})}off(e,t){this.subscriptions[e]=this.subscriptions[e].filter(n=>n!==t)}close(){this.log.info("Closing frames"),this.subscriptions[i.Message]=[],this.subscriptions[i.Close]=[],this.handshakeOperation=null,this.handshakeInterval&&window.clearInterval(this.handshakeInterval),f(this.handshakeActionResolverId),this.connected=!1}}class M{static createParentFrame(e){return new k(e)}static createChildFrame(e){return new y(e)}}o(M,"ParentFrame",k),o(M,"ChildFrame",y),l.ChildFrame=y,l.MessageType=i,l.ParentFrame=k,l.Vessel=M,Object.defineProperty(l,Symbol.toStringTag,{value:"Module"})}); |
import { ActionSubscriptionFn } from "./parent"; | ||
import { MessagePayloadType, MessageType } from "./utils/messaging"; | ||
type ChildFramesParams = { | ||
parentOrigin: string; | ||
debug?: boolean; | ||
allowedOrigins: string[]; | ||
}; | ||
@@ -13,2 +13,3 @@ export declare class ChildFrame { | ||
parentOrigin: string; | ||
private allowedOrigins; | ||
constructor(params: ChildFramesParams); | ||
@@ -15,0 +16,0 @@ private callSubscriptions; |
{ | ||
"name": "@opensea/vessel", | ||
"version": "0.0.22", | ||
"version": "0.0.23", | ||
"description": "🚢 Vessel: a promise-based postMessage library that sails your data smoothly across the Opensea.", | ||
@@ -20,2 +20,15 @@ "files": [ | ||
"types": "dist/index.d.ts", | ||
"scripts": { | ||
"build": "vite build && yarn tsc && rimraf tsconfig.tsbuildinfo", | ||
"dev": "vite", | ||
"dev:e2e": "concurrently 'serve -l 3000 tests/parent' 'serve -l 3001 tests/child' 'playwright test --ui' --kill-others --success first", | ||
"lint:types": "tsc", | ||
"postinstall": "husky install || exit 0", | ||
"prebuild": "rimraf tsconfig.tsbuildinfo dist", | ||
"prepare": "yarn build", | ||
"pretest:e2e": "tsc && vite build && cpy dist/* tests/parent && cpy dist/* tests/child", | ||
"test:e2e": "concurrently 'serve -l 3000 tests/parent' 'serve -l 3001 tests/child' 'playwright test' --kill-others --success first", | ||
"test:unit": "vitest src", | ||
"test:unit:coverage": "vitest src --coverage" | ||
}, | ||
"dependencies": { | ||
@@ -46,15 +59,3 @@ "nanoid": "4.0.2" | ||
] | ||
}, | ||
"scripts": { | ||
"build": "vite build && yarn tsc && rimraf tsconfig.tsbuildinfo", | ||
"dev": "vite", | ||
"dev:e2e": "concurrently 'serve -l 3000 tests/parent' 'serve -l 3001 tests/child' 'playwright test --ui' --kill-others --success first", | ||
"lint:types": "tsc", | ||
"postinstall": "husky install || exit 0", | ||
"prebuild": "rimraf tsconfig.tsbuildinfo dist", | ||
"pretest:e2e": "tsc && vite build && cpy dist/* tests/parent && cpy dist/* tests/child", | ||
"test:e2e": "concurrently 'serve -l 3000 tests/parent' 'serve -l 3001 tests/child' 'playwright test' --kill-others --success first", | ||
"test:unit": "vitest src", | ||
"test:unit:coverage": "vitest src --coverage" | ||
} | ||
} | ||
} |
@@ -45,7 +45,7 @@ import { | ||
const cf = new ChildFrame({ | ||
parentOrigin: "https://example.com", | ||
allowedOrigins: ["https://example.com"], | ||
debug: true, | ||
}) | ||
expect(cf.parentOrigin).toBe("https://example.com") | ||
expect(cf.parentOrigin).toBe("") | ||
expect(addEventListenerStub).toHaveBeenCalledOnce() | ||
@@ -58,2 +58,15 @@ | ||
) | ||
const message = new messaging.Message(messaging.MessageType.Handshake, { | ||
operation: "test", | ||
}) | ||
const event = new MessageEvent("message", { | ||
data: message.toObject(), | ||
origin: "https://example.com", | ||
}) | ||
cf["onMessage"](event) | ||
expect(cf.parentOrigin).toBe("https://example.com") | ||
}) | ||
@@ -63,3 +76,3 @@ | ||
const cf = new ChildFrame({ | ||
parentOrigin: "https://example.com", | ||
allowedOrigins: ["https://example.com"], | ||
debug: false, | ||
@@ -101,3 +114,3 @@ }) | ||
const cf = new ChildFrame({ | ||
parentOrigin: "https://example.com", | ||
allowedOrigins: ["https://example.com"], | ||
debug: false, | ||
@@ -145,3 +158,3 @@ }) | ||
const cf = new ChildFrame({ | ||
parentOrigin: "https://example.com", | ||
allowedOrigins: ["https://example.com"], | ||
debug: true, | ||
@@ -173,3 +186,3 @@ }) | ||
const cf = new ChildFrame({ | ||
parentOrigin: "https://example.com", | ||
allowedOrigins: ["https://example.com"], | ||
debug: true, | ||
@@ -209,3 +222,3 @@ }) | ||
const cf = new ChildFrame({ | ||
parentOrigin: "https://example.com", | ||
allowedOrigins: ["https://example.com"], | ||
debug: true, | ||
@@ -237,3 +250,3 @@ }) | ||
const cf = new ChildFrame({ | ||
parentOrigin: "https://example.com", | ||
allowedOrigins: ["https://example.com"], | ||
debug: true, | ||
@@ -280,3 +293,3 @@ }) | ||
const cf = new ChildFrame({ | ||
parentOrigin: "https://example.com", | ||
allowedOrigins: ["https://example.com"], | ||
debug: true, | ||
@@ -301,3 +314,3 @@ }) | ||
const cf = new ChildFrame({ | ||
parentOrigin: "https://example.com", | ||
allowedOrigins: ["https://example.com"], | ||
debug: false, | ||
@@ -325,3 +338,3 @@ }) | ||
const cf = new ChildFrame({ | ||
parentOrigin: "https://example.com", | ||
allowedOrigins: ["https://example.com"], | ||
debug: false, | ||
@@ -341,3 +354,3 @@ }) | ||
const cf = new ChildFrame({ | ||
parentOrigin: "https://example.com", | ||
allowedOrigins: ["https://example.com"], | ||
debug: false, | ||
@@ -360,3 +373,3 @@ }) | ||
const cf = new ChildFrame({ | ||
parentOrigin: "https://example.com", | ||
allowedOrigins: ["https://example.com"], | ||
debug: false, | ||
@@ -374,3 +387,3 @@ }) | ||
const cf = new ChildFrame({ | ||
parentOrigin: "https://example.com", | ||
allowedOrigins: ["https://example.com"], | ||
debug: false, | ||
@@ -392,3 +405,3 @@ }) | ||
const cf = new ChildFrame({ | ||
parentOrigin: "https://example.com", | ||
allowedOrigins: ["https://example.com"], | ||
debug: false, | ||
@@ -395,0 +408,0 @@ }) |
@@ -16,4 +16,4 @@ import { ActionSubscriptionFn, CloseSubscriptionFn } from "./parent" | ||
type ChildFramesParams = { | ||
parentOrigin: string | ||
debug?: boolean | ||
allowedOrigins: string[] | ||
} | ||
@@ -32,6 +32,9 @@ | ||
parentOrigin: string | ||
private allowedOrigins: string[] = [] | ||
constructor(params: ChildFramesParams) { | ||
this.parentOrigin = params.parentOrigin | ||
this.parentOrigin = "" | ||
this.allowedOrigins = params.allowedOrigins | ||
this.subscriptions = { | ||
@@ -76,22 +79,24 @@ [MessageType.Message]: [], | ||
try { | ||
const message = parseMessageFromMessageEvent(event, this.parentOrigin) | ||
if (this.allowedOrigins.includes(event.origin)) { | ||
this.parentOrigin = event.origin | ||
const message = parseMessageFromMessageEvent(event, this.parentOrigin) | ||
if (!message) { | ||
// Ignore messages from unallowed origins | ||
return | ||
} | ||
switch (message.type) { | ||
case MessageType.Handshake: | ||
this.parentOrigin = event.origin | ||
this.sendHandshakeReply(message) | ||
if (!message) { | ||
// Ignore messages from unallowed origins | ||
return | ||
} | ||
case MessageType.Message: | ||
this.callSubscriptions(MessageType.Message, message) | ||
return | ||
switch (message.type) { | ||
case MessageType.Handshake: | ||
this.sendHandshakeReply(message) | ||
return | ||
case MessageType.MessageReply: | ||
this.resolveReply(message) | ||
return | ||
case MessageType.Message: | ||
this.callSubscriptions(MessageType.Message, message) | ||
return | ||
case MessageType.MessageReply: | ||
this.resolveReply(message) | ||
return | ||
} | ||
} | ||
@@ -98,0 +103,0 @@ } catch (error) { |
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
76813
1.11%2031
0.89%1
Infinity%