!((define)=>{define((require,exports,module)=>{ /** * Mini Logger * * @type {Function} */ var debug = 0 ? function(arg1, ...args) { var type = `[${self.constructor.name}][${location.pathname}]`; console.log(`[ServiceStream]${type} - "${arg1}"`, ...args); } : () => {}; module.exports = function(service) { debug('attaching plugin'); service .method('_stream', onStream) .method('_streamcancel', onStreamCancel); service._streamHandlers = {}; service._activeStreams = []; service.stream = function(name, fn) { debug('register stream', name); this._streamHandlers[name] = fn; return this; }; function onStream(name, id, clientId, args) { debug('on stream open', name); var e = { preventDefault: () => e.defaultPrevented = true, arguments: arguments }; // Allow other plugins to override default behaviour service.emit('before-stream', e); if (e.defaultPrevented) return; var fn = service._streamHandlers[name]; if (!fn) throw error(1, name); var stream = new ServiceStream(id, service, clientId); service._activeStreams[id] = stream; // Always pass stream object as first // argument to simplify the process fn.apply(service, [stream].concat(args)); } function onStreamCancel(id, reason) { debug('stream cancel'); var stream = service._activeStreams[id]; delete service._activeStreams[id]; return stream.cancel(reason); } }; /** * Writable Stream instance passed to the * `service.stream` implementation * * @param {Object} options * @param {String} options.id Stream ID used to sync client and service streams * @param {BroadcastChannel} options.channel Channel used to postMessage * @param {String} options.serviceId ID of the service * @param {String} options.clientId ID of client that should receive message */ function ServiceStream(streamId, service, clientId) { this.id = streamId; this.service = service; this.clientId = clientId; this.writable = true; debug('initialized'); } /** * Prototype assigned to variable * to improve compression. * * @type {Object} */ var ServiceStreamPrototype = ServiceStream.prototype; /** * Services that allows clients to * cancel the operation before it's * complete should override the * `stream.cancel` method. * * @param {*} [reason] Data sent from client about the cancellation * @returns {(Promise|*)} */ ServiceStreamPrototype.cancel = function(reason) { var err = new TypeError('service should implement stream.cancel()'); return Promise.reject(err); }; /** * Signal to client that action was * aborted during the process, this * should be used as a way to * communicate errors. * * @param {*} [data] Reason of failure * @returns {Promise} * @public */ ServiceStreamPrototype.abort = function(data) { debug('abort', data); this._post('abort', data); this.writable = false; }; /** * Sends a chunk of data to the client. * * @param {*} data Chunk of data to be sent to client. * @returns {Promise} * @public */ ServiceStreamPrototype.write = function(data) { debug('write', data); this._post('write', data); }; /** * Closes the stream, signals that * action was completed with success. * * According to whatwg streams spec, * WritableStream#close() doesn't send data. * * @returns {Promise} */ ServiceStreamPrototype.close = function() { debug('close'); this._post('close'); this.writable = false; }; /** * Validate the current state and * call cancel on the target stream. * * Called by the Service when client * sends a 'streamcancel' message. * * @param {*} [reason] Reason for cancelation sent by the client * @returns {Promise} * @private */ ServiceStreamPrototype._cancel = function(reason) { debug('cancel', reason); return this.cancel(reason) .then(result => { this.writable = false; return result; }); }; /** * Validate the current state and post message to client. * * @param {String} type 'write', 'abort' or 'close' * @param {String} state 'writable', 'aborted' or 'closed' * @param {*} [data] Data to be sent to the client * @returns {Promise} * @private */ ServiceStreamPrototype._post = function(type, data) { debug('post', type, data, this.writable); if (!this.writable) return Promise.reject(); this.service.broadcast('streamevent', { streamId: this.id, type: type, data: data }, [this.clientId]); }; /** * Create new `Error` from registery. * * @param {Number} id Error Id * @return {Error} * @private */ function error(id) { var args = [].slice.call(arguments, 1); return new Error({ 1: 'stream "' + args[0] + '" doesn\'t exist' }[id]); } });})((typeof define)[0]=='f'&&define.amd?define:((n,w)=>{return(typeof module)[0]=='o'?c=>{c(require,exports,module);}:(c)=>{var m={exports:{}}; c(n=>w[n],m.exports,m);w[n]=m.exports;};})('streamService',this));