Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
23 lines
No EOL
16 KiB
JavaScript
23 lines
No EOL
16 KiB
JavaScript
;;;;;;;;;(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.bridge=f()}})(function(){var define,module,exports;return(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){var bridge=module.exports=self['bridge']||{};bridge['client']=require('../src/client');if((typeof define)[0]!='u')define([],()=>bridge);else self['bridge']=bridge;},{"../src/client":2}],2:[function(require,module,exports){'use strict';var createPort=require('./message/port-adaptors');var Emitter=require('./emitter');var message=require('./message');var uuid=require('./utils').uuid;module.exports=Client;var debug={0:()=>{},1:arg=>performance.mark(`[${self.constructor.name}][Client] - ${arg}`),2:(arg1,...args)=>{var type=`[${self.constructor.name}][${location.pathname}]`;console.log(`[Client]${type} - "${arg1}"`,...args);}}[0];var env=constructor.name
|
|
function Client(service,endpoint,timeout){if(!(this instanceof Client))return new Client(service,endpoint,timeout);if(typeof service=='object'){endpoint=service.endpoint;timeout=service.timeout;service=service.service;}
|
|
this.id=uuid();this.service=service;this.timeout=timeout;this.endpoint=endpoint||this.endpoint;if(!this.endpoint)throw error(1);this.setPort(this.endpoint);this.pending=new Set();this.receiver=message.receiver(this.id).on('_push',this.onPush.bind(this));debug('initialized',service);}
|
|
Client.prototype={connect(){debug('connect');if(this.connected)return this.connected;debug('connecting...',this.service);var mc=new MessageChannel();this.channel=mc.port1;this.channel.start();var data={clientId:this.id,service:this.service,originEnv:env};return this.connected=this.message('_connect').set('transfer',[mc.port2]).set('data',data).listen(mc.port1).send().then(response=>{debug('connected',response);var usingChannel=response.event.target===this.channel;if(usingChannel)this.setPort(this.channel);else{this.channel.close();delete this.channel;}
|
|
this.receiver.listen(this.port);}).catch(err=>{var msg=err&&err.message;if(msg=='timeout'){err=error(2,this.service);console.error(err.message);}
|
|
throw err;});},disconnect(options){if(!this.connected)return Promise.resolve();debug('disconnecting ...');var config={noRespond:options&&options.noRespond,data:this.id};this.cancelPending();return this.message('_disconnect').set(config).send().then(()=>this.onDisconnected());},method(name,...args){return this.connect().then(()=>{debug('method',name);return this.message('_method').set({recipient:this.service,data:{name:name,args:args}}).send();}).then(response=>response.value).catch(err=>{var msg=err&&err.message;if(msg=='timeout'){err=error(3,name);console.error(err.message);}
|
|
throw err;});},plugin(fn){fn(this,{'Emitter':Emitter,'uuid':uuid});return this;},message(type){debug('create message',type);var msg=message(type).set('port',this.port).set('timeout',this.timeout).on('response',()=>this.pending.delete(msg)).on('cancel',()=>this.pending.delete(msg));this.pending.add(msg);return msg;},cancelPending(){debug('cancel pending');this.pending.forEach(msg=>{msg.cancel();});this.pending.clear();},pendingResponded(){var responded=[];this.pending.forEach(msg=>responded.push(msg.responded));return Promise.all(responded);},onPush(message){debug('on push',message.data);this._emit(message.data.type,message.data.data);},onDisconnected(){delete this.connected;this.pendingResponded().then(()=>{debug('disconnected');if(this.channel)this.channel.close();this._emit('disconnected');});},setPort(endpoint){debug('set port');this.port=createPort(endpoint);},destroy:function(){return this.disconnect().then(()=>{if(this.destroyed)return;debug('destroy');this.destroyed=true;this.receiver.destroy();this._off();this.port=this.endpoint=this.receiver=null;});},_on:Emitter.prototype.on,_off:Emitter.prototype.off,_emit:Emitter.prototype.emit};Client.prototype.on=function(name,fn){this.connect().then(()=>{debug('bind on',name);Emitter.prototype.on.call(this,name,fn);this.message('_on').set('noRespond',true).set('data',{name:name,clientId:this.id}).send(this.port);});return this;};Client.prototype.off=function(name,fn){this.connect().then(()=>{Emitter.prototype.off.call(this,name,fn);this.message('_off').set('noRespond',true).set('data',{name:name,clientId:this.id}).send(this.port);});return this;};function error(id,...args){var help='Either the target endpoint is not alive or the Service is not `.listen()`ing.';return new Error({1:'an endpoint must be defined',2:`Unable to establish a connection with "${args[0]}". ${help}`,3:`Method "${args[0]}" didn't get a response. ${help}`}[id]);}},{"./emitter":3,"./message":4,"./message/port-adaptors":5,"./utils":6}],3:[function(require,module,exports){'use strict';module.exports=Emitter;var debug=0?console.log.bind(console,'[Emitter]'):()=>{};function Emitter(host){if(host)return Object.assign(host,Emitter.prototype);}
|
|
Emitter.prototype={on:function(type,callback){debug('on',type,callback);if(!this._callbacks)this._callbacks={};if(!this._callbacks[type])this._callbacks[type]=[];this._callbacks[type].push(callback);return this;},off:function(type,callback){debug('off',type,callback);if(this._callbacks){switch(arguments.length){case 0:this._callbacks={};break;case 1:delete this._callbacks[type];break;default:var typeListeners=this._callbacks[type];if(!typeListeners)return;var i=typeListeners.indexOf(callback);if(~i)typeListeners.splice(i,1);}}
|
|
return this;},emit:function(type,data){debug('emit',type,data);if(this._callbacks){var fns=this._callbacks[type]||[];fns=fns.concat(this._callbacks['*']||[]);for(var i=0;i<fns.length;i++)fns[i].call(this,data,type);}
|
|
return this;}};var p=Emitter.prototype;p['off']=p.off;p['on']=p.on;},{}],4:[function(require,module,exports){'use strict';var createPort=require('./port-adaptors');var Emitter=require('../emitter');var utils=require('../utils');var defer=utils.deferred;var uuid=utils.uuid;exports=module.exports=type=>new Message(type);exports.receiver=(id,n)=>new Receiver(id,n);exports.Receiver=Receiver;exports.Message=Message;var debug={0:()=>{},1:arg=>performance.mark(`[${self.constructor.name}][Message] - ${arg}`),2:(arg1,...args)=>{var type=`[${self.constructor.name}][${location.pathname}]`;console.log(`[Message]${type} - "${arg1}"`,...args);}}[0];var TIMEOUT=1000;function Message(type){this.cancelled=false;this.listeners=[];this.deferred=defer();this.onMessage=this.onMessage.bind(this);this.onTimeout=this.onTimeout.bind(this);if(typeof type==='object')this.setupInbound(type);else this.setupOutbound(type);debug('initialized',type);}
|
|
Message.prototype={setupOutbound(type){this.id=uuid();this.type=type;this.sent=false;this.recipient='*';},setupInbound(e){debug('inbound');this.hasResponded=false;this.setSourcePort(e.source||e.target);this.event=e;Object.assign(this,e.data);},setSourcePort(endpoint){debug('set source',endpoint.constructor.name);this.sourcePort=createPort(endpoint,{ready:true});return this;},set(key,value){debug('set',key,value);if(typeof key=='object')Object.assign(this,key);else this[key]=value;return this;},serialize(){return{id:this.id,type:this.type,data:this.data,recipient:this.recipient,noRespond:this.noRespond};},preventDefault(){debug('prevent default');this.defaultPrevented=true;},send(endpoint){debug('send',this.type);if(this.sent)throw error(1);var serialized=this.serialize();var expectsResponse=!this.noRespond;this.port=endpoint?createPort(endpoint):this.port;if(!this.port)throw error(3);if(expectsResponse){this.listen(this.port);this.setResponseTimeout();}else this.deferred.resolve();this.port.postMessage(serialized,this.getTransfer());debug('sent',serialized);return this.deferred.promise;},setResponseTimeout(){if(this.timeout===false)return;var ms=this.timeout||TIMEOUT;this._timer=setTimeout(this.onTimeout,ms);},clearResponseTimeout(){clearTimeout(this._timer);},getTransfer(){return this.transfer||this.event&&this.event.ports;},onMessage(e){var valid=!!e.data.response&&e.data.id===this.id&&!this.cancelled;if(valid)this.onResponse(e);},onTimeout(){debug('response timeout',this.type);if(!this.silentTimeout)this.deferred.reject(error(4));this.teardown();},listen(thing){debug('add response listener',thing);var port=createPort(thing);port.addListener(this.onMessage);this.listeners.push(port);return this;},unlisten(){debug('remove response listeners');this.listeners.forEach(port=>port.removeListener(this.onMessage));this.listeners=[];},cancel(){this.teardown();this.cancelled=true;this.emit('cancel');},teardown(){this.clearResponseTimeout();this.unlisten();},respond(result){debug('respond',result);if(this.hasResponded)throw error(2);if(!this.sourcePort)return;if(this.noRespond)return;var self=this;this.hasResponded=true;if(result instanceof Error)reject(result);Promise.resolve(result).then(resolve,reject).catch(reject);function resolve(value){debug('resolve',value);respond({type:'resolve',value:value});}
|
|
function reject(err){var msg=err&&err.message||err;debug('reject',msg);respond({type:'reject',value:msg});}
|
|
function respond(response){self.response=response;self.sourcePort.postMessage({id:self.id,response:response},self.transfer);debug('responded with:',response);}},forward(endpoint){debug('forward');return this.set('silentTimeout',true).send(endpoint).then(result=>this.respond(result.value));},onResponse(e){debug('on response',e.data);var response=e.data.response;var type=response.type;var value=type=='reject'?response.value:response;response.event=e;this.response=response;this.teardown();this.deferred[this.response.type](value);this.emit('response',response);}};Emitter(Message.prototype);function Receiver(name){this.name=name;this.ports=new Set();this.onMessage=this.onMessage.bind(this);this['listen']=this['listen'].bind(this);this['unlisten']=this['unlisten'].bind(this);debug('receiver initialized',name);}
|
|
Receiver.prototype={listen(thing){debug('listen');var _port=createPort(thing||self,{receiver:true});if(this.ports.has(_port))return;_port.addListener(this.onMessage,this.listen);this.ports.add(_port);return this;},unlisten(){debug('unlisten');this.ports.forEach(port=>{port.removeListener(this.onMessage,this.unlisten);});},onMessage(e){if(!e.data.id)return;if(!e.data.type)return;if(!this.isRecipient(e.data.recipient))return;debug('receiver on message',e.data);var message=new Message(e);this.emit('message',message);if(message.defaultPrevented)return;try{this.emit(message.type,message);}
|
|
catch(e){message.respond(e);throw e;}},isRecipient(recipient){return recipient==this.name||recipient=='*'||this.name=='*';},destroy:function(){this.unlisten();delete this.name;return this;}};Emitter(Receiver.prototype);function error(id,...args){return new Error({1:'.send() can only be called once',2:'response already sent for this message',3:'a port must be defined',4:'timeout'}[id]);}},{"../emitter":3,"../utils":6,"./port-adaptors":5}],5:[function(require,module,exports){'use strict';var deferred=require('../utils').deferred;const MSG='message';var debug=0?function(arg1,...args){var type=`[${self.constructor.name}][${location.pathname}]`;console.log(`[PortAdaptor]${type} - "${arg1}"`,...args);}:()=>{};module.exports=function create(target,options){if(!target)throw error(1);if(isEndpoint(target))return target;var type=target.constructor.name;var CustomAdaptor=adaptors[type];debug('creating port adaptor for',type);if(CustomAdaptor)return CustomAdaptor(target,options);return new PortAdaptor(target,options);};function PortAdaptor(target){debug('PortAdaptor');this.target=target;}
|
|
var PortAdaptorProto=PortAdaptor.prototype={constructor:PortAdaptor,addListener(callback){on(this.target,MSG,callback);},removeListener(callback){off(this.target,MSG,callback);},postMessage(data,transfer){this.target.postMessage(data,transfer);}};var adaptors={'HTMLIFrameElement':function(iframe){debug('HTMLIFrameElement');var ready=windowReady(iframe);return{addListener(callback,listen){on(window,MSG,callback);},removeListener(callback,listen){off(window,MSG,callback);},postMessage(data,transfer){ready.then(()=>postMessageSync(iframe.contentWindow,data,transfer));}};},'BroadcastChannel':function(channel,options){debug('BroadcastChannel',channel.name);var receiver=options&&options.receiver;var ready=options&&options.ready;var sendReady=()=>{channel.postMessage('ready');debug('sent ready');};ready=ready||receiver?Promise.resolve():setupSender();if(receiver){sendReady();on(channel,MSG,e=>{if(e.data!='ready?')return;sendReady();});}
|
|
function setupSender(){debug('setup sender');var promise=deferred();channel.postMessage('ready?');on(channel,MSG,function fn(e){if(e.data!='ready')return;off(channel,MSG,fn);debug('BroadcastChannel: ready');promise.resolve();});return promise.promise;}
|
|
return{target:channel,addListener:PortAdaptorProto.addListener,removeListener:PortAdaptorProto.removeListener,postMessage(data,transfer){ready.then(()=>channel.postMessage(data,transfer));}};},'Window':function(win,options){debug('Window');var ready=options&&options.ready||win===parent||win===self;ready=ready?Promise.resolve():windowReady(win);return{addListener(callback,listen){on(window,MSG,callback);},removeListener(callback,listen){off(window,MSG,callback);},postMessage(data,transfer){ready.then(()=>postMessageSync(win,data,transfer));}};},'SharedWorker':function(worker){worker.port.start();return new PortAdaptor(worker.port);},'SharedWorkerGlobalScope':function(){var ports=[];return{postMessage(){},addListener(callback,listen){this.onconnect=e=>{var port=e.ports[0];ports.push(port);port.start();listen(port);};on(self,'connect',this.onconnect);},removeListener(callback,unlisten){off(self,'connect',this.onconnect);ports.forEach(port=>{port.close();unlisten(port);});}};}};var windowReady=(function(){if(typeof window=='undefined')return;var parent=window.opener||window.parent;var domReady='DOMContentLoaded';var windows=new WeakSet();if(parent!=self){on(window,domReady,function fn(){off(window,domReady,fn);postMessageSync(parent,'load');});}
|
|
on(self,'message',e=>e.data=='load'&&windows.add(e.source));return target=>{var win=target.contentWindow||target;if(windows.has(win))return Promise.resolve();if(win==window.parent)return Promise.resolve();var def=deferred();debug('waiting for Window to be ready ...');on(window,'message',function fn(e){if(e.data=='load'&&e.source==win){debug('Window ready');off(window,'message',fn);def.resolve();}});return def.promise;};})();function isEndpoint(thing){return!!(thing&&thing.addListener);}
|
|
function on(target,name,fn){target.addEventListener(name,fn);}
|
|
function off(target,name,fn){target.removeEventListener(name,fn);}
|
|
function postMessageSync(win,data,transfer){try{void win.document;}catch(_){win.postMessage(data,location.origin,transfer||[]);return;}var event={data:data,source:self};if(transfer)event.ports=transfer;win.dispatchEvent(new MessageEvent('message',event));}
|
|
function error(id){return new Error({1:'target is undefined'}[id]);}},{"../utils":6}],6:[function(require,module,exports){'use strict';exports.uuid=function(){return'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g,function(c){var r=Math.random()*16|0,v=c=='x'?r:(r&0x3|0x8);return v.toString(16);});};exports.deferred=function(){var promise={};promise.promise=new Promise((resolve,reject)=>{promise.resolve=resolve;promise.reject=reject;});return promise;};},{}]},{},[1])(1)}); |