Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@opensea/vessel

Package Overview
Dependencies
Maintainers
10
Versions
508
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@opensea/vessel - npm Package Compare versions

Comparing version 0.0.3 to 0.0.4

338

dist/@opensea/vessel.es.js

@@ -1,34 +0,34 @@

var M = Object.defineProperty;
var E = (n, e, t) => e in n ? M(n, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : n[e] = t;
var s = (n, e, t) => (E(n, typeof e != "symbol" ? e + "" : e, t), t);
const l = /* @__PURE__ */ new Map();
function R(n, e, t) {
const i = l.get(n);
i && (i.timeout && clearTimeout(i.timeout), i.reject(
var O = Object.defineProperty;
var C = (s, e, t) => e in s ? O(s, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : s[e] = t;
var r = (s, e, t) => (C(s, typeof e != "symbol" ? e + "" : e, t), t);
const d = /* @__PURE__ */ new Map();
function k(s, e, t) {
const n = d.get(s);
n && (n.timeout && clearTimeout(n.timeout), n.reject(
new Error("[Vessel] Same action fired again. Keeping only latest.")
), l.delete(n)), l.set(n, e), typeof t == "number" && t > 0 && (e.timeout = setTimeout(() => {
v(n), e.reject(new Error("[Vessel] Action timed out."));
), d.delete(s)), d.set(s, e), typeof t == "number" && t > 0 && (e.timeout = setTimeout(() => {
u(s), e.reject(new Error("[Vessel] Action timed out."));
}, t));
}
function v(n) {
const e = l.get(n);
e && (e.timeout && clearTimeout(e.timeout), l.delete(n));
function u(s) {
const e = d.get(s);
e && (e.timeout && clearTimeout(e.timeout), d.delete(s));
}
function C(n) {
return l.get(n);
function b(s) {
return d.get(s);
}
function y(n) {
return `${n ? `[VESSEL-${n.toUpperCase()}]:` : "[VESSEL]:"}`.trimStart();
function M(s) {
return `${s ? `[VESSEL-${s.toUpperCase()}]:` : "[VESSEL]:"}`.trimStart();
}
function p(n = "log", e) {
const t = y(e == null ? void 0 : e.scope);
return (...i) => {
e != null && e.debug && console[n](t, ...i);
function f(s = "log", e) {
const t = M(e == null ? void 0 : e.scope);
return (...n) => {
e != null && e.debug && console[s](t, ...n);
};
}
function m(n) {
function m(s) {
return {
info: p("info", n),
warn: p("warn", n),
error: p("error", n)
info: f("info", s),
warn: f("warn", s),
error: f("error", s)
};

@@ -38,27 +38,27 @@ }

constructor(e, t) {
super(`${y(t)} ${e}`), this.name = "VesselError";
super(`${M(t)} ${e}`), this.name = "VesselError";
}
}
let b = (n = 21) => crypto.getRandomValues(new Uint8Array(n)).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 f = "application/x-opensea-vessel-v1+json";
let E = (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 g = "application/x-opensea-vessel-v1+json";
function I() {
return `op-${b()}`;
return `op-${E()}`;
}
function H() {
return `msg-${b()}`;
function $() {
return `msg-${E()}`;
}
function $(n) {
const e = new URL(n);
function H(s) {
const e = new URL(s);
return `${e.protocol}//${e.host}`;
}
var r = /* @__PURE__ */ ((n) => (n.Handshake = "handshake", n.HandshakeReply = "handshake-reply", n.Message = "message", n.MessageReply = "message-reply", n.Close = "close", n))(r || {});
class a {
var i = /* @__PURE__ */ ((s) => (s.Handshake = "handshake", s.HandshakeReply = "handshake-reply", s.Message = "message", s.MessageReply = "message-reply", s.Close = "close", s))(i || {});
class l {
constructor(e, t) {
s(this, "type");
s(this, "id");
s(this, "from");
s(this, "operation");
s(this, "payload");
s(this, "metadata");
this.type = e, this.id = (t == null ? void 0 : t.id) ?? H(), this.from = (t == null ? void 0 : t.from) ?? f, this.operation = (t == null ? void 0 : t.operation) ?? I(), this.payload = t == null ? void 0 : t.payload, this.metadata = t == null ? void 0 : t.metadata;
r(this, "type");
r(this, "id");
r(this, "from");
r(this, "operation");
r(this, "payload");
r(this, "metadata");
this.type = e, this.id = (t == null ? void 0 : t.id) ?? $(), this.from = (t == null ? void 0 : t.from) ?? g, this.operation = (t == null ? void 0 : t.operation) ?? I(), this.payload = t == null ? void 0 : t.payload, this.metadata = t == null ? void 0 : t.metadata;
}

@@ -76,34 +76,59 @@ toObject() {

}
function F(n, e = f) {
if (n && typeof n == "object" && "from" in n && n.from === e && "type" in n && Object.values(r).includes(n.type) && "id" in n && "operation" in n)
return new a(n.type, {
id: n.id,
from: n.from,
operation: n.operation,
payload: n.payload,
metadata: n.metadata
function S(s, e = g) {
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 l(s.type, {
id: s.id,
from: s.from,
operation: s.operation,
payload: s.payload,
metadata: s.metadata
});
throw new c("Invalid message.");
}
function O(n, e, t) {
if (e === "*" || n.origin === e)
return F(n.data, t ?? f);
function R(s, e, t) {
if (e === "*" || s.origin === e)
return S(s.data, t ?? g);
throw new c("Invalid message event origin.");
}
class g {
class w {
constructor(e) {
s(this, "log");
s(this, "parent", window.parent);
s(this, "closed", !1);
s(this, "parentOrigin");
this.parentOrigin = e.parentOrigin, this.log = m({ debug: e.debug, scope: "CHILD" }), this.onMessage = this.onMessage.bind(this), window.addEventListener("message", this.onMessage, !1);
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 = m({ 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));
return;
}
this.subscriptions[e].forEach((o) => {
o(t, (a, h) => {
n(
new l(i.MessageReply, {
operation: t.operation,
payload: a,
metadata: h
})
);
});
});
}
onMessage(e) {
try {
const t = O(e, this.parentOrigin);
const t = R(e, this.parentOrigin);
switch (t.type) {
case r.Handshake:
case i.Handshake:
this.sendHandshakeReply(t);
return;
case r.MessageReply:
case i.Message:
this.callSubscriptions(i.Message, t);
return;
case i.MessageReply:
this.resolveReply(t);

@@ -118,3 +143,3 @@ return;

this.log.info(`Received handshake from ${this.parentOrigin}`);
const t = new a(r.HandshakeReply, {
const t = new l(i.HandshakeReply, {
operation: e.operation

@@ -124,4 +149,4 @@ });

this.parent.postMessage(t.toObject(), this.parentOrigin);
} catch (i) {
this.log.error("Error sending handshake reply", i);
} catch (n) {
this.log.error("Error sending handshake reply", n);
}

@@ -133,8 +158,8 @@ }

try {
const i = C(e.operation);
if (i) {
const n = b(e.operation);
if (n) {
this.log.info(`Resolving action ${e.operation}`);
const { resolve: o, reject: h } = i;
if (v(e.operation), (t = e.payload) != null && t.error) {
h(e.payload.error);
const { resolve: o, reject: a } = n;
if (u(e.operation), (t = e.payload) != null && t.error) {
a(e.payload.error);
return;

@@ -144,6 +169,13 @@ }

}
} catch (i) {
this.log.error("Error resolving reply", i);
} catch (n) {
this.log.error("Error resolving reply", n);
}
}
sendMessage(e) {
if (!this.parent)
throw new c("Parent frame not found.");
if (this.closed)
throw new c("Cannot send message, frame is closed.");
this.parent.postMessage(e.toObject(), this.parentOrigin);
}
/**

@@ -157,15 +189,13 @@ * Send a message to the parent frame and wait for a reply.

*/
async send(e, t, i = 5e3) {
return new Promise((o, h) => {
if (this.closed)
throw new c("Cannot send message, frame is closed.");
const d = new a(r.Message, {
async send(e, t, n = 5e3) {
return new Promise((o, a) => {
const h = new l(i.Message, {
payload: e,
metadata: t
});
R(d.operation, { resolve: o, reject: h }, i);
k(h.operation, { resolve: o, reject: a }, n);
try {
this.parent.postMessage(d.toObject(), this.parentOrigin);
} catch (u) {
this.log.error("Error sending message to parent", u), h(u);
this.sendMessage(h);
} catch (p) {
this.log.error("Error sending message to parent", p), a(p);
}

@@ -182,29 +212,42 @@ });

throw new c("Cannot emit message, frame is closed.");
const i = new a(r.Message, {
const n = new l(i.Message, {
payload: e,
metadata: t
});
this.parent.postMessage(i.toObject(), this.parentOrigin);
this.parent.postMessage(n.toObject(), this.parentOrigin);
}
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 a(r.Close);
const e = new l(i.Close);
this.parent.postMessage(e.toObject(), this.parentOrigin);
}
}
class w {
class y {
constructor(e) {
s(this, "parentFrame");
s(this, "child");
s(this, "frame");
s(this, "handshakeOperation");
s(this, "handshakeInterval");
s(this, "subscriptions");
s(this, "log");
s(this, "childOrigin");
s(this, "childUrl");
s(this, "connected");
this.frame = e.frame, this.parentFrame = window, this.child = null, this.childUrl = e.url, this.childOrigin = $(e.url), this.connected = !1, this.handshakeOperation = null, this.handshakeInterval = null, this.subscriptions = {
[r.Message]: [],
[r.Close]: []
r(this, "parentFrame");
r(this, "child");
r(this, "frame");
r(this, "handshakeOperation");
r(this, "handshakeInterval");
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, this.subscriptions = {
[i.Message]: [],
[i.Close]: []
}, this.log = m({ debug: e.debug, scope: "PARENT" }), this.parentFrame.addEventListener(

@@ -223,4 +266,4 @@ "message",

e += 1;
const i = new a(r.Handshake);
this.handshakeOperation = i.operation, this.send(i);
const n = new l(i.Handshake);
this.handshakeOperation = n.operation, this.sendMessage(n);
}

@@ -237,4 +280,4 @@ };

callSubscriptions(e, t) {
const i = this.send.bind(this);
if (e === r.Close) {
const n = this.sendMessage.bind(this);
if (e === i.Close) {
this.close(), this.subscriptions[e].forEach((o) => o(t));

@@ -244,8 +287,8 @@ return;

this.subscriptions[e].forEach((o) => {
o(t, (h, d) => {
i(
new a(r.MessageReply, {
o(t, (a, h) => {
n(
new l(i.MessageReply, {
operation: t.operation,
payload: h,
metadata: d
payload: a,
metadata: h
})

@@ -263,13 +306,16 @@ );

try {
const t = O(e, this.childOrigin);
const t = R(e, this.childOrigin);
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.Close:
this.callSubscriptions(r.Close, t);
case i.MessageReply:
this.resolveReply(t);
break;
case i.Close:
this.callSubscriptions(i.Close, t);
break;
default:

@@ -282,9 +328,49 @@ this.log.warn(`Unknown message type: ${t.type}`);

}
send(e) {
resolveReply(e) {
var t;
this.log.info(`Received reply for action ${e.operation}`);
try {
const n = b(e.operation);
if (n) {
this.log.info(`Resolving action ${e.operation}`);
const { resolve: o, reject: a } = n;
if (u(e.operation), (t = e.payload) != null && t.error) {
a(e.payload.error);
return;
}
o(e.payload);
}
} catch (n) {
this.log.error("Error resolving reply", n);
}
}
sendMessage(e) {
if (!this.child)
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.");
this.child.postMessage(e.toObject(), this.childOrigin);
}
/**
* Send a message to the child frame and wait for a reply.
*
* @param payload The payload to send to the child frame
* @param metadata The metadata to send to the child frame
* @param timeout The timeout in milliseconds to wait for a reply, defaults to 5000
* @returns A promise that resolves with the reply payload. Rejects if the timeout is reached.
*/
async send(e, t, n = 5e3) {
return new Promise((o, a) => {
const h = new l(i.Message, {
payload: e,
metadata: t
});
k(h.operation, { resolve: o, reject: a }, n);
try {
this.sendMessage(h);
} catch (p) {
this.log.error("Error sending message to child", p), a(p);
}
});
}
connect() {

@@ -299,28 +385,28 @@ this.log.info(`Connecting to child iframe ${this.childUrl}`), this.frame.addEventListener("load", this.startHandshake.bind(this)), this.frame.src = this.childUrl;

once(e, t) {
const i = this.on(e, (...o) => {
i(), t(...o);
const n = this.on(e, (...o) => {
n(), t(...o);
});
}
off(e, t) {
this.subscriptions[e] = this.subscriptions[e].filter((i) => i !== t);
this.subscriptions[e] = this.subscriptions[e].filter((n) => n !== t);
}
close() {
var e;
this.log.info("Closing frames"), this.subscriptions[r.Message] = [], this.subscriptions[r.Close] = [], this.handshakeOperation = null, this.handshakeInterval && window.clearInterval(this.handshakeInterval), this.connected = !1, (e = this.frame.parentElement) == null || e.removeChild(this.frame);
this.log.info("Closing frames"), this.subscriptions[i.Message] = [], this.subscriptions[i.Close] = [], this.handshakeOperation = null, this.handshakeInterval && window.clearInterval(this.handshakeInterval), this.connected = !1, (e = this.frame.parentElement) == null || e.removeChild(this.frame);
}
}
class k {
class v {
static createParentFrame(e) {
return new w(e);
return new y(e);
}
static createChildFrame(e) {
return new g(e);
return new w(e);
}
}
s(k, "ParentFrame", w), s(k, "ChildFrame", g);
r(v, "ParentFrame", y), r(v, "ChildFrame", w);
export {
g as ChildFrame,
r as MessageType,
w as ParentFrame,
k as Vessel
w as ChildFrame,
i as MessageType,
y as ParentFrame,
v as Vessel
};

@@ -1,1 +0,1 @@

(function(a,o){typeof exports=="object"&&typeof module<"u"?o(exports):typeof define=="function"&&define.amd?define(["exports"],o):(a=typeof globalThis<"u"?globalThis:a||self,o(a.Vessel={}))})(this,function(a){"use strict";var S=Object.defineProperty;var $=(a,o,l)=>o in a?S(a,o,{enumerable:!0,configurable:!0,writable:!0,value:l}):a[o]=l;var s=(a,o,l)=>($(a,typeof o!="symbol"?o+"":o,l),l);const o=new Map;function l(n,e,t){const i=o.get(n);i&&(i.timeout&&clearTimeout(i.timeout),i.reject(new Error("[Vessel] Same action fired again. Keeping only latest.")),o.delete(n)),o.set(n,e),typeof t=="number"&&t>0&&(e.timeout=setTimeout(()=>{m(n),e.reject(new Error("[Vessel] Action timed out."))},t))}function m(n){const e=o.get(n);e&&(e.timeout&&clearTimeout(e.timeout),o.delete(n))}function R(n){return o.get(n)}function v(n){return`${n?`[VESSEL-${n.toUpperCase()}]:`:"[VESSEL]:"}`.trimStart()}function u(n="log",e){const t=v(e==null?void 0:e.scope);return(...i)=>{e!=null&&e.debug&&console[n](t,...i)}}function b(n){return{info:u("info",n),warn:u("warn",n),error:u("error",n)}}class c extends Error{constructor(e,t){super(`${v(t)} ${e}`),this.name="VesselError"}}let M=(n=21)=>crypto.getRandomValues(new Uint8Array(n)).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 g="application/x-opensea-vessel-v1+json";function C(){return`op-${M()}`}function I(){return`msg-${M()}`}function H(n){const e=new URL(n);return`${e.protocol}//${e.host}`}var r=(n=>(n.Handshake="handshake",n.HandshakeReply="handshake-reply",n.Message="message",n.MessageReply="message-reply",n.Close="close",n))(r||{});class d{constructor(e,t){s(this,"type");s(this,"id");s(this,"from");s(this,"operation");s(this,"payload");s(this,"metadata");this.type=e,this.id=(t==null?void 0:t.id)??I(),this.from=(t==null?void 0:t.from)??g,this.operation=(t==null?void 0:t.operation)??C(),this.payload=t==null?void 0:t.payload,this.metadata=t==null?void 0:t.metadata}toObject(){return{type:this.type,id:this.id,from:this.from,operation:this.operation,payload:this.payload,metadata:this.metadata}}}function F(n,e=g){if(n&&typeof n=="object"&&"from"in n&&n.from===e&&"type"in n&&Object.values(r).includes(n.type)&&"id"in n&&"operation"in n)return new d(n.type,{id:n.id,from:n.from,operation:n.operation,payload:n.payload,metadata:n.metadata});throw new c("Invalid message.")}function O(n,e,t){if(e==="*"||n.origin===e)return F(n.data,t??g);throw new c("Invalid message event origin.")}class w{constructor(e){s(this,"log");s(this,"parent",window.parent);s(this,"closed",!1);s(this,"parentOrigin");this.parentOrigin=e.parentOrigin,this.log=b({debug:e.debug,scope:"CHILD"}),this.onMessage=this.onMessage.bind(this),window.addEventListener("message",this.onMessage,!1)}onMessage(e){try{const t=O(e,this.parentOrigin);switch(t.type){case r.Handshake:this.sendHandshakeReply(t);return;case r.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(r.HandshakeReply,{operation:e.operation});try{this.parent.postMessage(t.toObject(),this.parentOrigin)}catch(i){this.log.error("Error sending handshake reply",i)}}resolveReply(e){var t;this.log.info(`Received reply for action ${e.operation}`);try{const i=R(e.operation);if(i){this.log.info(`Resolving action ${e.operation}`);const{resolve:h,reject:p}=i;if(m(e.operation),(t=e.payload)!=null&&t.error){p(e.payload.error);return}h(e.payload)}}catch(i){this.log.error("Error resolving reply",i)}}async send(e,t,i=5e3){return new Promise((h,p)=>{if(this.closed)throw new c("Cannot send message, frame is closed.");const f=new d(r.Message,{payload:e,metadata:t});l(f.operation,{resolve:h,reject:p},i);try{this.parent.postMessage(f.toObject(),this.parentOrigin)}catch(E){this.log.error("Error sending message to parent",E),p(E)}})}emit(e,t){if(this.closed)throw new c("Cannot emit message, frame is closed.");const i=new d(r.Message,{payload:e,metadata:t});this.parent.postMessage(i.toObject(),this.parentOrigin)}close(){this.closed=!0,window.removeEventListener("message",this.onMessage);const e=new d(r.Close);this.parent.postMessage(e.toObject(),this.parentOrigin)}}class y{constructor(e){s(this,"parentFrame");s(this,"child");s(this,"frame");s(this,"handshakeOperation");s(this,"handshakeInterval");s(this,"subscriptions");s(this,"log");s(this,"childOrigin");s(this,"childUrl");s(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,this.subscriptions={[r.Message]:[],[r.Close]:[]},this.log=b({debug:e.debug,scope:"PARENT"}),this.parentFrame.addEventListener("message",this.onMessage.bind(this),!1)}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 i=new d(r.Handshake);this.handshakeOperation=i.operation,this.send(i)}};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()},500)}callSubscriptions(e,t){const i=this.send.bind(this);if(e===r.Close){this.close(),this.subscriptions[e].forEach(h=>h(t));return}this.subscriptions[e].forEach(h=>{h(t,(p,f)=>{i(new d(r.MessageReply,{operation:t.operation,payload:p,metadata:f}))})})}handleHandshakeReply(e){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}onMessage(e){try{const t=O(e,this.childOrigin);switch(t.type){case r.HandshakeReply:this.handleHandshakeReply(t);break;case r.Message:this.callSubscriptions(r.Message,t);break;case r.Close:this.callSubscriptions(r.Close,t);break;default:this.log.warn(`Unknown message type: ${t.type}`)}}catch(t){this.log.error("Error handling message",t)}}send(e){if(!this.child)throw new c("Child frame not found.");if(e.type!==r.Handshake&&!this.connected)throw new c("Not connected to child frame.");this.child.postMessage(e.toObject(),this.childOrigin)}connect(){this.log.info(`Connecting to child iframe ${this.childUrl}`),this.frame.addEventListener("load",this.startHandshake.bind(this)),this.frame.src=this.childUrl}on(e,t){return this.subscriptions[e].push(t),()=>{this.off.call(this,e,t)}}once(e,t){const i=this.on(e,(...h)=>{i(),t(...h)})}off(e,t){this.subscriptions[e]=this.subscriptions[e].filter(i=>i!==t)}close(){var e;this.log.info("Closing frames"),this.subscriptions[r.Message]=[],this.subscriptions[r.Close]=[],this.handshakeOperation=null,this.handshakeInterval&&window.clearInterval(this.handshakeInterval),this.connected=!1,(e=this.frame.parentElement)==null||e.removeChild(this.frame)}}class k{static createParentFrame(e){return new y(e)}static createChildFrame(e){return new w(e)}}s(k,"ParentFrame",y),s(k,"ChildFrame",w),a.ChildFrame=w,a.MessageType=r,a.ParentFrame=y,a.Vessel=k,Object.defineProperty(a,Symbol.toStringTag,{value:"Module"})});
(function(h,a){typeof exports=="object"&&typeof module<"u"?a(exports):typeof define=="function"&&define.amd?define(["exports"],a):(h=typeof globalThis<"u"?globalThis:h||self,a(h.Vessel={}))})(this,function(h){"use strict";var H=Object.defineProperty;var F=(h,a,p)=>a in h?H(h,a,{enumerable:!0,configurable:!0,writable:!0,value:p}):h[a]=p;var r=(h,a,p)=>(F(h,typeof a!="symbol"?a+"":a,p),p);const a=new Map;function p(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(()=>{g(s),e.reject(new Error("[Vessel] Action timed out."))},t))}function g(s){const e=a.get(s);e&&(e.timeout&&clearTimeout(e.timeout),a.delete(s))}function M(s){return a.get(s)}function m(s){return`${s?`[VESSEL-${s.toUpperCase()}]:`:"[VESSEL]:"}`.trimStart()}function w(s="log",e){const t=m(e==null?void 0:e.scope);return(...n)=>{e!=null&&e.debug&&console[s](t,...n)}}function E(s){return{info:w("info",s),warn:w("warn",s),error:w("error",s)}}class f extends Error{constructor(e,t){super(`${m(t)} ${e}`),this.name="VesselError"}}let R=(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 y="application/x-opensea-vessel-v1+json";function C(){return`op-${R()}`}function I(){return`msg-${R()}`}function S(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");r(this,"metadata");this.type=e,this.id=(t==null?void 0:t.id)??I(),this.from=(t==null?void 0:t.from)??y,this.operation=(t==null?void 0:t.operation)??C(),this.payload=t==null?void 0:t.payload,this.metadata=t==null?void 0:t.metadata}toObject(){return{type:this.type,id:this.id,from:this.from,operation:this.operation,payload:this.payload,metadata:this.metadata}}}function $(s,e=y){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,metadata:s.metadata});throw new f("Invalid message.")}function O(s,e,t){if(e==="*"||s.origin===e)return $(s.data,t??y);throw new f("Invalid message event origin.")}class v{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=E({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));return}this.subscriptions[e].forEach(o=>{o(t,(l,d)=>{n(new c(i.MessageReply,{operation:t.operation,payload:l,metadata:d}))})})}onMessage(e){try{const t=O(e,this.parentOrigin);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 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=M(e.operation);if(n){this.log.info(`Resolving action ${e.operation}`);const{resolve:o,reject:l}=n;if(g(e.operation),(t=e.payload)!=null&&t.error){l(e.payload.error);return}o(e.payload)}}catch(n){this.log.error("Error resolving reply",n)}}sendMessage(e){if(!this.parent)throw new f("Parent frame not found.");if(this.closed)throw new f("Cannot send message, frame is closed.");this.parent.postMessage(e.toObject(),this.parentOrigin)}async send(e,t,n=5e3){return new Promise((o,l)=>{const d=new c(i.Message,{payload:e,metadata:t});p(d.operation,{resolve:o,reject:l},n);try{this.sendMessage(d)}catch(u){this.log.error("Error sending message to parent",u),l(u)}})}emit(e,t){if(this.closed)throw new f("Cannot emit message, frame is closed.");const n=new c(i.Message,{payload:e,metadata:t});this.parent.postMessage(n.toObject(),this.parentOrigin)}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 b{constructor(e){r(this,"parentFrame");r(this,"child");r(this,"frame");r(this,"handshakeOperation");r(this,"handshakeInterval");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=S(e.url),this.connected=!1,this.handshakeOperation=null,this.handshakeInterval=null,this.subscriptions={[i.Message]:[],[i.Close]:[]},this.log=E({debug:e.debug,scope:"PARENT"}),this.parentFrame.addEventListener("message",this.onMessage.bind(this),!1)}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()},500)}callSubscriptions(e,t){const n=this.sendMessage.bind(this);if(e===i.Close){this.close(),this.subscriptions[e].forEach(o=>o(t));return}this.subscriptions[e].forEach(o=>{o(t,(l,d)=>{n(new c(i.MessageReply,{operation:t.operation,payload:l,metadata:d}))})})}handleHandshakeReply(e){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}onMessage(e){try{const t=O(e,this.childOrigin);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=M(e.operation);if(n){this.log.info(`Resolving action ${e.operation}`);const{resolve:o,reject:l}=n;if(g(e.operation),(t=e.payload)!=null&&t.error){l(e.payload.error);return}o(e.payload)}}catch(n){this.log.error("Error resolving reply",n)}}sendMessage(e){if(!this.child)throw new f("Child frame not found.");if(e.type!==i.Handshake&&!this.connected)throw new f("Not connected to child frame.");this.child.postMessage(e.toObject(),this.childOrigin)}async send(e,t,n=5e3){return new Promise((o,l)=>{const d=new c(i.Message,{payload:e,metadata:t});p(d.operation,{resolve:o,reject:l},n);try{this.sendMessage(d)}catch(u){this.log.error("Error sending message to child",u),l(u)}})}connect(){this.log.info(`Connecting to child iframe ${this.childUrl}`),this.frame.addEventListener("load",this.startHandshake.bind(this)),this.frame.src=this.childUrl}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(){var e;this.log.info("Closing frames"),this.subscriptions[i.Message]=[],this.subscriptions[i.Close]=[],this.handshakeOperation=null,this.handshakeInterval&&window.clearInterval(this.handshakeInterval),this.connected=!1,(e=this.frame.parentElement)==null||e.removeChild(this.frame)}}class k{static createParentFrame(e){return new b(e)}static createChildFrame(e){return new v(e)}}r(k,"ParentFrame",b),r(k,"ChildFrame",v),h.ChildFrame=v,h.MessageType=i,h.ParentFrame=b,h.Vessel=k,Object.defineProperty(h,Symbol.toStringTag,{value:"Module"})});

@@ -1,2 +0,3 @@

import { MessageMetadataType, MessagePayloadType } from "./utils/messaging";
import { ActionSubscriptionFn } from "./parent";
import { MessageMetadataType, MessagePayloadType, MessageType } from "./utils/messaging";
type ChildFramesParams = {

@@ -9,8 +10,11 @@ parentOrigin: string;

private parent;
private subscriptions;
closed: boolean;
parentOrigin: string;
constructor(params: ChildFramesParams);
private callSubscriptions;
private onMessage;
private sendHandshakeReply;
private resolveReply;
private sendMessage;
/**

@@ -31,4 +35,7 @@ * Send a message to the parent frame and wait for a reply.

emit<P extends MessagePayloadType, M extends MessageMetadataType>(payload: P, metadata?: M): void;
on(type: MessageType.Message, fn: ActionSubscriptionFn): () => void;
once(type: MessageType.Message, fn: ActionSubscriptionFn): void;
off(type: MessageType.Message, fn: ActionSubscriptionFn): void;
close(): void;
}
export {};

@@ -25,3 +25,13 @@ import { Message, MessageMetadataType, MessagePayloadType, MessageType } from "./utils/messaging";

private onMessage;
private send;
private resolveReply;
private sendMessage;
/**
* Send a message to the child frame and wait for a reply.
*
* @param payload The payload to send to the child frame
* @param metadata The metadata to send to the child frame
* @param timeout The timeout in milliseconds to wait for a reply, defaults to 5000
* @returns A promise that resolves with the reply payload. Rejects if the timeout is reached.
*/
send<P extends MessagePayloadType, R extends MessagePayloadType, M extends MessageMetadataType>(payload: P, metadata?: M, timeout?: number): Promise<R>;
connect(): void;

@@ -28,0 +38,0 @@ on(type: MessageType.Message, fn: ActionSubscriptionFn): () => void;

{
"name": "@opensea/vessel",
"version": "0.0.3",
"version": "0.0.4",
"description": "🚢 Vessel: a promise-based postMessage library that sails your data smoothly across the Opensea.",

@@ -5,0 +5,0 @@ "files": [

@@ -226,3 +226,3 @@ import {

test("send sends correct message and adds action resolver", async () => {
test("sends correct message and adds action resolver", async () => {
const getActionResolverStub = vi.spyOn(actionMap, "getActionResolver")

@@ -376,2 +376,20 @@

})
test("It should handle subscription messages", () => {
const cf = new ChildFrame({
parentOrigin: "https://example.com",
debug: false,
})
const mockFn = vi.fn()
cf.on(messaging.MessageType.Message, mockFn)
const subscriber = cf["subscriptions"][messaging.MessageType.Message][0]
const message = new messaging.Message(messaging.MessageType.Message)
subscriber(message, vi.fn())
expect(mockFn).toHaveBeenCalledTimes(1)
expect(mockFn).toHaveBeenCalledWith(message, expect.any(Function))
})
})

@@ -0,1 +1,2 @@

import { ActionSubscriptionFn, CloseSubscriptionFn } from "./parent"
import {

@@ -23,2 +24,8 @@ addActionResolver,

private parent = window.parent
private subscriptions: {
[MessageType.Message]: ActionSubscriptionFn[]
[MessageType.Close]: CloseSubscriptionFn[]
}
closed = false

@@ -29,2 +36,8 @@ parentOrigin: string

this.parentOrigin = params.parentOrigin
this.subscriptions = {
[MessageType.Message]: [],
[MessageType.Close]: [],
}
this.log = createLogger({ debug: params.debug, scope: "CHILD" })

@@ -38,2 +51,27 @@

private callSubscriptions(
type: MessageType.Message | MessageType.Close,
message: Message<any, any>,
) {
const send = this.sendMessage.bind(this)
if (type === MessageType.Close) {
this.close()
this.subscriptions[type].forEach(fn => fn(message))
return
}
this.subscriptions[type].forEach(fn => {
fn(message, (payload, metadata) => {
send(
new Message(MessageType.MessageReply, {
operation: message.operation,
payload,
metadata,
}),
)
})
})
}
private onMessage(event: MessageEvent<any>) {

@@ -48,2 +86,6 @@ try {

case MessageType.Message:
this.callSubscriptions(MessageType.Message, message)
return
case MessageType.MessageReply:

@@ -96,2 +138,17 @@ this.resolveReply(message)

private sendMessage<
P extends MessagePayloadType,
M extends MessageMetadataType,
>(message: Message<P, M>) {
if (!this.parent) {
throw new VesselError("Parent frame not found.")
}
if (this.closed) {
throw new VesselError("Cannot send message, frame is closed.")
}
this.parent.postMessage(message.toObject(), this.parentOrigin)
}
/**

@@ -111,6 +168,2 @@ * Send a message to the parent frame and wait for a reply.

return new Promise<R>((resolve, reject) => {
if (this.closed) {
throw new VesselError("Cannot send message, frame is closed.")
}
const message = new Message<P, M>(MessageType.Message, {

@@ -124,3 +177,3 @@ payload,

try {
this.parent.postMessage(message.toObject(), this.parentOrigin)
this.sendMessage(message)
} catch (error) {

@@ -154,2 +207,21 @@ this.log.error("Error sending message to parent", error)

on(type: MessageType.Message, fn: ActionSubscriptionFn) {
this.subscriptions[type].push(fn)
return () => {
this.off.call(this, type, fn)
}
}
once(type: MessageType.Message, fn: ActionSubscriptionFn) {
const off = this.on(type, (...args) => {
off()
fn(...args)
})
}
off(type: MessageType.Message, fn: ActionSubscriptionFn) {
this.subscriptions[type] = this.subscriptions[type].filter(f => f !== fn)
}
close() {

@@ -156,0 +228,0 @@ this.closed = true

@@ -12,14 +12,5 @@ import { ParentFrame } from "./parent"

} from "vitest"
import * as actionMap from "./utils/action-map"
import * as messaging from "./utils/messaging"
function getFakeFrame() {
return {
src: null as null | string,
contentWindow: {
postMessage: vi.fn(),
},
parentElement: null,
addEventListener: vi.fn(),
} as unknown as HTMLIFrameElement
}
function getFramePostMessageMockCalls(frame: HTMLIFrameElement) {

@@ -44,2 +35,13 @@ return (frame as any).contentWindow.postMessage.mock.calls

function getFakeFrame() {
return {
src: null as null | string,
contentWindow: {
postMessage: postMessageStub,
},
parentElement: null,
addEventListener: vi.fn(),
} as unknown as HTMLIFrameElement
}
function doHandshake(childOrigin: string) {

@@ -126,2 +128,77 @@ const onFrameLoadCall = getFrameAddEventListenerMockCalls(frame)[0]

})
test("sends correct message and adds action resolver", async () => {
const pf = new ParentFrame({ frame, url })
pf.connect()
doHandshake(pf.childOrigin)
const getActionResolverStub = vi.spyOn(actionMap, "getActionResolver")
const resolveStub = vi.fn()
const rejectStub = vi.fn()
getActionResolverStub.mockImplementationOnce(() => ({
resolve: resolveStub,
reject: rejectStub,
}))
const promise = pf.send({ test: "test" }, undefined, 100)
clock.advanceTimersByTime(100)
expect(promise).rejects.toThrowErrorMatchingInlineSnapshot(
'"[Vessel] Action timed out."',
)
const interceptedMessage = postMessageStub.mock.calls[1][0]
const sentMessage = new messaging.Message(
interceptedMessage.type,
interceptedMessage,
)
expect(sentMessage.type).toBe(messaging.MessageType.Message)
expect(sentMessage.payload).toEqual({ test: "test" })
getActionResolverStub.mockRestore()
})
test.only("onMessage parses a valid MessageEvent and handles MessageType.MessageReply correctly", () => {
const addActionResolverStub = vi.spyOn(actionMap, "addActionResolver")
const getActionResolverStub = vi.spyOn(actionMap, "getActionResolver")
const removeActionResolverStub = vi.spyOn(actionMap, "removeActionResolver")
const resolveStub = vi.fn()
const rejectStub = vi.fn()
const pf = new ParentFrame({
frame,
url,
})
const message = new messaging.Message(messaging.MessageType.MessageReply, {
payload: { data: "test" },
})
getActionResolverStub.mockReturnValue({
resolve: resolveStub,
reject: rejectStub,
})
const event = new MessageEvent("message", {
data: message.toObject(),
origin: url,
})
pf["onMessage"](event)
expect(resolveStub).toHaveBeenCalledOnce()
expect(removeActionResolverStub).toHaveBeenCalledOnce()
expect(removeActionResolverStub).toHaveBeenCalledWith(message.operation)
expect(resolveStub).toHaveBeenCalled()
expect(rejectStub).not.toHaveBeenCalled()
addActionResolverStub.mockRestore()
getActionResolverStub.mockRestore()
removeActionResolverStub.mockRestore()
})
})

@@ -0,1 +1,6 @@

import {
addActionResolver,
getActionResolver,
removeActionResolver,
} from "./utils/action-map"
import { Logger, VesselError, createLogger } from "./utils/logger"

@@ -87,3 +92,3 @@ import {

this.send(handshake)
this.sendMessage(handshake)
}

@@ -109,3 +114,3 @@ }

) {
const send = this.send.bind(this)
const send = this.sendMessage.bind(this)

@@ -158,2 +163,6 @@ if (type === MessageType.Close) {

case MessageType.MessageReply:
this.resolveReply(message)
break
case MessageType.Close:

@@ -171,5 +180,30 @@ this.callSubscriptions(MessageType.Close, message)

private send<P extends MessagePayloadType, M extends MessageMetadataType>(
message: Message<P, M>,
) {
private resolveReply(message: Message<any, any>) {
this.log.info(`Received reply for action ${message.operation}`)
try {
const resolver = getActionResolver(message.operation)
if (resolver) {
this.log.info(`Resolving action ${message.operation}`)
const { resolve, reject } = resolver
removeActionResolver(message.operation)
if (message.payload?.error) {
reject(message.payload.error)
return
}
resolve(message.payload)
}
} catch (error) {
this.log.error("Error resolving reply", error)
}
}
private sendMessage<
P extends MessagePayloadType,
M extends MessageMetadataType,
>(message: Message<P, M>) {
if (!this.child) {

@@ -186,2 +220,32 @@ throw new VesselError("Child frame not found.")

/**
* Send a message to the child frame and wait for a reply.
*
* @param payload The payload to send to the child frame
* @param metadata The metadata to send to the child frame
* @param timeout The timeout in milliseconds to wait for a reply, defaults to 5000
* @returns A promise that resolves with the reply payload. Rejects if the timeout is reached.
*/
async send<
P extends MessagePayloadType,
R extends MessagePayloadType,
M extends MessageMetadataType,
>(payload: P, metadata?: M, timeout: number = 5000) {
return new Promise<R>((resolve, reject) => {
const message = new Message<P, M>(MessageType.Message, {
payload,
metadata,
})
addActionResolver(message.operation, { resolve, reject }, timeout)
try {
this.sendMessage(message)
} catch (error) {
this.log.error("Error sending message to child", error)
reject(error)
}
})
}
connect() {

@@ -188,0 +252,0 @@ this.log.info(`Connecting to child iframe ${this.childUrl}`)

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc