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

comlinkjs

Package Overview
Dependencies
Maintainers
1
Versions
26
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

comlinkjs - npm Package Compare versions

Comparing version 2.3.0 to 2.3.1

9

comlink.d.ts

@@ -19,6 +19,13 @@ /**

export declare type Proxy = Function;
export declare type Exposable = Function | Object;
export interface TransferHandler {
canHandle: (obj: {}) => Boolean;
serialize: (obj: {}) => {};
deserialize: (obj: {}) => {};
}
export declare const Comlink: {
proxy: (endpoint: Window | Endpoint) => Function;
proxyValue: (obj: {}) => {};
expose: (rootObj: Object | Function, endpoint: Window | Endpoint) => void;
transferHandlers: Map<string, TransferHandler>;
expose: (rootObj: Exposable, endpoint: Window | Endpoint) => void;
};

249

comlink.es6.js

@@ -14,9 +14,29 @@ /**

export const Comlink = (function () {
const TRANSFERABLE_TYPES = [ArrayBuffer, MessagePort];
const uid = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
const proxyValueSymbol = Symbol('proxyValue');
const throwSymbol = Symbol('throw');
const proxyTransferHandler = {
canHandle: (obj) => obj && obj[proxyValueSymbol],
serialize: (obj) => {
const { port1, port2 } = new MessageChannel();
expose(obj, port1);
return port2;
},
deserialize: (obj) => {
return proxy(obj);
},
};
const throwTransferHandler = {
canHandle: (obj) => obj && obj[throwSymbol],
serialize: (obj) => obj.toString() + '\n' + obj.stack,
deserialize: (obj) => {
throw Error(obj);
},
};
/* export */ const transferHandlers = new Map([
['PROXY', proxyTransferHandler],
['THROW', throwTransferHandler],
]);
let pingPongMessageCounter = 0;
const TRANSFERABLE_TYPES = [ArrayBuffer, MessagePort];
const proxyValueSymbol = Symbol('proxyValue');
// Symbols are not transferable. For the case where a parameter needs to be
// proxy’d, we need to set some sort of transferable, secret marker. This is it.
const transferMarker = '__omg_so_secret';
/* export */ function proxy(endpoint) {

@@ -28,24 +48,9 @@ if (isWindow(endpoint))

activateEndpoint(endpoint);
return batchingProxy(async (irequest) => {
return cbProxy(async (irequest) => {
let args = [];
if (irequest.type === 'APPLY' || irequest.type === 'CONSTRUCT') {
args = irequest.argumentsList =
irequest.argumentsList.map(arg => {
if (!isProxyValue(arg))
return arg;
const { port1, port2 } = new MessageChannel();
expose(arg, port1);
return {
[transferMarker]: 'PROXY',
endpoint: port2,
};
});
}
const response = await pingPongMessage(endpoint, irequest, transferableProperties(args));
if (irequest.type === 'APPLY' || irequest.type === 'CONSTRUCT')
args = irequest.argumentsList.map(wrapValue);
const response = await pingPongMessage(endpoint, Object.assign({}, irequest, { argumentsList: args }), transferableProperties(args));
const result = response.data;
if (result.type === 'ERROR')
throw Error(result.error);
if (result.type === 'PROXY')
return proxy(result.endpoint);
return result.obj;
return unwrapValue(result.value);
});

@@ -69,32 +74,23 @@ }

let obj = await irequest.callPath.reduce((obj, propName) => obj[propName], rootObj);
const isAsyncGenerator = obj.constructor.name === 'AsyncGeneratorFunction';
let iresult = obj;
let ierror;
// If there is an arguments list, proxy-fy parameters as necessary
if ('argumentsList' in irequest) {
irequest.argumentsList =
irequest.argumentsList.map(arg => {
if (arg[transferMarker] === 'PROXY')
return proxy(arg.endpoint);
else
return arg;
});
}
let args = [];
if (irequest.type === 'APPLY' || irequest.type === 'CONSTRUCT')
args = irequest.argumentsList.map(unwrapValue);
if (irequest.type === 'APPLY') {
try {
iresult = await obj.apply(that, irequest.argumentsList);
iresult = await obj.apply(that, args);
}
catch (e) {
ierror = e;
iresult = e;
iresult[throwSymbol] = true;
}
}
if (isAsyncGenerator)
iresult = proxyValue(iresult);
if (irequest.type === 'CONSTRUCT') {
try {
iresult = new obj(...(irequest.argumentsList || [])); // eslint-disable-line new-cap
iresult = new obj(...args); // eslint-disable-line new-cap
iresult = proxyValue(iresult);
}
catch (e) {
ierror = e;
iresult = e;
iresult[throwSymbol] = true;
}

@@ -108,3 +104,3 @@ }

}
iresult = makeInvocationResult(iresult, ierror);
iresult = makeInvocationResult(iresult);
iresult.id = irequest.id;

@@ -114,2 +110,60 @@ return endpoint.postMessage(iresult, transferableProperties([iresult]));

}
function wrapValue(arg) {
// Is arg itself handled by a TransferHandler?
for (const [key, transferHandler] of transferHandlers.entries()) {
if (transferHandler.canHandle(arg)) {
return {
type: key,
value: transferHandler.serialize(arg),
};
}
}
// If not, traverse the entire object and find handled values.
let wrappedChildren = [];
for (const item of iterateAllProperties(arg)) {
for (const [key, transferHandler] of transferHandlers.entries()) {
if (transferHandler.canHandle(item.value)) {
wrappedChildren.push({
path: item.path,
wrappedValue: {
type: key,
value: item.value,
},
});
}
}
}
return {
type: 'RAW',
value: arg,
wrappedChildren,
};
}
function unwrapValue(arg) {
if (transferHandlers.has(arg.type)) {
const transferHandler = transferHandlers.get(arg.type);
return transferHandler.deserialize(arg.value);
}
else if (isRawWrappedValue(arg)) {
for (const wrappedChildValue of (arg.wrappedChildren || [])) {
if (!transferHandlers.has(wrappedChildValue.wrappedValue.type))
throw Error(`Unknown value type "${arg.type}" at ${wrappedChildValue.path.join('.')}`);
const transferHandler = transferHandlers.get(wrappedChildValue.wrappedValue.type);
const newValue = transferHandler.deserialize(wrappedChildValue.wrappedValue.value);
replaceValueInObjectAtPath(arg.value, wrappedChildValue.path, newValue);
}
return arg.value;
}
else {
throw Error(`Unknown value type "${arg.type}"`);
}
}
function replaceValueInObjectAtPath(obj, path, newVal) {
const lastKey = path.slice(-1)[0];
const lastObj = path.slice(0, -1).reduce((obj, key) => obj[key], obj);
lastObj[lastKey] = newVal;
}
function isRawWrappedValue(arg) {
return arg.type === 'RAW';
}
function windowEndpoint(w) {

@@ -173,15 +227,6 @@ if (self.constructor.name !== 'Window')

}
function asyncIteratorSupport() {
return 'asyncIterator' in Symbol;
}
/**
* `batchingProxy` creates a ES6 Proxy that batches `get`s until either
* `construct` or `apply` is called. At that point the callback is invoked with
* the accumulated call path.
*/
function batchingProxy(cb) {
let callPath = [];
function cbProxy(cb, callPath = []) {
return new Proxy(function () { }, {
construct(_target, argumentsList, proxy) {
const r = cb({
return cb({
type: 'CONSTRUCT',

@@ -191,4 +236,2 @@ callPath,

});
callPath = [];
return r;
},

@@ -198,12 +241,5 @@ apply(_target, _thisArg, argumentsList) {

// The actual target for `bind()` is currently ignored.
if (callPath[callPath.length - 1] === 'bind') {
const localCallPath = callPath.slice();
callPath = [];
return (...args) => cb({
type: 'APPLY',
callPath: localCallPath.slice(0, -1),
argumentsList: args,
});
}
const r = cb({
if (callPath[callPath.length - 1] === 'bind')
return cbProxy(cb, callPath.slice(0, -1));
return cb({
type: 'APPLY',

@@ -213,4 +249,2 @@ callPath,

});
callPath = [];
return r;
},

@@ -221,7 +255,2 @@ get(_target, property, proxy) {

}
else if (asyncIteratorSupport() && property === Symbol.asyncIterator) {
// For now, only async generators use `Symbol.asyncIterator` and they
// return themselves, so we emulate that behavior here.
return () => proxy;
}
else if (property === 'then') {

@@ -232,8 +261,6 @@ const r = cb({

});
callPath = [];
return Promise.resolve(r).then.bind(r);
}
else {
callPath.push(property);
return proxy;
return cbProxy(cb, callPath.concat(property));
}

@@ -254,13 +281,17 @@ },

}
function* iterateAllProperties(obj) {
if (!obj)
function* iterateAllProperties(value, path = [], visited = null) {
if (!value)
return;
if (typeof obj === 'string')
if (!visited)
visited = new WeakSet();
if (visited.has(value))
return;
yield obj;
let vals = Object.values(obj);
if (Array.isArray(obj))
vals = obj;
for (const val of vals)
yield* iterateAllProperties(val);
if (typeof value === 'string')
return;
if (typeof value === 'object')
visited.add(value);
yield { value, path };
let keys = Object.keys(value);
for (const key of keys)
yield* iterateAllProperties(value[key], [...path, key], visited);
}

@@ -270,40 +301,24 @@ function transferableProperties(obj) {

for (const prop of iterateAllProperties(obj)) {
if (isTransferable(prop))
r.push(prop);
if (isTransferable(prop.value))
r.push(prop.value);
}
return r;
}
function isProxyValue(obj) {
return obj && obj[proxyValueSymbol];
}
function makeInvocationResult(obj, err = null) {
if (err) {
return {
type: 'ERROR',
error: ('stack' in err) ? err.stack : err.toString(),
};
function makeInvocationResult(obj) {
for (const [type, transferHandler] of transferHandlers.entries()) {
if (transferHandler.canHandle(obj)) {
const value = transferHandler.serialize(obj);
return {
value: { type, value },
};
}
}
// TODO We actually need to perform a structured clone tree
// walk of the data as we want to allow:
// return {foo: proxyValue(foo)};
// We also don't want to directly mutate the data as:
// class A {
// constructor() { this.b = {b: proxyValue(new B())} }
// method1() { return this.b; }
// method2() { this.b.foo; /* should work */ }
// }
if (isProxyValue(obj)) {
const { port1, port2 } = new MessageChannel();
expose(obj, port1);
return {
type: 'PROXY',
endpoint: port2,
};
}
return {
type: 'OBJECT',
obj,
value: {
type: 'RAW',
value: obj,
},
};
}
return { proxy, proxyValue, expose };
return { proxy, proxyValue, transferHandlers, expose };
})();

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

export const Comlink=function(){function a(b){if(j(b)&&(b=d(b)),!e(b))throw Error('endpoint does not have all of addEventListener, removeEventListener and postMessage defined');return f(b),m(async(d)=>{let e=[];('APPLY'===d.type||'CONSTRUCT'===d.type)&&(e=d.argumentsList=d.argumentsList.map((a)=>{if(!q(a))return a;const{port1:b,port2:d}=new MessageChannel;return c(a,b),{[w]:'PROXY',endpoint:d}}));const f=await k(b,d,p(e)),g=f.data;if('ERROR'===g.type)throw Error(g.error);return'PROXY'===g.type?a(g.endpoint):g.obj})}function b(a){return a[v]=!0,a}function c(c,h){if(j(h)&&(h=d(h)),!e(h))throw Error('endpoint does not have all of addEventListener, removeEventListener and postMessage defined');f(h),g(h,async function(d){if(!d.data.id)return;const e=d.data;let f=await e.callPath.slice(0,-1).reduce((a,b)=>a[b],c),g=await e.callPath.reduce((a,b)=>a[b],c);const i='AsyncGeneratorFunction'===g.constructor.name;let j,k=g;if('argumentsList'in e&&(e.argumentsList=e.argumentsList.map((b)=>{return'PROXY'===b[w]?a(b.endpoint):b})),'APPLY'===e.type)try{k=await g.apply(f,e.argumentsList)}catch(a){j=a}if(i&&(k=b(k)),'CONSTRUCT'===e.type)try{k=new g(...(e.argumentsList||[])),k=b(k)}catch(a){j=a}return'SET'===e.type&&(g[e.property]=e.value,k=!0),k=r(k,j),k.id=e.id,h.postMessage(k,p([k]))})}function d(a){if('Window'!==self.constructor.name)throw Error('self is not a window');return{addEventListener:self.addEventListener.bind(self),removeEventListener:self.removeEventListener.bind(self),postMessage:(b,c)=>a.postMessage(b,'*',c)}}function e(a){return'addEventListener'in a&&'removeEventListener'in a&&'postMessage'in a}function f(a){i(a)&&a.start()}function g(a,b){a.addEventListener('message',b)}function h(a,b){a.removeEventListener('message',b)}function i(a){return'MessagePort'===a.constructor.name}function j(a){return['window','length','location','parent','opener'].every((b)=>b in a)}function k(a,b,c){const d=`${s}-${t++}`;return new Promise((e)=>{g(a,function b(c){c.data.id!==d||(h(a,b),e(c))}),b=Object.assign({},b,{id:d}),a.postMessage(b,c)})}function l(){return'asyncIterator'in Symbol}function m(a){let b=[];return new Proxy(function(){},{construct(c,d){const e=a({type:'CONSTRUCT',callPath:b,argumentsList:d});return b=[],e},apply(c,d,e){if('bind'===b[b.length-1]){const c=b.slice();return b=[],(...b)=>a({type:'APPLY',callPath:c.slice(0,-1),argumentsList:b})}const f=a({type:'APPLY',callPath:b,argumentsList:e});return b=[],f},get(c,d,e){if('then'===d&&0===b.length)return{then:()=>e};if(l()&&d===Symbol.asyncIterator)return()=>e;if('then'===d){const c=a({type:'GET',callPath:b});return b=[],Promise.resolve(c).then.bind(c)}return b.push(d),e},set(c,d,e){return a({type:'SET',callPath:b,property:d,value:e})}})}function n(a){return u.some((b)=>a instanceof b)}function*o(a){if(!a)return;if('string'==typeof a)return;yield a;let b=Object.values(a);Array.isArray(a)&&(b=a);for(const c of b)yield*o(c)}function p(a){const b=[];for(const c of o(a))n(c)&&b.push(c);return b}function q(a){return a&&a[v]}function r(a,b=null){if(b)return{type:'ERROR',error:'stack'in b?b.stack:b.toString()};if(q(a)){const{port1:b,port2:d}=new MessageChannel;return c(a,b),{type:'PROXY',endpoint:d}}return{type:'OBJECT',obj:a}}const s=Math.floor(Math.random()*Number.MAX_SAFE_INTEGER);let t=0;const u=[ArrayBuffer,MessagePort],v=Symbol('proxyValue'),w='__omg_so_secret';return{proxy:a,proxyValue:b,expose:c}}();
export const Comlink=function(){function a(a){if(n(a)&&(a=h(a)),!i(a))throw Error('endpoint does not have all of addEventListener, removeEventListener and postMessage defined');return j(a),p(async(b)=>{let c=[];('APPLY'===b.type||'CONSTRUCT'===b.type)&&(c=b.argumentsList.map(d));const f=await o(a,Object.assign({},b,{argumentsList:c}),r(c)),g=f.data;return e(g.value)})}function b(a){return a[w]=!0,a}function c(a,c){if(n(c)&&(c=h(c)),!i(c))throw Error('endpoint does not have all of addEventListener, removeEventListener and postMessage defined');j(c),k(c,async function(d){if(!d.data.id)return;const f=d.data;let g=await f.callPath.slice(0,-1).reduce((a,b)=>a[b],a),h=await f.callPath.reduce((a,b)=>a[b],a),i=h,j=[];if(('APPLY'===f.type||'CONSTRUCT'===f.type)&&(j=f.argumentsList.map(e)),'APPLY'===f.type)try{i=await h.apply(g,j)}catch(a){i=a,i[x]=!0}if('CONSTRUCT'===f.type)try{i=new h(...j),i=b(i)}catch(a){i=a,i[x]=!0}return'SET'===f.type&&(h[f.property]=f.value,i=!0),i=t(i),i.id=f.id,c.postMessage(i,r([i]))})}function d(a){for(const[b,c]of y.entries())if(c.canHandle(a))return{type:b,value:c.serialize(a)};let b=[];for(const c of s(a))for(const[a,d]of y.entries())d.canHandle(c.value)&&b.push({path:c.path,wrappedValue:{type:a,value:c.value}});return{type:'RAW',value:a,wrappedChildren:b}}function e(a){if(y.has(a.type)){const b=y.get(a.type);return b.deserialize(a.value)}if(g(a)){for(const b of a.wrappedChildren||[]){if(!y.has(b.wrappedValue.type))throw Error(`Unknown value type "${a.type}" at ${b.path.join('.')}`);const c=y.get(b.wrappedValue.type),d=c.deserialize(b.wrappedValue.value);f(a.value,b.path,d)}return a.value}throw Error(`Unknown value type "${a.type}"`)}function f(a,b,c){const d=b.slice(-1)[0],e=b.slice(0,-1).reduce((a,b)=>a[b],a);e[d]=c}function g(a){return'RAW'===a.type}function h(a){if('Window'!==self.constructor.name)throw Error('self is not a window');return{addEventListener:self.addEventListener.bind(self),removeEventListener:self.removeEventListener.bind(self),postMessage:(b,c)=>a.postMessage(b,'*',c)}}function i(a){return'addEventListener'in a&&'removeEventListener'in a&&'postMessage'in a}function j(a){m(a)&&a.start()}function k(a,b){a.addEventListener('message',b)}function l(a,b){a.removeEventListener('message',b)}function m(a){return'MessagePort'===a.constructor.name}function n(a){return['window','length','location','parent','opener'].every((b)=>b in a)}function o(a,b,c){const d=`${v}-${z++}`;return new Promise((e)=>{k(a,function b(c){c.data.id!==d||(l(a,b),e(c))}),b=Object.assign({},b,{id:d}),a.postMessage(b,c)})}function p(a,b=[]){return new Proxy(function(){},{construct(c,d){return a({type:'CONSTRUCT',callPath:b,argumentsList:d})},apply(c,d,e){return'bind'===b[b.length-1]?p(a,b.slice(0,-1)):a({type:'APPLY',callPath:b,argumentsList:e})},get(c,d,e){if('then'===d&&0===b.length)return{then:()=>e};if('then'===d){const c=a({type:'GET',callPath:b});return Promise.resolve(c).then.bind(c)}return p(a,b.concat(d))},set(c,d,e){return a({type:'SET',callPath:b,property:d,value:e})}})}function q(a){return u.some((b)=>a instanceof b)}function*s(a,b=[],c=null){if(a&&(c||(c=new WeakSet),!c.has(a))&&'string'!=typeof a){'object'==typeof a&&c.add(a),yield{value:a,path:b};let d=Object.keys(a);for(const e of d)yield*s(a[e],[...b,e],c)}}function r(a){const b=[];for(const c of s(a))q(c.value)&&b.push(c.value);return b}function t(a){for(const[b,c]of y.entries())if(c.canHandle(a)){const d=c.serialize(a);return{value:{type:b,value:d}}}return{value:{type:'RAW',value:a}}}const u=[ArrayBuffer,MessagePort],v=Math.floor(Math.random()*Number.MAX_SAFE_INTEGER),w=Symbol('proxyValue'),x=Symbol('throw'),y=new Map([['PROXY',{canHandle:(a)=>a&&a[w],serialize:(a)=>{const{port1:b,port2:d}=new MessageChannel;return c(a,b),d},deserialize:(b)=>{return a(b)}}],['THROW',{canHandle:(a)=>a&&a[x],serialize:(a)=>a.toString()+'\n'+a.stack,deserialize:(a)=>{throw Error(a)}}]]);let z=0;return{proxy:a,proxyValue:b,transferHandlers:y,expose:c}}();

@@ -16,9 +16,29 @@ "use strict";

self.Comlink = (function () {
const TRANSFERABLE_TYPES = [ArrayBuffer, MessagePort];
const uid = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
const proxyValueSymbol = Symbol('proxyValue');
const throwSymbol = Symbol('throw');
const proxyTransferHandler = {
canHandle: (obj) => obj && obj[proxyValueSymbol],
serialize: (obj) => {
const { port1, port2 } = new MessageChannel();
expose(obj, port1);
return port2;
},
deserialize: (obj) => {
return proxy(obj);
},
};
const throwTransferHandler = {
canHandle: (obj) => obj && obj[throwSymbol],
serialize: (obj) => obj.toString() + '\n' + obj.stack,
deserialize: (obj) => {
throw Error(obj);
},
};
/* export */ const transferHandlers = new Map([
['PROXY', proxyTransferHandler],
['THROW', throwTransferHandler],
]);
let pingPongMessageCounter = 0;
const TRANSFERABLE_TYPES = [ArrayBuffer, MessagePort];
const proxyValueSymbol = Symbol('proxyValue');
// Symbols are not transferable. For the case where a parameter needs to be
// proxy’d, we need to set some sort of transferable, secret marker. This is it.
const transferMarker = '__omg_so_secret';
/* export */ function proxy(endpoint) {

@@ -30,24 +50,9 @@ if (isWindow(endpoint))

activateEndpoint(endpoint);
return batchingProxy(async (irequest) => {
return cbProxy(async (irequest) => {
let args = [];
if (irequest.type === 'APPLY' || irequest.type === 'CONSTRUCT') {
args = irequest.argumentsList =
irequest.argumentsList.map(arg => {
if (!isProxyValue(arg))
return arg;
const { port1, port2 } = new MessageChannel();
expose(arg, port1);
return {
[transferMarker]: 'PROXY',
endpoint: port2,
};
});
}
const response = await pingPongMessage(endpoint, irequest, transferableProperties(args));
if (irequest.type === 'APPLY' || irequest.type === 'CONSTRUCT')
args = irequest.argumentsList.map(wrapValue);
const response = await pingPongMessage(endpoint, Object.assign({}, irequest, { argumentsList: args }), transferableProperties(args));
const result = response.data;
if (result.type === 'ERROR')
throw Error(result.error);
if (result.type === 'PROXY')
return proxy(result.endpoint);
return result.obj;
return unwrapValue(result.value);
});

@@ -71,32 +76,23 @@ }

let obj = await irequest.callPath.reduce((obj, propName) => obj[propName], rootObj);
const isAsyncGenerator = obj.constructor.name === 'AsyncGeneratorFunction';
let iresult = obj;
let ierror;
// If there is an arguments list, proxy-fy parameters as necessary
if ('argumentsList' in irequest) {
irequest.argumentsList =
irequest.argumentsList.map(arg => {
if (arg[transferMarker] === 'PROXY')
return proxy(arg.endpoint);
else
return arg;
});
}
let args = [];
if (irequest.type === 'APPLY' || irequest.type === 'CONSTRUCT')
args = irequest.argumentsList.map(unwrapValue);
if (irequest.type === 'APPLY') {
try {
iresult = await obj.apply(that, irequest.argumentsList);
iresult = await obj.apply(that, args);
}
catch (e) {
ierror = e;
iresult = e;
iresult[throwSymbol] = true;
}
}
if (isAsyncGenerator)
iresult = proxyValue(iresult);
if (irequest.type === 'CONSTRUCT') {
try {
iresult = new obj(...(irequest.argumentsList || [])); // eslint-disable-line new-cap
iresult = new obj(...args); // eslint-disable-line new-cap
iresult = proxyValue(iresult);
}
catch (e) {
ierror = e;
iresult = e;
iresult[throwSymbol] = true;
}

@@ -110,3 +106,3 @@ }

}
iresult = makeInvocationResult(iresult, ierror);
iresult = makeInvocationResult(iresult);
iresult.id = irequest.id;

@@ -116,2 +112,60 @@ return endpoint.postMessage(iresult, transferableProperties([iresult]));

}
function wrapValue(arg) {
// Is arg itself handled by a TransferHandler?
for (const [key, transferHandler] of transferHandlers.entries()) {
if (transferHandler.canHandle(arg)) {
return {
type: key,
value: transferHandler.serialize(arg),
};
}
}
// If not, traverse the entire object and find handled values.
let wrappedChildren = [];
for (const item of iterateAllProperties(arg)) {
for (const [key, transferHandler] of transferHandlers.entries()) {
if (transferHandler.canHandle(item.value)) {
wrappedChildren.push({
path: item.path,
wrappedValue: {
type: key,
value: item.value,
},
});
}
}
}
return {
type: 'RAW',
value: arg,
wrappedChildren,
};
}
function unwrapValue(arg) {
if (transferHandlers.has(arg.type)) {
const transferHandler = transferHandlers.get(arg.type);
return transferHandler.deserialize(arg.value);
}
else if (isRawWrappedValue(arg)) {
for (const wrappedChildValue of (arg.wrappedChildren || [])) {
if (!transferHandlers.has(wrappedChildValue.wrappedValue.type))
throw Error(`Unknown value type "${arg.type}" at ${wrappedChildValue.path.join('.')}`);
const transferHandler = transferHandlers.get(wrappedChildValue.wrappedValue.type);
const newValue = transferHandler.deserialize(wrappedChildValue.wrappedValue.value);
replaceValueInObjectAtPath(arg.value, wrappedChildValue.path, newValue);
}
return arg.value;
}
else {
throw Error(`Unknown value type "${arg.type}"`);
}
}
function replaceValueInObjectAtPath(obj, path, newVal) {
const lastKey = path.slice(-1)[0];
const lastObj = path.slice(0, -1).reduce((obj, key) => obj[key], obj);
lastObj[lastKey] = newVal;
}
function isRawWrappedValue(arg) {
return arg.type === 'RAW';
}
function windowEndpoint(w) {

@@ -175,15 +229,6 @@ if (self.constructor.name !== 'Window')

}
function asyncIteratorSupport() {
return 'asyncIterator' in Symbol;
}
/**
* `batchingProxy` creates a ES6 Proxy that batches `get`s until either
* `construct` or `apply` is called. At that point the callback is invoked with
* the accumulated call path.
*/
function batchingProxy(cb) {
let callPath = [];
function cbProxy(cb, callPath = []) {
return new Proxy(function () { }, {
construct(_target, argumentsList, proxy) {
const r = cb({
return cb({
type: 'CONSTRUCT',

@@ -193,4 +238,2 @@ callPath,

});
callPath = [];
return r;
},

@@ -200,12 +243,5 @@ apply(_target, _thisArg, argumentsList) {

// The actual target for `bind()` is currently ignored.
if (callPath[callPath.length - 1] === 'bind') {
const localCallPath = callPath.slice();
callPath = [];
return (...args) => cb({
type: 'APPLY',
callPath: localCallPath.slice(0, -1),
argumentsList: args,
});
}
const r = cb({
if (callPath[callPath.length - 1] === 'bind')
return cbProxy(cb, callPath.slice(0, -1));
return cb({
type: 'APPLY',

@@ -215,4 +251,2 @@ callPath,

});
callPath = [];
return r;
},

@@ -223,7 +257,2 @@ get(_target, property, proxy) {

}
else if (asyncIteratorSupport() && property === Symbol.asyncIterator) {
// For now, only async generators use `Symbol.asyncIterator` and they
// return themselves, so we emulate that behavior here.
return () => proxy;
}
else if (property === 'then') {

@@ -234,8 +263,6 @@ const r = cb({

});
callPath = [];
return Promise.resolve(r).then.bind(r);
}
else {
callPath.push(property);
return proxy;
return cbProxy(cb, callPath.concat(property));
}

@@ -256,13 +283,17 @@ },

}
function* iterateAllProperties(obj) {
if (!obj)
function* iterateAllProperties(value, path = [], visited = null) {
if (!value)
return;
if (typeof obj === 'string')
if (!visited)
visited = new WeakSet();
if (visited.has(value))
return;
yield obj;
let vals = Object.values(obj);
if (Array.isArray(obj))
vals = obj;
for (const val of vals)
yield* iterateAllProperties(val);
if (typeof value === 'string')
return;
if (typeof value === 'object')
visited.add(value);
yield { value, path };
let keys = Object.keys(value);
for (const key of keys)
yield* iterateAllProperties(value[key], [...path, key], visited);
}

@@ -272,40 +303,24 @@ function transferableProperties(obj) {

for (const prop of iterateAllProperties(obj)) {
if (isTransferable(prop))
r.push(prop);
if (isTransferable(prop.value))
r.push(prop.value);
}
return r;
}
function isProxyValue(obj) {
return obj && obj[proxyValueSymbol];
}
function makeInvocationResult(obj, err = null) {
if (err) {
return {
type: 'ERROR',
error: ('stack' in err) ? err.stack : err.toString(),
};
function makeInvocationResult(obj) {
for (const [type, transferHandler] of transferHandlers.entries()) {
if (transferHandler.canHandle(obj)) {
const value = transferHandler.serialize(obj);
return {
value: { type, value },
};
}
}
// TODO We actually need to perform a structured clone tree
// walk of the data as we want to allow:
// return {foo: proxyValue(foo)};
// We also don't want to directly mutate the data as:
// class A {
// constructor() { this.b = {b: proxyValue(new B())} }
// method1() { return this.b; }
// method2() { this.b.foo; /* should work */ }
// }
if (isProxyValue(obj)) {
const { port1, port2 } = new MessageChannel();
expose(obj, port1);
return {
type: 'PROXY',
endpoint: port2,
};
}
return {
type: 'OBJECT',
obj,
value: {
type: 'RAW',
value: obj,
},
};
}
return { proxy, proxyValue, expose };
return { proxy, proxyValue, transferHandlers, expose };
})();

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

'use strict';self.Comlink=function(){function a(b){if(j(b)&&(b=d(b)),!e(b))throw Error('endpoint does not have all of addEventListener, removeEventListener and postMessage defined');return f(b),m(async(d)=>{let e=[];('APPLY'===d.type||'CONSTRUCT'===d.type)&&(e=d.argumentsList=d.argumentsList.map((a)=>{if(!q(a))return a;const{port1:b,port2:d}=new MessageChannel;return c(a,b),{[w]:'PROXY',endpoint:d}}));const f=await k(b,d,p(e)),g=f.data;if('ERROR'===g.type)throw Error(g.error);return'PROXY'===g.type?a(g.endpoint):g.obj})}function b(a){return a[v]=!0,a}function c(c,h){if(j(h)&&(h=d(h)),!e(h))throw Error('endpoint does not have all of addEventListener, removeEventListener and postMessage defined');f(h),g(h,async function(d){if(!d.data.id)return;const e=d.data;let f=await e.callPath.slice(0,-1).reduce((a,b)=>a[b],c),g=await e.callPath.reduce((a,b)=>a[b],c);const i='AsyncGeneratorFunction'===g.constructor.name;let j,k=g;if('argumentsList'in e&&(e.argumentsList=e.argumentsList.map((b)=>{return'PROXY'===b[w]?a(b.endpoint):b})),'APPLY'===e.type)try{k=await g.apply(f,e.argumentsList)}catch(a){j=a}if(i&&(k=b(k)),'CONSTRUCT'===e.type)try{k=new g(...(e.argumentsList||[])),k=b(k)}catch(a){j=a}return'SET'===e.type&&(g[e.property]=e.value,k=!0),k=r(k,j),k.id=e.id,h.postMessage(k,p([k]))})}function d(a){if('Window'!==self.constructor.name)throw Error('self is not a window');return{addEventListener:self.addEventListener.bind(self),removeEventListener:self.removeEventListener.bind(self),postMessage:(b,c)=>a.postMessage(b,'*',c)}}function e(a){return'addEventListener'in a&&'removeEventListener'in a&&'postMessage'in a}function f(a){i(a)&&a.start()}function g(a,b){a.addEventListener('message',b)}function h(a,b){a.removeEventListener('message',b)}function i(a){return'MessagePort'===a.constructor.name}function j(a){return['window','length','location','parent','opener'].every((b)=>b in a)}function k(a,b,c){const d=`${s}-${t++}`;return new Promise((e)=>{g(a,function b(c){c.data.id!==d||(h(a,b),e(c))}),b=Object.assign({},b,{id:d}),a.postMessage(b,c)})}function l(){return'asyncIterator'in Symbol}function m(a){let b=[];return new Proxy(function(){},{construct(c,d){const e=a({type:'CONSTRUCT',callPath:b,argumentsList:d});return b=[],e},apply(c,d,e){if('bind'===b[b.length-1]){const c=b.slice();return b=[],(...b)=>a({type:'APPLY',callPath:c.slice(0,-1),argumentsList:b})}const f=a({type:'APPLY',callPath:b,argumentsList:e});return b=[],f},get(c,d,e){if('then'===d&&0===b.length)return{then:()=>e};if(l()&&d===Symbol.asyncIterator)return()=>e;if('then'===d){const c=a({type:'GET',callPath:b});return b=[],Promise.resolve(c).then.bind(c)}return b.push(d),e},set(c,d,e){return a({type:'SET',callPath:b,property:d,value:e})}})}function n(a){return u.some((b)=>a instanceof b)}function*o(a){if(!a)return;if('string'==typeof a)return;yield a;let b=Object.values(a);Array.isArray(a)&&(b=a);for(const c of b)yield*o(c)}function p(a){const b=[];for(const c of o(a))n(c)&&b.push(c);return b}function q(a){return a&&a[v]}function r(a,b=null){if(b)return{type:'ERROR',error:'stack'in b?b.stack:b.toString()};if(q(a)){const{port1:b,port2:d}=new MessageChannel;return c(a,b),{type:'PROXY',endpoint:d}}return{type:'OBJECT',obj:a}}const s=Math.floor(Math.random()*Number.MAX_SAFE_INTEGER);let t=0;const u=[ArrayBuffer,MessagePort],v=Symbol('proxyValue'),w='__omg_so_secret';return{proxy:a,proxyValue:b,expose:c}}();
'use strict';self.Comlink=function(){function a(a){if(n(a)&&(a=h(a)),!i(a))throw Error('endpoint does not have all of addEventListener, removeEventListener and postMessage defined');return j(a),p(async(b)=>{let c=[];('APPLY'===b.type||'CONSTRUCT'===b.type)&&(c=b.argumentsList.map(d));const f=await o(a,Object.assign({},b,{argumentsList:c}),r(c)),g=f.data;return e(g.value)})}function b(a){return a[w]=!0,a}function c(a,c){if(n(c)&&(c=h(c)),!i(c))throw Error('endpoint does not have all of addEventListener, removeEventListener and postMessage defined');j(c),k(c,async function(d){if(!d.data.id)return;const f=d.data;let g=await f.callPath.slice(0,-1).reduce((a,b)=>a[b],a),h=await f.callPath.reduce((a,b)=>a[b],a),i=h,j=[];if(('APPLY'===f.type||'CONSTRUCT'===f.type)&&(j=f.argumentsList.map(e)),'APPLY'===f.type)try{i=await h.apply(g,j)}catch(a){i=a,i[x]=!0}if('CONSTRUCT'===f.type)try{i=new h(...j),i=b(i)}catch(a){i=a,i[x]=!0}return'SET'===f.type&&(h[f.property]=f.value,i=!0),i=t(i),i.id=f.id,c.postMessage(i,r([i]))})}function d(a){for(const[b,c]of y.entries())if(c.canHandle(a))return{type:b,value:c.serialize(a)};let b=[];for(const c of s(a))for(const[a,d]of y.entries())d.canHandle(c.value)&&b.push({path:c.path,wrappedValue:{type:a,value:c.value}});return{type:'RAW',value:a,wrappedChildren:b}}function e(a){if(y.has(a.type)){const b=y.get(a.type);return b.deserialize(a.value)}if(g(a)){for(const b of a.wrappedChildren||[]){if(!y.has(b.wrappedValue.type))throw Error(`Unknown value type "${a.type}" at ${b.path.join('.')}`);const c=y.get(b.wrappedValue.type),d=c.deserialize(b.wrappedValue.value);f(a.value,b.path,d)}return a.value}throw Error(`Unknown value type "${a.type}"`)}function f(a,b,c){const d=b.slice(-1)[0],e=b.slice(0,-1).reduce((a,b)=>a[b],a);e[d]=c}function g(a){return'RAW'===a.type}function h(a){if('Window'!==self.constructor.name)throw Error('self is not a window');return{addEventListener:self.addEventListener.bind(self),removeEventListener:self.removeEventListener.bind(self),postMessage:(b,c)=>a.postMessage(b,'*',c)}}function i(a){return'addEventListener'in a&&'removeEventListener'in a&&'postMessage'in a}function j(a){m(a)&&a.start()}function k(a,b){a.addEventListener('message',b)}function l(a,b){a.removeEventListener('message',b)}function m(a){return'MessagePort'===a.constructor.name}function n(a){return['window','length','location','parent','opener'].every((b)=>b in a)}function o(a,b,c){const d=`${v}-${z++}`;return new Promise((e)=>{k(a,function b(c){c.data.id!==d||(l(a,b),e(c))}),b=Object.assign({},b,{id:d}),a.postMessage(b,c)})}function p(a,b=[]){return new Proxy(function(){},{construct(c,d){return a({type:'CONSTRUCT',callPath:b,argumentsList:d})},apply(c,d,e){return'bind'===b[b.length-1]?p(a,b.slice(0,-1)):a({type:'APPLY',callPath:b,argumentsList:e})},get(c,d,e){if('then'===d&&0===b.length)return{then:()=>e};if('then'===d){const c=a({type:'GET',callPath:b});return Promise.resolve(c).then.bind(c)}return p(a,b.concat(d))},set(c,d,e){return a({type:'SET',callPath:b,property:d,value:e})}})}function q(a){return u.some((b)=>a instanceof b)}function*s(a,b=[],c=null){if(a&&(c||(c=new WeakSet),!c.has(a))&&'string'!=typeof a){'object'==typeof a&&c.add(a),yield{value:a,path:b};let d=Object.keys(a);for(const e of d)yield*s(a[e],[...b,e],c)}}function r(a){const b=[];for(const c of s(a))q(c.value)&&b.push(c.value);return b}function t(a){for(const[b,c]of y.entries())if(c.canHandle(a)){const d=c.serialize(a);return{value:{type:b,value:d}}}return{value:{type:'RAW',value:a}}}const u=[ArrayBuffer,MessagePort],v=Math.floor(Math.random()*Number.MAX_SAFE_INTEGER),w=Symbol('proxyValue'),x=Symbol('throw'),y=new Map([['PROXY',{canHandle:(a)=>a&&a[w],serialize:(a)=>{const{port1:b,port2:d}=new MessageChannel;return c(a,b),d},deserialize:(b)=>{return a(b)}}],['THROW',{canHandle:(a)=>a&&a[x],serialize:(a)=>a.toString()+'\n'+a.stack,deserialize:(a)=>{throw Error(a)}}]]);let z=0;return{proxy:a,proxyValue:b,transferHandlers:y,expose:c}}();

@@ -25,9 +25,29 @@ /**

exports.Comlink = (function () {
const TRANSFERABLE_TYPES = [ArrayBuffer, MessagePort];
const uid = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
const proxyValueSymbol = Symbol('proxyValue');
const throwSymbol = Symbol('throw');
const proxyTransferHandler = {
canHandle: (obj) => obj && obj[proxyValueSymbol],
serialize: (obj) => {
const { port1, port2 } = new MessageChannel();
expose(obj, port1);
return port2;
},
deserialize: (obj) => {
return proxy(obj);
},
};
const throwTransferHandler = {
canHandle: (obj) => obj && obj[throwSymbol],
serialize: (obj) => obj.toString() + '\n' + obj.stack,
deserialize: (obj) => {
throw Error(obj);
},
};
/* export */ const transferHandlers = new Map([
['PROXY', proxyTransferHandler],
['THROW', throwTransferHandler],
]);
let pingPongMessageCounter = 0;
const TRANSFERABLE_TYPES = [ArrayBuffer, MessagePort];
const proxyValueSymbol = Symbol('proxyValue');
// Symbols are not transferable. For the case where a parameter needs to be
// proxy’d, we need to set some sort of transferable, secret marker. This is it.
const transferMarker = '__omg_so_secret';
/* export */ function proxy(endpoint) {

@@ -39,24 +59,9 @@ if (isWindow(endpoint))

activateEndpoint(endpoint);
return batchingProxy(async (irequest) => {
return cbProxy(async (irequest) => {
let args = [];
if (irequest.type === 'APPLY' || irequest.type === 'CONSTRUCT') {
args = irequest.argumentsList =
irequest.argumentsList.map(arg => {
if (!isProxyValue(arg))
return arg;
const { port1, port2 } = new MessageChannel();
expose(arg, port1);
return {
[transferMarker]: 'PROXY',
endpoint: port2,
};
});
}
const response = await pingPongMessage(endpoint, irequest, transferableProperties(args));
if (irequest.type === 'APPLY' || irequest.type === 'CONSTRUCT')
args = irequest.argumentsList.map(wrapValue);
const response = await pingPongMessage(endpoint, Object.assign({}, irequest, { argumentsList: args }), transferableProperties(args));
const result = response.data;
if (result.type === 'ERROR')
throw Error(result.error);
if (result.type === 'PROXY')
return proxy(result.endpoint);
return result.obj;
return unwrapValue(result.value);
});

@@ -80,32 +85,23 @@ }

let obj = await irequest.callPath.reduce((obj, propName) => obj[propName], rootObj);
const isAsyncGenerator = obj.constructor.name === 'AsyncGeneratorFunction';
let iresult = obj;
let ierror;
// If there is an arguments list, proxy-fy parameters as necessary
if ('argumentsList' in irequest) {
irequest.argumentsList =
irequest.argumentsList.map(arg => {
if (arg[transferMarker] === 'PROXY')
return proxy(arg.endpoint);
else
return arg;
});
}
let args = [];
if (irequest.type === 'APPLY' || irequest.type === 'CONSTRUCT')
args = irequest.argumentsList.map(unwrapValue);
if (irequest.type === 'APPLY') {
try {
iresult = await obj.apply(that, irequest.argumentsList);
iresult = await obj.apply(that, args);
}
catch (e) {
ierror = e;
iresult = e;
iresult[throwSymbol] = true;
}
}
if (isAsyncGenerator)
iresult = proxyValue(iresult);
if (irequest.type === 'CONSTRUCT') {
try {
iresult = new obj(...(irequest.argumentsList || [])); // eslint-disable-line new-cap
iresult = new obj(...args); // eslint-disable-line new-cap
iresult = proxyValue(iresult);
}
catch (e) {
ierror = e;
iresult = e;
iresult[throwSymbol] = true;
}

@@ -119,3 +115,3 @@ }

}
iresult = makeInvocationResult(iresult, ierror);
iresult = makeInvocationResult(iresult);
iresult.id = irequest.id;

@@ -125,2 +121,60 @@ return endpoint.postMessage(iresult, transferableProperties([iresult]));

}
function wrapValue(arg) {
// Is arg itself handled by a TransferHandler?
for (const [key, transferHandler] of transferHandlers.entries()) {
if (transferHandler.canHandle(arg)) {
return {
type: key,
value: transferHandler.serialize(arg),
};
}
}
// If not, traverse the entire object and find handled values.
let wrappedChildren = [];
for (const item of iterateAllProperties(arg)) {
for (const [key, transferHandler] of transferHandlers.entries()) {
if (transferHandler.canHandle(item.value)) {
wrappedChildren.push({
path: item.path,
wrappedValue: {
type: key,
value: item.value,
},
});
}
}
}
return {
type: 'RAW',
value: arg,
wrappedChildren,
};
}
function unwrapValue(arg) {
if (transferHandlers.has(arg.type)) {
const transferHandler = transferHandlers.get(arg.type);
return transferHandler.deserialize(arg.value);
}
else if (isRawWrappedValue(arg)) {
for (const wrappedChildValue of (arg.wrappedChildren || [])) {
if (!transferHandlers.has(wrappedChildValue.wrappedValue.type))
throw Error(`Unknown value type "${arg.type}" at ${wrappedChildValue.path.join('.')}`);
const transferHandler = transferHandlers.get(wrappedChildValue.wrappedValue.type);
const newValue = transferHandler.deserialize(wrappedChildValue.wrappedValue.value);
replaceValueInObjectAtPath(arg.value, wrappedChildValue.path, newValue);
}
return arg.value;
}
else {
throw Error(`Unknown value type "${arg.type}"`);
}
}
function replaceValueInObjectAtPath(obj, path, newVal) {
const lastKey = path.slice(-1)[0];
const lastObj = path.slice(0, -1).reduce((obj, key) => obj[key], obj);
lastObj[lastKey] = newVal;
}
function isRawWrappedValue(arg) {
return arg.type === 'RAW';
}
function windowEndpoint(w) {

@@ -184,15 +238,6 @@ if (self.constructor.name !== 'Window')

}
function asyncIteratorSupport() {
return 'asyncIterator' in Symbol;
}
/**
* `batchingProxy` creates a ES6 Proxy that batches `get`s until either
* `construct` or `apply` is called. At that point the callback is invoked with
* the accumulated call path.
*/
function batchingProxy(cb) {
let callPath = [];
function cbProxy(cb, callPath = []) {
return new Proxy(function () { }, {
construct(_target, argumentsList, proxy) {
const r = cb({
return cb({
type: 'CONSTRUCT',

@@ -202,4 +247,2 @@ callPath,

});
callPath = [];
return r;
},

@@ -209,12 +252,5 @@ apply(_target, _thisArg, argumentsList) {

// The actual target for `bind()` is currently ignored.
if (callPath[callPath.length - 1] === 'bind') {
const localCallPath = callPath.slice();
callPath = [];
return (...args) => cb({
type: 'APPLY',
callPath: localCallPath.slice(0, -1),
argumentsList: args,
});
}
const r = cb({
if (callPath[callPath.length - 1] === 'bind')
return cbProxy(cb, callPath.slice(0, -1));
return cb({
type: 'APPLY',

@@ -224,4 +260,2 @@ callPath,

});
callPath = [];
return r;
},

@@ -232,7 +266,2 @@ get(_target, property, proxy) {

}
else if (asyncIteratorSupport() && property === Symbol.asyncIterator) {
// For now, only async generators use `Symbol.asyncIterator` and they
// return themselves, so we emulate that behavior here.
return () => proxy;
}
else if (property === 'then') {

@@ -243,8 +272,6 @@ const r = cb({

});
callPath = [];
return Promise.resolve(r).then.bind(r);
}
else {
callPath.push(property);
return proxy;
return cbProxy(cb, callPath.concat(property));
}

@@ -265,13 +292,17 @@ },

}
function* iterateAllProperties(obj) {
if (!obj)
function* iterateAllProperties(value, path = [], visited = null) {
if (!value)
return;
if (typeof obj === 'string')
if (!visited)
visited = new WeakSet();
if (visited.has(value))
return;
yield obj;
let vals = Object.values(obj);
if (Array.isArray(obj))
vals = obj;
for (const val of vals)
yield* iterateAllProperties(val);
if (typeof value === 'string')
return;
if (typeof value === 'object')
visited.add(value);
yield { value, path };
let keys = Object.keys(value);
for (const key of keys)
yield* iterateAllProperties(value[key], [...path, key], visited);
}

@@ -281,41 +312,25 @@ function transferableProperties(obj) {

for (const prop of iterateAllProperties(obj)) {
if (isTransferable(prop))
r.push(prop);
if (isTransferable(prop.value))
r.push(prop.value);
}
return r;
}
function isProxyValue(obj) {
return obj && obj[proxyValueSymbol];
}
function makeInvocationResult(obj, err = null) {
if (err) {
return {
type: 'ERROR',
error: ('stack' in err) ? err.stack : err.toString(),
};
function makeInvocationResult(obj) {
for (const [type, transferHandler] of transferHandlers.entries()) {
if (transferHandler.canHandle(obj)) {
const value = transferHandler.serialize(obj);
return {
value: { type, value },
};
}
}
// TODO We actually need to perform a structured clone tree
// walk of the data as we want to allow:
// return {foo: proxyValue(foo)};
// We also don't want to directly mutate the data as:
// class A {
// constructor() { this.b = {b: proxyValue(new B())} }
// method1() { return this.b; }
// method2() { this.b.foo; /* should work */ }
// }
if (isProxyValue(obj)) {
const { port1, port2 } = new MessageChannel();
expose(obj, port1);
return {
type: 'PROXY',
endpoint: port2,
};
}
return {
type: 'OBJECT',
obj,
value: {
type: 'RAW',
value: obj,
},
};
}
return { proxy, proxyValue, expose };
return { proxy, proxyValue, transferHandlers, expose };
})();
});

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

(function(a){if("object"==typeof module&&"object"==typeof module.exports){var b=a(require,exports);b!==void 0&&(module.exports=b)}else"function"==typeof define&&define.amd&&define(["require","exports"],a)})(function(a,b){"use strict";Object.defineProperty(b,"__esModule",{value:!0}),b.Comlink=function(){function a(b){if(j(b)&&(b=d(b)),!e(b))throw Error("endpoint does not have all of addEventListener, removeEventListener and postMessage defined");return f(b),m(async(d)=>{let e=[];("APPLY"===d.type||"CONSTRUCT"===d.type)&&(e=d.argumentsList=d.argumentsList.map((a)=>{if(!q(a))return a;const{port1:b,port2:d}=new MessageChannel;return c(a,b),{[w]:"PROXY",endpoint:d}}));const f=await k(b,d,p(e)),g=f.data;if("ERROR"===g.type)throw Error(g.error);return"PROXY"===g.type?a(g.endpoint):g.obj})}function b(a){return a[v]=!0,a}function c(c,h){if(j(h)&&(h=d(h)),!e(h))throw Error("endpoint does not have all of addEventListener, removeEventListener and postMessage defined");f(h),g(h,async function(d){if(!d.data.id)return;const e=d.data;let f=await e.callPath.slice(0,-1).reduce((a,b)=>a[b],c),g=await e.callPath.reduce((a,b)=>a[b],c);const i="AsyncGeneratorFunction"===g.constructor.name;let j,k=g;if("argumentsList"in e&&(e.argumentsList=e.argumentsList.map((b)=>{return"PROXY"===b[w]?a(b.endpoint):b})),"APPLY"===e.type)try{k=await g.apply(f,e.argumentsList)}catch(a){j=a}if(i&&(k=b(k)),"CONSTRUCT"===e.type)try{k=new g(...(e.argumentsList||[])),k=b(k)}catch(a){j=a}return"SET"===e.type&&(g[e.property]=e.value,k=!0),k=r(k,j),k.id=e.id,h.postMessage(k,p([k]))})}function d(a){if("Window"!==self.constructor.name)throw Error("self is not a window");return{addEventListener:self.addEventListener.bind(self),removeEventListener:self.removeEventListener.bind(self),postMessage:(b,c)=>a.postMessage(b,"*",c)}}function e(a){return"addEventListener"in a&&"removeEventListener"in a&&"postMessage"in a}function f(a){i(a)&&a.start()}function g(a,b){a.addEventListener("message",b)}function h(a,b){a.removeEventListener("message",b)}function i(a){return"MessagePort"===a.constructor.name}function j(a){return["window","length","location","parent","opener"].every((b)=>b in a)}function k(a,b,c){const d=`${s}-${t++}`;return new Promise((e)=>{g(a,function b(c){c.data.id!==d||(h(a,b),e(c))}),b=Object.assign({},b,{id:d}),a.postMessage(b,c)})}function l(){return"asyncIterator"in Symbol}function m(a){let b=[];return new Proxy(function(){},{construct(c,d){const e=a({type:"CONSTRUCT",callPath:b,argumentsList:d});return b=[],e},apply(c,d,e){if("bind"===b[b.length-1]){const c=b.slice();return b=[],(...b)=>a({type:"APPLY",callPath:c.slice(0,-1),argumentsList:b})}const f=a({type:"APPLY",callPath:b,argumentsList:e});return b=[],f},get(c,d,e){if("then"===d&&0===b.length)return{then:()=>e};if(l()&&d===Symbol.asyncIterator)return()=>e;if("then"===d){const c=a({type:"GET",callPath:b});return b=[],Promise.resolve(c).then.bind(c)}return b.push(d),e},set(c,d,e){return a({type:"SET",callPath:b,property:d,value:e})}})}function n(a){return u.some((b)=>a instanceof b)}function*o(a){if(!a)return;if("string"==typeof a)return;yield a;let b=Object.values(a);Array.isArray(a)&&(b=a);for(const c of b)yield*o(c)}function p(a){const b=[];for(const c of o(a))n(c)&&b.push(c);return b}function q(a){return a&&a[v]}function r(a,b=null){if(b)return{type:"ERROR",error:"stack"in b?b.stack:b.toString()};if(q(a)){const{port1:b,port2:d}=new MessageChannel;return c(a,b),{type:"PROXY",endpoint:d}}return{type:"OBJECT",obj:a}}const s=Math.floor(Math.random()*Number.MAX_SAFE_INTEGER);let t=0;const u=[ArrayBuffer,MessagePort],v=Symbol("proxyValue"),w="__omg_so_secret";return{proxy:a,proxyValue:b,expose:c}}()});
(function(a){if("object"==typeof module&&"object"==typeof module.exports){var b=a(require,exports);b!==void 0&&(module.exports=b)}else"function"==typeof define&&define.amd&&define(["require","exports"],a)})(function(a,b){"use strict";Object.defineProperty(b,"__esModule",{value:!0}),b.Comlink=function(){function a(a){if(n(a)&&(a=h(a)),!i(a))throw Error("endpoint does not have all of addEventListener, removeEventListener and postMessage defined");return j(a),p(async(b)=>{let c=[];("APPLY"===b.type||"CONSTRUCT"===b.type)&&(c=b.argumentsList.map(d));const f=await o(a,Object.assign({},b,{argumentsList:c}),r(c)),g=f.data;return e(g.value)})}function b(a){return a[w]=!0,a}function c(a,c){if(n(c)&&(c=h(c)),!i(c))throw Error("endpoint does not have all of addEventListener, removeEventListener and postMessage defined");j(c),k(c,async function(d){if(!d.data.id)return;const f=d.data;let g=await f.callPath.slice(0,-1).reduce((a,b)=>a[b],a),h=await f.callPath.reduce((a,b)=>a[b],a),i=h,j=[];if(("APPLY"===f.type||"CONSTRUCT"===f.type)&&(j=f.argumentsList.map(e)),"APPLY"===f.type)try{i=await h.apply(g,j)}catch(a){i=a,i[x]=!0}if("CONSTRUCT"===f.type)try{i=new h(...j),i=b(i)}catch(a){i=a,i[x]=!0}return"SET"===f.type&&(h[f.property]=f.value,i=!0),i=t(i),i.id=f.id,c.postMessage(i,r([i]))})}function d(a){for(const[b,c]of y.entries())if(c.canHandle(a))return{type:b,value:c.serialize(a)};let b=[];for(const c of s(a))for(const[a,d]of y.entries())d.canHandle(c.value)&&b.push({path:c.path,wrappedValue:{type:a,value:c.value}});return{type:"RAW",value:a,wrappedChildren:b}}function e(a){if(y.has(a.type)){const b=y.get(a.type);return b.deserialize(a.value)}if(g(a)){for(const b of a.wrappedChildren||[]){if(!y.has(b.wrappedValue.type))throw Error(`Unknown value type "${a.type}" at ${b.path.join(".")}`);const c=y.get(b.wrappedValue.type),d=c.deserialize(b.wrappedValue.value);f(a.value,b.path,d)}return a.value}throw Error(`Unknown value type "${a.type}"`)}function f(a,b,c){const d=b.slice(-1)[0],e=b.slice(0,-1).reduce((a,b)=>a[b],a);e[d]=c}function g(a){return"RAW"===a.type}function h(a){if("Window"!==self.constructor.name)throw Error("self is not a window");return{addEventListener:self.addEventListener.bind(self),removeEventListener:self.removeEventListener.bind(self),postMessage:(b,c)=>a.postMessage(b,"*",c)}}function i(a){return"addEventListener"in a&&"removeEventListener"in a&&"postMessage"in a}function j(a){m(a)&&a.start()}function k(a,b){a.addEventListener("message",b)}function l(a,b){a.removeEventListener("message",b)}function m(a){return"MessagePort"===a.constructor.name}function n(a){return["window","length","location","parent","opener"].every((b)=>b in a)}function o(a,b,c){const d=`${v}-${z++}`;return new Promise((e)=>{k(a,function b(c){c.data.id!==d||(l(a,b),e(c))}),b=Object.assign({},b,{id:d}),a.postMessage(b,c)})}function p(a,b=[]){return new Proxy(function(){},{construct(c,d){return a({type:"CONSTRUCT",callPath:b,argumentsList:d})},apply(c,d,e){return"bind"===b[b.length-1]?p(a,b.slice(0,-1)):a({type:"APPLY",callPath:b,argumentsList:e})},get(c,d,e){if("then"===d&&0===b.length)return{then:()=>e};if("then"===d){const c=a({type:"GET",callPath:b});return Promise.resolve(c).then.bind(c)}return p(a,b.concat(d))},set(c,d,e){return a({type:"SET",callPath:b,property:d,value:e})}})}function q(a){return u.some((b)=>a instanceof b)}function*s(a,b=[],c=null){if(a&&(c||(c=new WeakSet),!c.has(a))&&"string"!=typeof a){"object"==typeof a&&c.add(a),yield{value:a,path:b};let d=Object.keys(a);for(const e of d)yield*s(a[e],[...b,e],c)}}function r(a){const b=[];for(const c of s(a))q(c.value)&&b.push(c.value);return b}function t(a){for(const[b,c]of y.entries())if(c.canHandle(a)){const d=c.serialize(a);return{value:{type:b,value:d}}}return{value:{type:"RAW",value:a}}}const u=[ArrayBuffer,MessagePort],v=Math.floor(Math.random()*Number.MAX_SAFE_INTEGER),w=Symbol("proxyValue"),x=Symbol("throw"),y=new Map([["PROXY",{canHandle:(a)=>a&&a[w],serialize:(a)=>{const{port1:b,port2:d}=new MessageChannel;return c(a,b),d},deserialize:(b)=>{return a(b)}}],["THROW",{canHandle:(a)=>a&&a[x],serialize:(a)=>a.toString()+"\n"+a.stack,deserialize:(a)=>{throw Error(a)}}]]);let z=0;return{proxy:a,proxyValue:b,transferHandlers:y,expose:c}}()});
{
"name": "comlinkjs",
"version": "2.3.0",
"version": "2.3.1",
"description": "",

@@ -9,3 +9,3 @@ "main": "comlink.umd.js",

"scripts": {
"test": "npm run linter && npm run unittest",
"test": "npm run linter && npm run unittest && npm run build",
"unittest": "karma start",

@@ -15,7 +15,7 @@ "linter": "eslint comlink.ts && eslint messagechanneladapter.ts",

"watchtestharmony": "karma start --no-single-run --browsers ChromeCanaryHeadlessHarmony",
"version": "sed -i .bak -E 's!comlinkjs@[0-9.]+!comlinkjs@'${npm_package_version}'!' README.md && git add README.md",
"version": "sed -i.bak -e 's!comlinkjs@[0-9.]+!comlinkjs@'${npm_package_version}'!' README.md && git add README.md",
"mypublish": "npm run build && npm run test && cp README.md package.json dist && npm publish dist",
"build": "rm -rf dist && mkdir dist && npm run compile && npm run mangle_global && npm run minify",
"compile": "tsc --outDir dist -m none && mv dist/comlink.{,global.}js && mv dist/messagechanneladapter.{,global.}js && tsc --outDir dist -m es2015 && mv dist/comlink.{,es6.}js && mv dist/messagechanneladapter.{,es6.}js && tsc -d --outDir dist -m umd && mv dist/comlink.{,umd.}js && mv dist/messagechanneladapter.{,umd.}js",
"mangle_global": "sed -i .bak 's!exports.Comlink!self.Comlink!' dist/comlink.global.js && sed -i .bak 's!^.*\"__esModule\".*$!!' dist/comlink.global.js && sed -i .bak 's!exports.MessageChannelAdapter!self.MessageChannelAdapter!' dist/messagechanneladapter.global.js && sed -i .bak 's!^.*\"__esModule\".*$!!' dist/messagechanneladapter.global.js",
"mangle_global": "sed -i.bak -e 's!exports.Comlink!self.Comlink!' dist/comlink.global.js && sed -i.bak 's!^.*\"__esModule\".*$!!' dist/comlink.global.js && sed -i.bak -e 's!exports.MessageChannelAdapter!self.MessageChannelAdapter!' dist/messagechanneladapter.global.js && sed -i.bak -e 's!^.*\"__esModule\".*$!!' dist/messagechanneladapter.global.js",
"minify": "babili -o dist/comlink.global.{min.,}js && babili -o dist/comlink.es6.{min.,}js && babili -o dist/comlink.umd.{min.,}js && babili -o dist/messagechanneladapter.global.{min.,}js && babili -o dist/messagechanneladapter.es6.{min.,}js && babili -o dist/messagechanneladapter.umd.{min.,}js"

@@ -42,3 +42,3 @@ },

"chai": "4.1.2",
"eslint": "4.8.0",
"eslint": "4.13.1",
"eslint-config-google": "0.9.1",

@@ -48,11 +48,11 @@ "karma": "1.7.1",

"karma-chrome-launcher": "2.2.0",
"karma-firefox-launcher": "1.0.1",
"karma-firefox-launcher": "1.1.0",
"karma-mocha": "1.3.0",
"karma-safari-launcher": "1.0.0",
"karma-typescript": "3.0.7",
"mocha": "4.0.0",
"typescript": "2.5.3",
"typescript-eslint-parser": "8.0.0"
"karma-typescript": "3.0.8",
"mocha": "4.0.1",
"typescript": "2.6.2",
"typescript-eslint-parser": "11.0.0"
},
"dependencies": {}
}

@@ -26,3 +26,3 @@ # Comlink

**Size**: ~3.1k, ~1.3k gzip’d.
**Size**: ~4.0k, ~1.6k gzip’d.

@@ -118,3 +118,3 @@ ## Example

### `expose(rootObj, endpoint)`
### `Comlink.expose(rootObj, endpoint)`

@@ -126,3 +126,3 @@ `expose` is the counter-part to `proxy`. It listens for RPC messages on

### `proxyValue(value)`
### `Comlink.proxyValue(value)`

@@ -150,2 +150,51 @@ If structurally cloning a value is undesired (either for a function parameter or

# TransferHandler
Some types are neither transferable not structurally cloneable and can therefore
not be `postMessage`’d. To remedy this, a `TransferHandler` offers a hook into the
serialization and deserialization process to allow these types to be used with
Comlink. `TransferHandler`s must fulfill the following interface:
- `canHandle(obj)`: Should `true` if this `TransferHandler` is capable of
(de)serializing the given object.
- `serialize(obj)`: Serializes `obj` to something structurally cloneable.
- `deserialize(obj)`: The inverse of `serialize`.
## Example
One example would be that using an instance of a class as a parameter to a remote
function will invoke the function with a simple JSON object. The prototype gets
lost when the instance gets structurally cloned. Let’s say the class
`ComplexNumber` is used for some calculations. To make sure instances
of `ComplexNumber` are handled correctly, the following `TransferHandler` can be
used:
```js
const complexNumberTransferHandler = {
canHandle(obj) {
return obj instanceof ComplexNumber;
},
serialize(obj) {
return {re: obj.re, im: obj.im};
}
deserialize(obj) {
return new ComplexNumber(obj.re, obj.im);
}
};
```
This new `TransferHandler` can be registered with Comlink like this:
```js
Comlink.transferHandlers.set('COMPLEX', complexNumberTransferHandler);
```
The string can be arbitrary but must be unique across all `TransferHandler`s.
**Note:** The `TransferHandler` must be registered on _both_ sides of the
Comlink channel.
To see a more generic example see the [EventListener example] or the
[Classes example].
# MessageChannelAdapter

@@ -179,4 +228,6 @@

[PresentationConnection]: https://developer.mozilla.org/en-US/docs/Web/API/PresentationConnection
[EventListener example]: https://github.com/GoogleChromeLabs/comlink/tree/master/docs/examples/eventlistener
[Classes example]: https://github.com/GoogleChromeLabs/comlink/tree/master/docs/examples/classes
---
License Apache-2.0

Sorry, the diff of this file is not supported yet

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