UNPKG

data-transport

Version:
1,082 lines (1,049 loc) 74.2 kB
var listenerKey = Symbol('listener'); var listenKey = Symbol('listen'); var senderKey = Symbol('sender'); var requestsMapKey = Symbol('requestsMap'); var listensMapKey = Symbol('listensMap'); var serializerKey = Symbol('serializer'); var logKey = Symbol('log'); var verboseKey = Symbol('verbose'); var originalListensMapKey = Symbol('originalListensMap'); var callbackKey = Symbol('callback'); var timeoutKey = Symbol('timeout'); var prefixKey = Symbol('prefix'); var produceKey = Symbol('produce'); var beforeEmitKey = Symbol('beforeEmit'); var beforeEmitResolveKey = Symbol('beforeEmitResolve'); var transportKey = '__DATA_TRANSPORT_UUID__'; var transportType = { request: 'request', response: 'response', }; /****************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */ var extendStatics = function(d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; function __extends(d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); } var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; function __rest(s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; } function __awaiter(thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } function __generator(thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype); return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } } function __values(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); } function __read(o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; } function __spreadArray(to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); } typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { var e = new Error(message); return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; }; var listen = function (target, key, descriptor) { var _a; var fn = descriptor.value; { if (typeof fn !== 'function') { console.warn("The decorator '@listen' can only decorate methods, '".concat(key, "' is NOT a methods.")); return descriptor; } } target[originalListensMapKey] = (_a = target[originalListensMapKey]) !== null && _a !== void 0 ? _a : new Map(); target[originalListensMapKey].set(key, fn); return __assign(__assign({}, descriptor), { value: function () { { throw new Error("The method '".concat(key, "' is a listen function that can NOT be actively called.")); } } }); }; // Unique ID creation requires a high quality random # generator. In the browser we therefore // require the crypto API and do not support built-in fallback to lower quality random number // generators (like Math.random()). let getRandomValues; const rnds8 = new Uint8Array(16); function rng() { // lazy load so that environments that need to polyfill have a chance to do so if (!getRandomValues) { // getRandomValues needs to be invoked in a context where "this" is a Crypto implementation. getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto); if (!getRandomValues) { throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported'); } } return getRandomValues(rnds8); } /** * Convert array of 16 byte values to UUID string format of the form: * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX */ const byteToHex = []; for (let i = 0; i < 256; ++i) { byteToHex.push((i + 0x100).toString(16).slice(1)); } function unsafeStringify(arr, offset = 0) { // Note: Be careful editing this code! It's been tuned for performance // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434 return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase(); } const randomUUID = typeof crypto !== 'undefined' && crypto.randomUUID && crypto.randomUUID.bind(crypto); var native = { randomUUID }; function v4(options, buf, offset) { if (native.randomUUID && true && !options) { return native.randomUUID(); } options = options || {}; const rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved` rnds[6] = rnds[6] & 0x0f | 0x40; rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided return unsafeStringify(rnds); } var detectSafari = function () { return /^((?!chrome|android).)*safari/i.test(navigator.userAgent); }; var generateId = function () { return v4({ // In nodejs, crypto.getRandomValues() not supported. // workaround: https://github.com/uuidjs/uuid/issues/375 rng: function () { var randomNumbers = new Array(16); var r; for (var i = 0; i < 16; i++) { if ((i & 0x03) === 0) r = Math.random() * 0x100000000; randomNumbers[i] = (r >>> ((i & 0x03) << 3)) & 0xff; } return randomNumbers; }, }); }; var _a; var DEFAULT_TIMEOUT = 60 * 1000; var DEFAULT_RESPOND = true; var DEFAULT_SILENT = false; var DEFAULT_PREFIX = 'DataTransport'; var getAction = function (prefix, name) { return "".concat(prefix, "-").concat(name.toString()); }; var getListenName = function (prefix, action) { return action.replace(new RegExp("^".concat(prefix, "-")), ''); }; /** * Create a base transport */ var Transport = /** @class */ (function () { function Transport(_b) { var listener = _b.listener, sender = _b.sender, _c = _b.timeout, timeout = _c === void 0 ? DEFAULT_TIMEOUT : _c, _d = _b.verbose, verbose = _d === void 0 ? false : _d, _e = _b.prefix, prefix = _e === void 0 ? DEFAULT_PREFIX : _e, _f = _b.listenKeys, listenKeys = _f === void 0 ? [] : _f, _g = _b.checkListen, checkListen = _g === void 0 ? true : _g, serializer = _b.serializer, logger = _b.logger; var _this = this; var _h, _j; this[_a] = new Map(); this.id = generateId(); this[listensMapKey] = (_h = this[listensMapKey]) !== null && _h !== void 0 ? _h : new Map(); this[originalListensMapKey] = (_j = this[originalListensMapKey]) !== null && _j !== void 0 ? _j : new Map(); this[listenerKey] = listener.bind(this); this[senderKey] = sender.bind(this); this[timeoutKey] = timeout; this[prefixKey] = prefix; this[serializerKey] = serializer; this[verboseKey] = verbose; this[logKey] = logger; new Set(listenKeys).forEach(function (key) { var _b; var fn = _this[key]; { if (typeof fn !== 'function') { console.warn("'".concat(key, "' is NOT a methods or function.")); } } _this[originalListensMapKey].set(key, fn); Object.assign(_this, (_b = {}, _b[key] = function () { { throw new Error("The method '".concat(key, "' is a listen function that can NOT be actively called.")); } }, _b)); }); this[originalListensMapKey].forEach(function (value, name) { _this[produceKey](name, value); }); this[listenKey] = function (options) { var _b, _c; if (_this[verboseKey]) { if (typeof _this[logKey] === 'function' && options) { _this[logKey](options); } else { console.info('DataTransport Receive: ', options); } } if (options === null || options === void 0 ? void 0 : options[transportKey]) { var listenName = getListenName(_this[prefixKey], options.action); var hasListen = typeof _this[listenName] === 'function'; if (options.type === transportType.response) { var resolve = _this[requestsMapKey].get(options[transportKey]); if (resolve) { var response = options.response; resolve(typeof response === 'string' && ((_b = _this[serializerKey]) === null || _b === void 0 ? void 0 : _b.parse) ? _this[serializerKey].parse(response) : response); } else if (hasListen) { if (checkListen) { console.warn("The type '".concat(options.action, "' event '").concat(options[transportKey], "' has been resolved. Please check for a duplicate response.")); } } } else if (options.type === transportType.request) { var respond = _this[listensMapKey].get(options.action); if (typeof respond === 'function') { var request = options.request; respond(typeof request === 'string' && ((_c = _this[serializerKey]) === null || _c === void 0 ? void 0 : _c.parse) ? _this[serializerKey].parse(request) : request, __assign(__assign({}, options), { transportId: options[transportKey], hasRespond: options.hasRespond })); } else if (hasListen) { if (checkListen) { console.error("The listen method or function '".concat(listenName, "' is NOT decorated by decorator '@listen' or be added 'listenKeys' list.")); } } } } }; var dispose = this[listenerKey](this[listenKey]); this.dispose = function () { if (typeof dispose === 'function') { _this[requestsMapKey].clear(); _this[listensMapKey].clear(); _this[originalListensMapKey].clear(); return dispose(); } else { console.warn("The return value of the the '".concat(_this.constructor.name, "' transport's listener should be a 'dispose' function for removing the listener")); } }; } Transport.prototype[(_a = requestsMapKey, produceKey)] = function (name, fn) { var _this = this; // https://github.com/microsoft/TypeScript/issues/40465 var action = getAction(this[prefixKey], name); this[listensMapKey].set(action, function (request, _b) { return __awaiter(_this, void 0, void 0, function () { var response, data; var _c; var _d; var hasRespond = _b.hasRespond, transportId = _b.transportId; _b.request; var args = __rest(_b, ["hasRespond", "transportId", "request"]); return __generator(this, function (_e) { switch (_e.label) { case 0: if (!(typeof fn === 'function')) return [3 /*break*/, 2]; return [4 /*yield*/, fn.apply(this, request)]; case 1: response = _e.sent(); if (!hasRespond) return [2 /*return*/]; data = __assign(__assign({}, args), (_c = { action: action, response: (typeof response !== 'undefined' && ((_d = this[serializerKey]) === null || _d === void 0 ? void 0 : _d.stringify) ? this[serializerKey].stringify(response) : response), hasRespond: hasRespond }, _c[transportKey] = transportId, _c.type = transportType.response, _c.responseId = this.id, _c)); this[senderKey](data); return [3 /*break*/, 3]; case 2: throw new Error("The listener for event ".concat(name, " should be a function.")); case 3: return [2 /*return*/]; } }); }); }); }; /** * Listen an event that transport data. * * @param name A transport action as listen message data action type * @param fn A transport listener */ Transport.prototype.listen = function (name, fn) { var _this = this; if (typeof name === 'string') { if (this[originalListensMapKey].get(name)) { throw new Error("Failed to listen to the event \"".concat(name, "\", the event \"").concat(name, "\" is already listened to.")); } if (typeof fn === 'function') { this[originalListensMapKey].set(name, fn); this[produceKey](name, fn); } else { throw new Error("The listener for event ".concat(name, " should be a function.")); } } else { throw new Error("The event name \"".concat(name.toString(), "\" is not a string, it should be a string.")); } return function () { _this[originalListensMapKey].delete(name); var action = getAction(_this[prefixKey], name); _this[listensMapKey].delete(action); }; }; /** * Emit an event that transport data. * * @param emitOptions A option for the transport data * @param request A request data * * @returns Return a response for the request. */ Transport.prototype.emit = function (options) { var request = []; for (var _i = 1; _i < arguments.length; _i++) { request[_i - 1] = arguments[_i]; } return __awaiter(this, void 0, void 0, function () { var params, hasRespond, isSilent, timeout, name, transportId, action, rawRequestData, timeoutId, promise; var _b; var _this = this; var _c, _d, _e, _f, _g; return __generator(this, function (_h) { switch (_h.label) { case 0: params = typeof options === 'object' ? options : {}; hasRespond = (_c = params.respond) !== null && _c !== void 0 ? _c : DEFAULT_RESPOND; isSilent = (_d = params.silent) !== null && _d !== void 0 ? _d : DEFAULT_SILENT; timeout = (_e = params.timeout) !== null && _e !== void 0 ? _e : this[timeoutKey]; name = (_f = params.name) !== null && _f !== void 0 ? _f : options; transportId = generateId(); if ((!name || typeof name !== 'string')) { throw new Error("The event name should be a string, and it's required."); } action = getAction(this[prefixKey], name); rawRequestData = __assign(__assign({}, (params._extra ? { _extra: params._extra } : {})), (_b = { type: transportType.request, action: action, request: (typeof request !== 'undefined' && ((_g = this[serializerKey]) === null || _g === void 0 ? void 0 : _g.stringify) ? this[serializerKey].stringify(request) : request), hasRespond: hasRespond }, _b[transportKey] = transportId, _b.requestId = this.id, _b)); if (this[verboseKey]) { if (typeof this[logKey] === 'function') { this[logKey](rawRequestData); } else { console.info('DataTransport Send: ', rawRequestData); } } if (!!hasRespond) return [3 /*break*/, 3]; if (!(this[beforeEmitKey] && !params.skipBeforeEmit)) return [3 /*break*/, 2]; return [4 /*yield*/, this[beforeEmitKey]]; case 1: _h.sent(); _h.label = 2; case 2: this[senderKey](rawRequestData); return [2 /*return*/, Promise.resolve(undefined)]; case 3: promise = Promise.race([ new Promise(function (resolve) { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_b) { switch (_b.label) { case 0: if (!(this[beforeEmitKey] && !params.skipBeforeEmit)) return [3 /*break*/, 2]; return [4 /*yield*/, this[beforeEmitKey]]; case 1: _b.sent(); _b.label = 2; case 2: this[requestsMapKey].set(transportId, resolve); this[senderKey](rawRequestData); return [2 /*return*/]; } }); }); }), new Promise(function (_, reject) { timeoutId = setTimeout(function () { reject(); }, timeout); }), ]); return [2 /*return*/, promise .then(function (response) { // support Safari 10-11.1 clearTimeout(timeoutId); _this[requestsMapKey].delete(transportId); return response; }) .catch(function (error) { clearTimeout(timeoutId); _this[requestsMapKey].delete(transportId); if (typeof error === 'undefined') { if (isSilent) return; console.warn("The event '".concat(action, "' timed out for ").concat(timeout, " seconds..."), rawRequestData); } else { { throw error; } } })]; } }); }); }; return Transport; }()); var connectEventName$3 = 'iframe-connect'; var IFrameMainTransport = /** @class */ (function (_super) { __extends(IFrameMainTransport, _super); function IFrameMainTransport(_options) { var _this = this; var _a = _options.iframe, iframe = _a === void 0 ? document.querySelector('iframe') : _a, _b = _options.targetOrigin, targetOrigin = _b === void 0 ? '*' : _b, _c = _options.listener, listener = _c === void 0 ? function (callback) { var handler = function (_a) { var data = _a.data, source = _a.source; var contentWindow = iframe.contentWindow; if (contentWindow && contentWindow === source) { return callback(data); } }; window.addEventListener('message', handler); return function () { window.removeEventListener('message', handler); }; } : _c, _d = _options.sender, sender = _d === void 0 ? function (message) { if (iframe) { iframe.contentWindow.postMessage(message, targetOrigin); } else if (window.frames[0]) { window.frames[0].postMessage(message, targetOrigin); } else { console.error('The current page does not have any iframe elements'); } } : _d, skipConnectionCheck = _options.skipConnectionCheck, options = __rest(_options, ["iframe", "targetOrigin", "listener", "sender", "skipConnectionCheck"]); _this = _super.call(this, __assign(__assign({}, options), { listener: listener, sender: sender })) || this; if (!skipConnectionCheck) { var connect_1 = function () { _this.emit({ // @ts-ignore name: connectEventName$3, silent: true, skipBeforeEmit: true, }).then(function (connected) { if (connected) { _this[beforeEmitResolveKey](); } }); }; connect_1(); _this[beforeEmitKey] = new Promise(function (resolve) { _this[beforeEmitResolveKey] = resolve; }); // @ts-ignore _this.listen(connectEventName$3, function () { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) { this[beforeEmitResolveKey](); return [2 /*return*/, true]; }); }); }); // for iframe reload iframe === null || iframe === void 0 ? void 0 : iframe.addEventListener('load', function () { _this[beforeEmitKey] = new Promise(function (resolve) { _this[beforeEmitResolveKey] = resolve; }); connect_1(); }); } return _this; } return IFrameMainTransport; }(Transport)); var IFrameInternalTransport = /** @class */ (function (_super) { __extends(IFrameInternalTransport, _super); function IFrameInternalTransport(_options) { if (_options === void 0) { _options = {}; } var _this = this; var _a = _options.targetOrigin, targetOrigin = _a === void 0 ? '*' : _a, _b = _options.listener, listener = _b === void 0 ? function (callback) { var handler = function (_a) { var data = _a.data; return callback(data); }; window.addEventListener('message', handler); return function () { window.removeEventListener('message', handler); }; } : _b, _c = _options.sender, sender = _c === void 0 ? function (message) { return window.parent.postMessage(message, targetOrigin); } : _c, skipConnectionCheck = _options.skipConnectionCheck, options = __rest(_options, ["targetOrigin", "listener", "sender", "skipConnectionCheck"]); _this = _super.call(this, __assign(__assign({}, options), { listener: listener, sender: sender })) || this; if (!skipConnectionCheck) { _this.emit({ // @ts-ignore name: connectEventName$3, silent: true, }).then(function (connected) { if (connected) { _this[beforeEmitResolveKey](); } }); _this[beforeEmitKey] = new Promise(function (resolve) { _this[beforeEmitResolveKey] = resolve; }); // @ts-ignore _this.listen(connectEventName$3, function () { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) { this[beforeEmitResolveKey](); return [2 /*return*/, true]; }); }); }); } return _this; } return IFrameInternalTransport; }(Transport)); var IFrameTransport = { Main: IFrameMainTransport, IFrame: IFrameInternalTransport, }; var connectEventName$2 = 'worker-connect'; var WorkerMainTransport = /** @class */ (function (_super) { __extends(WorkerMainTransport, _super); function WorkerMainTransport(_options) { var _this = this; var worker = _options.worker, _a = _options.listener, listener = _a === void 0 ? function (callback) { var handler = function (_a) { var data = _a.data; callback(data); }; worker.addEventListener('message', handler); return function () { worker.removeEventListener('message', handler); }; } : _a, _b = _options.sender, sender = _b === void 0 ? function (message) { var _a; var transfer = (_a = message.transfer) !== null && _a !== void 0 ? _a : []; delete message.transfer; worker.postMessage(message, transfer); } : _b, options = __rest(_options, ["worker", "listener", "sender"]); _this = _super.call(this, __assign(__assign({}, options), { listener: listener, sender: sender })) || this; _this._connected = false; _this._handleConnectCallbacks = function () { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) { if (this._connected) { return [2 /*return*/]; } this._connected = true; this._onConnectCallback.forEach(function (callback) { callback(); }); this._onConnectCallback.clear(); return [2 /*return*/]; }); }); }; _this._onConnectCallback = new Set(); _this.emit({ // @ts-ignore name: connectEventName$2, respond: true, silent: true, }).then(_this._handleConnectCallbacks); // @ts-ignore _this.listen(connectEventName$2, _this._handleConnectCallbacks); return _this; } WorkerMainTransport.prototype.onConnect = function (callback) { var _this = this; if (this._connected) { return callback(); } this._onConnectCallback.add(callback); return function () { _this._onConnectCallback.delete(callback); }; }; return WorkerMainTransport; }(Transport)); var WorkerInternalTransport = /** @class */ (function (_super) { __extends(WorkerInternalTransport, _super); function WorkerInternalTransport(_options) { if (_options === void 0) { _options = {}; } var _this = this; var _a = _options.listener, listener = _a === void 0 ? function (callback) { var handler = (function (_a) { var data = _a.data; callback(data); }); self.addEventListener('message', handler); return function () { self.removeEventListener('message', handler); }; } : _a, _b = _options.sender, sender = _b === void 0 ? function (message) { var _a; var transfer = (_a = message.transfer) !== null && _a !== void 0 ? _a : []; delete message.transfer; postMessage(message, transfer); } : _b, options = __rest(_options, ["listener", "sender"]); _this = _super.call(this, __assign(__assign({}, options), { listener: listener, sender: sender })) || this; _this._handleConnectCallbacks = function () { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) { if (this._connected) { return [2 /*return*/]; } this._connected = true; this._onConnectCallback.forEach(function (callback) { callback(); }); this._onConnectCallback.clear(); return [2 /*return*/]; }); }); }; _this._connected = false; _this._onConnectCallback = new Set(); _this.emit({ // @ts-ignore name: connectEventName$2, respond: true, silent: true, }).then(_this._handleConnectCallbacks); // @ts-ignore _this.listen(connectEventName$2, _this._handleConnectCallbacks); return _this; } WorkerInternalTransport.prototype.onConnect = function (callback) { var _this = this; if (this._connected) { return callback(); } this._onConnectCallback.add(callback); return function () { _this._onConnectCallback.delete(callback); }; }; return WorkerInternalTransport; }(Transport)); var WorkerTransport = { Main: WorkerMainTransport, Worker: WorkerInternalTransport, }; var connectEventName$1 = 'sharedworker-connect'; var disconnectEventName = 'sharedworker-disconnect'; var SharedWorkerClientTransport = /** @class */ (function (_super) { __extends(SharedWorkerClientTransport, _super); function SharedWorkerClientTransport(_options) { var _this = this; var worker = _options.worker, _a = _options.listener, listener = _a === void 0 ? function (callback) { var handler = function (_a) { var data = _a.data; callback(data); }; worker.port.addEventListener('message', handler); worker.port.start(); return function () { worker.port.removeEventListener('message', handler); }; } : _a, _b = _options.sender, sender = _b === void 0 ? function (message) { var _a; var transfer = (_a = message.transfer) !== null && _a !== void 0 ? _a : []; delete message.transfer; worker.port.postMessage(message, transfer); } : _b, options = __rest(_options, ["worker", "listener", "sender"]); _this = _super.call(this, __assign(__assign({}, options), { listener: listener, sender: sender })) || this; _this._connected = false; _this._onConnectCallback = new Set(); // do not use `unload` event // https://developer.chrome.com/docs/web-platform/deprecating-unload window.addEventListener('pagehide', function () { // @ts-ignore _this.emit({ name: disconnectEventName, respond: false }, _this.id); }); // @ts-ignore _this.listen(connectEventName$1, function () { return __awaiter(_this, void 0, void 0, function () { var _this = this; return __generator(this, function (_a) { Promise.resolve().then(function () { _this._handleConnect(); }); return [2 /*return*/, this.id]; }); }); }); // ensure the connect event is sent when the client connect to the worker // @ts-ignore _this.emit({ name: connectEventName$1, respond: false, silent: true }); return _this; } SharedWorkerClientTransport.prototype._handleConnect = function () { if (this._connected) return; this._connected = true; this._onConnectCallback.forEach(function (callback) { callback(); }); }; SharedWorkerClientTransport.prototype.onConnect = function (callback) { var _this = this; this._onConnectCallback.add(callback); return function () { _this._onConnectCallback.delete(callback); }; }; return SharedWorkerClientTransport; }(Transport)); var SharedWorkerInternalTransport = /** @class */ (function (_super) { __extends(SharedWorkerInternalTransport, _super); function SharedWorkerInternalTransport(_options) { if (_options === void 0) { _options = {}; } var _this = this; var _a = _options.listener, listener = _a === void 0 ? function (callback) { var _this = this; this[callbackKey] = callback; return function () { _this.ports.forEach(function (port) { port._handler && port.removeEventListener('message', port._handler); delete port._handler; }); self.close(); }; } : _a, _b = _options.sender, sender = _b === void 0 ? function (message) { var _a, _b; var transfer = (_a = message.transfer) !== null && _a !== void 0 ? _a : []; delete message.transfer; var port = (_b = message._extra) === null || _b === void 0 ? void 0 : _b._port; // pick a client port for sender. if (port) { delete message._extra._port; port.postMessage(message, transfer); } else if (message.type === 'response' && // @ts-ignore _this.ports.has(message.requestId)) { // @ts-ignore var port_1 = _this.ports.get(message.requestId); port_1.postMessage(message, transfer); } else { _this.ports.forEach(function (port) { try { port.postMessage(message, transfer); } catch (error) { console.error(error); } }); _this.tempPorts.forEach(function (port) { try { port.postMessage(message, transfer); } catch (error) { console.error(error); } }); } } : _b, options = __rest(_options, ["listener", "sender"]); _this = _super.call(this, __assign(__assign({}, options), { listener: listener, sender: sender })) || this; _this.ports = new Map(); _this.tempPorts = new Set(); _this._onConnectCallback = new Set(); _this._onDisconnectCallback = new Set(); var disconnectAction = getAction(_this[prefixKey], disconnectEventName); var connectEvent = getAction(_this[prefixKey], connectEventName$1); self.addEventListener('connect', function (e) { return __awaiter(_this, void 0, void 0, function () { var port, id, err_1; var _this = this; return __generator(this, function (_a) { switch (_a.label) { case 0: port = e.ports[0]; port._handler = function (_a) { var _b; var data = _a.data; if (data.hasRespond) { data._extra = (_b = data._extra) !== null && _b !== void 0 ? _b : {}; data._extra._port = port; } if (data.action === disconnectAction && _this.ports.has(data.requestId)) { // clear port and clientId when the port's client is disconnected. _this.ports.delete(data.requestId); _this._onDisconnectCallback.forEach(function (callback) { callback(data.requestId); }); } if (data.type === 'request' && data.action === connectEvent) { _this.emit({ // @ts-ignore name: connectEventName$1, _extra: { _port: port }, silent: true, respond: false, }); _this._handleConnect(data.requestId, port); } _this[callbackKey](data); }; port.addEventListener('message', port._handler); port.start(); this.tempPorts.add(port); _a.label = 1; case 1: _a.trys.push([1, 3, , 4]); return [4 /*yield*/, this.emit({ // @ts-ignore name: connectEventName$1, _extra: { _port: port }, silent: true, })]; case 2: id = _a.sent(); this._handleConnect(id, port); return [3 /*break*/, 4]; case 3: err_1 = _a.sent(); this.tempPorts.delete(port); console.error(err_1); return [3 /*break*/, 4]; case 4: return [2 /*return*/]; } }); }); }); return _this; } SharedWorkerInternalTransport.prototype.onConnect = function (callback) { var _this = this; this._onConnectCallback.add(callback); return function () { _this._onConnectCallback.delete(callback); }; }; SharedWorkerInternalTransport.prototype._handleConnect = function (id, port) { if (id && !this.ports.has(id)) { this.ports.set(id, port); this.tempPorts.delete(port); this._onConnectCallback.forEach(function (callback) { callback(id); }); } }; SharedWorkerInternalTransport.prototype.onDisconnect = function (callback) { var _this = this; this._onDisconnectCallback.add(callback); return function () { _this._onDisconnectCallback.delete(callback); }; }; return SharedWorkerInternalTransport; }(Transport)); var SharedWorkerTransport = { Client: SharedWorkerClientTransport, Worker: SharedWorkerInternalTransport, }; var DEFAULT_USE_ON_SAFARI = true; var decode = function (data, useOnSafari) { try { return useOnSafari && detectSafari() ? JSON.stringify(data) : data; } catch (e) { console.error("Failed to stringify:", data); throw e; } }; var encode = function (data, useOnSafari) { try { return typeof data === 'string' && useOnSafari && detectSafari() ? JSON.parse(data) : data; } catch (e) { console.error("Failed to parse:", data); } return data; }; var ServiceWorkerClientTransport = /** @class */ (function (_super) { __extends(ServiceWorkerClientTransport, _super); function ServiceWorkerClientTransport(_options) { var worker = _options.worker, _a = _options.useOnSafari, useOnSafari = _a === void 0 ? DEFAULT_USE_ON_SAFARI : _a, _b = _options.listener, listener = _b === void 0 ? function (callback) { var handler = function (_a) { var data = _a.data; callback(encode(data, useOnSafari)); }; navigator.serviceWorker.addEventListener('message', handler); return function () { navigator.serviceWorker.removeEventListener('message', handler); }; } : _b, _c = _options.sender, sender = _c === void 0 ? function (message) { var _a; var transfer = (_a = message.transfer) !== null && _a !== void 0 ? _a : []; delete message.transfer; worker.postMessage(message, transfer); } : _c, options = __rest(_options, ["worker", "useOnSafari", "listener", "sender"]); return _super.call(this, __assign(__assign({}, options), { listener: listener, sender: sender })) || this; } return ServiceWorkerClientTransport; }(Transport)); var ServiceWorkerServiceTransport = /** @class */ (function (_super) { __extends(ServiceWorkerServiceTransport, _super); function ServiceWorkerServiceTransport(_options) { if (_options === void 0) { _options = {}; } var _this = this; var _a = _options.useOnSafari, useOnSafari = _a === void 0 ? DEFAULT_USE_ON_SAFARI : _a, _b = _options.listener, listener = _b === void 0 ? function (callback) { var handler = function (_a) { var data = _a.data, source = _a.source; data._clientId = source.id; callback(data); }; self.addEventListener('message', handler); return function () { return self.removeEventListener('message', handler); }; } : _b, _c = _options.sender, sender = _c === void 0 ? function (message) { return __awaiter(_this, void 0, void 0, function () { var transfer, data, client_1, client; var _a; return __generator(this, function (_b) { switch (_b.label) { case 0: transfer = message.transfer || []; delete message.transfer; data = decode(message, useOnSafari); if (!message._clientId) return [3 /*break*/, 2]; return [4 /*yield*/, self.clients.get(message._clientId)]; case 1: client_1 = _b.sent(); if (!client_1) { console.warn("The client \"".concat(message._clientId, "\" is closed.")); return [2 /*return*/]; } delete message._clientId; client_1.postMessage(data, transfer); return [2 /*return*/]; case 2: client = (_a = message._extra) === null || _a === void 0 ? void 0 : _a._client; if (client) { delete message._extra._client; client.postMessage(data, transfer); return [2 /*return*/]; } self.clients .matchAll() .then(function (all) { return all.map(function (client) { return client.postMessage(data, transfer); }); }); return [2 /*return*/]; } }); }); } : _c, options = __rest(_options, ["useOnSafari", "listener", "sender"]); _this = _super.call(this, __assign(__assign({}, options), { listener: listener, sender: sender })) || this; self.addEventListener('activate', function (event) { event.waitUntil(self.clients.claim()); }); return _this; } return ServiceWorkerServiceTransport; }(Transport)); var ServiceWorkerTransport = { Client: ServiceWorkerClientTransport, Service: ServiceWorkerServiceTransport, }; var defaultChannel$1 = '$$BroadcastChannel_Transport$$'; var BroadcastTransport = /** @class */ (function (_super) { __extends(BroadcastTransport, _super); function BroadcastTransport(_options) { if (_options === void 0) { _options = {}; } var _a = _options.channel, channel = _a === void 0 ? defaultChannel$1 : _a, _b = _options.broadcastChannel, broadcastChannel = _b === void 0 ? new BroadcastChannel(channel) : _b, _c = _options.listener, listener = _c === void 0 ? function (callback) { var handler = function (_a) { var data = _a.data; callback(data); }; broadcastChannel.addEventListener('message', handler); return function () { broadcastChannel.removeEventListener('message', handler); }; } : _c, _d = _options.sender, sender = _d === void 0 ? function (message) { return broadcastChannel.postMessage(message); } : _d, options = __rest(_options, ["channel",