diff --git a/.eslintrc.js b/.eslintrc.cjs similarity index 100% rename from .eslintrc.js rename to .eslintrc.cjs diff --git a/.github/workflows/release/versions.json b/.github/workflows/release/versions.json index 51884f614..dc23f3b23 100644 --- a/.github/workflows/release/versions.json +++ b/.github/workflows/release/versions.json @@ -20,7 +20,7 @@ "clearedSuffix": false } ], - "src/core/components/config.js": [ + "src/core/components/configuration.ts": [ { "pattern": "^\\s{2,}return '(v?(\\.?\\d+){2,}([a-zA-Z0-9-]+(\\.?\\d+)?)?)';$", "clearedPrefix": true, diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 003bf6d03..524b3c68a 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -11,6 +11,11 @@ defaults: shell: bash env: CXX: 'g++-4.8' + PAM_SUBSCRIBE_KEY: ${{ secrets.SDK_PAM_SUB_KEY }} + PAM_PUBLISH_KEY: ${{ secrets.SDK_PAM_PUB_KEY }} + PAM_SECRET_KEY: ${{ secrets.SDK_PAM_SEC_KEY }} + SUBSCRIBE_KEY: ${{ secrets.SDK_SUB_KEY }} + PUBLISH_KEY: ${{ secrets.SDK_PUB_KEY }} jobs: tests: @@ -19,10 +24,10 @@ jobs: strategy: fail-fast: true matrix: - node: [14, 16] + node: [18.18.0, 20] env: ['ci:node'] include: - - node: 16 + - node: 18.18.0 env: 'ci:web' steps: - name: Checkout repository @@ -53,4 +58,4 @@ jobs: needs: [tests] steps: - name: Tests summary - run: echo -e "\033[38;2;95;215;0m\033[1mAll tests successfully passed" \ No newline at end of file + run: echo -e "\033[38;2;95;215;0m\033[1mAll tests successfully passed" diff --git a/.mocharc.json b/.mocharc.json new file mode 100644 index 000000000..eb96a9a45 --- /dev/null +++ b/.mocharc.json @@ -0,0 +1,10 @@ +{ + "require": "tsx", + "spec": "test/**/*.test.ts", + "exclude": [ + "test/dist/*.{js,ts}", + "test/feature/*.{js,ts}" + ], + "timeout": 5000, + "reporter": "spec" +} \ No newline at end of file diff --git a/.mocharc.yml b/.mocharc.yml deleted file mode 100644 index 425715e05..000000000 --- a/.mocharc.yml +++ /dev/null @@ -1,7 +0,0 @@ -spec: test/**/*.test.{ts,js} -require: test/setup.js -exclude: - - test/dist/*.js - - test/feature/*.js -timeout: 5000 -reporter: spec diff --git a/.pubnub.yml b/.pubnub.yml index 488da2ef3..f86467bbe 100644 --- a/.pubnub.yml +++ b/.pubnub.yml @@ -1,5 +1,14 @@ --- changelog: + - date: 2024-04-22 + version: v8.0.0 + changes: + - type: feature + text: "Upgraded the network layer, replacing the `superagent` module with the `Fetch API` for browser integrations and node-fetch for `npm` integrations, ensuring enhanced performance and reliability." + - type: feature + text: "Added service worker ." + - type: feature + text: "Enhanced the subscribe feature with service worker support, improving user experience across multiple browser windows and tabs. The client interface rewritten with TypeScript, which gives an up-to-date interface." - date: 2024-04-18 version: v7.6.3 changes: @@ -958,7 +967,7 @@ supported-platforms: - 'Ubuntu 14.04 and up' - 'Windows 7 and up' version: 'Pubnub Javascript for Node' -version: '7.6.3' +version: '8.0.0' sdks: - full-name: PubNub Javascript SDK short-name: Javascript @@ -974,7 +983,7 @@ sdks: - distribution-type: source distribution-repository: GitHub release package-name: pubnub.js - location: https://github.com/pubnub/javascript/archive/refs/tags/v7.6.3.zip + location: https://github.com/pubnub/javascript/archive/refs/tags/v8.0.0.zip requires: - name: 'agentkeepalive' min-version: '3.5.2' @@ -1645,7 +1654,7 @@ sdks: - distribution-type: library distribution-repository: GitHub release package-name: pubnub.js - location: https://github.com/pubnub/javascript/releases/download/v7.6.3/pubnub.7.6.3.js + location: https://github.com/pubnub/javascript/releases/download/v8.0.0/pubnub.8.0.0.js requires: - name: 'agentkeepalive' min-version: '3.5.2' diff --git a/CHANGELOG.md b/CHANGELOG.md index c23b9c468..8da7ea74d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## v8.0.0 +April 22 2024 + +#### Added +- Upgraded the network layer, replacing the `superagent` module with the `Fetch API` for browser integrations and node-fetch for `npm` integrations, ensuring enhanced performance and reliability. +- Added service worker . +- Enhanced the subscribe feature with service worker support, improving user experience across multiple browser windows and tabs. The client interface rewritten with TypeScript, which gives an up-to-date interface. + ## v7.6.3 April 18 2024 diff --git a/README.md b/README.md index a4edab3ab..b9c208c6e 100644 --- a/README.md +++ b/README.md @@ -28,8 +28,8 @@ Watch [Getting Started with PubNub JS SDK](https://app.dashcam.io/replay/64ee0d2 npm install pubnub ``` * or download one of our builds from our CDN: - * https://cdn.pubnub.com/sdk/javascript/pubnub.7.6.3.js - * https://cdn.pubnub.com/sdk/javascript/pubnub.7.6.3.min.js + * https://cdn.pubnub.com/sdk/javascript/pubnub.8.0.0.js + * https://cdn.pubnub.com/sdk/javascript/pubnub.8.0.0.min.js 2. Configure your keys: diff --git a/cucumber.js b/cucumber.js index ff60e6702..754cfd292 100644 --- a/cucumber.js +++ b/cucumber.js @@ -7,6 +7,6 @@ module.exports = { '--format summary', '--format progress-bar', // '--format @cucumber/pretty-formatter', - '--publish-quiet', + // '--publish-quiet', ].join(' '), }; diff --git a/dist/web/pubnub.js b/dist/web/pubnub.js index 66510cb25..92b49723d 100644 --- a/dist/web/pubnub.js +++ b/dist/web/pubnub.js @@ -1,14652 +1,13083 @@ (function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : - typeof define === 'function' && define.amd ? define(factory) : - (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.PubNub = factory()); + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.PubNub = factory()); })(this, (function () { 'use strict'; - /*! ***************************************************************************** - Copyright (c) Microsoft Corporation. + var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; + + function getDefaultExportFromCjs (x) { + return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; + } + + var cbor = {exports: {}}; + + /* + * The MIT License (MIT) + * + * Copyright (c) 2014 Patrick Gansterer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + (function (module) { + (function(global, undefined$1) { var POW_2_24 = Math.pow(2, -24), + POW_2_32 = Math.pow(2, 32), + POW_2_53 = Math.pow(2, 53); - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted. + function encode(value) { + var data = new ArrayBuffer(256); + var dataView = new DataView(data); + var lastLength; + var offset = 0; - 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 */ + function ensureSpace(length) { + var newByteLength = data.byteLength; + var requiredLength = offset + length; + while (newByteLength < requiredLength) + newByteLength *= 2; + if (newByteLength !== data.byteLength) { + var oldDataView = dataView; + data = new ArrayBuffer(newByteLength); + dataView = new DataView(data); + var uint32count = (offset + 3) >> 2; + for (var i = 0; i < uint32count; ++i) + dataView.setUint32(i * 4, oldDataView.getUint32(i * 4)); + } - 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); - }; + lastLength = length; + return dataView; + } + function write() { + offset += lastLength; + } + function writeFloat64(value) { + write(ensureSpace(8).setFloat64(offset, value)); + } + function writeUint8(value) { + write(ensureSpace(1).setUint8(offset, value)); + } + function writeUint8Array(value) { + var dataView = ensureSpace(value.length); + for (var i = 0; i < value.length; ++i) + dataView.setUint8(offset + i, value[i]); + write(); + } + function writeUint16(value) { + write(ensureSpace(2).setUint16(offset, value)); + } + function writeUint32(value) { + write(ensureSpace(4).setUint32(offset, value)); + } + function writeUint64(value) { + var low = value % POW_2_32; + var high = (value - low) / POW_2_32; + var dataView = ensureSpace(8); + dataView.setUint32(offset, high); + dataView.setUint32(offset + 4, low); + write(); + } + function writeTypeAndLength(type, length) { + if (length < 24) { + writeUint8(type << 5 | length); + } else if (length < 0x100) { + writeUint8(type << 5 | 24); + writeUint8(length); + } else if (length < 0x10000) { + writeUint8(type << 5 | 25); + writeUint16(length); + } else if (length < 0x100000000) { + writeUint8(type << 5 | 26); + writeUint32(length); + } else { + writeUint8(type << 5 | 27); + writeUint64(length); + } + } + + function encodeItem(value) { + var i; - 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 __()); - } + if (value === false) + return writeUint8(0xf4); + if (value === true) + return writeUint8(0xf5); + if (value === null) + return writeUint8(0xf6); + if (value === undefined$1) + return writeUint8(0xf7); + + switch (typeof value) { + case "number": + if (Math.floor(value) === value) { + if (0 <= value && value <= POW_2_53) + return writeTypeAndLength(0, value); + if (-POW_2_53 <= value && value < 0) + return writeTypeAndLength(1, -(value + 1)); + } + writeUint8(0xfb); + return writeFloat64(value); - 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); - }; + case "string": + var utf8data = []; + for (i = 0; i < value.length; ++i) { + var charCode = value.charCodeAt(i); + if (charCode < 0x80) { + utf8data.push(charCode); + } else if (charCode < 0x800) { + utf8data.push(0xc0 | charCode >> 6); + utf8data.push(0x80 | charCode & 0x3f); + } else if (charCode < 0xd800) { + utf8data.push(0xe0 | charCode >> 12); + utf8data.push(0x80 | (charCode >> 6) & 0x3f); + utf8data.push(0x80 | charCode & 0x3f); + } else { + charCode = (charCode & 0x3ff) << 10; + charCode |= value.charCodeAt(++i) & 0x3ff; + charCode += 0x10000; - 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; - } + utf8data.push(0xf0 | charCode >> 18); + utf8data.push(0x80 | (charCode >> 12) & 0x3f); + utf8data.push(0x80 | (charCode >> 6) & 0x3f); + utf8data.push(0x80 | charCode & 0x3f); + } + } - 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()); - }); - } + writeTypeAndLength(3, utf8data.length); + return writeUint8Array(utf8data); - 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; - return g = { next: verb(0), "throw": verb(1), "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 (_) 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 }; - } - } + default: + var length; + if (Array.isArray(value)) { + length = value.length; + writeTypeAndLength(4, length); + for (i = 0; i < length; ++i) + encodeItem(value[i]); + } else if (value instanceof Uint8Array) { + writeTypeAndLength(2, value.length); + writeUint8Array(value); + } else { + var keys = Object.keys(value); + length = keys.length; + writeTypeAndLength(5, length); + for (i = 0; i < length; ++i) { + var key = keys[i]; + encodeItem(key); + encodeItem(value[key]); + } + } + } + } + + encodeItem(value); - 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."); - } + if ("slice" in data) + return data.slice(0, offset); + + var ret = new ArrayBuffer(offset); + var retView = new DataView(ret); + for (var i = 0; i < offset; ++i) + retView.setUint8(i, dataView.getUint8(i)); + return ret; + } - function __read$1(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 decode(data, tagger, simpleValue) { + var dataView = new DataView(data); + var offset = 0; + + if (typeof tagger !== "function") + tagger = function(value) { return value; }; + if (typeof simpleValue !== "function") + simpleValue = function() { return undefined$1; }; - function __spreadArray$1(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)); - } - - var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; - - function getAugmentedNamespace(n) { - if (n.__esModule) return n; - var a = Object.defineProperty({}, '__esModule', {value: true}); - Object.keys(n).forEach(function (k) { - var d = Object.getOwnPropertyDescriptor(n, k); - Object.defineProperty(a, k, d.get ? d : { - enumerable: true, - get: function () { - return n[k]; - } - }); - }); - return a; - } - - var cbor = {exports: {}}; - - /* - * The MIT License (MIT) - * - * Copyright (c) 2014 Patrick Gansterer - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - - (function (module) { - (function(global, undefined$1) {var POW_2_24 = Math.pow(2, -24), - POW_2_32 = Math.pow(2, 32), - POW_2_53 = Math.pow(2, 53); + function read(value, length) { + offset += length; + return value; + } + function readArrayBuffer(length) { + return read(new Uint8Array(data, offset, length), length); + } + function readFloat16() { + var tempArrayBuffer = new ArrayBuffer(4); + var tempDataView = new DataView(tempArrayBuffer); + var value = readUint16(); - function encode(value) { - var data = new ArrayBuffer(256); - var dataView = new DataView(data); - var lastLength; - var offset = 0; + var sign = value & 0x8000; + var exponent = value & 0x7c00; + var fraction = value & 0x03ff; + + if (exponent === 0x7c00) + exponent = 0xff << 10; + else if (exponent !== 0) + exponent += (127 - 15) << 10; + else if (fraction !== 0) + return fraction * POW_2_24; + + tempDataView.setUint32(0, sign << 16 | exponent << 13 | fraction << 13); + return tempDataView.getFloat32(0); + } + function readFloat32() { + return read(dataView.getFloat32(offset), 4); + } + function readFloat64() { + return read(dataView.getFloat64(offset), 8); + } + function readUint8() { + return read(dataView.getUint8(offset), 1); + } + function readUint16() { + return read(dataView.getUint16(offset), 2); + } + function readUint32() { + return read(dataView.getUint32(offset), 4); + } + function readUint64() { + return readUint32() * POW_2_32 + readUint32(); + } + function readBreak() { + if (dataView.getUint8(offset) !== 0xff) + return false; + offset += 1; + return true; + } + function readLength(additionalInformation) { + if (additionalInformation < 24) + return additionalInformation; + if (additionalInformation === 24) + return readUint8(); + if (additionalInformation === 25) + return readUint16(); + if (additionalInformation === 26) + return readUint32(); + if (additionalInformation === 27) + return readUint64(); + if (additionalInformation === 31) + return -1; + throw "Invalid length encoding"; + } + function readIndefiniteStringLength(majorType) { + var initialByte = readUint8(); + if (initialByte === 0xff) + return -1; + var length = readLength(initialByte & 0x1f); + if (length < 0 || (initialByte >> 5) !== majorType) + throw "Invalid indefinite length element"; + return length; + } - function ensureSpace(length) { - var newByteLength = data.byteLength; - var requiredLength = offset + length; - while (newByteLength < requiredLength) - newByteLength *= 2; - if (newByteLength !== data.byteLength) { - var oldDataView = dataView; - data = new ArrayBuffer(newByteLength); - dataView = new DataView(data); - var uint32count = (offset + 3) >> 2; - for (var i = 0; i < uint32count; ++i) - dataView.setUint32(i * 4, oldDataView.getUint32(i * 4)); - } + function appendUtf16data(utf16data, length) { + for (var i = 0; i < length; ++i) { + var value = readUint8(); + if (value & 0x80) { + if (value < 0xe0) { + value = (value & 0x1f) << 6 + | (readUint8() & 0x3f); + length -= 1; + } else if (value < 0xf0) { + value = (value & 0x0f) << 12 + | (readUint8() & 0x3f) << 6 + | (readUint8() & 0x3f); + length -= 2; + } else { + value = (value & 0x0f) << 18 + | (readUint8() & 0x3f) << 12 + | (readUint8() & 0x3f) << 6 + | (readUint8() & 0x3f); + length -= 3; + } + } - lastLength = length; - return dataView; - } - function write() { - offset += lastLength; - } - function writeFloat64(value) { - write(ensureSpace(8).setFloat64(offset, value)); - } - function writeUint8(value) { - write(ensureSpace(1).setUint8(offset, value)); - } - function writeUint8Array(value) { - var dataView = ensureSpace(value.length); - for (var i = 0; i < value.length; ++i) - dataView.setUint8(offset + i, value[i]); - write(); - } - function writeUint16(value) { - write(ensureSpace(2).setUint16(offset, value)); - } - function writeUint32(value) { - write(ensureSpace(4).setUint32(offset, value)); - } - function writeUint64(value) { - var low = value % POW_2_32; - var high = (value - low) / POW_2_32; - var dataView = ensureSpace(8); - dataView.setUint32(offset, high); - dataView.setUint32(offset + 4, low); - write(); - } - function writeTypeAndLength(type, length) { - if (length < 24) { - writeUint8(type << 5 | length); - } else if (length < 0x100) { - writeUint8(type << 5 | 24); - writeUint8(length); - } else if (length < 0x10000) { - writeUint8(type << 5 | 25); - writeUint16(length); - } else if (length < 0x100000000) { - writeUint8(type << 5 | 26); - writeUint32(length); - } else { - writeUint8(type << 5 | 27); - writeUint64(length); - } - } - - function encodeItem(value) { - var i; + if (value < 0x10000) { + utf16data.push(value); + } else { + value -= 0x10000; + utf16data.push(0xd800 | (value >> 10)); + utf16data.push(0xdc00 | (value & 0x3ff)); + } + } + } - if (value === false) - return writeUint8(0xf4); - if (value === true) - return writeUint8(0xf5); - if (value === null) - return writeUint8(0xf6); - if (value === undefined$1) - return writeUint8(0xf7); - - switch (typeof value) { - case "number": - if (Math.floor(value) === value) { - if (0 <= value && value <= POW_2_53) - return writeTypeAndLength(0, value); - if (-POW_2_53 <= value && value < 0) - return writeTypeAndLength(1, -(value + 1)); - } - writeUint8(0xfb); - return writeFloat64(value); + function decodeItem() { + var initialByte = readUint8(); + var majorType = initialByte >> 5; + var additionalInformation = initialByte & 0x1f; + var i; + var length; - case "string": - var utf8data = []; - for (i = 0; i < value.length; ++i) { - var charCode = value.charCodeAt(i); - if (charCode < 0x80) { - utf8data.push(charCode); - } else if (charCode < 0x800) { - utf8data.push(0xc0 | charCode >> 6); - utf8data.push(0x80 | charCode & 0x3f); - } else if (charCode < 0xd800) { - utf8data.push(0xe0 | charCode >> 12); - utf8data.push(0x80 | (charCode >> 6) & 0x3f); - utf8data.push(0x80 | charCode & 0x3f); - } else { - charCode = (charCode & 0x3ff) << 10; - charCode |= value.charCodeAt(++i) & 0x3ff; - charCode += 0x10000; + if (majorType === 7) { + switch (additionalInformation) { + case 25: + return readFloat16(); + case 26: + return readFloat32(); + case 27: + return readFloat64(); + } + } - utf8data.push(0xf0 | charCode >> 18); - utf8data.push(0x80 | (charCode >> 12) & 0x3f); - utf8data.push(0x80 | (charCode >> 6) & 0x3f); - utf8data.push(0x80 | charCode & 0x3f); - } - } + length = readLength(additionalInformation); + if (length < 0 && (majorType < 2 || 6 < majorType)) + throw "Invalid length"; - writeTypeAndLength(3, utf8data.length); - return writeUint8Array(utf8data); + switch (majorType) { + case 0: + return length; + case 1: + return -1 - length; + case 2: + if (length < 0) { + var elements = []; + var fullArrayLength = 0; + while ((length = readIndefiniteStringLength(majorType)) >= 0) { + fullArrayLength += length; + elements.push(readArrayBuffer(length)); + } + var fullArray = new Uint8Array(fullArrayLength); + var fullArrayOffset = 0; + for (i = 0; i < elements.length; ++i) { + fullArray.set(elements[i], fullArrayOffset); + fullArrayOffset += elements[i].length; + } + return fullArray; + } + return readArrayBuffer(length); + case 3: + var utf16data = []; + if (length < 0) { + while ((length = readIndefiniteStringLength(majorType)) >= 0) + appendUtf16data(utf16data, length); + } else + appendUtf16data(utf16data, length); + return String.fromCharCode.apply(null, utf16data); + case 4: + var retArray; + if (length < 0) { + retArray = []; + while (!readBreak()) + retArray.push(decodeItem()); + } else { + retArray = new Array(length); + for (i = 0; i < length; ++i) + retArray[i] = decodeItem(); + } + return retArray; + case 5: + var retObject = {}; + for (i = 0; i < length || length < 0 && !readBreak(); ++i) { + var key = decodeItem(); + retObject[key] = decodeItem(); + } + return retObject; + case 6: + return tagger(decodeItem(), length); + case 7: + switch (length) { + case 20: + return false; + case 21: + return true; + case 22: + return null; + case 23: + return undefined$1; + default: + return simpleValue(length); + } + } + } - default: - var length; - if (Array.isArray(value)) { - length = value.length; - writeTypeAndLength(4, length); - for (i = 0; i < length; ++i) - encodeItem(value[i]); - } else if (value instanceof Uint8Array) { - writeTypeAndLength(2, value.length); - writeUint8Array(value); - } else { - var keys = Object.keys(value); - length = keys.length; - writeTypeAndLength(5, length); - for (i = 0; i < length; ++i) { - var key = keys[i]; - encodeItem(key); - encodeItem(value[key]); - } - } - } - } - - encodeItem(value); + var ret = decodeItem(); + if (offset !== data.byteLength) + throw "Remaining bytes"; + return ret; + } - if ("slice" in data) - return data.slice(0, offset); - - var ret = new ArrayBuffer(offset); - var retView = new DataView(ret); - for (var i = 0; i < offset; ++i) - retView.setUint8(i, dataView.getUint8(i)); - return ret; - } + var obj = { encode: encode, decode: decode }; - function decode(data, tagger, simpleValue) { - var dataView = new DataView(data); - var offset = 0; - - if (typeof tagger !== "function") - tagger = function(value) { return value; }; - if (typeof simpleValue !== "function") - simpleValue = function() { return undefined$1; }; + if (typeof undefined$1 === "function" && undefined$1.amd) + undefined$1("cbor/cbor", obj); + else if (module.exports) + module.exports = obj; + else if (!global.CBOR) + global.CBOR = obj; - function read(value, length) { - offset += length; - return value; - } - function readArrayBuffer(length) { - return read(new Uint8Array(data, offset, length), length); - } - function readFloat16() { - var tempArrayBuffer = new ArrayBuffer(4); - var tempDataView = new DataView(tempArrayBuffer); - var value = readUint16(); + })(commonjsGlobal); + } (cbor)); + + var cborExports = cbor.exports; + var CborReader = /*@__PURE__*/getDefaultExportFromCjs(cborExports); + + /** + * Request processing status categories. + */ + var StatusCategory; + (function (StatusCategory) { + /** + * Call failed when network was unable to complete the call. + */ + StatusCategory["PNNetworkIssuesCategory"] = "PNNetworkIssuesCategory"; + /** + * Network call timed out. + */ + StatusCategory["PNTimeoutCategory"] = "PNTimeoutCategory"; + /** + * Request has been cancelled. + */ + StatusCategory["PNCancelledCategory"] = "PNCancelledCategory"; + /** + * Server responded with bad response. + */ + StatusCategory["PNBadRequestCategory"] = "PNBadRequestCategory"; + /** + * Server responded with access denied. + */ + StatusCategory["PNAccessDeniedCategory"] = "PNAccessDeniedCategory"; + /** + * Incomplete parameters provided for used endpoint. + */ + StatusCategory["PNValidationErrorCategory"] = "PNValidationErrorCategory"; + /** + * PubNub request acknowledgment status. + * + * Some API endpoints respond with request processing status w/o useful data. + */ + StatusCategory["PNAcknowledgmentCategory"] = "PNAcknowledgmentCategory"; + /** + * Something strange happened; please check the logs. + */ + StatusCategory["PNUnknownCategory"] = "PNUnknownCategory"; + // -------------------------------------------------------- + // --------------------- Network status ------------------- + // -------------------------------------------------------- + /** + * SDK will announce when the network appears to be connected again. + */ + StatusCategory["PNNetworkUpCategory"] = "PNNetworkUpCategory"; + /** + * SDK will announce when the network appears to down. + */ + StatusCategory["PNNetworkDownCategory"] = "PNNetworkDownCategory"; + // -------------------------------------------------------- + // -------------------- Real-time events ------------------ + // -------------------------------------------------------- + /** + * PubNub client reconnected to the real-time updates stream. + */ + StatusCategory["PNReconnectedCategory"] = "PNReconnectedCategory"; + /** + * PubNub client connected to the real-time updates stream. + */ + StatusCategory["PNConnectedCategory"] = "PNConnectedCategory"; + /** + * Received real-time updates exceed specified threshold. + * + * After temporary disconnection and catchup, this category means that potentially some + * real-time updates have been pushed into `storage` and need to be requested separately. + */ + StatusCategory["PNRequestMessageCountExceededCategory"] = "PNRequestMessageCountExceededCategory"; + /** + * PubNub client disconnected from the real-time updates streams. + */ + StatusCategory["PNDisconnectedCategory"] = "PNDisconnectedCategory"; + /** + * PubNub client wasn't able to connect to the real-time updates streams. + */ + StatusCategory["PNConnectionErrorCategory"] = "PNConnectionErrorCategory"; + /** + * PubNub client unexpectedly disconnected from the real-time updates streams. + */ + StatusCategory["PNDisconnectedUnexpectedlyCategory"] = "PNDisconnectedUnexpectedlyCategory"; + })(StatusCategory || (StatusCategory = {})); + var StatusCategory$1 = StatusCategory; + + class PubNubError extends Error { + constructor(message, status) { + super(message); + this.status = status; + this.name = 'PubNubError'; + this.message = message; + Object.setPrototypeOf(this, new.target.prototype); + } + } + function createError(errorPayload) { + var _a; + (_a = errorPayload.statusCode) !== null && _a !== void 0 ? _a : (errorPayload.statusCode = 0); + return Object.assign(Object.assign({}, errorPayload), { statusCode: errorPayload.statusCode, category: StatusCategory$1.PNValidationErrorCategory, error: true }); + } + function createValidationError(message, statusCode) { + return createError(Object.assign({ message }, (statusCode !== undefined ? { statusCode } : {}))); + } + + /** + * REST API endpoint use error module. + */ + /** + * PubNub REST API call error. + */ + class PubNubAPIError extends Error { + /** + * Construct API from known error object or {@link PubNub} service error response. + * + * @param errorOrResponse - `Error` or service error response object from which error information + * should be extracted. + * @param data - Preprocessed service error response. + * + * @returns `PubNubAPIError` object with known error category and additional information (if + * available). + */ + static create(errorOrResponse, data) { + if (errorOrResponse instanceof Error) + return PubNubAPIError.createFromError(errorOrResponse); + else + return PubNubAPIError.createFromServiceResponse(errorOrResponse, data); + } + /** + * Create API error instance from other error object. + * + * @param error - `Error` object provided by network provider (mostly) or other {@link PubNub} client components. + * + * @returns `PubNubAPIError` object with known error category and additional information (if + * available). + */ + static createFromError(error) { + let category = StatusCategory$1.PNUnknownCategory; + let message = 'Unknown error'; + let errorName = 'Error'; + if (!error) + return new PubNubAPIError(message, category, 0); + else if (error instanceof PubNubAPIError) + return error; + if (error instanceof Error) { + message = error.message; + errorName = error.name; + } + if (errorName === 'AbortError' || message.indexOf('Aborted') !== -1) { + category = StatusCategory$1.PNCancelledCategory; + message = 'Request cancelled'; + } + else if (message.indexOf('timeout') !== -1) { + category = StatusCategory$1.PNTimeoutCategory; + message = 'Request timeout'; + } + else if (message.indexOf('network') !== -1) { + category = StatusCategory$1.PNNetworkIssuesCategory; + message = 'Network issues'; + } + else if (errorName === 'TypeError') { + category = StatusCategory$1.PNBadRequestCategory; + } + else if (errorName === 'FetchError') { + const errorCode = error.code; + if (['ECONNREFUSED', 'ENETUNREACH', 'ENOTFOUND', 'ECONNRESET', 'EAI_AGAIN'].includes(errorCode)) + category = StatusCategory$1.PNNetworkIssuesCategory; + if (errorCode === 'ECONNREFUSED') + message = 'Connection refused'; + else if (errorCode === 'ENETUNREACH') + message = 'Network not reachable'; + else if (errorCode === 'ENOTFOUND') + message = 'Server not found'; + else if (errorCode === 'ECONNRESET') + message = 'Connection reset by peer'; + else if (errorCode === 'EAI_AGAIN') + message = 'Name resolution error'; + else if (errorCode === 'ETIMEDOUT') { + category = StatusCategory$1.PNTimeoutCategory; + message = 'Request timeout'; + } + else + message = `Unknown system error: ${error}`; + } + else if (message === 'Request timeout') + category = StatusCategory$1.PNTimeoutCategory; + return new PubNubAPIError(message, category, 0, error); + } + /** + * Construct API from known {@link PubNub} service error response. + * + * @param response - Service error response object from which error information should be + * extracted. + * @param data - Preprocessed service error response. + * + * @returns `PubNubAPIError` object with known error category and additional information (if + * available). + */ + static createFromServiceResponse(response, data) { + let category = StatusCategory$1.PNUnknownCategory; + let errorData; + let message = 'Unknown error'; + let { status } = response; + data !== null && data !== void 0 ? data : (data = response.body); + if (status === 402) + message = 'Not available for used key set. Contact support@pubnub.com'; + else if (status === 400) { + category = StatusCategory$1.PNBadRequestCategory; + message = 'Bad request'; + } + else if (status === 403) { + category = StatusCategory$1.PNAccessDeniedCategory; + message = 'Access denied'; + } + // Try to get more information about error from service response. + if (data && data.byteLength > 0) { + const decoded = new TextDecoder().decode(data); + if (response.headers['content-type'].indexOf('text/javascript') !== -1 || + response.headers['content-type'].indexOf('application/json') !== -1) { + try { + const errorResponse = JSON.parse(decoded); + if (typeof errorResponse === 'object' && !Array.isArray(errorResponse)) { + if ('error' in errorResponse && + (errorResponse.error === 1 || errorResponse.error === true) && + 'status' in errorResponse && + typeof errorResponse.status === 'number' && + 'message' in errorResponse && + 'service' in errorResponse) { + errorData = errorResponse; + status = errorResponse.status; + } + else + errorData = errorResponse; + if ('error' in errorResponse && errorResponse.error instanceof Error) + errorData = errorResponse.error; + } + } + catch (_) { + errorData = decoded; + } + } + else if (response.headers['content-type'].indexOf('xml') !== -1) { + const reason = /(.*)<\/Message>/gi.exec(decoded); + message = reason ? `Upload to bucket failed: ${reason[1]}` : 'Upload to bucket failed.'; + } + else { + errorData = decoded; + } + } + return new PubNubAPIError(message, category, status, errorData); + } + /** + * Construct PubNub endpoint error. + * + * @param message - Short API call error description. + * @param category - Error category. + * @param statusCode - Response HTTP status code. + * @param errorData - Error information. + */ + constructor(message, category, statusCode, errorData) { + super(message); + this.category = category; + this.statusCode = statusCode; + this.errorData = errorData; + this.name = 'PubNubAPIError'; + } + /** + * Convert API error object to API callback status object. + * + * @param operation - Request operation during which error happened. + * + * @returns Pre-formatted API callback status object. + */ + toStatus(operation) { + return { + error: true, + category: this.category, + operation, + statusCode: this.statusCode, + errorData: this.errorData, + }; + } + /** + * Convert API error object to PubNub client error object. + * + * @param operation - Request operation during which error happened. + * @param message - Custom error message. + * + * @returns Client-facing pre-formatted endpoint call error. + */ + toPubNubError(operation, message) { + return new PubNubError(message !== null && message !== void 0 ? message : this.message, this.toStatus(operation)); + } + } + + /** + * Subscription Service Worker transport middleware module. + * + * Middleware optimize subscription feature requests utilizing `Subscription Service Worker` if available and not + * disabled by user. + */ + // endregion + /** + * Subscription Service Worker transport middleware. + */ + class SubscriptionServiceWorkerMiddleware { + constructor(configuration) { + this.configuration = configuration; + this.serviceWorkerEventsQueue = []; + this.callbacks = new Map(); + this.setupServiceWorker(); + } + makeSendable(req) { + // Use default request flow for non-subscribe / presence leave requests. + if (!req.path.startsWith('/v2/subscribe') && !req.path.endsWith('/leave')) + return this.configuration.transport.makeSendable(req); + let controller; + const sendRequestEvent = { + type: 'send-request', + clientIdentifier: this.configuration.clientIdentifier, + subscriptionKey: this.configuration.subscriptionKey, + logVerbosity: this.configuration.logVerbosity, + request: req, + }; + if (req.cancellable) { + controller = { + abort: () => { + const cancelRequest = { + type: 'cancel-request', + clientIdentifier: this.configuration.clientIdentifier, + subscriptionKey: this.configuration.subscriptionKey, + logVerbosity: this.configuration.logVerbosity, + identifier: req.identifier, + }; + // Cancel active request with specified identifier. + this.scheduleEventPost(cancelRequest); + }, + }; + } + return [ + new Promise((resolve, reject) => { + // Associate Promise resolution / reject with request identifier for future usage in + // `onmessage` handler block to return results. + this.callbacks.set(req.identifier, { resolve, reject }); + // Trigger request processing by Service Worker. + this.scheduleEventPost(sendRequestEvent); + }), + controller, + ]; + } + request(req) { + return req; + } + /** + * Schedule {@link event} publish to the service worker. + * + * Service worker may not be ready for events processing and this method build queue for the time when worker will be + * ready. + * + * @param event - Event payload for service worker. + * @param outOfOrder - Whether event should be processed first then enqueued queue. + */ + scheduleEventPost(event, outOfOrder = false) { + // Trigger request processing by Web Worker. + const serviceWorker = this.serviceWorker; + if (serviceWorker) + serviceWorker.postMessage(event); + else { + if (outOfOrder) + this.serviceWorkerEventsQueue.splice(0, 0, event); + else + this.serviceWorkerEventsQueue.push(event); + } + } + /** + * Dequeue and post events from the queue to the service worker. + */ + flushScheduledEvents() { + // Trigger request processing by Web Worker. + const serviceWorker = this.serviceWorker; + if (!serviceWorker || this.serviceWorkerEventsQueue.length === 0) + return; + // Clean up from cancelled events. + const outdatedEvents = []; + for (let i = 0; i < this.serviceWorkerEventsQueue.length; i++) { + const event = this.serviceWorkerEventsQueue[i]; + // Check whether found request cancel event to search for request send event it cancels. + if (event.type !== 'cancel-request' || i === 0) + continue; + for (let j = 0; j < i; j++) { + const otherEvent = this.serviceWorkerEventsQueue[j]; + if (otherEvent.type !== 'send-request') + continue; + // Collect outdated events if identifiers match. + if (otherEvent.request.identifier === event.identifier) { + outdatedEvents.push(event, otherEvent); + break; + } + } + } + // Actualizing events queue. + this.serviceWorkerEventsQueue = this.serviceWorkerEventsQueue.filter((event) => !outdatedEvents.includes(event)); + this.serviceWorkerEventsQueue.forEach((event) => serviceWorker.postMessage(event)); + this.serviceWorkerEventsQueue = []; + } + /** + * Subscription service worker. + * + * @returns Service worker which has been registered by the PubNub SDK. + */ + get serviceWorker() { + return this.serviceWorkerRegistration ? this.serviceWorkerRegistration.active : null; + } + setupServiceWorker() { + if (!('serviceWorker' in navigator)) + return; + const serviceWorkerContainer = navigator.serviceWorker; + serviceWorkerContainer + .register(`https://cdn.pubnub.com/sdk/javascript/dist/web/pubnub.worker.js`, { + scope: `/pubnub-${this.configuration.sdkVersion}`, + }) + .then((registration) => { + this.serviceWorkerRegistration = registration; + // Flush any pending service worker events. + if (registration.active) + this.flushScheduledEvents(); + /** + * Listening for service worker code update. + * + * It is possible that one of the tabs will open with newer SDK version and Subscription Service Worker + * will be re-installed - in this case we need to "rehydrate" it. + * + * After re-installation of new service worker it will lose all accumulated state and client need to + * re-introduce itself and its state. + */ + this.serviceWorkerRegistration.addEventListener('updatefound', () => { + if (!this.serviceWorkerRegistration) + return; + // New service installing right now. + const serviceWorker = this.serviceWorkerRegistration.installing; + const stateChangeListener = () => { + // Flush any pending service worker events. + if (serviceWorker.state === 'activated') { + // Flush any pending service worker events. + this.flushScheduledEvents(); + } + else if (serviceWorker.state === 'redundant') { + // Clean up listener from deprecated service worker version. + serviceWorker.removeEventListener('statechange', stateChangeListener); + } + }; + serviceWorker.addEventListener('statechange', stateChangeListener); + }); + }); + serviceWorkerContainer.addEventListener('message', (event) => this.handleServiceWorkerEvent(event)); + } + handleServiceWorkerEvent(event) { + const { data } = event; + // Ignoring updates not related to this instance. + if (data.clientIdentifier !== this.configuration.clientIdentifier) + return; + if (data.type === 'request-progress-start' || data.type === 'request-progress-end') { + this.logRequestProgress(data); + } + else if (data.type === 'request-process-success' || data.type === 'request-process-error') { + const { resolve, reject } = this.callbacks.get(data.identifier); + if (data.type === 'request-process-success') { + resolve({ + status: data.response.status, + url: data.url, + headers: data.response.headers, + body: data.response.body, + }); + } + else { + let category = StatusCategory$1.PNUnknownCategory; + let message = 'Unknown error'; + // Handle client-side issues (if any). + if (data.error) { + if (data.error.type === 'NETWORK_ISSUE') + category = StatusCategory$1.PNNetworkIssuesCategory; + else if (data.error.type === 'TIMEOUT') + category = StatusCategory$1.PNTimeoutCategory; + else if (data.error.type === 'ABORTED') + category = StatusCategory$1.PNCancelledCategory; + message = `${data.error.message} (${data.identifier})`; + } + // Handle service error response. + else if (data.response) { + return reject(PubNubAPIError.create({ + url: data.url, + headers: data.response.headers, + body: data.response.body, + status: data.response.status, + }, data.response.body)); + } + reject(new PubNubAPIError(message, category, 0, new Error(message))); + } + } + } + /** + * Print request progress information. + * + * @param information - Request progress information from Web Worker. + */ + logRequestProgress(information) { + var _a, _b; + if (information.type === 'request-progress-start') { + console.log('<<<<<'); + console.log(`[${information.timestamp}] ${information.url}\n${JSON.stringify((_a = information.query) !== null && _a !== void 0 ? _a : {})}`); + console.log('-----'); + } + else { + console.log('>>>>>>'); + console.log(`[${information.timestamp} / ${information.duration}] ${information.url}\n${JSON.stringify((_b = information.query) !== null && _b !== void 0 ? _b : {})}\n${information.response}`); + console.log('-----'); + } + } + } + + /****************************************************************************** + Copyright (c) Microsoft Corporation. - var sign = value & 0x8000; - var exponent = value & 0x7c00; - var fraction = value & 0x03ff; - - if (exponent === 0x7c00) - exponent = 0xff << 10; - else if (exponent !== 0) - exponent += (127 - 15) << 10; - else if (fraction !== 0) - return fraction * POW_2_24; - - tempDataView.setUint32(0, sign << 16 | exponent << 13 | fraction << 13); - return tempDataView.getFloat32(0); - } - function readFloat32() { - return read(dataView.getFloat32(offset), 4); - } - function readFloat64() { - return read(dataView.getFloat64(offset), 8); - } - function readUint8() { - return read(dataView.getUint8(offset), 1); - } - function readUint16() { - return read(dataView.getUint16(offset), 2); - } - function readUint32() { - return read(dataView.getUint32(offset), 4); - } - function readUint64() { - return readUint32() * POW_2_32 + readUint32(); - } - function readBreak() { - if (dataView.getUint8(offset) !== 0xff) - return false; - offset += 1; - return true; - } - function readLength(additionalInformation) { - if (additionalInformation < 24) - return additionalInformation; - if (additionalInformation === 24) - return readUint8(); - if (additionalInformation === 25) - return readUint16(); - if (additionalInformation === 26) - return readUint32(); - if (additionalInformation === 27) - return readUint64(); - if (additionalInformation === 31) - return -1; - throw "Invalid length encoding"; - } - function readIndefiniteStringLength(majorType) { - var initialByte = readUint8(); - if (initialByte === 0xff) - return -1; - var length = readLength(initialByte & 0x1f); - if (length < 0 || (initialByte >> 5) !== majorType) - throw "Invalid indefinite length element"; - return length; - } + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted. - function appendUtf16data(utf16data, length) { - for (var i = 0; i < length; ++i) { - var value = readUint8(); - if (value & 0x80) { - if (value < 0xe0) { - value = (value & 0x1f) << 6 - | (readUint8() & 0x3f); - length -= 1; - } else if (value < 0xf0) { - value = (value & 0x0f) << 12 - | (readUint8() & 0x3f) << 6 - | (readUint8() & 0x3f); - length -= 2; - } else { - value = (value & 0x0f) << 18 - | (readUint8() & 0x3f) << 12 - | (readUint8() & 0x3f) << 6 - | (readUint8() & 0x3f); - length -= 3; - } - } + 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 */ - if (value < 0x10000) { - utf16data.push(value); - } else { - value -= 0x10000; - utf16data.push(0xd800 | (value >> 10)); - utf16data.push(0xdc00 | (value & 0x3ff)); - } - } - } - function decodeItem() { - var initialByte = readUint8(); - var majorType = initialByte >> 5; - var additionalInformation = initialByte & 0x1f; - var i; - var length; + 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; + } - if (majorType === 7) { - switch (additionalInformation) { - case 25: - return readFloat16(); - case 26: - return readFloat32(); - case 27: - return readFloat64(); - } - } + 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()); + }); + } - length = readLength(additionalInformation); - if (length < 0 && (majorType < 2 || 6 < majorType)) - throw "Invalid length"; - - switch (majorType) { - case 0: - return length; - case 1: - return -1 - length; - case 2: - if (length < 0) { - var elements = []; - var fullArrayLength = 0; - while ((length = readIndefiniteStringLength(majorType)) >= 0) { - fullArrayLength += length; - elements.push(readArrayBuffer(length)); - } - var fullArray = new Uint8Array(fullArrayLength); - var fullArrayOffset = 0; - for (i = 0; i < elements.length; ++i) { - fullArray.set(elements[i], fullArrayOffset); - fullArrayOffset += elements[i].length; - } - return fullArray; - } - return readArrayBuffer(length); - case 3: - var utf16data = []; - if (length < 0) { - while ((length = readIndefiniteStringLength(majorType)) >= 0) - appendUtf16data(utf16data, length); - } else - appendUtf16data(utf16data, length); - return String.fromCharCode.apply(null, utf16data); - case 4: - var retArray; - if (length < 0) { - retArray = []; - while (!readBreak()) - retArray.push(decodeItem()); - } else { - retArray = new Array(length); - for (i = 0; i < length; ++i) - retArray[i] = decodeItem(); - } - return retArray; - case 5: - var retObject = {}; - for (i = 0; i < length || length < 0 && !readBreak(); ++i) { - var key = decodeItem(); - retObject[key] = decodeItem(); - } - return retObject; - case 6: - return tagger(decodeItem(), length); - case 7: - switch (length) { - case 20: - return false; - case 21: - return true; - case 22: - return null; - case 23: - return undefined$1; - default: - return simpleValue(length); - } - } - } - - var ret = decodeItem(); - if (offset !== data.byteLength) - throw "Remaining bytes"; - return ret; - } - - var obj = { encode: encode, decode: decode }; - - if (typeof undefined$1 === "function" && undefined$1.amd) - undefined$1("cbor/cbor", obj); - else if (module.exports) - module.exports = obj; - else if (!global.CBOR) - global.CBOR = obj; - - })(commonjsGlobal); - }(cbor)); - - var CborReader = cbor.exports; - - var uuid = {exports: {}}; - - /*! lil-uuid - v0.1 - MIT License - https://github.com/lil-js/uuid */ - - (function (module, exports) { - (function (root, factory) { - { - factory(exports); - if (module !== null) { - module.exports = exports.uuid; - } - } - }(commonjsGlobal, function (exports) { - var VERSION = '0.1.0'; - var uuidRegex = { - '3': /^[0-9A-F]{8}-[0-9A-F]{4}-3[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}$/i, - '4': /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i, - '5': /^[0-9A-F]{8}-[0-9A-F]{4}-5[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i, - all: /^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i - }; - - function uuid() { - var uuid = '', i, random; - for (i = 0; i < 32; i++) { - random = Math.random() * 16 | 0; - if (i === 8 || i === 12 || i === 16 || i === 20) uuid += '-'; - uuid += (i === 12 ? 4 : (i === 16 ? (random & 3 | 8) : random)).toString(16); - } - return uuid - } - - function isUUID(str, version) { - var pattern = uuidRegex[version || 'all']; - return pattern && pattern.test(str) || false - } - - uuid.isUUID = isUUID; - uuid.VERSION = VERSION; - - exports.uuid = uuid; - exports.isUUID = isUUID; - })); - }(uuid, uuid.exports)); - - var uuidGenerator$1 = uuid.exports; - - var uuidGenerator = { - createUUID: function () { - if (uuidGenerator$1.uuid) { - return uuidGenerator$1.uuid(); - } - return uuidGenerator$1(); - }, - }; - - /* */ - var PRESENCE_TIMEOUT_MINIMUM = 20; - var PRESENCE_TIMEOUT_DEFAULT = 300; - var makeDefaultOrigins = function () { return Array.from({ length: 20 }, function (_, i) { return "ps".concat(i + 1, ".pndsn.com"); }); }; - var default_1$b = /** @class */ (function () { - function default_1(_a) { - var setup = _a.setup; - var _b, _c, _d, _e; - this._PNSDKSuffix = {}; - this.instanceId = "pn-".concat(uuidGenerator.createUUID()); - this.secretKey = setup.secretKey || setup.secret_key; - this.subscribeKey = setup.subscribeKey || setup.subscribe_key; - this.publishKey = setup.publishKey || setup.publish_key; - this.sdkName = setup.sdkName; - this.sdkFamily = setup.sdkFamily; - this.partnerId = setup.partnerId; - this.setAuthKey(setup.authKey); - this.cryptoModule = setup.cryptoModule; - this.setFilterExpression(setup.filterExpression); - if (typeof setup.origin !== 'string' && !Array.isArray(setup.origin) && setup.origin !== undefined) { - throw new Error('Origin must be either undefined, a string or a list of strings.'); - } - this.origin = setup.origin || makeDefaultOrigins(); - this.secure = setup.ssl || false; - this.restore = setup.restore || false; - this.proxy = setup.proxy; - this.keepAlive = setup.keepAlive; - this.keepAliveSettings = setup.keepAliveSettings; - this.autoNetworkDetection = setup.autoNetworkDetection || false; - this.dedupeOnSubscribe = setup.dedupeOnSubscribe || false; - this.maximumCacheSize = setup.maximumCacheSize || 100; - this.customEncrypt = setup.customEncrypt; - this.customDecrypt = setup.customDecrypt; - this.fileUploadPublishRetryLimit = (_b = setup.fileUploadPublishRetryLimit) !== null && _b !== void 0 ? _b : 5; - this.useRandomIVs = (_c = setup.useRandomIVs) !== null && _c !== void 0 ? _c : true; - this.enableEventEngine = (_d = setup.enableEventEngine) !== null && _d !== void 0 ? _d : false; - this.maintainPresenceState = (_e = setup.maintainPresenceState) !== null && _e !== void 0 ? _e : true; - // if location config exist and we are in https, force secure to true. - if (typeof location !== 'undefined' && location.protocol === 'https:') { - this.secure = true; - } - this.logVerbosity = setup.logVerbosity || false; - this.suppressLeaveEvents = setup.suppressLeaveEvents || false; - this.announceFailedHeartbeats = setup.announceFailedHeartbeats || true; - this.announceSuccessfulHeartbeats = setup.announceSuccessfulHeartbeats || false; - this.useInstanceId = setup.useInstanceId || false; - this.useRequestId = setup.useRequestId || false; - this.requestMessageCountThreshold = setup.requestMessageCountThreshold; - if (setup.retryConfiguration) { - this._setRetryConfiguration(setup.retryConfiguration); - } - // set timeout to how long a transaction request will wait for the server (default 15 seconds) - this.setTransactionTimeout(setup.transactionalRequestTimeout || 15 * 1000); - // set timeout to how long a subscribe event loop will run (default 310 seconds) - this.setSubscribeTimeout(setup.subscribeRequestTimeout || 310 * 1000); - // set config on beacon (https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon) usage - this.setSendBeaconConfig(setup.useSendBeacon || true); - // how long the SDK will report the client to be alive before issuing a timeout - if (setup.presenceTimeout) { - this.setPresenceTimeout(setup.presenceTimeout); - } - else { - this._presenceTimeout = PRESENCE_TIMEOUT_DEFAULT; - } - if (setup.heartbeatInterval != null) { - this.setHeartbeatInterval(setup.heartbeatInterval); - } - if (typeof setup.userId === 'string') { - if (typeof setup.uuid === 'string') { - throw new Error('Only one of the following configuration options has to be provided: `uuid` or `userId`'); - } - this.setUserId(setup.userId); - } - else { - if (typeof setup.uuid !== 'string') { - throw new Error('One of the following configuration options has to be provided: `uuid` or `userId`'); - } - this.setUUID(setup.uuid); - } - this.setCipherKey(setup.cipherKey, setup); - } - // exposed setters - default_1.prototype.getAuthKey = function () { - return this.authKey; - }; - default_1.prototype.setAuthKey = function (val) { - this.authKey = val; - return this; - }; - default_1.prototype.setCipherKey = function (val, setup, modules) { - var _a; - this.cipherKey = val; - if (this.cipherKey) { - this.cryptoModule = - (_a = setup.cryptoModule) !== null && _a !== void 0 ? _a : setup.initCryptoModule({ cipherKey: this.cipherKey, useRandomIVs: this.useRandomIVs }); - if (modules) - modules.cryptoModule = this.cryptoModule; - } - return this; - }; - default_1.prototype.getUUID = function () { - return this.UUID; - }; - default_1.prototype.setUUID = function (val) { - if (!val || typeof val !== 'string' || val.trim().length === 0) { - throw new Error('Missing uuid parameter. Provide a valid string uuid'); - } - this.UUID = val; - return this; - }; - default_1.prototype.getUserId = function () { - return this.UUID; - }; - default_1.prototype.setUserId = function (value) { - if (!value || typeof value !== 'string' || value.trim().length === 0) { - throw new Error('Missing or invalid userId parameter. Provide a valid string userId'); - } - this.UUID = value; - return this; - }; - default_1.prototype.getFilterExpression = function () { - return this.filterExpression; - }; - default_1.prototype.setFilterExpression = function (val) { - this.filterExpression = val; - return this; - }; - default_1.prototype.getPresenceTimeout = function () { - return this._presenceTimeout; - }; - default_1.prototype.setPresenceTimeout = function (val) { - if (val >= PRESENCE_TIMEOUT_MINIMUM) { - this._presenceTimeout = val; - } - else { - this._presenceTimeout = PRESENCE_TIMEOUT_MINIMUM; - // eslint-disable-next-line no-console - console.log('WARNING: Presence timeout is less than the minimum. Using minimum value: ', this._presenceTimeout); - } - this.setHeartbeatInterval(this._presenceTimeout / 2 - 1); - return this; - }; - default_1.prototype.setProxy = function (proxy) { - this.proxy = proxy; - }; - default_1.prototype.getHeartbeatInterval = function () { - return this._heartbeatInterval; - }; - default_1.prototype.setHeartbeatInterval = function (val) { - this._heartbeatInterval = val; - return this; - }; - // deprecated setters. - default_1.prototype.getSubscribeTimeout = function () { - return this._subscribeRequestTimeout; - }; - default_1.prototype.setSubscribeTimeout = function (val) { - this._subscribeRequestTimeout = val; - return this; - }; - default_1.prototype.getTransactionTimeout = function () { - return this._transactionalRequestTimeout; - }; - default_1.prototype.setTransactionTimeout = function (val) { - this._transactionalRequestTimeout = val; - return this; - }; - default_1.prototype.isSendBeaconEnabled = function () { - return this._useSendBeacon; - }; - default_1.prototype.setSendBeaconConfig = function (val) { - this._useSendBeacon = val; - return this; - }; - default_1.prototype.getVersion = function () { - return '7.6.3'; - }; - default_1.prototype._setRetryConfiguration = function (configuration) { - if (configuration.minimumdelay < 2) { - throw new Error('Minimum delay can not be set less than 2 seconds for retry'); - } - if (configuration.maximumDelay > 150) { - throw new Error('Maximum delay can not be set more than 150 seconds for retry'); - } - if (configuration.maximumDelay && maximumRetry > 6) { - throw new Error('Maximum retry for exponential retry policy can not be more than 6'); - } - else if (configuration.maximumRetry > 10) { - throw new Error('Maximum retry for linear retry policy can not be more than 10'); - } - this.retryConfiguration = configuration; - }; - default_1.prototype._addPnsdkSuffix = function (name, suffix) { - this._PNSDKSuffix[name] = suffix; - }; - default_1.prototype._getPnsdkSuffix = function (separator) { - var _this = this; - return Object.keys(this._PNSDKSuffix).reduce(function (result, key) { return result + separator + _this._PNSDKSuffix[key]; }, ''); - }; - return default_1; - }()); - - var BASE64_CHARMAP = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; - /** - * Decode a Base64 encoded string. - * - * @param paddedInput Base64 string with padding - * @returns ArrayBuffer with decoded data - */ - function decode$1(paddedInput) { - // Remove up to last two equal signs. - var input = paddedInput.replace(/==?$/, ''); - var outputLength = Math.floor((input.length / 4) * 3); - // Prepare output buffer. - var data = new ArrayBuffer(outputLength); - var view = new Uint8Array(data); - var cursor = 0; - /** - * Returns the next integer representation of a sixtet of bytes from the input - * @returns sixtet of bytes - */ - function nextSixtet() { - var char = input.charAt(cursor++); - var index = BASE64_CHARMAP.indexOf(char); - if (index === -1) { - throw new Error("Illegal character at ".concat(cursor, ": ").concat(input.charAt(cursor - 1))); - } - return index; - } - for (var i = 0; i < outputLength; i += 3) { - // Obtain four sixtets - var sx1 = nextSixtet(); - var sx2 = nextSixtet(); - var sx3 = nextSixtet(); - var sx4 = nextSixtet(); - // Encode them as three octets - var oc1 = ((sx1 & 63) << 2) | (sx2 >> 4); - var oc2 = ((sx2 & 15) << 4) | (sx3 >> 2); - var oc3 = ((sx3 & 3) << 6) | (sx4 >> 0); - view[i] = oc1; - // Skip padding bytes. - if (sx3 != 64) - view[i + 1] = oc2; - if (sx4 != 64) - view[i + 2] = oc3; - } - return data; - } - function encode$1(input) { - var base64 = ''; - var encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; - var bytes = new Uint8Array(input); - var byteLength = bytes.byteLength; - var byteRemainder = byteLength % 3; - var mainLength = byteLength - byteRemainder; - var a, b, c, d; - var chunk; - // Main loop deals with bytes in chunks of 3 - for (var i = 0; i < mainLength; i = i + 3) { - // Combine the three bytes into a single integer - chunk = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2]; - // Use bitmasks to extract 6-bit segments from the triplet - a = (chunk & 16515072) >> 18; // 16515072 = (2^6 - 1) << 18 - b = (chunk & 258048) >> 12; // 258048 = (2^6 - 1) << 12 - c = (chunk & 4032) >> 6; // 4032 = (2^6 - 1) << 6 - d = chunk & 63; // 63 = 2^6 - 1 - // Convert the raw binary segments to the appropriate ASCII encoding - base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d]; - } - // Deal with the remaining bytes and padding - if (byteRemainder == 1) { - chunk = bytes[mainLength]; - a = (chunk & 252) >> 2; // 252 = (2^6 - 1) << 2 - // Set the 4 least significant bits to zero - b = (chunk & 3) << 4; // 3 = 2^2 - 1 - base64 += encodings[a] + encodings[b] + '=='; - } - else if (byteRemainder == 2) { - chunk = (bytes[mainLength] << 8) | bytes[mainLength + 1]; - a = (chunk & 64512) >> 10; // 64512 = (2^6 - 1) << 10 - b = (chunk & 1008) >> 4; // 1008 = (2^6 - 1) << 4 - // Set the 2 least significant bits to zero - c = (chunk & 15) << 2; // 15 = 2^4 - 1 - base64 += encodings[a] + encodings[b] + encodings[c] + '='; - } - return base64; - } - - /*eslint-disable */ - /* - CryptoJS v3.1.2 - code.google.com/p/crypto-js - (c) 2009-2013 by Jeff Mott. All rights reserved. - code.google.com/p/crypto-js/wiki/License - */ - var CryptoJS = CryptoJS || - (function (h, s) { - var f = {}, g = (f.lib = {}), q = function () { }, m = (g.Base = { - extend: function (a) { - q.prototype = this; - var c = new q(); - a && c.mixIn(a); - c.hasOwnProperty('init') || - (c.init = function () { - c.$super.init.apply(this, arguments); - }); - c.init.prototype = c; - c.$super = this; - return c; - }, - create: function () { - var a = this.extend(); - a.init.apply(a, arguments); - return a; - }, - init: function () { }, - mixIn: function (a) { - for (var c in a) - a.hasOwnProperty(c) && (this[c] = a[c]); - a.hasOwnProperty('toString') && (this.toString = a.toString); - }, - clone: function () { - return this.init.prototype.extend(this); - }, - }), r = (g.WordArray = m.extend({ - init: function (a, c) { - a = this.words = a || []; - this.sigBytes = c != s ? c : 4 * a.length; - }, - toString: function (a) { - return (a || k).stringify(this); - }, - concat: function (a) { - var c = this.words, d = a.words, b = this.sigBytes; - a = a.sigBytes; - this.clamp(); - if (b % 4) - for (var e = 0; e < a; e++) - c[(b + e) >>> 2] |= ((d[e >>> 2] >>> (24 - 8 * (e % 4))) & 255) << (24 - 8 * ((b + e) % 4)); - else if (65535 < d.length) - for (e = 0; e < a; e += 4) - c[(b + e) >>> 2] = d[e >>> 2]; - else - c.push.apply(c, d); - this.sigBytes += a; - return this; - }, - clamp: function () { - var a = this.words, c = this.sigBytes; - a[c >>> 2] &= 4294967295 << (32 - 8 * (c % 4)); - a.length = h.ceil(c / 4); - }, - clone: function () { - var a = m.clone.call(this); - a.words = this.words.slice(0); - return a; - }, - random: function (a) { - for (var c = [], d = 0; d < a; d += 4) - c.push((4294967296 * h.random()) | 0); - return new r.init(c, a); - }, - })), l = (f.enc = {}), k = (l.Hex = { - stringify: function (a) { - var c = a.words; - a = a.sigBytes; - for (var d = [], b = 0; b < a; b++) { - var e = (c[b >>> 2] >>> (24 - 8 * (b % 4))) & 255; - d.push((e >>> 4).toString(16)); - d.push((e & 15).toString(16)); - } - return d.join(''); - }, - parse: function (a) { - for (var c = a.length, d = [], b = 0; b < c; b += 2) - d[b >>> 3] |= parseInt(a.substr(b, 2), 16) << (24 - 4 * (b % 8)); - return new r.init(d, c / 2); - }, - }), n = (l.Latin1 = { - stringify: function (a) { - var c = a.words; - a = a.sigBytes; - for (var d = [], b = 0; b < a; b++) - d.push(String.fromCharCode((c[b >>> 2] >>> (24 - 8 * (b % 4))) & 255)); - return d.join(''); - }, - parse: function (a) { - for (var c = a.length, d = [], b = 0; b < c; b++) - d[b >>> 2] |= (a.charCodeAt(b) & 255) << (24 - 8 * (b % 4)); - return new r.init(d, c); - }, - }), j = (l.Utf8 = { - stringify: function (a) { - try { - return decodeURIComponent(escape(n.stringify(a))); - } - catch (c) { - throw Error('Malformed UTF-8 data'); - } - }, - parse: function (a) { - return n.parse(unescape(encodeURIComponent(a))); - }, - }), u = (g.BufferedBlockAlgorithm = m.extend({ - reset: function () { - this._data = new r.init(); - this._nDataBytes = 0; - }, - _append: function (a) { - 'string' == typeof a && (a = j.parse(a)); - this._data.concat(a); - this._nDataBytes += a.sigBytes; - }, - _process: function (a) { - var c = this._data, d = c.words, b = c.sigBytes, e = this.blockSize, f = b / (4 * e), f = a ? h.ceil(f) : h.max((f | 0) - this._minBufferSize, 0); - a = f * e; - b = h.min(4 * a, b); - if (a) { - for (var g = 0; g < a; g += e) - this._doProcessBlock(d, g); - g = d.splice(0, a); - c.sigBytes -= b; - } - return new r.init(g, b); - }, - clone: function () { - var a = m.clone.call(this); - a._data = this._data.clone(); - return a; - }, - _minBufferSize: 0, - })); - g.Hasher = u.extend({ - cfg: m.extend(), - init: function (a) { - this.cfg = this.cfg.extend(a); - this.reset(); - }, - reset: function () { - u.reset.call(this); - this._doReset(); - }, - update: function (a) { - this._append(a); - this._process(); - return this; - }, - finalize: function (a) { - a && this._append(a); - return this._doFinalize(); - }, - blockSize: 16, - _createHelper: function (a) { - return function (c, d) { - return new a.init(d).finalize(c); - }; - }, - _createHmacHelper: function (a) { - return function (c, d) { - return new t.HMAC.init(a, d).finalize(c); - }; - }, - }); - var t = (f.algo = {}); - return f; - })(Math); - // SHA256 - (function (h) { - for (var s = CryptoJS, f = s.lib, g = f.WordArray, q = f.Hasher, f = s.algo, m = [], r = [], l = function (a) { - return (4294967296 * (a - (a | 0))) | 0; - }, k = 2, n = 0; 64 > n;) { - var j; - a: { - j = k; - for (var u = h.sqrt(j), t = 2; t <= u; t++) - if (!(j % t)) { - j = !1; - break a; - } - j = !0; - } - j && (8 > n && (m[n] = l(h.pow(k, 0.5))), (r[n] = l(h.pow(k, 1 / 3))), n++); - k++; - } - var a = [], f = (f.SHA256 = q.extend({ - _doReset: function () { - this._hash = new g.init(m.slice(0)); - }, - _doProcessBlock: function (c, d) { - for (var b = this._hash.words, e = b[0], f = b[1], g = b[2], j = b[3], h = b[4], m = b[5], n = b[6], q = b[7], p = 0; 64 > p; p++) { - if (16 > p) - a[p] = c[d + p] | 0; - else { - var k = a[p - 15], l = a[p - 2]; - a[p] = - (((k << 25) | (k >>> 7)) ^ ((k << 14) | (k >>> 18)) ^ (k >>> 3)) + - a[p - 7] + - (((l << 15) | (l >>> 17)) ^ ((l << 13) | (l >>> 19)) ^ (l >>> 10)) + - a[p - 16]; - } - k = - q + - (((h << 26) | (h >>> 6)) ^ ((h << 21) | (h >>> 11)) ^ ((h << 7) | (h >>> 25))) + - ((h & m) ^ (~h & n)) + - r[p] + - a[p]; - l = - (((e << 30) | (e >>> 2)) ^ ((e << 19) | (e >>> 13)) ^ ((e << 10) | (e >>> 22))) + - ((e & f) ^ (e & g) ^ (f & g)); - q = n; - n = m; - m = h; - h = (j + k) | 0; - j = g; - g = f; - f = e; - e = (k + l) | 0; - } - b[0] = (b[0] + e) | 0; - b[1] = (b[1] + f) | 0; - b[2] = (b[2] + g) | 0; - b[3] = (b[3] + j) | 0; - b[4] = (b[4] + h) | 0; - b[5] = (b[5] + m) | 0; - b[6] = (b[6] + n) | 0; - b[7] = (b[7] + q) | 0; - }, - _doFinalize: function () { - var a = this._data, d = a.words, b = 8 * this._nDataBytes, e = 8 * a.sigBytes; - d[e >>> 5] |= 128 << (24 - (e % 32)); - d[(((e + 64) >>> 9) << 4) + 14] = h.floor(b / 4294967296); - d[(((e + 64) >>> 9) << 4) + 15] = b; - a.sigBytes = 4 * d.length; - this._process(); - return this._hash; - }, - clone: function () { - var a = q.clone.call(this); - a._hash = this._hash.clone(); - return a; - }, - })); - s.SHA256 = q._createHelper(f); - s.HmacSHA256 = q._createHmacHelper(f); - })(Math); - // HMAC SHA256 - (function () { - var h = CryptoJS, s = h.enc.Utf8; - h.algo.HMAC = h.lib.Base.extend({ - init: function (f, g) { - f = this._hasher = new f.init(); - 'string' == typeof g && (g = s.parse(g)); - var h = f.blockSize, m = 4 * h; - g.sigBytes > m && (g = f.finalize(g)); - g.clamp(); - for (var r = (this._oKey = g.clone()), l = (this._iKey = g.clone()), k = r.words, n = l.words, j = 0; j < h; j++) - (k[j] ^= 1549556828), (n[j] ^= 909522486); - r.sigBytes = l.sigBytes = m; - this.reset(); - }, - reset: function () { - var f = this._hasher; - f.reset(); - f.update(this._iKey); - }, - update: function (f) { - this._hasher.update(f); - return this; - }, - finalize: function (f) { - var g = this._hasher; - f = g.finalize(f); - g.reset(); - return g.finalize(this._oKey.clone().concat(f)); - }, - }); - })(); - // Base64 - (function () { - var u = CryptoJS, p = u.lib.WordArray; - u.enc.Base64 = { - stringify: function (d) { - var l = d.words, p = d.sigBytes, t = this._map; - d.clamp(); - d = []; - for (var r = 0; r < p; r += 3) - for (var w = (((l[r >>> 2] >>> (24 - 8 * (r % 4))) & 255) << 16) | - (((l[(r + 1) >>> 2] >>> (24 - 8 * ((r + 1) % 4))) & 255) << 8) | - ((l[(r + 2) >>> 2] >>> (24 - 8 * ((r + 2) % 4))) & 255), v = 0; 4 > v && r + 0.75 * v < p; v++) - d.push(t.charAt((w >>> (6 * (3 - v))) & 63)); - if ((l = t.charAt(64))) - for (; d.length % 4;) - d.push(l); - return d.join(''); - }, - parse: function (d) { - var l = d.length, s = this._map, t = s.charAt(64); - t && ((t = d.indexOf(t)), -1 != t && (l = t)); - for (var t = [], r = 0, w = 0; w < l; w++) - if (w % 4) { - var v = s.indexOf(d.charAt(w - 1)) << (2 * (w % 4)), b = s.indexOf(d.charAt(w)) >>> (6 - 2 * (w % 4)); - t[r >>> 2] |= (v | b) << (24 - 8 * (r % 4)); - r++; - } - return p.create(t, r); - }, - _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=', - }; - })(); - // BlockCipher - (function (u) { - function p(b, n, a, c, e, j, k) { - b = b + ((n & a) | (~n & c)) + e + k; - return ((b << j) | (b >>> (32 - j))) + n; - } - function d(b, n, a, c, e, j, k) { - b = b + ((n & c) | (a & ~c)) + e + k; - return ((b << j) | (b >>> (32 - j))) + n; - } - function l(b, n, a, c, e, j, k) { - b = b + (n ^ a ^ c) + e + k; - return ((b << j) | (b >>> (32 - j))) + n; - } - function s(b, n, a, c, e, j, k) { - b = b + (a ^ (n | ~c)) + e + k; - return ((b << j) | (b >>> (32 - j))) + n; - } - for (var t = CryptoJS, r = t.lib, w = r.WordArray, v = r.Hasher, r = t.algo, b = [], x = 0; 64 > x; x++) - b[x] = (4294967296 * u.abs(u.sin(x + 1))) | 0; - r = r.MD5 = v.extend({ - _doReset: function () { - this._hash = new w.init([1732584193, 4023233417, 2562383102, 271733878]); - }, - _doProcessBlock: function (q, n) { - for (var a = 0; 16 > a; a++) { - var c = n + a, e = q[c]; - q[c] = (((e << 8) | (e >>> 24)) & 16711935) | (((e << 24) | (e >>> 8)) & 4278255360); - } - var a = this._hash.words, c = q[n + 0], e = q[n + 1], j = q[n + 2], k = q[n + 3], z = q[n + 4], r = q[n + 5], t = q[n + 6], w = q[n + 7], v = q[n + 8], A = q[n + 9], B = q[n + 10], C = q[n + 11], u = q[n + 12], D = q[n + 13], E = q[n + 14], x = q[n + 15], f = a[0], m = a[1], g = a[2], h = a[3], f = p(f, m, g, h, c, 7, b[0]), h = p(h, f, m, g, e, 12, b[1]), g = p(g, h, f, m, j, 17, b[2]), m = p(m, g, h, f, k, 22, b[3]), f = p(f, m, g, h, z, 7, b[4]), h = p(h, f, m, g, r, 12, b[5]), g = p(g, h, f, m, t, 17, b[6]), m = p(m, g, h, f, w, 22, b[7]), f = p(f, m, g, h, v, 7, b[8]), h = p(h, f, m, g, A, 12, b[9]), g = p(g, h, f, m, B, 17, b[10]), m = p(m, g, h, f, C, 22, b[11]), f = p(f, m, g, h, u, 7, b[12]), h = p(h, f, m, g, D, 12, b[13]), g = p(g, h, f, m, E, 17, b[14]), m = p(m, g, h, f, x, 22, b[15]), f = d(f, m, g, h, e, 5, b[16]), h = d(h, f, m, g, t, 9, b[17]), g = d(g, h, f, m, C, 14, b[18]), m = d(m, g, h, f, c, 20, b[19]), f = d(f, m, g, h, r, 5, b[20]), h = d(h, f, m, g, B, 9, b[21]), g = d(g, h, f, m, x, 14, b[22]), m = d(m, g, h, f, z, 20, b[23]), f = d(f, m, g, h, A, 5, b[24]), h = d(h, f, m, g, E, 9, b[25]), g = d(g, h, f, m, k, 14, b[26]), m = d(m, g, h, f, v, 20, b[27]), f = d(f, m, g, h, D, 5, b[28]), h = d(h, f, m, g, j, 9, b[29]), g = d(g, h, f, m, w, 14, b[30]), m = d(m, g, h, f, u, 20, b[31]), f = l(f, m, g, h, r, 4, b[32]), h = l(h, f, m, g, v, 11, b[33]), g = l(g, h, f, m, C, 16, b[34]), m = l(m, g, h, f, E, 23, b[35]), f = l(f, m, g, h, e, 4, b[36]), h = l(h, f, m, g, z, 11, b[37]), g = l(g, h, f, m, w, 16, b[38]), m = l(m, g, h, f, B, 23, b[39]), f = l(f, m, g, h, D, 4, b[40]), h = l(h, f, m, g, c, 11, b[41]), g = l(g, h, f, m, k, 16, b[42]), m = l(m, g, h, f, t, 23, b[43]), f = l(f, m, g, h, A, 4, b[44]), h = l(h, f, m, g, u, 11, b[45]), g = l(g, h, f, m, x, 16, b[46]), m = l(m, g, h, f, j, 23, b[47]), f = s(f, m, g, h, c, 6, b[48]), h = s(h, f, m, g, w, 10, b[49]), g = s(g, h, f, m, E, 15, b[50]), m = s(m, g, h, f, r, 21, b[51]), f = s(f, m, g, h, u, 6, b[52]), h = s(h, f, m, g, k, 10, b[53]), g = s(g, h, f, m, B, 15, b[54]), m = s(m, g, h, f, e, 21, b[55]), f = s(f, m, g, h, v, 6, b[56]), h = s(h, f, m, g, x, 10, b[57]), g = s(g, h, f, m, t, 15, b[58]), m = s(m, g, h, f, D, 21, b[59]), f = s(f, m, g, h, z, 6, b[60]), h = s(h, f, m, g, C, 10, b[61]), g = s(g, h, f, m, j, 15, b[62]), m = s(m, g, h, f, A, 21, b[63]); - a[0] = (a[0] + f) | 0; - a[1] = (a[1] + m) | 0; - a[2] = (a[2] + g) | 0; - a[3] = (a[3] + h) | 0; - }, - _doFinalize: function () { - var b = this._data, n = b.words, a = 8 * this._nDataBytes, c = 8 * b.sigBytes; - n[c >>> 5] |= 128 << (24 - (c % 32)); - var e = u.floor(a / 4294967296); - n[(((c + 64) >>> 9) << 4) + 15] = (((e << 8) | (e >>> 24)) & 16711935) | (((e << 24) | (e >>> 8)) & 4278255360); - n[(((c + 64) >>> 9) << 4) + 14] = (((a << 8) | (a >>> 24)) & 16711935) | (((a << 24) | (a >>> 8)) & 4278255360); - b.sigBytes = 4 * (n.length + 1); - this._process(); - b = this._hash; - n = b.words; - for (a = 0; 4 > a; a++) - (c = n[a]), (n[a] = (((c << 8) | (c >>> 24)) & 16711935) | (((c << 24) | (c >>> 8)) & 4278255360)); - return b; - }, - clone: function () { - var b = v.clone.call(this); - b._hash = this._hash.clone(); - return b; - }, - }); - t.MD5 = v._createHelper(r); - t.HmacMD5 = v._createHmacHelper(r); - })(Math); - (function () { - var u = CryptoJS, p = u.lib, d = p.Base, l = p.WordArray, p = u.algo, s = (p.EvpKDF = d.extend({ - cfg: d.extend({ keySize: 4, hasher: p.MD5, iterations: 1 }), - init: function (d) { - this.cfg = this.cfg.extend(d); - }, - compute: function (d, r) { - for (var p = this.cfg, s = p.hasher.create(), b = l.create(), u = b.words, q = p.keySize, p = p.iterations; u.length < q;) { - n && s.update(n); - var n = s.update(d).finalize(r); - s.reset(); - for (var a = 1; a < p; a++) - (n = s.finalize(n)), s.reset(); - b.concat(n); - } - b.sigBytes = 4 * q; - return b; - }, - })); - u.EvpKDF = function (d, l, p) { - return s.create(p).compute(d, l); - }; - })(); - // Cipher - CryptoJS.lib.Cipher || - (function (u) { - var p = CryptoJS, d = p.lib, l = d.Base, s = d.WordArray, t = d.BufferedBlockAlgorithm, r = p.enc.Base64, w = p.algo.EvpKDF, v = (d.Cipher = t.extend({ - cfg: l.extend(), - createEncryptor: function (e, a) { - return this.create(this._ENC_XFORM_MODE, e, a); - }, - createDecryptor: function (e, a) { - return this.create(this._DEC_XFORM_MODE, e, a); - }, - init: function (e, a, b) { - this.cfg = this.cfg.extend(b); - this._xformMode = e; - this._key = a; - this.reset(); - }, - reset: function () { - t.reset.call(this); - this._doReset(); - }, - process: function (e) { - this._append(e); - return this._process(); - }, - finalize: function (e) { - e && this._append(e); - return this._doFinalize(); - }, - keySize: 4, - ivSize: 4, - _ENC_XFORM_MODE: 1, - _DEC_XFORM_MODE: 2, - _createHelper: function (e) { - return { - encrypt: function (b, k, d) { - return ('string' == typeof k ? c : a).encrypt(e, b, k, d); - }, - decrypt: function (b, k, d) { - return ('string' == typeof k ? c : a).decrypt(e, b, k, d); - }, - }; - }, - })); - d.StreamCipher = v.extend({ - _doFinalize: function () { - return this._process(!0); - }, - blockSize: 1, - }); - var b = (p.mode = {}), x = function (e, a, b) { - var c = this._iv; - c ? (this._iv = u) : (c = this._prevBlock); - for (var d = 0; d < b; d++) - e[a + d] ^= c[d]; - }, q = (d.BlockCipherMode = l.extend({ - createEncryptor: function (e, a) { - return this.Encryptor.create(e, a); - }, - createDecryptor: function (e, a) { - return this.Decryptor.create(e, a); - }, - init: function (e, a) { - this._cipher = e; - this._iv = a; - }, - })).extend(); - q.Encryptor = q.extend({ - processBlock: function (e, a) { - var b = this._cipher, c = b.blockSize; - x.call(this, e, a, c); - b.encryptBlock(e, a); - this._prevBlock = e.slice(a, a + c); - }, - }); - q.Decryptor = q.extend({ - processBlock: function (e, a) { - var b = this._cipher, c = b.blockSize, d = e.slice(a, a + c); - b.decryptBlock(e, a); - x.call(this, e, a, c); - this._prevBlock = d; - }, - }); - b = b.CBC = q; - q = (p.pad = {}).Pkcs7 = { - pad: function (a, b) { - for (var c = 4 * b, c = c - (a.sigBytes % c), d = (c << 24) | (c << 16) | (c << 8) | c, l = [], n = 0; n < c; n += 4) - l.push(d); - c = s.create(l, c); - a.concat(c); - }, - unpad: function (a) { - a.sigBytes -= a.words[(a.sigBytes - 1) >>> 2] & 255; - }, - }; - d.BlockCipher = v.extend({ - cfg: v.cfg.extend({ mode: b, padding: q }), - reset: function () { - v.reset.call(this); - var a = this.cfg, b = a.iv, a = a.mode; - if (this._xformMode == this._ENC_XFORM_MODE) - var c = a.createEncryptor; - else - (c = a.createDecryptor), (this._minBufferSize = 1); - this._mode = c.call(a, this, b && b.words); - }, - _doProcessBlock: function (a, b) { - this._mode.processBlock(a, b); - }, - _doFinalize: function () { - var a = this.cfg.padding; - if (this._xformMode == this._ENC_XFORM_MODE) { - a.pad(this._data, this.blockSize); - var b = this._process(!0); - } - else - (b = this._process(!0)), a.unpad(b); - return b; - }, - blockSize: 4, - }); - var n = (d.CipherParams = l.extend({ - init: function (a) { - this.mixIn(a); - }, - toString: function (a) { - return (a || this.formatter).stringify(this); - }, - })), b = ((p.format = {}).OpenSSL = { - stringify: function (a) { - var b = a.ciphertext; - a = a.salt; - return (a ? s.create([1398893684, 1701076831]).concat(a).concat(b) : b).toString(r); - }, - parse: function (a) { - a = r.parse(a); - var b = a.words; - if (1398893684 == b[0] && 1701076831 == b[1]) { - var c = s.create(b.slice(2, 4)); - b.splice(0, 4); - a.sigBytes -= 16; - } - return n.create({ ciphertext: a, salt: c }); - }, - }), a = (d.SerializableCipher = l.extend({ - cfg: l.extend({ format: b }), - encrypt: function (a, b, c, d) { - d = this.cfg.extend(d); - var l = a.createEncryptor(c, d); - b = l.finalize(b); - l = l.cfg; - return n.create({ - ciphertext: b, - key: c, - iv: l.iv, - algorithm: a, - mode: l.mode, - padding: l.padding, - blockSize: a.blockSize, - formatter: d.format, - }); - }, - decrypt: function (a, b, c, d) { - d = this.cfg.extend(d); - b = this._parse(b, d.format); - return a.createDecryptor(c, d).finalize(b.ciphertext); - }, - _parse: function (a, b) { - return 'string' == typeof a ? b.parse(a, this) : a; - }, - })), p = ((p.kdf = {}).OpenSSL = { - execute: function (a, b, c, d) { - d || (d = s.random(8)); - a = w.create({ keySize: b + c }).compute(a, d); - c = s.create(a.words.slice(b), 4 * c); - a.sigBytes = 4 * b; - return n.create({ key: a, iv: c, salt: d }); - }, - }), c = (d.PasswordBasedCipher = a.extend({ - cfg: a.cfg.extend({ kdf: p }), - encrypt: function (b, c, d, l) { - l = this.cfg.extend(l); - d = l.kdf.execute(d, b.keySize, b.ivSize); - l.iv = d.iv; - b = a.encrypt.call(this, b, c, d.key, l); - b.mixIn(d); - return b; - }, - decrypt: function (b, c, d, l) { - l = this.cfg.extend(l); - c = this._parse(c, l.format); - d = l.kdf.execute(d, b.keySize, b.ivSize, c.salt); - l.iv = d.iv; - return a.decrypt.call(this, b, c, d.key, l); - }, - })); - })(); - // AES - (function () { - for (var u = CryptoJS, p = u.lib.BlockCipher, d = u.algo, l = [], s = [], t = [], r = [], w = [], v = [], b = [], x = [], q = [], n = [], a = [], c = 0; 256 > c; c++) - a[c] = 128 > c ? c << 1 : (c << 1) ^ 283; - for (var e = 0, j = 0, c = 0; 256 > c; c++) { - var k = j ^ (j << 1) ^ (j << 2) ^ (j << 3) ^ (j << 4), k = (k >>> 8) ^ (k & 255) ^ 99; - l[e] = k; - s[k] = e; - var z = a[e], F = a[z], G = a[F], y = (257 * a[k]) ^ (16843008 * k); - t[e] = (y << 24) | (y >>> 8); - r[e] = (y << 16) | (y >>> 16); - w[e] = (y << 8) | (y >>> 24); - v[e] = y; - y = (16843009 * G) ^ (65537 * F) ^ (257 * z) ^ (16843008 * e); - b[k] = (y << 24) | (y >>> 8); - x[k] = (y << 16) | (y >>> 16); - q[k] = (y << 8) | (y >>> 24); - n[k] = y; - e ? ((e = z ^ a[a[a[G ^ z]]]), (j ^= a[a[j]])) : (e = j = 1); - } - var H = [0, 1, 2, 4, 8, 16, 32, 64, 128, 27, 54], d = (d.AES = p.extend({ - _doReset: function () { - for (var a = this._key, c = a.words, d = a.sigBytes / 4, a = 4 * ((this._nRounds = d + 6) + 1), e = (this._keySchedule = []), j = 0; j < a; j++) - if (j < d) - e[j] = c[j]; - else { - var k = e[j - 1]; - j % d - ? 6 < d && - 4 == j % d && - (k = (l[k >>> 24] << 24) | (l[(k >>> 16) & 255] << 16) | (l[(k >>> 8) & 255] << 8) | l[k & 255]) - : ((k = (k << 8) | (k >>> 24)), - (k = (l[k >>> 24] << 24) | (l[(k >>> 16) & 255] << 16) | (l[(k >>> 8) & 255] << 8) | l[k & 255]), - (k ^= H[(j / d) | 0] << 24)); - e[j] = e[j - d] ^ k; - } - c = this._invKeySchedule = []; - for (d = 0; d < a; d++) - (j = a - d), - (k = d % 4 ? e[j] : e[j - 4]), - (c[d] = - 4 > d || 4 >= j ? k : b[l[k >>> 24]] ^ x[l[(k >>> 16) & 255]] ^ q[l[(k >>> 8) & 255]] ^ n[l[k & 255]]); - }, - encryptBlock: function (a, b) { - this._doCryptBlock(a, b, this._keySchedule, t, r, w, v, l); - }, - decryptBlock: function (a, c) { - var d = a[c + 1]; - a[c + 1] = a[c + 3]; - a[c + 3] = d; - this._doCryptBlock(a, c, this._invKeySchedule, b, x, q, n, s); - d = a[c + 1]; - a[c + 1] = a[c + 3]; - a[c + 3] = d; - }, - _doCryptBlock: function (a, b, c, d, e, j, l, f) { - for (var m = this._nRounds, g = a[b] ^ c[0], h = a[b + 1] ^ c[1], k = a[b + 2] ^ c[2], n = a[b + 3] ^ c[3], p = 4, r = 1; r < m; r++) - var q = d[g >>> 24] ^ e[(h >>> 16) & 255] ^ j[(k >>> 8) & 255] ^ l[n & 255] ^ c[p++], s = d[h >>> 24] ^ e[(k >>> 16) & 255] ^ j[(n >>> 8) & 255] ^ l[g & 255] ^ c[p++], t = d[k >>> 24] ^ e[(n >>> 16) & 255] ^ j[(g >>> 8) & 255] ^ l[h & 255] ^ c[p++], n = d[n >>> 24] ^ e[(g >>> 16) & 255] ^ j[(h >>> 8) & 255] ^ l[k & 255] ^ c[p++], g = q, h = s, k = t; - q = ((f[g >>> 24] << 24) | (f[(h >>> 16) & 255] << 16) | (f[(k >>> 8) & 255] << 8) | f[n & 255]) ^ c[p++]; - s = ((f[h >>> 24] << 24) | (f[(k >>> 16) & 255] << 16) | (f[(n >>> 8) & 255] << 8) | f[g & 255]) ^ c[p++]; - t = ((f[k >>> 24] << 24) | (f[(n >>> 16) & 255] << 16) | (f[(g >>> 8) & 255] << 8) | f[h & 255]) ^ c[p++]; - n = ((f[n >>> 24] << 24) | (f[(g >>> 16) & 255] << 16) | (f[(h >>> 8) & 255] << 8) | f[k & 255]) ^ c[p++]; - a[b] = q; - a[b + 1] = s; - a[b + 2] = t; - a[b + 3] = n; - }, - keySize: 8, - })); - u.AES = p._createHelper(d); - })(); - // Mode ECB - CryptoJS.mode.ECB = (function () { - var ECB = CryptoJS.lib.BlockCipherMode.extend(); - ECB.Encryptor = ECB.extend({ - processBlock: function (words, offset) { - this._cipher.encryptBlock(words, offset); - }, - }); - ECB.Decryptor = ECB.extend({ - processBlock: function (words, offset) { - this._cipher.decryptBlock(words, offset); - }, - }); - return ECB; - })(); - var hmacSha256 = CryptoJS; - - function bufferToWordArray(b) { - var wa = []; - var i; - for (i = 0; i < b.length; i += 1) { - wa[(i / 4) | 0] |= b[i] << (24 - 8 * i); - } - return hmacSha256.lib.WordArray.create(wa, b.length); - } - var default_1$a = /** @class */ (function () { - function default_1(_a) { - var config = _a.config; - this._config = config; - this._iv = '0123456789012345'; - this._allowedKeyEncodings = ['hex', 'utf8', 'base64', 'binary']; - this._allowedKeyLengths = [128, 256]; - this._allowedModes = ['ecb', 'cbc']; - this._defaultOptions = { - encryptKey: true, - keyEncoding: 'utf8', - keyLength: 256, - mode: 'cbc', - }; - } - default_1.prototype.HMACSHA256 = function (data) { - var hash = hmacSha256.HmacSHA256(data, this._config.secretKey); - return hash.toString(hmacSha256.enc.Base64); - }; - default_1.prototype.SHA256 = function (s) { - return hmacSha256.SHA256(s).toString(hmacSha256.enc.Hex); - }; - default_1.prototype._parseOptions = function (incomingOptions) { - // Defaults - var options = incomingOptions || {}; - if (!options.hasOwnProperty('encryptKey')) - options.encryptKey = this._defaultOptions.encryptKey; - if (!options.hasOwnProperty('keyEncoding')) - options.keyEncoding = this._defaultOptions.keyEncoding; - if (!options.hasOwnProperty('keyLength')) - options.keyLength = this._defaultOptions.keyLength; - if (!options.hasOwnProperty('mode')) - options.mode = this._defaultOptions.mode; - // Validation - if (this._allowedKeyEncodings.indexOf(options.keyEncoding.toLowerCase()) === -1) { - options.keyEncoding = this._defaultOptions.keyEncoding; - } - if (this._allowedKeyLengths.indexOf(parseInt(options.keyLength, 10)) === -1) { - options.keyLength = this._defaultOptions.keyLength; - } - if (this._allowedModes.indexOf(options.mode.toLowerCase()) === -1) { - options.mode = this._defaultOptions.mode; - } - return options; - }; - default_1.prototype._decodeKey = function (key, options) { - if (options.keyEncoding === 'base64') { - return hmacSha256.enc.Base64.parse(key); - } - if (options.keyEncoding === 'hex') { - return hmacSha256.enc.Hex.parse(key); - } - return key; - }; - default_1.prototype._getPaddedKey = function (key, options) { - key = this._decodeKey(key, options); - if (options.encryptKey) { - return hmacSha256.enc.Utf8.parse(this.SHA256(key).slice(0, 32)); - } - return key; - }; - default_1.prototype._getMode = function (options) { - if (options.mode === 'ecb') { - return hmacSha256.mode.ECB; - } - return hmacSha256.mode.CBC; - }; - default_1.prototype._getIV = function (options) { - return options.mode === 'cbc' ? hmacSha256.enc.Utf8.parse(this._iv) : null; - }; - default_1.prototype._getRandomIV = function () { - return hmacSha256.lib.WordArray.random(16); - }; - default_1.prototype.encrypt = function (data, customCipherKey, options) { - if (this._config.customEncrypt) { - return this._config.customEncrypt(data); - } - return this.pnEncrypt(data, customCipherKey, options); - }; - default_1.prototype.decrypt = function (data, customCipherKey, options) { - if (this._config.customDecrypt) { - return this._config.customDecrypt(data); - } - return this.pnDecrypt(data, customCipherKey, options); - }; - default_1.prototype.pnEncrypt = function (data, customCipherKey, options) { - if (!customCipherKey && !this._config.cipherKey) - return data; - options = this._parseOptions(options); - var mode = this._getMode(options); - var cipherKey = this._getPaddedKey(customCipherKey || this._config.cipherKey, options); - if (this._config.useRandomIVs) { - var waIv = this._getRandomIV(); - var waPayload = hmacSha256.AES.encrypt(data, cipherKey, { iv: waIv, mode: mode }).ciphertext; - return waIv.clone().concat(waPayload.clone()).toString(hmacSha256.enc.Base64); - } - var iv = this._getIV(options); - var encryptedHexArray = hmacSha256.AES.encrypt(data, cipherKey, { iv: iv, mode: mode }).ciphertext; - var base64Encrypted = encryptedHexArray.toString(hmacSha256.enc.Base64); - return base64Encrypted || data; - }; - default_1.prototype.pnDecrypt = function (data, customCipherKey, options) { - if (!customCipherKey && !this._config.cipherKey) - return data; - options = this._parseOptions(options); - var mode = this._getMode(options); - var cipherKey = this._getPaddedKey(customCipherKey || this._config.cipherKey, options); - if (this._config.useRandomIVs) { - var ciphertext = new Uint8ClampedArray(decode$1(data)); - var iv = bufferToWordArray(ciphertext.slice(0, 16)); - var payload = bufferToWordArray(ciphertext.slice(16)); - try { - var plainJSON = hmacSha256.AES.decrypt({ ciphertext: payload }, cipherKey, { iv: iv, mode: mode }).toString(hmacSha256.enc.Utf8); - var plaintext = JSON.parse(plainJSON); - return plaintext; - } - catch (e) { - return null; - } - } - else { - var iv = this._getIV(options); - try { - var ciphertext = hmacSha256.enc.Base64.parse(data); - var plainJSON = hmacSha256.AES.decrypt({ ciphertext: ciphertext }, cipherKey, { iv: iv, mode: mode }).toString(hmacSha256.enc.Utf8); - var plaintext = JSON.parse(plainJSON); - return plaintext; - } - catch (e) { - return null; - } - } - }; - return default_1; - }()); - - var default_1$9 = /** @class */ (function () { - function default_1(_a) { - var timeEndpoint = _a.timeEndpoint; - this._timeEndpoint = timeEndpoint; - } - default_1.prototype.onReconnection = function (reconnectionCallback) { - this._reconnectionCallback = reconnectionCallback; - }; - default_1.prototype.startPolling = function () { - this._timeTimer = setInterval(this._performTimeLoop.bind(this), 3000); - }; - default_1.prototype.stopPolling = function () { - clearInterval(this._timeTimer); - }; - default_1.prototype._performTimeLoop = function () { - var _this = this; - this._timeEndpoint(function (status) { - if (!status.error) { - clearInterval(_this._timeTimer); - _this._reconnectionCallback(); - } - }); - }; - return default_1; - }()); - - /* */ - var hashCode = function (payload) { - var hash = 0; - if (payload.length === 0) - return hash; - for (var i = 0; i < payload.length; i += 1) { - var character = payload.charCodeAt(i); - hash = (hash << 5) - hash + character; // eslint-disable-line - hash = hash & hash; // eslint-disable-line - } - return hash; - }; - var default_1$8 = /** @class */ (function () { - function default_1(_a) { - var config = _a.config; - this.hashHistory = []; - this._config = config; - } - default_1.prototype.getKey = function (message) { - var hashedPayload = hashCode(JSON.stringify(message.payload)).toString(); - var timetoken = message.publishMetaData.publishTimetoken; - return "".concat(timetoken, "-").concat(hashedPayload); - }; - default_1.prototype.isDuplicate = function (message) { - return this.hashHistory.includes(this.getKey(message)); - }; - default_1.prototype.addEntry = function (message) { - if (this.hashHistory.length >= this._config.maximumCacheSize) { - this.hashHistory.shift(); - } - this.hashHistory.push(this.getKey(message)); - }; - default_1.prototype.clearHistory = function () { - this.hashHistory = []; - }; - return default_1; - }()); - - /* */ - var categories = { - // SDK will announce when the network appears to be connected again. - PNNetworkUpCategory: 'PNNetworkUpCategory', - // SDK will announce when the network appears to down. - PNNetworkDownCategory: 'PNNetworkDownCategory', - // call failed when network was unable to complete the call. - PNNetworkIssuesCategory: 'PNNetworkIssuesCategory', - // network call timed out - PNTimeoutCategory: 'PNTimeoutCategory', - // server responded with bad response - PNBadRequestCategory: 'PNBadRequestCategory', - // server responded with access denied - PNAccessDeniedCategory: 'PNAccessDeniedCategory', - // something strange happened; please check the logs. - PNUnknownCategory: 'PNUnknownCategory', - // on reconnection - PNReconnectedCategory: 'PNReconnectedCategory', - PNConnectedCategory: 'PNConnectedCategory', - PNRequestMessageCountExceededCategory: 'PNRequestMessageCountExceededCategory', - PNDisconnectedCategory: 'PNDisconnectedCategory', - PNConnectionErrorCategory: 'PNConnectionErrorCategory', - PNDisconnectedUnexpectedlyCategory: 'PNDisconnectedUnexpectedlyCategory', - }; - - var default_1$7 = /** @class */ (function () { - function default_1(_a) { - var subscribeEndpoint = _a.subscribeEndpoint, leaveEndpoint = _a.leaveEndpoint, heartbeatEndpoint = _a.heartbeatEndpoint, setStateEndpoint = _a.setStateEndpoint, timeEndpoint = _a.timeEndpoint, getFileUrl = _a.getFileUrl, config = _a.config, crypto = _a.crypto, listenerManager = _a.listenerManager, cryptoModule = _a.cryptoModule, eventEmitter = _a.eventEmitter; - this._listenerManager = listenerManager; - this._config = config; - this._leaveEndpoint = leaveEndpoint; - this._heartbeatEndpoint = heartbeatEndpoint; - this._setStateEndpoint = setStateEndpoint; - this._subscribeEndpoint = subscribeEndpoint; - this._getFileUrl = getFileUrl; - this._crypto = crypto; - this._cryptoModule = cryptoModule; - this._channels = {}; - this._presenceChannels = {}; - this._heartbeatChannels = {}; - this._heartbeatChannelGroups = {}; - this._channelGroups = {}; - this._presenceChannelGroups = {}; - this._pendingChannelSubscriptions = []; - this._pendingChannelGroupSubscriptions = []; - this._currentTimetoken = 0; - this._lastTimetoken = 0; - this._storedTimetoken = null; - this._subscriptionStatusAnnounced = false; - this._isOnline = true; - this._reconnectionManager = new default_1$9({ timeEndpoint: timeEndpoint }); - this._dedupingManager = new default_1$8({ config: config }); - if (this._cryptoModule) - this._decoder = new TextDecoder(); - this._eventEmitter = eventEmitter; - } - default_1.prototype.adaptStateChange = function (args, callback) { - var _this = this; - var state = args.state, _a = args.channels, channels = _a === void 0 ? [] : _a, _b = args.channelGroups, channelGroups = _b === void 0 ? [] : _b, _c = args.withHeartbeat, withHeartbeat = _c === void 0 ? false : _c; - channels.forEach(function (channel) { - if (channel in _this._channels) - _this._channels[channel].state = state; - }); - channelGroups.forEach(function (channelGroup) { - if (channelGroup in _this._channelGroups) { - _this._channelGroups[channelGroup].state = state; - } - }); - if (withHeartbeat) { - var presenceState_1 = {}; - channels.forEach(function (channel) { return (presenceState_1[channel] = state); }); - channelGroups.forEach(function (group) { return (presenceState_1[group] = state); }); - return this._heartbeatEndpoint({ channels: channels, channelGroups: channelGroups, state: presenceState_1 }, callback); - } - return this._setStateEndpoint({ state: state, channels: channels, channelGroups: channelGroups }, callback); - }; - default_1.prototype.adaptPresenceChange = function (args) { - var _this = this; - var connected = args.connected, _a = args.channels, channels = _a === void 0 ? [] : _a, _b = args.channelGroups, channelGroups = _b === void 0 ? [] : _b; - if (connected) { - channels.forEach(function (channel) { - _this._heartbeatChannels[channel] = { state: {} }; - }); - channelGroups.forEach(function (channelGroup) { - _this._heartbeatChannelGroups[channelGroup] = { state: {} }; - }); - } - else { - channels.forEach(function (channel) { - if (channel in _this._heartbeatChannels) { - delete _this._heartbeatChannels[channel]; - } - }); - channelGroups.forEach(function (channelGroup) { - if (channelGroup in _this._heartbeatChannelGroups) { - delete _this._heartbeatChannelGroups[channelGroup]; - } - }); - if (this._config.suppressLeaveEvents === false) { - this._leaveEndpoint({ channels: channels, channelGroups: channelGroups }, function (status) { - _this._listenerManager.announceStatus(status); - }); - } - } - this.reconnect(); - }; - default_1.prototype.adaptSubscribeChange = function (args) { - var _this = this; - var timetoken = args.timetoken, _a = args.channels, channels = _a === void 0 ? [] : _a, _b = args.channelGroups, channelGroups = _b === void 0 ? [] : _b, _c = args.withPresence, withPresence = _c === void 0 ? false : _c, _d = args.withHeartbeats, withHeartbeats = _d === void 0 ? false : _d; - if (!this._config.subscribeKey || this._config.subscribeKey === '') { - // eslint-disable-next-line - if (console && console.log) { - console.log('subscribe key missing; aborting subscribe'); //eslint-disable-line - } - return; - } - if (timetoken) { - this._lastTimetoken = this._currentTimetoken; - this._currentTimetoken = timetoken; - } - // reset the current timetoken to get a connect event. - // $FlowFixMe - if (this._currentTimetoken !== '0' && this._currentTimetoken !== 0) { - this._storedTimetoken = this._currentTimetoken; - this._currentTimetoken = 0; - } - channels.forEach(function (channel) { - _this._channels[channel] = { state: {} }; - if (withPresence) - _this._presenceChannels[channel] = {}; - if (withHeartbeats || _this._config.getHeartbeatInterval()) - _this._heartbeatChannels[channel] = {}; - _this._pendingChannelSubscriptions.push(channel); - }); - channelGroups.forEach(function (channelGroup) { - _this._channelGroups[channelGroup] = { state: {} }; - if (withPresence) - _this._presenceChannelGroups[channelGroup] = {}; - if (withHeartbeats || _this._config.getHeartbeatInterval()) - _this._heartbeatChannelGroups[channelGroup] = {}; - _this._pendingChannelGroupSubscriptions.push(channelGroup); - }); - this._subscriptionStatusAnnounced = false; - this.reconnect(); - }; - default_1.prototype.adaptUnsubscribeChange = function (args, isOffline) { - var _this = this; - var _a = args.channels, channels = _a === void 0 ? [] : _a, _b = args.channelGroups, channelGroups = _b === void 0 ? [] : _b; - // keep track of which channels and channel groups - // we are going to unsubscribe from. - var actualChannels = []; - var actualChannelGroups = []; - // - channels.forEach(function (channel) { - if (channel in _this._channels) { - delete _this._channels[channel]; - actualChannels.push(channel); - if (channel in _this._heartbeatChannels) { - delete _this._heartbeatChannels[channel]; - } - } - if (channel in _this._presenceChannels) { - delete _this._presenceChannels[channel]; - actualChannels.push(channel); - } - }); - channelGroups.forEach(function (channelGroup) { - if (channelGroup in _this._channelGroups) { - delete _this._channelGroups[channelGroup]; - actualChannelGroups.push(channelGroup); - if (channelGroup in _this._heartbeatChannelGroups) { - delete _this._heartbeatChannelGroups[channelGroup]; - } - } - if (channelGroup in _this._presenceChannelGroups) { - delete _this._presenceChannelGroups[channelGroup]; - actualChannelGroups.push(channelGroup); - } - }); - // no-op if there are no channels and cg's to unsubscribe from. - if (actualChannels.length === 0 && actualChannelGroups.length === 0) { - return; - } - if (this._config.suppressLeaveEvents === false && !isOffline) { - this._leaveEndpoint({ channels: actualChannels, channelGroups: actualChannelGroups }, function (status) { - status.affectedChannels = actualChannels; - status.affectedChannelGroups = actualChannelGroups; - status.currentTimetoken = _this._currentTimetoken; - status.lastTimetoken = _this._lastTimetoken; - _this._listenerManager.announceStatus(status); - }); - } - // if we have nothing to subscribe to, reset the timetoken. - if (Object.keys(this._channels).length === 0 && - Object.keys(this._presenceChannels).length === 0 && - Object.keys(this._channelGroups).length === 0 && - Object.keys(this._presenceChannelGroups).length === 0) { - this._lastTimetoken = 0; - this._currentTimetoken = 0; - this._storedTimetoken = null; - this._region = null; - this._reconnectionManager.stopPolling(); - } - this.reconnect(); - }; - default_1.prototype.unsubscribeAll = function (isOffline) { - this.adaptUnsubscribeChange({ - channels: this.getSubscribedChannels(), - channelGroups: this.getSubscribedChannelGroups(), - }, isOffline); - }; - default_1.prototype.getHeartbeatChannels = function () { - return Object.keys(this._heartbeatChannels); - }; - default_1.prototype.getHeartbeatChannelGroups = function () { - return Object.keys(this._heartbeatChannelGroups); - }; - default_1.prototype.getSubscribedChannels = function () { - return Object.keys(this._channels); - }; - default_1.prototype.getSubscribedChannelGroups = function () { - return Object.keys(this._channelGroups); - }; - default_1.prototype.reconnect = function () { - this._startSubscribeLoop(); - this._registerHeartbeatTimer(); - }; - default_1.prototype.disconnect = function () { - this._stopSubscribeLoop(); - this._stopHeartbeatTimer(); - this._reconnectionManager.stopPolling(); - }; - default_1.prototype._registerHeartbeatTimer = function () { - this._stopHeartbeatTimer(); - // if the interval is 0 or undefined, do not queue up heartbeating - if (this._config.getHeartbeatInterval() === 0 || this._config.getHeartbeatInterval() === undefined) { - return; - } - this._performHeartbeatLoop(); - // $FlowFixMe - this._heartbeatTimer = setInterval(this._performHeartbeatLoop.bind(this), this._config.getHeartbeatInterval() * 1000); - }; - default_1.prototype._stopHeartbeatTimer = function () { - if (this._heartbeatTimer) { - // $FlowFixMe - clearInterval(this._heartbeatTimer); - this._heartbeatTimer = null; - } - }; - default_1.prototype._performHeartbeatLoop = function () { - var _this = this; - var heartbeatChannels = this.getHeartbeatChannels(); - var heartbeatChannelGroups = this.getHeartbeatChannelGroups(); - var presenceState = {}; - if (heartbeatChannels.length === 0 && heartbeatChannelGroups.length === 0) { - return; - } - this.getSubscribedChannels().forEach(function (channel) { - var channelState = _this._channels[channel].state; - if (Object.keys(channelState).length) { - presenceState[channel] = channelState; - } - }); - this.getSubscribedChannelGroups().forEach(function (channelGroup) { - var channelGroupState = _this._channelGroups[channelGroup].state; - if (Object.keys(channelGroupState).length) { - presenceState[channelGroup] = channelGroupState; - } - }); - var onHeartbeat = function (status) { - if (status.error && _this._config.announceFailedHeartbeats) { - _this._listenerManager.announceStatus(status); - } - if (status.error && _this._config.autoNetworkDetection && _this._isOnline) { - _this._isOnline = false; - _this.disconnect(); - _this._listenerManager.announceNetworkDown(); - _this.reconnect(); - } - if (!status.error && _this._config.announceSuccessfulHeartbeats) { - _this._listenerManager.announceStatus(status); - } - }; - this._heartbeatEndpoint({ - channels: heartbeatChannels, - channelGroups: heartbeatChannelGroups, - state: presenceState, - }, onHeartbeat.bind(this)); - }; - default_1.prototype._startSubscribeLoop = function () { - var _this = this; - this._stopSubscribeLoop(); - var presenceState = {}; - var channels = []; - var channelGroups = []; - Object.keys(this._channels).forEach(function (channel) { - var channelState = _this._channels[channel].state; - if (Object.keys(channelState).length) { - presenceState[channel] = channelState; - } - channels.push(channel); - }); - Object.keys(this._presenceChannels).forEach(function (channel) { - channels.push("".concat(channel, "-pnpres")); - }); - Object.keys(this._channelGroups).forEach(function (channelGroup) { - var channelGroupState = _this._channelGroups[channelGroup].state; - if (Object.keys(channelGroupState).length) { - presenceState[channelGroup] = channelGroupState; - } - channelGroups.push(channelGroup); - }); - Object.keys(this._presenceChannelGroups).forEach(function (channelGroup) { - channelGroups.push("".concat(channelGroup, "-pnpres")); - }); - if (channels.length === 0 && channelGroups.length === 0) { - return; - } - var subscribeArgs = { - channels: channels, - channelGroups: channelGroups, - state: presenceState, - timetoken: this._currentTimetoken, - filterExpression: this._config.filterExpression, - region: this._region, - }; - this._subscribeCall = this._subscribeEndpoint(subscribeArgs, this._processSubscribeResponse.bind(this)); - }; - default_1.prototype._processSubscribeResponse = function (status, payload) { - var _this = this; - if (status.error) { - // if error comes from request abort, ignore - if (status.errorData && status.errorData.message === 'Aborted') { - return; - } - // if we timeout from server, restart the loop. - if (status.category === categories.PNTimeoutCategory) { - this._startSubscribeLoop(); - } - else if (status.category === categories.PNNetworkIssuesCategory) { - // we lost internet connection, alert the reconnection manager and terminate all loops - this.disconnect(); - if (status.error && this._config.autoNetworkDetection && this._isOnline) { - this._isOnline = false; - this._listenerManager.announceNetworkDown(); - } - this._reconnectionManager.onReconnection(function () { - if (_this._config.autoNetworkDetection && !_this._isOnline) { - _this._isOnline = true; - _this._listenerManager.announceNetworkUp(); - } - _this.reconnect(); - _this._subscriptionStatusAnnounced = true; - var reconnectedAnnounce = { - category: categories.PNReconnectedCategory, - operation: status.operation, - lastTimetoken: _this._lastTimetoken, - currentTimetoken: _this._currentTimetoken, - }; - _this._listenerManager.announceStatus(reconnectedAnnounce); - }); - this._reconnectionManager.startPolling(); - this._listenerManager.announceStatus(status); - } - else if (status.category === categories.PNBadRequestCategory) { - this._stopHeartbeatTimer(); - this._listenerManager.announceStatus(status); - } - else { - this._listenerManager.announceStatus(status); - } - return; - } - if (this._storedTimetoken) { - this._currentTimetoken = this._storedTimetoken; - this._storedTimetoken = null; - } - else { - this._lastTimetoken = this._currentTimetoken; - this._currentTimetoken = payload.metadata.timetoken; - } - if (!this._subscriptionStatusAnnounced) { - var connectedAnnounce = {}; - connectedAnnounce.category = categories.PNConnectedCategory; - connectedAnnounce.operation = status.operation; - connectedAnnounce.affectedChannels = this._pendingChannelSubscriptions; - connectedAnnounce.subscribedChannels = this.getSubscribedChannels(); - connectedAnnounce.affectedChannelGroups = this._pendingChannelGroupSubscriptions; - connectedAnnounce.lastTimetoken = this._lastTimetoken; - connectedAnnounce.currentTimetoken = this._currentTimetoken; - this._subscriptionStatusAnnounced = true; - this._listenerManager.announceStatus(connectedAnnounce); - // clear the pending connections list - this._pendingChannelSubscriptions = []; - this._pendingChannelGroupSubscriptions = []; - } - var messages = payload.messages || []; - var _a = this._config, requestMessageCountThreshold = _a.requestMessageCountThreshold, dedupeOnSubscribe = _a.dedupeOnSubscribe; - if (requestMessageCountThreshold && messages.length >= requestMessageCountThreshold) { - var countAnnouncement = {}; - countAnnouncement.category = categories.PNRequestMessageCountExceededCategory; - countAnnouncement.operation = status.operation; - this._listenerManager.announceStatus(countAnnouncement); - } - messages.forEach(function (message) { - message.channel; - message.subscriptionMatch; - if (dedupeOnSubscribe) { - if (_this._dedupingManager.isDuplicate(message)) { - return; - } - _this._dedupingManager.addEntry(message); - } - _this._eventEmitter.emitEvent(message); - }); - this._region = payload.metadata.region; - this._startSubscribeLoop(); - }; - default_1.prototype._stopSubscribeLoop = function () { - if (this._subscribeCall) { - if (typeof this._subscribeCall.abort === 'function') { - this._subscribeCall.abort(); - } - this._subscribeCall = null; - } - }; - default_1.prototype._renameEvent = function (e) { - return e === 'set' ? 'updated' : 'removed'; - }; - default_1.prototype._renameChannelField = function (announce) { - var channel = announce.channel, eventData = __rest(announce, ["channel"]); - eventData.spaceId = channel; - return eventData; - }; - return default_1; - }()); - - /* */ - var OPERATIONS = { - PNTimeOperation: 'PNTimeOperation', - PNHistoryOperation: 'PNHistoryOperation', - PNDeleteMessagesOperation: 'PNDeleteMessagesOperation', - PNFetchMessagesOperation: 'PNFetchMessagesOperation', - PNMessageCounts: 'PNMessageCountsOperation', - // pubsub - PNSubscribeOperation: 'PNSubscribeOperation', - PNUnsubscribeOperation: 'PNUnsubscribeOperation', - PNPublishOperation: 'PNPublishOperation', - PNSignalOperation: 'PNSignalOperation', - // Actions API - PNAddMessageActionOperation: 'PNAddActionOperation', - PNRemoveMessageActionOperation: 'PNRemoveMessageActionOperation', - PNGetMessageActionsOperation: 'PNGetMessageActionsOperation', - // Objects API - PNCreateUserOperation: 'PNCreateUserOperation', - PNUpdateUserOperation: 'PNUpdateUserOperation', - PNDeleteUserOperation: 'PNDeleteUserOperation', - PNGetUserOperation: 'PNGetUsersOperation', - PNGetUsersOperation: 'PNGetUsersOperation', - PNCreateSpaceOperation: 'PNCreateSpaceOperation', - PNUpdateSpaceOperation: 'PNUpdateSpaceOperation', - PNDeleteSpaceOperation: 'PNDeleteSpaceOperation', - PNGetSpaceOperation: 'PNGetSpacesOperation', - PNGetSpacesOperation: 'PNGetSpacesOperation', - PNGetMembersOperation: 'PNGetMembersOperation', - PNUpdateMembersOperation: 'PNUpdateMembersOperation', - PNGetMembershipsOperation: 'PNGetMembershipsOperation', - PNUpdateMembershipsOperation: 'PNUpdateMembershipsOperation', - // File Upload API v1 - PNListFilesOperation: 'PNListFilesOperation', - PNGenerateUploadUrlOperation: 'PNGenerateUploadUrlOperation', - PNPublishFileOperation: 'PNPublishFileOperation', - PNGetFileUrlOperation: 'PNGetFileUrlOperation', - PNDownloadFileOperation: 'PNDownloadFileOperation', - // Objects API v2 - // UUID - PNGetAllUUIDMetadataOperation: 'PNGetAllUUIDMetadataOperation', - PNGetUUIDMetadataOperation: 'PNGetUUIDMetadataOperation', - PNSetUUIDMetadataOperation: 'PNSetUUIDMetadataOperation', - PNRemoveUUIDMetadataOperation: 'PNRemoveUUIDMetadataOperation', - // channel - PNGetAllChannelMetadataOperation: 'PNGetAllChannelMetadataOperation', - PNGetChannelMetadataOperation: 'PNGetChannelMetadataOperation', - PNSetChannelMetadataOperation: 'PNSetChannelMetadataOperation', - PNRemoveChannelMetadataOperation: 'PNRemoveChannelMetadataOperation', - // member - // PNGetMembersOperation: 'PNGetMembersOperation', - PNSetMembersOperation: 'PNSetMembersOperation', - // PNGetMembershipsOperation: 'PNGetMembersOperation', - PNSetMembershipsOperation: 'PNSetMembershipsOperation', - // push - PNPushNotificationEnabledChannelsOperation: 'PNPushNotificationEnabledChannelsOperation', - PNRemoveAllPushNotificationsOperation: 'PNRemoveAllPushNotificationsOperation', - // - // presence - PNWhereNowOperation: 'PNWhereNowOperation', - PNSetStateOperation: 'PNSetStateOperation', - PNHereNowOperation: 'PNHereNowOperation', - PNGetStateOperation: 'PNGetStateOperation', - PNHeartbeatOperation: 'PNHeartbeatOperation', - // - // channel group - PNChannelGroupsOperation: 'PNChannelGroupsOperation', - PNRemoveGroupOperation: 'PNRemoveGroupOperation', - PNChannelsForGroupOperation: 'PNChannelsForGroupOperation', - PNAddChannelsToGroupOperation: 'PNAddChannelsToGroupOperation', - PNRemoveChannelsFromGroupOperation: 'PNRemoveChannelsFromGroupOperation', - // - // PAM - PNAccessManagerGrant: 'PNAccessManagerGrant', - PNAccessManagerGrantToken: 'PNAccessManagerGrantToken', - PNAccessManagerAudit: 'PNAccessManagerAudit', - PNAccessManagerRevokeToken: 'PNAccessManagerRevokeToken', - // - // subscription utilities - PNHandshakeOperation: 'PNHandshakeOperation', - PNReceiveMessagesOperation: 'PNReceiveMessagesOperation', - }; - - /* */ - var default_1$6 = /** @class */ (function () { - function default_1(configuration) { - this._maximumSamplesCount = 100; - this._trackedLatencies = {}; - this._latencies = {}; - this._telemetryExcludeOperations = [ - OPERATIONS.PNSubscribeOperation, - OPERATIONS.PNReceiveMessagesOperation, - OPERATIONS.PNHandshakeOperation, - ]; - this._maximumSamplesCount = configuration.maximumSamplesCount || this._maximumSamplesCount; - } - /** - * Compose object with latency information of recently used API endpoints. - * - * @return {Object} Object with request query key/value pairs. - */ - default_1.prototype.operationsLatencyForRequest = function () { - var _this = this; - var latencies = {}; - Object.keys(this._latencies).forEach(function (endpointName) { - var operationLatencies = _this._latencies[endpointName]; - var averageLatency = _this._averageLatency(operationLatencies); - if (averageLatency > 0) { - latencies["l_".concat(endpointName)] = averageLatency; - } - }); - return latencies; - }; - default_1.prototype.startLatencyMeasure = function (operationType, identifier) { - if (this._telemetryExcludeOperations.includes(operationType) || !identifier) { - return; - } - this._trackedLatencies[identifier] = Date.now(); - }; - default_1.prototype.stopLatencyMeasure = function (operationType, identifier) { - if (this._telemetryExcludeOperations.includes(operationType) || !identifier) { - return; - } - var endpointName = this._endpointName(operationType); - /** @type Array */ - var endpointLatencies = this._latencies[endpointName]; - var startDate = this._trackedLatencies[identifier]; - if (!endpointLatencies) { - this._latencies[endpointName] = []; - endpointLatencies = this._latencies[endpointName]; - } - endpointLatencies.push(Date.now() - startDate); - // Truncate samples count if there is more then configured. - if (endpointLatencies.length > this._maximumSamplesCount) { - endpointLatencies.splice(0, endpointLatencies.length - this._maximumSamplesCount); - } - delete this._trackedLatencies[identifier]; - }; - default_1.prototype._averageLatency = function (latencies) { - var arrayReduce = function (accumulatedLatency, latency) { return accumulatedLatency + latency; }; - return Math.floor(latencies.reduce(arrayReduce, 0) / latencies.length); - }; - default_1.prototype._endpointName = function (operationType) { - var operation = null; - switch (operationType) { - case OPERATIONS.PNPublishOperation: - operation = 'pub'; - break; - case OPERATIONS.PNSignalOperation: - operation = 'sig'; - break; - case OPERATIONS.PNHistoryOperation: - case OPERATIONS.PNFetchMessagesOperation: - case OPERATIONS.PNDeleteMessagesOperation: - case OPERATIONS.PNMessageCounts: - operation = 'hist'; - break; - case OPERATIONS.PNUnsubscribeOperation: - case OPERATIONS.PNWhereNowOperation: - case OPERATIONS.PNHereNowOperation: - case OPERATIONS.PNHeartbeatOperation: - case OPERATIONS.PNSetStateOperation: - case OPERATIONS.PNGetStateOperation: - operation = 'pres'; - break; - case OPERATIONS.PNAddChannelsToGroupOperation: - case OPERATIONS.PNRemoveChannelsFromGroupOperation: - case OPERATIONS.PNChannelGroupsOperation: - case OPERATIONS.PNRemoveGroupOperation: - case OPERATIONS.PNChannelsForGroupOperation: - operation = 'cg'; - break; - case OPERATIONS.PNPushNotificationEnabledChannelsOperation: - case OPERATIONS.PNRemoveAllPushNotificationsOperation: - operation = 'push'; - break; - case OPERATIONS.PNCreateUserOperation: - case OPERATIONS.PNUpdateUserOperation: - case OPERATIONS.PNDeleteUserOperation: - case OPERATIONS.PNGetUserOperation: - case OPERATIONS.PNGetUsersOperation: - case OPERATIONS.PNCreateSpaceOperation: - case OPERATIONS.PNUpdateSpaceOperation: - case OPERATIONS.PNDeleteSpaceOperation: - case OPERATIONS.PNGetSpaceOperation: - case OPERATIONS.PNGetSpacesOperation: - case OPERATIONS.PNGetMembersOperation: - case OPERATIONS.PNUpdateMembersOperation: - case OPERATIONS.PNGetMembershipsOperation: - case OPERATIONS.PNUpdateMembershipsOperation: - operation = 'obj'; - break; - case OPERATIONS.PNAddMessageActionOperation: - case OPERATIONS.PNRemoveMessageActionOperation: - case OPERATIONS.PNGetMessageActionsOperation: - operation = 'msga'; - break; - case OPERATIONS.PNAccessManagerGrant: - case OPERATIONS.PNAccessManagerAudit: - operation = 'pam'; - break; - case OPERATIONS.PNAccessManagerGrantToken: - case OPERATIONS.PNAccessManagerRevokeToken: - operation = 'pamv3'; - break; - default: - operation = 'time'; - break; - } - return operation; - }; - return default_1; - }()); - - /* */ - var BaseNotificationPayload = /** @class */ (function () { - function BaseNotificationPayload(payload, title, body) { - this._payload = payload; - this._setDefaultPayloadStructure(); - this.title = title; - this.body = body; - } - Object.defineProperty(BaseNotificationPayload.prototype, "payload", { - get: function () { - return this._payload; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(BaseNotificationPayload.prototype, "title", { - set: function (value) { - this._title = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(BaseNotificationPayload.prototype, "subtitle", { - set: function (value) { - this._subtitle = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(BaseNotificationPayload.prototype, "body", { - set: function (value) { - this._body = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(BaseNotificationPayload.prototype, "badge", { - set: function (value) { - this._badge = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(BaseNotificationPayload.prototype, "sound", { - set: function (value) { - this._sound = value; - }, - enumerable: false, - configurable: true - }); - BaseNotificationPayload.prototype._setDefaultPayloadStructure = function () { - // Empty. - }; - BaseNotificationPayload.prototype.toObject = function () { - return {}; - }; - return BaseNotificationPayload; - }()); - var APNSNotificationPayload = /** @class */ (function (_super) { - __extends(APNSNotificationPayload, _super); - function APNSNotificationPayload() { - return _super !== null && _super.apply(this, arguments) || this; - } - Object.defineProperty(APNSNotificationPayload.prototype, "configurations", { - set: function (value) { - if (!value || !value.length) - return; - this._configurations = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(APNSNotificationPayload.prototype, "notification", { - get: function () { - return this._payload.aps; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(APNSNotificationPayload.prototype, "title", { - get: function () { - return this._title; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.aps.alert.title = value; - this._title = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(APNSNotificationPayload.prototype, "subtitle", { - get: function () { - return this._subtitle; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.aps.alert.subtitle = value; - this._subtitle = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(APNSNotificationPayload.prototype, "body", { - get: function () { - return this._body; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.aps.alert.body = value; - this._body = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(APNSNotificationPayload.prototype, "badge", { - get: function () { - return this._badge; - }, - set: function (value) { - if (value === undefined || value === null) - return; - this._payload.aps.badge = value; - this._badge = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(APNSNotificationPayload.prototype, "sound", { - get: function () { - return this._sound; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.aps.sound = value; - this._sound = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(APNSNotificationPayload.prototype, "silent", { - set: function (value) { - this._isSilent = value; - }, - enumerable: false, - configurable: true - }); - APNSNotificationPayload.prototype._setDefaultPayloadStructure = function () { - this._payload.aps = { alert: {} }; - }; - APNSNotificationPayload.prototype.toObject = function () { - var _this = this; - var payload = __assign({}, this._payload); - /** @type {{alert: Object, badge: number, sound: string}} */ - var aps = payload.aps; - var alert = aps.alert; - if (this._isSilent) { - aps['content-available'] = 1; - } - if (this._apnsPushType === 'apns2') { - if (!this._configurations || !this._configurations.length) { - throw new ReferenceError('APNS2 configuration is missing'); - } - var configurations_1 = []; - this._configurations.forEach(function (configuration) { - configurations_1.push(_this._objectFromAPNS2Configuration(configuration)); - }); - if (configurations_1.length) { - payload.pn_push = configurations_1; - } - } - if (!alert || !Object.keys(alert).length) { - delete aps.alert; - } - if (this._isSilent) { - delete aps.alert; - delete aps.badge; - delete aps.sound; - alert = {}; - } - return this._isSilent || Object.keys(alert).length ? payload : null; - }; - APNSNotificationPayload.prototype._objectFromAPNS2Configuration = function (configuration) { - var _this = this; - if (!configuration.targets || !configuration.targets.length) { - throw new ReferenceError('At least one APNS2 target should be provided'); - } - var targets = []; - configuration.targets.forEach(function (target) { - targets.push(_this._objectFromAPNSTarget(target)); - }); - var collapseId = configuration.collapseId, expirationDate = configuration.expirationDate; - var objectifiedConfiguration = { auth_method: 'token', targets: targets, version: 'v2' }; - if (collapseId && collapseId.length) { - objectifiedConfiguration.collapse_id = collapseId; - } - if (expirationDate) { - objectifiedConfiguration.expiration = expirationDate.toISOString(); - } - return objectifiedConfiguration; - }; - APNSNotificationPayload.prototype._objectFromAPNSTarget = function (target) { - if (!target.topic || !target.topic.length) { - throw new TypeError("Target 'topic' undefined."); - } - var topic = target.topic, _a = target.environment, environment = _a === void 0 ? 'development' : _a, _b = target.excludedDevices, excludedDevices = _b === void 0 ? [] : _b; - var objectifiedTarget = { topic: topic, environment: environment }; - if (excludedDevices.length) { - objectifiedTarget.excluded_devices = excludedDevices; - } - return objectifiedTarget; - }; - return APNSNotificationPayload; - }(BaseNotificationPayload)); - var MPNSNotificationPayload = /** @class */ (function (_super) { - __extends(MPNSNotificationPayload, _super); - function MPNSNotificationPayload() { - return _super !== null && _super.apply(this, arguments) || this; - } - Object.defineProperty(MPNSNotificationPayload.prototype, "backContent", { - get: function () { - return this._backContent; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.back_content = value; - this._backContent = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(MPNSNotificationPayload.prototype, "backTitle", { - get: function () { - return this._backTitle; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.back_title = value; - this._backTitle = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(MPNSNotificationPayload.prototype, "count", { - get: function () { - return this._count; - }, - set: function (value) { - if (value === undefined || value === null) - return; - this._payload.count = value; - this._count = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(MPNSNotificationPayload.prototype, "title", { - get: function () { - return this._title; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.title = value; - this._title = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(MPNSNotificationPayload.prototype, "type", { - get: function () { - return this._type; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.type = value; - this._type = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(MPNSNotificationPayload.prototype, "subtitle", { - get: function () { - return this.backTitle; - }, - set: function (value) { - this.backTitle = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(MPNSNotificationPayload.prototype, "body", { - get: function () { - return this.backContent; - }, - set: function (value) { - this.backContent = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(MPNSNotificationPayload.prototype, "badge", { - get: function () { - return this.count; - }, - set: function (value) { - this.count = value; - }, - enumerable: false, - configurable: true - }); - MPNSNotificationPayload.prototype.toObject = function () { - return Object.keys(this._payload).length ? __assign({}, this._payload) : null; - }; - return MPNSNotificationPayload; - }(BaseNotificationPayload)); - var FCMNotificationPayload = /** @class */ (function (_super) { - __extends(FCMNotificationPayload, _super); - function FCMNotificationPayload() { - return _super !== null && _super.apply(this, arguments) || this; - } - Object.defineProperty(FCMNotificationPayload.prototype, "notification", { - get: function () { - return this._payload.notification; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(FCMNotificationPayload.prototype, "data", { - get: function () { - return this._payload.data; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(FCMNotificationPayload.prototype, "title", { - get: function () { - return this._title; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.notification.title = value; - this._title = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(FCMNotificationPayload.prototype, "body", { - get: function () { - return this._body; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.notification.body = value; - this._body = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(FCMNotificationPayload.prototype, "sound", { - get: function () { - return this._sound; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.notification.sound = value; - this._sound = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(FCMNotificationPayload.prototype, "icon", { - get: function () { - return this._icon; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.notification.icon = value; - this._icon = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(FCMNotificationPayload.prototype, "tag", { - get: function () { - return this._tag; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.notification.tag = value; - this._tag = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(FCMNotificationPayload.prototype, "silent", { - set: function (value) { - this._isSilent = value; - }, - enumerable: false, - configurable: true - }); - FCMNotificationPayload.prototype._setDefaultPayloadStructure = function () { - this._payload.notification = {}; - this._payload.data = {}; - }; - FCMNotificationPayload.prototype.toObject = function () { - var data = __assign({}, this._payload.data); - var notification = null; - var payload = {}; - /** - * Check whether additional data has been passed outside of 'data' object - * and put it into it if required. - */ - if (Object.keys(this._payload).length > 2) { - var _a = this._payload; _a.notification; _a.data; var additionalData = __rest(_a, ["notification", "data"]); - data = __assign(__assign({}, data), additionalData); - } - if (this._isSilent) { - data.notification = this._payload.notification; - } - else { - notification = this._payload.notification; - } - if (Object.keys(data).length) { - payload.data = data; - } - if (notification && Object.keys(notification).length) { - payload.notification = notification; - } - return Object.keys(payload).length ? payload : null; - }; - return FCMNotificationPayload; - }(BaseNotificationPayload)); - var NotificationsPayload = /** @class */ (function () { - function NotificationsPayload(title, body) { - this._payload = { apns: {}, mpns: {}, fcm: {} }; - this._title = title; - this._body = body; - this.apns = new APNSNotificationPayload(this._payload.apns, title, body); - this.mpns = new MPNSNotificationPayload(this._payload.mpns, title, body); - this.fcm = new FCMNotificationPayload(this._payload.fcm, title, body); - } - Object.defineProperty(NotificationsPayload.prototype, "debugging", { - set: function (value) { - this._debugging = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(NotificationsPayload.prototype, "title", { - get: function () { - return this._title; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(NotificationsPayload.prototype, "body", { - get: function () { - return this._body; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(NotificationsPayload.prototype, "subtitle", { - get: function () { - return this._subtitle; - }, - set: function (value) { - this._subtitle = value; - this.apns.subtitle = value; - this.mpns.subtitle = value; - this.fcm.subtitle = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(NotificationsPayload.prototype, "badge", { - get: function () { - return this._badge; - }, - set: function (value) { - this._badge = value; - this.apns.badge = value; - this.mpns.badge = value; - this.fcm.badge = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(NotificationsPayload.prototype, "sound", { - get: function () { - return this._sound; - }, - set: function (value) { - this._sound = value; - this.apns.sound = value; - this.mpns.sound = value; - this.fcm.sound = value; - }, - enumerable: false, - configurable: true - }); - /** - * Build notifications platform for requested platforms. - * - * @param {Array} platforms - List of platforms for which payload - * should be added to final dictionary. Supported values: gcm, apns, apns2, - * mpns. - * - * @returns {Object} Object with data, which can be sent with publish method - * call and trigger remote notifications for specified platforms. - */ - NotificationsPayload.prototype.buildPayload = function (platforms) { - var payload = {}; - if (platforms.includes('apns') || platforms.includes('apns2')) { - this.apns._apnsPushType = platforms.includes('apns') ? 'apns' : 'apns2'; - var apnsPayload = this.apns.toObject(); - if (apnsPayload && Object.keys(apnsPayload).length) { - payload.pn_apns = apnsPayload; - } - } - if (platforms.includes('mpns')) { - var mpnsPayload = this.mpns.toObject(); - if (mpnsPayload && Object.keys(mpnsPayload).length) { - payload.pn_mpns = mpnsPayload; - } - } - if (platforms.includes('fcm')) { - var fcmPayload = this.fcm.toObject(); - if (fcmPayload && Object.keys(fcmPayload).length) { - payload.pn_gcm = fcmPayload; - } - } - if (Object.keys(payload).length && this._debugging) { - payload.pn_debug = true; - } - return payload; - }; - return NotificationsPayload; - }()); - - var default_1$5 = /** @class */ (function () { - function default_1() { - this._listeners = []; - } - default_1.prototype.addListener = function (newListener) { - if (this._listeners.includes(newListener)) { - return; - } - this._listeners.push(newListener); - }; - default_1.prototype.removeListener = function (deprecatedListener) { - var newListeners = []; - this._listeners.forEach(function (listener) { - if (listener !== deprecatedListener) - newListeners.push(listener); - }); - this._listeners = newListeners; - }; - default_1.prototype.removeAllListeners = function () { - this._listeners = []; - }; - default_1.prototype.announcePresence = function (announce) { - this._listeners.forEach(function (listener) { - if (listener.presence) - listener.presence(announce); - }); - }; - default_1.prototype.announceStatus = function (announce) { - this._listeners.forEach(function (listener) { - if (listener.status) - listener.status(announce); - }); - }; - default_1.prototype.announceMessage = function (announce) { - this._listeners.forEach(function (listener) { - if (listener.message) - listener.message(announce); - }); - }; - default_1.prototype.announceSignal = function (announce) { - this._listeners.forEach(function (listener) { - if (listener.signal) - listener.signal(announce); - }); - }; - default_1.prototype.announceMessageAction = function (announce) { - this._listeners.forEach(function (listener) { - if (listener.messageAction) - listener.messageAction(announce); - }); - }; - default_1.prototype.announceFile = function (announce) { - this._listeners.forEach(function (listener) { - if (listener.file) - listener.file(announce); - }); - }; - default_1.prototype.announceObjects = function (announce) { - this._listeners.forEach(function (listener) { - if (listener.objects) - listener.objects(announce); - }); - }; - default_1.prototype.announceUser = function (announce) { - this._listeners.forEach(function (listener) { - if (listener.user) - listener.user(announce); - }); - }; - default_1.prototype.announceSpace = function (announce) { - this._listeners.forEach(function (listener) { - if (listener.space) - listener.space(announce); - }); - }; - default_1.prototype.announceMembership = function (announce) { - this._listeners.forEach(function (listener) { - if (listener.membership) - listener.membership(announce); - }); - }; - default_1.prototype.announceNetworkUp = function () { - var networkStatus = {}; - networkStatus.category = categories.PNNetworkUpCategory; - this.announceStatus(networkStatus); - }; - default_1.prototype.announceNetworkDown = function () { - var networkStatus = {}; - networkStatus.category = categories.PNNetworkDownCategory; - this.announceStatus(networkStatus); - }; - return default_1; - }()); - - var default_1$4 = /** @class */ (function () { - function default_1(config, cbor) { - this._config = config; - this._cbor = cbor; - } - default_1.prototype.setToken = function (token) { - if (token && token.length > 0) { - this._token = token; - } - else { - this._token = undefined; - } - }; - default_1.prototype.getToken = function () { - return this._token; - }; - default_1.prototype.extractPermissions = function (permissions) { - var permissionsResult = { - read: false, - write: false, - manage: false, - delete: false, - get: false, - update: false, - join: false, - }; - /* eslint-disable */ - if ((permissions & 128) === 128) { - permissionsResult.join = true; - } - if ((permissions & 64) === 64) { - permissionsResult.update = true; - } - if ((permissions & 32) === 32) { - permissionsResult.get = true; - } - if ((permissions & 8) === 8) { - permissionsResult.delete = true; - } - if ((permissions & 4) === 4) { - permissionsResult.manage = true; - } - if ((permissions & 2) === 2) { - permissionsResult.write = true; - } - if ((permissions & 1) === 1) { - permissionsResult.read = true; - } - /* eslint-enable */ - return permissionsResult; - }; - default_1.prototype.parseToken = function (tokenString) { - var _this = this; - var parsed = this._cbor.decodeToken(tokenString); - if (parsed !== undefined) { - var uuidResourcePermissions = parsed.res.uuid ? Object.keys(parsed.res.uuid) : []; - var channelResourcePermissions = Object.keys(parsed.res.chan); - var groupResourcePermissions = Object.keys(parsed.res.grp); - var uuidPatternPermissions = parsed.pat.uuid ? Object.keys(parsed.pat.uuid) : []; - var channelPatternPermissions = Object.keys(parsed.pat.chan); - var groupPatternPermissions = Object.keys(parsed.pat.grp); - var result_1 = { - version: parsed.v, - timestamp: parsed.t, - ttl: parsed.ttl, - authorized_uuid: parsed.uuid, - }; - var uuidResources = uuidResourcePermissions.length > 0; - var channelResources = channelResourcePermissions.length > 0; - var groupResources = groupResourcePermissions.length > 0; - if (uuidResources || channelResources || groupResources) { - result_1.resources = {}; - if (uuidResources) { - result_1.resources.uuids = {}; - uuidResourcePermissions.forEach(function (id) { - result_1.resources.uuids[id] = _this.extractPermissions(parsed.res.uuid[id]); - }); - } - if (channelResources) { - result_1.resources.channels = {}; - channelResourcePermissions.forEach(function (id) { - result_1.resources.channels[id] = _this.extractPermissions(parsed.res.chan[id]); - }); - } - if (groupResources) { - result_1.resources.groups = {}; - groupResourcePermissions.forEach(function (id) { - result_1.resources.groups[id] = _this.extractPermissions(parsed.res.grp[id]); - }); - } - } - var uuidPatterns = uuidPatternPermissions.length > 0; - var channelPatterns = channelPatternPermissions.length > 0; - var groupPatterns = groupPatternPermissions.length > 0; - if (uuidPatterns || channelPatterns || groupPatterns) { - result_1.patterns = {}; - if (uuidPatterns) { - result_1.patterns.uuids = {}; - uuidPatternPermissions.forEach(function (id) { - result_1.patterns.uuids[id] = _this.extractPermissions(parsed.pat.uuid[id]); - }); - } - if (channelPatterns) { - result_1.patterns.channels = {}; - channelPatternPermissions.forEach(function (id) { - result_1.patterns.channels[id] = _this.extractPermissions(parsed.pat.chan[id]); - }); - } - if (groupPatterns) { - result_1.patterns.groups = {}; - groupPatternPermissions.forEach(function (id) { - result_1.patterns.groups[id] = _this.extractPermissions(parsed.pat.grp[id]); - }); - } - } - if (Object.keys(parsed.meta).length > 0) { - result_1.meta = parsed.meta; - } - result_1.signature = parsed.sig; - return result_1; - } - return undefined; - }; - return default_1; - }()); - - function objectToList(o) { - var l = []; - Object.keys(o).forEach(function (key) { return l.push(key); }); - return l; - } - function encodeString(input) { - return encodeURIComponent(input).replace(/[!~*'()]/g, function (x) { return "%".concat(x.charCodeAt(0).toString(16).toUpperCase()); }); - } - function objectToListSorted(o) { - return objectToList(o).sort(); - } - function signPamFromParams(params) { - var l = objectToListSorted(params); - return l.map(function (paramKey) { return "".concat(paramKey, "=").concat(encodeString(params[paramKey])); }).join('&'); - } - function endsWith(searchString, suffix) { - return searchString.indexOf(suffix, this.length - suffix.length) !== -1; - } - function createPromise() { - var successResolve; - var failureResolve; - var promise = new Promise(function (fulfill, reject) { - successResolve = fulfill; - failureResolve = reject; - }); - return { promise: promise, reject: failureResolve, fulfill: successResolve }; - } - function stringToArrayBuffer(str) { - var buf = new ArrayBuffer(str.length * 2); - var bufView = new Uint16Array(buf); - for (var i = 0, strLen = str.length; i < strLen; i++) { - bufView[i] = str.charCodeAt(i); - } - return buf; - } - function removeSingleOccurance(source, elementsToRemove) { - var removed = Object.fromEntries(elementsToRemove.map(function (prop) { return [prop, false]; })); - return source.filter(function (e) { - if (elementsToRemove.includes(e) && !removed[e]) { - removed[e] = true; - return false; - } - return true; - }); - } - function findUniqueCommonElements(a, b) { - return __spreadArray([], __read(a), false).filter(function (value) { - return b.includes(value) && a.indexOf(value) === a.lastIndexOf(value) && b.indexOf(value) === b.lastIndexOf(value); - }); - } - var utils$5 = { - signPamFromParams: signPamFromParams, - endsWith: endsWith, - createPromise: createPromise, - encodeString: encodeString, - stringToArrayBuffer: stringToArrayBuffer, - removeSingleOccurance: removeSingleOccurance, - findUniqueCommonElements: findUniqueCommonElements, - }; - - var PubNubError = /** @class */ (function (_super) { - __extends(PubNubError, _super); - function PubNubError(message, status) { - var _newTarget = this.constructor; - var _this = _super.call(this, message) || this; - _this.name = _this.constructor.name; - _this.status = status; - _this.message = message; - Object.setPrototypeOf(_this, _newTarget.prototype); - return _this; - } - return PubNubError; - }(Error)); - function createError(errorPayload, type) { - errorPayload.type = type; - errorPayload.error = true; - return errorPayload; - } - function createValidationError(message) { - return createError({ message: message }, 'validationError'); - } - function decideURL(endpoint, modules, incomingParams) { - if (endpoint.usePost && endpoint.usePost(modules, incomingParams)) { - return endpoint.postURL(modules, incomingParams); - } - if (endpoint.usePatch && endpoint.usePatch(modules, incomingParams)) { - return endpoint.patchURL(modules, incomingParams); - } - if (endpoint.useGetFile && endpoint.useGetFile(modules, incomingParams)) { - return endpoint.getFileURL(modules, incomingParams); - } - return endpoint.getURL(modules, incomingParams); - } - function generatePNSDK(config) { - if (config.sdkName) { - return config.sdkName; - } - var base = "PubNub-JS-".concat(config.sdkFamily); - if (config.partnerId) { - base += "-".concat(config.partnerId); - } - base += "/".concat(config.getVersion()); - var pnsdkSuffix = config._getPnsdkSuffix(' '); - if (pnsdkSuffix.length > 0) { - base += pnsdkSuffix; - } - return base; - } - function getHttpMethod(modules, endpoint, incomingParams) { - if (endpoint.usePost && endpoint.usePost(modules, incomingParams)) { - return 'POST'; - } - if (endpoint.usePatch && endpoint.usePatch(modules, incomingParams)) { - return 'PATCH'; - } - if (endpoint.useDelete && endpoint.useDelete(modules, incomingParams)) { - return 'DELETE'; - } - if (endpoint.useGetFile && endpoint.useGetFile(modules, incomingParams)) { - return 'GETFILE'; - } - return 'GET'; - } - function signRequest(modules, url, outgoingParams, incomingParams, endpoint) { - var config = modules.config, crypto = modules.crypto; - var httpMethod = getHttpMethod(modules, endpoint, incomingParams); - outgoingParams.timestamp = Math.floor(new Date().getTime() / 1000); - // This is because of a server-side bug, old publish using post should be deprecated - if (endpoint.getOperation() === 'PNPublishOperation' && - endpoint.usePost && - endpoint.usePost(modules, incomingParams)) { - httpMethod = 'GET'; - } - if (httpMethod === 'GETFILE') { - httpMethod = 'GET'; - } - var signInput = "".concat(httpMethod, "\n").concat(config.publishKey, "\n").concat(url, "\n").concat(utils$5.signPamFromParams(outgoingParams), "\n"); - if (httpMethod === 'POST') { - var payload = endpoint.postPayload(modules, incomingParams); - if (typeof payload === 'string') { - signInput += payload; - } - else { - signInput += JSON.stringify(payload); - } - } - else if (httpMethod === 'PATCH') { - var payload = endpoint.patchPayload(modules, incomingParams); - if (typeof payload === 'string') { - signInput += payload; - } - else { - signInput += JSON.stringify(payload); - } - } - var signature = "v2.".concat(crypto.HMACSHA256(signInput)); - signature = signature.replace(/\+/g, '-'); - signature = signature.replace(/\//g, '_'); - signature = signature.replace(/=+$/, ''); - outgoingParams.signature = signature; - } - function endpointCreator (modules, endpoint) { - var args = []; - for (var _i = 2; _i < arguments.length; _i++) { - args[_i - 2] = arguments[_i]; - } - var networking = modules.networking, config = modules.config, telemetryManager = modules.telemetryManager, tokenManager = modules.tokenManager; - var requestId = uuidGenerator.createUUID(); - var callback = null; - var promiseComponent = null; - var incomingParams = {}; - if (endpoint.getOperation() === OPERATIONS.PNTimeOperation || - endpoint.getOperation() === OPERATIONS.PNChannelGroupsOperation) { - callback = args[0]; - } - else { - incomingParams = args[0]; - callback = args[1]; - } - // bridge in Promise support. - if (typeof Promise !== 'undefined' && !callback) { - promiseComponent = utils$5.createPromise(); - } - var validationResult = endpoint.validateParams(modules, incomingParams); - if (validationResult) { - if (callback) { - return callback(createValidationError(validationResult)); - } - if (promiseComponent) { - promiseComponent.reject(new PubNubError('Validation failed, check status for details', createValidationError(validationResult))); - return promiseComponent.promise; - } - return; - } - var outgoingParams = endpoint.prepareParams(modules, incomingParams); - var url = decideURL(endpoint, modules, incomingParams); - var callInstance; - var networkingParams = { - url: url, - operation: endpoint.getOperation(), - timeout: endpoint.getRequestTimeout(modules), - headers: endpoint.getRequestHeaders ? endpoint.getRequestHeaders() : {}, - ignoreBody: typeof endpoint.ignoreBody === 'function' ? endpoint.ignoreBody(modules) : false, - forceBuffered: typeof endpoint.forceBuffered === 'function' ? endpoint.forceBuffered(modules, incomingParams) : null, - abortSignal: typeof endpoint.getAbortSignal === 'function' ? endpoint.getAbortSignal(modules, incomingParams) : null, - }; - outgoingParams.uuid = config.UUID; - outgoingParams.pnsdk = generatePNSDK(config); - // Add telemetry information (if there is any available). - var telemetryLatencies = telemetryManager.operationsLatencyForRequest(); - if (Object.keys(telemetryLatencies).length) { - outgoingParams = __assign(__assign({}, outgoingParams), telemetryLatencies); - } - if (config.useInstanceId) { - outgoingParams.instanceid = config.instanceId; - } - if (config.useRequestId) { - outgoingParams.requestid = requestId; - } - if (endpoint.isAuthSupported()) { - var tokenOrKey = tokenManager.getToken() || config.getAuthKey(); - if (tokenOrKey) { - outgoingParams.auth = tokenOrKey; - } - } - if (config.secretKey) { - signRequest(modules, url, outgoingParams, incomingParams, endpoint); - } - var onResponse = function (status, payload) { - if (status.error) { - if (endpoint.handleError) { - endpoint.handleError(modules, incomingParams, status); - } - if (callback) { - callback(status); - } - else if (promiseComponent) { - promiseComponent.reject(new PubNubError('PubNub call failed, check status for details', status)); - } - return; - } - // Stop endpoint latency tracking. - telemetryManager.stopLatencyMeasure(endpoint.getOperation(), requestId); - var responseP = endpoint.handleResponse(modules, payload, incomingParams); - if (typeof (responseP === null || responseP === void 0 ? void 0 : responseP.then) !== 'function') { - responseP = Promise.resolve(responseP); - } - responseP - .then(function (result) { - if (callback) { - callback(status, result); - } - else if (promiseComponent) { - promiseComponent.fulfill(result); - } - }) - .catch(function (e) { - if (callback) { - var errorData = e; - if (endpoint.getOperation() === OPERATIONS.PNSubscribeOperation) { - errorData = { - statusCode: 400, - error: true, - operation: endpoint.getOperation(), - errorData: e, - category: categories.PNUnknownCategory, - }; - } - callback(errorData, null); - } - else if (promiseComponent) { - promiseComponent.reject(new PubNubError('PubNub call failed, check status for details', e)); - } - }); - }; - // Start endpoint latency tracking. - telemetryManager.startLatencyMeasure(endpoint.getOperation(), requestId); - if (getHttpMethod(modules, endpoint, incomingParams) === 'POST') { - var payload = endpoint.postPayload(modules, incomingParams); - callInstance = networking.POST(outgoingParams, payload, networkingParams, onResponse); - } - else if (getHttpMethod(modules, endpoint, incomingParams) === 'PATCH') { - var payload = endpoint.patchPayload(modules, incomingParams); - callInstance = networking.PATCH(outgoingParams, payload, networkingParams, onResponse); - } - else if (getHttpMethod(modules, endpoint, incomingParams) === 'DELETE') { - callInstance = networking.DELETE(outgoingParams, networkingParams, onResponse); - } - else if (getHttpMethod(modules, endpoint, incomingParams) === 'GETFILE') { - callInstance = networking.GETFILE(outgoingParams, networkingParams, onResponse); - } - else { - callInstance = networking.GET(outgoingParams, networkingParams, onResponse); - } - if (endpoint.getOperation() === OPERATIONS.PNSubscribeOperation) { - return callInstance; - } - if (promiseComponent) { - return promiseComponent.promise; - } - } - - /* */ - function getOperation$s() { - return OPERATIONS.PNAddChannelsToGroupOperation; - } - function validateParams$s(modules, incomingParams) { - var channels = incomingParams.channels, channelGroup = incomingParams.channelGroup; - var config = modules.config; - if (!channelGroup) - return 'Missing Channel Group'; - if (!channels || channels.length === 0) - return 'Missing Channels'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$q(modules, incomingParams) { - var channelGroup = incomingParams.channelGroup; - var config = modules.config; - return "/v1/channel-registration/sub-key/".concat(config.subscribeKey, "/channel-group/").concat(utils$5.encodeString(channelGroup)); - } - function getRequestTimeout$s(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$s() { - return true; - } - function prepareParams$s(modules, incomingParams) { - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a; - return { - add: channels.join(','), - }; - } - function handleResponse$s() { - return {}; - } - - var addChannelsChannelGroupConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$s, - validateParams: validateParams$s, - getURL: getURL$q, - getRequestTimeout: getRequestTimeout$s, - isAuthSupported: isAuthSupported$s, - prepareParams: prepareParams$s, - handleResponse: handleResponse$s - }); - - /* */ - function getOperation$r() { - return OPERATIONS.PNRemoveChannelsFromGroupOperation; - } - function validateParams$r(modules, incomingParams) { - var channels = incomingParams.channels, channelGroup = incomingParams.channelGroup; - var config = modules.config; - if (!channelGroup) - return 'Missing Channel Group'; - if (!channels || channels.length === 0) - return 'Missing Channels'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$p(modules, incomingParams) { - var channelGroup = incomingParams.channelGroup; - var config = modules.config; - return "/v1/channel-registration/sub-key/".concat(config.subscribeKey, "/channel-group/").concat(utils$5.encodeString(channelGroup)); - } - function getRequestTimeout$r(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$r() { - return true; - } - function prepareParams$r(modules, incomingParams) { - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a; - return { - remove: channels.join(','), - }; - } - function handleResponse$r() { - return {}; - } - - var removeChannelsChannelGroupConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$r, - validateParams: validateParams$r, - getURL: getURL$p, - getRequestTimeout: getRequestTimeout$r, - isAuthSupported: isAuthSupported$r, - prepareParams: prepareParams$r, - handleResponse: handleResponse$r - }); - - /* */ - function getOperation$q() { - return OPERATIONS.PNRemoveGroupOperation; - } - function validateParams$q(modules, incomingParams) { - var channelGroup = incomingParams.channelGroup; - var config = modules.config; - if (!channelGroup) - return 'Missing Channel Group'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$o(modules, incomingParams) { - var channelGroup = incomingParams.channelGroup; - var config = modules.config; - return "/v1/channel-registration/sub-key/".concat(config.subscribeKey, "/channel-group/").concat(utils$5.encodeString(channelGroup), "/remove"); - } - function isAuthSupported$q() { - return true; - } - function getRequestTimeout$q(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function prepareParams$q() { - return {}; - } - function handleResponse$q() { - return {}; - } - - var deleteChannelGroupConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$q, - validateParams: validateParams$q, - getURL: getURL$o, - isAuthSupported: isAuthSupported$q, - getRequestTimeout: getRequestTimeout$q, - prepareParams: prepareParams$q, - handleResponse: handleResponse$q - }); - - /* */ - function getOperation$p() { - return OPERATIONS.PNChannelGroupsOperation; - } - function validateParams$p(modules) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$n(modules) { - var config = modules.config; - return "/v1/channel-registration/sub-key/".concat(config.subscribeKey, "/channel-group"); - } - function getRequestTimeout$p(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$p() { - return true; - } - function prepareParams$p() { - return {}; - } - function handleResponse$p(modules, serverResponse) { - return { - groups: serverResponse.payload.groups, - }; - } - - var listChannelGroupsConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$p, - validateParams: validateParams$p, - getURL: getURL$n, - getRequestTimeout: getRequestTimeout$p, - isAuthSupported: isAuthSupported$p, - prepareParams: prepareParams$p, - handleResponse: handleResponse$p - }); - - /* */ - function getOperation$o() { - return OPERATIONS.PNChannelsForGroupOperation; - } - function validateParams$o(modules, incomingParams) { - var channelGroup = incomingParams.channelGroup; - var config = modules.config; - if (!channelGroup) - return 'Missing Channel Group'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$m(modules, incomingParams) { - var channelGroup = incomingParams.channelGroup; - var config = modules.config; - return "/v1/channel-registration/sub-key/".concat(config.subscribeKey, "/channel-group/").concat(utils$5.encodeString(channelGroup)); - } - function getRequestTimeout$o(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$o() { - return true; - } - function prepareParams$o() { - return {}; - } - function handleResponse$o(modules, serverResponse) { - return { - channels: serverResponse.payload.channels, - }; - } - - var listChannelsInChannelGroupConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$o, - validateParams: validateParams$o, - getURL: getURL$m, - getRequestTimeout: getRequestTimeout$o, - isAuthSupported: isAuthSupported$o, - prepareParams: prepareParams$o, - handleResponse: handleResponse$o - }); - - /* */ - function getOperation$n() { - return OPERATIONS.PNPushNotificationEnabledChannelsOperation; - } - function validateParams$n(modules, incomingParams) { - var device = incomingParams.device, pushGateway = incomingParams.pushGateway, channels = incomingParams.channels, topic = incomingParams.topic; - var config = modules.config; - if (!device) - return 'Missing Device ID (device)'; - if (!pushGateway) - return 'Missing GW Type (pushGateway: gcm, apns or apns2)'; - if (pushGateway === 'apns2' && !topic) - return 'Missing APNS2 topic'; - if (!channels || channels.length === 0) - return 'Missing Channels'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$l(modules, incomingParams) { - var device = incomingParams.device, pushGateway = incomingParams.pushGateway; - var config = modules.config; - if (pushGateway === 'apns2') { - return "/v2/push/sub-key/".concat(config.subscribeKey, "/devices-apns2/").concat(device); - } - return "/v1/push/sub-key/".concat(config.subscribeKey, "/devices/").concat(device); - } - function getRequestTimeout$n(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$n() { - return true; - } - function prepareParams$n(modules, incomingParams) { - var pushGateway = incomingParams.pushGateway, _a = incomingParams.channels, channels = _a === void 0 ? [] : _a, _b = incomingParams.environment, environment = _b === void 0 ? 'development' : _b, topic = incomingParams.topic; - var parameters = { type: pushGateway, add: channels.join(',') }; - if (pushGateway === 'apns2') { - parameters = __assign(__assign({}, parameters), { environment: environment, topic: topic }); - delete parameters.type; - } - return parameters; - } - function handleResponse$n() { - return {}; - } - - var addPushChannelsConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$n, - validateParams: validateParams$n, - getURL: getURL$l, - getRequestTimeout: getRequestTimeout$n, - isAuthSupported: isAuthSupported$n, - prepareParams: prepareParams$n, - handleResponse: handleResponse$n - }); - - /* */ - function getOperation$m() { - return OPERATIONS.PNPushNotificationEnabledChannelsOperation; - } - function validateParams$m(modules, incomingParams) { - var device = incomingParams.device, pushGateway = incomingParams.pushGateway, channels = incomingParams.channels, topic = incomingParams.topic; - var config = modules.config; - if (!device) - return 'Missing Device ID (device)'; - if (!pushGateway) - return 'Missing GW Type (pushGateway: gcm, apns or apns2)'; - if (pushGateway === 'apns2' && !topic) - return 'Missing APNS2 topic'; - if (!channels || channels.length === 0) - return 'Missing Channels'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$k(modules, incomingParams) { - var device = incomingParams.device, pushGateway = incomingParams.pushGateway; - var config = modules.config; - if (pushGateway === 'apns2') { - return "/v2/push/sub-key/".concat(config.subscribeKey, "/devices-apns2/").concat(device); - } - return "/v1/push/sub-key/".concat(config.subscribeKey, "/devices/").concat(device); - } - function getRequestTimeout$m(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$m() { - return true; - } - function prepareParams$m(modules, incomingParams) { - var pushGateway = incomingParams.pushGateway, _a = incomingParams.channels, channels = _a === void 0 ? [] : _a, _b = incomingParams.environment, environment = _b === void 0 ? 'development' : _b, topic = incomingParams.topic; - var parameters = { type: pushGateway, remove: channels.join(',') }; - if (pushGateway === 'apns2') { - parameters = __assign(__assign({}, parameters), { environment: environment, topic: topic }); - delete parameters.type; - } - return parameters; - } - function handleResponse$m() { - return {}; - } - - var removePushChannelsConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$m, - validateParams: validateParams$m, - getURL: getURL$k, - getRequestTimeout: getRequestTimeout$m, - isAuthSupported: isAuthSupported$m, - prepareParams: prepareParams$m, - handleResponse: handleResponse$m - }); - - function getOperation$l() { - return OPERATIONS.PNPushNotificationEnabledChannelsOperation; - } - function validateParams$l(modules, incomingParams) { - var device = incomingParams.device, pushGateway = incomingParams.pushGateway, topic = incomingParams.topic; - var config = modules.config; - if (!device) - return 'Missing Device ID (device)'; - if (!pushGateway) - return 'Missing GW Type (pushGateway: gcm, apns or apns2)'; - if (pushGateway === 'apns2' && !topic) - return 'Missing APNS2 topic'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$j(modules, incomingParams) { - var device = incomingParams.device, pushGateway = incomingParams.pushGateway; - var config = modules.config; - if (pushGateway === 'apns2') { - return "/v2/push/sub-key/".concat(config.subscribeKey, "/devices-apns2/").concat(device); - } - return "/v1/push/sub-key/".concat(config.subscribeKey, "/devices/").concat(device); - } - function getRequestTimeout$l(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$l() { - return true; - } - function prepareParams$l(modules, incomingParams) { - var pushGateway = incomingParams.pushGateway, _a = incomingParams.environment, environment = _a === void 0 ? 'development' : _a, topic = incomingParams.topic, start = incomingParams.start, count = incomingParams.count; - var parameters = { type: pushGateway }; - if (pushGateway === 'apns2') { - parameters = __assign(__assign({}, parameters), { environment: environment, topic: topic }); - delete parameters.type; - } - if (start) - parameters.start = start; - if (count && count > 0) - parameters.count = count; - return parameters; - } - function handleResponse$l(modules, serverResponse) { - return { channels: serverResponse }; - } - - var listPushChannelsConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$l, - validateParams: validateParams$l, - getURL: getURL$j, - getRequestTimeout: getRequestTimeout$l, - isAuthSupported: isAuthSupported$l, - prepareParams: prepareParams$l, - handleResponse: handleResponse$l - }); - - /* */ - function getOperation$k() { - return OPERATIONS.PNRemoveAllPushNotificationsOperation; - } - function validateParams$k(modules, incomingParams) { - var device = incomingParams.device, pushGateway = incomingParams.pushGateway, topic = incomingParams.topic; - var config = modules.config; - if (!device) - return 'Missing Device ID (device)'; - if (!pushGateway) - return 'Missing GW Type (pushGateway: gcm, apns or apns2)'; - if (pushGateway === 'apns2' && !topic) - return 'Missing APNS2 topic'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$i(modules, incomingParams) { - var device = incomingParams.device, pushGateway = incomingParams.pushGateway; - var config = modules.config; - if (pushGateway === 'apns2') { - return "/v2/push/sub-key/".concat(config.subscribeKey, "/devices-apns2/").concat(device, "/remove"); - } - return "/v1/push/sub-key/".concat(config.subscribeKey, "/devices/").concat(device, "/remove"); - } - function getRequestTimeout$k(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$k() { - return true; - } - function prepareParams$k(modules, incomingParams) { - var pushGateway = incomingParams.pushGateway, _a = incomingParams.environment, environment = _a === void 0 ? 'development' : _a, topic = incomingParams.topic; - var parameters = { type: pushGateway }; - if (pushGateway === 'apns2') { - parameters = __assign(__assign({}, parameters), { environment: environment, topic: topic }); - delete parameters.type; - } - return parameters; - } - function handleResponse$k() { - return {}; - } - - var removeDevicePushConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$k, - validateParams: validateParams$k, - getURL: getURL$i, - getRequestTimeout: getRequestTimeout$k, - isAuthSupported: isAuthSupported$k, - prepareParams: prepareParams$k, - handleResponse: handleResponse$k - }); - - /* */ - function getOperation$j() { - return OPERATIONS.PNUnsubscribeOperation; - } - function validateParams$j(modules) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$h(modules, incomingParams) { - var config = modules.config; - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a; - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return "/v2/presence/sub-key/".concat(config.subscribeKey, "/channel/").concat(utils$5.encodeString(stringifiedChannels), "/leave"); - } - function getRequestTimeout$j(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$j() { - return true; - } - function prepareParams$j(modules, incomingParams) { - var _a = incomingParams.channelGroups, channelGroups = _a === void 0 ? [] : _a; - var params = {}; - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); - } - return params; - } - function handleResponse$j() { - return {}; - } - - var presenceLeaveEndpointConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$j, - validateParams: validateParams$j, - getURL: getURL$h, - getRequestTimeout: getRequestTimeout$j, - isAuthSupported: isAuthSupported$j, - prepareParams: prepareParams$j, - handleResponse: handleResponse$j - }); - - /* */ - function getOperation$i() { - return OPERATIONS.PNWhereNowOperation; - } - function validateParams$i(modules) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$g(modules, incomingParams) { - var config = modules.config; - var _a = incomingParams.uuid, uuid = _a === void 0 ? config.UUID : _a; - return "/v2/presence/sub-key/".concat(config.subscribeKey, "/uuid/").concat(utils$5.encodeString(uuid)); - } - function getRequestTimeout$i(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$i() { - return true; - } - function prepareParams$i() { - return {}; - } - function handleResponse$i(modules, serverResponse) { - // This is a quick fix for when the server does not include a payload - // in where now responses - if (!serverResponse.payload) { - return { channels: [] }; - } - return { channels: serverResponse.payload.channels }; - } - - var presenceWhereNowEndpointConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$i, - validateParams: validateParams$i, - getURL: getURL$g, - getRequestTimeout: getRequestTimeout$i, - isAuthSupported: isAuthSupported$i, - prepareParams: prepareParams$i, - handleResponse: handleResponse$i - }); - - /* */ - function getOperation$h() { - return OPERATIONS.PNHeartbeatOperation; - } - function validateParams$h(modules) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$f(modules, incomingParams) { - var config = modules.config; - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a; - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return "/v2/presence/sub-key/".concat(config.subscribeKey, "/channel/").concat(utils$5.encodeString(stringifiedChannels), "/heartbeat"); - } - function isAuthSupported$h() { - return true; - } - function getRequestTimeout$h(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function prepareParams$h(modules, incomingParams) { - var _a = incomingParams.channelGroups, channelGroups = _a === void 0 ? [] : _a, state = incomingParams.state; - var config = modules.config; - var params = {}; - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); - } - if (state) { - params.state = JSON.stringify(state); - } - params.heartbeat = config.getPresenceTimeout(); - return params; - } - function handleResponse$h() { - return {}; - } - - var presenceHeartbeatEndpointConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$h, - validateParams: validateParams$h, - getURL: getURL$f, - isAuthSupported: isAuthSupported$h, - getRequestTimeout: getRequestTimeout$h, - prepareParams: prepareParams$h, - handleResponse: handleResponse$h - }); - - /* */ - function getOperation$g() { - return OPERATIONS.PNGetStateOperation; - } - function validateParams$g(modules) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$e(modules, incomingParams) { - var config = modules.config; - var _a = incomingParams.uuid, uuid = _a === void 0 ? config.UUID : _a, _b = incomingParams.channels, channels = _b === void 0 ? [] : _b; - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return "/v2/presence/sub-key/".concat(config.subscribeKey, "/channel/").concat(utils$5.encodeString(stringifiedChannels), "/uuid/").concat(uuid); - } - function getRequestTimeout$g(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$g() { - return true; - } - function prepareParams$g(modules, incomingParams) { - var _a = incomingParams.channelGroups, channelGroups = _a === void 0 ? [] : _a; - var params = {}; - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); - } - return params; - } - function handleResponse$g(modules, serverResponse, incomingParams) { - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a, _b = incomingParams.channelGroups, channelGroups = _b === void 0 ? [] : _b; - var channelsResponse = {}; - if (channels.length === 1 && channelGroups.length === 0) { - channelsResponse[channels[0]] = serverResponse.payload; - } - else { - channelsResponse = serverResponse.payload; - } - return { channels: channelsResponse }; - } - - var presenceGetStateConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$g, - validateParams: validateParams$g, - getURL: getURL$e, - getRequestTimeout: getRequestTimeout$g, - isAuthSupported: isAuthSupported$g, - prepareParams: prepareParams$g, - handleResponse: handleResponse$g - }); - - function getOperation$f() { - return OPERATIONS.PNSetStateOperation; - } - function validateParams$f(modules, incomingParams) { - var config = modules.config; - var state = incomingParams.state, _a = incomingParams.channels, channels = _a === void 0 ? [] : _a, _b = incomingParams.channelGroups, channelGroups = _b === void 0 ? [] : _b; - if (!state) - return 'Missing State'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - if (channels.length === 0 && channelGroups.length === 0) { - return 'Please provide a list of channels and/or channel-groups'; - } - } - function getURL$d(modules, incomingParams) { - var config = modules.config; - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a; - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return "/v2/presence/sub-key/".concat(config.subscribeKey, "/channel/").concat(utils$5.encodeString(stringifiedChannels), "/uuid/").concat(utils$5.encodeString(config.UUID), "/data"); - } - function getRequestTimeout$f(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$f() { - return true; - } - function prepareParams$f(modules, incomingParams) { - var state = incomingParams.state, _a = incomingParams.channelGroups, channelGroups = _a === void 0 ? [] : _a; - var params = {}; - params.state = JSON.stringify(state); - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); - } - return params; - } - function handleResponse$f(modules, serverResponse) { - return { state: serverResponse.payload }; - } - - var presenceSetStateConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$f, - validateParams: validateParams$f, - getURL: getURL$d, - getRequestTimeout: getRequestTimeout$f, - isAuthSupported: isAuthSupported$f, - prepareParams: prepareParams$f, - handleResponse: handleResponse$f - }); - - function getOperation$e() { - return OPERATIONS.PNHereNowOperation; - } - function validateParams$e(modules) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$c(modules, incomingParams) { - var config = modules.config; - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a, _b = incomingParams.channelGroups, channelGroups = _b === void 0 ? [] : _b; - var baseURL = "/v2/presence/sub-key/".concat(config.subscribeKey); - if (channels.length > 0 || channelGroups.length > 0) { - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - baseURL += "/channel/".concat(utils$5.encodeString(stringifiedChannels)); - } - return baseURL; - } - function getRequestTimeout$e(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$e() { - return true; - } - function prepareParams$e(modules, incomingParams) { - var _a = incomingParams.channelGroups, channelGroups = _a === void 0 ? [] : _a, _b = incomingParams.includeUUIDs, includeUUIDs = _b === void 0 ? true : _b, _c = incomingParams.includeState, includeState = _c === void 0 ? false : _c, _d = incomingParams.queryParameters, queryParameters = _d === void 0 ? {} : _d; - var params = {}; - if (!includeUUIDs) - params.disable_uuids = 1; - if (includeState) - params.state = 1; - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); - } - params = __assign(__assign({}, params), queryParameters); - return params; - } - function handleResponse$e(modules, serverResponse, incomingParams) { - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a, _b = incomingParams.channelGroups, channelGroups = _b === void 0 ? [] : _b, _c = incomingParams.includeUUIDs, includeUUIDs = _c === void 0 ? true : _c, _d = incomingParams.includeState, includeState = _d === void 0 ? false : _d; - var prepareSingularChannel = function () { - var response = {}; - var occupantsList = []; - response.totalChannels = 1; - response.totalOccupancy = serverResponse.occupancy; - response.channels = {}; - response.channels[channels[0]] = { - occupants: occupantsList, - name: channels[0], - occupancy: serverResponse.occupancy, - }; - // We have had issues in the past with server returning responses - // that contain no uuids array - if (includeUUIDs && serverResponse.uuids) { - serverResponse.uuids.forEach(function (uuidEntry) { - if (includeState) { - occupantsList.push({ state: uuidEntry.state, uuid: uuidEntry.uuid }); - } - else { - occupantsList.push({ state: null, uuid: uuidEntry }); - } - }); - } - return response; - }; - var prepareMultipleChannel = function () { - var response = {}; - response.totalChannels = serverResponse.payload.total_channels; - response.totalOccupancy = serverResponse.payload.total_occupancy; - response.channels = {}; - Object.keys(serverResponse.payload.channels).forEach(function (channelName) { - var channelEntry = serverResponse.payload.channels[channelName]; - var occupantsList = []; - response.channels[channelName] = { - occupants: occupantsList, - name: channelName, - occupancy: channelEntry.occupancy, - }; - if (includeUUIDs) { - channelEntry.uuids.forEach(function (uuidEntry) { - if (includeState) { - occupantsList.push({ - state: uuidEntry.state, - uuid: uuidEntry.uuid, - }); - } - else { - occupantsList.push({ state: null, uuid: uuidEntry }); - } - }); - } - return response; - }); - return response; - }; - var response; - if (channels.length > 1 || channelGroups.length > 0 || (channelGroups.length === 0 && channels.length === 0)) { - response = prepareMultipleChannel(); - } - else { - response = prepareSingularChannel(); - } - return response; - } - function handleError(modules, params, status) { - if (status.statusCode === 402 && !this.getURL(modules, params).includes('channel')) { - status.errorData.message = - 'You have tried to perform a Global Here Now operation, ' + - 'your keyset configuration does not support that. Please provide a channel, ' + - 'or enable the Global Here Now feature from the Portal.'; - } - } - - var presenceHereNowConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$e, - validateParams: validateParams$e, - getURL: getURL$c, - getRequestTimeout: getRequestTimeout$e, - isAuthSupported: isAuthSupported$e, - prepareParams: prepareParams$e, - handleResponse: handleResponse$e, - handleError: handleError - }); - - /* */ - function getOperation$d() { - return OPERATIONS.PNAddMessageActionOperation; - } - function validateParams$d(_a, incomingParams) { - var config = _a.config; - var action = incomingParams.action, channel = incomingParams.channel, messageTimetoken = incomingParams.messageTimetoken; - if (!messageTimetoken) - return 'Missing message timetoken'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - if (!channel) - return 'Missing message channel'; - if (!action) - return 'Missing Action'; - if (!action.value) - return 'Missing Action.value'; - if (!action.type) - return 'Missing Action.type'; - if (action.type.length > 15) - return 'Action.type value exceed maximum length of 15'; - } - function usePost$2() { - return true; - } - function postURL$2(_a, incomingParams) { - var config = _a.config; - var channel = incomingParams.channel, messageTimetoken = incomingParams.messageTimetoken; - return "/v1/message-actions/".concat(config.subscribeKey, "/channel/").concat(utils$5.encodeString(channel), "/message/").concat(messageTimetoken); - } - function getRequestTimeout$d(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function getRequestHeaders() { - return { 'Content-Type': 'application/json' }; - } - function isAuthSupported$d() { - return true; - } - function prepareParams$d() { - return {}; - } - function postPayload$2(modules, incomingParams) { - return incomingParams.action; - } - function handleResponse$d(modules, addMessageActionResponse) { - return { data: addMessageActionResponse.data }; - } - - var addMessageActionEndpointConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$d, - validateParams: validateParams$d, - usePost: usePost$2, - postURL: postURL$2, - getRequestTimeout: getRequestTimeout$d, - getRequestHeaders: getRequestHeaders, - isAuthSupported: isAuthSupported$d, - prepareParams: prepareParams$d, - postPayload: postPayload$2, - handleResponse: handleResponse$d - }); - - /* */ - function getOperation$c() { - return OPERATIONS.PNRemoveMessageActionOperation; - } - function validateParams$c(_a, incomingParams) { - var config = _a.config; - var channel = incomingParams.channel, actionTimetoken = incomingParams.actionTimetoken, messageTimetoken = incomingParams.messageTimetoken; - if (!messageTimetoken) - return 'Missing message timetoken'; - if (!actionTimetoken) - return 'Missing action timetoken'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - if (!channel) - return 'Missing message channel'; - } - function useDelete$1() { - return true; - } - function getURL$b(_a, incomingParams) { - var config = _a.config; - var channel = incomingParams.channel, actionTimetoken = incomingParams.actionTimetoken, messageTimetoken = incomingParams.messageTimetoken; - return "/v1/message-actions/".concat(config.subscribeKey, "/channel/").concat(utils$5.encodeString(channel), "/message/").concat(messageTimetoken, "/action/").concat(actionTimetoken); - } - function getRequestTimeout$c(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$c() { - return true; - } - function prepareParams$c() { - return {}; - } - function handleResponse$c(modules, removeMessageActionResponse) { - return { data: removeMessageActionResponse.data }; - } - - var removeMessageActionEndpointConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$c, - validateParams: validateParams$c, - useDelete: useDelete$1, - getURL: getURL$b, - getRequestTimeout: getRequestTimeout$c, - isAuthSupported: isAuthSupported$c, - prepareParams: prepareParams$c, - handleResponse: handleResponse$c - }); - - /* */ - function getOperation$b() { - return OPERATIONS.PNGetMessageActionsOperation; - } - function validateParams$b(_a, incomingParams) { - var config = _a.config; - var channel = incomingParams.channel; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - if (!channel) - return 'Missing message channel'; - } - function getURL$a(_a, incomingParams) { - var config = _a.config; - var channel = incomingParams.channel; - return "/v1/message-actions/".concat(config.subscribeKey, "/channel/").concat(utils$5.encodeString(channel)); - } - function getRequestTimeout$b(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$b() { - return true; - } - function prepareParams$b(modules, incomingParams) { - var limit = incomingParams.limit, start = incomingParams.start, end = incomingParams.end; - var outgoingParams = {}; - if (limit) - outgoingParams.limit = limit; - if (start) - outgoingParams.start = start; - if (end) - outgoingParams.end = end; - return outgoingParams; - } - function handleResponse$b(modules, getMessageActionsResponse) { - /** @type GetMessageActionsResponse */ - var response = { data: getMessageActionsResponse.data, start: null, end: null }; - if (response.data.length) { - response.end = response.data[response.data.length - 1].actionTimetoken; - response.start = response.data[0].actionTimetoken; - } - return response; - } - - var getMessageActionEndpointConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$b, - validateParams: validateParams$b, - getURL: getURL$a, - getRequestTimeout: getRequestTimeout$b, - isAuthSupported: isAuthSupported$b, - prepareParams: prepareParams$b, - handleResponse: handleResponse$b - }); - - /** */ - var endpoint$j = { - getOperation: function () { return OPERATIONS.PNListFilesOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { - return "channel can't be empty"; - } - }, - getURL: function (_a, params) { - var config = _a.config; - return "/v1/files/".concat(config.subscribeKey, "/channels/").concat(utils$5.encodeString(params.channel), "/files"); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_, params) { - var outParams = {}; - if (params.limit) { - outParams.limit = params.limit; - } - if (params.next) { - outParams.next = params.next; - } - return outParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - next: response.next, - count: response.count, - }); }, - }; - - /** */ - var endpoint$i = { - getOperation: function () { return OPERATIONS.PNGenerateUploadUrlOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { - return "channel can't be empty"; - } - if (!(params === null || params === void 0 ? void 0 : params.name)) { - return "name can't be empty"; - } - }, - usePost: function () { return true; }, - postURL: function (_a, params) { - var config = _a.config; - return "/v1/files/".concat(config.subscribeKey, "/channels/").concat(utils$5.encodeString(params.channel), "/generate-upload-url"); - }, - postPayload: function (_, params) { return ({ - name: params.name, - }); }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function () { return ({}); }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - file_upload_request: response.file_upload_request, - }); }, - }; - - /** */ - var preparePayload = function (modules, payload) { - var stringifiedPayload = JSON.stringify(payload); - if (modules.cryptoModule) { - var encrypted = modules.cryptoModule.encrypt(stringifiedPayload); - stringifiedPayload = typeof encrypted === 'string' ? encrypted : encode$1(encrypted); - stringifiedPayload = JSON.stringify(stringifiedPayload); - } - return stringifiedPayload || ''; - }; - var endpoint$h = { - getOperation: function () { return OPERATIONS.PNPublishFileOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { - return "channel can't be empty"; - } - if (!(params === null || params === void 0 ? void 0 : params.fileId)) { - return "file id can't be empty"; - } - if (!(params === null || params === void 0 ? void 0 : params.fileName)) { - return "file name can't be empty"; - } - }, - getURL: function (modules, params) { - var _a = modules.config, publishKey = _a.publishKey, subscribeKey = _a.subscribeKey; - var message = { - message: params.message, - file: { - name: params.fileName, - id: params.fileId, - }, - }; - var payload = preparePayload(modules, message); - return "/v1/files/publish-file/".concat(publishKey, "/").concat(subscribeKey, "/0/").concat(utils$5.encodeString(params.channel), "/0/").concat(utils$5.encodeString(payload)); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_, params) { - var outParams = {}; - if (params.ttl) { - outParams.ttl = params.ttl; - } - if (params.storeInHistory !== undefined) { - outParams.store = params.storeInHistory ? '1' : '0'; - } - if (params.meta && typeof params.meta === 'object') { - outParams.meta = JSON.stringify(params.meta); - } - return outParams; - }, - handleResponse: function (_, response) { return ({ - timetoken: response['2'], - }); }, - }; - - var sendFile = function (_a) { - var _this = this; - var generateUploadUrl = _a.generateUploadUrl, publishFile = _a.publishFile, _b = _a.modules, PubNubFile = _b.PubNubFile, config = _b.config, cryptography = _b.cryptography, cryptoModule = _b.cryptoModule, networking = _b.networking; - return function (_a) { - var channel = _a.channel, input = _a.file, message = _a.message, cipherKey = _a.cipherKey, meta = _a.meta, ttl = _a.ttl, storeInHistory = _a.storeInHistory; - return __awaiter(_this, void 0, void 0, function () { - var file, _b, _c, url, formFields, _d, id, name, _e, formFieldsWithMimeType, result, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, e_1, errorBody, reason, retries, wasSuccessful, publishResult; - return __generator(this, function (_t) { - switch (_t.label) { - case 0: - if (!channel) { - throw new PubNubError('Validation failed, check status for details', createValidationError("channel can't be empty")); - } - if (!input) { - throw new PubNubError('Validation failed, check status for details', createValidationError("file can't be empty")); - } - file = PubNubFile.create(input); - return [4 /*yield*/, generateUploadUrl({ channel: channel, name: file.name })]; - case 1: - _b = _t.sent(), _c = _b.file_upload_request, url = _c.url, formFields = _c.form_fields, _d = _b.data, id = _d.id, name = _d.name; - if (!(PubNubFile.supportsEncryptFile && (cipherKey || cryptoModule))) return [3 /*break*/, 6]; - if (!(cipherKey == null)) return [3 /*break*/, 3]; - return [4 /*yield*/, cryptoModule.encryptFile(file, PubNubFile)]; - case 2: - _e = _t.sent(); - return [3 /*break*/, 5]; - case 3: return [4 /*yield*/, cryptography.encryptFile(cipherKey, file, PubNubFile)]; - case 4: - _e = _t.sent(); - _t.label = 5; - case 5: - file = _e; - _t.label = 6; - case 6: - formFieldsWithMimeType = formFields; - if (file.mimeType) { - formFieldsWithMimeType = formFields.map(function (entry) { - if (entry.key === 'Content-Type') - return { key: entry.key, value: file.mimeType }; - return entry; - }); - } - _t.label = 7; - case 7: - _t.trys.push([7, 21, , 22]); - if (!(PubNubFile.supportsFileUri && input.uri)) return [3 /*break*/, 10]; - _g = (_f = networking).POSTFILE; - _h = [url, formFieldsWithMimeType]; - return [4 /*yield*/, file.toFileUri()]; - case 8: return [4 /*yield*/, _g.apply(_f, _h.concat([_t.sent()]))]; - case 9: - result = _t.sent(); - return [3 /*break*/, 20]; - case 10: - if (!PubNubFile.supportsFile) return [3 /*break*/, 13]; - _k = (_j = networking).POSTFILE; - _l = [url, formFieldsWithMimeType]; - return [4 /*yield*/, file.toFile()]; - case 11: return [4 /*yield*/, _k.apply(_j, _l.concat([_t.sent()]))]; - case 12: - result = _t.sent(); - return [3 /*break*/, 20]; - case 13: - if (!PubNubFile.supportsBuffer) return [3 /*break*/, 16]; - _o = (_m = networking).POSTFILE; - _p = [url, formFieldsWithMimeType]; - return [4 /*yield*/, file.toBuffer()]; - case 14: return [4 /*yield*/, _o.apply(_m, _p.concat([_t.sent()]))]; - case 15: - result = _t.sent(); - return [3 /*break*/, 20]; - case 16: - if (!PubNubFile.supportsBlob) return [3 /*break*/, 19]; - _r = (_q = networking).POSTFILE; - _s = [url, formFieldsWithMimeType]; - return [4 /*yield*/, file.toBlob()]; - case 17: return [4 /*yield*/, _r.apply(_q, _s.concat([_t.sent()]))]; - case 18: - result = _t.sent(); - return [3 /*break*/, 20]; - case 19: throw new Error('Unsupported environment'); - case 20: return [3 /*break*/, 22]; - case 21: - e_1 = _t.sent(); - if (e_1.response && typeof e_1.response.text === 'string') { - errorBody = e_1.response.text; - reason = /(.*)<\/Message>/gi.exec(errorBody); - throw new PubNubError(reason ? "Upload to bucket failed: ".concat(reason[1]) : 'Upload to bucket failed.', e_1); - } - else { - throw new PubNubError('Upload to bucket failed.', e_1); - } - case 22: - if (result.status !== 204) { - throw new PubNubError('Upload to bucket was unsuccessful', result); - } - retries = config.fileUploadPublishRetryLimit; - wasSuccessful = false; - publishResult = { timetoken: '0' }; - _t.label = 23; - case 23: - _t.trys.push([23, 25, , 26]); - return [4 /*yield*/, publishFile({ - channel: channel, - message: message, - fileId: id, - fileName: name, - meta: meta, - storeInHistory: storeInHistory, - ttl: ttl, - })]; - case 24: - /* eslint-disable-next-line no-await-in-loop */ - publishResult = _t.sent(); - wasSuccessful = true; - return [3 /*break*/, 26]; - case 25: - _t.sent(); - retries -= 1; - return [3 /*break*/, 26]; - case 26: - if (!wasSuccessful && retries > 0) return [3 /*break*/, 23]; - _t.label = 27; - case 27: - if (!wasSuccessful) { - throw new PubNubError('Publish failed. You may want to execute that operation manually using pubnub.publishFile', { - channel: channel, - id: id, - name: name, - }); - } - else { - return [2 /*return*/, { - timetoken: publishResult.timetoken, - id: id, - name: name, - }]; - } - } - }); - }); - }; - }; - var sendFileFunction = (function (deps) { - var f = sendFile(deps); - return function (params, cb) { - var resultP = f(params); - if (typeof cb === 'function') { - resultP.then(function (result) { return cb(null, result); }).catch(function (error) { return cb(error, null); }); - return resultP; - } - return resultP; - }; - }); - - /** */ - var getFileUrlFunction = (function (modules, _a) { - var channel = _a.channel, id = _a.id, name = _a.name; - var config = modules.config, networking = modules.networking, tokenManager = modules.tokenManager; - if (!channel) { - throw new PubNubError('Validation failed, check status for details', createValidationError("channel can't be empty")); - } - if (!id) { - throw new PubNubError('Validation failed, check status for details', createValidationError("file id can't be empty")); - } - if (!name) { - throw new PubNubError('Validation failed, check status for details', createValidationError("file name can't be empty")); - } - var url = "/v1/files/".concat(config.subscribeKey, "/channels/").concat(utils$5.encodeString(channel), "/files/").concat(id, "/").concat(name); - var params = {}; - params.uuid = config.getUUID(); - params.pnsdk = generatePNSDK(config); - var tokenOrKey = tokenManager.getToken() || config.getAuthKey(); - if (tokenOrKey) { - params.auth = tokenOrKey; - } - if (config.secretKey) { - signRequest(modules, url, params, {}, { - getOperation: function () { return 'PubNubGetFileUrlOperation'; }, - }); - } - var queryParams = Object.keys(params) - .map(function (key) { return "".concat(encodeURIComponent(key), "=").concat(encodeURIComponent(params[key])); }) - .join('&'); - if (queryParams !== '') { - return "".concat(networking.getStandardOrigin()).concat(url, "?").concat(queryParams); - } - return "".concat(networking.getStandardOrigin()).concat(url); - }); - - // Download_file.js - var endpoint$g = { - getOperation: function () { return OPERATIONS.PNDownloadFileOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { - return "channel can't be empty"; - } - if (!(params === null || params === void 0 ? void 0 : params.name)) { - return "name can't be empty"; - } - if (!(params === null || params === void 0 ? void 0 : params.id)) { - return "id can't be empty"; - } - }, - useGetFile: function () { return true; }, - getFileURL: function (_a, params) { - var config = _a.config; - return "/v1/files/".concat(config.subscribeKey, "/channels/").concat(utils$5.encodeString(params.channel), "/files/").concat(params.id, "/").concat(params.name); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - ignoreBody: function () { return true; }, - forceBuffered: function () { return true; }, - prepareParams: function () { return ({}); }, - handleResponse: function (_a, res, params) { - var PubNubFile = _a.PubNubFile, config = _a.config, cryptography = _a.cryptography, cryptoModule = _a.cryptoModule; - return __awaiter(void 0, void 0, void 0, function () { - var body, _b; - var _c, _d; - return __generator(this, function (_e) { - switch (_e.label) { - case 0: - body = res.response.body; - if (!(PubNubFile.supportsEncryptFile && (params.cipherKey || cryptoModule))) return [3 /*break*/, 5]; - if (!(params.cipherKey == null)) return [3 /*break*/, 2]; - return [4 /*yield*/, cryptoModule.decryptFile(PubNubFile.create({ data: body, name: params.name }), PubNubFile)]; - case 1: - _b = (_e.sent()).data; - return [3 /*break*/, 4]; - case 2: return [4 /*yield*/, cryptography.decrypt((_c = params.cipherKey) !== null && _c !== void 0 ? _c : config.cipherKey, body)]; - case 3: - _b = _e.sent(); - _e.label = 4; - case 4: - body = _b; - _e.label = 5; - case 5: return [2 /*return*/, PubNubFile.create({ - data: body, - name: (_d = res.response.name) !== null && _d !== void 0 ? _d : params.name, - mimeType: res.response.type, - })]; - } - }); - }); - }, - }; - - /** */ - var endpoint$f = { - getOperation: function () { return OPERATIONS.PNListFilesOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { - return "channel can't be empty"; - } - if (!(params === null || params === void 0 ? void 0 : params.id)) { - return "file id can't be empty"; - } - if (!(params === null || params === void 0 ? void 0 : params.name)) { - return "file name can't be empty"; - } - }, - useDelete: function () { return true; }, - getURL: function (_a, params) { - var config = _a.config; - return "/v1/files/".concat(config.subscribeKey, "/channels/").concat(utils$5.encodeString(params.channel), "/files/").concat(params.id, "/").concat(params.name); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function () { return ({}); }, - handleResponse: function (_, response) { return ({ - status: response.status, - }); }, - }; - - var endpoint$e = { - getOperation: function () { return OPERATIONS.PNGetAllUUIDMetadataOperation; }, - validateParams: function () { - // No required parameters. - }, - getURL: function (_a) { - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/uuids"); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_modules, params) { - var _a, _b, _c, _d, _e, _f, _g, _h, _j; - var queryParams = {}; - queryParams.include = ['status', 'type']; - if (params === null || params === void 0 ? void 0 : params.include) { - if ((_a = params.include) === null || _a === void 0 ? void 0 : _a.customFields) { - queryParams.include.push('custom'); - } - } - queryParams.include = queryParams.include.join(','); - if ((_b = params === null || params === void 0 ? void 0 : params.include) === null || _b === void 0 ? void 0 : _b.totalCount) { - queryParams.count = (_c = params.include) === null || _c === void 0 ? void 0 : _c.totalCount; - } - if ((_d = params === null || params === void 0 ? void 0 : params.page) === null || _d === void 0 ? void 0 : _d.next) { - queryParams.start = (_e = params.page) === null || _e === void 0 ? void 0 : _e.next; - } - if ((_f = params === null || params === void 0 ? void 0 : params.page) === null || _f === void 0 ? void 0 : _f.prev) { - queryParams.end = (_g = params.page) === null || _g === void 0 ? void 0 : _g.prev; - } - if (params === null || params === void 0 ? void 0 : params.filter) { - queryParams.filter = params.filter; - } - queryParams.limit = (_h = params === null || params === void 0 ? void 0 : params.limit) !== null && _h !== void 0 ? _h : 100; - if (params === null || params === void 0 ? void 0 : params.sort) { - queryParams.sort = Object.entries((_j = params.sort) !== null && _j !== void 0 ? _j : {}).map(function (_a) { - var _b = __read$1(_a, 2), key = _b[0], value = _b[1]; - if (value === 'asc' || value === 'desc') { - return "".concat(key, ":").concat(value); - } - return key; - }); - } - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - next: response.next, - prev: response.prev, - }); }, - }; - - /** */ - var endpoint$d = { - getOperation: function () { return OPERATIONS.PNGetUUIDMetadataOperation; }, - validateParams: function () { - // No required parameters. - }, - getURL: function (_a, params) { - var _b; - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/uuids/").concat(utils$5.encodeString((_b = params === null || params === void 0 ? void 0 : params.uuid) !== null && _b !== void 0 ? _b : config.getUUID())); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_a, params) { - var _b, _c; - var config = _a.config; - var queryParams = {}; - queryParams.uuid = (_b = params === null || params === void 0 ? void 0 : params.uuid) !== null && _b !== void 0 ? _b : config.getUUID(); - queryParams.include = ['status', 'type', 'custom']; - if (params === null || params === void 0 ? void 0 : params.include) { - if (((_c = params.include) === null || _c === void 0 ? void 0 : _c.customFields) === false) { - queryParams.include.pop(); - } - } - queryParams.include = queryParams.include.join(','); - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - }); }, - }; - - /** */ - var endpoint$c = { - getOperation: function () { return OPERATIONS.PNSetUUIDMetadataOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.data)) { - return 'Data cannot be empty'; - } - }, - usePatch: function () { return true; }, - patchURL: function (_a, params) { - var _b; - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/uuids/").concat(utils$5.encodeString((_b = params.uuid) !== null && _b !== void 0 ? _b : config.getUUID())); - }, - patchPayload: function (_, params) { return params.data; }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_a, params) { - var _b, _c; - var config = _a.config; - var queryParams = {}; - queryParams.uuid = (_b = params === null || params === void 0 ? void 0 : params.uuid) !== null && _b !== void 0 ? _b : config.getUUID(); - queryParams.include = ['status', 'type', 'custom']; - if (params === null || params === void 0 ? void 0 : params.include) { - if (((_c = params.include) === null || _c === void 0 ? void 0 : _c.customFields) === false) { - queryParams.include.pop(); - } - } - queryParams.include = queryParams.include.join(','); - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - }); }, - }; - - /** */ - var endpoint$b = { - getOperation: function () { return OPERATIONS.PNRemoveUUIDMetadataOperation; }, - validateParams: function () { - // No required parameters. - }, - getURL: function (_a, params) { - var _b; - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/uuids/").concat(utils$5.encodeString((_b = params === null || params === void 0 ? void 0 : params.uuid) !== null && _b !== void 0 ? _b : config.getUUID())); - }, - useDelete: function () { return true; }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_a, params) { - var _b; - var config = _a.config; - return ({ - uuid: (_b = params === null || params === void 0 ? void 0 : params.uuid) !== null && _b !== void 0 ? _b : config.getUUID(), - }); - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - }); }, - }; - - var endpoint$a = { - getOperation: function () { return OPERATIONS.PNGetAllChannelMetadataOperation; }, - validateParams: function () { - // No required parameters. - }, - getURL: function (_a) { - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/channels"); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_modules, params) { - var _a, _b, _c, _d, _e, _f, _g, _h, _j; - var queryParams = {}; - queryParams.include = ['status', 'type']; - if (params === null || params === void 0 ? void 0 : params.include) { - if ((_a = params.include) === null || _a === void 0 ? void 0 : _a.customFields) { - queryParams.include.push('custom'); - } - } - queryParams.include = queryParams.include.join(','); - if ((_b = params === null || params === void 0 ? void 0 : params.include) === null || _b === void 0 ? void 0 : _b.totalCount) { - queryParams.count = (_c = params.include) === null || _c === void 0 ? void 0 : _c.totalCount; - } - if ((_d = params === null || params === void 0 ? void 0 : params.page) === null || _d === void 0 ? void 0 : _d.next) { - queryParams.start = (_e = params.page) === null || _e === void 0 ? void 0 : _e.next; - } - if ((_f = params === null || params === void 0 ? void 0 : params.page) === null || _f === void 0 ? void 0 : _f.prev) { - queryParams.end = (_g = params.page) === null || _g === void 0 ? void 0 : _g.prev; - } - if (params === null || params === void 0 ? void 0 : params.filter) { - queryParams.filter = params.filter; - } - queryParams.limit = (_h = params === null || params === void 0 ? void 0 : params.limit) !== null && _h !== void 0 ? _h : 100; - if (params === null || params === void 0 ? void 0 : params.sort) { - queryParams.sort = Object.entries((_j = params.sort) !== null && _j !== void 0 ? _j : {}).map(function (_a) { - var _b = __read$1(_a, 2), key = _b[0], value = _b[1]; - if (value === 'asc' || value === 'desc') { - return "".concat(key, ":").concat(value); - } - return key; - }); - } - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - prev: response.prev, - next: response.next, - }); }, - }; - - var endpoint$9 = { - getOperation: function () { return OPERATIONS.PNGetChannelMetadataOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { - return 'Channel cannot be empty'; - } - }, - getURL: function (_a, params) { - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/channels/").concat(utils$5.encodeString(params.channel)); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_, params) { - var _a; - var queryParams = {}; - queryParams.include = ['status', 'type', 'custom']; - if (params === null || params === void 0 ? void 0 : params.include) { - if (((_a = params.include) === null || _a === void 0 ? void 0 : _a.customFields) === false) { - queryParams.include.pop(); - } - } - queryParams.include = queryParams.include.join(','); - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - }); }, - }; - - /** */ - var endpoint$8 = { - getOperation: function () { return OPERATIONS.PNSetChannelMetadataOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { - return 'Channel cannot be empty'; - } - if (!(params === null || params === void 0 ? void 0 : params.data)) { - return 'Data cannot be empty'; - } - }, - usePatch: function () { return true; }, - patchURL: function (_a, params) { - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/channels/").concat(utils$5.encodeString(params.channel)); - }, - patchPayload: function (_, params) { return params.data; }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_, params) { - var _a; - var queryParams = {}; - queryParams.include = ['status', 'type', 'custom']; - if (params === null || params === void 0 ? void 0 : params.include) { - if (((_a = params.include) === null || _a === void 0 ? void 0 : _a.customFields) === false) { - queryParams.include.pop(); - } - } - queryParams.include = queryParams.include.join(','); - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - }); }, - }; - - /** */ - var endpoint$7 = { - getOperation: function () { return OPERATIONS.PNRemoveChannelMetadataOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { - return 'Channel cannot be empty'; - } - }, - getURL: function (_a, params) { - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/channels/").concat(utils$5.encodeString(params.channel)); - }, - useDelete: function () { return true; }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function () { return ({}); }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - }); }, - }; - - /** */ - var endpoint$6 = { - getOperation: function () { return OPERATIONS.PNGetMembersOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { - return 'channel cannot be empty'; - } - }, - getURL: function (_a, params) { - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/channels/").concat(utils$5.encodeString(params.channel), "/uuids"); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_modules, params) { - var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p; - var queryParams = {}; - queryParams.include = []; - if (params === null || params === void 0 ? void 0 : params.include) { - if ((_a = params.include) === null || _a === void 0 ? void 0 : _a.statusField) { - queryParams.include.push('status'); - } - if ((_b = params.include) === null || _b === void 0 ? void 0 : _b.customFields) { - queryParams.include.push('custom'); - } - if ((_c = params.include) === null || _c === void 0 ? void 0 : _c.UUIDFields) { - queryParams.include.push('uuid'); - } - if ((_d = params.include) === null || _d === void 0 ? void 0 : _d.customUUIDFields) { - queryParams.include.push('uuid.custom'); - } - if ((_e = params.include) === null || _e === void 0 ? void 0 : _e.UUIDStatusField) { - queryParams.include.push('uuid.status'); - } - if ((_f = params.include) === null || _f === void 0 ? void 0 : _f.UUIDTypeField) { - queryParams.include.push('uuid.type'); - } - } - queryParams.include = queryParams.include.join(','); - if ((_g = params === null || params === void 0 ? void 0 : params.include) === null || _g === void 0 ? void 0 : _g.totalCount) { - queryParams.count = (_h = params.include) === null || _h === void 0 ? void 0 : _h.totalCount; - } - if ((_j = params === null || params === void 0 ? void 0 : params.page) === null || _j === void 0 ? void 0 : _j.next) { - queryParams.start = (_k = params.page) === null || _k === void 0 ? void 0 : _k.next; - } - if ((_l = params === null || params === void 0 ? void 0 : params.page) === null || _l === void 0 ? void 0 : _l.prev) { - queryParams.end = (_m = params.page) === null || _m === void 0 ? void 0 : _m.prev; - } - if (params === null || params === void 0 ? void 0 : params.filter) { - queryParams.filter = params.filter; - } - queryParams.limit = (_o = params === null || params === void 0 ? void 0 : params.limit) !== null && _o !== void 0 ? _o : 100; - if (params === null || params === void 0 ? void 0 : params.sort) { - queryParams.sort = Object.entries((_p = params.sort) !== null && _p !== void 0 ? _p : {}).map(function (_a) { - var _b = __read$1(_a, 2), key = _b[0], value = _b[1]; - if (value === 'asc' || value === 'desc') { - return "".concat(key, ":").concat(value); - } - return key; - }); - } - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - prev: response.prev, - next: response.next, - }); }, - }; - - var endpoint$5 = { - getOperation: function () { return OPERATIONS.PNSetMembersOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { - return 'Channel cannot be empty'; - } - if (!(params === null || params === void 0 ? void 0 : params.uuids) || (params === null || params === void 0 ? void 0 : params.uuids.length) === 0) { - return 'UUIDs cannot be empty'; - } - }, - usePatch: function () { return true; }, - patchURL: function (_a, params) { - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/channels/").concat(utils$5.encodeString(params.channel), "/uuids"); - }, - patchPayload: function (_, params) { - var _a; - return (_a = { - set: [], - delete: [] - }, - _a[params.type] = params.uuids.map(function (uuid) { - if (typeof uuid === 'string') { - return { - uuid: { - id: uuid, - }, - }; - } - return { - uuid: { id: uuid.id }, - custom: uuid.custom, - status: uuid.status, - }; - }), - _a); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_modules, params) { - var _a, _b, _c, _d, _e, _f, _g, _h, _j; - var queryParams = {}; - queryParams.include = ['uuid.status', 'uuid.type', 'type']; - if (params === null || params === void 0 ? void 0 : params.include) { - if ((_a = params.include) === null || _a === void 0 ? void 0 : _a.customFields) { - queryParams.include.push('custom'); - } - if ((_b = params.include) === null || _b === void 0 ? void 0 : _b.customUUIDFields) { - queryParams.include.push('uuid.custom'); - } - if ((_c = params.include) === null || _c === void 0 ? void 0 : _c.UUIDFields) { - queryParams.include.push('uuid'); - } - } - queryParams.include = queryParams.include.join(','); - if ((_d = params === null || params === void 0 ? void 0 : params.include) === null || _d === void 0 ? void 0 : _d.totalCount) { - queryParams.count = true; - } - if ((_e = params === null || params === void 0 ? void 0 : params.page) === null || _e === void 0 ? void 0 : _e.next) { - queryParams.start = (_f = params.page) === null || _f === void 0 ? void 0 : _f.next; - } - if ((_g = params === null || params === void 0 ? void 0 : params.page) === null || _g === void 0 ? void 0 : _g.prev) { - queryParams.end = (_h = params.page) === null || _h === void 0 ? void 0 : _h.prev; - } - if (params === null || params === void 0 ? void 0 : params.filter) { - queryParams.filter = params.filter; - } - if (params.limit != null) { - queryParams.limit = params.limit; - } - if (params === null || params === void 0 ? void 0 : params.sort) { - queryParams.sort = Object.entries((_j = params.sort) !== null && _j !== void 0 ? _j : {}).map(function (_a) { - var _b = __read$1(_a, 2), key = _b[0], value = _b[1]; - if (value === 'asc' || value === 'desc') { - return "".concat(key, ":").concat(value); - } - return key; - }); - } - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - prev: response.prev, - next: response.next, - }); }, - }; - - var endpoint$4 = { - getOperation: function () { return OPERATIONS.PNGetMembershipsOperation; }, - validateParams: function () { - // No required parameters. - }, - getURL: function (_a, params) { - var _b; - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/uuids/").concat(utils$5.encodeString((_b = params === null || params === void 0 ? void 0 : params.uuid) !== null && _b !== void 0 ? _b : config.getUUID()), "/channels"); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_modules, params) { - var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p; - var queryParams = {}; - queryParams.include = []; - if (params === null || params === void 0 ? void 0 : params.include) { - if ((_a = params.include) === null || _a === void 0 ? void 0 : _a.statusField) { - queryParams.include.push('status'); - } - if ((_b = params.include) === null || _b === void 0 ? void 0 : _b.customFields) { - queryParams.include.push('custom'); - } - if ((_c = params.include) === null || _c === void 0 ? void 0 : _c.channelFields) { - queryParams.include.push('channel'); - } - if ((_d = params.include) === null || _d === void 0 ? void 0 : _d.customChannelFields) { - queryParams.include.push('channel.custom'); - } - if ((_e = params.include) === null || _e === void 0 ? void 0 : _e.channelStatusField) { - queryParams.include.push('channel.status'); - } - if ((_f = params.include) === null || _f === void 0 ? void 0 : _f.channelTypeField) { - queryParams.include.push('channel.type'); - } - } - queryParams.include = queryParams.include.join(','); - if ((_g = params === null || params === void 0 ? void 0 : params.include) === null || _g === void 0 ? void 0 : _g.totalCount) { - queryParams.count = (_h = params.include) === null || _h === void 0 ? void 0 : _h.totalCount; - } - if ((_j = params === null || params === void 0 ? void 0 : params.page) === null || _j === void 0 ? void 0 : _j.next) { - queryParams.start = (_k = params.page) === null || _k === void 0 ? void 0 : _k.next; - } - if ((_l = params === null || params === void 0 ? void 0 : params.page) === null || _l === void 0 ? void 0 : _l.prev) { - queryParams.end = (_m = params.page) === null || _m === void 0 ? void 0 : _m.prev; - } - if (params === null || params === void 0 ? void 0 : params.filter) { - queryParams.filter = params.filter; - } - queryParams.limit = (_o = params === null || params === void 0 ? void 0 : params.limit) !== null && _o !== void 0 ? _o : 100; - if (params === null || params === void 0 ? void 0 : params.sort) { - queryParams.sort = Object.entries((_p = params.sort) !== null && _p !== void 0 ? _p : {}).map(function (_a) { - var _b = __read$1(_a, 2), key = _b[0], value = _b[1]; - if (value === 'asc' || value === 'desc') { - return "".concat(key, ":").concat(value); - } - return key; - }); - } - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - prev: response.prev, - next: response.next, - }); }, - }; - - /** */ - var endpoint$3 = { - getOperation: function () { return OPERATIONS.PNSetMembershipsOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channels) || (params === null || params === void 0 ? void 0 : params.channels.length) === 0) { - return 'Channels cannot be empty'; - } - }, - usePatch: function () { return true; }, - patchURL: function (_a, params) { - var _b; - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/uuids/").concat(utils$5.encodeString((_b = params.uuid) !== null && _b !== void 0 ? _b : config.getUUID()), "/channels"); - }, - patchPayload: function (_, params) { - var _a; - return (_a = { - set: [], - delete: [] - }, - _a[params.type] = params.channels.map(function (channel) { - if (typeof channel === 'string') { - return { - channel: { - id: channel, - }, - }; - } - return { - channel: { id: channel.id }, - custom: channel.custom, - status: channel.status, - }; - }), - _a); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_modules, params) { - var _a, _b, _c, _d, _e, _f, _g, _h, _j; - var queryParams = {}; - queryParams.include = ['channel.status', 'channel.type', 'status']; - if (params === null || params === void 0 ? void 0 : params.include) { - if ((_a = params.include) === null || _a === void 0 ? void 0 : _a.customFields) { - queryParams.include.push('custom'); - } - if ((_b = params.include) === null || _b === void 0 ? void 0 : _b.customChannelFields) { - queryParams.include.push('channel.custom'); - } - if ((_c = params.include) === null || _c === void 0 ? void 0 : _c.channelFields) { - queryParams.include.push('channel'); - } - } - queryParams.include = queryParams.include.join(','); - if ((_d = params === null || params === void 0 ? void 0 : params.include) === null || _d === void 0 ? void 0 : _d.totalCount) { - queryParams.count = true; - } - if ((_e = params === null || params === void 0 ? void 0 : params.page) === null || _e === void 0 ? void 0 : _e.next) { - queryParams.start = (_f = params.page) === null || _f === void 0 ? void 0 : _f.next; - } - if ((_g = params === null || params === void 0 ? void 0 : params.page) === null || _g === void 0 ? void 0 : _g.prev) { - queryParams.end = (_h = params.page) === null || _h === void 0 ? void 0 : _h.prev; - } - if (params === null || params === void 0 ? void 0 : params.filter) { - queryParams.filter = params.filter; - } - if (params.limit != null) { - queryParams.limit = params.limit; - } - if (params === null || params === void 0 ? void 0 : params.sort) { - queryParams.sort = Object.entries((_j = params.sort) !== null && _j !== void 0 ? _j : {}).map(function (_a) { - var _b = __read$1(_a, 2), key = _b[0], value = _b[1]; - if (value === 'asc' || value === 'desc') { - return "".concat(key, ":").concat(value); - } - return key; - }); - } - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - prev: response.prev, - next: response.next, - }); }, - }; - - /* */ - function getOperation$a() { - return OPERATIONS.PNAccessManagerAudit; - } - function validateParams$a(modules) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$9(modules) { - var config = modules.config; - return "/v2/auth/audit/sub-key/".concat(config.subscribeKey); - } - function getRequestTimeout$a(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$a() { - return false; - } - function prepareParams$a(modules, incomingParams) { - var channel = incomingParams.channel, channelGroup = incomingParams.channelGroup, _a = incomingParams.authKeys, authKeys = _a === void 0 ? [] : _a; - var params = {}; - if (channel) { - params.channel = channel; - } - if (channelGroup) { - params['channel-group'] = channelGroup; - } - if (authKeys.length > 0) { - params.auth = authKeys.join(','); - } - return params; - } - function handleResponse$a(modules, serverResponse) { - return serverResponse.payload; - } - - var auditEndpointConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$a, - validateParams: validateParams$a, - getURL: getURL$9, - getRequestTimeout: getRequestTimeout$a, - isAuthSupported: isAuthSupported$a, - prepareParams: prepareParams$a, - handleResponse: handleResponse$a - }); - - /* */ - function getOperation$9() { - return OPERATIONS.PNAccessManagerGrant; - } - function validateParams$9(modules, incomingParams) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - if (!config.publishKey) - return 'Missing Publish Key'; - if (!config.secretKey) - return 'Missing Secret Key'; - if (incomingParams.uuids != null && !incomingParams.authKeys) { - return 'authKeys are required for grant request on uuids'; - } - if (incomingParams.uuids != null && (incomingParams.channels != null || incomingParams.channelGroups != null)) { - return 'Both channel/channelgroup and uuid cannot be used in the same request'; - } - } - function getURL$8(modules) { - var config = modules.config; - return "/v2/auth/grant/sub-key/".concat(config.subscribeKey); - } - function getRequestTimeout$9(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$9() { - return false; - } - function prepareParams$9(modules, incomingParams) { - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a, _b = incomingParams.channelGroups, channelGroups = _b === void 0 ? [] : _b, _c = incomingParams.uuids, uuids = _c === void 0 ? [] : _c, ttl = incomingParams.ttl, _d = incomingParams.read, read = _d === void 0 ? false : _d, _e = incomingParams.write, write = _e === void 0 ? false : _e, _f = incomingParams.manage, manage = _f === void 0 ? false : _f, _g = incomingParams.get, get = _g === void 0 ? false : _g, _h = incomingParams.join, join = _h === void 0 ? false : _h, _j = incomingParams.update, update = _j === void 0 ? false : _j, _k = incomingParams.authKeys, authKeys = _k === void 0 ? [] : _k; - var deleteParam = incomingParams.delete; - var params = {}; - params.r = read ? '1' : '0'; - params.w = write ? '1' : '0'; - params.m = manage ? '1' : '0'; - params.d = deleteParam ? '1' : '0'; - params.g = get ? '1' : '0'; - params.j = join ? '1' : '0'; - params.u = update ? '1' : '0'; - if (channels.length > 0) { - params.channel = channels.join(','); - } - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); - } - if (authKeys.length > 0) { - params.auth = authKeys.join(','); - } - if (uuids.length > 0) { - params['target-uuid'] = uuids.join(','); - } - if (ttl || ttl === 0) { - params.ttl = ttl; - } - return params; - } - function handleResponse$9() { - return {}; - } - - var grantEndpointConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$9, - validateParams: validateParams$9, - getURL: getURL$8, - getRequestTimeout: getRequestTimeout$9, - isAuthSupported: isAuthSupported$9, - prepareParams: prepareParams$9, - handleResponse: handleResponse$9 - }); - - function getOperation$8() { - return OPERATIONS.PNAccessManagerGrantToken; - } - function hasVspTerms(incomingParams) { - var _a, _b, _c, _d; - var hasAuthorizedUserId = (incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.authorizedUserId) !== undefined; - var hasUserResources = ((_a = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.resources) === null || _a === void 0 ? void 0 : _a.users) !== undefined; - var hasSpaceResources = ((_b = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.resources) === null || _b === void 0 ? void 0 : _b.spaces) !== undefined; - var hasUserPatterns = ((_c = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.patterns) === null || _c === void 0 ? void 0 : _c.users) !== undefined; - var hasSpacePatterns = ((_d = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.patterns) === null || _d === void 0 ? void 0 : _d.spaces) !== undefined; - return hasUserPatterns || hasUserResources || hasSpacePatterns || hasSpaceResources || hasAuthorizedUserId; - } - function extractPermissions(permissions) { - var permissionsResult = 0; - if (permissions.join) { - permissionsResult |= 128; - } - if (permissions.update) { - permissionsResult |= 64; - } - if (permissions.get) { - permissionsResult |= 32; - } - if (permissions.delete) { - permissionsResult |= 8; - } - if (permissions.manage) { - permissionsResult |= 4; - } - if (permissions.write) { - permissionsResult |= 2; - } - if (permissions.read) { - permissionsResult |= 1; - } - return permissionsResult; - } - function prepareMessagePayloadVsp(_modules, _a) { - var ttl = _a.ttl, resources = _a.resources, patterns = _a.patterns, meta = _a.meta, authorizedUserId = _a.authorizedUserId; - var params = { - ttl: 0, - permissions: { - resources: { - channels: {}, - groups: {}, - uuids: {}, - users: {}, - spaces: {}, // not used, needed for api backward compatibility - }, - patterns: { - channels: {}, - groups: {}, - uuids: {}, - users: {}, - spaces: {}, // not used, needed for api backward compatibility - }, - meta: {}, - }, - }; - if (resources) { - var users_1 = resources.users, spaces_1 = resources.spaces, groups_1 = resources.groups; - if (users_1) { - Object.keys(users_1).forEach(function (userID) { - params.permissions.resources.uuids[userID] = extractPermissions(users_1[userID]); - }); - } - if (spaces_1) { - Object.keys(spaces_1).forEach(function (spaceId) { - params.permissions.resources.channels[spaceId] = extractPermissions(spaces_1[spaceId]); - }); - } - if (groups_1) { - Object.keys(groups_1).forEach(function (group) { - params.permissions.resources.groups[group] = extractPermissions(groups_1[group]); - }); - } - } - if (patterns) { - var users_2 = patterns.users, spaces_2 = patterns.spaces, groups_2 = patterns.groups; - if (users_2) { - Object.keys(users_2).forEach(function (userId) { - params.permissions.patterns.uuids[userId] = extractPermissions(users_2[userId]); - }); - } - if (spaces_2) { - Object.keys(spaces_2).forEach(function (spaceId) { - params.permissions.patterns.channels[spaceId] = extractPermissions(spaces_2[spaceId]); - }); - } - if (groups_2) { - Object.keys(groups_2).forEach(function (group) { - params.permissions.patterns.groups[group] = extractPermissions(groups_2[group]); - }); - } - } - if (ttl || ttl === 0) { - params.ttl = ttl; - } - if (meta) { - params.permissions.meta = meta; - } - if (authorizedUserId) { - params.permissions.uuid = "".concat(authorizedUserId); // ensure this is a string - } - return params; - } - function prepareMessagePayload$2(_modules, incomingParams) { - if (hasVspTerms(incomingParams)) { - return prepareMessagePayloadVsp(_modules, incomingParams); - } - var ttl = incomingParams.ttl, resources = incomingParams.resources, patterns = incomingParams.patterns, meta = incomingParams.meta, authorized_uuid = incomingParams.authorized_uuid; - var params = { - ttl: 0, - permissions: { - resources: { - channels: {}, - groups: {}, - uuids: {}, - users: {}, - spaces: {}, // not used, needed for api backward compatibility - }, - patterns: { - channels: {}, - groups: {}, - uuids: {}, - users: {}, - spaces: {}, // not used, needed for api backward compatibility - }, - meta: {}, - }, - }; - if (resources) { - var uuids_1 = resources.uuids, channels_1 = resources.channels, groups_3 = resources.groups; - if (uuids_1) { - Object.keys(uuids_1).forEach(function (uuid) { - params.permissions.resources.uuids[uuid] = extractPermissions(uuids_1[uuid]); - }); - } - if (channels_1) { - Object.keys(channels_1).forEach(function (channel) { - params.permissions.resources.channels[channel] = extractPermissions(channels_1[channel]); - }); - } - if (groups_3) { - Object.keys(groups_3).forEach(function (group) { - params.permissions.resources.groups[group] = extractPermissions(groups_3[group]); - }); - } - } - if (patterns) { - var uuids_2 = patterns.uuids, channels_2 = patterns.channels, groups_4 = patterns.groups; - if (uuids_2) { - Object.keys(uuids_2).forEach(function (uuid) { - params.permissions.patterns.uuids[uuid] = extractPermissions(uuids_2[uuid]); - }); - } - if (channels_2) { - Object.keys(channels_2).forEach(function (channel) { - params.permissions.patterns.channels[channel] = extractPermissions(channels_2[channel]); - }); - } - if (groups_4) { - Object.keys(groups_4).forEach(function (group) { - params.permissions.patterns.groups[group] = extractPermissions(groups_4[group]); - }); - } - } - if (ttl || ttl === 0) { - params.ttl = ttl; - } - if (meta) { - params.permissions.meta = meta; - } - if (authorized_uuid) { - params.permissions.uuid = "".concat(authorized_uuid); // ensure this is a string - } - return params; - } - function validateParams$8(modules, incomingParams) { - var _a, _b, _c, _d, _e, _f; - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - if (!config.publishKey) - return 'Missing Publish Key'; - if (!config.secretKey) - return 'Missing Secret Key'; - if (!incomingParams.resources && !incomingParams.patterns) - return 'Missing either Resources or Patterns.'; - var hasAuthorizedUuid = (incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.authorized_uuid) !== undefined; - var hasUuidResources = ((_a = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.resources) === null || _a === void 0 ? void 0 : _a.uuids) !== undefined; - var hasChannelResources = ((_b = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.resources) === null || _b === void 0 ? void 0 : _b.channels) !== undefined; - var hasGroupResources = ((_c = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.resources) === null || _c === void 0 ? void 0 : _c.groups) !== undefined; - var hasUuidPatterns = ((_d = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.patterns) === null || _d === void 0 ? void 0 : _d.uuids) !== undefined; - var hasChannelPatterns = ((_e = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.patterns) === null || _e === void 0 ? void 0 : _e.channels) !== undefined; - var hasGroupPatterns = ((_f = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.patterns) === null || _f === void 0 ? void 0 : _f.groups) !== undefined; - var hasLegacyTerms = hasAuthorizedUuid || - hasUuidResources || - hasUuidPatterns || - hasChannelResources || - hasChannelPatterns || - hasGroupResources || - hasGroupPatterns; - if (hasVspTerms(incomingParams) && hasLegacyTerms) { - return ('Cannot mix `users`, `spaces` and `authorizedUserId` ' + - 'with `uuids`, `channels`, `groups` and `authorized_uuid`'); - } - if ((incomingParams.resources && - (!incomingParams.resources.uuids || Object.keys(incomingParams.resources.uuids).length === 0) && - (!incomingParams.resources.channels || Object.keys(incomingParams.resources.channels).length === 0) && - (!incomingParams.resources.groups || Object.keys(incomingParams.resources.groups).length === 0) && - (!incomingParams.resources.users || Object.keys(incomingParams.resources.users).length === 0) && - (!incomingParams.resources.spaces || Object.keys(incomingParams.resources.spaces).length === 0)) || - (incomingParams.patterns && - (!incomingParams.patterns.uuids || Object.keys(incomingParams.patterns.uuids).length === 0) && - (!incomingParams.patterns.channels || Object.keys(incomingParams.patterns.channels).length === 0) && - (!incomingParams.patterns.groups || Object.keys(incomingParams.patterns.groups).length === 0) && - (!incomingParams.patterns.users || Object.keys(incomingParams.patterns.users).length === 0) && - (!incomingParams.patterns.spaces || Object.keys(incomingParams.patterns.spaces).length === 0))) { - return 'Missing values for either Resources or Patterns.'; - } - } - function postURL$1(modules) { - var config = modules.config; - return "/v3/pam/".concat(config.subscribeKey, "/grant"); - } - function usePost$1() { - return true; - } - function getRequestTimeout$8(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$8() { - return false; - } - function prepareParams$8() { - return {}; - } - function postPayload$1(modules, incomingParams) { - return prepareMessagePayload$2(modules, incomingParams); - } - function handleResponse$8(modules, response) { - var token = response.data.token; - return token; - } - - var grantTokenEndpointConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$8, - extractPermissions: extractPermissions, - validateParams: validateParams$8, - postURL: postURL$1, - usePost: usePost$1, - getRequestTimeout: getRequestTimeout$8, - isAuthSupported: isAuthSupported$8, - prepareParams: prepareParams$8, - postPayload: postPayload$1, - handleResponse: handleResponse$8 - }); - - /** */ - var endpoint$2 = { - getOperation: function () { return OPERATIONS.PNAccessManagerRevokeToken; }, - validateParams: function (modules, token) { - var secretKey = modules.config.secretKey; - if (!secretKey) { - return 'Missing Secret Key'; - } - if (!token) { - return "token can't be empty"; - } - }, - getURL: function (_a, token) { - var config = _a.config; - return "/v3/pam/".concat(config.subscribeKey, "/grant/").concat(utils$5.encodeString(token)); - }, - useDelete: function () { return true; }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return false; }, - prepareParams: function (_a) { - var config = _a.config; - return ({ - uuid: config.getUUID(), - }); - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - }); }, - }; - - /* */ - function prepareMessagePayload$1(modules, messagePayload) { - var stringifiedPayload = JSON.stringify(messagePayload); - if (modules.cryptoModule) { - var encrypted = modules.cryptoModule.encrypt(stringifiedPayload); - stringifiedPayload = typeof encrypted === 'string' ? encrypted : encode$1(encrypted); - stringifiedPayload = JSON.stringify(stringifiedPayload); - } - return stringifiedPayload || ''; - } - function getOperation$7() { - return OPERATIONS.PNPublishOperation; - } - function validateParams$7(_a, incomingParams) { - var config = _a.config; - var message = incomingParams.message, channel = incomingParams.channel; - if (!channel) - return 'Missing Channel'; - if (!message) - return 'Missing Message'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function usePost(modules, incomingParams) { - var _a = incomingParams.sendByPost, sendByPost = _a === void 0 ? false : _a; - return sendByPost; - } - function getURL$7(modules, incomingParams) { - var config = modules.config; - var channel = incomingParams.channel, message = incomingParams.message; - var stringifiedPayload = prepareMessagePayload$1(modules, message); - return "/publish/".concat(config.publishKey, "/").concat(config.subscribeKey, "/0/").concat(utils$5.encodeString(channel), "/0/").concat(utils$5.encodeString(stringifiedPayload)); - } - function postURL(modules, incomingParams) { - var config = modules.config; - var channel = incomingParams.channel; - return "/publish/".concat(config.publishKey, "/").concat(config.subscribeKey, "/0/").concat(utils$5.encodeString(channel), "/0"); - } - function getRequestTimeout$7(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$7() { - return true; - } - function postPayload(modules, incomingParams) { - var message = incomingParams.message; - return prepareMessagePayload$1(modules, message); - } - function prepareParams$7(modules, incomingParams) { - var meta = incomingParams.meta, _a = incomingParams.replicate, replicate = _a === void 0 ? true : _a, storeInHistory = incomingParams.storeInHistory, ttl = incomingParams.ttl; - var params = {}; - if (storeInHistory != null) { - if (storeInHistory) { - params.store = '1'; - } - else { - params.store = '0'; - } - } - if (ttl) { - params.ttl = ttl; - } - if (replicate === false) { - params.norep = 'true'; - } - if (meta && typeof meta === 'object') { - params.meta = JSON.stringify(meta); - } - return params; - } - function handleResponse$7(modules, serverResponse) { - return { timetoken: serverResponse[2] }; - } - - var publishEndpointConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$7, - validateParams: validateParams$7, - usePost: usePost, - getURL: getURL$7, - postURL: postURL, - getRequestTimeout: getRequestTimeout$7, - isAuthSupported: isAuthSupported$7, - postPayload: postPayload, - prepareParams: prepareParams$7, - handleResponse: handleResponse$7 - }); - - /* */ - function prepareMessagePayload(modules, messagePayload) { - var stringifiedPayload = JSON.stringify(messagePayload); - return stringifiedPayload; - } - function getOperation$6() { - return OPERATIONS.PNSignalOperation; - } - function validateParams$6(_a, incomingParams) { - var config = _a.config; - var message = incomingParams.message, channel = incomingParams.channel; - if (!channel) - return 'Missing Channel'; - if (!message) - return 'Missing Message'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$6(modules, incomingParams) { - var config = modules.config; - var channel = incomingParams.channel, message = incomingParams.message; - var stringifiedPayload = prepareMessagePayload(modules, message); - return "/signal/".concat(config.publishKey, "/").concat(config.subscribeKey, "/0/").concat(utils$5.encodeString(channel), "/0/").concat(utils$5.encodeString(stringifiedPayload)); - } - function getRequestTimeout$6(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$6() { - return true; - } - function prepareParams$6() { - var params = {}; - return params; - } - function handleResponse$6(modules, serverResponse) { - return { timetoken: serverResponse[2] }; - } - - var signalEndpointConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$6, - validateParams: validateParams$6, - getURL: getURL$6, - getRequestTimeout: getRequestTimeout$6, - isAuthSupported: isAuthSupported$6, - prepareParams: prepareParams$6, - handleResponse: handleResponse$6 - }); - - /* */ - function __processMessage$1(modules, message) { - var result = {}; - if (!modules.cryptoModule) { - result.payload = message; - return result; - } - try { - var decryptedData = modules.cryptoModule.decrypt(message); - var decryptedPayload = decryptedData instanceof ArrayBuffer ? JSON.parse(new TextDecoder().decode(decryptedData)) : decryptedData; - result.payload = decryptedPayload; - return result; - } - catch (e) { - if (modules.config.logVerbosity && console && console.log) - console.log('decryption error', e.message); - result.payload = message; - result.error = "Error while decrypting message content: ".concat(e.message); - } - return result; - } - function getOperation$5() { - return OPERATIONS.PNHistoryOperation; - } - function validateParams$5(modules, incomingParams) { - var channel = incomingParams.channel; - var config = modules.config; - if (!channel) - return 'Missing channel'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$5(modules, incomingParams) { - var channel = incomingParams.channel; - var config = modules.config; - return "/v2/history/sub-key/".concat(config.subscribeKey, "/channel/").concat(utils$5.encodeString(channel)); - } - function getRequestTimeout$5(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$5() { - return true; - } - function prepareParams$5(modules, incomingParams) { - var start = incomingParams.start, end = incomingParams.end, reverse = incomingParams.reverse, _a = incomingParams.count, count = _a === void 0 ? 100 : _a, _b = incomingParams.stringifiedTimeToken, stringifiedTimeToken = _b === void 0 ? false : _b, _c = incomingParams.includeMeta, includeMeta = _c === void 0 ? false : _c; - var outgoingParams = { - include_token: 'true', - }; - outgoingParams.count = count; - if (start) - outgoingParams.start = start; - if (end) - outgoingParams.end = end; - if (stringifiedTimeToken) - outgoingParams.string_message_token = 'true'; - if (reverse != null) - outgoingParams.reverse = reverse.toString(); - if (includeMeta) - outgoingParams.include_meta = 'true'; - return outgoingParams; - } - function handleResponse$5(modules, serverResponse) { - var response = { - messages: [], - startTimeToken: serverResponse[1], - endTimeToken: serverResponse[2], - }; - if (Array.isArray(serverResponse[0])) { - serverResponse[0].forEach(function (serverHistoryItem) { - var processedMessgeResult = __processMessage$1(modules, serverHistoryItem.message); - var item = { - timetoken: serverHistoryItem.timetoken, - entry: processedMessgeResult.payload, - }; - if (serverHistoryItem.meta) { - item.meta = serverHistoryItem.meta; - } - if (processedMessgeResult.error) - item.error = processedMessgeResult.error; - response.messages.push(item); - }); - } - return response; - } - - var historyEndpointConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$5, - validateParams: validateParams$5, - getURL: getURL$5, - getRequestTimeout: getRequestTimeout$5, - isAuthSupported: isAuthSupported$5, - prepareParams: prepareParams$5, - handleResponse: handleResponse$5 - }); - - /* */ - function getOperation$4() { - return OPERATIONS.PNDeleteMessagesOperation; - } - function validateParams$4(modules, incomingParams) { - var channel = incomingParams.channel; - var config = modules.config; - if (!channel) - return 'Missing channel'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function useDelete() { - return true; - } - function getURL$4(modules, incomingParams) { - var channel = incomingParams.channel; - var config = modules.config; - return "/v3/history/sub-key/".concat(config.subscribeKey, "/channel/").concat(utils$5.encodeString(channel)); - } - function getRequestTimeout$4(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$4() { - return true; - } - function prepareParams$4(modules, incomingParams) { - var start = incomingParams.start, end = incomingParams.end; - var outgoingParams = {}; - if (start) - outgoingParams.start = start; - if (end) - outgoingParams.end = end; - return outgoingParams; - } - function handleResponse$4(modules, serverResponse) { - return serverResponse.payload; - } - - var deleteMessagesEndpointConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$4, - validateParams: validateParams$4, - useDelete: useDelete, - getURL: getURL$4, - getRequestTimeout: getRequestTimeout$4, - isAuthSupported: isAuthSupported$4, - prepareParams: prepareParams$4, - handleResponse: handleResponse$4 - }); - - function getOperation$3() { - return OPERATIONS.PNMessageCounts; - } - function validateParams$3(modules, incomingParams) { - var channels = incomingParams.channels, timetoken = incomingParams.timetoken, channelTimetokens = incomingParams.channelTimetokens; - var config = modules.config; - if (!channels) - return 'Missing channel'; - if (timetoken && channelTimetokens) - return 'timetoken and channelTimetokens are incompatible together'; - if (channelTimetokens && channelTimetokens.length > 1 && channels.length !== channelTimetokens.length) { - return 'Length of channelTimetokens and channels do not match'; - } - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$3(modules, incomingParams) { - var channels = incomingParams.channels; - var config = modules.config; - var stringifiedChannels = channels.join(','); - return "/v3/history/sub-key/".concat(config.subscribeKey, "/message-counts/").concat(utils$5.encodeString(stringifiedChannels)); - } - function getRequestTimeout$3(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$3() { - return true; - } - function prepareParams$3(modules, incomingParams) { - var timetoken = incomingParams.timetoken, channelTimetokens = incomingParams.channelTimetokens; - var outgoingParams = {}; - if (channelTimetokens && channelTimetokens.length === 1) { - var _a = __read$1(channelTimetokens, 1), tt = _a[0]; - outgoingParams.timetoken = tt; - } - else if (channelTimetokens) { - outgoingParams.channelsTimetoken = channelTimetokens.join(','); - } - else if (timetoken) { - outgoingParams.timetoken = timetoken; - } - return outgoingParams; - } - function handleResponse$3(modules, serverResponse) { - return { channels: serverResponse.channels }; - } - - var messageCountsEndpointConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$3, - validateParams: validateParams$3, - getURL: getURL$3, - getRequestTimeout: getRequestTimeout$3, - isAuthSupported: isAuthSupported$3, - prepareParams: prepareParams$3, - handleResponse: handleResponse$3 - }); - - /* */ - function __processMessage(modules, message) { - var result = {}; - if (!modules.cryptoModule) { - result.payload = message; - return result; - } - try { - var decryptedData = modules.cryptoModule.decrypt(message); - var decryptedPayload = decryptedData instanceof ArrayBuffer ? JSON.parse(new TextDecoder().decode(decryptedData)) : decryptedData; - result.payload = decryptedPayload; - return result; - } - catch (e) { - if (modules.config.logVerbosity && console && console.log) - console.log('decryption error', e.message); - result.payload = message; - result.error = "Error while decrypting message content: ".concat(e.message); - } - return result; - } - function getOperation$2() { - return OPERATIONS.PNFetchMessagesOperation; - } - function validateParams$2(modules, incomingParams) { - var channels = incomingParams.channels, _a = incomingParams.includeMessageActions, includeMessageActions = _a === void 0 ? false : _a; - var config = modules.config; - if (!channels || channels.length === 0) - return 'Missing channels'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - if (includeMessageActions && channels.length > 1) { - throw new TypeError('History can return actions data for a single channel only. ' + - 'Either pass a single channel or disable the includeMessageActions flag.'); - } - } - function getURL$2(modules, incomingParams) { - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a, _b = incomingParams.includeMessageActions, includeMessageActions = _b === void 0 ? false : _b; - var config = modules.config; - var endpoint = !includeMessageActions ? 'history' : 'history-with-actions'; - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return "/v3/".concat(endpoint, "/sub-key/").concat(config.subscribeKey, "/channel/").concat(utils$5.encodeString(stringifiedChannels)); - } - function getRequestTimeout$2(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$2() { - return true; - } - function prepareParams$2(modules, incomingParams) { - var channels = incomingParams.channels, start = incomingParams.start, end = incomingParams.end, includeMessageActions = incomingParams.includeMessageActions, count = incomingParams.count, _a = incomingParams.stringifiedTimeToken, stringifiedTimeToken = _a === void 0 ? false : _a, _b = incomingParams.includeMeta, includeMeta = _b === void 0 ? false : _b, includeUuid = incomingParams.includeUuid, _c = incomingParams.includeUUID, includeUUID = _c === void 0 ? true : _c, _d = incomingParams.includeMessageType, includeMessageType = _d === void 0 ? true : _d; - var outgoingParams = {}; - if (count) { - outgoingParams.max = count; - } - else { - outgoingParams.max = channels.length > 1 || includeMessageActions === true ? 25 : 100; - } - if (start) - outgoingParams.start = start; - if (end) - outgoingParams.end = end; - if (stringifiedTimeToken) - outgoingParams.string_message_token = 'true'; - if (includeMeta) - outgoingParams.include_meta = 'true'; - if (includeUUID && includeUuid !== false) - outgoingParams.include_uuid = 'true'; - if (includeMessageType) - outgoingParams.include_message_type = 'true'; - return outgoingParams; - } - function handleResponse$2(modules, serverResponse) { - var response = { - channels: {}, - }; - Object.keys(serverResponse.channels || {}).forEach(function (channelName) { - response.channels[channelName] = []; - (serverResponse.channels[channelName] || []).forEach(function (messageEnvelope) { - var announce = {}; - var processedMessgeResult = __processMessage(modules, messageEnvelope.message); - announce.channel = channelName; - announce.timetoken = messageEnvelope.timetoken; - announce.message = processedMessgeResult.payload; - announce.messageType = messageEnvelope.message_type; - announce.uuid = messageEnvelope.uuid; - if (messageEnvelope.actions) { - announce.actions = messageEnvelope.actions; - // This should be kept for few updates for existing clients consistency. - announce.data = messageEnvelope.actions; - } - if (messageEnvelope.meta) { - announce.meta = messageEnvelope.meta; - } - if (processedMessgeResult.error) - announce.error = processedMessgeResult.error; - response.channels[channelName].push(announce); - }); - }); - if (serverResponse.more) { - response.more = serverResponse.more; - } - return response; - } - - var fetchMessagesEndpointConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$2, - validateParams: validateParams$2, - getURL: getURL$2, - getRequestTimeout: getRequestTimeout$2, - isAuthSupported: isAuthSupported$2, - prepareParams: prepareParams$2, - handleResponse: handleResponse$2 - }); - - /* */ - function getOperation$1() { - return OPERATIONS.PNTimeOperation; - } - function getURL$1() { - return '/time/0'; - } - function getRequestTimeout$1(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function prepareParams$1() { - return {}; - } - function isAuthSupported$1() { - return false; - } - function handleResponse$1(modules, serverResponse) { - return { - timetoken: serverResponse[0], - }; - } - function validateParams$1() { - // pass - } - - var timeEndpointConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$1, - getURL: getURL$1, - getRequestTimeout: getRequestTimeout$1, - prepareParams: prepareParams$1, - isAuthSupported: isAuthSupported$1, - handleResponse: handleResponse$1, - validateParams: validateParams$1 - }); - - /* */ - function getOperation() { - return OPERATIONS.PNSubscribeOperation; - } - function validateParams(modules) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL(modules, incomingParams) { - var config = modules.config; - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a; - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return "/v2/subscribe/".concat(config.subscribeKey, "/").concat(utils$5.encodeString(stringifiedChannels), "/0"); - } - function getRequestTimeout(_a) { - var config = _a.config; - return config.getSubscribeTimeout(); - } - function isAuthSupported() { - return true; - } - function prepareParams(_a, incomingParams) { - var config = _a.config; - var state = incomingParams.state, _b = incomingParams.channelGroups, channelGroups = _b === void 0 ? [] : _b, timetoken = incomingParams.timetoken, filterExpression = incomingParams.filterExpression, region = incomingParams.region; - var params = { - heartbeat: config.getPresenceTimeout(), - }; - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); - } - if (filterExpression && filterExpression.length > 0) { - params['filter-expr'] = filterExpression; - } - if (Object.keys(state).length) { - params.state = JSON.stringify(state); - } - if (timetoken) { - params.tt = timetoken; - } - if (region) { - params.tr = region; - } - return params; - } - function handleResponse(modules, serverResponse) { - var messages = []; - serverResponse.m.forEach(function (rawMessage) { - var publishMetaData = { - timetoken: rawMessage.p.t, - region: rawMessage.p.r, - }; - var parsedMessage = { - shard: parseInt(rawMessage.a, 10), - subscriptionMatch: rawMessage.b, - channel: rawMessage.c, - messageType: rawMessage.e, - payload: rawMessage.d, - flags: rawMessage.f, - issuingClientId: rawMessage.i, - subscribeKey: rawMessage.k, - originationTimetoken: rawMessage.o, - userMetadata: rawMessage.u, - publishMetaData: publishMetaData, - }; - messages.push(parsedMessage); - }); - var metadata = { - timetoken: serverResponse.t.t, - region: serverResponse.t.r, - }; - return { messages: messages, metadata: metadata }; - } - - var subscribeEndpointConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation, - validateParams: validateParams, - getURL: getURL, - getRequestTimeout: getRequestTimeout, - isAuthSupported: isAuthSupported, - prepareParams: prepareParams, - handleResponse: handleResponse - }); - - var endpoint$1 = { - getOperation: function () { return OPERATIONS.PNHandshakeOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channels) && !(params === null || params === void 0 ? void 0 : params.channelGroups)) { - return 'channels and channleGroups both should not be empty'; - } - }, - getURL: function (_a, params) { - var config = _a.config; - var _b = params.channels, channels = _b === void 0 ? [] : _b; - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return "/v2/subscribe/".concat(config.subscribeKey, "/").concat(utils$5.encodeString(stringifiedChannels), "/0"); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getSubscribeTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_, params) { - var outParams = {}; - if (params.channelGroups && params.channelGroups.length > 0) { - outParams['channel-group'] = params.channelGroups.join(','); - } - outParams.tt = 0; - if (params.state) { - outParams.state = JSON.stringify(params.state); - } - if (params.filterExpression && params.filterExpression.length > 0) { - outParams['filter-expr'] = params.filterExpression; - } - outParams.ee = ''; - return outParams; - }, - handleResponse: function (_, response) { return ({ - region: response.t.r, - timetoken: response.t.t, - }); }, - }; - - var endpoint = { - getOperation: function () { return OPERATIONS.PNReceiveMessagesOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channels) && !(params === null || params === void 0 ? void 0 : params.channelGroups)) { - return 'channels and channleGroups both should not be empty'; - } - if (!(params === null || params === void 0 ? void 0 : params.timetoken)) { - return 'timetoken can not be empty'; - } - if (!(params === null || params === void 0 ? void 0 : params.region)) { - return 'region can not be empty'; - } - }, - getURL: function (_a, params) { - var config = _a.config; - var _b = params.channels, channels = _b === void 0 ? [] : _b; - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return "/v2/subscribe/".concat(config.subscribeKey, "/").concat(utils$5.encodeString(stringifiedChannels), "/0"); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getSubscribeTimeout(); - }, - isAuthSupported: function () { return true; }, - getAbortSignal: function (_, params) { return params.abortSignal; }, - prepareParams: function (_, params) { - var outParams = {}; - if (params.channelGroups && params.channelGroups.length > 0) { - outParams['channel-group'] = params.channelGroups.join(','); - } - if (params.filterExpression && params.filterExpression.length > 0) { - outParams['filter-expr'] = params.filterExpression; - } - outParams.tt = params.timetoken; - outParams.tr = params.region; - outParams.ee = ''; - return outParams; - }, - handleResponse: function (_, response) { - var parsedMessages = []; - response.m.forEach(function (envelope) { - var parsedMessage = { - shard: parseInt(envelope.a, 10), - subscriptionMatch: envelope.b, - channel: envelope.c, - messageType: envelope.e, - payload: envelope.d, - flags: envelope.f, - issuingClientId: envelope.i, - subscribeKey: envelope.k, - originationTimetoken: envelope.o, - userMetadata: envelope.u, - publishMetaData: { - timetoken: envelope.p.t, - region: envelope.p.r, - }, - }; - parsedMessages.push(parsedMessage); - }); - return { - messages: parsedMessages, - metadata: { - region: response.t.r, - timetoken: response.t.t, - }, - }; - }, - }; - - var Subject = /** @class */ (function () { - function Subject(sync) { - if (sync === void 0) { sync = false; } - this.sync = sync; - this.listeners = new Set(); - } - Subject.prototype.subscribe = function (listener) { - var _this = this; - this.listeners.add(listener); - return function () { - _this.listeners.delete(listener); - }; - }; - Subject.prototype.notify = function (event) { - var _this = this; - var wrapper = function () { - _this.listeners.forEach(function (listener) { - listener(event); - }); - }; - if (this.sync) { - wrapper(); - } - else { - setTimeout(wrapper, 0); - } - }; - return Subject; - }()); - - /* eslint-disable @typescript-eslint/no-explicit-any */ - var State = /** @class */ (function () { - function State(label) { - this.label = label; - this.transitionMap = new Map(); - this.enterEffects = []; - this.exitEffects = []; - } - State.prototype.transition = function (context, event) { - var _a; - if (this.transitionMap.has(event.type)) { - return (_a = this.transitionMap.get(event.type)) === null || _a === void 0 ? void 0 : _a(context, event); - } - return undefined; - }; - State.prototype.on = function (eventType, transition) { - this.transitionMap.set(eventType, transition); - return this; - }; - State.prototype.with = function (context, effects) { - return [this, context, effects !== null && effects !== void 0 ? effects : []]; - }; - State.prototype.onEnter = function (effect) { - this.enterEffects.push(effect); - return this; - }; - State.prototype.onExit = function (effect) { - this.exitEffects.push(effect); - return this; - }; - return State; - }()); - - /* eslint-disable @typescript-eslint/no-explicit-any */ - var Engine = /** @class */ (function (_super) { - __extends(Engine, _super); - function Engine() { - return _super !== null && _super.apply(this, arguments) || this; - } - Engine.prototype.describe = function (label) { - return new State(label); - }; - Engine.prototype.start = function (initialState, initialContext) { - this.currentState = initialState; - this.currentContext = initialContext; - this.notify({ - type: 'engineStarted', - state: initialState, - context: initialContext, - }); - return; - }; - Engine.prototype.transition = function (event) { - var e_1, _a, e_2, _b, e_3, _c; - if (!this.currentState) { - throw new Error('Start the engine first'); - } - this.notify({ - type: 'eventReceived', - event: event, - }); - var transition = this.currentState.transition(this.currentContext, event); - if (transition) { - var _d = __read$1(transition, 3), newState = _d[0], newContext = _d[1], effects = _d[2]; - try { - for (var _e = __values(this.currentState.exitEffects), _f = _e.next(); !_f.done; _f = _e.next()) { - var effect = _f.value; - this.notify({ - type: 'invocationDispatched', - invocation: effect(this.currentContext), - }); - } - } - catch (e_1_1) { e_1 = { error: e_1_1 }; } - finally { - try { - if (_f && !_f.done && (_a = _e.return)) _a.call(_e); - } - finally { if (e_1) throw e_1.error; } - } - var oldState = this.currentState; - this.currentState = newState; - var oldContext = this.currentContext; - this.currentContext = newContext; - this.notify({ - type: 'transitionDone', - fromState: oldState, - fromContext: oldContext, - toState: newState, - toContext: newContext, - event: event, - }); - try { - for (var effects_1 = __values(effects), effects_1_1 = effects_1.next(); !effects_1_1.done; effects_1_1 = effects_1.next()) { - var effect = effects_1_1.value; - this.notify({ - type: 'invocationDispatched', - invocation: effect, - }); - } - } - catch (e_2_1) { e_2 = { error: e_2_1 }; } - finally { - try { - if (effects_1_1 && !effects_1_1.done && (_b = effects_1.return)) _b.call(effects_1); - } - finally { if (e_2) throw e_2.error; } - } - try { - for (var _g = __values(this.currentState.enterEffects), _h = _g.next(); !_h.done; _h = _g.next()) { - var effect = _h.value; - this.notify({ - type: 'invocationDispatched', - invocation: effect(this.currentContext), - }); - } - } - catch (e_3_1) { e_3 = { error: e_3_1 }; } - finally { - try { - if (_h && !_h.done && (_c = _g.return)) _c.call(_g); - } - finally { if (e_3) throw e_3.error; } - } - } - }; - return Engine; - }(Subject)); - - /* eslint-disable @typescript-eslint/no-explicit-any */ - var Dispatcher = /** @class */ (function () { - function Dispatcher(dependencies) { - this.dependencies = dependencies; - this.instances = new Map(); - this.handlers = new Map(); - } - Dispatcher.prototype.on = function (type, handlerCreator) { - this.handlers.set(type, handlerCreator); - }; - Dispatcher.prototype.dispatch = function (invocation) { - if (invocation.type === 'CANCEL') { - if (this.instances.has(invocation.payload)) { - var instance_1 = this.instances.get(invocation.payload); - instance_1 === null || instance_1 === void 0 ? void 0 : instance_1.cancel(); - this.instances.delete(invocation.payload); - } - return; - } - var handlerCreator = this.handlers.get(invocation.type); - if (!handlerCreator) { - throw new Error("Unhandled invocation '".concat(invocation.type, "'")); - } - var instance = handlerCreator(invocation.payload, this.dependencies); - if (invocation.managed) { - this.instances.set(invocation.type, instance); - } - instance.start(); - }; - Dispatcher.prototype.dispose = function () { - var e_1, _a; - try { - for (var _b = __values(this.instances.entries()), _c = _b.next(); !_c.done; _c = _b.next()) { - var _d = __read$1(_c.value, 2), key = _d[0], instance = _d[1]; - instance.cancel(); - this.instances.delete(key); - } - } - catch (e_1_1) { e_1 = { error: e_1_1 }; } - finally { - try { - if (_c && !_c.done && (_a = _b.return)) _a.call(_b); - } - finally { if (e_1) throw e_1.error; } - } - }; - return Dispatcher; - }()); - - /* eslint-disable @typescript-eslint/no-explicit-any */ - function createEvent(type, fn) { - var creator = function () { - var args = []; - for (var _i = 0; _i < arguments.length; _i++) { - args[_i] = arguments[_i]; - } - return { - type: type, - payload: fn === null || fn === void 0 ? void 0 : fn.apply(void 0, __spreadArray$1([], __read$1(args), false)), - }; - }; - creator.type = type; - return creator; - } - function createEffect(type, fn) { - var creator = function () { - var args = []; - for (var _i = 0; _i < arguments.length; _i++) { - args[_i] = arguments[_i]; - } - return { type: type, payload: fn.apply(void 0, __spreadArray$1([], __read$1(args), false)), managed: false }; - }; - creator.type = type; - return creator; - } - function createManagedEffect(type, fn) { - var creator = function () { - var args = []; - for (var _i = 0; _i < arguments.length; _i++) { - args[_i] = arguments[_i]; - } - return { type: type, payload: fn.apply(void 0, __spreadArray$1([], __read$1(args), false)), managed: true }; - }; - creator.type = type; - creator.cancel = { type: 'CANCEL', payload: type, managed: false }; - return creator; - } - - var AbortError = /** @class */ (function (_super) { - __extends(AbortError, _super); - function AbortError() { - var _newTarget = this.constructor; - var _this = _super.call(this, 'The operation was aborted.') || this; - _this.name = 'AbortError'; - Object.setPrototypeOf(_this, _newTarget.prototype); - return _this; - } - return AbortError; - }(Error)); - var AbortSignal = /** @class */ (function (_super) { - __extends(AbortSignal, _super); - function AbortSignal() { - var _this = _super !== null && _super.apply(this, arguments) || this; - _this._aborted = false; - return _this; - } - Object.defineProperty(AbortSignal.prototype, "aborted", { - get: function () { - return this._aborted; - }, - enumerable: false, - configurable: true - }); - AbortSignal.prototype.throwIfAborted = function () { - if (this._aborted) { - throw new AbortError(); - } - }; - AbortSignal.prototype.abort = function () { - this._aborted = true; - this.notify(new AbortError()); - }; - return AbortSignal; - }(Subject)); - - var Handler = /** @class */ (function () { - function Handler(payload, dependencies) { - this.payload = payload; - this.dependencies = dependencies; - } - return Handler; - }()); - var AsyncHandler = /** @class */ (function (_super) { - __extends(AsyncHandler, _super); - function AsyncHandler(payload, dependencies, asyncFunction) { - var _this = _super.call(this, payload, dependencies) || this; - _this.asyncFunction = asyncFunction; - _this.abortSignal = new AbortSignal(); - return _this; - } - AsyncHandler.prototype.start = function () { - this.asyncFunction(this.payload, this.abortSignal, this.dependencies).catch(function (error) { - // console.log('Unhandled error:', error); - // swallow the error - }); - }; - AsyncHandler.prototype.cancel = function () { - this.abortSignal.abort(); - }; - return AsyncHandler; - }(Handler)); - var asyncHandler = function (handlerFunction) { - return function (payload, dependencies) { - return new AsyncHandler(payload, dependencies, handlerFunction); - }; - }; - - var handshake = createManagedEffect('HANDSHAKE', function (channels, groups) { return ({ - channels: channels, - groups: groups, - }); }); - var receiveMessages = createManagedEffect('RECEIVE_MESSAGES', function (channels, groups, cursor) { return ({ channels: channels, groups: groups, cursor: cursor }); }); - var emitMessages = createEffect('EMIT_MESSAGES', function (events) { return events; }); - var emitStatus$1 = createEffect('EMIT_STATUS', function (status) { return status; }); - var receiveReconnect = createManagedEffect('RECEIVE_RECONNECT', function (context) { return context; }); - var handshakeReconnect = createManagedEffect('HANDSHAKE_RECONNECT', function (context) { return context; }); - - var subscriptionChange = createEvent('SUBSCRIPTION_CHANGED', function (channels, groups) { return ({ - channels: channels, - groups: groups, - }); }); - var restore = createEvent('SUBSCRIPTION_RESTORED', function (channels, groups, timetoken, region) { return ({ - channels: channels, - groups: groups, - cursor: { - timetoken: timetoken, - region: region !== null && region !== void 0 ? region : 0, - }, - }); }); - var handshakeSuccess = createEvent('HANDSHAKE_SUCCESS', function (cursor) { return cursor; }); - var handshakeFailure = createEvent('HANDSHAKE_FAILURE', function (error) { return error; }); - var handshakeReconnectSuccess = createEvent('HANDSHAKE_RECONNECT_SUCCESS', function (cursor) { return ({ - cursor: cursor, - }); }); - var handshakeReconnectFailure = createEvent('HANDSHAKE_RECONNECT_FAILURE', function (error) { return error; }); - var handshakeReconnectGiveup = createEvent('HANDSHAKE_RECONNECT_GIVEUP', function (error) { return error; }); - var receiveSuccess = createEvent('RECEIVE_SUCCESS', function (cursor, events) { return ({ - cursor: cursor, - events: events, - }); }); - var receiveFailure = createEvent('RECEIVE_FAILURE', function (error) { return error; }); - var receiveReconnectSuccess = createEvent('RECEIVE_RECONNECT_SUCCESS', function (cursor, events) { return ({ - cursor: cursor, - events: events, - }); }); - var receiveReconnectFailure = createEvent('RECEIVE_RECONNECT_FAILURE', function (error) { return error; }); - var receiveReconnectGiveup = createEvent('RECEIVING_RECONNECT_GIVEUP', function (error) { return error; }); - var disconnect$1 = createEvent('DISCONNECT', function () { return ({}); }); - var reconnect$1 = createEvent('RECONNECT', function (timetoken, region) { return ({ - cursor: { - timetoken: timetoken !== null && timetoken !== void 0 ? timetoken : '', - region: region !== null && region !== void 0 ? region : 0, - }, - }); }); - var unsubscribeAll = createEvent('UNSUBSCRIBE_ALL', function () { return ({}); }); - - var EventEngineDispatcher = /** @class */ (function (_super) { - __extends(EventEngineDispatcher, _super); - function EventEngineDispatcher(engine, dependencies) { - var _this = _super.call(this, dependencies) || this; - _this.on(handshake.type, asyncHandler(function (payload, abortSignal, _a) { - var handshake = _a.handshake, presenceState = _a.presenceState, config = _a.config; - return __awaiter(_this, void 0, void 0, function () { - var result, e_1; - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - abortSignal.throwIfAborted(); - _b.label = 1; - case 1: - _b.trys.push([1, 3, , 4]); - return [4 /*yield*/, handshake(__assign({ abortSignal: abortSignal, channels: payload.channels, channelGroups: payload.groups, filterExpression: config.filterExpression }, (config.maintainPresenceState && { state: presenceState })))]; - case 2: - result = _b.sent(); - return [2 /*return*/, engine.transition(handshakeSuccess(result))]; - case 3: - e_1 = _b.sent(); - if (e_1 instanceof Error && e_1.message === 'Aborted') { - return [2 /*return*/]; - } - if (e_1 instanceof PubNubError) { - return [2 /*return*/, engine.transition(handshakeFailure(e_1))]; - } - return [3 /*break*/, 4]; - case 4: return [2 /*return*/]; - } - }); - }); - })); - _this.on(receiveMessages.type, asyncHandler(function (payload, abortSignal, _a) { - var receiveMessages = _a.receiveMessages, config = _a.config; - return __awaiter(_this, void 0, void 0, function () { - var result, error_1; - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - abortSignal.throwIfAborted(); - _b.label = 1; - case 1: - _b.trys.push([1, 3, , 4]); - return [4 /*yield*/, receiveMessages({ - abortSignal: abortSignal, - channels: payload.channels, - channelGroups: payload.groups, - timetoken: payload.cursor.timetoken, - region: payload.cursor.region, - filterExpression: config.filterExpression, - })]; - case 2: - result = _b.sent(); - engine.transition(receiveSuccess(result.metadata, result.messages)); - return [3 /*break*/, 4]; - case 3: - error_1 = _b.sent(); - if (error_1 instanceof Error && error_1.message === 'Aborted') { - return [2 /*return*/]; - } - if (error_1 instanceof PubNubError && !abortSignal.aborted) { - return [2 /*return*/, engine.transition(receiveFailure(error_1))]; - } - return [3 /*break*/, 4]; - case 4: return [2 /*return*/]; - } - }); - }); - })); - _this.on(emitMessages.type, asyncHandler(function (payload, _, _a) { - var emitMessages = _a.emitMessages; - return __awaiter(_this, void 0, void 0, function () { - return __generator(this, function (_b) { - if (payload.length > 0) { - emitMessages(payload); - } - return [2 /*return*/]; - }); - }); - })); - _this.on(emitStatus$1.type, asyncHandler(function (payload, _, _a) { - var emitStatus = _a.emitStatus; - return __awaiter(_this, void 0, void 0, function () { - return __generator(this, function (_b) { - emitStatus(payload); - return [2 /*return*/]; - }); - }); - })); - _this.on(receiveReconnect.type, asyncHandler(function (payload, abortSignal, _a) { - var receiveMessages = _a.receiveMessages, delay = _a.delay, config = _a.config; - return __awaiter(_this, void 0, void 0, function () { - var result, error_2; - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - if (!(config.retryConfiguration && config.retryConfiguration.shouldRetry(payload.reason, payload.attempts))) return [3 /*break*/, 6]; - abortSignal.throwIfAborted(); - return [4 /*yield*/, delay(config.retryConfiguration.getDelay(payload.attempts, payload.reason))]; - case 1: - _b.sent(); - abortSignal.throwIfAborted(); - _b.label = 2; - case 2: - _b.trys.push([2, 4, , 5]); - return [4 /*yield*/, receiveMessages({ - abortSignal: abortSignal, - channels: payload.channels, - channelGroups: payload.groups, - timetoken: payload.cursor.timetoken, - region: payload.cursor.region, - filterExpression: config.filterExpression, - })]; - case 3: - result = _b.sent(); - return [2 /*return*/, engine.transition(receiveReconnectSuccess(result.metadata, result.messages))]; - case 4: - error_2 = _b.sent(); - if (error_2 instanceof Error && error_2.message === 'Aborted') { - return [2 /*return*/]; - } - if (error_2 instanceof PubNubError) { - return [2 /*return*/, engine.transition(receiveReconnectFailure(error_2))]; - } - return [3 /*break*/, 5]; - case 5: return [3 /*break*/, 7]; - case 6: return [2 /*return*/, engine.transition(receiveReconnectGiveup(new PubNubError(config.retryConfiguration.getGiveupReason(payload.reason, payload.attempts))))]; - case 7: return [2 /*return*/]; - } - }); - }); - })); - _this.on(handshakeReconnect.type, asyncHandler(function (payload, abortSignal, _a) { - var handshake = _a.handshake, delay = _a.delay, presenceState = _a.presenceState, config = _a.config; - return __awaiter(_this, void 0, void 0, function () { - var result, error_3; - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - if (!(config.retryConfiguration && config.retryConfiguration.shouldRetry(payload.reason, payload.attempts))) return [3 /*break*/, 6]; - abortSignal.throwIfAborted(); - return [4 /*yield*/, delay(config.retryConfiguration.getDelay(payload.attempts, payload.reason))]; - case 1: - _b.sent(); - abortSignal.throwIfAborted(); - _b.label = 2; - case 2: - _b.trys.push([2, 4, , 5]); - return [4 /*yield*/, handshake(__assign({ abortSignal: abortSignal, channels: payload.channels, channelGroups: payload.groups, filterExpression: config.filterExpression }, (config.maintainPresenceState && { state: presenceState })))]; - case 3: - result = _b.sent(); - return [2 /*return*/, engine.transition(handshakeReconnectSuccess(result))]; - case 4: - error_3 = _b.sent(); - if (error_3 instanceof Error && error_3.message === 'Aborted') { - return [2 /*return*/]; - } - if (error_3 instanceof PubNubError) { - return [2 /*return*/, engine.transition(handshakeReconnectFailure(error_3))]; - } - return [3 /*break*/, 5]; - case 5: return [3 /*break*/, 7]; - case 6: return [2 /*return*/, engine.transition(handshakeReconnectGiveup(new PubNubError(config.retryConfiguration.getGiveupReason(payload.reason, payload.attempts))))]; - case 7: return [2 /*return*/]; - } - }); - }); - })); - return _this; - } - return EventEngineDispatcher; - }(Dispatcher)); - - var HandshakeFailedState = new State('HANDSHAKE_FAILED'); - HandshakeFailedState.on(subscriptionChange.type, function (context, event) { - return HandshakingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: context.cursor, - }); - }); - HandshakeFailedState.on(reconnect$1.type, function (context, event) { - return HandshakingState.with({ - channels: context.channels, - groups: context.groups, - cursor: event.payload.cursor || context.cursor, - }); - }); - HandshakeFailedState.on(restore.type, function (context, event) { - var _a, _b; - return HandshakingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: { - timetoken: event.payload.cursor.timetoken, - region: event.payload.cursor.region ? event.payload.cursor.region : (_b = (_a = context === null || context === void 0 ? void 0 : context.cursor) === null || _a === void 0 ? void 0 : _a.region) !== null && _b !== void 0 ? _b : 0, - }, - }); - }); - HandshakeFailedState.on(unsubscribeAll.type, function (_) { return UnsubscribedState.with(); }); - - var HandshakeStoppedState = new State('HANDSHAKE_STOPPED'); - HandshakeStoppedState.on(subscriptionChange.type, function (context, event) { - return HandshakeStoppedState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: context.cursor, - }); - }); - HandshakeStoppedState.on(reconnect$1.type, function (context, event) { - return HandshakingState.with(__assign(__assign({}, context), { cursor: event.payload.cursor || context.cursor })); - }); - HandshakeStoppedState.on(restore.type, function (context, event) { - var _a; - return HandshakeStoppedState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: { - timetoken: event.payload.cursor.timetoken, - region: event.payload.cursor.region || ((_a = context === null || context === void 0 ? void 0 : context.cursor) === null || _a === void 0 ? void 0 : _a.region) || 0, - }, - }); - }); - HandshakeStoppedState.on(unsubscribeAll.type, function (_) { return UnsubscribedState.with(); }); - - var ReceiveFailedState = new State('RECEIVE_FAILED'); - ReceiveFailedState.on(reconnect$1.type, function (context, event) { - var _a; - return HandshakingState.with({ - channels: context.channels, - groups: context.groups, - cursor: { - timetoken: !!event.payload.cursor.timetoken ? (_a = event.payload.cursor) === null || _a === void 0 ? void 0 : _a.timetoken : context.cursor.timetoken, - region: event.payload.cursor.region || context.cursor.region, - }, - }); - }); - ReceiveFailedState.on(subscriptionChange.type, function (context, event) { - return HandshakingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: context.cursor, - }); - }); - ReceiveFailedState.on(restore.type, function (context, event) { - return HandshakingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: { - timetoken: event.payload.cursor.timetoken, - region: event.payload.cursor.region || context.cursor.region, - }, - }); - }); - ReceiveFailedState.on(unsubscribeAll.type, function (_) { return UnsubscribedState.with(undefined); }); - - var ReceiveStoppedState = new State('RECEIVE_STOPPED'); - ReceiveStoppedState.on(subscriptionChange.type, function (context, event) { - return ReceiveStoppedState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: context.cursor, - }); - }); - ReceiveStoppedState.on(restore.type, function (context, event) { - return ReceiveStoppedState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: { - timetoken: event.payload.cursor.timetoken, - region: event.payload.cursor.region || context.cursor.region, - }, - }); - }); - ReceiveStoppedState.on(reconnect$1.type, function (context, event) { - var _a; - return HandshakingState.with({ - channels: context.channels, - groups: context.groups, - cursor: { - timetoken: !!event.payload.cursor.timetoken ? (_a = event.payload.cursor) === null || _a === void 0 ? void 0 : _a.timetoken : context.cursor.timetoken, - region: event.payload.cursor.region || context.cursor.region, - }, - }); - }); - ReceiveStoppedState.on(unsubscribeAll.type, function () { return UnsubscribedState.with(undefined); }); - - var ReceiveReconnectingState = new State('RECEIVE_RECONNECTING'); - ReceiveReconnectingState.onEnter(function (context) { return receiveReconnect(context); }); - ReceiveReconnectingState.onExit(function () { return receiveReconnect.cancel; }); - ReceiveReconnectingState.on(receiveReconnectSuccess.type, function (context, event) { - return ReceivingState.with({ - channels: context.channels, - groups: context.groups, - cursor: event.payload.cursor, - }, [emitMessages(event.payload.events)]); - }); - ReceiveReconnectingState.on(receiveReconnectFailure.type, function (context, event) { - return ReceiveReconnectingState.with(__assign(__assign({}, context), { attempts: context.attempts + 1, reason: event.payload })); - }); - ReceiveReconnectingState.on(receiveReconnectGiveup.type, function (context, event) { - var _a; - return ReceiveFailedState.with({ - groups: context.groups, - channels: context.channels, - cursor: context.cursor, - reason: event.payload, - }, [emitStatus$1({ category: categories.PNDisconnectedUnexpectedlyCategory, error: (_a = event.payload) === null || _a === void 0 ? void 0 : _a.message })]); - }); - ReceiveReconnectingState.on(disconnect$1.type, function (context) { - return ReceiveStoppedState.with({ - channels: context.channels, - groups: context.groups, - cursor: context.cursor, - }, [emitStatus$1({ category: categories.PNDisconnectedCategory })]); - }); - ReceiveReconnectingState.on(restore.type, function (context, event) { - return ReceivingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: { - timetoken: event.payload.cursor.timetoken, - region: event.payload.cursor.region || context.cursor.region, - }, - }); - }); - ReceiveReconnectingState.on(subscriptionChange.type, function (context, event) { - return ReceivingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: context.cursor, - }); - }); - ReceiveReconnectingState.on(unsubscribeAll.type, function (_) { - return UnsubscribedState.with(undefined, [emitStatus$1({ category: categories.PNDisconnectedCategory })]); - }); - - var ReceivingState = new State('RECEIVING'); - ReceivingState.onEnter(function (context) { return receiveMessages(context.channels, context.groups, context.cursor); }); - ReceivingState.onExit(function () { return receiveMessages.cancel; }); - ReceivingState.on(receiveSuccess.type, function (context, event) { - return ReceivingState.with({ channels: context.channels, groups: context.groups, cursor: event.payload.cursor }, [ - emitMessages(event.payload.events), - ]); - }); - ReceivingState.on(subscriptionChange.type, function (context, event) { - if (event.payload.channels.length === 0 && event.payload.groups.length === 0) { - return UnsubscribedState.with(undefined); - } - return ReceivingState.with({ - cursor: context.cursor, - channels: event.payload.channels, - groups: event.payload.groups, - }); - }); - ReceivingState.on(restore.type, function (context, event) { - if (event.payload.channels.length === 0 && event.payload.groups.length === 0) { - return UnsubscribedState.with(undefined); - } - return ReceivingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: { - timetoken: event.payload.cursor.timetoken, - region: event.payload.cursor.region || context.cursor.region, - }, - }); - }); - ReceivingState.on(receiveFailure.type, function (context, event) { - return ReceiveReconnectingState.with(__assign(__assign({}, context), { attempts: 0, reason: event.payload })); - }); - ReceivingState.on(disconnect$1.type, function (context) { - return ReceiveStoppedState.with({ - channels: context.channels, - groups: context.groups, - cursor: context.cursor, - }, [emitStatus$1({ category: categories.PNDisconnectedCategory })]); - }); - ReceivingState.on(unsubscribeAll.type, function (_) { - return UnsubscribedState.with(undefined, [emitStatus$1({ category: categories.PNDisconnectedCategory })]); - }); - - var HandshakeReconnectingState = new State('HANDSHAKE_RECONNECTING'); - HandshakeReconnectingState.onEnter(function (context) { return handshakeReconnect(context); }); - HandshakeReconnectingState.onExit(function () { return handshakeReconnect.cancel; }); - HandshakeReconnectingState.on(handshakeReconnectSuccess.type, function (context, event) { - var _a, _b; - var cursor = { - timetoken: !!((_a = context.cursor) === null || _a === void 0 ? void 0 : _a.timetoken) ? (_b = context.cursor) === null || _b === void 0 ? void 0 : _b.timetoken : event.payload.cursor.timetoken, - region: event.payload.cursor.region, - }; - return ReceivingState.with({ - channels: context.channels, - groups: context.groups, - cursor: cursor, - }, [emitStatus$1({ category: categories.PNConnectedCategory })]); - }); - HandshakeReconnectingState.on(handshakeReconnectFailure.type, function (context, event) { - return HandshakeReconnectingState.with(__assign(__assign({}, context), { attempts: context.attempts + 1, reason: event.payload })); - }); - HandshakeReconnectingState.on(handshakeReconnectGiveup.type, function (context, event) { - var _a; - return HandshakeFailedState.with({ - groups: context.groups, - channels: context.channels, - cursor: context.cursor, - reason: event.payload, - }, [emitStatus$1({ category: categories.PNConnectionErrorCategory, error: (_a = event.payload) === null || _a === void 0 ? void 0 : _a.message })]); - }); - HandshakeReconnectingState.on(disconnect$1.type, function (context) { - return HandshakeStoppedState.with({ - channels: context.channels, - groups: context.groups, - cursor: context.cursor, - }); - }); - HandshakeReconnectingState.on(subscriptionChange.type, function (context, event) { - return HandshakingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: context.cursor, - }); - }); - HandshakeReconnectingState.on(restore.type, function (context, event) { - var _a, _b; - return HandshakingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: { - timetoken: event.payload.cursor.timetoken, - region: ((_a = event.payload.cursor) === null || _a === void 0 ? void 0 : _a.region) || ((_b = context === null || context === void 0 ? void 0 : context.cursor) === null || _b === void 0 ? void 0 : _b.region) || 0, - }, - }); - }); - HandshakeReconnectingState.on(unsubscribeAll.type, function (_) { return UnsubscribedState.with(undefined); }); - - var HandshakingState = new State('HANDSHAKING'); - HandshakingState.onEnter(function (context) { return handshake(context.channels, context.groups); }); - HandshakingState.onExit(function () { return handshake.cancel; }); - HandshakingState.on(subscriptionChange.type, function (context, event) { - if (event.payload.channels.length === 0 && event.payload.groups.length === 0) { - return UnsubscribedState.with(undefined); - } - return HandshakingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: context.cursor, - }); - }); - HandshakingState.on(handshakeSuccess.type, function (context, event) { - var _a, _b; - return ReceivingState.with({ - channels: context.channels, - groups: context.groups, - cursor: { - timetoken: !!((_a = context === null || context === void 0 ? void 0 : context.cursor) === null || _a === void 0 ? void 0 : _a.timetoken) ? (_b = context === null || context === void 0 ? void 0 : context.cursor) === null || _b === void 0 ? void 0 : _b.timetoken : event.payload.timetoken, - region: event.payload.region, - }, - }, [ - emitStatus$1({ - category: categories.PNConnectedCategory, - }), - ]); - }); - HandshakingState.on(handshakeFailure.type, function (context, event) { - return HandshakeReconnectingState.with({ - channels: context.channels, - groups: context.groups, - cursor: context.cursor, - attempts: 0, - reason: event.payload, - }); - }); - HandshakingState.on(disconnect$1.type, function (context) { - return HandshakeStoppedState.with({ - channels: context.channels, - groups: context.groups, - cursor: context.cursor, - }); - }); - HandshakingState.on(restore.type, function (context, event) { - var _a; - return HandshakingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: { - timetoken: event.payload.cursor.timetoken, - region: event.payload.cursor.region || ((_a = context === null || context === void 0 ? void 0 : context.cursor) === null || _a === void 0 ? void 0 : _a.region) || 0, - }, - }); - }); - HandshakingState.on(unsubscribeAll.type, function (_) { return UnsubscribedState.with(); }); - - var UnsubscribedState = new State('UNSUBSCRIBED'); - UnsubscribedState.on(subscriptionChange.type, function (_, event) { - return HandshakingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - }); - }); - UnsubscribedState.on(restore.type, function (_, event) { - return HandshakingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: event.payload.cursor, - }); - }); - - var EventEngine = /** @class */ (function () { - function EventEngine(dependencies) { - var _this = this; - this.engine = new Engine(); - this.channels = []; - this.groups = []; - this.dependencies = dependencies; - this.dispatcher = new EventEngineDispatcher(this.engine, dependencies); - this._unsubscribeEngine = this.engine.subscribe(function (change) { - if (change.type === 'invocationDispatched') { - _this.dispatcher.dispatch(change.invocation); - } - }); - this.engine.start(UnsubscribedState, undefined); - } - Object.defineProperty(EventEngine.prototype, "_engine", { - get: function () { - return this.engine; - }, - enumerable: false, - configurable: true - }); - EventEngine.prototype.subscribe = function (_a) { - var _this = this; - var channels = _a.channels, channelGroups = _a.channelGroups, timetoken = _a.timetoken, withPresence = _a.withPresence; - this.channels = __spreadArray$1(__spreadArray$1([], __read$1(this.channels), false), __read$1((channels !== null && channels !== void 0 ? channels : [])), false); - this.groups = __spreadArray$1(__spreadArray$1([], __read$1(this.groups), false), __read$1((channelGroups !== null && channelGroups !== void 0 ? channelGroups : [])), false); - if (withPresence) { - this.channels.map(function (c) { return _this.channels.push("".concat(c, "-pnpres")); }); - this.groups.map(function (g) { return _this.groups.push("".concat(g, "-pnpres")); }); - } - if (timetoken) { - this.engine.transition(restore(Array.from(new Set(__spreadArray$1(__spreadArray$1([], __read$1(this.channels), false), __read$1((channels !== null && channels !== void 0 ? channels : [])), false))), Array.from(new Set(__spreadArray$1(__spreadArray$1([], __read$1(this.groups), false), __read$1((channelGroups !== null && channelGroups !== void 0 ? channelGroups : [])), false))), timetoken)); - } - else { - this.engine.transition(subscriptionChange(Array.from(new Set(__spreadArray$1(__spreadArray$1([], __read$1(this.channels), false), __read$1((channels !== null && channels !== void 0 ? channels : [])), false))), Array.from(new Set(__spreadArray$1(__spreadArray$1([], __read$1(this.groups), false), __read$1((channelGroups !== null && channelGroups !== void 0 ? channelGroups : [])), false))))); - } - if (this.dependencies.join) { - this.dependencies.join({ - channels: Array.from(new Set(this.channels.filter(function (c) { return !c.endsWith('-pnpres'); }))), - groups: Array.from(new Set(this.groups.filter(function (g) { return !g.endsWith('-pnpres'); }))), - }); - } - }; - EventEngine.prototype.unsubscribe = function (_a) { - var _this = this; - var _b = _a.channels, channels = _b === void 0 ? [] : _b, _c = _a.channelGroups, channelGroups = _c === void 0 ? [] : _c; - var filteredChannels = utils$5.removeSingleOccurance(this.channels, __spreadArray$1(__spreadArray$1([], __read$1(channels), false), __read$1(channels.map(function (c) { return "".concat(c, "-pnpres"); })), false)); - var filteredGroups = utils$5.removeSingleOccurance(this.groups, __spreadArray$1(__spreadArray$1([], __read$1(channelGroups), false), __read$1(channelGroups.map(function (c) { return "".concat(c, "-pnpres"); })), false)); - if (new Set(this.channels).size !== new Set(filteredChannels).size || - new Set(this.groups).size !== new Set(filteredGroups).size) { - var channelsToLeave = utils$5.findUniqueCommonElements(this.channels, channels); - var groupstoLeave = utils$5.findUniqueCommonElements(this.groups, channelGroups); - if (this.dependencies.presenceState) { - channelsToLeave === null || channelsToLeave === void 0 ? void 0 : channelsToLeave.forEach(function (c) { return delete _this.dependencies.presenceState[c]; }); - groupstoLeave === null || groupstoLeave === void 0 ? void 0 : groupstoLeave.forEach(function (g) { return delete _this.dependencies.presenceState[g]; }); - } - this.channels = filteredChannels; - this.groups = filteredGroups; - this.engine.transition(subscriptionChange(Array.from(new Set(this.channels.slice(0))), Array.from(new Set(this.groups.slice(0))))); - if (this.dependencies.leave) { - this.dependencies.leave({ - channels: channelsToLeave.slice(0), - groups: groupstoLeave.slice(0), - }); - } - } - }; - EventEngine.prototype.unsubscribeAll = function () { - this.channels = []; - this.groups = []; - if (this.dependencies.presenceState) { - this.dependencies.presenceState = {}; - } - this.engine.transition(subscriptionChange(this.channels.slice(0), this.groups.slice(0))); - if (this.dependencies.leaveAll) { - this.dependencies.leaveAll(); - } - }; - EventEngine.prototype.reconnect = function (_a) { - var timetoken = _a.timetoken, region = _a.region; - this.engine.transition(reconnect$1(timetoken, region)); - }; - EventEngine.prototype.disconnect = function () { - this.engine.transition(disconnect$1()); - if (this.dependencies.leaveAll) { - this.dependencies.leaveAll(); - } - }; - EventEngine.prototype.getSubscribedChannels = function () { - return Array.from(new Set(this.channels)); - }; - EventEngine.prototype.getSubscribedChannelGroups = function () { - return Array.from(new Set(this.groups)); - }; - EventEngine.prototype.dispose = function () { - this.disconnect(); - this._unsubscribeEngine(); - this.dispatcher.dispose(); - }; - return EventEngine; - }()); - - var reconnect = createEvent('RECONNECT', function () { return ({}); }); - var disconnect = createEvent('DISCONNECT', function () { return ({}); }); - var joined = createEvent('JOINED', function (channels, groups) { return ({ - channels: channels, - groups: groups, - }); }); - var left = createEvent('LEFT', function (channels, groups) { return ({ - channels: channels, - groups: groups, - }); }); - var leftAll = createEvent('LEFT_ALL', function () { return ({}); }); - var heartbeatSuccess = createEvent('HEARTBEAT_SUCCESS', function (statusCode) { return ({ statusCode: statusCode }); }); - var heartbeatFailure = createEvent('HEARTBEAT_FAILURE', function (error) { return error; }); - var heartbeatGiveup = createEvent('HEARTBEAT_GIVEUP', function () { return ({}); }); - var timesUp = createEvent('TIMES_UP', function () { return ({}); }); - - var heartbeat = createEffect('HEARTBEAT', function (channels, groups) { return ({ - channels: channels, - groups: groups, - }); }); - var leave = createEffect('LEAVE', function (channels, groups) { return ({ - channels: channels, - groups: groups, - }); }); - var emitStatus = createEffect('EMIT_STATUS', function (status) { return status; }); - var wait = createManagedEffect('WAIT', function () { return ({}); }); - var delayedHeartbeat = createManagedEffect('DELAYED_HEARTBEAT', function (context) { return context; }); - - var PresenceEventEngineDispatcher = /** @class */ (function (_super) { - __extends(PresenceEventEngineDispatcher, _super); - function PresenceEventEngineDispatcher(engine, dependencies) { - var _this = _super.call(this, dependencies) || this; - _this.on(heartbeat.type, asyncHandler(function (payload, _, _a) { - var heartbeat = _a.heartbeat, presenceState = _a.presenceState, config = _a.config; - return __awaiter(_this, void 0, void 0, function () { - var e_1; - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - _b.trys.push([0, 2, , 3]); - return [4 /*yield*/, heartbeat(__assign({ channels: payload.channels, channelGroups: payload.groups }, (config.maintainPresenceState && { state: presenceState })))]; - case 1: - _b.sent(); - engine.transition(heartbeatSuccess(200)); - return [3 /*break*/, 3]; - case 2: - e_1 = _b.sent(); - if (e_1 instanceof PubNubError) { - return [2 /*return*/, engine.transition(heartbeatFailure(e_1))]; - } - return [3 /*break*/, 3]; - case 3: return [2 /*return*/]; - } - }); - }); - })); - _this.on(leave.type, asyncHandler(function (payload, _, _a) { - var leave = _a.leave, config = _a.config; - return __awaiter(_this, void 0, void 0, function () { - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - if (!!config.suppressLeaveEvents) return [3 /*break*/, 4]; - _b.label = 1; - case 1: - _b.trys.push([1, 3, , 4]); - return [4 /*yield*/, leave({ - channels: payload.channels, - channelGroups: payload.groups, - })]; - case 2: - _b.sent(); - return [3 /*break*/, 4]; - case 3: - _b.sent(); - return [3 /*break*/, 4]; - case 4: return [2 /*return*/]; - } - }); - }); - })); - _this.on(wait.type, asyncHandler(function (_, abortSignal, _a) { - var heartbeatDelay = _a.heartbeatDelay; - return __awaiter(_this, void 0, void 0, function () { - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - abortSignal.throwIfAborted(); - return [4 /*yield*/, heartbeatDelay()]; - case 1: - _b.sent(); - abortSignal.throwIfAborted(); - return [2 /*return*/, engine.transition(timesUp())]; - } - }); - }); - })); - _this.on(delayedHeartbeat.type, asyncHandler(function (payload, abortSignal, _a) { - var heartbeat = _a.heartbeat, retryDelay = _a.retryDelay, presenceState = _a.presenceState, config = _a.config; - return __awaiter(_this, void 0, void 0, function () { - var e_3; - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - if (!(config.retryConfiguration && config.retryConfiguration.shouldRetry(payload.reason, payload.attempts))) return [3 /*break*/, 6]; - abortSignal.throwIfAborted(); - return [4 /*yield*/, retryDelay(config.retryConfiguration.getDelay(payload.attempts, payload.reason))]; - case 1: - _b.sent(); - abortSignal.throwIfAborted(); - _b.label = 2; - case 2: - _b.trys.push([2, 4, , 5]); - return [4 /*yield*/, heartbeat(__assign({ channels: payload.channels, channelGroups: payload.groups }, (config.maintainPresenceState && { state: presenceState })))]; - case 3: - _b.sent(); - return [2 /*return*/, engine.transition(heartbeatSuccess(200))]; - case 4: - e_3 = _b.sent(); - if (e_3 instanceof Error && e_3.message === 'Aborted') { - return [2 /*return*/]; - } - if (e_3 instanceof PubNubError) { - return [2 /*return*/, engine.transition(heartbeatFailure(e_3))]; - } - return [3 /*break*/, 5]; - case 5: return [3 /*break*/, 7]; - case 6: return [2 /*return*/, engine.transition(heartbeatGiveup())]; - case 7: return [2 /*return*/]; - } - }); - }); - })); - _this.on(emitStatus.type, asyncHandler(function (payload, _, _a) { - var emitStatus = _a.emitStatus, config = _a.config; - return __awaiter(_this, void 0, void 0, function () { - var _b; - return __generator(this, function (_c) { - if (config.announceFailedHeartbeats && ((_b = payload === null || payload === void 0 ? void 0 : payload.status) === null || _b === void 0 ? void 0 : _b.error) === true) { - emitStatus(payload.status); - } - else if (config.announceSuccessfulHeartbeats && payload.statusCode === 200) { - emitStatus(__assign(__assign({}, payload), { operation: OPERATIONS.PNHeartbeatOperation, error: false })); - } - return [2 /*return*/]; - }); - }); - })); - return _this; - } - return PresenceEventEngineDispatcher; - }(Dispatcher)); - - var HeartbeatStoppedState = new State('HEARTBEAT_STOPPED'); - HeartbeatStoppedState.on(joined.type, function (context, event) { - return HeartbeatStoppedState.with({ - channels: __spreadArray$1(__spreadArray$1([], __read$1(context.channels), false), __read$1(event.payload.channels), false), - groups: __spreadArray$1(__spreadArray$1([], __read$1(context.groups), false), __read$1(event.payload.groups), false), - }); - }); - HeartbeatStoppedState.on(left.type, function (context, event) { - return HeartbeatStoppedState.with({ - channels: context.channels.filter(function (channel) { return !event.payload.channels.includes(channel); }), - groups: context.groups.filter(function (group) { return !event.payload.groups.includes(group); }), - }); - }); - HeartbeatStoppedState.on(reconnect.type, function (context, _) { - return HeartbeatingState.with({ - channels: context.channels, - groups: context.groups, - }); - }); - HeartbeatStoppedState.on(leftAll.type, function (context, _) { return HeartbeatInactiveState.with(undefined); }); - - var HeartbeatCooldownState = new State('HEARTBEAT_COOLDOWN'); - HeartbeatCooldownState.onEnter(function () { return wait(); }); - HeartbeatCooldownState.onExit(function () { return wait.cancel; }); - HeartbeatCooldownState.on(timesUp.type, function (context, _) { - return HeartbeatingState.with({ - channels: context.channels, - groups: context.groups, - }); - }); - HeartbeatCooldownState.on(joined.type, function (context, event) { - return HeartbeatingState.with({ - channels: __spreadArray$1(__spreadArray$1([], __read$1(context.channels), false), __read$1(event.payload.channels), false), - groups: __spreadArray$1(__spreadArray$1([], __read$1(context.groups), false), __read$1(event.payload.groups), false), - }); - }); - HeartbeatCooldownState.on(left.type, function (context, event) { - return HeartbeatingState.with({ - channels: context.channels.filter(function (channel) { return !event.payload.channels.includes(channel); }), - groups: context.groups.filter(function (group) { return !event.payload.groups.includes(group); }), - }, [leave(event.payload.channels, event.payload.groups)]); - }); - HeartbeatCooldownState.on(disconnect.type, function (context) { - return HeartbeatStoppedState.with({ - channels: context.channels, - groups: context.groups, - }, [leave(context.channels, context.groups)]); - }); - HeartbeatCooldownState.on(leftAll.type, function (context, _) { - return HeartbeatInactiveState.with(undefined, [leave(context.channels, context.groups)]); - }); - - var HeartbeatFailedState = new State('HEARTBEAT_FAILED'); - HeartbeatFailedState.on(joined.type, function (context, event) { - return HeartbeatingState.with({ - channels: __spreadArray$1(__spreadArray$1([], __read$1(context.channels), false), __read$1(event.payload.channels), false), - groups: __spreadArray$1(__spreadArray$1([], __read$1(context.groups), false), __read$1(event.payload.groups), false), - }); - }); - HeartbeatFailedState.on(left.type, function (context, event) { - return HeartbeatingState.with({ - channels: context.channels.filter(function (channel) { return !event.payload.channels.includes(channel); }), - groups: context.groups.filter(function (group) { return !event.payload.groups.includes(group); }), - }, [leave(event.payload.channels, event.payload.groups)]); - }); - HeartbeatFailedState.on(reconnect.type, function (context, _) { - return HeartbeatingState.with({ - channels: context.channels, - groups: context.groups, - }); - }); - HeartbeatFailedState.on(disconnect.type, function (context, _) { - return HeartbeatStoppedState.with({ - channels: context.channels, - groups: context.groups, - }, [leave(context.channels, context.groups)]); - }); - HeartbeatFailedState.on(leftAll.type, function (context, _) { - return HeartbeatInactiveState.with(undefined, [leave(context.channels, context.groups)]); - }); - - var HearbeatReconnectingState = new State('HEARBEAT_RECONNECTING'); - HearbeatReconnectingState.onEnter(function (context) { return delayedHeartbeat(context); }); - HearbeatReconnectingState.onExit(function () { return delayedHeartbeat.cancel; }); - HearbeatReconnectingState.on(joined.type, function (context, event) { - return HeartbeatingState.with({ - channels: __spreadArray$1(__spreadArray$1([], __read$1(context.channels), false), __read$1(event.payload.channels), false), - groups: __spreadArray$1(__spreadArray$1([], __read$1(context.groups), false), __read$1(event.payload.groups), false), - }); - }); - HearbeatReconnectingState.on(left.type, function (context, event) { - return HeartbeatingState.with({ - channels: context.channels.filter(function (channel) { return !event.payload.channels.includes(channel); }), - groups: context.groups.filter(function (group) { return !event.payload.groups.includes(group); }), - }, [leave(event.payload.channels, event.payload.groups)]); - }); - HearbeatReconnectingState.on(disconnect.type, function (context, _) { - HeartbeatStoppedState.with({ - channels: context.channels, - groups: context.groups, - }, [leave(context.channels, context.groups)]); - }); - HearbeatReconnectingState.on(heartbeatSuccess.type, function (context, event) { - return HeartbeatCooldownState.with({ - channels: context.channels, - groups: context.groups, - }); - }); - HearbeatReconnectingState.on(heartbeatFailure.type, function (context, event) { - return HearbeatReconnectingState.with(__assign(__assign({}, context), { attempts: context.attempts + 1, reason: event.payload })); - }); - HearbeatReconnectingState.on(heartbeatGiveup.type, function (context, event) { - return HeartbeatFailedState.with({ - channels: context.channels, - groups: context.groups, - }); - }); - HearbeatReconnectingState.on(leftAll.type, function (context, _) { - return HeartbeatInactiveState.with(undefined, [leave(context.channels, context.groups)]); - }); - - var HeartbeatingState = new State('HEARTBEATING'); - HeartbeatingState.onEnter(function (context) { return heartbeat(context.channels, context.groups); }); - HeartbeatingState.on(heartbeatSuccess.type, function (context, event) { - return HeartbeatCooldownState.with({ - channels: context.channels, - groups: context.groups, - }); - }); - HeartbeatingState.on(joined.type, function (context, event) { - return HeartbeatingState.with({ - channels: __spreadArray$1(__spreadArray$1([], __read$1(context.channels), false), __read$1(event.payload.channels), false), - groups: __spreadArray$1(__spreadArray$1([], __read$1(context.groups), false), __read$1(event.payload.groups), false), - }); - }); - HeartbeatingState.on(left.type, function (context, event) { - return HeartbeatingState.with({ - channels: context.channels.filter(function (channel) { return !event.payload.channels.includes(channel); }), - groups: context.groups.filter(function (group) { return !event.payload.groups.includes(group); }), - }, [leave(event.payload.channels, event.payload.groups)]); - }); - HeartbeatingState.on(heartbeatFailure.type, function (context, event) { - return HearbeatReconnectingState.with(__assign(__assign({}, context), { attempts: 0, reason: event.payload })); - }); - HeartbeatingState.on(disconnect.type, function (context) { - return HeartbeatStoppedState.with({ - channels: context.channels, - groups: context.groups, - }, [leave(context.channels, context.groups)]); - }); - HeartbeatingState.on(leftAll.type, function (context, _) { - return HeartbeatInactiveState.with(undefined, [leave(context.channels, context.groups)]); - }); - - var HeartbeatInactiveState = new State('HEARTBEAT_INACTIVE'); - HeartbeatInactiveState.on(joined.type, function (_, event) { - return HeartbeatingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - }); - }); - - var PresenceEventEngine = /** @class */ (function () { - function PresenceEventEngine(dependencies) { - var _this = this; - this.engine = new Engine(); - this.channels = []; - this.groups = []; - this.dispatcher = new PresenceEventEngineDispatcher(this.engine, dependencies); - this.dependencies = dependencies; - this._unsubscribeEngine = this.engine.subscribe(function (change) { - if (change.type === 'invocationDispatched') { - _this.dispatcher.dispatch(change.invocation); - } - }); - this.engine.start(HeartbeatInactiveState, undefined); - } - Object.defineProperty(PresenceEventEngine.prototype, "_engine", { - get: function () { - return this.engine; - }, - enumerable: false, - configurable: true - }); - PresenceEventEngine.prototype.join = function (_a) { - var channels = _a.channels, groups = _a.groups; - this.channels = __spreadArray$1(__spreadArray$1([], __read$1(this.channels), false), __read$1((channels !== null && channels !== void 0 ? channels : [])), false); - this.groups = __spreadArray$1(__spreadArray$1([], __read$1(this.groups), false), __read$1((groups !== null && groups !== void 0 ? groups : [])), false); - this.engine.transition(joined(this.channels.slice(0), this.groups.slice(0))); - }; - PresenceEventEngine.prototype.leave = function (_a) { - var _this = this; - var channels = _a.channels, groups = _a.groups; - if (this.dependencies.presenceState) { - channels === null || channels === void 0 ? void 0 : channels.forEach(function (c) { return delete _this.dependencies.presenceState[c]; }); - groups === null || groups === void 0 ? void 0 : groups.forEach(function (g) { return delete _this.dependencies.presenceState[g]; }); - } - this.engine.transition(left(channels !== null && channels !== void 0 ? channels : [], groups !== null && groups !== void 0 ? groups : [])); - }; - PresenceEventEngine.prototype.leaveAll = function () { - this.engine.transition(leftAll()); - }; - PresenceEventEngine.prototype.dispose = function () { - this._unsubscribeEngine(); - this.dispatcher.dispose(); - }; - return PresenceEventEngine; - }()); - - var RetryPolicy = /** @class */ (function () { - function RetryPolicy() { - } - RetryPolicy.LinearRetryPolicy = function (configuration) { - return { - delay: configuration.delay, - maximumRetry: configuration.maximumRetry, - shouldRetry: function (error, attempt) { - var _a; - if (((_a = error === null || error === void 0 ? void 0 : error.status) === null || _a === void 0 ? void 0 : _a.statusCode) === 403) { - return false; - } - return this.maximumRetry > attempt; - }, - getDelay: function (_, reason) { - var _a; - var delay = (_a = reason.retryAfter) !== null && _a !== void 0 ? _a : this.delay; - return (delay + Math.random()) * 1000; - }, - getGiveupReason: function (error, attempt) { - var _a; - if (this.maximumRetry <= attempt) { - return 'retry attempts exhaused.'; - } - if (((_a = error === null || error === void 0 ? void 0 : error.status) === null || _a === void 0 ? void 0 : _a.statusCode) === 403) { - return 'forbidden operation.'; - } - return 'unknown error'; - }, - }; - }; - RetryPolicy.ExponentialRetryPolicy = function (configuration) { - return { - minimumDelay: configuration.minimumDelay, - maximumDelay: configuration.maximumDelay, - maximumRetry: configuration.maximumRetry, - shouldRetry: function (error, attempt) { - var _a; - if (((_a = error === null || error === void 0 ? void 0 : error.status) === null || _a === void 0 ? void 0 : _a.statusCode) === 403) { - return false; - } - return this.maximumRetry > attempt; - }, - getDelay: function (attempt, reason) { - var _a; - var delay = (_a = reason.retryAfter) !== null && _a !== void 0 ? _a : Math.min(Math.pow(2, attempt), this.maximumDelay); - return (delay + Math.random()) * 1000; - }, - getGiveupReason: function (error, attempt) { - var _a; - if (this.maximumRetry <= attempt) { - return 'retry attempts exhaused.'; - } - if (((_a = error === null || error === void 0 ? void 0 : error.status) === null || _a === void 0 ? void 0 : _a.statusCode) === 403) { - return 'forbidden operation.'; - } - return 'unknown error'; - }, - }; - }; - return RetryPolicy; - }()); - - var EventEmitter = /** @class */ (function () { - function EventEmitter(_a) { - var modules = _a.modules, listenerManager = _a.listenerManager, getFileUrl = _a.getFileUrl; - this.modules = modules; - this.listenerManager = listenerManager; - this.getFileUrl = getFileUrl; - this._channelListenerMap = new Map(); - this._groupListenerMap = new Map(); - if (modules.cryptoModule) - this._decoder = new TextDecoder(); - } - EventEmitter.prototype.emitEvent = function (e) { - var channel = e.channel, publishMetaData = e.publishMetaData; - var subscriptionMatch = e.subscriptionMatch; - if (channel === subscriptionMatch) { - subscriptionMatch = null; - } - if (e.channel.endsWith('-pnpres')) { - var announce = {}; - announce.channel = null; - announce.subscription = null; - if (channel) { - announce.channel = channel.substring(0, channel.lastIndexOf('-pnpres')); - } - if (subscriptionMatch) { - announce.subscription = subscriptionMatch.substring(0, subscriptionMatch.lastIndexOf('-pnpres')); - } - announce.action = e.payload.action; - announce.state = e.payload.data; - announce.timetoken = publishMetaData.timetoken; - announce.occupancy = e.payload.occupancy; - announce.uuid = e.payload.uuid; - announce.timestamp = e.payload.timestamp; - if (e.payload.join) { - announce.join = e.payload.join; - } - if (e.payload.leave) { - announce.leave = e.payload.leave; - } - if (e.payload.timeout) { - announce.timeout = e.payload.timeout; - } - // deprecated --> - announce.actualChannel = subscriptionMatch != null ? channel : null; - announce.subscribedChannel = subscriptionMatch != null ? subscriptionMatch : channel; - // <-- deprecated - this.listenerManager.announcePresence(announce); - this._announce('presence', announce, announce.channel, announce.subscription); - } - else if (e.messageType === 1) { - var announce = {}; - announce.channel = null; - announce.subscription = null; - announce.channel = channel; - announce.subscription = subscriptionMatch; - announce.timetoken = publishMetaData.timetoken; - announce.publisher = e.issuingClientId; - if (e.userMetadata) { - announce.userMetadata = e.userMetadata; - } - announce.message = e.payload; - this.listenerManager.announceSignal(announce); - this._announce('signal', announce, announce.channel, announce.subscription); - } - else if (e.messageType === 2) { - var announce = {}; - announce.channel = null; - announce.subscription = null; - announce.channel = channel; - announce.subscription = subscriptionMatch; - announce.timetoken = publishMetaData.timetoken; - announce.publisher = e.issuingClientId; - if (e.userMetadata) { - announce.userMetadata = e.userMetadata; - } - announce.message = { - event: e.payload.event, - type: e.payload.type, - data: e.payload.data, - }; - this.listenerManager.announceObjects(announce); - this._announce('objects', announce, announce.channel, announce.subscription); - if (e.payload.type === 'uuid') { - var eventData = this._renameChannelField(announce); - var userEvent = __assign(__assign({}, eventData), { message: __assign(__assign({}, eventData.message), { event: this._renameEvent(eventData.message.event), type: 'user' }) }); - this.listenerManager.announceUser(userEvent); - this._announce('user', userEvent, announce.channel, announce.subscription); - } - else if (e.payload.type === 'channel') { - var eventData = this._renameChannelField(announce); - var spaceEvent = __assign(__assign({}, eventData), { message: __assign(__assign({}, eventData.message), { event: this._renameEvent(eventData.message.event), type: 'space' }) }); - this.listenerManager.announceSpace(spaceEvent); - this._announce('space', spaceEvent, announce.channel, announce.subscription); - } - else if (e.payload.type === 'membership') { - var eventData = this._renameChannelField(announce); - var _a = eventData.message.data, user = _a.uuid, space = _a.channel, membershipData = __rest(_a, ["uuid", "channel"]); - membershipData.user = user; - membershipData.space = space; - var membershipEvent = __assign(__assign({}, eventData), { message: __assign(__assign({}, eventData.message), { event: this._renameEvent(eventData.message.event), data: membershipData }) }); - this.listenerManager.announceMembership(membershipEvent); - this._announce('membership', membershipEvent, announce.channel, announce.subscription); - } - } - else if (e.messageType === 3) { - var announce = {}; - announce.channel = channel; - announce.subscription = subscriptionMatch; - announce.timetoken = publishMetaData.timetoken; - announce.publisher = e.issuingClientId; - announce.data = { - messageTimetoken: e.payload.data.messageTimetoken, - actionTimetoken: e.payload.data.actionTimetoken, - type: e.payload.data.type, - uuid: e.issuingClientId, - value: e.payload.data.value, - }; - announce.event = e.payload.event; - this.listenerManager.announceMessageAction(announce); - this._announce('messageAction', announce, announce.channel, announce.subscription); - } - else if (e.messageType === 4) { - var announce = {}; - announce.channel = channel; - announce.subscription = subscriptionMatch; - announce.timetoken = publishMetaData.timetoken; - announce.publisher = e.issuingClientId; - var msgPayload = e.payload; - if (this.modules.cryptoModule) { - var decryptedPayload = void 0; - try { - var decryptedData = this.modules.cryptoModule.decrypt(e.payload); - decryptedPayload = - decryptedData instanceof ArrayBuffer ? JSON.parse(this._decoder.decode(decryptedData)) : decryptedData; - } - catch (e) { - decryptedPayload = null; - announce.error = "Error while decrypting message content: ".concat(e.message); - } - if (decryptedPayload !== null) { - msgPayload = decryptedPayload; - } - } - if (e.userMetadata) { - announce.userMetadata = e.userMetadata; - } - announce.message = msgPayload.message; - announce.file = { - id: msgPayload.file.id, - name: msgPayload.file.name, - url: this.getFileUrl({ - id: msgPayload.file.id, - name: msgPayload.file.name, - channel: channel, - }), - }; - this.listenerManager.announceFile(announce); - this._announce('file', announce, announce.channel, announce.subscription); - } - else { - var announce = {}; - announce.channel = null; - announce.subscription = null; - announce.channel = channel; - announce.subscription = subscriptionMatch; - announce.timetoken = publishMetaData.timetoken; - announce.publisher = e.issuingClientId; - if (e.userMetadata) { - announce.userMetadata = e.userMetadata; - } - if (this.modules.cryptoModule) { - var decryptedPayload = void 0; - try { - var decryptedData = this.modules.cryptoModule.decrypt(e.payload); - decryptedPayload = - decryptedData instanceof ArrayBuffer ? JSON.parse(this._decoder.decode(decryptedData)) : decryptedData; - } - catch (e) { - decryptedPayload = null; - announce.error = "Error while decrypting message content: ".concat(e.message); - } - if (decryptedPayload != null) { - announce.message = decryptedPayload; - } - else { - announce.message = e.payload; - } - } - else { - announce.message = e.payload; - } - // deprecated --> - announce.actualChannel = subscriptionMatch != null ? channel : null; - announce.subscribedChannel = subscriptionMatch != null ? subscriptionMatch : channel; - // <-- deprecated - this.listenerManager.announceMessage(announce); - this._announce('message', announce, announce.channel, announce.subscription); - } - }; - EventEmitter.prototype.addListener = function (l, channels, groups) { - var _this = this; - if (!(channels && groups)) { - this.listenerManager.addListener(l); - } - else { - channels === null || channels === void 0 ? void 0 : channels.forEach(function (c) { - if (_this._channelListenerMap[c]) { - if (!_this._channelListenerMap[c].includes(l)) - _this._channelListenerMap[c].push(l); - } - else { - _this._channelListenerMap[c] = [l]; - } - }); - groups === null || groups === void 0 ? void 0 : groups.forEach(function (g) { - if (_this._groupListenerMap[g]) { - if (!_this._groupListenerMap[g].includes(l)) - _this._groupListenerMap[g].push(l); - } - else { - _this._groupListenerMap[g] = [l]; - } - }); - } - }; - EventEmitter.prototype.removeListener = function (listener, channels, groups) { - var _this = this; - if (!(channels && groups)) { - this.listenerManager.removeListener(listener); - } - else { - channels === null || channels === void 0 ? void 0 : channels.forEach(function (c) { - var _a; - _this._channelListenerMap[c] = (_a = _this._channelListenerMap[c]) === null || _a === void 0 ? void 0 : _a.filter(function (l) { return l !== listener; }); - }); - groups === null || groups === void 0 ? void 0 : groups.forEach(function (g) { - var _a; - _this._groupListenerMap[g] = (_a = _this._groupListenerMap[g]) === null || _a === void 0 ? void 0 : _a.filter(function (l) { return l !== listener; }); - }); - } - }; - EventEmitter.prototype.removeAllListeners = function () { - this.listenerManager.removeAllListeners(); - }; - EventEmitter.prototype._renameEvent = function (e) { - return e === 'set' ? 'updated' : 'removed'; - }; - EventEmitter.prototype._renameChannelField = function (announce) { - var channel = announce.channel, eventData = __rest(announce, ["channel"]); - eventData.spaceId = channel; - return eventData; - }; - EventEmitter.prototype._announce = function (type, event, channel, group) { - var _a, _b; - (_a = this._channelListenerMap[channel]) === null || _a === void 0 ? void 0 : _a.forEach(function (l) { return l[type] && l[type](event); }); - (_b = this._groupListenerMap[group]) === null || _b === void 0 ? void 0 : _b.forEach(function (l) { return l[type] && l[type](event); }); - }; - return EventEmitter; - }()); - - var SubscribeCapable = /** @class */ (function () { - function SubscribeCapable() { - } - SubscribeCapable.prototype.subscribe = function () { - var _a, _b; - this.pubnub.subscribe(__assign({ channels: this.channelNames, channelGroups: this.groupNames }, (((_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.cursor) === null || _b === void 0 ? void 0 : _b.timetoken) && { timetoken: this.options.cursor.timetoken }))); - }; - SubscribeCapable.prototype.unsubscribe = function () { - this.pubnub.unsubscribe({ - channels: this.channelNames.filter(function (c) { return !c.endsWith('-pnpres'); }), - channelGroups: this.groupNames.filter(function (cg) { return !cg.endsWith('-pnpres'); }), - }); - }; - Object.defineProperty(SubscribeCapable.prototype, "onMessage", { - set: function (onMessagelistener) { - this.listener.message = onMessagelistener; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(SubscribeCapable.prototype, "onPresence", { - set: function (onPresencelistener) { - this.listener.presence = onPresencelistener; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(SubscribeCapable.prototype, "onSignal", { - set: function (onSignalListener) { - this.listener.signal = onSignalListener; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(SubscribeCapable.prototype, "onObjects", { - set: function (onObjectsListener) { - this.listener.objects = onObjectsListener; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(SubscribeCapable.prototype, "onMessageAction", { - set: function (messageActionEventListener) { - this.listener.messageAction = messageActionEventListener; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(SubscribeCapable.prototype, "onFile", { - set: function (fileEventListener) { - this.listener.file = fileEventListener; - }, - enumerable: false, - configurable: true - }); - SubscribeCapable.prototype.addListener = function (listener) { - this.eventEmitter.addListener(listener, this.channelNames.filter(function (c) { return !c.endsWith('-pnpres'); }), this.groupNames.filter(function (cg) { return !cg.endsWith('-pnpres'); })); - }; - SubscribeCapable.prototype.removeListener = function (listener) { - this.eventEmitter.removeListener(listener, this.channelNames, this.groupNames); - }; - Object.defineProperty(SubscribeCapable.prototype, "channels", { - get: function () { - return this.channelNames.slice(0); - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(SubscribeCapable.prototype, "channelGroups", { - get: function () { - return this.groupNames.slice(0); - }, - enumerable: false, - configurable: true - }); - return SubscribeCapable; - }()); - - var SubscriptionSet = /** @class */ (function (_super) { - __extends(SubscriptionSet, _super); - function SubscriptionSet(_a) { - var _b = _a.channels, channels = _b === void 0 ? [] : _b, _c = _a.channelGroups, channelGroups = _c === void 0 ? [] : _c, subscriptionOptions = _a.subscriptionOptions, eventEmitter = _a.eventEmitter, pubnub = _a.pubnub; - var _this = _super.call(this) || this; - _this.channelNames = []; - _this.groupNames = []; - _this.subscriptionList = []; - _this.options = subscriptionOptions; - _this.eventEmitter = eventEmitter; - _this.pubnub = pubnub; - channels - .filter(function (c) { return !c.endsWith('-pnpres'); }) - .forEach(function (c) { - var subscription = _this.pubnub.channel(c).subscription(_this.options); - _this.channelNames = __spreadArray$1(__spreadArray$1([], __read$1(_this.channelNames), false), __read$1(subscription.channels), false); - _this.subscriptionList.push(subscription); - }); - channelGroups - .filter(function (cg) { return !cg.endsWith('-pnpres'); }) - .forEach(function (cg) { - var subscription = _this.pubnub.channelGroup(cg).subscription(_this.options); - _this.groupNames = __spreadArray$1(__spreadArray$1([], __read$1(_this.groupNames), false), __read$1(subscription.channelGroups), false); - _this.subscriptionList.push(subscription); - }); - _this.listener = {}; - eventEmitter.addListener(_this.listener, _this.channelNames.filter(function (c) { return !c.endsWith('-pnpres'); }), _this.groupNames.filter(function (cg) { return !cg.endsWith('-pnpres'); })); - return _this; - } - SubscriptionSet.prototype.addSubscription = function (subscription) { - this.subscriptionList.push(subscription); - this.channelNames = __spreadArray$1(__spreadArray$1([], __read$1(this.channelNames), false), __read$1(subscription.channels), false); - this.groupNames = __spreadArray$1(__spreadArray$1([], __read$1(this.groupNames), false), __read$1(subscription.channelGroups), false); - this.eventEmitter.addListener(this.listener, subscription.channels, subscription.channelGroups); - }; - SubscriptionSet.prototype.removeSubscription = function (subscription) { - var channelsToRemove = subscription.channels; - var groupsToRemove = subscription.channelGroups; - this.channelNames = this.channelNames.filter(function (c) { return !channelsToRemove.includes(c); }); - this.groupNames = this.groupNames.filter(function (cg) { return !groupsToRemove.includes(cg); }); - this.subscriptionList = this.subscriptionList.filter(function (s) { return s !== subscription; }); - this.eventEmitter.removeListener(this.listener, channelsToRemove, groupsToRemove); - }; - SubscriptionSet.prototype.addSubscriptionSet = function (subscriptionSet) { - this.subscriptionList = __spreadArray$1(__spreadArray$1([], __read$1(this.subscriptionList), false), __read$1(subscriptionSet.subscriptions), false); - this.channelNames = __spreadArray$1(__spreadArray$1([], __read$1(this.channelNames), false), __read$1(subscriptionSet.channels), false); - this.groupNames = __spreadArray$1(__spreadArray$1([], __read$1(this.groupNames), false), __read$1(subscriptionSet.channelGroups), false); - this.eventEmitter.addListener(this.listener, subscriptionSet.channels, subscriptionSet.channelGroups); - }; - SubscriptionSet.prototype.removeSubscriptionSet = function (subscriptionSet) { - var channelsToRemove = subscriptionSet.channels; - var groupsToRemove = subscriptionSet.channelGroups; - this.channelNames = this.channelNames.filter(function (c) { return !channelsToRemove.includes(c); }); - this.groupNames = this.groupNames.filter(function (cg) { return !groupsToRemove.includes(cg); }); - this.subscriptionList = this.subscriptionList.filter(function (s) { return !subscriptionSet.subscriptions.includes(s); }); - this.eventEmitter.removeListener(this.listener, channelsToRemove, groupsToRemove); - }; - Object.defineProperty(SubscriptionSet.prototype, "subscriptions", { - get: function () { - return this.subscriptionList.slice(0); - }, - enumerable: false, - configurable: true - }); - return SubscriptionSet; - }(SubscribeCapable)); - - var Subscription = /** @class */ (function (_super) { - __extends(Subscription, _super); - function Subscription(_a) { - var channels = _a.channels, channelGroups = _a.channelGroups, subscriptionOptions = _a.subscriptionOptions, eventEmitter = _a.eventEmitter, pubnub = _a.pubnub; - var _this = _super.call(this) || this; - _this.channelNames = []; - _this.groupNames = []; - _this.channelNames = channels; - _this.groupNames = channelGroups; - _this.options = subscriptionOptions; - _this.pubnub = pubnub; - _this.eventEmitter = eventEmitter; - _this.listener = {}; - eventEmitter.addListener(_this.listener, _this.channelNames.filter(function (c) { return !c.endsWith('-pnpres'); }), _this.groupNames.filter(function (cg) { return !cg.endsWith('-pnpres'); })); - return _this; - } - Subscription.prototype.addSubscription = function (subscription) { - return new SubscriptionSet({ - channels: __spreadArray$1(__spreadArray$1([], __read$1(this.channelNames), false), __read$1(subscription.channels), false), - channelGroups: __spreadArray$1(__spreadArray$1([], __read$1(this.groupNames), false), __read$1(subscription.channelGroups), false), - subscriptionOptions: __assign(__assign({}, this.options), subscription === null || subscription === void 0 ? void 0 : subscription.options), - eventEmitter: this.eventEmitter, - pubnub: this.pubnub, - }); - }; - return Subscription; - }(SubscribeCapable)); - - var Channel = /** @class */ (function () { - function Channel(channelName, eventEmitter, pubnub) { - this.name = channelName; - this.eventEmitter = eventEmitter; - this.pubnub = pubnub; - } - Channel.prototype.subscription = function (subscriptionOptions) { - return new Subscription({ - channels: (subscriptionOptions === null || subscriptionOptions === void 0 ? void 0 : subscriptionOptions.receivePresenceEvents) ? [this.name, "".concat(this.name, "-pnpres")] : [this.name], - channelGroups: [], - subscriptionOptions: subscriptionOptions, - eventEmitter: this.eventEmitter, - pubnub: this.pubnub, - }); - }; - return Channel; - }()); - - var ChannelGroup = /** @class */ (function () { - function ChannelGroup(channelGroup, eventEmitter, pubnub) { - this.name = channelGroup; - this.eventEmitter = eventEmitter; - this.pubnub = pubnub; - } - ChannelGroup.prototype.subscription = function (subscriptionOptions) { - return new Subscription({ - channels: [], - channelGroups: (subscriptionOptions === null || subscriptionOptions === void 0 ? void 0 : subscriptionOptions.receivePresenceEvents) ? [this.name, "".concat(this.name, "-pnpres")] : [this.name], - subscriptionOptions: subscriptionOptions, - eventEmitter: this.eventEmitter, - pubnub: this.pubnub, - }); - }; - return ChannelGroup; - }()); - - var ChannelMetadata = /** @class */ (function () { - function ChannelMetadata(id, eventEmitter, pubnub) { - this.id = id; - this.eventEmitter = eventEmitter; - this.pubnub = pubnub; - } - ChannelMetadata.prototype.subscription = function (subscriptionOptions) { - return new Subscription({ - channels: [this.id], - channelGroups: [], - subscriptionOptions: subscriptionOptions, - eventEmitter: this.eventEmitter, - pubnub: this.pubnub, - }); - }; - return ChannelMetadata; - }()); - - var UserMetadata = /** @class */ (function () { - function UserMetadata(id, eventEmitter, pubnub) { - this.id = id; - this.eventEmitter = eventEmitter; - this.pubnub = pubnub; - } - UserMetadata.prototype.subscription = function (subscriptionOptions) { - return new Subscription({ - channels: [this.id], - channelGroups: [], - subscriptionOptions: subscriptionOptions, - eventEmitter: this.eventEmitter, - pubnub: this.pubnub, - }); - }; - return UserMetadata; - }()); - - var default_1$3 = /** @class */ (function () { - function default_1(setup) { - var _this = this; - var networking = setup.networking, cbor = setup.cbor; - var config = new default_1$b({ setup: setup }); - this._config = config; - var crypto = new default_1$a({ config: config }); // LEGACY - var cryptography = setup.cryptography; - networking.init(config); - var tokenManager = new default_1$4(config, cbor); - this._tokenManager = tokenManager; - var telemetryManager = new default_1$6({ - maximumSamplesCount: 60000, - }); - this._telemetryManager = telemetryManager; - var cryptoModule = this._config.cryptoModule; - var modules = { - config: config, - networking: networking, - crypto: crypto, - cryptography: cryptography, - tokenManager: tokenManager, - telemetryManager: telemetryManager, - PubNubFile: setup.PubNubFile, - cryptoModule: cryptoModule, - }; - this.File = setup.PubNubFile; - this.encryptFile = function (key, file) { - if (arguments.length == 1 && typeof key != 'string' && modules.cryptoModule) { - file = key; - return modules.cryptoModule.encryptFile(file, this.File); - } - return cryptography.encryptFile(key, file, this.File); - }; - this.decryptFile = function (key, file) { - if (arguments.length == 1 && typeof key != 'string' && modules.cryptoModule) { - file = key; - return modules.cryptoModule.decryptFile(file, this.File); - } - return cryptography.decryptFile(key, file, this.File); - }; - var timeEndpoint = endpointCreator.bind(this, modules, timeEndpointConfig); - var leaveEndpoint = endpointCreator.bind(this, modules, presenceLeaveEndpointConfig); - var heartbeatEndpoint = endpointCreator.bind(this, modules, presenceHeartbeatEndpointConfig); - var setStateEndpoint = endpointCreator.bind(this, modules, presenceSetStateConfig); - var subscribeEndpoint = endpointCreator.bind(this, modules, subscribeEndpointConfig); - // managers - var listenerManager = new default_1$5(); - this._listenerManager = listenerManager; - this.iAmHere = endpointCreator.bind(this, modules, presenceHeartbeatEndpointConfig); - this.iAmAway = endpointCreator.bind(this, modules, presenceLeaveEndpointConfig); - this.setPresenceState = endpointCreator.bind(this, modules, presenceSetStateConfig); - this.handshake = endpointCreator.bind(this, modules, endpoint$1); - this.receiveMessages = endpointCreator.bind(this, modules, endpoint); - this._eventEmitter = new EventEmitter({ - modules: modules, - listenerManager: this._listenerManager, - getFileUrl: function (params) { return getFileUrlFunction(modules, params); }, - }); - if (config.enableEventEngine === true) { - if (config.maintainPresenceState) { - this.presenceState = {}; - this.setState = function (args) { - var _a, _b; - (_a = args.channels) === null || _a === void 0 ? void 0 : _a.forEach(function (channel) { return (_this.presenceState[channel] = args.state); }); - (_b = args.channelGroups) === null || _b === void 0 ? void 0 : _b.forEach(function (group) { return (_this.presenceState[group] = args.state); }); - return _this.setPresenceState({ - channels: args.channels, - channelGroups: args.channelGroups, - state: _this.presenceState, - }); - }; - } - if (config.getHeartbeatInterval()) { - var presenceEventEngine = new PresenceEventEngine({ - heartbeat: this.iAmHere, - leave: this.iAmAway, - heartbeatDelay: function () { - return new Promise(function (resolve) { return setTimeout(resolve, modules.config.getHeartbeatInterval() * 1000); }); - }, - retryDelay: function (amount) { return new Promise(function (resolve) { return setTimeout(resolve, amount); }); }, - config: modules.config, - presenceState: this.presenceState, - emitStatus: function (status) { - listenerManager.announceStatus(status); - }, - }); - this.presenceEventEngine = presenceEventEngine; - this.join = this.presenceEventEngine.join.bind(presenceEventEngine); - this.leave = this.presenceEventEngine.leave.bind(presenceEventEngine); - this.leaveAll = this.presenceEventEngine.leaveAll.bind(presenceEventEngine); - } - var eventEngine = new EventEngine({ - handshake: this.handshake, - receiveMessages: this.receiveMessages, - delay: function (amount) { return new Promise(function (resolve) { return setTimeout(resolve, amount); }); }, - join: this.join, - leave: this.leave, - leaveAll: this.leaveAll, - presenceState: this.presenceState, - config: modules.config, - emitMessages: function (events) { - var e_1, _a; - try { - for (var events_1 = __values(events), events_1_1 = events_1.next(); !events_1_1.done; events_1_1 = events_1.next()) { - var event_1 = events_1_1.value; - _this._eventEmitter.emitEvent(event_1); - } - } - catch (e_1_1) { e_1 = { error: e_1_1 }; } - finally { - try { - if (events_1_1 && !events_1_1.done && (_a = events_1.return)) _a.call(events_1); - } - finally { if (e_1) throw e_1.error; } - } - }, - emitStatus: function (status) { - listenerManager.announceStatus(status); - }, - }); - this.subscribe = eventEngine.subscribe.bind(eventEngine); - this.unsubscribe = eventEngine.unsubscribe.bind(eventEngine); - this.unsubscribeAll = eventEngine.unsubscribeAll.bind(eventEngine); - this.reconnect = eventEngine.reconnect.bind(eventEngine); - this.disconnect = eventEngine.disconnect.bind(eventEngine); - this.destroy = eventEngine.dispose.bind(eventEngine); - this.getSubscribedChannels = eventEngine.getSubscribedChannels.bind(eventEngine); - this.getSubscribedChannelGroups = eventEngine.getSubscribedChannelGroups.bind(eventEngine); - this.eventEngine = eventEngine; - } - else { - var subscriptionManager_1 = new default_1$7({ - timeEndpoint: timeEndpoint, - leaveEndpoint: leaveEndpoint, - heartbeatEndpoint: heartbeatEndpoint, - setStateEndpoint: setStateEndpoint, - subscribeEndpoint: subscribeEndpoint, - crypto: modules.crypto, - config: modules.config, - listenerManager: listenerManager, - getFileUrl: function (params) { return getFileUrlFunction(modules, params); }, - cryptoModule: modules.cryptoModule, - eventEmitter: this._eventEmitter, - }); - this.subscribe = subscriptionManager_1.adaptSubscribeChange.bind(subscriptionManager_1); - this.unsubscribe = subscriptionManager_1.adaptUnsubscribeChange.bind(subscriptionManager_1); - this.disconnect = subscriptionManager_1.disconnect.bind(subscriptionManager_1); - this.reconnect = subscriptionManager_1.reconnect.bind(subscriptionManager_1); - this.unsubscribeAll = subscriptionManager_1.unsubscribeAll.bind(subscriptionManager_1); - this.getSubscribedChannels = subscriptionManager_1.getSubscribedChannels.bind(subscriptionManager_1); - this.getSubscribedChannelGroups = subscriptionManager_1.getSubscribedChannelGroups.bind(subscriptionManager_1); - this.setState = subscriptionManager_1.adaptStateChange.bind(subscriptionManager_1); - this.presence = subscriptionManager_1.adaptPresenceChange.bind(subscriptionManager_1); - this.destroy = function (isOffline) { - subscriptionManager_1.unsubscribeAll(isOffline); - subscriptionManager_1.disconnect(); - }; - } - this.addListener = this._eventEmitter.addListener.bind(this._eventEmitter); - this.removeListener = this._eventEmitter.removeListener.bind(this._eventEmitter); - this.removeAllListeners = this._eventEmitter.removeAllListeners.bind(this._eventEmitter); - this.parseToken = tokenManager.parseToken.bind(tokenManager); - this.setToken = tokenManager.setToken.bind(tokenManager); - this.getToken = tokenManager.getToken.bind(tokenManager); - /* channel groups */ - this.channelGroups = { - listGroups: endpointCreator.bind(this, modules, listChannelGroupsConfig), - listChannels: endpointCreator.bind(this, modules, listChannelsInChannelGroupConfig), - addChannels: endpointCreator.bind(this, modules, addChannelsChannelGroupConfig), - removeChannels: endpointCreator.bind(this, modules, removeChannelsChannelGroupConfig), - deleteGroup: endpointCreator.bind(this, modules, deleteChannelGroupConfig), - }; - /* push */ - this.push = { - addChannels: endpointCreator.bind(this, modules, addPushChannelsConfig), - removeChannels: endpointCreator.bind(this, modules, removePushChannelsConfig), - deleteDevice: endpointCreator.bind(this, modules, removeDevicePushConfig), - listChannels: endpointCreator.bind(this, modules, listPushChannelsConfig), - }; - /* presence */ - this.hereNow = endpointCreator.bind(this, modules, presenceHereNowConfig); - this.whereNow = endpointCreator.bind(this, modules, presenceWhereNowEndpointConfig); - this.getState = endpointCreator.bind(this, modules, presenceGetStateConfig); - /* PAM */ - this.grant = endpointCreator.bind(this, modules, grantEndpointConfig); - this.grantToken = endpointCreator.bind(this, modules, grantTokenEndpointConfig); - this.audit = endpointCreator.bind(this, modules, auditEndpointConfig); - this.revokeToken = endpointCreator.bind(this, modules, endpoint$2); - this.publish = endpointCreator.bind(this, modules, publishEndpointConfig); - this.fire = function (args, callback) { - args.replicate = false; - args.storeInHistory = false; - return _this.publish(args, callback); - }; - this.signal = endpointCreator.bind(this, modules, signalEndpointConfig); - this.history = endpointCreator.bind(this, modules, historyEndpointConfig); - this.deleteMessages = endpointCreator.bind(this, modules, deleteMessagesEndpointConfig); - this.messageCounts = endpointCreator.bind(this, modules, messageCountsEndpointConfig); - this.fetchMessages = endpointCreator.bind(this, modules, fetchMessagesEndpointConfig); - // Actions API - this.addMessageAction = endpointCreator.bind(this, modules, addMessageActionEndpointConfig); - this.removeMessageAction = endpointCreator.bind(this, modules, removeMessageActionEndpointConfig); - this.getMessageActions = endpointCreator.bind(this, modules, getMessageActionEndpointConfig); - // File Upload API v1 - this.listFiles = endpointCreator.bind(this, modules, endpoint$j); - var generateUploadUrl = endpointCreator.bind(this, modules, endpoint$i); - this.publishFile = endpointCreator.bind(this, modules, endpoint$h); - this.sendFile = sendFileFunction({ - generateUploadUrl: generateUploadUrl, - publishFile: this.publishFile, - modules: modules, - }); - this.getFileUrl = function (params) { return getFileUrlFunction(modules, params); }; - this.downloadFile = endpointCreator.bind(this, modules, endpoint$g); - this.deleteFile = endpointCreator.bind(this, modules, endpoint$f); - // entities - this.channel = function (name) { return new Channel(name, _this._eventEmitter, _this); }; - this.channelGroup = function (name) { return new ChannelGroup(name, _this._eventEmitter, _this); }; - this.channelMetadata = function (id) { return new ChannelMetadata(id, _this._eventEmitter, _this); }; - this.userMetadata = function (id) { return new UserMetadata(id, _this._eventEmitter, _this); }; - this.subscriptionSet = function (args) { - return new SubscriptionSet({ - channels: args.channels, - channelGroups: args.channelGroups, - subscriptionOptions: args.subscriptionOptions, - eventEmitter: _this._eventEmitter, - pubnub: _this, - }); - }; - // Objects API v2 - this.objects = { - getAllUUIDMetadata: endpointCreator.bind(this, modules, endpoint$e), - getUUIDMetadata: endpointCreator.bind(this, modules, endpoint$d), - setUUIDMetadata: endpointCreator.bind(this, modules, endpoint$c), - removeUUIDMetadata: endpointCreator.bind(this, modules, endpoint$b), - getAllChannelMetadata: endpointCreator.bind(this, modules, endpoint$a), - getChannelMetadata: endpointCreator.bind(this, modules, endpoint$9), - setChannelMetadata: endpointCreator.bind(this, modules, endpoint$8), - removeChannelMetadata: endpointCreator.bind(this, modules, endpoint$7), - getChannelMembers: endpointCreator.bind(this, modules, endpoint$6), - setChannelMembers: function (parameters) { - var rest = []; - for (var _i = 1; _i < arguments.length; _i++) { - rest[_i - 1] = arguments[_i]; - } - return endpointCreator.call.apply(endpointCreator, __spreadArray$1([_this, - modules, - endpoint$5, __assign({ type: 'set' }, parameters)], __read$1(rest), false)); - }, - removeChannelMembers: function (parameters) { - var rest = []; - for (var _i = 1; _i < arguments.length; _i++) { - rest[_i - 1] = arguments[_i]; - } - return endpointCreator.call.apply(endpointCreator, __spreadArray$1([_this, - modules, - endpoint$5, __assign({ type: 'delete' }, parameters)], __read$1(rest), false)); - }, - getMemberships: endpointCreator.bind(this, modules, endpoint$4), - setMemberships: function (parameters) { - var rest = []; - for (var _i = 1; _i < arguments.length; _i++) { - rest[_i - 1] = arguments[_i]; - } - return endpointCreator.call.apply(endpointCreator, __spreadArray$1([_this, - modules, - endpoint$3, __assign({ type: 'set' }, parameters)], __read$1(rest), false)); - }, - removeMemberships: function (parameters) { - var rest = []; - for (var _i = 1; _i < arguments.length; _i++) { - rest[_i - 1] = arguments[_i]; - } - return endpointCreator.call.apply(endpointCreator, __spreadArray$1([_this, - modules, - endpoint$3, __assign({ type: 'delete' }, parameters)], __read$1(rest), false)); - }, - }; - // User Apis - this.createUser = function (args) { - return _this.objects.setUUIDMetadata({ - uuid: args.userId, - data: args.data, - include: args.include, - }); - }; - this.updateUser = this.createUser; - this.removeUser = function (args) { - return _this.objects.removeUUIDMetadata({ - uuid: args === null || args === void 0 ? void 0 : args.userId, - }); - }; - this.fetchUser = function (args) { - return _this.objects.getUUIDMetadata({ - uuid: args === null || args === void 0 ? void 0 : args.userId, - include: args === null || args === void 0 ? void 0 : args.include, - }); - }; - this.fetchUsers = this.objects.getAllUUIDMetadata; - // Space apis - this.createSpace = function (args) { - return _this.objects.setChannelMetadata({ - channel: args.spaceId, - data: args.data, - include: args.include, - }); - }; - this.updateSpace = this.createSpace; - this.removeSpace = function (args) { - return _this.objects.removeChannelMetadata({ - channel: args.spaceId, - }); - }; - this.fetchSpace = function (args) { - return _this.objects.getChannelMetadata({ - channel: args.spaceId, - include: args.include, - }); - }; - this.fetchSpaces = this.objects.getAllChannelMetadata; - // Membership apis - this.addMemberships = function (parameters) { - var _a, _b; - if (typeof parameters.spaceId === 'string') { - return _this.objects.setChannelMembers({ - channel: parameters.spaceId, - uuids: (_a = parameters.users) === null || _a === void 0 ? void 0 : _a.map(function (user) { - if (typeof user === 'string') { - return user; - } - return { - id: user.userId, - custom: user.custom, - status: user.status, - }; - }), - limit: 0, - }); - } - else { - return _this.objects.setMemberships({ - uuid: parameters.userId, - channels: (_b = parameters.spaces) === null || _b === void 0 ? void 0 : _b.map(function (space) { - if (typeof space === 'string') { - return space; - } - return { - id: space.spaceId, - custom: space.custom, - status: space.status, - }; - }), - limit: 0, - }); - } - }; - this.updateMemberships = this.addMemberships; - this.removeMemberships = function (parameters) { - if (typeof parameters.spaceId === 'string') { - return _this.objects.removeChannelMembers({ - channel: parameters.spaceId, - uuids: parameters.userIds, - limit: 0, - }); - } - else { - return _this.objects.removeMemberships({ - uuid: parameters.userId, - channels: parameters.spaceIds, - limit: 0, - }); - } - }; - this.fetchMemberships = function (params) { - if (typeof params.spaceId === 'string') { - return _this.objects - .getChannelMembers({ - channel: params.spaceId, - filter: params.filter, - limit: params.limit, - page: params.page, - include: { - customFields: params.include.customFields, - UUIDFields: params.include.userFields, - customUUIDFields: params.include.customUserFields, - statusField: params.include.statusField, - UUIDStatusField: params.include.userStatusField, - UUIDTypeField: params.include.userTypeField, - totalCount: params.include.totalCount, - }, - sort: params.sort != null - ? Object.fromEntries(Object.entries(params.sort).map(function (_a) { - var _b = __read$1(_a, 2), k = _b[0], v = _b[1]; - return [k.replace('user', 'uuid'), v]; - })) - : null, - }) - .then(function (res) { - var _a; - res.data = (_a = res.data) === null || _a === void 0 ? void 0 : _a.map(function (m) { - return { - user: m.uuid, - custom: m.custom, - updated: m.updated, - eTag: m.eTag, - }; - }); - return res; - }); - } - else { - return _this.objects - .getMemberships({ - uuid: params.userId, - filter: params.filter, - limit: params.limit, - page: params.page, - include: { - customFields: params.include.customFields, - channelFields: params.include.spaceFields, - customChannelFields: params.include.customSpaceFields, - statusField: params.include.statusField, - channelStatusField: params.include.spaceStatusField, - channelTypeField: params.include.spaceTypeField, - totalCount: params.include.totalCount, - }, - sort: params.sort != null - ? Object.fromEntries(Object.entries(params.sort).map(function (_a) { - var _b = __read$1(_a, 2), k = _b[0], v = _b[1]; - return [k.replace('space', 'channel'), v]; - })) - : null, - }) - .then(function (res) { - var _a; - res.data = (_a = res.data) === null || _a === void 0 ? void 0 : _a.map(function (m) { - return { - space: m.channel, - custom: m.custom, - updated: m.updated, - eTag: m.eTag, - }; - }); - return res; - }); - } - }; - this.time = timeEndpoint; - // --- deprecated ------------------ - this.stop = this.destroy; // -------- - // --- deprecated ------------------ - // mount crypto - this.encrypt = function (data, key) { - if (typeof key === 'undefined' && modules.cryptoModule) { - var encrypted = modules.cryptoModule.encrypt(data); - return typeof encrypted === 'string' ? encrypted : encode$1(encrypted); - } - else { - return crypto.encrypt(data, key); - } - }; - this.decrypt = function (data, key) { - if (typeof key === 'undefined' && cryptoModule) { - var decrypted = modules.cryptoModule.decrypt(data); - return decrypted instanceof ArrayBuffer ? JSON.parse(new TextDecoder().decode(decrypted)) : decrypted; - } - else { - return crypto.decrypt(data, key); - } - }; - /* config */ - this.getAuthKey = modules.config.getAuthKey.bind(modules.config); - this.setAuthKey = modules.config.setAuthKey.bind(modules.config); - this.getUUID = modules.config.getUUID.bind(modules.config); - this.setUUID = modules.config.setUUID.bind(modules.config); - this.getUserId = modules.config.getUserId.bind(modules.config); - this.setUserId = modules.config.setUserId.bind(modules.config); - this.getFilterExpression = modules.config.getFilterExpression.bind(modules.config); - this.setFilterExpression = modules.config.setFilterExpression.bind(modules.config); - this.setCipherKey = function (key) { return modules.config.setCipherKey(key, setup, modules); }; - this.setHeartbeatInterval = modules.config.setHeartbeatInterval.bind(modules.config); - if (networking.hasModule('proxy')) { - this.setProxy = function (proxy) { - modules.config.setProxy(proxy); - _this.reconnect(); - }; - } - } - default_1.prototype.getVersion = function () { - return this._config.getVersion(); - }; - default_1.prototype._addPnsdkSuffix = function (name, suffix) { - this._config._addPnsdkSuffix(name, suffix); - }; - // network hooks to indicate network changes - default_1.prototype.networkDownDetected = function () { - this._listenerManager.announceNetworkDown(); - if (this._config.restore) { - this.disconnect(); - } - else { - this.destroy(true); - } - }; - default_1.prototype.networkUpDetected = function () { - this._listenerManager.announceNetworkUp(); - this.reconnect(); - }; - default_1.notificationPayload = function (title, body) { - return new NotificationsPayload(title, body); - }; - default_1.generateUUID = function () { - return uuidGenerator.createUUID(); - }; - default_1.OPERATIONS = OPERATIONS; - default_1.CATEGORIES = categories; - default_1.LinearRetryPolicy = RetryPolicy.LinearRetryPolicy; - default_1.ExponentialRetryPolicy = RetryPolicy.ExponentialRetryPolicy; - return default_1; - }()); - - /* */ - var default_1$2 = /** @class */ (function () { - function default_1(modules) { - var _this = this; - this._modules = {}; - Object.keys(modules).forEach(function (key) { - _this._modules[key] = modules[key].bind(_this); - }); - } - default_1.prototype.init = function (config) { - this._config = config; - if (Array.isArray(this._config.origin)) { - this._currentSubDomain = Math.floor(Math.random() * this._config.origin.length); - } - else { - this._currentSubDomain = 0; - } - this._coreParams = {}; - // create initial origins - this.shiftStandardOrigin(); - }; - default_1.prototype.nextOrigin = function () { - var protocol = this._config.secure ? 'https://' : 'http://'; - if (typeof this._config.origin === 'string') { - return "".concat(protocol).concat(this._config.origin); - } - this._currentSubDomain += 1; - if (this._currentSubDomain >= this._config.origin.length) { - this._currentSubDomain = 0; - } - var origin = this._config.origin[this._currentSubDomain]; - return "".concat(protocol).concat(origin); - }; - default_1.prototype.hasModule = function (name) { - return name in this._modules; - }; - // origin operations - default_1.prototype.shiftStandardOrigin = function () { - this._standardOrigin = this.nextOrigin(); - return this._standardOrigin; - }; - default_1.prototype.getStandardOrigin = function () { - return this._standardOrigin; - }; - default_1.prototype.POSTFILE = function (url, fields, file) { - return this._modules.postfile(url, fields, file); - }; - default_1.prototype.GETFILE = function (params, endpoint, callback) { - return this._modules.getfile(params, endpoint, callback); - }; - default_1.prototype.POST = function (params, body, endpoint, callback) { - return this._modules.post(params, body, endpoint, callback); - }; - default_1.prototype.PATCH = function (params, body, endpoint, callback) { - return this._modules.patch(params, body, endpoint, callback); - }; - default_1.prototype.GET = function (params, endpoint, callback) { - return this._modules.get(params, endpoint, callback); - }; - default_1.prototype.DELETE = function (params, endpoint, callback) { - return this._modules.del(params, endpoint, callback); - }; - default_1.prototype._detectErrorCategory = function (err) { - if (err.code === 'ENOTFOUND') { - return categories.PNNetworkIssuesCategory; - } - if (err.code === 'ECONNREFUSED') { - return categories.PNNetworkIssuesCategory; - } - if (err.code === 'ECONNRESET') { - return categories.PNNetworkIssuesCategory; - } - if (err.code === 'EAI_AGAIN') { - return categories.PNNetworkIssuesCategory; - } - if (err.status === 0 || (err.hasOwnProperty('status') && typeof err.status === 'undefined')) { - return categories.PNNetworkIssuesCategory; - } - if (err.timeout) - return categories.PNTimeoutCategory; - if (err.code === 'ETIMEDOUT') { - return categories.PNNetworkIssuesCategory; - } - if (err.response) { - if (err.response.badRequest) { - return categories.PNBadRequestCategory; - } - if (err.response.forbidden) { - return categories.PNAccessDeniedCategory; - } - } - return categories.PNUnknownCategory; - }; - return default_1; - }()); - - function stringifyBufferKeys(obj) { - var isObject = function (value) { return value && typeof value === 'object' && value.constructor === Object; }; - var isString = function (value) { return typeof value === 'string' || value instanceof String; }; - var isNumber = function (value) { return typeof value === 'number' && isFinite(value); }; - if (!isObject(obj)) { - return obj; - } - var normalizedObject = {}; - Object.keys(obj).forEach(function (key) { - var keyIsString = isString(key); - var stringifiedKey = key; - var value = obj[key]; - if (Array.isArray(key) || (keyIsString && key.indexOf(',') >= 0)) { - var bytes = keyIsString ? key.split(',') : key; - stringifiedKey = bytes.reduce(function (string, byte) { - string += String.fromCharCode(byte); - return string; - }, ''); - } - else if (isNumber(key) || (keyIsString && !isNaN(key))) { - stringifiedKey = String.fromCharCode(keyIsString ? parseInt(key, 10) : 10); - } - normalizedObject[stringifiedKey] = isObject(value) ? stringifyBufferKeys(value) : value; - }); - return normalizedObject; - } - - var default_1$1 = /** @class */ (function () { - function default_1(decode, base64ToBinary) { - this._base64ToBinary = base64ToBinary; - this._decode = decode; - } - default_1.prototype.decodeToken = function (tokenString) { - var padding = ''; - if (tokenString.length % 4 === 3) { - padding = '='; - } - else if (tokenString.length % 4 === 2) { - padding = '=='; - } - var cleaned = tokenString.replace(/-/gi, '+').replace(/_/gi, '/') + padding; - var result = this._decode(this._base64ToBinary(cleaned)); - if (typeof result === 'object') { - return result; - } - return undefined; - }; - return default_1; - }()); - - var client = {exports: {}}; - - var componentEmitter = {exports: {}}; - - (function (module) { - /** - * Expose `Emitter`. - */ - - { - module.exports = Emitter; - } - - /** - * Initialize a new `Emitter`. - * - * @api public - */ - - function Emitter(obj) { - if (obj) return mixin(obj); - } - /** - * Mixin the emitter properties. - * - * @param {Object} obj - * @return {Object} - * @api private - */ - - function mixin(obj) { - for (var key in Emitter.prototype) { - obj[key] = Emitter.prototype[key]; - } - return obj; - } - - /** - * Listen on the given `event` with `fn`. - * - * @param {String} event - * @param {Function} fn - * @return {Emitter} - * @api public - */ - - Emitter.prototype.on = - Emitter.prototype.addEventListener = function(event, fn){ - this._callbacks = this._callbacks || {}; - (this._callbacks['$' + event] = this._callbacks['$' + event] || []) - .push(fn); - return this; - }; - - /** - * Adds an `event` listener that will be invoked a single - * time then automatically removed. - * - * @param {String} event - * @param {Function} fn - * @return {Emitter} - * @api public - */ - - Emitter.prototype.once = function(event, fn){ - function on() { - this.off(event, on); - fn.apply(this, arguments); - } - - on.fn = fn; - this.on(event, on); - return this; - }; - - /** - * Remove the given callback for `event` or all - * registered callbacks. - * - * @param {String} event - * @param {Function} fn - * @return {Emitter} - * @api public - */ - - Emitter.prototype.off = - Emitter.prototype.removeListener = - Emitter.prototype.removeAllListeners = - Emitter.prototype.removeEventListener = function(event, fn){ - this._callbacks = this._callbacks || {}; - - // all - if (0 == arguments.length) { - this._callbacks = {}; - return this; - } - - // specific event - var callbacks = this._callbacks['$' + event]; - if (!callbacks) return this; - - // remove all handlers - if (1 == arguments.length) { - delete this._callbacks['$' + event]; - return this; - } - - // remove specific handler - var cb; - for (var i = 0; i < callbacks.length; i++) { - cb = callbacks[i]; - if (cb === fn || cb.fn === fn) { - callbacks.splice(i, 1); - break; - } - } - - // Remove event specific arrays for event types that no - // one is subscribed for to avoid memory leak. - if (callbacks.length === 0) { - delete this._callbacks['$' + event]; - } - - return this; - }; - - /** - * Emit `event` with the given args. - * - * @param {String} event - * @param {Mixed} ... - * @return {Emitter} - */ - - Emitter.prototype.emit = function(event){ - this._callbacks = this._callbacks || {}; - - var args = new Array(arguments.length - 1) - , callbacks = this._callbacks['$' + event]; - - for (var i = 1; i < arguments.length; i++) { - args[i - 1] = arguments[i]; - } - - if (callbacks) { - callbacks = callbacks.slice(0); - for (var i = 0, len = callbacks.length; i < len; ++i) { - callbacks[i].apply(this, args); - } - } - - return this; - }; - - /** - * Return array of callbacks for `event`. - * - * @param {String} event - * @return {Array} - * @api public - */ - - Emitter.prototype.listeners = function(event){ - this._callbacks = this._callbacks || {}; - return this._callbacks['$' + event] || []; - }; - - /** - * Check if this emitter has `event` handlers. - * - * @param {String} event - * @return {Boolean} - * @api public - */ - - Emitter.prototype.hasListeners = function(event){ - return !! this.listeners(event).length; - }; - }(componentEmitter)); - - var fastSafeStringify = stringify$2; - stringify$2.default = stringify$2; - stringify$2.stable = deterministicStringify; - stringify$2.stableStringify = deterministicStringify; - - var LIMIT_REPLACE_NODE = '[...]'; - var CIRCULAR_REPLACE_NODE = '[Circular]'; - - var arr = []; - var replacerStack = []; - - function defaultOptions () { - return { - depthLimit: Number.MAX_SAFE_INTEGER, - edgesLimit: Number.MAX_SAFE_INTEGER - } - } - - // Regular stringify - function stringify$2 (obj, replacer, spacer, options) { - if (typeof options === 'undefined') { - options = defaultOptions(); - } - - decirc(obj, '', 0, [], undefined, 0, options); - var res; - try { - if (replacerStack.length === 0) { - res = JSON.stringify(obj, replacer, spacer); - } else { - res = JSON.stringify(obj, replaceGetterValues(replacer), spacer); - } - } catch (_) { - return JSON.stringify('[unable to serialize, circular reference is too complex to analyze]') - } finally { - while (arr.length !== 0) { - var part = arr.pop(); - if (part.length === 4) { - Object.defineProperty(part[0], part[1], part[3]); - } else { - part[0][part[1]] = part[2]; - } - } - } - return res - } - - function setReplace (replace, val, k, parent) { - var propertyDescriptor = Object.getOwnPropertyDescriptor(parent, k); - if (propertyDescriptor.get !== undefined) { - if (propertyDescriptor.configurable) { - Object.defineProperty(parent, k, { value: replace }); - arr.push([parent, k, val, propertyDescriptor]); - } else { - replacerStack.push([val, k, replace]); - } - } else { - parent[k] = replace; - arr.push([parent, k, val]); - } - } - - function decirc (val, k, edgeIndex, stack, parent, depth, options) { - depth += 1; - var i; - if (typeof val === 'object' && val !== null) { - for (i = 0; i < stack.length; i++) { - if (stack[i] === val) { - setReplace(CIRCULAR_REPLACE_NODE, val, k, parent); - return - } - } - - if ( - typeof options.depthLimit !== 'undefined' && - depth > options.depthLimit - ) { - setReplace(LIMIT_REPLACE_NODE, val, k, parent); - return - } - - if ( - typeof options.edgesLimit !== 'undefined' && - edgeIndex + 1 > options.edgesLimit - ) { - setReplace(LIMIT_REPLACE_NODE, val, k, parent); - return - } - - stack.push(val); - // Optimize for Arrays. Big arrays could kill the performance otherwise! - if (Array.isArray(val)) { - for (i = 0; i < val.length; i++) { - decirc(val[i], i, i, stack, val, depth, options); - } - } else { - var keys = Object.keys(val); - for (i = 0; i < keys.length; i++) { - var key = keys[i]; - decirc(val[key], key, i, stack, val, depth, options); - } - } - stack.pop(); - } - } - - // Stable-stringify - function compareFunction (a, b) { - if (a < b) { - return -1 - } - if (a > b) { - return 1 - } - return 0 - } - - function deterministicStringify (obj, replacer, spacer, options) { - if (typeof options === 'undefined') { - options = defaultOptions(); - } - - var tmp = deterministicDecirc(obj, '', 0, [], undefined, 0, options) || obj; - var res; - try { - if (replacerStack.length === 0) { - res = JSON.stringify(tmp, replacer, spacer); - } else { - res = JSON.stringify(tmp, replaceGetterValues(replacer), spacer); - } - } catch (_) { - return JSON.stringify('[unable to serialize, circular reference is too complex to analyze]') - } finally { - // Ensure that we restore the object as it was. - while (arr.length !== 0) { - var part = arr.pop(); - if (part.length === 4) { - Object.defineProperty(part[0], part[1], part[3]); - } else { - part[0][part[1]] = part[2]; - } - } - } - return res - } - - function deterministicDecirc (val, k, edgeIndex, stack, parent, depth, options) { - depth += 1; - var i; - if (typeof val === 'object' && val !== null) { - for (i = 0; i < stack.length; i++) { - if (stack[i] === val) { - setReplace(CIRCULAR_REPLACE_NODE, val, k, parent); - return - } - } - try { - if (typeof val.toJSON === 'function') { - return - } - } catch (_) { - return - } - - if ( - typeof options.depthLimit !== 'undefined' && - depth > options.depthLimit - ) { - setReplace(LIMIT_REPLACE_NODE, val, k, parent); - return - } - - if ( - typeof options.edgesLimit !== 'undefined' && - edgeIndex + 1 > options.edgesLimit - ) { - setReplace(LIMIT_REPLACE_NODE, val, k, parent); - return - } - - stack.push(val); - // Optimize for Arrays. Big arrays could kill the performance otherwise! - if (Array.isArray(val)) { - for (i = 0; i < val.length; i++) { - deterministicDecirc(val[i], i, i, stack, val, depth, options); - } - } else { - // Create a temporary object in the required way - var tmp = {}; - var keys = Object.keys(val).sort(compareFunction); - for (i = 0; i < keys.length; i++) { - var key = keys[i]; - deterministicDecirc(val[key], key, i, stack, val, depth, options); - tmp[key] = val[key]; - } - if (typeof parent !== 'undefined') { - arr.push([parent, k, val]); - parent[k] = tmp; - } else { - return tmp - } - } - stack.pop(); - } - } - - // wraps replacer function to handle values we couldn't replace - // and mark them as replaced value - function replaceGetterValues (replacer) { - replacer = - typeof replacer !== 'undefined' - ? replacer - : function (k, v) { - return v - }; - return function (key, val) { - if (replacerStack.length > 0) { - for (var i = 0; i < replacerStack.length; i++) { - var part = replacerStack[i]; - if (part[1] === key && part[0] === val) { - val = part[2]; - replacerStack.splice(i, 1); - break - } - } - } - return replacer.call(this, key, val) - } - } - - /* eslint complexity: [2, 18], max-statements: [2, 33] */ - var shams = function hasSymbols() { - if (typeof Symbol !== 'function' || typeof Object.getOwnPropertySymbols !== 'function') { return false; } - if (typeof Symbol.iterator === 'symbol') { return true; } - - var obj = {}; - var sym = Symbol('test'); - var symObj = Object(sym); - if (typeof sym === 'string') { return false; } - - if (Object.prototype.toString.call(sym) !== '[object Symbol]') { return false; } - if (Object.prototype.toString.call(symObj) !== '[object Symbol]') { return false; } - - // temp disabled per https://github.com/ljharb/object.assign/issues/17 - // if (sym instanceof Symbol) { return false; } - // temp disabled per https://github.com/WebReflection/get-own-property-symbols/issues/4 - // if (!(symObj instanceof Symbol)) { return false; } - - // if (typeof Symbol.prototype.toString !== 'function') { return false; } - // if (String(sym) !== Symbol.prototype.toString.call(sym)) { return false; } - - var symVal = 42; - obj[sym] = symVal; - for (sym in obj) { return false; } // eslint-disable-line no-restricted-syntax, no-unreachable-loop - if (typeof Object.keys === 'function' && Object.keys(obj).length !== 0) { return false; } - - if (typeof Object.getOwnPropertyNames === 'function' && Object.getOwnPropertyNames(obj).length !== 0) { return false; } - - var syms = Object.getOwnPropertySymbols(obj); - if (syms.length !== 1 || syms[0] !== sym) { return false; } - - if (!Object.prototype.propertyIsEnumerable.call(obj, sym)) { return false; } - - if (typeof Object.getOwnPropertyDescriptor === 'function') { - var descriptor = Object.getOwnPropertyDescriptor(obj, sym); - if (descriptor.value !== symVal || descriptor.enumerable !== true) { return false; } - } - - return true; - }; - - var origSymbol = typeof Symbol !== 'undefined' && Symbol; - var hasSymbolSham = shams; - - var hasSymbols$1 = function hasNativeSymbols() { - if (typeof origSymbol !== 'function') { return false; } - if (typeof Symbol !== 'function') { return false; } - if (typeof origSymbol('foo') !== 'symbol') { return false; } - if (typeof Symbol('bar') !== 'symbol') { return false; } - - return hasSymbolSham(); - }; - - /* eslint no-invalid-this: 1 */ - - var ERROR_MESSAGE = 'Function.prototype.bind called on incompatible '; - var slice = Array.prototype.slice; - var toStr$1 = Object.prototype.toString; - var funcType = '[object Function]'; - - var implementation$1 = function bind(that) { - var target = this; - if (typeof target !== 'function' || toStr$1.call(target) !== funcType) { - throw new TypeError(ERROR_MESSAGE + target); - } - var args = slice.call(arguments, 1); - - var bound; - var binder = function () { - if (this instanceof bound) { - var result = target.apply( - this, - args.concat(slice.call(arguments)) - ); - if (Object(result) === result) { - return result; - } - return this; - } else { - return target.apply( - that, - args.concat(slice.call(arguments)) - ); - } - }; - - var boundLength = Math.max(0, target.length - args.length); - var boundArgs = []; - for (var i = 0; i < boundLength; i++) { - boundArgs.push('$' + i); - } - - bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this,arguments); }')(binder); - - if (target.prototype) { - var Empty = function Empty() {}; - Empty.prototype = target.prototype; - bound.prototype = new Empty(); - Empty.prototype = null; - } - - return bound; - }; - - var implementation = implementation$1; - - var functionBind = Function.prototype.bind || implementation; - - var bind$1 = functionBind; - - var src = bind$1.call(Function.call, Object.prototype.hasOwnProperty); - - var undefined$1; - - var $SyntaxError = SyntaxError; - var $Function = Function; - var $TypeError$1 = TypeError; - - // eslint-disable-next-line consistent-return - var getEvalledConstructor = function (expressionSyntax) { - try { - return $Function('"use strict"; return (' + expressionSyntax + ').constructor;')(); - } catch (e) {} - }; - - var $gOPD = Object.getOwnPropertyDescriptor; - if ($gOPD) { - try { - $gOPD({}, ''); - } catch (e) { - $gOPD = null; // this is IE 8, which has a broken gOPD - } - } - - var throwTypeError = function () { - throw new $TypeError$1(); - }; - var ThrowTypeError = $gOPD - ? (function () { - try { - // eslint-disable-next-line no-unused-expressions, no-caller, no-restricted-properties - arguments.callee; // IE 8 does not throw here - return throwTypeError; - } catch (calleeThrows) { - try { - // IE 8 throws on Object.getOwnPropertyDescriptor(arguments, '') - return $gOPD(arguments, 'callee').get; - } catch (gOPDthrows) { - return throwTypeError; - } - } - }()) - : throwTypeError; - - var hasSymbols = hasSymbols$1(); - - var getProto = Object.getPrototypeOf || function (x) { return x.__proto__; }; // eslint-disable-line no-proto - - var needsEval = {}; - - var TypedArray = typeof Uint8Array === 'undefined' ? undefined$1 : getProto(Uint8Array); - - var INTRINSICS = { - '%AggregateError%': typeof AggregateError === 'undefined' ? undefined$1 : AggregateError, - '%Array%': Array, - '%ArrayBuffer%': typeof ArrayBuffer === 'undefined' ? undefined$1 : ArrayBuffer, - '%ArrayIteratorPrototype%': hasSymbols ? getProto([][Symbol.iterator]()) : undefined$1, - '%AsyncFromSyncIteratorPrototype%': undefined$1, - '%AsyncFunction%': needsEval, - '%AsyncGenerator%': needsEval, - '%AsyncGeneratorFunction%': needsEval, - '%AsyncIteratorPrototype%': needsEval, - '%Atomics%': typeof Atomics === 'undefined' ? undefined$1 : Atomics, - '%BigInt%': typeof BigInt === 'undefined' ? undefined$1 : BigInt, - '%Boolean%': Boolean, - '%DataView%': typeof DataView === 'undefined' ? undefined$1 : DataView, - '%Date%': Date, - '%decodeURI%': decodeURI, - '%decodeURIComponent%': decodeURIComponent, - '%encodeURI%': encodeURI, - '%encodeURIComponent%': encodeURIComponent, - '%Error%': Error, - '%eval%': eval, // eslint-disable-line no-eval - '%EvalError%': EvalError, - '%Float32Array%': typeof Float32Array === 'undefined' ? undefined$1 : Float32Array, - '%Float64Array%': typeof Float64Array === 'undefined' ? undefined$1 : Float64Array, - '%FinalizationRegistry%': typeof FinalizationRegistry === 'undefined' ? undefined$1 : FinalizationRegistry, - '%Function%': $Function, - '%GeneratorFunction%': needsEval, - '%Int8Array%': typeof Int8Array === 'undefined' ? undefined$1 : Int8Array, - '%Int16Array%': typeof Int16Array === 'undefined' ? undefined$1 : Int16Array, - '%Int32Array%': typeof Int32Array === 'undefined' ? undefined$1 : Int32Array, - '%isFinite%': isFinite, - '%isNaN%': isNaN, - '%IteratorPrototype%': hasSymbols ? getProto(getProto([][Symbol.iterator]())) : undefined$1, - '%JSON%': typeof JSON === 'object' ? JSON : undefined$1, - '%Map%': typeof Map === 'undefined' ? undefined$1 : Map, - '%MapIteratorPrototype%': typeof Map === 'undefined' || !hasSymbols ? undefined$1 : getProto(new Map()[Symbol.iterator]()), - '%Math%': Math, - '%Number%': Number, - '%Object%': Object, - '%parseFloat%': parseFloat, - '%parseInt%': parseInt, - '%Promise%': typeof Promise === 'undefined' ? undefined$1 : Promise, - '%Proxy%': typeof Proxy === 'undefined' ? undefined$1 : Proxy, - '%RangeError%': RangeError, - '%ReferenceError%': ReferenceError, - '%Reflect%': typeof Reflect === 'undefined' ? undefined$1 : Reflect, - '%RegExp%': RegExp, - '%Set%': typeof Set === 'undefined' ? undefined$1 : Set, - '%SetIteratorPrototype%': typeof Set === 'undefined' || !hasSymbols ? undefined$1 : getProto(new Set()[Symbol.iterator]()), - '%SharedArrayBuffer%': typeof SharedArrayBuffer === 'undefined' ? undefined$1 : SharedArrayBuffer, - '%String%': String, - '%StringIteratorPrototype%': hasSymbols ? getProto(''[Symbol.iterator]()) : undefined$1, - '%Symbol%': hasSymbols ? Symbol : undefined$1, - '%SyntaxError%': $SyntaxError, - '%ThrowTypeError%': ThrowTypeError, - '%TypedArray%': TypedArray, - '%TypeError%': $TypeError$1, - '%Uint8Array%': typeof Uint8Array === 'undefined' ? undefined$1 : Uint8Array, - '%Uint8ClampedArray%': typeof Uint8ClampedArray === 'undefined' ? undefined$1 : Uint8ClampedArray, - '%Uint16Array%': typeof Uint16Array === 'undefined' ? undefined$1 : Uint16Array, - '%Uint32Array%': typeof Uint32Array === 'undefined' ? undefined$1 : Uint32Array, - '%URIError%': URIError, - '%WeakMap%': typeof WeakMap === 'undefined' ? undefined$1 : WeakMap, - '%WeakRef%': typeof WeakRef === 'undefined' ? undefined$1 : WeakRef, - '%WeakSet%': typeof WeakSet === 'undefined' ? undefined$1 : WeakSet - }; - - var doEval = function doEval(name) { - var value; - if (name === '%AsyncFunction%') { - value = getEvalledConstructor('async function () {}'); - } else if (name === '%GeneratorFunction%') { - value = getEvalledConstructor('function* () {}'); - } else if (name === '%AsyncGeneratorFunction%') { - value = getEvalledConstructor('async function* () {}'); - } else if (name === '%AsyncGenerator%') { - var fn = doEval('%AsyncGeneratorFunction%'); - if (fn) { - value = fn.prototype; - } - } else if (name === '%AsyncIteratorPrototype%') { - var gen = doEval('%AsyncGenerator%'); - if (gen) { - value = getProto(gen.prototype); - } - } - - INTRINSICS[name] = value; - - return value; - }; - - var LEGACY_ALIASES = { - '%ArrayBufferPrototype%': ['ArrayBuffer', 'prototype'], - '%ArrayPrototype%': ['Array', 'prototype'], - '%ArrayProto_entries%': ['Array', 'prototype', 'entries'], - '%ArrayProto_forEach%': ['Array', 'prototype', 'forEach'], - '%ArrayProto_keys%': ['Array', 'prototype', 'keys'], - '%ArrayProto_values%': ['Array', 'prototype', 'values'], - '%AsyncFunctionPrototype%': ['AsyncFunction', 'prototype'], - '%AsyncGenerator%': ['AsyncGeneratorFunction', 'prototype'], - '%AsyncGeneratorPrototype%': ['AsyncGeneratorFunction', 'prototype', 'prototype'], - '%BooleanPrototype%': ['Boolean', 'prototype'], - '%DataViewPrototype%': ['DataView', 'prototype'], - '%DatePrototype%': ['Date', 'prototype'], - '%ErrorPrototype%': ['Error', 'prototype'], - '%EvalErrorPrototype%': ['EvalError', 'prototype'], - '%Float32ArrayPrototype%': ['Float32Array', 'prototype'], - '%Float64ArrayPrototype%': ['Float64Array', 'prototype'], - '%FunctionPrototype%': ['Function', 'prototype'], - '%Generator%': ['GeneratorFunction', 'prototype'], - '%GeneratorPrototype%': ['GeneratorFunction', 'prototype', 'prototype'], - '%Int8ArrayPrototype%': ['Int8Array', 'prototype'], - '%Int16ArrayPrototype%': ['Int16Array', 'prototype'], - '%Int32ArrayPrototype%': ['Int32Array', 'prototype'], - '%JSONParse%': ['JSON', 'parse'], - '%JSONStringify%': ['JSON', 'stringify'], - '%MapPrototype%': ['Map', 'prototype'], - '%NumberPrototype%': ['Number', 'prototype'], - '%ObjectPrototype%': ['Object', 'prototype'], - '%ObjProto_toString%': ['Object', 'prototype', 'toString'], - '%ObjProto_valueOf%': ['Object', 'prototype', 'valueOf'], - '%PromisePrototype%': ['Promise', 'prototype'], - '%PromiseProto_then%': ['Promise', 'prototype', 'then'], - '%Promise_all%': ['Promise', 'all'], - '%Promise_reject%': ['Promise', 'reject'], - '%Promise_resolve%': ['Promise', 'resolve'], - '%RangeErrorPrototype%': ['RangeError', 'prototype'], - '%ReferenceErrorPrototype%': ['ReferenceError', 'prototype'], - '%RegExpPrototype%': ['RegExp', 'prototype'], - '%SetPrototype%': ['Set', 'prototype'], - '%SharedArrayBufferPrototype%': ['SharedArrayBuffer', 'prototype'], - '%StringPrototype%': ['String', 'prototype'], - '%SymbolPrototype%': ['Symbol', 'prototype'], - '%SyntaxErrorPrototype%': ['SyntaxError', 'prototype'], - '%TypedArrayPrototype%': ['TypedArray', 'prototype'], - '%TypeErrorPrototype%': ['TypeError', 'prototype'], - '%Uint8ArrayPrototype%': ['Uint8Array', 'prototype'], - '%Uint8ClampedArrayPrototype%': ['Uint8ClampedArray', 'prototype'], - '%Uint16ArrayPrototype%': ['Uint16Array', 'prototype'], - '%Uint32ArrayPrototype%': ['Uint32Array', 'prototype'], - '%URIErrorPrototype%': ['URIError', 'prototype'], - '%WeakMapPrototype%': ['WeakMap', 'prototype'], - '%WeakSetPrototype%': ['WeakSet', 'prototype'] - }; - - var bind = functionBind; - var hasOwn$2 = src; - var $concat$1 = bind.call(Function.call, Array.prototype.concat); - var $spliceApply = bind.call(Function.apply, Array.prototype.splice); - var $replace$1 = bind.call(Function.call, String.prototype.replace); - var $strSlice = bind.call(Function.call, String.prototype.slice); - - /* adapted from https://github.com/lodash/lodash/blob/4.17.15/dist/lodash.js#L6735-L6744 */ - var rePropName = /[^%.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|%$))/g; - var reEscapeChar = /\\(\\)?/g; /** Used to match backslashes in property paths. */ - var stringToPath = function stringToPath(string) { - var first = $strSlice(string, 0, 1); - var last = $strSlice(string, -1); - if (first === '%' && last !== '%') { - throw new $SyntaxError('invalid intrinsic syntax, expected closing `%`'); - } else if (last === '%' && first !== '%') { - throw new $SyntaxError('invalid intrinsic syntax, expected opening `%`'); - } - var result = []; - $replace$1(string, rePropName, function (match, number, quote, subString) { - result[result.length] = quote ? $replace$1(subString, reEscapeChar, '$1') : number || match; - }); - return result; - }; - /* end adaptation */ - - var getBaseIntrinsic = function getBaseIntrinsic(name, allowMissing) { - var intrinsicName = name; - var alias; - if (hasOwn$2(LEGACY_ALIASES, intrinsicName)) { - alias = LEGACY_ALIASES[intrinsicName]; - intrinsicName = '%' + alias[0] + '%'; - } - - if (hasOwn$2(INTRINSICS, intrinsicName)) { - var value = INTRINSICS[intrinsicName]; - if (value === needsEval) { - value = doEval(intrinsicName); - } - if (typeof value === 'undefined' && !allowMissing) { - throw new $TypeError$1('intrinsic ' + name + ' exists, but is not available. Please file an issue!'); - } - - return { - alias: alias, - name: intrinsicName, - value: value - }; - } - - throw new $SyntaxError('intrinsic ' + name + ' does not exist!'); - }; - - var getIntrinsic = function GetIntrinsic(name, allowMissing) { - if (typeof name !== 'string' || name.length === 0) { - throw new $TypeError$1('intrinsic name must be a non-empty string'); - } - if (arguments.length > 1 && typeof allowMissing !== 'boolean') { - throw new $TypeError$1('"allowMissing" argument must be a boolean'); - } - - var parts = stringToPath(name); - var intrinsicBaseName = parts.length > 0 ? parts[0] : ''; - - var intrinsic = getBaseIntrinsic('%' + intrinsicBaseName + '%', allowMissing); - var intrinsicRealName = intrinsic.name; - var value = intrinsic.value; - var skipFurtherCaching = false; - - var alias = intrinsic.alias; - if (alias) { - intrinsicBaseName = alias[0]; - $spliceApply(parts, $concat$1([0, 1], alias)); - } - - for (var i = 1, isOwn = true; i < parts.length; i += 1) { - var part = parts[i]; - var first = $strSlice(part, 0, 1); - var last = $strSlice(part, -1); - if ( - ( - (first === '"' || first === "'" || first === '`') - || (last === '"' || last === "'" || last === '`') - ) - && first !== last - ) { - throw new $SyntaxError('property names with quotes must have matching quotes'); - } - if (part === 'constructor' || !isOwn) { - skipFurtherCaching = true; - } - - intrinsicBaseName += '.' + part; - intrinsicRealName = '%' + intrinsicBaseName + '%'; - - if (hasOwn$2(INTRINSICS, intrinsicRealName)) { - value = INTRINSICS[intrinsicRealName]; - } else if (value != null) { - if (!(part in value)) { - if (!allowMissing) { - throw new $TypeError$1('base intrinsic for ' + name + ' exists, but the property is not available.'); - } - return void undefined$1; - } - if ($gOPD && (i + 1) >= parts.length) { - var desc = $gOPD(value, part); - isOwn = !!desc; - - // By convention, when a data property is converted to an accessor - // property to emulate a data property that does not suffer from - // the override mistake, that accessor's getter is marked with - // an `originalValue` property. Here, when we detect this, we - // uphold the illusion by pretending to see that original data - // property, i.e., returning the value rather than the getter - // itself. - if (isOwn && 'get' in desc && !('originalValue' in desc.get)) { - value = desc.get; - } else { - value = value[part]; - } - } else { - isOwn = hasOwn$2(value, part); - value = value[part]; - } - - if (isOwn && !skipFurtherCaching) { - INTRINSICS[intrinsicRealName] = value; - } - } - } - return value; - }; - - var callBind$1 = {exports: {}}; - - (function (module) { - - var bind = functionBind; - var GetIntrinsic = getIntrinsic; - - var $apply = GetIntrinsic('%Function.prototype.apply%'); - var $call = GetIntrinsic('%Function.prototype.call%'); - var $reflectApply = GetIntrinsic('%Reflect.apply%', true) || bind.call($call, $apply); - - var $gOPD = GetIntrinsic('%Object.getOwnPropertyDescriptor%', true); - var $defineProperty = GetIntrinsic('%Object.defineProperty%', true); - var $max = GetIntrinsic('%Math.max%'); - - if ($defineProperty) { - try { - $defineProperty({}, 'a', { value: 1 }); - } catch (e) { - // IE 8 has a broken defineProperty - $defineProperty = null; - } - } - - module.exports = function callBind(originalFunction) { - var func = $reflectApply(bind, $call, arguments); - if ($gOPD && $defineProperty) { - var desc = $gOPD(func, 'length'); - if (desc.configurable) { - // original length, plus the receiver, minus any additional arguments (after the receiver) - $defineProperty( - func, - 'length', - { value: 1 + $max(0, originalFunction.length - (arguments.length - 1)) } - ); - } - } - return func; - }; - - var applyBind = function applyBind() { - return $reflectApply(bind, $apply, arguments); - }; - - if ($defineProperty) { - $defineProperty(module.exports, 'apply', { value: applyBind }); - } else { - module.exports.apply = applyBind; - } - }(callBind$1)); - - var GetIntrinsic$1 = getIntrinsic; - - var callBind = callBind$1.exports; - - var $indexOf = callBind(GetIntrinsic$1('String.prototype.indexOf')); - - var callBound$1 = function callBoundIntrinsic(name, allowMissing) { - var intrinsic = GetIntrinsic$1(name, !!allowMissing); - if (typeof intrinsic === 'function' && $indexOf(name, '.prototype.') > -1) { - return callBind(intrinsic); - } - return intrinsic; - }; - - var _nodeResolve_empty = {}; - - var _nodeResolve_empty$1 = /*#__PURE__*/Object.freeze({ - __proto__: null, - 'default': _nodeResolve_empty - }); - - var require$$0 = /*@__PURE__*/getAugmentedNamespace(_nodeResolve_empty$1); - - var hasMap = typeof Map === 'function' && Map.prototype; - var mapSizeDescriptor = Object.getOwnPropertyDescriptor && hasMap ? Object.getOwnPropertyDescriptor(Map.prototype, 'size') : null; - var mapSize = hasMap && mapSizeDescriptor && typeof mapSizeDescriptor.get === 'function' ? mapSizeDescriptor.get : null; - var mapForEach = hasMap && Map.prototype.forEach; - var hasSet = typeof Set === 'function' && Set.prototype; - var setSizeDescriptor = Object.getOwnPropertyDescriptor && hasSet ? Object.getOwnPropertyDescriptor(Set.prototype, 'size') : null; - var setSize = hasSet && setSizeDescriptor && typeof setSizeDescriptor.get === 'function' ? setSizeDescriptor.get : null; - var setForEach = hasSet && Set.prototype.forEach; - var hasWeakMap = typeof WeakMap === 'function' && WeakMap.prototype; - var weakMapHas = hasWeakMap ? WeakMap.prototype.has : null; - var hasWeakSet = typeof WeakSet === 'function' && WeakSet.prototype; - var weakSetHas = hasWeakSet ? WeakSet.prototype.has : null; - var hasWeakRef = typeof WeakRef === 'function' && WeakRef.prototype; - var weakRefDeref = hasWeakRef ? WeakRef.prototype.deref : null; - var booleanValueOf = Boolean.prototype.valueOf; - var objectToString = Object.prototype.toString; - var functionToString = Function.prototype.toString; - var $match = String.prototype.match; - var $slice = String.prototype.slice; - var $replace = String.prototype.replace; - var $toUpperCase = String.prototype.toUpperCase; - var $toLowerCase = String.prototype.toLowerCase; - var $test = RegExp.prototype.test; - var $concat = Array.prototype.concat; - var $join = Array.prototype.join; - var $arrSlice = Array.prototype.slice; - var $floor = Math.floor; - var bigIntValueOf = typeof BigInt === 'function' ? BigInt.prototype.valueOf : null; - var gOPS = Object.getOwnPropertySymbols; - var symToString = typeof Symbol === 'function' && typeof Symbol.iterator === 'symbol' ? Symbol.prototype.toString : null; - var hasShammedSymbols = typeof Symbol === 'function' && typeof Symbol.iterator === 'object'; - // ie, `has-tostringtag/shams - var toStringTag = typeof Symbol === 'function' && Symbol.toStringTag && (typeof Symbol.toStringTag === hasShammedSymbols ? 'object' : 'symbol') - ? Symbol.toStringTag - : null; - var isEnumerable = Object.prototype.propertyIsEnumerable; - - var gPO = (typeof Reflect === 'function' ? Reflect.getPrototypeOf : Object.getPrototypeOf) || ( - [].__proto__ === Array.prototype // eslint-disable-line no-proto - ? function (O) { - return O.__proto__; // eslint-disable-line no-proto - } - : null - ); - - function addNumericSeparator(num, str) { - if ( - num === Infinity - || num === -Infinity - || num !== num - || (num && num > -1000 && num < 1000) - || $test.call(/e/, str) - ) { - return str; - } - var sepRegex = /[0-9](?=(?:[0-9]{3})+(?![0-9]))/g; - if (typeof num === 'number') { - var int = num < 0 ? -$floor(-num) : $floor(num); // trunc(num) - if (int !== num) { - var intStr = String(int); - var dec = $slice.call(str, intStr.length + 1); - return $replace.call(intStr, sepRegex, '$&_') + '.' + $replace.call($replace.call(dec, /([0-9]{3})/g, '$&_'), /_$/, ''); - } - } - return $replace.call(str, sepRegex, '$&_'); - } - - var utilInspect = require$$0; - var inspectCustom = utilInspect.custom; - var inspectSymbol = isSymbol(inspectCustom) ? inspectCustom : null; - - var objectInspect = function inspect_(obj, options, depth, seen) { - var opts = options || {}; - - if (has$3(opts, 'quoteStyle') && (opts.quoteStyle !== 'single' && opts.quoteStyle !== 'double')) { - throw new TypeError('option "quoteStyle" must be "single" or "double"'); - } - if ( - has$3(opts, 'maxStringLength') && (typeof opts.maxStringLength === 'number' - ? opts.maxStringLength < 0 && opts.maxStringLength !== Infinity - : opts.maxStringLength !== null - ) - ) { - throw new TypeError('option "maxStringLength", if provided, must be a positive integer, Infinity, or `null`'); - } - var customInspect = has$3(opts, 'customInspect') ? opts.customInspect : true; - if (typeof customInspect !== 'boolean' && customInspect !== 'symbol') { - throw new TypeError('option "customInspect", if provided, must be `true`, `false`, or `\'symbol\'`'); - } - - if ( - has$3(opts, 'indent') - && opts.indent !== null - && opts.indent !== '\t' - && !(parseInt(opts.indent, 10) === opts.indent && opts.indent > 0) - ) { - throw new TypeError('option "indent" must be "\\t", an integer > 0, or `null`'); - } - if (has$3(opts, 'numericSeparator') && typeof opts.numericSeparator !== 'boolean') { - throw new TypeError('option "numericSeparator", if provided, must be `true` or `false`'); - } - var numericSeparator = opts.numericSeparator; - - if (typeof obj === 'undefined') { - return 'undefined'; - } - if (obj === null) { - return 'null'; - } - if (typeof obj === 'boolean') { - return obj ? 'true' : 'false'; - } - - if (typeof obj === 'string') { - return inspectString(obj, opts); - } - if (typeof obj === 'number') { - if (obj === 0) { - return Infinity / obj > 0 ? '0' : '-0'; - } - var str = String(obj); - return numericSeparator ? addNumericSeparator(obj, str) : str; - } - if (typeof obj === 'bigint') { - var bigIntStr = String(obj) + 'n'; - return numericSeparator ? addNumericSeparator(obj, bigIntStr) : bigIntStr; - } - - var maxDepth = typeof opts.depth === 'undefined' ? 5 : opts.depth; - if (typeof depth === 'undefined') { depth = 0; } - if (depth >= maxDepth && maxDepth > 0 && typeof obj === 'object') { - return isArray$3(obj) ? '[Array]' : '[Object]'; - } - - var indent = getIndent(opts, depth); - - if (typeof seen === 'undefined') { - seen = []; - } else if (indexOf(seen, obj) >= 0) { - return '[Circular]'; - } - - function inspect(value, from, noIndent) { - if (from) { - seen = $arrSlice.call(seen); - seen.push(from); - } - if (noIndent) { - var newOpts = { - depth: opts.depth - }; - if (has$3(opts, 'quoteStyle')) { - newOpts.quoteStyle = opts.quoteStyle; - } - return inspect_(value, newOpts, depth + 1, seen); - } - return inspect_(value, opts, depth + 1, seen); - } - - if (typeof obj === 'function' && !isRegExp$1(obj)) { // in older engines, regexes are callable - var name = nameOf(obj); - var keys = arrObjKeys(obj, inspect); - return '[Function' + (name ? ': ' + name : ' (anonymous)') + ']' + (keys.length > 0 ? ' { ' + $join.call(keys, ', ') + ' }' : ''); - } - if (isSymbol(obj)) { - var symString = hasShammedSymbols ? $replace.call(String(obj), /^(Symbol\(.*\))_[^)]*$/, '$1') : symToString.call(obj); - return typeof obj === 'object' && !hasShammedSymbols ? markBoxed(symString) : symString; - } - if (isElement(obj)) { - var s = '<' + $toLowerCase.call(String(obj.nodeName)); - var attrs = obj.attributes || []; - for (var i = 0; i < attrs.length; i++) { - s += ' ' + attrs[i].name + '=' + wrapQuotes(quote(attrs[i].value), 'double', opts); - } - s += '>'; - if (obj.childNodes && obj.childNodes.length) { s += '...'; } - s += ''; - return s; - } - if (isArray$3(obj)) { - if (obj.length === 0) { return '[]'; } - var xs = arrObjKeys(obj, inspect); - if (indent && !singleLineValues(xs)) { - return '[' + indentedJoin(xs, indent) + ']'; - } - return '[ ' + $join.call(xs, ', ') + ' ]'; - } - if (isError(obj)) { - var parts = arrObjKeys(obj, inspect); - if (!('cause' in Error.prototype) && 'cause' in obj && !isEnumerable.call(obj, 'cause')) { - return '{ [' + String(obj) + '] ' + $join.call($concat.call('[cause]: ' + inspect(obj.cause), parts), ', ') + ' }'; - } - if (parts.length === 0) { return '[' + String(obj) + ']'; } - return '{ [' + String(obj) + '] ' + $join.call(parts, ', ') + ' }'; - } - if (typeof obj === 'object' && customInspect) { - if (inspectSymbol && typeof obj[inspectSymbol] === 'function' && utilInspect) { - return utilInspect(obj, { depth: maxDepth - depth }); - } else if (customInspect !== 'symbol' && typeof obj.inspect === 'function') { - return obj.inspect(); - } - } - if (isMap(obj)) { - var mapParts = []; - if (mapForEach) { - mapForEach.call(obj, function (value, key) { - mapParts.push(inspect(key, obj, true) + ' => ' + inspect(value, obj)); - }); - } - return collectionOf('Map', mapSize.call(obj), mapParts, indent); - } - if (isSet(obj)) { - var setParts = []; - if (setForEach) { - setForEach.call(obj, function (value) { - setParts.push(inspect(value, obj)); - }); - } - return collectionOf('Set', setSize.call(obj), setParts, indent); - } - if (isWeakMap(obj)) { - return weakCollectionOf('WeakMap'); - } - if (isWeakSet(obj)) { - return weakCollectionOf('WeakSet'); - } - if (isWeakRef(obj)) { - return weakCollectionOf('WeakRef'); - } - if (isNumber(obj)) { - return markBoxed(inspect(Number(obj))); - } - if (isBigInt(obj)) { - return markBoxed(inspect(bigIntValueOf.call(obj))); - } - if (isBoolean(obj)) { - return markBoxed(booleanValueOf.call(obj)); - } - if (isString(obj)) { - return markBoxed(inspect(String(obj))); - } - // note: in IE 8, sometimes `global !== window` but both are the prototypes of each other - /* eslint-env browser */ - if (typeof window !== 'undefined' && obj === window) { - return '{ [object Window] }'; - } - if (obj === commonjsGlobal) { - return '{ [object globalThis] }'; - } - if (!isDate(obj) && !isRegExp$1(obj)) { - var ys = arrObjKeys(obj, inspect); - var isPlainObject = gPO ? gPO(obj) === Object.prototype : obj instanceof Object || obj.constructor === Object; - var protoTag = obj instanceof Object ? '' : 'null prototype'; - var stringTag = !isPlainObject && toStringTag && Object(obj) === obj && toStringTag in obj ? $slice.call(toStr(obj), 8, -1) : protoTag ? 'Object' : ''; - var constructorTag = isPlainObject || typeof obj.constructor !== 'function' ? '' : obj.constructor.name ? obj.constructor.name + ' ' : ''; - var tag = constructorTag + (stringTag || protoTag ? '[' + $join.call($concat.call([], stringTag || [], protoTag || []), ': ') + '] ' : ''); - if (ys.length === 0) { return tag + '{}'; } - if (indent) { - return tag + '{' + indentedJoin(ys, indent) + '}'; - } - return tag + '{ ' + $join.call(ys, ', ') + ' }'; - } - return String(obj); - }; - - function wrapQuotes(s, defaultStyle, opts) { - var quoteChar = (opts.quoteStyle || defaultStyle) === 'double' ? '"' : "'"; - return quoteChar + s + quoteChar; - } - - function quote(s) { - return $replace.call(String(s), /"/g, '"'); - } - - function isArray$3(obj) { return toStr(obj) === '[object Array]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); } - function isDate(obj) { return toStr(obj) === '[object Date]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); } - function isRegExp$1(obj) { return toStr(obj) === '[object RegExp]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); } - function isError(obj) { return toStr(obj) === '[object Error]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); } - function isString(obj) { return toStr(obj) === '[object String]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); } - function isNumber(obj) { return toStr(obj) === '[object Number]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); } - function isBoolean(obj) { return toStr(obj) === '[object Boolean]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); } - - // Symbol and BigInt do have Symbol.toStringTag by spec, so that can't be used to eliminate false positives - function isSymbol(obj) { - if (hasShammedSymbols) { - return obj && typeof obj === 'object' && obj instanceof Symbol; - } - if (typeof obj === 'symbol') { - return true; - } - if (!obj || typeof obj !== 'object' || !symToString) { - return false; - } - try { - symToString.call(obj); - return true; - } catch (e) {} - return false; - } - - function isBigInt(obj) { - if (!obj || typeof obj !== 'object' || !bigIntValueOf) { - return false; - } - try { - bigIntValueOf.call(obj); - return true; - } catch (e) {} - return false; - } - - var hasOwn$1 = Object.prototype.hasOwnProperty || function (key) { return key in this; }; - function has$3(obj, key) { - return hasOwn$1.call(obj, key); - } - - function toStr(obj) { - return objectToString.call(obj); - } - - function nameOf(f) { - if (f.name) { return f.name; } - var m = $match.call(functionToString.call(f), /^function\s*([\w$]+)/); - if (m) { return m[1]; } - return null; - } - - function indexOf(xs, x) { - if (xs.indexOf) { return xs.indexOf(x); } - for (var i = 0, l = xs.length; i < l; i++) { - if (xs[i] === x) { return i; } - } - return -1; - } - - function isMap(x) { - if (!mapSize || !x || typeof x !== 'object') { - return false; - } - try { - mapSize.call(x); - try { - setSize.call(x); - } catch (s) { - return true; - } - return x instanceof Map; // core-js workaround, pre-v2.5.0 - } catch (e) {} - return false; - } - - function isWeakMap(x) { - if (!weakMapHas || !x || typeof x !== 'object') { - return false; - } - try { - weakMapHas.call(x, weakMapHas); - try { - weakSetHas.call(x, weakSetHas); - } catch (s) { - return true; - } - return x instanceof WeakMap; // core-js workaround, pre-v2.5.0 - } catch (e) {} - return false; - } - - function isWeakRef(x) { - if (!weakRefDeref || !x || typeof x !== 'object') { - return false; - } - try { - weakRefDeref.call(x); - return true; - } catch (e) {} - return false; - } - - function isSet(x) { - if (!setSize || !x || typeof x !== 'object') { - return false; - } - try { - setSize.call(x); - try { - mapSize.call(x); - } catch (m) { - return true; - } - return x instanceof Set; // core-js workaround, pre-v2.5.0 - } catch (e) {} - return false; - } - - function isWeakSet(x) { - if (!weakSetHas || !x || typeof x !== 'object') { - return false; - } - try { - weakSetHas.call(x, weakSetHas); - try { - weakMapHas.call(x, weakMapHas); - } catch (s) { - return true; - } - return x instanceof WeakSet; // core-js workaround, pre-v2.5.0 - } catch (e) {} - return false; - } - - function isElement(x) { - if (!x || typeof x !== 'object') { return false; } - if (typeof HTMLElement !== 'undefined' && x instanceof HTMLElement) { - return true; - } - return typeof x.nodeName === 'string' && typeof x.getAttribute === 'function'; - } - - function inspectString(str, opts) { - if (str.length > opts.maxStringLength) { - var remaining = str.length - opts.maxStringLength; - var trailer = '... ' + remaining + ' more character' + (remaining > 1 ? 's' : ''); - return inspectString($slice.call(str, 0, opts.maxStringLength), opts) + trailer; - } - // eslint-disable-next-line no-control-regex - var s = $replace.call($replace.call(str, /(['\\])/g, '\\$1'), /[\x00-\x1f]/g, lowbyte); - return wrapQuotes(s, 'single', opts); - } - - function lowbyte(c) { - var n = c.charCodeAt(0); - var x = { - 8: 'b', - 9: 't', - 10: 'n', - 12: 'f', - 13: 'r' - }[n]; - if (x) { return '\\' + x; } - return '\\x' + (n < 0x10 ? '0' : '') + $toUpperCase.call(n.toString(16)); - } - - function markBoxed(str) { - return 'Object(' + str + ')'; - } - - function weakCollectionOf(type) { - return type + ' { ? }'; - } - - function collectionOf(type, size, entries, indent) { - var joinedEntries = indent ? indentedJoin(entries, indent) : $join.call(entries, ', '); - return type + ' (' + size + ') {' + joinedEntries + '}'; - } - - function singleLineValues(xs) { - for (var i = 0; i < xs.length; i++) { - if (indexOf(xs[i], '\n') >= 0) { - return false; - } - } - return true; - } - - function getIndent(opts, depth) { - var baseIndent; - if (opts.indent === '\t') { - baseIndent = '\t'; - } else if (typeof opts.indent === 'number' && opts.indent > 0) { - baseIndent = $join.call(Array(opts.indent + 1), ' '); - } else { - return null; - } - return { - base: baseIndent, - prev: $join.call(Array(depth + 1), baseIndent) - }; - } - - function indentedJoin(xs, indent) { - if (xs.length === 0) { return ''; } - var lineJoiner = '\n' + indent.prev + indent.base; - return lineJoiner + $join.call(xs, ',' + lineJoiner) + '\n' + indent.prev; - } - - function arrObjKeys(obj, inspect) { - var isArr = isArray$3(obj); - var xs = []; - if (isArr) { - xs.length = obj.length; - for (var i = 0; i < obj.length; i++) { - xs[i] = has$3(obj, i) ? inspect(obj[i], obj) : ''; - } - } - var syms = typeof gOPS === 'function' ? gOPS(obj) : []; - var symMap; - if (hasShammedSymbols) { - symMap = {}; - for (var k = 0; k < syms.length; k++) { - symMap['$' + syms[k]] = syms[k]; - } - } - - for (var key in obj) { // eslint-disable-line no-restricted-syntax - if (!has$3(obj, key)) { continue; } // eslint-disable-line no-restricted-syntax, no-continue - if (isArr && String(Number(key)) === key && key < obj.length) { continue; } // eslint-disable-line no-restricted-syntax, no-continue - if (hasShammedSymbols && symMap['$' + key] instanceof Symbol) { - // this is to prevent shammed Symbols, which are stored as strings, from being included in the string key section - continue; // eslint-disable-line no-restricted-syntax, no-continue - } else if ($test.call(/[^\w$]/, key)) { - xs.push(inspect(key, obj) + ': ' + inspect(obj[key], obj)); - } else { - xs.push(key + ': ' + inspect(obj[key], obj)); - } - } - if (typeof gOPS === 'function') { - for (var j = 0; j < syms.length; j++) { - if (isEnumerable.call(obj, syms[j])) { - xs.push('[' + inspect(syms[j]) + ']: ' + inspect(obj[syms[j]], obj)); - } - } - } - return xs; - } - - var GetIntrinsic = getIntrinsic; - var callBound = callBound$1; - var inspect = objectInspect; - - var $TypeError = GetIntrinsic('%TypeError%'); - var $WeakMap = GetIntrinsic('%WeakMap%', true); - var $Map = GetIntrinsic('%Map%', true); - - var $weakMapGet = callBound('WeakMap.prototype.get', true); - var $weakMapSet = callBound('WeakMap.prototype.set', true); - var $weakMapHas = callBound('WeakMap.prototype.has', true); - var $mapGet = callBound('Map.prototype.get', true); - var $mapSet = callBound('Map.prototype.set', true); - var $mapHas = callBound('Map.prototype.has', true); - - /* - * This function traverses the list returning the node corresponding to the - * given key. - * - * That node is also moved to the head of the list, so that if it's accessed - * again we don't need to traverse the whole list. By doing so, all the recently - * used nodes can be accessed relatively quickly. - */ - var listGetNode = function (list, key) { // eslint-disable-line consistent-return - for (var prev = list, curr; (curr = prev.next) !== null; prev = curr) { - if (curr.key === key) { - prev.next = curr.next; - curr.next = list.next; - list.next = curr; // eslint-disable-line no-param-reassign - return curr; - } - } - }; - - var listGet = function (objects, key) { - var node = listGetNode(objects, key); - return node && node.value; - }; - var listSet = function (objects, key, value) { - var node = listGetNode(objects, key); - if (node) { - node.value = value; - } else { - // Prepend the new node to the beginning of the list - objects.next = { // eslint-disable-line no-param-reassign - key: key, - next: objects.next, - value: value - }; - } - }; - var listHas = function (objects, key) { - return !!listGetNode(objects, key); - }; - - var sideChannel = function getSideChannel() { - var $wm; - var $m; - var $o; - var channel = { - assert: function (key) { - if (!channel.has(key)) { - throw new $TypeError('Side channel does not contain ' + inspect(key)); - } - }, - get: function (key) { // eslint-disable-line consistent-return - if ($WeakMap && key && (typeof key === 'object' || typeof key === 'function')) { - if ($wm) { - return $weakMapGet($wm, key); - } - } else if ($Map) { - if ($m) { - return $mapGet($m, key); - } - } else { - if ($o) { // eslint-disable-line no-lonely-if - return listGet($o, key); - } - } - }, - has: function (key) { - if ($WeakMap && key && (typeof key === 'object' || typeof key === 'function')) { - if ($wm) { - return $weakMapHas($wm, key); - } - } else if ($Map) { - if ($m) { - return $mapHas($m, key); - } - } else { - if ($o) { // eslint-disable-line no-lonely-if - return listHas($o, key); - } - } - return false; - }, - set: function (key, value) { - if ($WeakMap && key && (typeof key === 'object' || typeof key === 'function')) { - if (!$wm) { - $wm = new $WeakMap(); - } - $weakMapSet($wm, key, value); - } else if ($Map) { - if (!$m) { - $m = new $Map(); - } - $mapSet($m, key, value); - } else { - if (!$o) { - /* - * Initialize the linked list as an empty node, so that we don't have - * to special-case handling of the first node: we can always refer to - * it as (previous node).next, instead of something like (list).head - */ - $o = { key: {}, next: null }; - } - listSet($o, key, value); - } - } - }; - return channel; - }; - - var replace = String.prototype.replace; - var percentTwenties = /%20/g; - - var Format = { - RFC1738: 'RFC1738', - RFC3986: 'RFC3986' - }; - - var formats$3 = { - 'default': Format.RFC3986, - formatters: { - RFC1738: function (value) { - return replace.call(value, percentTwenties, '+'); - }, - RFC3986: function (value) { - return String(value); - } - }, - RFC1738: Format.RFC1738, - RFC3986: Format.RFC3986 - }; - - var formats$2 = formats$3; - - var has$2 = Object.prototype.hasOwnProperty; - var isArray$2 = Array.isArray; - - var hexTable = (function () { - var array = []; - for (var i = 0; i < 256; ++i) { - array.push('%' + ((i < 16 ? '0' : '') + i.toString(16)).toUpperCase()); - } - - return array; - }()); - - var compactQueue = function compactQueue(queue) { - while (queue.length > 1) { - var item = queue.pop(); - var obj = item.obj[item.prop]; - - if (isArray$2(obj)) { - var compacted = []; - - for (var j = 0; j < obj.length; ++j) { - if (typeof obj[j] !== 'undefined') { - compacted.push(obj[j]); - } - } - - item.obj[item.prop] = compacted; - } - } - }; - - var arrayToObject = function arrayToObject(source, options) { - var obj = options && options.plainObjects ? Object.create(null) : {}; - for (var i = 0; i < source.length; ++i) { - if (typeof source[i] !== 'undefined') { - obj[i] = source[i]; - } - } - - return obj; - }; - - var merge = function merge(target, source, options) { - /* eslint no-param-reassign: 0 */ - if (!source) { - return target; - } - - if (typeof source !== 'object') { - if (isArray$2(target)) { - target.push(source); - } else if (target && typeof target === 'object') { - if ((options && (options.plainObjects || options.allowPrototypes)) || !has$2.call(Object.prototype, source)) { - target[source] = true; - } - } else { - return [target, source]; - } - - return target; - } - - if (!target || typeof target !== 'object') { - return [target].concat(source); - } - - var mergeTarget = target; - if (isArray$2(target) && !isArray$2(source)) { - mergeTarget = arrayToObject(target, options); - } - - if (isArray$2(target) && isArray$2(source)) { - source.forEach(function (item, i) { - if (has$2.call(target, i)) { - var targetItem = target[i]; - if (targetItem && typeof targetItem === 'object' && item && typeof item === 'object') { - target[i] = merge(targetItem, item, options); - } else { - target.push(item); - } - } else { - target[i] = item; - } - }); - return target; - } - - return Object.keys(source).reduce(function (acc, key) { - var value = source[key]; - - if (has$2.call(acc, key)) { - acc[key] = merge(acc[key], value, options); - } else { - acc[key] = value; - } - return acc; - }, mergeTarget); - }; - - var assign = function assignSingleSource(target, source) { - return Object.keys(source).reduce(function (acc, key) { - acc[key] = source[key]; - return acc; - }, target); - }; - - var decode = function (str, decoder, charset) { - var strWithoutPlus = str.replace(/\+/g, ' '); - if (charset === 'iso-8859-1') { - // unescape never throws, no try...catch needed: - return strWithoutPlus.replace(/%[0-9a-f]{2}/gi, unescape); - } - // utf-8 - try { - return decodeURIComponent(strWithoutPlus); - } catch (e) { - return strWithoutPlus; - } - }; - - var encode = function encode(str, defaultEncoder, charset, kind, format) { - // This code was originally written by Brian White (mscdex) for the io.js core querystring library. - // It has been adapted here for stricter adherence to RFC 3986 - if (str.length === 0) { - return str; - } - - var string = str; - if (typeof str === 'symbol') { - string = Symbol.prototype.toString.call(str); - } else if (typeof str !== 'string') { - string = String(str); - } - - if (charset === 'iso-8859-1') { - return escape(string).replace(/%u[0-9a-f]{4}/gi, function ($0) { - return '%26%23' + parseInt($0.slice(2), 16) + '%3B'; - }); - } - - var out = ''; - for (var i = 0; i < string.length; ++i) { - var c = string.charCodeAt(i); - - if ( - c === 0x2D // - - || c === 0x2E // . - || c === 0x5F // _ - || c === 0x7E // ~ - || (c >= 0x30 && c <= 0x39) // 0-9 - || (c >= 0x41 && c <= 0x5A) // a-z - || (c >= 0x61 && c <= 0x7A) // A-Z - || (format === formats$2.RFC1738 && (c === 0x28 || c === 0x29)) // ( ) - ) { - out += string.charAt(i); - continue; - } - - if (c < 0x80) { - out = out + hexTable[c]; - continue; - } - - if (c < 0x800) { - out = out + (hexTable[0xC0 | (c >> 6)] + hexTable[0x80 | (c & 0x3F)]); - continue; - } - - if (c < 0xD800 || c >= 0xE000) { - out = out + (hexTable[0xE0 | (c >> 12)] + hexTable[0x80 | ((c >> 6) & 0x3F)] + hexTable[0x80 | (c & 0x3F)]); - continue; - } - - i += 1; - c = 0x10000 + (((c & 0x3FF) << 10) | (string.charCodeAt(i) & 0x3FF)); - /* eslint operator-linebreak: [2, "before"] */ - out += hexTable[0xF0 | (c >> 18)] - + hexTable[0x80 | ((c >> 12) & 0x3F)] - + hexTable[0x80 | ((c >> 6) & 0x3F)] - + hexTable[0x80 | (c & 0x3F)]; - } - - return out; - }; - - var compact = function compact(value) { - var queue = [{ obj: { o: value }, prop: 'o' }]; - var refs = []; - - for (var i = 0; i < queue.length; ++i) { - var item = queue[i]; - var obj = item.obj[item.prop]; - - var keys = Object.keys(obj); - for (var j = 0; j < keys.length; ++j) { - var key = keys[j]; - var val = obj[key]; - if (typeof val === 'object' && val !== null && refs.indexOf(val) === -1) { - queue.push({ obj: obj, prop: key }); - refs.push(val); - } - } - } - - compactQueue(queue); - - return value; - }; - - var isRegExp = function isRegExp(obj) { - return Object.prototype.toString.call(obj) === '[object RegExp]'; - }; - - var isBuffer = function isBuffer(obj) { - if (!obj || typeof obj !== 'object') { - return false; - } - - return !!(obj.constructor && obj.constructor.isBuffer && obj.constructor.isBuffer(obj)); - }; - - var combine = function combine(a, b) { - return [].concat(a, b); - }; - - var maybeMap = function maybeMap(val, fn) { - if (isArray$2(val)) { - var mapped = []; - for (var i = 0; i < val.length; i += 1) { - mapped.push(fn(val[i])); - } - return mapped; - } - return fn(val); - }; - - var utils$4 = { - arrayToObject: arrayToObject, - assign: assign, - combine: combine, - compact: compact, - decode: decode, - encode: encode, - isBuffer: isBuffer, - isRegExp: isRegExp, - maybeMap: maybeMap, - merge: merge - }; - - var getSideChannel = sideChannel; - var utils$3 = utils$4; - var formats$1 = formats$3; - var has$1 = Object.prototype.hasOwnProperty; - - var arrayPrefixGenerators = { - brackets: function brackets(prefix) { - return prefix + '[]'; - }, - comma: 'comma', - indices: function indices(prefix, key) { - return prefix + '[' + key + ']'; - }, - repeat: function repeat(prefix) { - return prefix; - } - }; - - var isArray$1 = Array.isArray; - var push = Array.prototype.push; - var pushToArray = function (arr, valueOrArray) { - push.apply(arr, isArray$1(valueOrArray) ? valueOrArray : [valueOrArray]); - }; - - var toISO = Date.prototype.toISOString; - - var defaultFormat = formats$1['default']; - var defaults$1 = { - addQueryPrefix: false, - allowDots: false, - charset: 'utf-8', - charsetSentinel: false, - delimiter: '&', - encode: true, - encoder: utils$3.encode, - encodeValuesOnly: false, - format: defaultFormat, - formatter: formats$1.formatters[defaultFormat], - // deprecated - indices: false, - serializeDate: function serializeDate(date) { - return toISO.call(date); - }, - skipNulls: false, - strictNullHandling: false - }; - - var isNonNullishPrimitive = function isNonNullishPrimitive(v) { - return typeof v === 'string' - || typeof v === 'number' - || typeof v === 'boolean' - || typeof v === 'symbol' - || typeof v === 'bigint'; - }; - - var sentinel = {}; - - var stringify$1 = function stringify( - object, - prefix, - generateArrayPrefix, - commaRoundTrip, - strictNullHandling, - skipNulls, - encoder, - filter, - sort, - allowDots, - serializeDate, - format, - formatter, - encodeValuesOnly, - charset, - sideChannel - ) { - var obj = object; - - var tmpSc = sideChannel; - var step = 0; - var findFlag = false; - while ((tmpSc = tmpSc.get(sentinel)) !== void undefined && !findFlag) { - // Where object last appeared in the ref tree - var pos = tmpSc.get(object); - step += 1; - if (typeof pos !== 'undefined') { - if (pos === step) { - throw new RangeError('Cyclic object value'); - } else { - findFlag = true; // Break while - } - } - if (typeof tmpSc.get(sentinel) === 'undefined') { - step = 0; - } - } - - if (typeof filter === 'function') { - obj = filter(prefix, obj); - } else if (obj instanceof Date) { - obj = serializeDate(obj); - } else if (generateArrayPrefix === 'comma' && isArray$1(obj)) { - obj = utils$3.maybeMap(obj, function (value) { - if (value instanceof Date) { - return serializeDate(value); - } - return value; - }); - } - - if (obj === null) { - if (strictNullHandling) { - return encoder && !encodeValuesOnly ? encoder(prefix, defaults$1.encoder, charset, 'key', format) : prefix; - } - - obj = ''; - } - - if (isNonNullishPrimitive(obj) || utils$3.isBuffer(obj)) { - if (encoder) { - var keyValue = encodeValuesOnly ? prefix : encoder(prefix, defaults$1.encoder, charset, 'key', format); - return [formatter(keyValue) + '=' + formatter(encoder(obj, defaults$1.encoder, charset, 'value', format))]; - } - return [formatter(prefix) + '=' + formatter(String(obj))]; - } - - var values = []; - - if (typeof obj === 'undefined') { - return values; - } - - var objKeys; - if (generateArrayPrefix === 'comma' && isArray$1(obj)) { - // we need to join elements in - if (encodeValuesOnly && encoder) { - obj = utils$3.maybeMap(obj, encoder); - } - objKeys = [{ value: obj.length > 0 ? obj.join(',') || null : void undefined }]; - } else if (isArray$1(filter)) { - objKeys = filter; - } else { - var keys = Object.keys(obj); - objKeys = sort ? keys.sort(sort) : keys; - } - - var adjustedPrefix = commaRoundTrip && isArray$1(obj) && obj.length === 1 ? prefix + '[]' : prefix; - - for (var j = 0; j < objKeys.length; ++j) { - var key = objKeys[j]; - var value = typeof key === 'object' && typeof key.value !== 'undefined' ? key.value : obj[key]; - - if (skipNulls && value === null) { - continue; - } - - var keyPrefix = isArray$1(obj) - ? typeof generateArrayPrefix === 'function' ? generateArrayPrefix(adjustedPrefix, key) : adjustedPrefix - : adjustedPrefix + (allowDots ? '.' + key : '[' + key + ']'); - - sideChannel.set(object, step); - var valueSideChannel = getSideChannel(); - valueSideChannel.set(sentinel, sideChannel); - pushToArray(values, stringify( - value, - keyPrefix, - generateArrayPrefix, - commaRoundTrip, - strictNullHandling, - skipNulls, - generateArrayPrefix === 'comma' && encodeValuesOnly && isArray$1(obj) ? null : encoder, - filter, - sort, - allowDots, - serializeDate, - format, - formatter, - encodeValuesOnly, - charset, - valueSideChannel - )); - } - - return values; - }; - - var normalizeStringifyOptions = function normalizeStringifyOptions(opts) { - if (!opts) { - return defaults$1; - } - - if (opts.encoder !== null && typeof opts.encoder !== 'undefined' && typeof opts.encoder !== 'function') { - throw new TypeError('Encoder has to be a function.'); - } - - var charset = opts.charset || defaults$1.charset; - if (typeof opts.charset !== 'undefined' && opts.charset !== 'utf-8' && opts.charset !== 'iso-8859-1') { - throw new TypeError('The charset option must be either utf-8, iso-8859-1, or undefined'); - } - - var format = formats$1['default']; - if (typeof opts.format !== 'undefined') { - if (!has$1.call(formats$1.formatters, opts.format)) { - throw new TypeError('Unknown format option provided.'); - } - format = opts.format; - } - var formatter = formats$1.formatters[format]; - - var filter = defaults$1.filter; - if (typeof opts.filter === 'function' || isArray$1(opts.filter)) { - filter = opts.filter; - } - - return { - addQueryPrefix: typeof opts.addQueryPrefix === 'boolean' ? opts.addQueryPrefix : defaults$1.addQueryPrefix, - allowDots: typeof opts.allowDots === 'undefined' ? defaults$1.allowDots : !!opts.allowDots, - charset: charset, - charsetSentinel: typeof opts.charsetSentinel === 'boolean' ? opts.charsetSentinel : defaults$1.charsetSentinel, - delimiter: typeof opts.delimiter === 'undefined' ? defaults$1.delimiter : opts.delimiter, - encode: typeof opts.encode === 'boolean' ? opts.encode : defaults$1.encode, - encoder: typeof opts.encoder === 'function' ? opts.encoder : defaults$1.encoder, - encodeValuesOnly: typeof opts.encodeValuesOnly === 'boolean' ? opts.encodeValuesOnly : defaults$1.encodeValuesOnly, - filter: filter, - format: format, - formatter: formatter, - serializeDate: typeof opts.serializeDate === 'function' ? opts.serializeDate : defaults$1.serializeDate, - skipNulls: typeof opts.skipNulls === 'boolean' ? opts.skipNulls : defaults$1.skipNulls, - sort: typeof opts.sort === 'function' ? opts.sort : null, - strictNullHandling: typeof opts.strictNullHandling === 'boolean' ? opts.strictNullHandling : defaults$1.strictNullHandling - }; - }; - - var stringify_1 = function (object, opts) { - var obj = object; - var options = normalizeStringifyOptions(opts); - - var objKeys; - var filter; - - if (typeof options.filter === 'function') { - filter = options.filter; - obj = filter('', obj); - } else if (isArray$1(options.filter)) { - filter = options.filter; - objKeys = filter; - } - - var keys = []; - - if (typeof obj !== 'object' || obj === null) { - return ''; - } - - var arrayFormat; - if (opts && opts.arrayFormat in arrayPrefixGenerators) { - arrayFormat = opts.arrayFormat; - } else if (opts && 'indices' in opts) { - arrayFormat = opts.indices ? 'indices' : 'repeat'; - } else { - arrayFormat = 'indices'; - } - - var generateArrayPrefix = arrayPrefixGenerators[arrayFormat]; - if (opts && 'commaRoundTrip' in opts && typeof opts.commaRoundTrip !== 'boolean') { - throw new TypeError('`commaRoundTrip` must be a boolean, or absent'); - } - var commaRoundTrip = generateArrayPrefix === 'comma' && opts && opts.commaRoundTrip; - - if (!objKeys) { - objKeys = Object.keys(obj); - } - - if (options.sort) { - objKeys.sort(options.sort); - } - - var sideChannel = getSideChannel(); - for (var i = 0; i < objKeys.length; ++i) { - var key = objKeys[i]; - - if (options.skipNulls && obj[key] === null) { - continue; - } - pushToArray(keys, stringify$1( - obj[key], - key, - generateArrayPrefix, - commaRoundTrip, - options.strictNullHandling, - options.skipNulls, - options.encode ? options.encoder : null, - options.filter, - options.sort, - options.allowDots, - options.serializeDate, - options.format, - options.formatter, - options.encodeValuesOnly, - options.charset, - sideChannel - )); - } - - var joined = keys.join(options.delimiter); - var prefix = options.addQueryPrefix === true ? '?' : ''; - - if (options.charsetSentinel) { - if (options.charset === 'iso-8859-1') { - // encodeURIComponent('✓'), the "numeric entity" representation of a checkmark - prefix += 'utf8=%26%2310003%3B&'; - } else { - // encodeURIComponent('✓') - prefix += 'utf8=%E2%9C%93&'; - } - } - - return joined.length > 0 ? prefix + joined : ''; - }; - - var utils$2 = utils$4; - - var has = Object.prototype.hasOwnProperty; - var isArray = Array.isArray; - - var defaults = { - allowDots: false, - allowPrototypes: false, - allowSparse: false, - arrayLimit: 20, - charset: 'utf-8', - charsetSentinel: false, - comma: false, - decoder: utils$2.decode, - delimiter: '&', - depth: 5, - ignoreQueryPrefix: false, - interpretNumericEntities: false, - parameterLimit: 1000, - parseArrays: true, - plainObjects: false, - strictNullHandling: false - }; - - var interpretNumericEntities = function (str) { - return str.replace(/&#(\d+);/g, function ($0, numberStr) { - return String.fromCharCode(parseInt(numberStr, 10)); - }); - }; - - var parseArrayValue = function (val, options) { - if (val && typeof val === 'string' && options.comma && val.indexOf(',') > -1) { - return val.split(','); - } - - return val; - }; - - // This is what browsers will submit when the ✓ character occurs in an - // application/x-www-form-urlencoded body and the encoding of the page containing - // the form is iso-8859-1, or when the submitted form has an accept-charset - // attribute of iso-8859-1. Presumably also with other charsets that do not contain - // the ✓ character, such as us-ascii. - var isoSentinel = 'utf8=%26%2310003%3B'; // encodeURIComponent('✓') - - // These are the percent-encoded utf-8 octets representing a checkmark, indicating that the request actually is utf-8 encoded. - var charsetSentinel = 'utf8=%E2%9C%93'; // encodeURIComponent('✓') - - var parseValues = function parseQueryStringValues(str, options) { - var obj = { __proto__: null }; - - var cleanStr = options.ignoreQueryPrefix ? str.replace(/^\?/, '') : str; - var limit = options.parameterLimit === Infinity ? undefined : options.parameterLimit; - var parts = cleanStr.split(options.delimiter, limit); - var skipIndex = -1; // Keep track of where the utf8 sentinel was found - var i; - - var charset = options.charset; - if (options.charsetSentinel) { - for (i = 0; i < parts.length; ++i) { - if (parts[i].indexOf('utf8=') === 0) { - if (parts[i] === charsetSentinel) { - charset = 'utf-8'; - } else if (parts[i] === isoSentinel) { - charset = 'iso-8859-1'; - } - skipIndex = i; - i = parts.length; // The eslint settings do not allow break; - } - } - } - - for (i = 0; i < parts.length; ++i) { - if (i === skipIndex) { - continue; - } - var part = parts[i]; - - var bracketEqualsPos = part.indexOf(']='); - var pos = bracketEqualsPos === -1 ? part.indexOf('=') : bracketEqualsPos + 1; - - var key, val; - if (pos === -1) { - key = options.decoder(part, defaults.decoder, charset, 'key'); - val = options.strictNullHandling ? null : ''; - } else { - key = options.decoder(part.slice(0, pos), defaults.decoder, charset, 'key'); - val = utils$2.maybeMap( - parseArrayValue(part.slice(pos + 1), options), - function (encodedVal) { - return options.decoder(encodedVal, defaults.decoder, charset, 'value'); - } - ); - } - - if (val && options.interpretNumericEntities && charset === 'iso-8859-1') { - val = interpretNumericEntities(val); - } - - if (part.indexOf('[]=') > -1) { - val = isArray(val) ? [val] : val; - } - - if (has.call(obj, key)) { - obj[key] = utils$2.combine(obj[key], val); - } else { - obj[key] = val; - } - } - - return obj; - }; - - var parseObject = function (chain, val, options, valuesParsed) { - var leaf = valuesParsed ? val : parseArrayValue(val, options); - - for (var i = chain.length - 1; i >= 0; --i) { - var obj; - var root = chain[i]; - - if (root === '[]' && options.parseArrays) { - obj = [].concat(leaf); - } else { - obj = options.plainObjects ? Object.create(null) : {}; - var cleanRoot = root.charAt(0) === '[' && root.charAt(root.length - 1) === ']' ? root.slice(1, -1) : root; - var index = parseInt(cleanRoot, 10); - if (!options.parseArrays && cleanRoot === '') { - obj = { 0: leaf }; - } else if ( - !isNaN(index) - && root !== cleanRoot - && String(index) === cleanRoot - && index >= 0 - && (options.parseArrays && index <= options.arrayLimit) - ) { - obj = []; - obj[index] = leaf; - } else if (cleanRoot !== '__proto__') { - obj[cleanRoot] = leaf; - } - } - - leaf = obj; - } - - return leaf; - }; - - var parseKeys = function parseQueryStringKeys(givenKey, val, options, valuesParsed) { - if (!givenKey) { - return; - } - - // Transform dot notation to bracket notation - var key = options.allowDots ? givenKey.replace(/\.([^.[]+)/g, '[$1]') : givenKey; - - // The regex chunks - - var brackets = /(\[[^[\]]*])/; - var child = /(\[[^[\]]*])/g; - - // Get the parent - - var segment = options.depth > 0 && brackets.exec(key); - var parent = segment ? key.slice(0, segment.index) : key; - - // Stash the parent if it exists - - var keys = []; - if (parent) { - // If we aren't using plain objects, optionally prefix keys that would overwrite object prototype properties - if (!options.plainObjects && has.call(Object.prototype, parent)) { - if (!options.allowPrototypes) { - return; - } - } - - keys.push(parent); - } - - // Loop through children appending to the array until we hit depth - - var i = 0; - while (options.depth > 0 && (segment = child.exec(key)) !== null && i < options.depth) { - i += 1; - if (!options.plainObjects && has.call(Object.prototype, segment[1].slice(1, -1))) { - if (!options.allowPrototypes) { - return; - } - } - keys.push(segment[1]); - } - - // If there's a remainder, just add whatever is left - - if (segment) { - keys.push('[' + key.slice(segment.index) + ']'); - } - - return parseObject(keys, val, options, valuesParsed); - }; - - var normalizeParseOptions = function normalizeParseOptions(opts) { - if (!opts) { - return defaults; - } - - if (opts.decoder !== null && opts.decoder !== undefined && typeof opts.decoder !== 'function') { - throw new TypeError('Decoder has to be a function.'); - } - - if (typeof opts.charset !== 'undefined' && opts.charset !== 'utf-8' && opts.charset !== 'iso-8859-1') { - throw new TypeError('The charset option must be either utf-8, iso-8859-1, or undefined'); - } - var charset = typeof opts.charset === 'undefined' ? defaults.charset : opts.charset; - - return { - allowDots: typeof opts.allowDots === 'undefined' ? defaults.allowDots : !!opts.allowDots, - allowPrototypes: typeof opts.allowPrototypes === 'boolean' ? opts.allowPrototypes : defaults.allowPrototypes, - allowSparse: typeof opts.allowSparse === 'boolean' ? opts.allowSparse : defaults.allowSparse, - arrayLimit: typeof opts.arrayLimit === 'number' ? opts.arrayLimit : defaults.arrayLimit, - charset: charset, - charsetSentinel: typeof opts.charsetSentinel === 'boolean' ? opts.charsetSentinel : defaults.charsetSentinel, - comma: typeof opts.comma === 'boolean' ? opts.comma : defaults.comma, - decoder: typeof opts.decoder === 'function' ? opts.decoder : defaults.decoder, - delimiter: typeof opts.delimiter === 'string' || utils$2.isRegExp(opts.delimiter) ? opts.delimiter : defaults.delimiter, - // eslint-disable-next-line no-implicit-coercion, no-extra-parens - depth: (typeof opts.depth === 'number' || opts.depth === false) ? +opts.depth : defaults.depth, - ignoreQueryPrefix: opts.ignoreQueryPrefix === true, - interpretNumericEntities: typeof opts.interpretNumericEntities === 'boolean' ? opts.interpretNumericEntities : defaults.interpretNumericEntities, - parameterLimit: typeof opts.parameterLimit === 'number' ? opts.parameterLimit : defaults.parameterLimit, - parseArrays: opts.parseArrays !== false, - plainObjects: typeof opts.plainObjects === 'boolean' ? opts.plainObjects : defaults.plainObjects, - strictNullHandling: typeof opts.strictNullHandling === 'boolean' ? opts.strictNullHandling : defaults.strictNullHandling - }; - }; - - var parse$1 = function (str, opts) { - var options = normalizeParseOptions(opts); - - if (str === '' || str === null || typeof str === 'undefined') { - return options.plainObjects ? Object.create(null) : {}; - } - - var tempObj = typeof str === 'string' ? parseValues(str, options) : str; - var obj = options.plainObjects ? Object.create(null) : {}; - - // Iterate over the keys and setup the new object - - var keys = Object.keys(tempObj); - for (var i = 0; i < keys.length; ++i) { - var key = keys[i]; - var newObj = parseKeys(key, tempObj[key], options, typeof str === 'string'); - obj = utils$2.merge(obj, newObj, options); - } - - if (options.allowSparse === true) { - return obj; - } - - return utils$2.compact(obj); - }; - - var stringify = stringify_1; - var parse = parse$1; - var formats = formats$3; - - var lib = { - formats: formats, - parse: parse, - stringify: stringify - }; - - var utils$1 = {}; - - (function (exports) { - - function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } - function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } - function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } - /** - * Return the mime type for the given `str`. - * - * @param {String} str - * @return {String} - * @api private - */ - - exports.type = string_ => string_.split(/ *; */).shift(); - - /** - * Return header field parameters. - * - * @param {String} str - * @return {Object} - * @api private - */ - - exports.params = value => { - const object = {}; - var _iterator = _createForOfIteratorHelper(value.split(/ *; */)), - _step; - try { - for (_iterator.s(); !(_step = _iterator.n()).done;) { - const string_ = _step.value; - const parts = string_.split(/ *= */); - const key = parts.shift(); - const value = parts.shift(); - if (key && value) object[key] = value; - } - } catch (err) { - _iterator.e(err); - } finally { - _iterator.f(); - } - return object; - }; - - /** - * Parse Link header fields. - * - * @param {String} str - * @return {Object} - * @api private - */ - - exports.parseLinks = value => { - const object = {}; - var _iterator2 = _createForOfIteratorHelper(value.split(/ *, */)), - _step2; - try { - for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { - const string_ = _step2.value; - const parts = string_.split(/ *; */); - const url = parts[0].slice(1, -1); - const rel = parts[1].split(/ *= */)[1].slice(1, -1); - object[rel] = url; - } - } catch (err) { - _iterator2.e(err); - } finally { - _iterator2.f(); - } - return object; - }; - - /** - * Strip content related fields from `header`. - * - * @param {Object} header - * @return {Object} header - * @api private - */ - - exports.cleanHeader = (header, changesOrigin) => { - delete header['content-type']; - delete header['content-length']; - delete header['transfer-encoding']; - delete header.host; - // secuirty - if (changesOrigin) { - delete header.authorization; - delete header.cookie; - } - return header; - }; - - /** - * Check if `obj` is an object. - * - * @param {Object} object - * @return {Boolean} - * @api private - */ - exports.isObject = object => { - return object !== null && typeof object === 'object'; - }; - - /** - * Object.hasOwn fallback/polyfill. - * - * @type {(object: object, property: string) => boolean} object - * @api private - */ - exports.hasOwn = Object.hasOwn || function (object, property) { - if (object == null) { - throw new TypeError('Cannot convert undefined or null to object'); - } - return Object.prototype.hasOwnProperty.call(new Object(object), property); - }; - exports.mixin = (target, source) => { - for (const key in source) { - if (exports.hasOwn(source, key)) { - target[key] = source[key]; - } - } - }; - - }(utils$1)); - - const semver = require$$0; - - /** - * Module of mixed-in functions shared between node and client code - */ - const _require = utils$1, - isObject = _require.isObject, - hasOwn = _require.hasOwn; - - /** - * Expose `RequestBase`. - */ - - var requestBase = RequestBase; - - /** - * Initialize a new `RequestBase`. - * - * @api public - */ - - function RequestBase() {} - - /** - * Clear previous timeout. - * - * @return {Request} for chaining - * @api public - */ - - RequestBase.prototype.clearTimeout = function () { - clearTimeout(this._timer); - clearTimeout(this._responseTimeoutTimer); - clearTimeout(this._uploadTimeoutTimer); - delete this._timer; - delete this._responseTimeoutTimer; - delete this._uploadTimeoutTimer; - return this; - }; - - /** - * Override default response body parser - * - * This function will be called to convert incoming data into request.body - * - * @param {Function} - * @api public - */ - - RequestBase.prototype.parse = function (fn) { - this._parser = fn; - return this; - }; - - /** - * Set format of binary response body. - * In browser valid formats are 'blob' and 'arraybuffer', - * which return Blob and ArrayBuffer, respectively. - * - * In Node all values result in Buffer. - * - * Examples: - * - * req.get('/') - * .responseType('blob') - * .end(callback); - * - * @param {String} val - * @return {Request} for chaining - * @api public - */ - - RequestBase.prototype.responseType = function (value) { - this._responseType = value; - return this; - }; - - /** - * Override default request body serializer - * - * This function will be called to convert data set via .send or .attach into payload to send - * - * @param {Function} - * @api public - */ - - RequestBase.prototype.serialize = function (fn) { - this._serializer = fn; - return this; - }; - - /** - * Set timeouts. - * - * - response timeout is time between sending request and receiving the first byte of the response. Includes DNS and connection time. - * - deadline is the time from start of the request to receiving response body in full. If the deadline is too short large files may not load at all on slow connections. - * - upload is the time since last bit of data was sent or received. This timeout works only if deadline timeout is off - * - * Value of 0 or false means no timeout. - * - * @param {Number|Object} ms or {response, deadline} - * @return {Request} for chaining - * @api public - */ - - RequestBase.prototype.timeout = function (options) { - if (!options || typeof options !== 'object') { - this._timeout = options; - this._responseTimeout = 0; - this._uploadTimeout = 0; - return this; - } - for (const option in options) { - if (hasOwn(options, option)) { - switch (option) { - case 'deadline': - this._timeout = options.deadline; - break; - case 'response': - this._responseTimeout = options.response; - break; - case 'upload': - this._uploadTimeout = options.upload; - break; - default: - console.warn('Unknown timeout option', option); - } - } - } - return this; - }; - - /** - * Set number of retry attempts on error. - * - * Failed requests will be retried 'count' times if timeout or err.code >= 500. - * - * @param {Number} count - * @param {Function} [fn] - * @return {Request} for chaining - * @api public - */ - - RequestBase.prototype.retry = function (count, fn) { - // Default to 1 if no count passed or true - if (arguments.length === 0 || count === true) count = 1; - if (count <= 0) count = 0; - this._maxRetries = count; - this._retries = 0; - this._retryCallback = fn; - return this; - }; - - // - // NOTE: we do not include ESOCKETTIMEDOUT because that is from `request` package - // - // - // NOTE: we do not include EADDRINFO because it was removed from libuv in 2014 - // - // - // - // - // TODO: expose these as configurable defaults - // - const ERROR_CODES = new Set(['ETIMEDOUT', 'ECONNRESET', 'EADDRINUSE', 'ECONNREFUSED', 'EPIPE', 'ENOTFOUND', 'ENETUNREACH', 'EAI_AGAIN']); - const STATUS_CODES = new Set([408, 413, 429, 500, 502, 503, 504, 521, 522, 524]); - - // TODO: we would need to make this easily configurable before adding it in (e.g. some might want to add POST) - // const METHODS = new Set(['GET', 'PUT', 'HEAD', 'DELETE', 'OPTIONS', 'TRACE']); - - /** - * Determine if a request should be retried. - * (Inspired by https://github.com/sindresorhus/got#retry) - * - * @param {Error} err an error - * @param {Response} [res] response - * @returns {Boolean} if segment should be retried - */ - RequestBase.prototype._shouldRetry = function (error, res) { - if (!this._maxRetries || this._retries++ >= this._maxRetries) { - return false; - } - if (this._retryCallback) { - try { - const override = this._retryCallback(error, res); - if (override === true) return true; - if (override === false) return false; - // undefined falls back to defaults - } catch (err) { - console.error(err); - } - } - - // TODO: we would need to make this easily configurable before adding it in (e.g. some might want to add POST) - /* - if ( - this.req && - this.req.method && - !METHODS.has(this.req.method.toUpperCase()) - ) - return false; - */ - if (res && res.status && STATUS_CODES.has(res.status)) return true; - if (error) { - if (error.code && ERROR_CODES.has(error.code)) return true; - // Superagent timeout - if (error.timeout && error.code === 'ECONNABORTED') return true; - if (error.crossDomain) return true; - } - return false; - }; - - /** - * Retry request - * - * @return {Request} for chaining - * @api private - */ - - RequestBase.prototype._retry = function () { - this.clearTimeout(); - - // node - if (this.req) { - this.req = null; - this.req = this.request(); - } - this._aborted = false; - this.timedout = false; - this.timedoutError = null; - return this._end(); - }; - - /** - * Promise support - * - * @param {Function} resolve - * @param {Function} [reject] - * @return {Request} - */ - - RequestBase.prototype.then = function (resolve, reject) { - if (!this._fullfilledPromise) { - const self = this; - if (this._endCalled) { - console.warn('Warning: superagent request was sent twice, because both .end() and .then() were called. Never call .end() if you use promises'); - } - this._fullfilledPromise = new Promise((resolve, reject) => { - self.on('abort', () => { - if (this._maxRetries && this._maxRetries > this._retries) { - return; - } - if (this.timedout && this.timedoutError) { - reject(this.timedoutError); - return; - } - const error = new Error('Aborted'); - error.code = 'ABORTED'; - error.status = this.status; - error.method = this.method; - error.url = this.url; - reject(error); - }); - self.end((error, res) => { - if (error) reject(error);else resolve(res); - }); - }); - } - return this._fullfilledPromise.then(resolve, reject); - }; - RequestBase.prototype.catch = function (callback) { - return this.then(undefined, callback); - }; - - /** - * Allow for extension - */ - - RequestBase.prototype.use = function (fn) { - fn(this); - return this; - }; - RequestBase.prototype.ok = function (callback) { - if (typeof callback !== 'function') throw new Error('Callback required'); - this._okCallback = callback; - return this; - }; - RequestBase.prototype._isResponseOK = function (res) { - if (!res) { - return false; - } - if (this._okCallback) { - return this._okCallback(res); - } - return res.status >= 200 && res.status < 300; - }; - - /** - * Get request header `field`. - * Case-insensitive. - * - * @param {String} field - * @return {String} - * @api public - */ - - RequestBase.prototype.get = function (field) { - return this._header[field.toLowerCase()]; - }; - - /** - * Get case-insensitive header `field` value. - * This is a deprecated internal API. Use `.get(field)` instead. - * - * (getHeader is no longer used internally by the superagent code base) - * - * @param {String} field - * @return {String} - * @api private - * @deprecated - */ - - RequestBase.prototype.getHeader = RequestBase.prototype.get; - - /** - * Set header `field` to `val`, or multiple fields with one object. - * Case-insensitive. - * - * Examples: - * - * req.get('/') - * .set('Accept', 'application/json') - * .set('X-API-Key', 'foobar') - * .end(callback); - * - * req.get('/') - * .set({ Accept: 'application/json', 'X-API-Key': 'foobar' }) - * .end(callback); - * - * @param {String|Object} field - * @param {String} val - * @return {Request} for chaining - * @api public - */ - - RequestBase.prototype.set = function (field, value) { - if (isObject(field)) { - for (const key in field) { - if (hasOwn(field, key)) this.set(key, field[key]); - } - return this; - } - this._header[field.toLowerCase()] = value; - this.header[field] = value; - return this; - }; - - /** - * Remove header `field`. - * Case-insensitive. - * - * Example: - * - * req.get('/') - * .unset('User-Agent') - * .end(callback); - * - * @param {String} field field name - */ - RequestBase.prototype.unset = function (field) { - delete this._header[field.toLowerCase()]; - delete this.header[field]; - return this; - }; - - /** - * Write the field `name` and `val`, or multiple fields with one object - * for "multipart/form-data" request bodies. - * - * ``` js - * request.post('/upload') - * .field('foo', 'bar') - * .end(callback); - * - * request.post('/upload') - * .field({ foo: 'bar', baz: 'qux' }) - * .end(callback); - * ``` - * - * @param {String|Object} name name of field - * @param {String|Blob|File|Buffer|fs.ReadStream} val value of field - * @param {String} options extra options, e.g. 'blob' - * @return {Request} for chaining - * @api public - */ - RequestBase.prototype.field = function (name, value, options) { - // name should be either a string or an object. - if (name === null || undefined === name) { - throw new Error('.field(name, val) name can not be empty'); - } - if (this._data) { - throw new Error(".field() can't be used if .send() is used. Please use only .send() or only .field() & .attach()"); - } - if (isObject(name)) { - for (const key in name) { - if (hasOwn(name, key)) this.field(key, name[key]); - } - return this; - } - if (Array.isArray(value)) { - for (const i in value) { - if (hasOwn(value, i)) this.field(name, value[i]); - } - return this; - } - - // val should be defined now - if (value === null || undefined === value) { - throw new Error('.field(name, val) val can not be empty'); - } - if (typeof value === 'boolean') { - value = String(value); - } - - // fix https://github.com/ladjs/superagent/issues/1680 - if (options) this._getFormData().append(name, value, options);else this._getFormData().append(name, value); - return this; - }; - - /** - * Abort the request, and clear potential timeout. - * - * @return {Request} request - * @api public - */ - RequestBase.prototype.abort = function () { - if (this._aborted) { - return this; - } - this._aborted = true; - if (this.xhr) this.xhr.abort(); // browser - if (this.req) { - // Node v13 has major differences in `abort()` - // https://github.com/nodejs/node/blob/v12.x/lib/internal/streams/end-of-stream.js - // https://github.com/nodejs/node/blob/v13.x/lib/internal/streams/end-of-stream.js - // https://github.com/nodejs/node/blob/v14.x/lib/internal/streams/end-of-stream.js - // (if you run a diff across these you will see the differences) - // - // References: - // - // - // - // Thanks to @shadowgate15 and @niftylettuce - if (semver.gte(process.version, 'v13.0.0') && semver.lt(process.version, 'v14.0.0')) { - // Note that the reason this doesn't work is because in v13 as compared to v14 - // there is no `callback = nop` set in end-of-stream.js above - throw new Error('Superagent does not work in v13 properly with abort() due to Node.js core changes'); - } - this.req.abort(); // node - } - - this.clearTimeout(); - this.emit('abort'); - return this; - }; - RequestBase.prototype._auth = function (user, pass, options, base64Encoder) { - switch (options.type) { - case 'basic': - this.set('Authorization', `Basic ${base64Encoder(`${user}:${pass}`)}`); - break; - case 'auto': - this.username = user; - this.password = pass; - break; - case 'bearer': - // usage would be .auth(accessToken, { type: 'bearer' }) - this.set('Authorization', `Bearer ${user}`); - break; - } - return this; - }; - - /** - * Enable transmission of cookies with x-domain requests. - * - * Note that for this to work the origin must not be - * using "Access-Control-Allow-Origin" with a wildcard, - * and also must set "Access-Control-Allow-Credentials" - * to "true". - * @param {Boolean} [on=true] - Set 'withCredentials' state - * @return {Request} for chaining - * @api public - */ - - RequestBase.prototype.withCredentials = function (on) { - // This is browser-only functionality. Node side is no-op. - if (on === undefined) on = true; - this._withCredentials = on; - return this; - }; - - /** - * Set the max redirects to `n`. Does nothing in browser XHR implementation. - * - * @param {Number} n - * @return {Request} for chaining - * @api public - */ - - RequestBase.prototype.redirects = function (n) { - this._maxRedirects = n; - return this; - }; - - /** - * Maximum size of buffered response body, in bytes. Counts uncompressed size. - * Default 200MB. - * - * @param {Number} n number of bytes - * @return {Request} for chaining - */ - RequestBase.prototype.maxResponseSize = function (n) { - if (typeof n !== 'number') { - throw new TypeError('Invalid argument'); - } - this._maxResponseSize = n; - return this; - }; - - /** - * Convert to a plain javascript object (not JSON string) of scalar properties. - * Note as this method is designed to return a useful non-this value, - * it cannot be chained. - * - * @return {Object} describing method, url, and data of this request - * @api public - */ - - RequestBase.prototype.toJSON = function () { - return { - method: this.method, - url: this.url, - data: this._data, - headers: this._header - }; - }; - - /** - * Send `data` as the request body, defaulting the `.type()` to "json" when - * an object is given. - * - * Examples: - * - * // manual json - * request.post('/user') - * .type('json') - * .send('{"name":"tj"}') - * .end(callback) - * - * // auto json - * request.post('/user') - * .send({ name: 'tj' }) - * .end(callback) - * - * // manual x-www-form-urlencoded - * request.post('/user') - * .type('form') - * .send('name=tj') - * .end(callback) - * - * // auto x-www-form-urlencoded - * request.post('/user') - * .type('form') - * .send({ name: 'tj' }) - * .end(callback) - * - * // defaults to x-www-form-urlencoded - * request.post('/user') - * .send('name=tobi') - * .send('species=ferret') - * .end(callback) - * - * @param {String|Object} data - * @return {Request} for chaining - * @api public - */ - - // eslint-disable-next-line complexity - RequestBase.prototype.send = function (data) { - const isObject_ = isObject(data); - let type = this._header['content-type']; - if (this._formData) { - throw new Error(".send() can't be used if .attach() or .field() is used. Please use only .send() or only .field() & .attach()"); - } - if (isObject_ && !this._data) { - if (Array.isArray(data)) { - this._data = []; - } else if (!this._isHost(data)) { - this._data = {}; - } - } else if (data && this._data && this._isHost(this._data)) { - throw new Error("Can't merge these send calls"); - } - - // merge - if (isObject_ && isObject(this._data)) { - for (const key in data) { - if (typeof data[key] == 'bigint' && !data[key].toJSON) throw new Error('Cannot serialize BigInt value to json'); - if (hasOwn(data, key)) this._data[key] = data[key]; - } - } else if (typeof data === 'bigint') throw new Error("Cannot send value of type BigInt");else if (typeof data === 'string') { - // default to x-www-form-urlencoded - if (!type) this.type('form'); - type = this._header['content-type']; - if (type) type = type.toLowerCase().trim(); - if (type === 'application/x-www-form-urlencoded') { - this._data = this._data ? `${this._data}&${data}` : data; - } else { - this._data = (this._data || '') + data; - } - } else { - this._data = data; - } - if (!isObject_ || this._isHost(data)) { - return this; - } - - // default to json - if (!type) this.type('json'); - return this; - }; - - /** - * Sort `querystring` by the sort function - * - * - * Examples: - * - * // default order - * request.get('/user') - * .query('name=Nick') - * .query('search=Manny') - * .sortQuery() - * .end(callback) - * - * // customized sort function - * request.get('/user') - * .query('name=Nick') - * .query('search=Manny') - * .sortQuery(function(a, b){ - * return a.length - b.length; - * }) - * .end(callback) - * - * - * @param {Function} sort - * @return {Request} for chaining - * @api public - */ - - RequestBase.prototype.sortQuery = function (sort) { - // _sort default to true but otherwise can be a function or boolean - this._sort = typeof sort === 'undefined' ? true : sort; - return this; - }; - - /** - * Compose querystring to append to req.url - * - * @api private - */ - RequestBase.prototype._finalizeQueryString = function () { - const query = this._query.join('&'); - if (query) { - this.url += (this.url.includes('?') ? '&' : '?') + query; - } - this._query.length = 0; // Makes the call idempotent - - if (this._sort) { - const index = this.url.indexOf('?'); - if (index >= 0) { - const queryArray = this.url.slice(index + 1).split('&'); - if (typeof this._sort === 'function') { - queryArray.sort(this._sort); - } else { - queryArray.sort(); - } - this.url = this.url.slice(0, index) + '?' + queryArray.join('&'); - } - } - }; - - // For backwards compat only - RequestBase.prototype._appendQueryString = () => { - console.warn('Unsupported'); - }; - - /** - * Invoke callback with timeout error. - * - * @api private - */ - - RequestBase.prototype._timeoutError = function (reason, timeout, errno) { - if (this._aborted) { - return; - } - const error = new Error(`${reason + timeout}ms exceeded`); - error.timeout = timeout; - error.code = 'ECONNABORTED'; - error.errno = errno; - this.timedout = true; - this.timedoutError = error; - this.abort(); - this.callback(error); - }; - RequestBase.prototype._setTimeouts = function () { - const self = this; - - // deadline - if (this._timeout && !this._timer) { - this._timer = setTimeout(() => { - self._timeoutError('Timeout of ', self._timeout, 'ETIME'); - }, this._timeout); - } - - // response timeout - if (this._responseTimeout && !this._responseTimeoutTimer) { - this._responseTimeoutTimer = setTimeout(() => { - self._timeoutError('Response timeout of ', self._responseTimeout, 'ETIMEDOUT'); - }, this._responseTimeout); - } - }; - - /** - * Module dependencies. - */ - - const utils = utils$1; - - /** - * Expose `ResponseBase`. - */ - - var responseBase = ResponseBase; - - /** - * Initialize a new `ResponseBase`. - * - * @api public - */ - - function ResponseBase() {} - - /** - * Get case-insensitive `field` value. - * - * @param {String} field - * @return {String} - * @api public - */ - - ResponseBase.prototype.get = function (field) { - return this.header[field.toLowerCase()]; - }; - - /** - * Set header related properties: - * - * - `.type` the content type without params - * - * A response of "Content-Type: text/plain; charset=utf-8" - * will provide you with a `.type` of "text/plain". - * - * @param {Object} header - * @api private - */ - - ResponseBase.prototype._setHeaderProperties = function (header) { - // TODO: moar! - // TODO: make this a util - - // content-type - const ct = header['content-type'] || ''; - this.type = utils.type(ct); - - // params - const parameters = utils.params(ct); - for (const key in parameters) { - if (Object.prototype.hasOwnProperty.call(parameters, key)) this[key] = parameters[key]; - } - this.links = {}; - - // links - try { - if (header.link) { - this.links = utils.parseLinks(header.link); - } - } catch (err) { - // ignore - } - }; - - /** - * Set flags such as `.ok` based on `status`. - * - * For example a 2xx response will give you a `.ok` of __true__ - * whereas 5xx will be __false__ and `.error` will be __true__. The - * `.clientError` and `.serverError` are also available to be more - * specific, and `.statusType` is the class of error ranging from 1..5 - * sometimes useful for mapping respond colors etc. - * - * "sugar" properties are also defined for common cases. Currently providing: - * - * - .noContent - * - .badRequest - * - .unauthorized - * - .notAcceptable - * - .notFound - * - * @param {Number} status - * @api private - */ - - ResponseBase.prototype._setStatusProperties = function (status) { - const type = Math.trunc(status / 100); - - // status / class - this.statusCode = status; - this.status = this.statusCode; - this.statusType = type; - - // basics - this.info = type === 1; - this.ok = type === 2; - this.redirect = type === 3; - this.clientError = type === 4; - this.serverError = type === 5; - this.error = type === 4 || type === 5 ? this.toError() : false; - - // sugar - this.created = status === 201; - this.accepted = status === 202; - this.noContent = status === 204; - this.badRequest = status === 400; - this.unauthorized = status === 401; - this.notAcceptable = status === 406; - this.forbidden = status === 403; - this.notFound = status === 404; - this.unprocessableEntity = status === 422; - }; - - function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } - function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } - function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } - function Agent() { - this._defaults = []; - } - for (var _i = 0, _arr = ['use', 'on', 'once', 'set', 'query', 'type', 'accept', 'auth', 'withCredentials', 'sortQuery', 'retry', 'ok', 'redirects', 'timeout', 'buffer', 'serialize', 'parse', 'ca', 'key', 'pfx', 'cert', 'disableTLSCerts']; _i < _arr.length; _i++) { - const fn = _arr[_i]; - // Default setting for all requests from this agent - Agent.prototype[fn] = function () { - for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; - } - this._defaults.push({ - fn, - args - }); - return this; - }; - } - Agent.prototype._setDefaults = function (request) { - var _iterator = _createForOfIteratorHelper(this._defaults), - _step; - try { - for (_iterator.s(); !(_step = _iterator.n()).done;) { - const def = _step.value; - request[def.fn](...def.args); - } - } catch (err) { - _iterator.e(err); - } finally { - _iterator.f(); - } - }; - var agentBase = Agent; - - (function (module, exports) { - - function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } - function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } - function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } - /** - * Root reference for iframes. - */ - - let root; - if (typeof window !== 'undefined') { - // Browser window - root = window; - } else if (typeof self === 'undefined') { - // Other environments - console.warn('Using browser-only version of superagent in non-browser environment'); - root = void 0; - } else { - // Web Worker - root = self; - } - const Emitter = componentEmitter.exports; - const safeStringify = fastSafeStringify; - const qs = lib; - const RequestBase = requestBase; - const _require = utils$1, - isObject = _require.isObject, - mixin = _require.mixin, - hasOwn = _require.hasOwn; - const ResponseBase = responseBase; - const Agent = agentBase; - - /** - * Noop. - */ - - function noop() {} - - /** - * Expose `request`. - */ - - module.exports = function (method, url) { - // callback - if (typeof url === 'function') { - return new exports.Request('GET', method).end(url); - } - - // url first - if (arguments.length === 1) { - return new exports.Request('GET', method); - } - return new exports.Request(method, url); - }; - exports = module.exports; - const request = exports; - exports.Request = Request; - - /** - * Determine XHR. - */ - - request.getXHR = () => { - if (root.XMLHttpRequest) { - return new root.XMLHttpRequest(); - } - throw new Error('Browser-only version of superagent could not find XHR'); - }; - - /** - * Removes leading and trailing whitespace, added to support IE. - * - * @param {String} s - * @return {String} - * @api private - */ - - const trim = ''.trim ? s => s.trim() : s => s.replace(/(^\s*|\s*$)/g, ''); - - /** - * Serialize the given `obj`. - * - * @param {Object} obj - * @return {String} - * @api private - */ - - function serialize(object) { - if (!isObject(object)) return object; - const pairs = []; - for (const key in object) { - if (hasOwn(object, key)) pushEncodedKeyValuePair(pairs, key, object[key]); - } - return pairs.join('&'); - } - - /** - * Helps 'serialize' with serializing arrays. - * Mutates the pairs array. - * - * @param {Array} pairs - * @param {String} key - * @param {Mixed} val - */ - - function pushEncodedKeyValuePair(pairs, key, value) { - if (value === undefined) return; - if (value === null) { - pairs.push(encodeURI(key)); - return; - } - if (Array.isArray(value)) { - var _iterator = _createForOfIteratorHelper(value), - _step; - try { - for (_iterator.s(); !(_step = _iterator.n()).done;) { - const v = _step.value; - pushEncodedKeyValuePair(pairs, key, v); - } - } catch (err) { - _iterator.e(err); - } finally { - _iterator.f(); - } - } else if (isObject(value)) { - for (const subkey in value) { - if (hasOwn(value, subkey)) pushEncodedKeyValuePair(pairs, `${key}[${subkey}]`, value[subkey]); - } - } else { - pairs.push(encodeURI(key) + '=' + encodeURIComponent(value)); - } - } - - /** - * Expose serialization method. - */ - - request.serializeObject = serialize; - - /** - * Parse the given x-www-form-urlencoded `str`. - * - * @param {String} str - * @return {Object} - * @api private - */ - - function parseString(string_) { - const object = {}; - const pairs = string_.split('&'); - let pair; - let pos; - for (let i = 0, length_ = pairs.length; i < length_; ++i) { - pair = pairs[i]; - pos = pair.indexOf('='); - if (pos === -1) { - object[decodeURIComponent(pair)] = ''; - } else { - object[decodeURIComponent(pair.slice(0, pos))] = decodeURIComponent(pair.slice(pos + 1)); - } - } - return object; - } - - /** - * Expose parser. - */ - - request.parseString = parseString; - - /** - * Default MIME type map. - * - * superagent.types.xml = 'application/xml'; - * - */ - - request.types = { - html: 'text/html', - json: 'application/json', - xml: 'text/xml', - urlencoded: 'application/x-www-form-urlencoded', - form: 'application/x-www-form-urlencoded', - 'form-data': 'application/x-www-form-urlencoded' - }; - - /** - * Default serialization map. - * - * superagent.serialize['application/xml'] = function(obj){ - * return 'generated xml here'; - * }; - * - */ - - request.serialize = { - 'application/x-www-form-urlencoded': qs.stringify, - 'application/json': safeStringify - }; - - /** - * Default parsers. - * - * superagent.parse['application/xml'] = function(str){ - * return { object parsed from str }; - * }; - * - */ - - request.parse = { - 'application/x-www-form-urlencoded': parseString, - 'application/json': JSON.parse - }; - - /** - * Parse the given header `str` into - * an object containing the mapped fields. - * - * @param {String} str - * @return {Object} - * @api private - */ - - function parseHeader(string_) { - const lines = string_.split(/\r?\n/); - const fields = {}; - let index; - let line; - let field; - let value; - for (let i = 0, length_ = lines.length; i < length_; ++i) { - line = lines[i]; - index = line.indexOf(':'); - if (index === -1) { - // could be empty line, just skip it - continue; - } - field = line.slice(0, index).toLowerCase(); - value = trim(line.slice(index + 1)); - fields[field] = value; - } - return fields; - } - - /** - * Check if `mime` is json or has +json structured syntax suffix. - * - * @param {String} mime - * @return {Boolean} - * @api private - */ - - function isJSON(mime) { - // should match /json or +json - // but not /json-seq - return /[/+]json($|[^-\w])/i.test(mime); - } - - /** - * Initialize a new `Response` with the given `xhr`. - * - * - set flags (.ok, .error, etc) - * - parse header - * - * Examples: - * - * Aliasing `superagent` as `request` is nice: - * - * request = superagent; - * - * We can use the promise-like API, or pass callbacks: - * - * request.get('/').end(function(res){}); - * request.get('/', function(res){}); - * - * Sending data can be chained: - * - * request - * .post('/user') - * .send({ name: 'tj' }) - * .end(function(res){}); - * - * Or passed to `.send()`: - * - * request - * .post('/user') - * .send({ name: 'tj' }, function(res){}); - * - * Or passed to `.post()`: - * - * request - * .post('/user', { name: 'tj' }) - * .end(function(res){}); - * - * Or further reduced to a single call for simple cases: - * - * request - * .post('/user', { name: 'tj' }, function(res){}); - * - * @param {XMLHTTPRequest} xhr - * @param {Object} options - * @api private - */ - - function Response(request_) { - this.req = request_; - this.xhr = this.req.xhr; - // responseText is accessible only if responseType is '' or 'text' and on older browsers - this.text = this.req.method !== 'HEAD' && (this.xhr.responseType === '' || this.xhr.responseType === 'text') || typeof this.xhr.responseType === 'undefined' ? this.xhr.responseText : null; - this.statusText = this.req.xhr.statusText; - let status = this.xhr.status; - // handle IE9 bug: http://stackoverflow.com/questions/10046972/msie-returns-status-code-of-1223-for-ajax-request - if (status === 1223) { - status = 204; - } - this._setStatusProperties(status); - this.headers = parseHeader(this.xhr.getAllResponseHeaders()); - this.header = this.headers; - // getAllResponseHeaders sometimes falsely returns "" for CORS requests, but - // getResponseHeader still works. so we get content-type even if getting - // other headers fails. - this.header['content-type'] = this.xhr.getResponseHeader('content-type'); - this._setHeaderProperties(this.header); - if (this.text === null && request_._responseType) { - this.body = this.xhr.response; - } else { - this.body = this.req.method === 'HEAD' ? null : this._parseBody(this.text ? this.text : this.xhr.response); - } - } - mixin(Response.prototype, ResponseBase.prototype); - - /** - * Parse the given body `str`. - * - * Used for auto-parsing of bodies. Parsers - * are defined on the `superagent.parse` object. - * - * @param {String} str - * @return {Mixed} - * @api private - */ - - Response.prototype._parseBody = function (string_) { - let parse = request.parse[this.type]; - if (this.req._parser) { - return this.req._parser(this, string_); - } - if (!parse && isJSON(this.type)) { - parse = request.parse['application/json']; - } - return parse && string_ && (string_.length > 0 || string_ instanceof Object) ? parse(string_) : null; - }; - - /** - * Return an `Error` representative of this response. - * - * @return {Error} - * @api public - */ - - Response.prototype.toError = function () { - const req = this.req; - const method = req.method; - const url = req.url; - const message = `cannot ${method} ${url} (${this.status})`; - const error = new Error(message); - error.status = this.status; - error.method = method; - error.url = url; - return error; - }; - - /** - * Expose `Response`. - */ - - request.Response = Response; - - /** - * Initialize a new `Request` with the given `method` and `url`. - * - * @param {String} method - * @param {String} url - * @api public - */ - - function Request(method, url) { - const self = this; - this._query = this._query || []; - this.method = method; - this.url = url; - this.header = {}; // preserves header name case - this._header = {}; // coerces header names to lowercase - this.on('end', () => { - let error = null; - let res = null; - try { - res = new Response(self); - } catch (err) { - error = new Error('Parser is unable to parse the response'); - error.parse = true; - error.original = err; - // issue #675: return the raw response if the response parsing fails - if (self.xhr) { - // ie9 doesn't have 'response' property - error.rawResponse = typeof self.xhr.responseType === 'undefined' ? self.xhr.responseText : self.xhr.response; - // issue #876: return the http status code if the response parsing fails - error.status = self.xhr.status ? self.xhr.status : null; - error.statusCode = error.status; // backwards-compat only - } else { - error.rawResponse = null; - error.status = null; - } - return self.callback(error); - } - self.emit('response', res); - let new_error; - try { - if (!self._isResponseOK(res)) { - new_error = new Error(res.statusText || res.text || 'Unsuccessful HTTP response'); - } - } catch (err) { - new_error = err; // ok() callback can throw - } - - // #1000 don't catch errors from the callback to avoid double calling it - if (new_error) { - new_error.original = error; - new_error.response = res; - new_error.status = new_error.status || res.status; - self.callback(new_error, res); - } else { - self.callback(null, res); - } - }); - } - - /** - * Mixin `Emitter` and `RequestBase`. - */ - - // eslint-disable-next-line new-cap - Emitter(Request.prototype); - mixin(Request.prototype, RequestBase.prototype); - - /** - * Set Content-Type to `type`, mapping values from `request.types`. - * - * Examples: - * - * superagent.types.xml = 'application/xml'; - * - * request.post('/') - * .type('xml') - * .send(xmlstring) - * .end(callback); - * - * request.post('/') - * .type('application/xml') - * .send(xmlstring) - * .end(callback); - * - * @param {String} type - * @return {Request} for chaining - * @api public - */ - - Request.prototype.type = function (type) { - this.set('Content-Type', request.types[type] || type); - return this; - }; - - /** - * Set Accept to `type`, mapping values from `request.types`. - * - * Examples: - * - * superagent.types.json = 'application/json'; - * - * request.get('/agent') - * .accept('json') - * .end(callback); - * - * request.get('/agent') - * .accept('application/json') - * .end(callback); - * - * @param {String} accept - * @return {Request} for chaining - * @api public - */ - - Request.prototype.accept = function (type) { - this.set('Accept', request.types[type] || type); - return this; - }; - - /** - * Set Authorization field value with `user` and `pass`. - * - * @param {String} user - * @param {String} [pass] optional in case of using 'bearer' as type - * @param {Object} options with 'type' property 'auto', 'basic' or 'bearer' (default 'basic') - * @return {Request} for chaining - * @api public - */ - - Request.prototype.auth = function (user, pass, options) { - if (arguments.length === 1) pass = ''; - if (typeof pass === 'object' && pass !== null) { - // pass is optional and can be replaced with options - options = pass; - pass = ''; - } - if (!options) { - options = { - type: typeof btoa === 'function' ? 'basic' : 'auto' - }; - } - const encoder = options.encoder ? options.encoder : string => { - if (typeof btoa === 'function') { - return btoa(string); - } - throw new Error('Cannot use basic auth, btoa is not a function'); - }; - return this._auth(user, pass, options, encoder); - }; - - /** - * Add query-string `val`. - * - * Examples: - * - * request.get('/shoes') - * .query('size=10') - * .query({ color: 'blue' }) - * - * @param {Object|String} val - * @return {Request} for chaining - * @api public - */ - - Request.prototype.query = function (value) { - if (typeof value !== 'string') value = serialize(value); - if (value) this._query.push(value); - return this; - }; - - /** - * Queue the given `file` as an attachment to the specified `field`, - * with optional `options` (or filename). - * - * ``` js - * request.post('/upload') - * .attach('content', new Blob(['hey!'], { type: "text/html"})) - * .end(callback); - * ``` - * - * @param {String} field - * @param {Blob|File} file - * @param {String|Object} options - * @return {Request} for chaining - * @api public - */ - - Request.prototype.attach = function (field, file, options) { - if (file) { - if (this._data) { - throw new Error("superagent can't mix .send() and .attach()"); - } - this._getFormData().append(field, file, options || file.name); - } - return this; - }; - Request.prototype._getFormData = function () { - if (!this._formData) { - this._formData = new root.FormData(); - } - return this._formData; - }; - - /** - * Invoke the callback with `err` and `res` - * and handle arity check. - * - * @param {Error} err - * @param {Response} res - * @api private - */ - - Request.prototype.callback = function (error, res) { - if (this._shouldRetry(error, res)) { - return this._retry(); - } - const fn = this._callback; - this.clearTimeout(); - if (error) { - if (this._maxRetries) error.retries = this._retries - 1; - this.emit('error', error); - } - fn(error, res); - }; - - /** - * Invoke callback with x-domain error. - * - * @api private - */ - - Request.prototype.crossDomainError = function () { - const error = new Error('Request has been terminated\nPossible causes: the network is offline, Origin is not allowed by Access-Control-Allow-Origin, the page is being unloaded, etc.'); - error.crossDomain = true; - error.status = this.status; - error.method = this.method; - error.url = this.url; - this.callback(error); - }; - - // This only warns, because the request is still likely to work - Request.prototype.agent = function () { - console.warn('This is not supported in browser version of superagent'); - return this; - }; - Request.prototype.ca = Request.prototype.agent; - Request.prototype.buffer = Request.prototype.ca; - - // This throws, because it can't send/receive data as expected - Request.prototype.write = () => { - throw new Error('Streaming is not supported in browser version of superagent'); - }; - Request.prototype.pipe = Request.prototype.write; - - /** - * Check if `obj` is a host object, - * we don't want to serialize these :) - * - * @param {Object} obj host object - * @return {Boolean} is a host object - * @api private - */ - Request.prototype._isHost = function (object) { - // Native objects stringify to [object File], [object Blob], [object FormData], etc. - return object && typeof object === 'object' && !Array.isArray(object) && Object.prototype.toString.call(object) !== '[object Object]'; - }; - - /** - * Initiate request, invoking callback `fn(res)` - * with an instanceof `Response`. - * - * @param {Function} fn - * @return {Request} for chaining - * @api public - */ - - Request.prototype.end = function (fn) { - if (this._endCalled) { - console.warn('Warning: .end() was called twice. This is not supported in superagent'); - } - this._endCalled = true; - - // store callback - this._callback = fn || noop; - - // querystring - this._finalizeQueryString(); - this._end(); - }; - Request.prototype._setUploadTimeout = function () { - const self = this; - - // upload timeout it's wokrs only if deadline timeout is off - if (this._uploadTimeout && !this._uploadTimeoutTimer) { - this._uploadTimeoutTimer = setTimeout(() => { - self._timeoutError('Upload timeout of ', self._uploadTimeout, 'ETIMEDOUT'); - }, this._uploadTimeout); - } - }; - - // eslint-disable-next-line complexity - Request.prototype._end = function () { - if (this._aborted) return this.callback(new Error('The request has been aborted even before .end() was called')); - const self = this; - this.xhr = request.getXHR(); - const xhr = this.xhr; - let data = this._formData || this._data; - this._setTimeouts(); - - // state change - xhr.addEventListener('readystatechange', () => { - const readyState = xhr.readyState; - if (readyState >= 2 && self._responseTimeoutTimer) { - clearTimeout(self._responseTimeoutTimer); - } - if (readyState !== 4) { - return; - } - - // In IE9, reads to any property (e.g. status) off of an aborted XHR will - // result in the error "Could not complete the operation due to error c00c023f" - let status; - try { - status = xhr.status; - } catch (err) { - status = 0; - } - if (!status) { - if (self.timedout || self._aborted) return; - return self.crossDomainError(); - } - self.emit('end'); - }); - - // progress - const handleProgress = (direction, e) => { - if (e.total > 0) { - e.percent = e.loaded / e.total * 100; - if (e.percent === 100) { - clearTimeout(self._uploadTimeoutTimer); - } - } - e.direction = direction; - self.emit('progress', e); - }; - if (this.hasListeners('progress')) { - try { - xhr.addEventListener('progress', handleProgress.bind(null, 'download')); - if (xhr.upload) { - xhr.upload.addEventListener('progress', handleProgress.bind(null, 'upload')); - } - } catch (err) { - // Accessing xhr.upload fails in IE from a web worker, so just pretend it doesn't exist. - // Reported here: - // https://connect.microsoft.com/IE/feedback/details/837245/xmlhttprequest-upload-throws-invalid-argument-when-used-from-web-worker-context - } - } - if (xhr.upload) { - this._setUploadTimeout(); - } - - // initiate request - try { - if (this.username && this.password) { - xhr.open(this.method, this.url, true, this.username, this.password); - } else { - xhr.open(this.method, this.url, true); - } - } catch (err) { - // see #1149 - return this.callback(err); - } - - // CORS - if (this._withCredentials) xhr.withCredentials = true; - - // body - if (!this._formData && this.method !== 'GET' && this.method !== 'HEAD' && typeof data !== 'string' && !this._isHost(data)) { - // serialize stuff - const contentType = this._header['content-type']; - let serialize = this._serializer || request.serialize[contentType ? contentType.split(';')[0] : '']; - if (!serialize && isJSON(contentType)) { - serialize = request.serialize['application/json']; - } - if (serialize) data = serialize(data); - } - - // set header fields - for (const field in this.header) { - if (this.header[field] === null) continue; - if (hasOwn(this.header, field)) xhr.setRequestHeader(field, this.header[field]); - } - if (this._responseType) { - xhr.responseType = this._responseType; - } - - // send stuff - this.emit('request', this); - - // IE11 xhr.send(undefined) sends 'undefined' string as POST payload (instead of nothing) - // We need null here if data is undefined - xhr.send(typeof data === 'undefined' ? null : data); - }; - request.agent = () => new Agent(); - for (var _i = 0, _arr = ['GET', 'POST', 'OPTIONS', 'PATCH', 'PUT', 'DELETE']; _i < _arr.length; _i++) { - const method = _arr[_i]; - Agent.prototype[method.toLowerCase()] = function (url, fn) { - const request_ = new request.Request(method, url); - this._setDefaults(request_); - if (fn) { - request_.end(fn); - } - return request_; - }; - } - Agent.prototype.del = Agent.prototype.delete; - - /** - * GET `url` with optional callback `fn(res)`. - * - * @param {String} url - * @param {Mixed|Function} [data] or fn - * @param {Function} [fn] - * @return {Request} - * @api public - */ - - request.get = (url, data, fn) => { - const request_ = request('GET', url); - if (typeof data === 'function') { - fn = data; - data = null; - } - if (data) request_.query(data); - if (fn) request_.end(fn); - return request_; - }; - - /** - * HEAD `url` with optional callback `fn(res)`. - * - * @param {String} url - * @param {Mixed|Function} [data] or fn - * @param {Function} [fn] - * @return {Request} - * @api public - */ - - request.head = (url, data, fn) => { - const request_ = request('HEAD', url); - if (typeof data === 'function') { - fn = data; - data = null; - } - if (data) request_.query(data); - if (fn) request_.end(fn); - return request_; - }; - - /** - * OPTIONS query to `url` with optional callback `fn(res)`. - * - * @param {String} url - * @param {Mixed|Function} [data] or fn - * @param {Function} [fn] - * @return {Request} - * @api public - */ - - request.options = (url, data, fn) => { - const request_ = request('OPTIONS', url); - if (typeof data === 'function') { - fn = data; - data = null; - } - if (data) request_.send(data); - if (fn) request_.end(fn); - return request_; - }; - - /** - * DELETE `url` with optional `data` and callback `fn(res)`. - * - * @param {String} url - * @param {Mixed} [data] - * @param {Function} [fn] - * @return {Request} - * @api public - */ - - function del(url, data, fn) { - const request_ = request('DELETE', url); - if (typeof data === 'function') { - fn = data; - data = null; - } - if (data) request_.send(data); - if (fn) request_.end(fn); - return request_; - } - request.del = del; - request.delete = del; - - /** - * PATCH `url` with optional `data` and callback `fn(res)`. - * - * @param {String} url - * @param {Mixed} [data] - * @param {Function} [fn] - * @return {Request} - * @api public - */ - - request.patch = (url, data, fn) => { - const request_ = request('PATCH', url); - if (typeof data === 'function') { - fn = data; - data = null; - } - if (data) request_.send(data); - if (fn) request_.end(fn); - return request_; - }; - - /** - * POST `url` with optional `data` and callback `fn(res)`. - * - * @param {String} url - * @param {Mixed} [data] - * @param {Function} [fn] - * @return {Request} - * @api public - */ - - request.post = (url, data, fn) => { - const request_ = request('POST', url); - if (typeof data === 'function') { - fn = data; - data = null; - } - if (data) request_.send(data); - if (fn) request_.end(fn); - return request_; - }; - - /** - * PUT `url` with optional `data` and callback `fn(res)`. - * - * @param {String} url - * @param {Mixed|Function} [data] or fn - * @param {Function} [fn] - * @return {Request} - * @api public - */ - - request.put = (url, data, fn) => { - const request_ = request('PUT', url); - if (typeof data === 'function') { - fn = data; - data = null; - } - if (data) request_.send(data); - if (fn) request_.end(fn); - return request_; - }; - - }(client, client.exports)); - - var superagent = client.exports; - - /* */ - function log(req) { - var _pickLogger = function () { - if (console && console.log) - return console; // eslint-disable-line no-console - if (window && window.console && window.console.log) - return window.console; - return console; - }; - var start = new Date().getTime(); - var timestamp = new Date().toISOString(); - var logger = _pickLogger(); - logger.log('<<<<<'); - logger.log("[".concat(timestamp, "]"), '\n', req.url, '\n', req.qs); - logger.log('-----'); - req.on('response', function (res) { - var now = new Date().getTime(); - var elapsed = now - start; - var timestampDone = new Date().toISOString(); - logger.log('>>>>>>'); - logger.log("[".concat(timestampDone, " / ").concat(elapsed, "]"), '\n', req.url, '\n', req.qs, '\n', res.text); - logger.log('-----'); - }); - } - function xdr(superagentConstruct, endpoint, callback) { - var _this = this; - if (this._config.logVerbosity) { - superagentConstruct = superagentConstruct.use(log); - } - if (this._config.proxy && this._modules.proxy) { - superagentConstruct = this._modules.proxy.call(this, superagentConstruct); - } - if (this._config.keepAlive && this._modules.keepAlive) { - superagentConstruct = this._modules.keepAlive(superagentConstruct); - } - var sc = superagentConstruct; - if (endpoint.abortSignal) { - var unsubscribe_1 = endpoint.abortSignal.subscribe(function () { - sc.abort(); - unsubscribe_1(); - }); - } - if (endpoint.forceBuffered === true) { - if (typeof Blob === 'undefined') { - sc = sc.buffer().responseType('arraybuffer'); - } - else { - sc = sc.responseType('arraybuffer'); - } - } - else if (endpoint.forceBuffered === false) { - sc = sc.buffer(false); - } - sc = sc.timeout(endpoint.timeout); - sc.on('abort', function () { - return callback({ - category: categories.PNUnknownCategory, - error: true, - operation: endpoint.operation, - errorData: new Error('Aborted'), - }, null); - }); - sc.end(function (err, resp) { - var parsedResponse; - var status = {}; - status.error = err !== null; - status.operation = endpoint.operation; - if (resp && resp.status) { - status.statusCode = resp.status; - } - if (err) { - if (err.response && err.response.text && !_this._config.logVerbosity) { - try { - status.errorData = JSON.parse(err.response.text); - } - catch (e) { - status.errorData = err; - } - } - else { - status.errorData = err; - } - status.category = _this._detectErrorCategory(err); - return callback(status, null); - } - if (endpoint.ignoreBody) { - parsedResponse = { - headers: resp.headers, - redirects: resp.redirects, - response: resp, - }; - } - else { - try { - parsedResponse = JSON.parse(resp.text); - } - catch (e) { - status.errorData = resp; - status.error = true; - return callback(status, null); - } - } - if (parsedResponse.error && - parsedResponse.error === 1 && - parsedResponse.status && - parsedResponse.message && - parsedResponse.service) { - status.errorData = parsedResponse; - status.statusCode = parsedResponse.status; - status.error = true; - status.category = _this._detectErrorCategory(status); - return callback(status, null); - } - if (parsedResponse.error && parsedResponse.error.message) { - status.errorData = parsedResponse.error; - } - return callback(status, parsedResponse); - }); - return sc; - } - function postfile(url, fields, fileInput) { - return __awaiter(this, void 0, void 0, function () { - var agent, result; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - agent = superagent.post(url); - fields.forEach(function (_a) { - var key = _a.key, value = _a.value; - agent = agent.field(key, value); - }); - agent.attach('file', fileInput, { contentType: 'application/octet-stream' }); - return [4 /*yield*/, agent]; - case 1: - result = _a.sent(); - return [2 /*return*/, result]; - } - }); - }); - } - function getfile(params, endpoint, callback) { - var superagentConstruct = superagent - .get(this.getStandardOrigin() + endpoint.url) - .set(endpoint.headers) - .query(params); - return xdr.call(this, superagentConstruct, endpoint, callback); - } - function get(params, endpoint, callback) { - var superagentConstruct = superagent - .get(this.getStandardOrigin() + endpoint.url) - .set(endpoint.headers) - .query(params); - return xdr.call(this, superagentConstruct, endpoint, callback); - } - function post(params, body, endpoint, callback) { - var superagentConstruct = superagent - .post(this.getStandardOrigin() + endpoint.url) - .query(params) - .set(endpoint.headers) - .send(body); - return xdr.call(this, superagentConstruct, endpoint, callback); - } - function patch(params, body, endpoint, callback) { - var superagentConstruct = superagent - .patch(this.getStandardOrigin() + endpoint.url) - .query(params) - .set(endpoint.headers) - .send(body); - return xdr.call(this, superagentConstruct, endpoint, callback); - } - function del(params, endpoint, callback) { - var superagentConstruct = superagent - .delete(this.getStandardOrigin() + endpoint.url) - .set(endpoint.headers) - .query(params); - return xdr.call(this, superagentConstruct, endpoint, callback); - } - - /* global crypto */ - function concatArrayBuffer(ab1, ab2) { - var tmp = new Uint8Array(ab1.byteLength + ab2.byteLength); - tmp.set(new Uint8Array(ab1), 0); - tmp.set(new Uint8Array(ab2), ab1.byteLength); - return tmp.buffer; - } - var WebCryptography = /** @class */ (function () { - function WebCryptography() { - } - Object.defineProperty(WebCryptography.prototype, "algo", { - get: function () { - return 'aes-256-cbc'; - }, - enumerable: false, - configurable: true - }); - WebCryptography.prototype.encrypt = function (key, input) { - return __awaiter(this, void 0, void 0, function () { - var cKey; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: return [4 /*yield*/, this.getKey(key)]; - case 1: - cKey = _a.sent(); - if (input instanceof ArrayBuffer) { - return [2 /*return*/, this.encryptArrayBuffer(cKey, input)]; - } - if (typeof input === 'string') { - return [2 /*return*/, this.encryptString(cKey, input)]; - } - throw new Error('Cannot encrypt this file. In browsers file encryption supports only string or ArrayBuffer'); - } - }); - }); - }; - WebCryptography.prototype.decrypt = function (key, input) { - return __awaiter(this, void 0, void 0, function () { - var cKey; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: return [4 /*yield*/, this.getKey(key)]; - case 1: - cKey = _a.sent(); - if (input instanceof ArrayBuffer) { - return [2 /*return*/, this.decryptArrayBuffer(cKey, input)]; - } - if (typeof input === 'string') { - return [2 /*return*/, this.decryptString(cKey, input)]; - } - throw new Error('Cannot decrypt this file. In browsers file decryption supports only string or ArrayBuffer'); - } - }); - }); - }; - WebCryptography.prototype.encryptFile = function (key, file, File) { - return __awaiter(this, void 0, void 0, function () { - var bKey, abPlaindata, abCipherdata; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - if (file.data.byteLength <= 0) - throw new Error('encryption error. empty content'); - return [4 /*yield*/, this.getKey(key)]; - case 1: - bKey = _a.sent(); - return [4 /*yield*/, file.data.arrayBuffer()]; - case 2: - abPlaindata = _a.sent(); - return [4 /*yield*/, this.encryptArrayBuffer(bKey, abPlaindata)]; - case 3: - abCipherdata = _a.sent(); - return [2 /*return*/, File.create({ - name: file.name, - mimeType: 'application/octet-stream', - data: abCipherdata, - })]; - } - }); - }); - }; - WebCryptography.prototype.decryptFile = function (key, file, File) { - return __awaiter(this, void 0, void 0, function () { - var bKey, abCipherdata, abPlaindata; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: return [4 /*yield*/, this.getKey(key)]; - case 1: - bKey = _a.sent(); - return [4 /*yield*/, file.data.arrayBuffer()]; - case 2: - abCipherdata = _a.sent(); - return [4 /*yield*/, this.decryptArrayBuffer(bKey, abCipherdata)]; - case 3: - abPlaindata = _a.sent(); - return [2 /*return*/, File.create({ - name: file.name, - data: abPlaindata, - })]; - } - }); - }); - }; - WebCryptography.prototype.getKey = function (key) { - return __awaiter(this, void 0, void 0, function () { - var digest, hashHex, abKey; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: return [4 /*yield*/, crypto.subtle.digest('SHA-256', WebCryptography.encoder.encode(key))]; - case 1: - digest = _a.sent(); - hashHex = Array.from(new Uint8Array(digest)) - .map(function (b) { return b.toString(16).padStart(2, '0'); }) - .join(''); - abKey = WebCryptography.encoder.encode(hashHex.slice(0, 32)).buffer; - return [2 /*return*/, crypto.subtle.importKey('raw', abKey, 'AES-CBC', true, ['encrypt', 'decrypt'])]; - } - }); - }); - }; - WebCryptography.prototype.encryptArrayBuffer = function (key, plaintext) { - return __awaiter(this, void 0, void 0, function () { - var abIv, _a, _b; - return __generator(this, function (_c) { - switch (_c.label) { - case 0: - abIv = crypto.getRandomValues(new Uint8Array(16)); - _a = concatArrayBuffer; - _b = [abIv.buffer]; - return [4 /*yield*/, crypto.subtle.encrypt({ name: 'AES-CBC', iv: abIv }, key, plaintext)]; - case 1: return [2 /*return*/, _a.apply(void 0, _b.concat([_c.sent()]))]; - } - }); - }); - }; - WebCryptography.prototype.decryptArrayBuffer = function (key, ciphertext) { - return __awaiter(this, void 0, void 0, function () { - var abIv, data; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - abIv = ciphertext.slice(0, 16); - if (ciphertext.slice(WebCryptography.IV_LENGTH).byteLength <= 0) - throw new Error('decryption error: empty content'); - return [4 /*yield*/, crypto.subtle.decrypt({ name: 'AES-CBC', iv: abIv }, key, ciphertext.slice(WebCryptography.IV_LENGTH))]; - case 1: - data = _a.sent(); - return [2 /*return*/, data]; - } - }); - }); - }; - WebCryptography.prototype.encryptString = function (key, plaintext) { - return __awaiter(this, void 0, void 0, function () { - var abIv, abPlaintext, abPayload, ciphertext; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - abIv = crypto.getRandomValues(new Uint8Array(16)); - abPlaintext = WebCryptography.encoder.encode(plaintext).buffer; - return [4 /*yield*/, crypto.subtle.encrypt({ name: 'AES-CBC', iv: abIv }, key, abPlaintext)]; - case 1: - abPayload = _a.sent(); - ciphertext = concatArrayBuffer(abIv.buffer, abPayload); - return [2 /*return*/, WebCryptography.decoder.decode(ciphertext)]; - } - }); - }); - }; - WebCryptography.prototype.decryptString = function (key, ciphertext) { - return __awaiter(this, void 0, void 0, function () { - var abCiphertext, abIv, abPayload, abPlaintext; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - abCiphertext = WebCryptography.encoder.encode(ciphertext).buffer; - abIv = abCiphertext.slice(0, 16); - abPayload = abCiphertext.slice(16); - return [4 /*yield*/, crypto.subtle.decrypt({ name: 'AES-CBC', iv: abIv }, key, abPayload)]; - case 1: - abPlaintext = _a.sent(); - return [2 /*return*/, WebCryptography.decoder.decode(abPlaintext)]; - } - }); - }); - }; - WebCryptography.IV_LENGTH = 16; - WebCryptography.encoder = new TextEncoder(); - WebCryptography.decoder = new TextDecoder(); - return WebCryptography; - }()); - - /* global File, FileReader */ - var _a; - var PubNubFile = (_a = /** @class */ (function () { - function PubNubFile(config) { - if (config instanceof File) { - this.data = config; - this.name = this.data.name; - this.mimeType = this.data.type; - } - else if (config.data) { - var contents = config.data; - this.data = new File([contents], config.name, { type: config.mimeType }); - this.name = config.name; - if (config.mimeType) { - this.mimeType = config.mimeType; - } - } - if (this.data === undefined) { - throw new Error("Couldn't construct a file out of supplied options."); - } - if (this.name === undefined) { - throw new Error("Couldn't guess filename out of the options. Please provide one."); - } - } - PubNubFile.create = function (config) { - return new this(config); - }; - PubNubFile.prototype.toBuffer = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - throw new Error('This feature is only supported in Node.js environments.'); - }); - }); - }; - PubNubFile.prototype.toStream = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - throw new Error('This feature is only supported in Node.js environments.'); - }); - }); - }; - PubNubFile.prototype.toFileUri = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - throw new Error('This feature is only supported in react native environments.'); - }); - }); - }; - PubNubFile.prototype.toBlob = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - return [2 /*return*/, this.data]; - }); - }); - }; - PubNubFile.prototype.toArrayBuffer = function () { - return __awaiter(this, void 0, void 0, function () { - var _this = this; - return __generator(this, function (_a) { - return [2 /*return*/, new Promise(function (resolve, reject) { - var reader = new FileReader(); - reader.addEventListener('load', function () { - if (reader.result instanceof ArrayBuffer) { - return resolve(reader.result); - } - }); - reader.addEventListener('error', function () { - reject(reader.error); - }); - reader.readAsArrayBuffer(_this.data); - })]; - }); - }); - }; - PubNubFile.prototype.toString = function () { - return __awaiter(this, void 0, void 0, function () { - var _this = this; - return __generator(this, function (_a) { - return [2 /*return*/, new Promise(function (resolve, reject) { - var reader = new FileReader(); - reader.addEventListener('load', function () { - if (typeof reader.result === 'string') { - return resolve(reader.result); - } - }); - reader.addEventListener('error', function () { - reject(reader.error); - }); - reader.readAsBinaryString(_this.data); - })]; - }); - }); - }; - PubNubFile.prototype.toFile = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - return [2 /*return*/, this.data]; - }); - }); - }; - return PubNubFile; - }()), - _a.supportsFile = typeof File !== 'undefined', - _a.supportsBlob = typeof Blob !== 'undefined', - _a.supportsArrayBuffer = typeof ArrayBuffer !== 'undefined', - _a.supportsBuffer = false, - _a.supportsStream = false, - _a.supportsString = true, - _a.supportsEncryptFile = true, - _a.supportsFileUri = false, - _a); - - var LegacyCryptor = /** @class */ (function () { - function LegacyCryptor(config) { - this.config = config; - this.cryptor = new default_1$a({ config: config }); - this.fileCryptor = new WebCryptography(); - } - Object.defineProperty(LegacyCryptor.prototype, "identifier", { - get: function () { - return ''; - }, - enumerable: false, - configurable: true - }); - LegacyCryptor.prototype.encrypt = function (data) { - var stringData = typeof data === 'string' ? data : new TextDecoder().decode(data); - return { - data: this.cryptor.encrypt(stringData), - metadata: null, - }; - }; - LegacyCryptor.prototype.decrypt = function (encryptedData) { - var data = typeof encryptedData.data === 'string' ? encryptedData.data : encode$1(encryptedData.data); - return this.cryptor.decrypt(data); - }; - LegacyCryptor.prototype.encryptFile = function (file, File) { - var _a; - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_b) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - //@ts-ignore: can not detect cipherKey from old Config - return [2 /*return*/, this.fileCryptor.encryptFile((_a = this.config) === null || _a === void 0 ? void 0 : _a.cipherKey, file, File)]; - }); - }); - }; - LegacyCryptor.prototype.decryptFile = function (file, File) { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - //@ts-ignore: can not detect cipherKey from old Config - return [2 /*return*/, this.fileCryptor.decryptFile(this.config.cipherKey, file, File)]; - }); - }); - }; - return LegacyCryptor; - }()); - - var AesCbcCryptor = /** @class */ (function () { - function AesCbcCryptor(configuration) { - this.cipherKey = configuration.cipherKey; - this.CryptoJS = hmacSha256; - this.encryptedKey = this.CryptoJS.SHA256(this.cipherKey); - } - Object.defineProperty(AesCbcCryptor.prototype, "algo", { - get: function () { - return 'AES-CBC'; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(AesCbcCryptor.prototype, "identifier", { - get: function () { - return 'ACRH'; - }, - enumerable: false, - configurable: true - }); - AesCbcCryptor.prototype.getIv = function () { - return crypto.getRandomValues(new Uint8Array(AesCbcCryptor.BLOCK_SIZE)); - }; - AesCbcCryptor.prototype.getKey = function () { - return __awaiter(this, void 0, void 0, function () { - var bKey, abHash; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - bKey = AesCbcCryptor.encoder.encode(this.cipherKey); - return [4 /*yield*/, crypto.subtle.digest('SHA-256', bKey.buffer)]; - case 1: - abHash = _a.sent(); - return [2 /*return*/, crypto.subtle.importKey('raw', abHash, this.algo, true, ['encrypt', 'decrypt'])]; - } - }); - }); - }; - AesCbcCryptor.prototype.encrypt = function (data) { - var stringData = typeof data === 'string' ? data : AesCbcCryptor.decoder.decode(data); - if (stringData.length === 0) - throw new Error('encryption error. empty content'); - var abIv = this.getIv(); - return { - metadata: abIv, - data: decode$1(this.CryptoJS.AES.encrypt(data, this.encryptedKey, { - iv: this.bufferToWordArray(abIv), - mode: this.CryptoJS.mode.CBC, - }).ciphertext.toString(this.CryptoJS.enc.Base64)), - }; - }; - AesCbcCryptor.prototype.decrypt = function (encryptedData) { - var iv = this.bufferToWordArray(new Uint8ClampedArray(encryptedData.metadata)); - var data = this.bufferToWordArray(new Uint8ClampedArray(encryptedData.data)); - return AesCbcCryptor.encoder.encode(this.CryptoJS.AES.decrypt({ ciphertext: data }, this.encryptedKey, { - iv: iv, - mode: this.CryptoJS.mode.CBC, - }).toString(this.CryptoJS.enc.Utf8)).buffer; - }; - AesCbcCryptor.prototype.encryptFileData = function (data) { - return __awaiter(this, void 0, void 0, function () { - var key, iv; - var _a; - return __generator(this, function (_b) { - switch (_b.label) { - case 0: return [4 /*yield*/, this.getKey()]; - case 1: - key = _b.sent(); - iv = this.getIv(); - _a = {}; - return [4 /*yield*/, crypto.subtle.encrypt({ name: this.algo, iv: iv }, key, data)]; - case 2: return [2 /*return*/, (_a.data = _b.sent(), - _a.metadata = iv, - _a)]; - } - }); - }); - }; - AesCbcCryptor.prototype.decryptFileData = function (encryptedData) { - return __awaiter(this, void 0, void 0, function () { - var key; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: return [4 /*yield*/, this.getKey()]; - case 1: - key = _a.sent(); - return [2 /*return*/, crypto.subtle.decrypt({ name: this.algo, iv: encryptedData.metadata }, key, encryptedData.data)]; - } - }); - }); - }; - AesCbcCryptor.prototype.bufferToWordArray = function (b) { - var wa = []; - var i; - for (i = 0; i < b.length; i += 1) { - wa[(i / 4) | 0] |= b[i] << (24 - 8 * i); - } - return this.CryptoJS.lib.WordArray.create(wa, b.length); - }; - AesCbcCryptor.BLOCK_SIZE = 16; - AesCbcCryptor.encoder = new TextEncoder(); - AesCbcCryptor.decoder = new TextDecoder(); - return AesCbcCryptor; - }()); - - var CryptoModule = /** @class */ (function () { - function CryptoModule(cryptoModuleConfiguration) { - var _a; - this.defaultCryptor = cryptoModuleConfiguration.default; - this.cryptors = (_a = cryptoModuleConfiguration.cryptors) !== null && _a !== void 0 ? _a : []; - } - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - //@ts-ignore: type detection issue with old Config type assignment - CryptoModule.legacyCryptoModule = function (config) { - var _a; - return new this({ - default: new LegacyCryptor({ - cipherKey: config.cipherKey, - useRandomIVs: (_a = config.useRandomIVs) !== null && _a !== void 0 ? _a : true, - }), - cryptors: [new AesCbcCryptor({ cipherKey: config.cipherKey })], - }); - }; - CryptoModule.aesCbcCryptoModule = function (config) { - var _a; - return new this({ - default: new AesCbcCryptor({ cipherKey: config.cipherKey }), - cryptors: [ - new LegacyCryptor({ - cipherKey: config.cipherKey, - useRandomIVs: (_a = config.useRandomIVs) !== null && _a !== void 0 ? _a : true, - }), - ], - }); - }; - CryptoModule.withDefaultCryptor = function (defaultCryptor) { - return new this({ default: defaultCryptor }); - }; - CryptoModule.prototype.getAllCryptors = function () { - return __spreadArray$1([this.defaultCryptor], __read$1(this.cryptors), false); - }; - CryptoModule.prototype.encrypt = function (data) { - var encrypted = this.defaultCryptor.encrypt(data); - if (!encrypted.metadata) - return encrypted.data; - var headerData = this.getHeaderData(encrypted); - return this.concatArrayBuffer(headerData, encrypted.data); - }; - CryptoModule.prototype.decrypt = function (data) { - var encryptedData = typeof data === 'string' ? decode$1(data) : data; - var header = CryptorHeader.tryParse(encryptedData); - var cryptor = this.getCryptor(header); - var metadata = header.length > 0 - ? encryptedData.slice(header.length - header.metadataLength, header.length) - : null; - if (encryptedData.slice(header.length).byteLength <= 0) - throw new Error('decryption error. empty content'); - return cryptor.decrypt({ - data: encryptedData.slice(header.length), - metadata: metadata, - }); - }; - CryptoModule.prototype.encryptFile = function (file, File) { - return __awaiter(this, void 0, void 0, function () { - var fileData, encrypted; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - if (this.defaultCryptor.identifier === CryptorHeader.LEGACY_IDENTIFIER) - return [2 /*return*/, this.defaultCryptor.encryptFile(file, File)]; - return [4 /*yield*/, this.getFileData(file.data)]; - case 1: - fileData = _a.sent(); - return [4 /*yield*/, this.defaultCryptor.encryptFileData(fileData)]; - case 2: - encrypted = _a.sent(); - return [2 /*return*/, File.create({ - name: file.name, - mimeType: 'application/octet-stream', - data: this.concatArrayBuffer(this.getHeaderData(encrypted), encrypted.data), - })]; - } - }); - }); - }; - CryptoModule.prototype.decryptFile = function (file, File) { - return __awaiter(this, void 0, void 0, function () { - var data, header, cryptor, fileData, metadata, _a, _b; - var _c; - return __generator(this, function (_d) { - switch (_d.label) { - case 0: return [4 /*yield*/, file.data.arrayBuffer()]; - case 1: - data = _d.sent(); - header = CryptorHeader.tryParse(data); - cryptor = this.getCryptor(header); - if ((cryptor === null || cryptor === void 0 ? void 0 : cryptor.identifier) === CryptoModule.LEGACY_IDENTIFIER) { - return [2 /*return*/, cryptor.decryptFile(file, File)]; - } - return [4 /*yield*/, this.getFileData(data)]; - case 2: - fileData = _d.sent(); - metadata = fileData.slice(header.length - header.metadataLength, header.length); - _b = (_a = File).create; - _c = { - name: file.name - }; - return [4 /*yield*/, this.defaultCryptor.decryptFileData({ - data: data.slice(header.length), - metadata: metadata, - })]; - case 3: return [2 /*return*/, _b.apply(_a, [(_c.data = _d.sent(), - _c)])]; - } - }); - }); - }; - CryptoModule.prototype.getCryptor = function (header) { - if (header === '') { - var cryptor = this.getAllCryptors().find(function (c) { return c.identifier === ''; }); - if (cryptor) - return cryptor; - throw new Error('unknown cryptor error'); - } - else if (header instanceof CryptorHeaderV1) { - return this.getCryptorFromId(header.identifier); - } - }; - CryptoModule.prototype.getCryptorFromId = function (id) { - var cryptor = this.getAllCryptors().find(function (c) { return id === c.identifier; }); - if (cryptor) { - return cryptor; - } - throw Error('unknown cryptor error'); - }; - CryptoModule.prototype.concatArrayBuffer = function (ab1, ab2) { - var tmp = new Uint8Array(ab1.byteLength + ab2.byteLength); - tmp.set(new Uint8Array(ab1), 0); - tmp.set(new Uint8Array(ab2), ab1.byteLength); - return tmp.buffer; - }; - CryptoModule.prototype.getHeaderData = function (encrypted) { - if (!encrypted.metadata) - return; - var header = CryptorHeader.from(this.defaultCryptor.identifier, encrypted.metadata); - var headerData = new Uint8Array(header.length); - var pos = 0; - headerData.set(header.data, pos); - pos += header.length - encrypted.metadata.byteLength; - headerData.set(new Uint8Array(encrypted.metadata), pos); - return headerData.buffer; - }; - CryptoModule.prototype.getFileData = function (input) { - return __awaiter(this, void 0, void 0, function () { - var fileData; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - if (!(input instanceof Blob)) return [3 /*break*/, 2]; - return [4 /*yield*/, input.arrayBuffer()]; - case 1: - fileData = _a.sent(); - return [2 /*return*/, fileData]; - case 2: - if (input instanceof ArrayBuffer) { - return [2 /*return*/, input]; - } - if (typeof input === 'string') { - return [2 /*return*/, CryptoModule.encoder.encode(input)]; - } - throw new Error('Cannot decrypt/encrypt file. In browsers file encrypt/decrypt supported for string, ArrayBuffer or Blob'); - } - }); - }); - }; - CryptoModule.LEGACY_IDENTIFIER = ''; - CryptoModule.encoder = new TextEncoder(); - CryptoModule.decoder = new TextDecoder(); - return CryptoModule; - }()); - // CryptorHeader Utility - var CryptorHeader = /** @class */ (function () { - function CryptorHeader() { - } - CryptorHeader.from = function (id, metadata) { - if (id === CryptorHeader.LEGACY_IDENTIFIER) - return; - return new CryptorHeaderV1(id, metadata.byteLength); - }; - CryptorHeader.tryParse = function (data) { - var encryptedData = new Uint8Array(data); - var sentinel = ''; - var version = null; - if (encryptedData.byteLength >= 4) { - sentinel = encryptedData.slice(0, 4); - if (this.decoder.decode(sentinel) !== CryptorHeader.SENTINEL) - return ''; - } - if (encryptedData.byteLength >= 5) { - version = encryptedData[4]; - } - else { - throw new Error('decryption error. invalid header version'); - } - if (version > CryptorHeader.MAX_VERSION) - throw new Error('unknown cryptor error'); - var identifier = ''; - var pos = 5 + CryptorHeader.IDENTIFIER_LENGTH; - if (encryptedData.byteLength >= pos) { - identifier = encryptedData.slice(5, pos); - } - else { - throw new Error('decryption error. invalid crypto identifier'); - } - var metadataLength = null; - if (encryptedData.byteLength >= pos + 1) { - metadataLength = encryptedData[pos]; - } - else { - throw new Error('decryption error. invalid metadata length'); - } - pos += 1; - if (metadataLength === 255 && encryptedData.byteLength >= pos + 2) { - metadataLength = new Uint16Array(encryptedData.slice(pos, pos + 2)).reduce(function (acc, val) { return (acc << 8) + val; }, 0); - pos += 2; - } - return new CryptorHeaderV1(this.decoder.decode(identifier), metadataLength); - }; - CryptorHeader.SENTINEL = 'PNED'; - CryptorHeader.LEGACY_IDENTIFIER = ''; - CryptorHeader.IDENTIFIER_LENGTH = 4; - CryptorHeader.VERSION = 1; - CryptorHeader.MAX_VERSION = 1; - CryptorHeader.decoder = new TextDecoder(); - return CryptorHeader; - }()); - // v1 CryptorHeader - var CryptorHeaderV1 = /** @class */ (function () { - function CryptorHeaderV1(id, metadataLength) { - this._identifier = id; - this._metadataLength = metadataLength; - } - Object.defineProperty(CryptorHeaderV1.prototype, "identifier", { - get: function () { - return this._identifier; - }, - set: function (value) { - this._identifier = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(CryptorHeaderV1.prototype, "metadataLength", { - get: function () { - return this._metadataLength; - }, - set: function (value) { - this._metadataLength = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(CryptorHeaderV1.prototype, "version", { - get: function () { - return CryptorHeader.VERSION; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(CryptorHeaderV1.prototype, "length", { - get: function () { - return (CryptorHeader.SENTINEL.length + - 1 + - CryptorHeader.IDENTIFIER_LENGTH + - (this.metadataLength < 255 ? 1 : 3) + - this.metadataLength); - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(CryptorHeaderV1.prototype, "data", { - get: function () { - var pos = 0; - var header = new Uint8Array(this.length); - var encoder = new TextEncoder(); - header.set(encoder.encode(CryptorHeader.SENTINEL)); - pos += CryptorHeader.SENTINEL.length; - header[pos] = this.version; - pos++; - if (this.identifier) - header.set(encoder.encode(this.identifier), pos); - pos += CryptorHeader.IDENTIFIER_LENGTH; - var metadataLength = this.metadataLength; - if (metadataLength < 255) { - header[pos] = metadataLength; - } - else { - header.set([255, metadataLength >> 8, metadataLength & 0xff], pos); - } - return header; - }, - enumerable: false, - configurable: true - }); - CryptorHeaderV1.IDENTIFIER_LENGTH = 4; - CryptorHeaderV1.SENTINEL = 'PNED'; - return CryptorHeaderV1; - }()); - - /* eslint no-bitwise: ["error", { "allow": ["~", "&", ">>"] }] */ - function sendBeacon(url) { - if (navigator && navigator.sendBeacon) { - navigator.sendBeacon(url); - } - else { - return false; - } - } - var default_1 = /** @class */ (function (_super) { - __extends(default_1, _super); - function default_1(setup) { - var _this = this; - // extract config. - var _a = setup.listenToBrowserNetworkEvents, listenToBrowserNetworkEvents = _a === void 0 ? true : _a; - setup.sdkFamily = 'Web'; - setup.networking = new default_1$2({ - del: del, - get: get, - post: post, - patch: patch, - sendBeacon: sendBeacon, - getfile: getfile, - postfile: postfile, - }); - setup.cbor = new default_1$1(function (arrayBuffer) { return stringifyBufferKeys(CborReader.decode(arrayBuffer)); }, decode$1); - setup.PubNubFile = PubNubFile; - setup.cryptography = new WebCryptography(); - setup.initCryptoModule = function (cryptoConfiguration) { - return new CryptoModule({ - default: new LegacyCryptor({ - cipherKey: cryptoConfiguration.cipherKey, - useRandomIVs: cryptoConfiguration.useRandomIVs, - }), - cryptors: [new AesCbcCryptor({ cipherKey: cryptoConfiguration.cipherKey })], - }); - }; - _this = _super.call(this, setup) || this; - if (listenToBrowserNetworkEvents) { - // mount network events. - window.addEventListener('offline', function () { - _this.networkDownDetected(); - }); - window.addEventListener('online', function () { - _this.networkUpDetected(); - }); - } - return _this; - } - default_1.CryptoModule = CryptoModule; - return default_1; - }(default_1$3)); - - return default_1; + typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { + var e = new Error(message); + return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; + }; + + /** + * Crypto module. + */ + class AbstractCryptoModule { + // -------------------------------------------------------- + // --------------- Convenience functions ------------------ + // -------------------------------------------------------- + // region Convenience functions + /** + * Construct crypto module with legacy cryptor for encryption and both legacy and AES-CBC + * cryptors for decryption. + * + * @param config Cryptors configuration options. + * + * @returns Crypto module which encrypts data using legacy cryptor. + * + * @throws Error if `config.cipherKey` not set. + */ + static legacyCryptoModule(config) { + throw new Error('Should be implemented by concrete crypto module implementation.'); + } + /** + * Construct crypto module with AES-CBC cryptor for encryption and both AES-CBC and legacy + * cryptors for decryption. + * + * @param config Cryptors configuration options. + * + * @returns Crypto module which encrypts data using AES-CBC cryptor. + * + * @throws Error if `config.cipherKey` not set. + */ + static aesCbcCryptoModule(config) { + throw new Error('Should be implemented by concrete crypto module implementation.'); + } + // endregion + constructor(configuration) { + var _a; + this.defaultCryptor = configuration.default; + this.cryptors = (_a = configuration.cryptors) !== null && _a !== void 0 ? _a : []; + } + // endregion + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + // region Helpers + /** + * Retrieve list of module's cryptors. + */ + getAllCryptors() { + return [this.defaultCryptor, ...this.cryptors]; + } + } + /** + * `String` to {@link ArrayBuffer} response decoder. + */ + AbstractCryptoModule.encoder = new TextEncoder(); + /** + * {@link ArrayBuffer} to {@link string} decoder. + */ + AbstractCryptoModule.decoder = new TextDecoder(); + + /* global File, FileReader */ + /** + * Browser {@link PubNub} File object module. + */ + // endregion + /** + * Web implementation for {@link PubNub} File object. + * + * **Important:** Class should implement constructor and class fields from {@link PubNubFileConstructor}. + */ + class PubNubFile { + // endregion + static create(file) { + return new PubNubFile(file); + } + constructor(file) { + let contentLength; + let fileMimeType; + let fileName; + let fileData; + if (file instanceof File) { + fileData = file; + fileName = file.name; + fileMimeType = file.type; + contentLength = file.size; + } + else if ('data' in file) { + const contents = file.data; + fileMimeType = file.mimeType; + fileName = file.name; + fileData = new File([contents], fileName, { type: fileMimeType }); + contentLength = fileData.size; + } + if (fileData === undefined) + throw new Error("Couldn't construct a file out of supplied options."); + if (fileName === undefined) + throw new Error("Couldn't guess filename out of the options. Please provide one."); + if (contentLength) + this.contentLength = contentLength; + this.mimeType = fileMimeType; + this.data = fileData; + this.name = fileName; + } + /** + * Convert {@link PubNub} File object content to {@link Buffer}. + * + * @throws Error because {@link Buffer} not available in browser environment. + */ + toBuffer() { + return __awaiter(this, void 0, void 0, function* () { + throw new Error('This feature is only supported in Node.js environments.'); + }); + } + /** + * Convert {@link PubNub} File object content to {@link ArrayBuffer}. + * + * @returns Asynchronous results of conversion to the {@link ArrayBuffer}. + */ + toArrayBuffer() { + return __awaiter(this, void 0, void 0, function* () { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.addEventListener('load', () => { + if (reader.result instanceof ArrayBuffer) + return resolve(reader.result); + }); + reader.addEventListener('error', () => reject(reader.error)); + reader.readAsArrayBuffer(this.data); + }); + }); + } + /** + * Convert {@link PubNub} File object content to {@link string}. + * + * @returns Asynchronous results of conversion to the {@link string}. + */ + toString() { + return __awaiter(this, void 0, void 0, function* () { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.addEventListener('load', () => { + if (typeof reader.result === 'string') { + return resolve(reader.result); + } + }); + reader.addEventListener('error', () => { + reject(reader.error); + }); + reader.readAsBinaryString(this.data); + }); + }); + } + /** + * Convert {@link PubNub} File object content to {@link Readable} stream. + * + * @throws Error because {@link Readable} stream not available in browser environment. + */ + toStream() { + return __awaiter(this, void 0, void 0, function* () { + throw new Error('This feature is only supported in Node.js environments.'); + }); + } + /** + * Convert {@link PubNub} File object content to {@link File}. + * + * @returns Asynchronous results of conversion to the {@link File}. + */ + toFile() { + return __awaiter(this, void 0, void 0, function* () { + return this.data; + }); + } + /** + * Convert {@link PubNub} File object content to file `Uri`. + * + * @throws Error because file `Uri` not available in browser environment. + */ + toFileUri() { + return __awaiter(this, void 0, void 0, function* () { + throw new Error('This feature is only supported in React Native environments.'); + }); + } + /** + * Convert {@link PubNub} File object content to {@link Blob}. + * + * @returns Asynchronous results of conversion to the {@link Blob}. + */ + toBlob() { + return __awaiter(this, void 0, void 0, function* () { + return this.data; + }); + } + } + // region Class properties + /** + * Whether {@link Blob} data supported by platform or not. + */ + PubNubFile.supportsBlob = typeof Blob !== 'undefined'; + /** + * Whether {@link File} data supported by platform or not. + */ + PubNubFile.supportsFile = typeof File !== 'undefined'; + /** + * Whether {@link Buffer} data supported by platform or not. + */ + PubNubFile.supportsBuffer = false; + /** + * Whether {@link Stream} data supported by platform or not. + */ + PubNubFile.supportsStream = false; + /** + * Whether {@link String} data supported by platform or not. + */ + PubNubFile.supportsString = true; + /** + * Whether {@link ArrayBuffer} supported by platform or not. + */ + PubNubFile.supportsArrayBuffer = true; + /** + * Whether {@link PubNub} File object encryption supported or not. + */ + PubNubFile.supportsEncryptFile = true; + /** + * Whether `File Uri` data supported by platform or not. + */ + PubNubFile.supportsFileUri = false; + + const BASE64_CHARMAP = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; + /** + * Decode a Base64 encoded string. + * + * @param paddedInput Base64 string with padding + * @returns ArrayBuffer with decoded data + */ + function decode(paddedInput) { + // Remove up to last two equal signs. + const input = paddedInput.replace(/==?$/, ''); + const outputLength = Math.floor((input.length / 4) * 3); + // Prepare output buffer. + const data = new ArrayBuffer(outputLength); + const view = new Uint8Array(data); + let cursor = 0; + /** + * Returns the next integer representation of a sixtet of bytes from the input + * @returns sixtet of bytes + */ + function nextSixtet() { + const char = input.charAt(cursor++); + const index = BASE64_CHARMAP.indexOf(char); + if (index === -1) { + throw new Error(`Illegal character at ${cursor}: ${input.charAt(cursor - 1)}`); + } + return index; + } + for (let i = 0; i < outputLength; i += 3) { + // Obtain four sixtets + const sx1 = nextSixtet(); + const sx2 = nextSixtet(); + const sx3 = nextSixtet(); + const sx4 = nextSixtet(); + // Encode them as three octets + const oc1 = ((sx1 & 0b00111111) << 2) | (sx2 >> 4); + const oc2 = ((sx2 & 0b00001111) << 4) | (sx3 >> 2); + const oc3 = ((sx3 & 0b00000011) << 6) | (sx4 >> 0); + view[i] = oc1; + // Skip padding bytes. + if (sx3 != 64) + view[i + 1] = oc2; + if (sx4 != 64) + view[i + 2] = oc3; + } + return data; + } + function encode(input) { + let base64 = ''; + const encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + const bytes = new Uint8Array(input); + const byteLength = bytes.byteLength; + const byteRemainder = byteLength % 3; + const mainLength = byteLength - byteRemainder; + let a, b, c, d; + let chunk; + // Main loop deals with bytes in chunks of 3 + for (let i = 0; i < mainLength; i = i + 3) { + // Combine the three bytes into a single integer + chunk = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2]; + // Use bitmasks to extract 6-bit segments from the triplet + a = (chunk & 16515072) >> 18; // 16515072 = (2^6 - 1) << 18 + b = (chunk & 258048) >> 12; // 258048 = (2^6 - 1) << 12 + c = (chunk & 4032) >> 6; // 4032 = (2^6 - 1) << 6 + d = chunk & 63; // 63 = 2^6 - 1 + // Convert the raw binary segments to the appropriate ASCII encoding + base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d]; + } + // Deal with the remaining bytes and padding + if (byteRemainder == 1) { + chunk = bytes[mainLength]; + a = (chunk & 252) >> 2; // 252 = (2^6 - 1) << 2 + // Set the 4 least significant bits to zero + b = (chunk & 3) << 4; // 3 = 2^2 - 1 + base64 += encodings[a] + encodings[b] + '=='; + } + else if (byteRemainder == 2) { + chunk = (bytes[mainLength] << 8) | bytes[mainLength + 1]; + a = (chunk & 64512) >> 10; // 64512 = (2^6 - 1) << 10 + b = (chunk & 1008) >> 4; // 1008 = (2^6 - 1) << 4 + // Set the 2 least significant bits to zero + c = (chunk & 15) << 2; // 15 = 2^4 - 1 + base64 += encodings[a] + encodings[b] + encodings[c] + '='; + } + return base64; + } + + /*eslint-disable */ + + /* + CryptoJS v3.1.2 + code.google.com/p/crypto-js + (c) 2009-2013 by Jeff Mott. All rights reserved. + code.google.com/p/crypto-js/wiki/License + */ + var CryptoJS = + CryptoJS || + (function (h, s) { + var f = {}, + g = (f.lib = {}), + q = function () {}, + m = (g.Base = { + extend: function (a) { + q.prototype = this; + var c = new q(); + a && c.mixIn(a); + c.hasOwnProperty('init') || + (c.init = function () { + c.$super.init.apply(this, arguments); + }); + c.init.prototype = c; + c.$super = this; + return c; + }, + create: function () { + var a = this.extend(); + a.init.apply(a, arguments); + return a; + }, + init: function () {}, + mixIn: function (a) { + for (var c in a) a.hasOwnProperty(c) && (this[c] = a[c]); + a.hasOwnProperty('toString') && (this.toString = a.toString); + }, + clone: function () { + return this.init.prototype.extend(this); + }, + }), + r = (g.WordArray = m.extend({ + init: function (a, c) { + a = this.words = a || []; + this.sigBytes = c != s ? c : 4 * a.length; + }, + toString: function (a) { + return (a || k).stringify(this); + }, + concat: function (a) { + var c = this.words, + d = a.words, + b = this.sigBytes; + a = a.sigBytes; + this.clamp(); + if (b % 4) + for (var e = 0; e < a; e++) + c[(b + e) >>> 2] |= ((d[e >>> 2] >>> (24 - 8 * (e % 4))) & 255) << (24 - 8 * ((b + e) % 4)); + else if (65535 < d.length) for (e = 0; e < a; e += 4) c[(b + e) >>> 2] = d[e >>> 2]; + else c.push.apply(c, d); + this.sigBytes += a; + return this; + }, + clamp: function () { + var a = this.words, + c = this.sigBytes; + a[c >>> 2] &= 4294967295 << (32 - 8 * (c % 4)); + a.length = h.ceil(c / 4); + }, + clone: function () { + var a = m.clone.call(this); + a.words = this.words.slice(0); + return a; + }, + random: function (a) { + for (var c = [], d = 0; d < a; d += 4) c.push((4294967296 * h.random()) | 0); + return new r.init(c, a); + }, + })), + l = (f.enc = {}), + k = (l.Hex = { + stringify: function (a) { + var c = a.words; + a = a.sigBytes; + for (var d = [], b = 0; b < a; b++) { + var e = (c[b >>> 2] >>> (24 - 8 * (b % 4))) & 255; + d.push((e >>> 4).toString(16)); + d.push((e & 15).toString(16)); + } + return d.join(''); + }, + parse: function (a) { + for (var c = a.length, d = [], b = 0; b < c; b += 2) + d[b >>> 3] |= parseInt(a.substr(b, 2), 16) << (24 - 4 * (b % 8)); + return new r.init(d, c / 2); + }, + }), + n = (l.Latin1 = { + stringify: function (a) { + var c = a.words; + a = a.sigBytes; + for (var d = [], b = 0; b < a; b++) d.push(String.fromCharCode((c[b >>> 2] >>> (24 - 8 * (b % 4))) & 255)); + return d.join(''); + }, + parse: function (a) { + for (var c = a.length, d = [], b = 0; b < c; b++) d[b >>> 2] |= (a.charCodeAt(b) & 255) << (24 - 8 * (b % 4)); + return new r.init(d, c); + }, + }), + j = (l.Utf8 = { + stringify: function (a) { + try { + return decodeURIComponent(escape(n.stringify(a))); + } catch (c) { + throw Error('Malformed UTF-8 data'); + } + }, + parse: function (a) { + return n.parse(unescape(encodeURIComponent(a))); + }, + }), + u = (g.BufferedBlockAlgorithm = m.extend({ + reset: function () { + this._data = new r.init(); + this._nDataBytes = 0; + }, + _append: function (a) { + 'string' == typeof a && (a = j.parse(a)); + this._data.concat(a); + this._nDataBytes += a.sigBytes; + }, + _process: function (a) { + var c = this._data, + d = c.words, + b = c.sigBytes, + e = this.blockSize, + f = b / (4 * e), + f = a ? h.ceil(f) : h.max((f | 0) - this._minBufferSize, 0); + a = f * e; + b = h.min(4 * a, b); + if (a) { + for (var g = 0; g < a; g += e) this._doProcessBlock(d, g); + g = d.splice(0, a); + c.sigBytes -= b; + } + return new r.init(g, b); + }, + clone: function () { + var a = m.clone.call(this); + a._data = this._data.clone(); + return a; + }, + _minBufferSize: 0, + })); + g.Hasher = u.extend({ + cfg: m.extend(), + init: function (a) { + this.cfg = this.cfg.extend(a); + this.reset(); + }, + reset: function () { + u.reset.call(this); + this._doReset(); + }, + update: function (a) { + this._append(a); + this._process(); + return this; + }, + finalize: function (a) { + a && this._append(a); + return this._doFinalize(); + }, + blockSize: 16, + _createHelper: function (a) { + return function (c, d) { + return new a.init(d).finalize(c); + }; + }, + _createHmacHelper: function (a) { + return function (c, d) { + return new t.HMAC.init(a, d).finalize(c); + }; + }, + }); + var t = (f.algo = {}); + return f; + })(Math); + + // SHA256 + (function (h) { + for ( + var s = CryptoJS, + f = s.lib, + g = f.WordArray, + q = f.Hasher, + f = s.algo, + m = [], + r = [], + l = function (a) { + return (4294967296 * (a - (a | 0))) | 0; + }, + k = 2, + n = 0; + 64 > n; + + ) { + var j; + a: { + j = k; + for (var u = h.sqrt(j), t = 2; t <= u; t++) + if (!(j % t)) { + j = !1; + break a; + } + j = !0; + } + j && (8 > n && (m[n] = l(h.pow(k, 0.5))), (r[n] = l(h.pow(k, 1 / 3))), n++); + k++; + } + var a = [], + f = (f.SHA256 = q.extend({ + _doReset: function () { + this._hash = new g.init(m.slice(0)); + }, + _doProcessBlock: function (c, d) { + for ( + var b = this._hash.words, + e = b[0], + f = b[1], + g = b[2], + j = b[3], + h = b[4], + m = b[5], + n = b[6], + q = b[7], + p = 0; + 64 > p; + p++ + ) { + if (16 > p) a[p] = c[d + p] | 0; + else { + var k = a[p - 15], + l = a[p - 2]; + a[p] = + (((k << 25) | (k >>> 7)) ^ ((k << 14) | (k >>> 18)) ^ (k >>> 3)) + + a[p - 7] + + (((l << 15) | (l >>> 17)) ^ ((l << 13) | (l >>> 19)) ^ (l >>> 10)) + + a[p - 16]; + } + k = + q + + (((h << 26) | (h >>> 6)) ^ ((h << 21) | (h >>> 11)) ^ ((h << 7) | (h >>> 25))) + + ((h & m) ^ (~h & n)) + + r[p] + + a[p]; + l = + (((e << 30) | (e >>> 2)) ^ ((e << 19) | (e >>> 13)) ^ ((e << 10) | (e >>> 22))) + + ((e & f) ^ (e & g) ^ (f & g)); + q = n; + n = m; + m = h; + h = (j + k) | 0; + j = g; + g = f; + f = e; + e = (k + l) | 0; + } + b[0] = (b[0] + e) | 0; + b[1] = (b[1] + f) | 0; + b[2] = (b[2] + g) | 0; + b[3] = (b[3] + j) | 0; + b[4] = (b[4] + h) | 0; + b[5] = (b[5] + m) | 0; + b[6] = (b[6] + n) | 0; + b[7] = (b[7] + q) | 0; + }, + _doFinalize: function () { + var a = this._data, + d = a.words, + b = 8 * this._nDataBytes, + e = 8 * a.sigBytes; + d[e >>> 5] |= 128 << (24 - (e % 32)); + d[(((e + 64) >>> 9) << 4) + 14] = h.floor(b / 4294967296); + d[(((e + 64) >>> 9) << 4) + 15] = b; + a.sigBytes = 4 * d.length; + this._process(); + return this._hash; + }, + clone: function () { + var a = q.clone.call(this); + a._hash = this._hash.clone(); + return a; + }, + })); + s.SHA256 = q._createHelper(f); + s.HmacSHA256 = q._createHmacHelper(f); + })(Math); + + // HMAC SHA256 + (function () { + var h = CryptoJS, + s = h.enc.Utf8; + h.algo.HMAC = h.lib.Base.extend({ + init: function (f, g) { + f = this._hasher = new f.init(); + 'string' == typeof g && (g = s.parse(g)); + var h = f.blockSize, + m = 4 * h; + g.sigBytes > m && (g = f.finalize(g)); + g.clamp(); + for (var r = (this._oKey = g.clone()), l = (this._iKey = g.clone()), k = r.words, n = l.words, j = 0; j < h; j++) + (k[j] ^= 1549556828), (n[j] ^= 909522486); + r.sigBytes = l.sigBytes = m; + this.reset(); + }, + reset: function () { + var f = this._hasher; + f.reset(); + f.update(this._iKey); + }, + update: function (f) { + this._hasher.update(f); + return this; + }, + finalize: function (f) { + var g = this._hasher; + f = g.finalize(f); + g.reset(); + return g.finalize(this._oKey.clone().concat(f)); + }, + }); + })(); + + // Base64 + (function () { + var u = CryptoJS, + p = u.lib.WordArray; + u.enc.Base64 = { + stringify: function (d) { + var l = d.words, + p = d.sigBytes, + t = this._map; + d.clamp(); + d = []; + for (var r = 0; r < p; r += 3) + for ( + var w = + (((l[r >>> 2] >>> (24 - 8 * (r % 4))) & 255) << 16) | + (((l[(r + 1) >>> 2] >>> (24 - 8 * ((r + 1) % 4))) & 255) << 8) | + ((l[(r + 2) >>> 2] >>> (24 - 8 * ((r + 2) % 4))) & 255), + v = 0; + 4 > v && r + 0.75 * v < p; + v++ + ) + d.push(t.charAt((w >>> (6 * (3 - v))) & 63)); + if ((l = t.charAt(64))) for (; d.length % 4; ) d.push(l); + return d.join(''); + }, + parse: function (d) { + var l = d.length, + s = this._map, + t = s.charAt(64); + t && ((t = d.indexOf(t)), -1 != t && (l = t)); + for (var t = [], r = 0, w = 0; w < l; w++) + if (w % 4) { + var v = s.indexOf(d.charAt(w - 1)) << (2 * (w % 4)), + b = s.indexOf(d.charAt(w)) >>> (6 - 2 * (w % 4)); + t[r >>> 2] |= (v | b) << (24 - 8 * (r % 4)); + r++; + } + return p.create(t, r); + }, + _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=', + }; + })(); + + // BlockCipher + (function (u) { + function p(b, n, a, c, e, j, k) { + b = b + ((n & a) | (~n & c)) + e + k; + return ((b << j) | (b >>> (32 - j))) + n; + } + function d(b, n, a, c, e, j, k) { + b = b + ((n & c) | (a & ~c)) + e + k; + return ((b << j) | (b >>> (32 - j))) + n; + } + function l(b, n, a, c, e, j, k) { + b = b + (n ^ a ^ c) + e + k; + return ((b << j) | (b >>> (32 - j))) + n; + } + function s(b, n, a, c, e, j, k) { + b = b + (a ^ (n | ~c)) + e + k; + return ((b << j) | (b >>> (32 - j))) + n; + } + for (var t = CryptoJS, r = t.lib, w = r.WordArray, v = r.Hasher, r = t.algo, b = [], x = 0; 64 > x; x++) + b[x] = (4294967296 * u.abs(u.sin(x + 1))) | 0; + r = r.MD5 = v.extend({ + _doReset: function () { + this._hash = new w.init([1732584193, 4023233417, 2562383102, 271733878]); + }, + _doProcessBlock: function (q, n) { + for (var a = 0; 16 > a; a++) { + var c = n + a, + e = q[c]; + q[c] = (((e << 8) | (e >>> 24)) & 16711935) | (((e << 24) | (e >>> 8)) & 4278255360); + } + var a = this._hash.words, + c = q[n + 0], + e = q[n + 1], + j = q[n + 2], + k = q[n + 3], + z = q[n + 4], + r = q[n + 5], + t = q[n + 6], + w = q[n + 7], + v = q[n + 8], + A = q[n + 9], + B = q[n + 10], + C = q[n + 11], + u = q[n + 12], + D = q[n + 13], + E = q[n + 14], + x = q[n + 15], + f = a[0], + m = a[1], + g = a[2], + h = a[3], + f = p(f, m, g, h, c, 7, b[0]), + h = p(h, f, m, g, e, 12, b[1]), + g = p(g, h, f, m, j, 17, b[2]), + m = p(m, g, h, f, k, 22, b[3]), + f = p(f, m, g, h, z, 7, b[4]), + h = p(h, f, m, g, r, 12, b[5]), + g = p(g, h, f, m, t, 17, b[6]), + m = p(m, g, h, f, w, 22, b[7]), + f = p(f, m, g, h, v, 7, b[8]), + h = p(h, f, m, g, A, 12, b[9]), + g = p(g, h, f, m, B, 17, b[10]), + m = p(m, g, h, f, C, 22, b[11]), + f = p(f, m, g, h, u, 7, b[12]), + h = p(h, f, m, g, D, 12, b[13]), + g = p(g, h, f, m, E, 17, b[14]), + m = p(m, g, h, f, x, 22, b[15]), + f = d(f, m, g, h, e, 5, b[16]), + h = d(h, f, m, g, t, 9, b[17]), + g = d(g, h, f, m, C, 14, b[18]), + m = d(m, g, h, f, c, 20, b[19]), + f = d(f, m, g, h, r, 5, b[20]), + h = d(h, f, m, g, B, 9, b[21]), + g = d(g, h, f, m, x, 14, b[22]), + m = d(m, g, h, f, z, 20, b[23]), + f = d(f, m, g, h, A, 5, b[24]), + h = d(h, f, m, g, E, 9, b[25]), + g = d(g, h, f, m, k, 14, b[26]), + m = d(m, g, h, f, v, 20, b[27]), + f = d(f, m, g, h, D, 5, b[28]), + h = d(h, f, m, g, j, 9, b[29]), + g = d(g, h, f, m, w, 14, b[30]), + m = d(m, g, h, f, u, 20, b[31]), + f = l(f, m, g, h, r, 4, b[32]), + h = l(h, f, m, g, v, 11, b[33]), + g = l(g, h, f, m, C, 16, b[34]), + m = l(m, g, h, f, E, 23, b[35]), + f = l(f, m, g, h, e, 4, b[36]), + h = l(h, f, m, g, z, 11, b[37]), + g = l(g, h, f, m, w, 16, b[38]), + m = l(m, g, h, f, B, 23, b[39]), + f = l(f, m, g, h, D, 4, b[40]), + h = l(h, f, m, g, c, 11, b[41]), + g = l(g, h, f, m, k, 16, b[42]), + m = l(m, g, h, f, t, 23, b[43]), + f = l(f, m, g, h, A, 4, b[44]), + h = l(h, f, m, g, u, 11, b[45]), + g = l(g, h, f, m, x, 16, b[46]), + m = l(m, g, h, f, j, 23, b[47]), + f = s(f, m, g, h, c, 6, b[48]), + h = s(h, f, m, g, w, 10, b[49]), + g = s(g, h, f, m, E, 15, b[50]), + m = s(m, g, h, f, r, 21, b[51]), + f = s(f, m, g, h, u, 6, b[52]), + h = s(h, f, m, g, k, 10, b[53]), + g = s(g, h, f, m, B, 15, b[54]), + m = s(m, g, h, f, e, 21, b[55]), + f = s(f, m, g, h, v, 6, b[56]), + h = s(h, f, m, g, x, 10, b[57]), + g = s(g, h, f, m, t, 15, b[58]), + m = s(m, g, h, f, D, 21, b[59]), + f = s(f, m, g, h, z, 6, b[60]), + h = s(h, f, m, g, C, 10, b[61]), + g = s(g, h, f, m, j, 15, b[62]), + m = s(m, g, h, f, A, 21, b[63]); + a[0] = (a[0] + f) | 0; + a[1] = (a[1] + m) | 0; + a[2] = (a[2] + g) | 0; + a[3] = (a[3] + h) | 0; + }, + _doFinalize: function () { + var b = this._data, + n = b.words, + a = 8 * this._nDataBytes, + c = 8 * b.sigBytes; + n[c >>> 5] |= 128 << (24 - (c % 32)); + var e = u.floor(a / 4294967296); + n[(((c + 64) >>> 9) << 4) + 15] = (((e << 8) | (e >>> 24)) & 16711935) | (((e << 24) | (e >>> 8)) & 4278255360); + n[(((c + 64) >>> 9) << 4) + 14] = (((a << 8) | (a >>> 24)) & 16711935) | (((a << 24) | (a >>> 8)) & 4278255360); + b.sigBytes = 4 * (n.length + 1); + this._process(); + b = this._hash; + n = b.words; + for (a = 0; 4 > a; a++) + (c = n[a]), (n[a] = (((c << 8) | (c >>> 24)) & 16711935) | (((c << 24) | (c >>> 8)) & 4278255360)); + return b; + }, + clone: function () { + var b = v.clone.call(this); + b._hash = this._hash.clone(); + return b; + }, + }); + t.MD5 = v._createHelper(r); + t.HmacMD5 = v._createHmacHelper(r); + })(Math); + (function () { + var u = CryptoJS, + p = u.lib, + d = p.Base, + l = p.WordArray, + p = u.algo, + s = (p.EvpKDF = d.extend({ + cfg: d.extend({ keySize: 4, hasher: p.MD5, iterations: 1 }), + init: function (d) { + this.cfg = this.cfg.extend(d); + }, + compute: function (d, r) { + for ( + var p = this.cfg, s = p.hasher.create(), b = l.create(), u = b.words, q = p.keySize, p = p.iterations; + u.length < q; + + ) { + n && s.update(n); + var n = s.update(d).finalize(r); + s.reset(); + for (var a = 1; a < p; a++) (n = s.finalize(n)), s.reset(); + b.concat(n); + } + b.sigBytes = 4 * q; + return b; + }, + })); + u.EvpKDF = function (d, l, p) { + return s.create(p).compute(d, l); + }; + })(); + + // Cipher + CryptoJS.lib.Cipher || + (function (u) { + var p = CryptoJS, + d = p.lib, + l = d.Base, + s = d.WordArray, + t = d.BufferedBlockAlgorithm, + r = p.enc.Base64, + w = p.algo.EvpKDF, + v = (d.Cipher = t.extend({ + cfg: l.extend(), + createEncryptor: function (e, a) { + return this.create(this._ENC_XFORM_MODE, e, a); + }, + createDecryptor: function (e, a) { + return this.create(this._DEC_XFORM_MODE, e, a); + }, + init: function (e, a, b) { + this.cfg = this.cfg.extend(b); + this._xformMode = e; + this._key = a; + this.reset(); + }, + reset: function () { + t.reset.call(this); + this._doReset(); + }, + process: function (e) { + this._append(e); + return this._process(); + }, + finalize: function (e) { + e && this._append(e); + return this._doFinalize(); + }, + keySize: 4, + ivSize: 4, + _ENC_XFORM_MODE: 1, + _DEC_XFORM_MODE: 2, + _createHelper: function (e) { + return { + encrypt: function (b, k, d) { + return ('string' == typeof k ? c : a).encrypt(e, b, k, d); + }, + decrypt: function (b, k, d) { + return ('string' == typeof k ? c : a).decrypt(e, b, k, d); + }, + }; + }, + })); + d.StreamCipher = v.extend({ + _doFinalize: function () { + return this._process(!0); + }, + blockSize: 1, + }); + var b = (p.mode = {}), + x = function (e, a, b) { + var c = this._iv; + c ? (this._iv = u) : (c = this._prevBlock); + for (var d = 0; d < b; d++) e[a + d] ^= c[d]; + }, + q = (d.BlockCipherMode = l.extend({ + createEncryptor: function (e, a) { + return this.Encryptor.create(e, a); + }, + createDecryptor: function (e, a) { + return this.Decryptor.create(e, a); + }, + init: function (e, a) { + this._cipher = e; + this._iv = a; + }, + })).extend(); + q.Encryptor = q.extend({ + processBlock: function (e, a) { + var b = this._cipher, + c = b.blockSize; + x.call(this, e, a, c); + b.encryptBlock(e, a); + this._prevBlock = e.slice(a, a + c); + }, + }); + q.Decryptor = q.extend({ + processBlock: function (e, a) { + var b = this._cipher, + c = b.blockSize, + d = e.slice(a, a + c); + b.decryptBlock(e, a); + x.call(this, e, a, c); + this._prevBlock = d; + }, + }); + b = b.CBC = q; + q = (p.pad = {}).Pkcs7 = { + pad: function (a, b) { + for ( + var c = 4 * b, c = c - (a.sigBytes % c), d = (c << 24) | (c << 16) | (c << 8) | c, l = [], n = 0; + n < c; + n += 4 + ) + l.push(d); + c = s.create(l, c); + a.concat(c); + }, + unpad: function (a) { + a.sigBytes -= a.words[(a.sigBytes - 1) >>> 2] & 255; + }, + }; + d.BlockCipher = v.extend({ + cfg: v.cfg.extend({ mode: b, padding: q }), + reset: function () { + v.reset.call(this); + var a = this.cfg, + b = a.iv, + a = a.mode; + if (this._xformMode == this._ENC_XFORM_MODE) var c = a.createEncryptor; + else (c = a.createDecryptor), (this._minBufferSize = 1); + this._mode = c.call(a, this, b && b.words); + }, + _doProcessBlock: function (a, b) { + this._mode.processBlock(a, b); + }, + _doFinalize: function () { + var a = this.cfg.padding; + if (this._xformMode == this._ENC_XFORM_MODE) { + a.pad(this._data, this.blockSize); + var b = this._process(!0); + } else (b = this._process(!0)), a.unpad(b); + return b; + }, + blockSize: 4, + }); + var n = (d.CipherParams = l.extend({ + init: function (a) { + this.mixIn(a); + }, + toString: function (a) { + return (a || this.formatter).stringify(this); + }, + })), + b = ((p.format = {}).OpenSSL = { + stringify: function (a) { + var b = a.ciphertext; + a = a.salt; + return (a ? s.create([1398893684, 1701076831]).concat(a).concat(b) : b).toString(r); + }, + parse: function (a) { + a = r.parse(a); + var b = a.words; + if (1398893684 == b[0] && 1701076831 == b[1]) { + var c = s.create(b.slice(2, 4)); + b.splice(0, 4); + a.sigBytes -= 16; + } + return n.create({ ciphertext: a, salt: c }); + }, + }), + a = (d.SerializableCipher = l.extend({ + cfg: l.extend({ format: b }), + encrypt: function (a, b, c, d) { + d = this.cfg.extend(d); + var l = a.createEncryptor(c, d); + b = l.finalize(b); + l = l.cfg; + return n.create({ + ciphertext: b, + key: c, + iv: l.iv, + algorithm: a, + mode: l.mode, + padding: l.padding, + blockSize: a.blockSize, + formatter: d.format, + }); + }, + decrypt: function (a, b, c, d) { + d = this.cfg.extend(d); + b = this._parse(b, d.format); + return a.createDecryptor(c, d).finalize(b.ciphertext); + }, + _parse: function (a, b) { + return 'string' == typeof a ? b.parse(a, this) : a; + }, + })), + p = ((p.kdf = {}).OpenSSL = { + execute: function (a, b, c, d) { + d || (d = s.random(8)); + a = w.create({ keySize: b + c }).compute(a, d); + c = s.create(a.words.slice(b), 4 * c); + a.sigBytes = 4 * b; + return n.create({ key: a, iv: c, salt: d }); + }, + }), + c = (d.PasswordBasedCipher = a.extend({ + cfg: a.cfg.extend({ kdf: p }), + encrypt: function (b, c, d, l) { + l = this.cfg.extend(l); + d = l.kdf.execute(d, b.keySize, b.ivSize); + l.iv = d.iv; + b = a.encrypt.call(this, b, c, d.key, l); + b.mixIn(d); + return b; + }, + decrypt: function (b, c, d, l) { + l = this.cfg.extend(l); + c = this._parse(c, l.format); + d = l.kdf.execute(d, b.keySize, b.ivSize, c.salt); + l.iv = d.iv; + return a.decrypt.call(this, b, c, d.key, l); + }, + })); + })(); + + // AES + (function () { + for ( + var u = CryptoJS, + p = u.lib.BlockCipher, + d = u.algo, + l = [], + s = [], + t = [], + r = [], + w = [], + v = [], + b = [], + x = [], + q = [], + n = [], + a = [], + c = 0; + 256 > c; + c++ + ) + a[c] = 128 > c ? c << 1 : (c << 1) ^ 283; + for (var e = 0, j = 0, c = 0; 256 > c; c++) { + var k = j ^ (j << 1) ^ (j << 2) ^ (j << 3) ^ (j << 4), + k = (k >>> 8) ^ (k & 255) ^ 99; + l[e] = k; + s[k] = e; + var z = a[e], + F = a[z], + G = a[F], + y = (257 * a[k]) ^ (16843008 * k); + t[e] = (y << 24) | (y >>> 8); + r[e] = (y << 16) | (y >>> 16); + w[e] = (y << 8) | (y >>> 24); + v[e] = y; + y = (16843009 * G) ^ (65537 * F) ^ (257 * z) ^ (16843008 * e); + b[k] = (y << 24) | (y >>> 8); + x[k] = (y << 16) | (y >>> 16); + q[k] = (y << 8) | (y >>> 24); + n[k] = y; + e ? ((e = z ^ a[a[a[G ^ z]]]), (j ^= a[a[j]])) : (e = j = 1); + } + var H = [0, 1, 2, 4, 8, 16, 32, 64, 128, 27, 54], + d = (d.AES = p.extend({ + _doReset: function () { + for ( + var a = this._key, + c = a.words, + d = a.sigBytes / 4, + a = 4 * ((this._nRounds = d + 6) + 1), + e = (this._keySchedule = []), + j = 0; + j < a; + j++ + ) + if (j < d) e[j] = c[j]; + else { + var k = e[j - 1]; + j % d + ? 6 < d && + 4 == j % d && + (k = (l[k >>> 24] << 24) | (l[(k >>> 16) & 255] << 16) | (l[(k >>> 8) & 255] << 8) | l[k & 255]) + : ((k = (k << 8) | (k >>> 24)), + (k = (l[k >>> 24] << 24) | (l[(k >>> 16) & 255] << 16) | (l[(k >>> 8) & 255] << 8) | l[k & 255]), + (k ^= H[(j / d) | 0] << 24)); + e[j] = e[j - d] ^ k; + } + c = this._invKeySchedule = []; + for (d = 0; d < a; d++) + (j = a - d), + (k = d % 4 ? e[j] : e[j - 4]), + (c[d] = + 4 > d || 4 >= j ? k : b[l[k >>> 24]] ^ x[l[(k >>> 16) & 255]] ^ q[l[(k >>> 8) & 255]] ^ n[l[k & 255]]); + }, + encryptBlock: function (a, b) { + this._doCryptBlock(a, b, this._keySchedule, t, r, w, v, l); + }, + decryptBlock: function (a, c) { + var d = a[c + 1]; + a[c + 1] = a[c + 3]; + a[c + 3] = d; + this._doCryptBlock(a, c, this._invKeySchedule, b, x, q, n, s); + d = a[c + 1]; + a[c + 1] = a[c + 3]; + a[c + 3] = d; + }, + _doCryptBlock: function (a, b, c, d, e, j, l, f) { + for ( + var m = this._nRounds, + g = a[b] ^ c[0], + h = a[b + 1] ^ c[1], + k = a[b + 2] ^ c[2], + n = a[b + 3] ^ c[3], + p = 4, + r = 1; + r < m; + r++ + ) + var q = d[g >>> 24] ^ e[(h >>> 16) & 255] ^ j[(k >>> 8) & 255] ^ l[n & 255] ^ c[p++], + s = d[h >>> 24] ^ e[(k >>> 16) & 255] ^ j[(n >>> 8) & 255] ^ l[g & 255] ^ c[p++], + t = d[k >>> 24] ^ e[(n >>> 16) & 255] ^ j[(g >>> 8) & 255] ^ l[h & 255] ^ c[p++], + n = d[n >>> 24] ^ e[(g >>> 16) & 255] ^ j[(h >>> 8) & 255] ^ l[k & 255] ^ c[p++], + g = q, + h = s, + k = t; + q = ((f[g >>> 24] << 24) | (f[(h >>> 16) & 255] << 16) | (f[(k >>> 8) & 255] << 8) | f[n & 255]) ^ c[p++]; + s = ((f[h >>> 24] << 24) | (f[(k >>> 16) & 255] << 16) | (f[(n >>> 8) & 255] << 8) | f[g & 255]) ^ c[p++]; + t = ((f[k >>> 24] << 24) | (f[(n >>> 16) & 255] << 16) | (f[(g >>> 8) & 255] << 8) | f[h & 255]) ^ c[p++]; + n = ((f[n >>> 24] << 24) | (f[(g >>> 16) & 255] << 16) | (f[(h >>> 8) & 255] << 8) | f[k & 255]) ^ c[p++]; + a[b] = q; + a[b + 1] = s; + a[b + 2] = t; + a[b + 3] = n; + }, + keySize: 8, + })); + u.AES = p._createHelper(d); + })(); + + // Mode ECB + CryptoJS.mode.ECB = (function () { + var ECB = CryptoJS.lib.BlockCipherMode.extend(); + + ECB.Encryptor = ECB.extend({ + processBlock: function (words, offset) { + this._cipher.encryptBlock(words, offset); + }, + }); + + ECB.Decryptor = ECB.extend({ + processBlock: function (words, offset) { + this._cipher.decryptBlock(words, offset); + }, + }); + + return ECB; + })(); + + var hmacSha256 = CryptoJS; + + var CryptoJS$1 = /*@__PURE__*/getDefaultExportFromCjs(hmacSha256); + + /** + * AES-CBC cryptor module. + */ + /** + * AES-CBC cryptor. + * + * AES-CBC cryptor with enhanced cipher strength. + */ + class AesCbcCryptor { + constructor({ cipherKey }) { + this.cipherKey = cipherKey; + this.CryptoJS = CryptoJS$1; + this.encryptedKey = this.CryptoJS.SHA256(cipherKey); + } + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + // region Encryption + encrypt(data) { + const stringData = typeof data === 'string' ? data : AesCbcCryptor.decoder.decode(data); + if (stringData.length === 0) + throw new Error('encryption error. empty content'); + const abIv = this.getIv(); + return { + metadata: abIv, + data: decode(this.CryptoJS.AES.encrypt(data, this.encryptedKey, { + iv: this.bufferToWordArray(abIv), + mode: this.CryptoJS.mode.CBC, + }).ciphertext.toString(this.CryptoJS.enc.Base64)), + }; + } + encryptFileData(data) { + return __awaiter(this, void 0, void 0, function* () { + const key = yield this.getKey(); + const iv = this.getIv(); + return { + data: yield crypto.subtle.encrypt({ name: this.algo, iv: iv }, key, data), + metadata: iv, + }; + }); + } + // endregion + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + // region Decryption + decrypt(encryptedData) { + if (typeof encryptedData.data === 'string') + throw new Error('Decryption error: data for decryption should be ArrayBuffed.'); + const iv = this.bufferToWordArray(new Uint8ClampedArray(encryptedData.metadata)); + const data = this.bufferToWordArray(new Uint8ClampedArray(encryptedData.data)); + return AesCbcCryptor.encoder.encode(this.CryptoJS.AES.decrypt({ ciphertext: data }, this.encryptedKey, { + iv, + mode: this.CryptoJS.mode.CBC, + }).toString(this.CryptoJS.enc.Utf8)).buffer; + } + decryptFileData(encryptedData) { + return __awaiter(this, void 0, void 0, function* () { + if (typeof encryptedData.data === 'string') + throw new Error('Decryption error: data for decryption should be ArrayBuffed.'); + const key = yield this.getKey(); + return crypto.subtle.decrypt({ name: this.algo, iv: encryptedData.metadata }, key, encryptedData.data); + }); + } + // endregion + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + // region Helpers + get identifier() { + return 'ACRH'; + } + /** + * Cryptor algorithm. + * + * @returns Cryptor module algorithm. + */ + get algo() { + return 'AES-CBC'; + } + /** + * Generate random initialization vector. + * + * @returns Random initialization vector. + */ + getIv() { + return crypto.getRandomValues(new Uint8Array(AesCbcCryptor.BLOCK_SIZE)); + } + /** + * Convert cipher key to the {@link Buffer}. + * + * @returns SHA256 encoded cipher key {@link Buffer}. + */ + getKey() { + return __awaiter(this, void 0, void 0, function* () { + const bKey = AesCbcCryptor.encoder.encode(this.cipherKey); + const abHash = yield crypto.subtle.digest('SHA-256', bKey.buffer); + return crypto.subtle.importKey('raw', abHash, this.algo, true, ['encrypt', 'decrypt']); + }); + } + /** + * Convert bytes array to words array. + * + * @param b - Bytes array (buffer) which should be converted. + * + * @returns Word sized array. + */ + bufferToWordArray(b) { + const wa = []; + let i; + for (i = 0; i < b.length; i += 1) { + wa[(i / 4) | 0] |= b[i] << (24 - 8 * i); + } + return this.CryptoJS.lib.WordArray.create(wa, b.length); + } + } + /** + * Cryptor block size. + */ + AesCbcCryptor.BLOCK_SIZE = 16; + /** + * {@link string|String} to {@link ArrayBuffer} response decoder. + */ + AesCbcCryptor.encoder = new TextEncoder(); + /** + * {@link ArrayBuffer} to {@link string} decoder. + */ + AesCbcCryptor.decoder = new TextDecoder(); + + /** + * Legacy cryptography module. + */ + /** + * Convert bytes array to words array. + * + * @param b - Bytes array (buffer) which should be converted. + * + * @returns Word sized array. + */ + /* eslint-disable @typescript-eslint/no-explicit-any */ + function bufferToWordArray(b) { + const wa = []; + let i; + for (i = 0; i < b.length; i += 1) { + wa[(i / 4) | 0] |= b[i] << (24 - 8 * i); + } + // @ts-expect-error Bundled library without types. + return CryptoJS$1.lib.WordArray.create(wa, b.length); + } + class Crypto { + constructor(configuration) { + this.configuration = configuration; + /** + * Crypto initialization vector. + */ + this.iv = '0123456789012345'; + /** + * List os allowed cipher key encodings. + */ + this.allowedKeyEncodings = ['hex', 'utf8', 'base64', 'binary']; + /** + * Allowed cipher key lengths. + */ + this.allowedKeyLengths = [128, 256]; + /** + * Allowed crypto modes. + */ + this.allowedModes = ['ecb', 'cbc']; + this.defaultOptions = { + encryptKey: true, + keyEncoding: 'utf8', + keyLength: 256, + mode: 'cbc', + }; + } + /** + * Generate HMAC-SHA256 hash from input data. + * + * @param data - Data from which hash should be generated. + * + * @returns HMAC-SHA256 hash from provided `data`. + */ + HMACSHA256(data) { + // @ts-expect-error Bundled library without types. + const hash = CryptoJS$1.HmacSHA256(data, this.configuration.secretKey); + // @ts-expect-error Bundled library without types. + return hash.toString(CryptoJS$1.enc.Base64); + } + /** + * Generate SHA256 hash from input data. + * + * @param data - Data from which hash should be generated. + * + * @returns SHA256 hash from provided `data`. + */ + SHA256(data) { + // @ts-expect-error Bundled library without types. + return CryptoJS$1.SHA256(data).toString(CryptoJS$1.enc.Hex); + } + /** + * Encrypt provided data. + * + * @param data - Source data which should be encrypted. + * @param [customCipherKey] - Custom cipher key (different from defined on client level). + * @param [options] - Specific crypto configuration options. + * + * @returns Encrypted `data`. + */ + encrypt(data, customCipherKey, options) { + if (this.configuration.customEncrypt) + return this.configuration.customEncrypt(data); + return this.pnEncrypt(data, customCipherKey, options); + } + /** + * Decrypt provided data. + * + * @param data - Encrypted data which should be decrypted. + * @param [customCipherKey] - Custom cipher key (different from defined on client level). + * @param [options] - Specific crypto configuration options. + * + * @returns Decrypted `data`. + */ + decrypt(data, customCipherKey, options) { + if (this.configuration.customDecrypt) + return this.configuration.customDecrypt(data); + return this.pnDecrypt(data, customCipherKey, options); + } + /** + * Encrypt provided data. + * + * @param data - Source data which should be encrypted. + * @param [customCipherKey] - Custom cipher key (different from defined on client level). + * @param [options] - Specific crypto configuration options. + * + * @returns Encrypted `data` as string. + */ + pnEncrypt(data, customCipherKey, options) { + const decidedCipherKey = customCipherKey !== null && customCipherKey !== void 0 ? customCipherKey : this.configuration.cipherKey; + if (!decidedCipherKey) + return data; + options = this.parseOptions(options); + const mode = this.getMode(options); + const cipherKey = this.getPaddedKey(decidedCipherKey, options); + if (this.configuration.useRandomIVs) { + const waIv = this.getRandomIV(); + // @ts-expect-error Bundled library without types. + const waPayload = CryptoJS$1.AES.encrypt(data, cipherKey, { iv: waIv, mode }).ciphertext; + // @ts-expect-error Bundled library without types. + return waIv.clone().concat(waPayload.clone()).toString(CryptoJS$1.enc.Base64); + } + const iv = this.getIV(options); + // @ts-expect-error Bundled library without types. + const encryptedHexArray = CryptoJS$1.AES.encrypt(data, cipherKey, { iv, mode }).ciphertext; + // @ts-expect-error Bundled library without types. + const base64Encrypted = encryptedHexArray.toString(CryptoJS$1.enc.Base64); + return base64Encrypted || data; + } + /** + * Decrypt provided data. + * + * @param data - Encrypted data which should be decrypted. + * @param [customCipherKey] - Custom cipher key (different from defined on client level). + * @param [options] - Specific crypto configuration options. + * + * @returns Decrypted `data`. + */ + pnDecrypt(data, customCipherKey, options) { + const decidedCipherKey = customCipherKey !== null && customCipherKey !== void 0 ? customCipherKey : this.configuration.cipherKey; + if (!decidedCipherKey) + return data; + options = this.parseOptions(options); + const mode = this.getMode(options); + const cipherKey = this.getPaddedKey(decidedCipherKey, options); + if (this.configuration.useRandomIVs) { + const ciphertext = new Uint8ClampedArray(decode(data)); + const iv = bufferToWordArray(ciphertext.slice(0, 16)); + const payload = bufferToWordArray(ciphertext.slice(16)); + try { + // @ts-expect-error Bundled library without types. + const plainJSON = CryptoJS$1.AES.decrypt({ ciphertext: payload }, cipherKey, { iv, mode }).toString( + // @ts-expect-error Bundled library without types. + CryptoJS$1.enc.Utf8); + return JSON.parse(plainJSON); + } + catch (e) { + return null; + } + } + else { + const iv = this.getIV(options); + try { + // @ts-expect-error Bundled library without types. + const ciphertext = CryptoJS$1.enc.Base64.parse(data); + // @ts-expect-error Bundled library without types. + const plainJSON = CryptoJS$1.AES.decrypt({ ciphertext }, cipherKey, { iv, mode }).toString(CryptoJS$1.enc.Utf8); + return JSON.parse(plainJSON); + } + catch (e) { + return null; + } + } + } + /** + * Pre-process provided custom crypto configuration. + * + * @param incomingOptions - Configuration which should be pre-processed before use. + * + * @returns Normalized crypto configuration options. + */ + parseOptions(incomingOptions) { + var _a, _b, _c, _d; + if (!incomingOptions) + return this.defaultOptions; + // Defaults + const options = { + encryptKey: (_a = incomingOptions.encryptKey) !== null && _a !== void 0 ? _a : this.defaultOptions.encryptKey, + keyEncoding: (_b = incomingOptions.keyEncoding) !== null && _b !== void 0 ? _b : this.defaultOptions.keyEncoding, + keyLength: (_c = incomingOptions.keyLength) !== null && _c !== void 0 ? _c : this.defaultOptions.keyLength, + mode: (_d = incomingOptions.mode) !== null && _d !== void 0 ? _d : this.defaultOptions.mode, + }; + // Validation + if (this.allowedKeyEncodings.indexOf(options.keyEncoding.toLowerCase()) === -1) + options.keyEncoding = this.defaultOptions.keyEncoding; + if (this.allowedKeyLengths.indexOf(options.keyLength) === -1) + options.keyLength = this.defaultOptions.keyLength; + if (this.allowedModes.indexOf(options.mode.toLowerCase()) === -1) + options.mode = this.defaultOptions.mode; + return options; + } + /** + * Decode provided cipher key. + * + * @param key - Key in `encoding` provided by `options`. + * @param options - Crypto configuration options with cipher key details. + * + * @returns Array buffer with decoded key. + */ + decodeKey(key, options) { + // @ts-expect-error Bundled library without types. + if (options.keyEncoding === 'base64') + return CryptoJS$1.enc.Base64.parse(key); + // @ts-expect-error Bundled library without types. + if (options.keyEncoding === 'hex') + return CryptoJS$1.enc.Hex.parse(key); + return key; + } + /** + * Add padding to the cipher key. + * + * @param key - Key which should be padded. + * @param options - Crypto configuration options with cipher key details. + * + * @returns Properly padded cipher key. + */ + getPaddedKey(key, options) { + key = this.decodeKey(key, options); + // @ts-expect-error Bundled library without types. + if (options.encryptKey) + return CryptoJS$1.enc.Utf8.parse(this.SHA256(key).slice(0, 32)); + return key; + } + /** + * Cipher mode. + * + * @param options - Crypto configuration with information about cipher mode. + * + * @returns Crypto cipher mode. + */ + getMode(options) { + // @ts-expect-error Bundled library without types. + if (options.mode === 'ecb') + return CryptoJS$1.mode.ECB; + // @ts-expect-error Bundled library without types. + return CryptoJS$1.mode.CBC; + } + /** + * Cipher initialization vector. + * + * @param options - Crypto configuration with information about cipher mode. + * + * @returns Initialization vector. + */ + getIV(options) { + // @ts-expect-error Bundled library without types. + return options.mode === 'cbc' ? CryptoJS$1.enc.Utf8.parse(this.iv) : null; + } + /** + * Random initialization vector. + * + * @returns Generated random initialization vector. + */ + getRandomIV() { + // @ts-expect-error Bundled library without types. + return CryptoJS$1.lib.WordArray.random(16); + } + } + + /* global crypto */ + /** + * Legacy browser cryptography module. + */ + function concatArrayBuffer(ab1, ab2) { + const tmp = new Uint8Array(ab1.byteLength + ab2.byteLength); + tmp.set(new Uint8Array(ab1), 0); + tmp.set(new Uint8Array(ab2), ab1.byteLength); + return tmp.buffer; + } + /** + * Legacy cryptography implementation for browser-based {@link PubNub} client. + */ + class WebCryptography { + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + // region Encryption + /** + * Encrypt provided source data using specific encryption {@link key}. + * + * @param key - Data encryption key.
**Note:** Same key should be used to `decrypt` data. + * @param input - Source data for encryption. + * + * @returns Encrypted data as object or stream (depending on from source data type). + * + * @throws Error if unknown data type has been passed. + */ + encrypt(key, input) { + return __awaiter(this, void 0, void 0, function* () { + if (!(input instanceof ArrayBuffer) && typeof input !== 'string') + throw new Error('Cannot encrypt this file. In browsers file encryption supports only string or ArrayBuffer'); + const cKey = yield this.getKey(key); + return input instanceof ArrayBuffer ? this.encryptArrayBuffer(cKey, input) : this.encryptString(cKey, input); + }); + } + /** + * Encrypt provided source {@link Buffer} using specific encryption {@link ArrayBuffer}. + * + * @param key - Data encryption key.
**Note:** Same key should be used to `decrypt` {@link ArrayBuffer}. + * @param buffer - Source {@link ArrayBuffer} for encryption. + * + * @returns Encrypted data as {@link ArrayBuffer} object. + */ + encryptArrayBuffer(key, buffer) { + return __awaiter(this, void 0, void 0, function* () { + const abIv = crypto.getRandomValues(new Uint8Array(16)); + return concatArrayBuffer(abIv.buffer, yield crypto.subtle.encrypt({ name: 'AES-CBC', iv: abIv }, key, buffer)); + }); + } + /** + * Encrypt provided source {@link string} using specific encryption {@link key}. + * + * @param key - Data encryption key.
**Note:** Same key should be used to `decrypt` {@link string}. + * @param text - Source {@link string} for encryption. + * + * @returns Encrypted data as byte {@link string}. + */ + encryptString(key, text) { + return __awaiter(this, void 0, void 0, function* () { + const abIv = crypto.getRandomValues(new Uint8Array(16)); + const abPlaintext = WebCryptography.encoder.encode(text).buffer; + const abPayload = yield crypto.subtle.encrypt({ name: 'AES-CBC', iv: abIv }, key, abPlaintext); + const ciphertext = concatArrayBuffer(abIv.buffer, abPayload); + return WebCryptography.decoder.decode(ciphertext); + }); + } + /** + * Encrypt provided {@link PubNub} File object using specific encryption {@link key}. + * + * @param key - Key for {@link PubNub} File object encryption.
**Note:** Same key should be + * used to `decrypt` data. + * @param file - Source {@link PubNub} File object for encryption. + * @param File - Class constructor for {@link PubNub} File object. + * + * @returns Encrypted data as {@link PubNub} File object. + * + * @throws Error if file is empty or contains unsupported data type. + */ + encryptFile(key, file, File) { + return __awaiter(this, void 0, void 0, function* () { + var _a, _b; + if (((_a = file.contentLength) !== null && _a !== void 0 ? _a : 0) <= 0) + throw new Error('encryption error. empty content'); + const bKey = yield this.getKey(key); + const abPlaindata = yield file.toArrayBuffer(); + const abCipherdata = yield this.encryptArrayBuffer(bKey, abPlaindata); + return File.create({ + name: file.name, + mimeType: (_b = file.mimeType) !== null && _b !== void 0 ? _b : 'application/octet-stream', + data: abCipherdata, + }); + }); + } + // endregion + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + // region Decryption + /** + * Decrypt provided encrypted data using specific decryption {@link key}. + * + * @param key - Data decryption key.
**Note:** Should be the same as used to `encrypt` data. + * @param input - Encrypted data for decryption. + * + * @returns Decrypted data as object or stream (depending on from encrypted data type). + * + * @throws Error if unknown data type has been passed. + */ + decrypt(key, input) { + return __awaiter(this, void 0, void 0, function* () { + if (!(input instanceof ArrayBuffer) && typeof input !== 'string') + throw new Error('Cannot decrypt this file. In browsers file decryption supports only string or ArrayBuffer'); + const cKey = yield this.getKey(key); + return input instanceof ArrayBuffer ? this.decryptArrayBuffer(cKey, input) : this.decryptString(cKey, input); + }); + } + /** + * Decrypt provided encrypted {@link ArrayBuffer} using specific decryption {@link key}. + * + * @param key - Data decryption key.
**Note:** Should be the same as used to `encrypt` {@link ArrayBuffer}. + * @param buffer - Encrypted {@link ArrayBuffer} for decryption. + * + * @returns Decrypted data as {@link ArrayBuffer} object. + */ + decryptArrayBuffer(key, buffer) { + return __awaiter(this, void 0, void 0, function* () { + const abIv = buffer.slice(0, 16); + if (buffer.slice(WebCryptography.IV_LENGTH).byteLength <= 0) + throw new Error('decryption error: empty content'); + return yield crypto.subtle.decrypt({ name: 'AES-CBC', iv: abIv }, key, buffer.slice(WebCryptography.IV_LENGTH)); + }); + } + /** + * Decrypt provided encrypted {@link string} using specific decryption {@link key}. + * + * @param key - Data decryption key.
**Note:** Should be the same as used to `encrypt` {@link string}. + * @param text - Encrypted {@link string} for decryption. + * + * @returns Decrypted data as byte {@link string}. + */ + decryptString(key, text) { + return __awaiter(this, void 0, void 0, function* () { + const abCiphertext = WebCryptography.encoder.encode(text).buffer; + const abIv = abCiphertext.slice(0, 16); + const abPayload = abCiphertext.slice(16); + const abPlaintext = yield crypto.subtle.decrypt({ name: 'AES-CBC', iv: abIv }, key, abPayload); + return WebCryptography.decoder.decode(abPlaintext); + }); + } + /** + * Decrypt provided {@link PubNub} File object using specific decryption {@link key}. + * + * @param key - Key for {@link PubNub} File object decryption.
**Note:** Should be the same + * as used to `encrypt` data. + * @param file - Encrypted {@link PubNub} File object for decryption. + * @param File - Class constructor for {@link PubNub} File object. + * + * @returns Decrypted data as {@link PubNub} File object. + * + * @throws Error if file is empty or contains unsupported data type. + */ + decryptFile(key, file, File) { + return __awaiter(this, void 0, void 0, function* () { + const bKey = yield this.getKey(key); + const abCipherdata = yield file.toArrayBuffer(); + const abPlaindata = yield this.decryptArrayBuffer(bKey, abCipherdata); + return File.create({ + name: file.name, + mimeType: file.mimeType, + data: abPlaindata, + }); + }); + } + // endregion + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + // region Helpers + /** + * Convert cipher key to the {@link Buffer}. + * + * @param key - String cipher key. + * + * @returns SHA256 HEX encoded cipher key {@link CryptoKey}. + */ + getKey(key) { + return __awaiter(this, void 0, void 0, function* () { + const digest = yield crypto.subtle.digest('SHA-256', WebCryptography.encoder.encode(key)); + const hashHex = Array.from(new Uint8Array(digest)) + .map((b) => b.toString(16).padStart(2, '0')) + .join(''); + const abKey = WebCryptography.encoder.encode(hashHex.slice(0, 32)).buffer; + return crypto.subtle.importKey('raw', abKey, 'AES-CBC', true, ['encrypt', 'decrypt']); + }); + } + } + /** + * Random initialization vector size. + */ + WebCryptography.IV_LENGTH = 16; + /** + * {@link string|String} to {@link ArrayBuffer} response decoder. + */ + WebCryptography.encoder = new TextEncoder(); + /** + * {@link ArrayBuffer} to {@link string} decoder. + */ + WebCryptography.decoder = new TextDecoder(); + + /** + * Legacy cryptor module. + */ + /** + * Legacy cryptor. + */ + class LegacyCryptor { + constructor(config) { + this.config = config; + this.cryptor = new Crypto(Object.assign({}, config)); + this.fileCryptor = new WebCryptography(); + } + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + // region Encryption + encrypt(data) { + const stringData = typeof data === 'string' ? data : LegacyCryptor.decoder.decode(data); + return { + data: this.cryptor.encrypt(stringData), + metadata: null, + }; + } + encryptFile(file, File) { + return __awaiter(this, void 0, void 0, function* () { + var _a; + if (!this.config.cipherKey) + throw new PubNubError('File encryption error: cipher key not set.'); + return this.fileCryptor.encryptFile((_a = this.config) === null || _a === void 0 ? void 0 : _a.cipherKey, file, File); + }); + } + // endregion + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + // region Decryption + decrypt(encryptedData) { + const data = typeof encryptedData.data === 'string' ? encryptedData.data : encode(encryptedData.data); + return this.cryptor.decrypt(data); + } + decryptFile(file, File) { + return __awaiter(this, void 0, void 0, function* () { + if (!this.config.cipherKey) + throw new PubNubError('File encryption error: cipher key not set.'); + return this.fileCryptor.decryptFile(this.config.cipherKey, file, File); + }); + } + // endregion + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + // region Helpers + get identifier() { + return ''; + } + } + /** + * `string` to {@link ArrayBuffer} response decoder. + */ + LegacyCryptor.encoder = new TextEncoder(); + /** + * {@link ArrayBuffer} to {@link string} decoder. + */ + LegacyCryptor.decoder = new TextDecoder(); + + /** + * Browser crypto module. + */ + /** + * CryptoModule for browser platform. + */ + class WebCryptoModule extends AbstractCryptoModule { + // -------------------------------------------------------- + // --------------- Convenience functions ------------------ + // ------------------------------------------------------- + // region Convenience functions + static legacyCryptoModule(config) { + var _a; + if (!config.cipherKey) + throw new PubNubError('Crypto module error: cipher key not set.'); + return new WebCryptoModule({ + default: new LegacyCryptor(Object.assign(Object.assign({}, config), { useRandomIVs: (_a = config.useRandomIVs) !== null && _a !== void 0 ? _a : true })), + cryptors: [new AesCbcCryptor({ cipherKey: config.cipherKey })], + }); + } + static aesCbcCryptoModule(config) { + var _a; + if (!config.cipherKey) + throw new PubNubError('Crypto module error: cipher key not set.'); + return new WebCryptoModule({ + default: new AesCbcCryptor({ cipherKey: config.cipherKey }), + cryptors: [ + new LegacyCryptor(Object.assign(Object.assign({}, config), { useRandomIVs: (_a = config.useRandomIVs) !== null && _a !== void 0 ? _a : true })), + ], + }); + } + /** + * Construct crypto module with `cryptor` as default for data encryption and decryption. + * + * @param defaultCryptor - Default cryptor for data encryption and decryption. + * + * @returns Crypto module with pre-configured default cryptor. + */ + static withDefaultCryptor(defaultCryptor) { + return new this({ default: defaultCryptor }); + } + // endregion + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + // region Encryption + encrypt(data) { + // Encrypt data. + const encrypted = data instanceof ArrayBuffer && this.defaultCryptor.identifier === WebCryptoModule.LEGACY_IDENTIFIER + ? this.defaultCryptor.encrypt(WebCryptoModule.decoder.decode(data)) + : this.defaultCryptor.encrypt(data); + if (!encrypted.metadata) + return encrypted.data; + else if (typeof encrypted.data === 'string') + throw new Error('Encryption error: encrypted data should be ArrayBuffed.'); + const headerData = this.getHeaderData(encrypted); + return this.concatArrayBuffer(headerData, encrypted.data); + } + encryptFile(file, File) { + return __awaiter(this, void 0, void 0, function* () { + /** + * Files handled differently in case of Legacy cryptor. + * (as long as we support legacy need to check on instance type) + */ + if (this.defaultCryptor.identifier === CryptorHeader.LEGACY_IDENTIFIER) + return this.defaultCryptor.encryptFile(file, File); + const fileData = yield this.getFileData(file); + const encrypted = yield this.defaultCryptor.encryptFileData(fileData); + if (typeof encrypted.data === 'string') + throw new Error('Encryption error: encrypted data should be ArrayBuffed.'); + return File.create({ + name: file.name, + mimeType: 'application/octet-stream', + data: this.concatArrayBuffer(this.getHeaderData(encrypted), encrypted.data), + }); + }); + } + // endregion + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + // region Decryption + decrypt(data) { + const encryptedData = typeof data === 'string' ? decode(data) : data; + const header = CryptorHeader.tryParse(encryptedData); + const cryptor = this.getCryptor(header); + const metadata = header.length > 0 + ? encryptedData.slice(header.length - header.metadataLength, header.length) + : null; + if (encryptedData.slice(header.length).byteLength <= 0) + throw new Error('Decryption error: empty content'); + return cryptor.decrypt({ + data: encryptedData.slice(header.length), + metadata: metadata, + }); + } + decryptFile(file, File) { + return __awaiter(this, void 0, void 0, function* () { + const data = yield file.data.arrayBuffer(); + const header = CryptorHeader.tryParse(data); + const cryptor = this.getCryptor(header); + /** + * Files handled differently in case of Legacy cryptor. + * (as long as we support legacy need to check on instance type) + */ + if ((cryptor === null || cryptor === void 0 ? void 0 : cryptor.identifier) === CryptorHeader.LEGACY_IDENTIFIER) + return cryptor.decryptFile(file, File); + const fileData = yield this.getFileData(data); + const metadata = fileData.slice(header.length - header.metadataLength, header.length); + return File.create({ + name: file.name, + data: yield this.defaultCryptor.decryptFileData({ + data: data.slice(header.length), + metadata: metadata, + }), + }); + }); + } + // endregion + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + // region Helpers + /** + * Retrieve registered cryptor by its identifier. + * + * @param id - Unique cryptor identifier. + * + * @returns Registered cryptor with specified identifier. + * + * @throws Error if cryptor with specified {@link id} can't be found. + */ + getCryptorFromId(id) { + const cryptor = this.getAllCryptors().find((cryptor) => id === cryptor.identifier); + if (cryptor) + return cryptor; + throw Error('Unknown cryptor error'); + } + /** + * Retrieve cryptor by its identifier. + * + * @param header - Header with cryptor-defined data or raw cryptor identifier. + * + * @returns Cryptor which correspond to provided {@link header}. + */ + getCryptor(header) { + if (typeof header === 'string') { + const cryptor = this.getAllCryptors().find((cryptor) => cryptor.identifier === header); + if (cryptor) + return cryptor; + throw new Error('Unknown cryptor error'); + } + else if (header instanceof CryptorHeaderV1) { + return this.getCryptorFromId(header.identifier); + } + } + /** + * Create cryptor header data. + * + * @param encrypted - Encryption data object as source for header data. + * + * @returns Binary representation of the cryptor header data. + */ + getHeaderData(encrypted) { + if (!encrypted.metadata) + return; + const header = CryptorHeader.from(this.defaultCryptor.identifier, encrypted.metadata); + const headerData = new Uint8Array(header.length); + let pos = 0; + headerData.set(header.data, pos); + pos += header.length - encrypted.metadata.byteLength; + headerData.set(new Uint8Array(encrypted.metadata), pos); + return headerData.buffer; + } + /** + * Merge two {@link ArrayBuffer} instances. + * + * @param ab1 - First {@link ArrayBuffer}. + * @param ab2 - Second {@link ArrayBuffer}. + * + * @returns Merged data as {@link ArrayBuffer}. + */ + concatArrayBuffer(ab1, ab2) { + const tmp = new Uint8Array(ab1.byteLength + ab2.byteLength); + tmp.set(new Uint8Array(ab1), 0); + tmp.set(new Uint8Array(ab2), ab1.byteLength); + return tmp.buffer; + } + /** + * Retrieve file content. + * + * @param file - Content of the {@link PubNub} File object. + * + * @returns Normalized file {@link data} as {@link ArrayBuffer}; + */ + getFileData(file) { + return __awaiter(this, void 0, void 0, function* () { + if (file instanceof ArrayBuffer) + return file; + else if (file instanceof PubNubFile) + return file.toArrayBuffer(); + throw new Error('Cannot decrypt/encrypt file. In browsers file encrypt/decrypt supported for string, ArrayBuffer or Blob'); + }); + } + } + /** + * {@link LegacyCryptor|Legacy} cryptor identifier. + */ + WebCryptoModule.LEGACY_IDENTIFIER = ''; + /** + * CryptorHeader Utility + */ + class CryptorHeader { + static from(id, metadata) { + if (id === CryptorHeader.LEGACY_IDENTIFIER) + return; + return new CryptorHeaderV1(id, metadata.byteLength); + } + static tryParse(data) { + const encryptedData = new Uint8Array(data); + let sentinel; + let version = null; + if (encryptedData.byteLength >= 4) { + sentinel = encryptedData.slice(0, 4); + if (this.decoder.decode(sentinel) !== CryptorHeader.SENTINEL) + return WebCryptoModule.LEGACY_IDENTIFIER; + } + if (encryptedData.byteLength >= 5) + version = encryptedData[4]; + else + throw new Error('Decryption error: invalid header version'); + if (version > CryptorHeader.MAX_VERSION) + throw new Error('Decryption error: Unknown cryptor error'); + let identifier; + let pos = 5 + CryptorHeader.IDENTIFIER_LENGTH; + if (encryptedData.byteLength >= pos) + identifier = encryptedData.slice(5, pos); + else + throw new Error('Decryption error: invalid crypto identifier'); + let metadataLength = null; + if (encryptedData.byteLength >= pos + 1) + metadataLength = encryptedData[pos]; + else + throw new Error('Decryption error: invalid metadata length'); + pos += 1; + if (metadataLength === 255 && encryptedData.byteLength >= pos + 2) { + metadataLength = new Uint16Array(encryptedData.slice(pos, pos + 2)).reduce((acc, val) => (acc << 8) + val, 0); + } + return new CryptorHeaderV1(this.decoder.decode(identifier), metadataLength); + } + } + CryptorHeader.SENTINEL = 'PNED'; + CryptorHeader.LEGACY_IDENTIFIER = ''; + CryptorHeader.IDENTIFIER_LENGTH = 4; + CryptorHeader.VERSION = 1; + CryptorHeader.MAX_VERSION = 1; + CryptorHeader.decoder = new TextDecoder(); + // v1 CryptorHeader + class CryptorHeaderV1 { + constructor(id, metadataLength) { + this._identifier = id; + this._metadataLength = metadataLength; + } + get identifier() { + return this._identifier; + } + set identifier(value) { + this._identifier = value; + } + get metadataLength() { + return this._metadataLength; + } + set metadataLength(value) { + this._metadataLength = value; + } + get version() { + return CryptorHeader.VERSION; + } + get length() { + return (CryptorHeader.SENTINEL.length + + 1 + + CryptorHeader.IDENTIFIER_LENGTH + + (this.metadataLength < 255 ? 1 : 3) + + this.metadataLength); + } + get data() { + let pos = 0; + const header = new Uint8Array(this.length); + const encoder = new TextEncoder(); + header.set(encoder.encode(CryptorHeader.SENTINEL)); + pos += CryptorHeader.SENTINEL.length; + header[pos] = this.version; + pos++; + if (this.identifier) + header.set(encoder.encode(this.identifier), pos); + const metadataLength = this.metadataLength; + pos += CryptorHeader.IDENTIFIER_LENGTH; + if (metadataLength < 255) + header[pos] = metadataLength; + else + header.set([255, metadataLength >> 8, metadataLength & 0xff], pos); + return header; + } + } + CryptorHeaderV1.IDENTIFIER_LENGTH = 4; + CryptorHeaderV1.SENTINEL = 'PNED'; + + /** + * Percent-encode input string. + * + * **Note:** Encode content in accordance of the `PubNub` service requirements. + * + * @param input - Source string or number for encoding. + * + * @returns Percent-encoded string. + */ + const encodeString = (input) => { + return encodeURIComponent(input).replace(/[!~*'()]/g, (x) => `%${x.charCodeAt(0).toString(16).toUpperCase()}`); + }; + /** + * Percent-encode list of names (channels). + * + * @param names - List of names which should be encoded. + * + * @param [defaultString] - String which should be used in case if {@link names} is empty. + * + * @returns String which contains encoded names joined by non-encoded `,`. + */ + const encodeNames = (names, defaultString) => { + const encodedNames = names.map((name) => encodeString(name)); + return encodedNames.length ? encodedNames.join(',') : defaultString !== null && defaultString !== void 0 ? defaultString : ''; + }; + const removeSingleOccurance = (source, elementsToRemove) => { + const removed = Object.fromEntries(elementsToRemove.map((prop) => [prop, false])); + return source.filter((e) => { + if (elementsToRemove.includes(e) && !removed[e]) { + removed[e] = true; + return false; + } + return true; + }); + }; + const findUniqueCommonElements = (a, b) => { + return [...a].filter((value) => b.includes(value) && a.indexOf(value) === a.lastIndexOf(value) && b.indexOf(value) === b.lastIndexOf(value)); + }; + /** + * Transform query key / value pairs to the string. + * + * @param query - Key / value pairs of the request query parameters. + * + * @returns Stringified query key / value pairs. + */ + const queryStringFromObject = (query) => { + return Object.keys(query) + .map((key) => { + const queryValue = query[key]; + if (!Array.isArray(queryValue)) + return `${key}=${encodeString(queryValue)}`; + return queryValue.map((value) => `${key}=${encodeString(value)}`).join('&'); + }) + .join('&'); + }; + + /** + * Common browser and React Native Transport provider module. + */ + /** + * Class representing a `fetch`-based browser and React Native transport provider. + */ + class WebReactNativeTransport { + constructor(keepAlive = false, logVerbosity) { + this.keepAlive = keepAlive; + this.logVerbosity = logVerbosity; + } + makeSendable(req) { + let controller; + let abortController; + if (req.cancellable) { + abortController = new AbortController(); + controller = { + // Storing controller inside to prolong object lifetime. + abortController, + abort: () => abortController === null || abortController === void 0 ? void 0 : abortController.abort(), + }; + } + return [ + this.requestFromTransportRequest(req).then((request) => { + const start = new Date().getTime(); + this.logRequestProcessProgress(request); + /** + * Setup request timeout promise. + * + * **Note:** Native Fetch API doesn't support `timeout` out-of-box. + */ + const requestTimeout = new Promise((_, reject) => { + const timeoutId = setTimeout(() => { + // Clean up. + clearTimeout(timeoutId); + reject(new Error('Request timeout')); + }, req.timeout * 1000); + }); + return Promise.race([fetch(request, { signal: abortController === null || abortController === void 0 ? void 0 : abortController.signal }), requestTimeout]) + .then((response) => response.arrayBuffer().then((arrayBuffer) => [response, arrayBuffer])) + .then((response) => { + const responseBody = response[1].byteLength > 0 ? response[1] : undefined; + const { status, headers: requestHeaders } = response[0]; + const headers = {}; + // Copy Headers object content into plain Record. + requestHeaders.forEach((value, key) => (headers[key] = value.toLowerCase())); + const transportResponse = { + status, + url: request.url, + headers, + body: responseBody, + }; + if (status >= 400) + throw PubNubAPIError.create(transportResponse); + this.logRequestProcessProgress(request, new Date().getTime() - start, responseBody); + return transportResponse; + }) + .catch((error) => { + throw PubNubAPIError.create(error); + }); + }), + controller, + ]; + } + request(req) { + return req; + } + /** + * Creates a Request object from a given {@link TransportRequest} object. + * + * @param req - The {@link TransportRequest} object containing request information. + * + * @returns Request object generated from the {@link TransportRequest} object. + */ + requestFromTransportRequest(req) { + return __awaiter(this, void 0, void 0, function* () { + let body; + let path = req.path; + // Create multipart request body. + if (req.formData && req.formData.length > 0) { + // Reset query parameters to conform to signed URL + req.queryParameters = {}; + const file = req.body; + const formData = new FormData(); + for (const { key, value } of req.formData) + formData.append(key, value); + try { + const fileData = yield file.toArrayBuffer(); + formData.append('file', new Blob([fileData], { type: 'application/octet-stream' }), file.name); + } + catch (_) { + try { + const fileData = yield file.toFileUri(); + // @ts-expect-error React Native File Uri support. + formData.append('file', fileData, file.name); + } + catch (_) { } + } + body = formData; + } + // Handle regular body payload (if passed). + else if (req.body && (typeof req.body === 'string' || req.body instanceof ArrayBuffer)) + body = req.body; + if (req.queryParameters && Object.keys(req.queryParameters).length !== 0) + path = `${path}?${queryStringFromObject(req.queryParameters)}`; + return new Request(`${req.origin}${path}`, { + method: req.method, + headers: req.headers, + redirect: 'follow', + body, + }); + }); + } + /** + * Log out request processing progress and result. + * + * @param request - Platform-specific + * @param [elapsed] - How many seconds passed since request processing started. + * @param [body] - Service response (if available). + */ + logRequestProcessProgress(request, elapsed, body) { + if (!this.logVerbosity) + return; + const { protocol, host, pathname, search } = new URL(request.url); + const timestamp = new Date().toISOString(); + if (!elapsed) { + console.log('<<<<<'); + console.log(`[${timestamp}]`, `\n${protocol}//${host}${pathname}`, `\n${search}`); + console.log('-----'); + } + else { + const stringifiedBody = body ? WebReactNativeTransport.decoder.decode(body) : undefined; + console.log('>>>>>>'); + console.log(`[${timestamp} / ${elapsed}]`, `\n${protocol}//${host}${pathname}`, `\n${search}`, `\n${stringifiedBody}`); + console.log('-----'); + } + } + } + /** + * Service {@link ArrayBuffer} response decoder. + */ + WebReactNativeTransport.decoder = new TextDecoder(); + + function stringifyBufferKeys(obj) { + const isObject = (value) => typeof value === 'object' && value !== null && value.constructor === Object; + const isString = (value) => typeof value === 'string' || value instanceof String; + const isNumber = (value) => typeof value === 'number' && isFinite(value); + if (!isObject(obj)) + return obj; + const normalizedObject = {}; + Object.keys(obj).forEach((key) => { + const keyIsString = isString(key); + let stringifiedKey = key; + const value = obj[key]; + if (keyIsString && key.indexOf(',') >= 0) { + const bytes = key.split(',').map(Number); + stringifiedKey = bytes.reduce((string, byte) => { + return string + String.fromCharCode(byte); + }, ''); + } + else if (isNumber(key) || (keyIsString && !isNaN(Number(key)))) { + stringifiedKey = String.fromCharCode(isNumber(key) ? key : parseInt(key, 10)); + } + normalizedObject[stringifiedKey] = isObject(value) ? stringifyBufferKeys(value) : value; + }); + return normalizedObject; + } + + /** + * {@link PubNub} client configuration module. + */ + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults + /** + * Whether secured connection should be used by or not. + */ + const USE_SSL = true; + /** + * Whether PubNub client should catch up subscription after network issues. + */ + const RESTORE = false; + /** + * Whether network availability change should be announced with `PNNetworkDownCategory` and + * `PNNetworkUpCategory` state or not. + */ + const AUTO_NETWORK_DETECTION = false; + /** + * Whether messages should be de-duplicated before announcement or not. + */ + const DEDUPE_ON_SUBSCRIBE = false; + /** + * Maximum cache which should be used for message de-duplication functionality. + */ + const DEDUPE_CACHE_SIZE = 100; + /** + * Maximum number of file message publish retries. + */ + const FILE_PUBLISH_RETRY_LIMIT = 5; + /** + * Whether subscription event engine should be used or not. + */ + const ENABLE_EVENT_ENGINE = false; + /** + * Whether configured user presence state should be maintained by the PubNub client or not. + */ + const MAINTAIN_PRESENCE_STATE = true; + /** + * Whether PubNub client should try to utilize existing TCP connection for new requests or not. + */ + const KEEP_ALIVE$1 = false; + /** + * Whether verbose logging should be enabled or not. + */ + const USE_VERBOSE_LOGGING = false; + /** + * Whether leave events should be suppressed or not. + */ + const SUPPRESS_LEAVE_EVENTS = false; + /** + * Whether heartbeat request failure should be announced or not. + */ + const ANNOUNCE_HEARTBEAT_FAILURE = true; + /** + * Whether heartbeat request success should be announced or not. + */ + const ANNOUNCE_HEARTBEAT_SUCCESS = false; + /** + * Whether PubNub client instance id should be added to the requests or not. + */ + const USE_INSTANCE_ID = false; + /** + * Whether unique identifier should be added to the request or not. + */ + const USE_REQUEST_ID = true; + /** + * Transactional requests timeout. + */ + const TRANSACTIONAL_REQUEST_TIMEOUT = 15; + /** + * Subscription request timeout. + */ + const SUBSCRIBE_REQUEST_TIMEOUT = 310; + /** + * Default user presence timeout. + */ + const PRESENCE_TIMEOUT = 300; + /** + * Minimum user presence timeout. + */ + const PRESENCE_TIMEOUT_MINIMUM = 20; + /** + * Apply configuration default values. + * + * @param configuration - User-provided configuration. + */ + const setDefaults$1 = (configuration) => { + var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q; + // Copy configuration. + const configurationCopy = Object.assign({}, configuration); + (_a = configurationCopy.logVerbosity) !== null && _a !== void 0 ? _a : (configurationCopy.logVerbosity = USE_VERBOSE_LOGGING); + (_b = configurationCopy.ssl) !== null && _b !== void 0 ? _b : (configurationCopy.ssl = USE_SSL); + (_c = configurationCopy.transactionalRequestTimeout) !== null && _c !== void 0 ? _c : (configurationCopy.transactionalRequestTimeout = TRANSACTIONAL_REQUEST_TIMEOUT); + (_d = configurationCopy.subscribeRequestTimeout) !== null && _d !== void 0 ? _d : (configurationCopy.subscribeRequestTimeout = SUBSCRIBE_REQUEST_TIMEOUT); + (_e = configurationCopy.restore) !== null && _e !== void 0 ? _e : (configurationCopy.restore = RESTORE); + (_f = configurationCopy.useInstanceId) !== null && _f !== void 0 ? _f : (configurationCopy.useInstanceId = USE_INSTANCE_ID); + (_g = configurationCopy.suppressLeaveEvents) !== null && _g !== void 0 ? _g : (configurationCopy.suppressLeaveEvents = SUPPRESS_LEAVE_EVENTS); + (_h = configurationCopy.requestMessageCountThreshold) !== null && _h !== void 0 ? _h : (configurationCopy.requestMessageCountThreshold = DEDUPE_CACHE_SIZE); + (_j = configurationCopy.autoNetworkDetection) !== null && _j !== void 0 ? _j : (configurationCopy.autoNetworkDetection = AUTO_NETWORK_DETECTION); + (_k = configurationCopy.enableEventEngine) !== null && _k !== void 0 ? _k : (configurationCopy.enableEventEngine = ENABLE_EVENT_ENGINE); + (_l = configurationCopy.maintainPresenceState) !== null && _l !== void 0 ? _l : (configurationCopy.maintainPresenceState = MAINTAIN_PRESENCE_STATE); + (_m = configurationCopy.keepAlive) !== null && _m !== void 0 ? _m : (configurationCopy.keepAlive = KEEP_ALIVE$1); + if (configurationCopy.userId && configurationCopy.uuid) + throw new PubNubError("PubNub client configuration error: use only 'userId'"); + (_o = configurationCopy.userId) !== null && _o !== void 0 ? _o : (configurationCopy.userId = configurationCopy.uuid); + if (!configurationCopy.userId) + throw new PubNubError("PubNub client configuration error: 'userId' not set"); + else if (((_p = configurationCopy.userId) === null || _p === void 0 ? void 0 : _p.trim().length) === 0) + throw new PubNubError("PubNub client configuration error: 'userId' is empty"); + // Generate default origin subdomains. + if (!configurationCopy.origin) + configurationCopy.origin = Array.from({ length: 20 }, (_, i) => `ps${i + 1}.pndsn.com`); + const keySet = { + subscribeKey: configurationCopy.subscribeKey, + publishKey: configurationCopy.publishKey, + secretKey: configurationCopy.secretKey, + }; + if (configurationCopy.presenceTimeout !== undefined && configurationCopy.presenceTimeout < PRESENCE_TIMEOUT_MINIMUM) { + configurationCopy.presenceTimeout = PRESENCE_TIMEOUT_MINIMUM; + // eslint-disable-next-line no-console + console.log('WARNING: Presence timeout is less than the minimum. Using minimum value: ', PRESENCE_TIMEOUT_MINIMUM); + } + (_q = configurationCopy.presenceTimeout) !== null && _q !== void 0 ? _q : (configurationCopy.presenceTimeout = PRESENCE_TIMEOUT); + // Apply extended configuration defaults. + let announceSuccessfulHeartbeats = ANNOUNCE_HEARTBEAT_SUCCESS; + let announceFailedHeartbeats = ANNOUNCE_HEARTBEAT_FAILURE; + let fileUploadPublishRetryLimit = FILE_PUBLISH_RETRY_LIMIT; + let dedupeOnSubscribe = DEDUPE_ON_SUBSCRIBE; + const maximumCacheSize = DEDUPE_CACHE_SIZE; + let useRequestId = USE_REQUEST_ID; + // @ts-expect-error Not documented legacy configuration options. + if (configurationCopy.dedupeOnSubscribe !== undefined && typeof configurationCopy.dedupeOnSubscribe === 'boolean') { + // @ts-expect-error Not documented legacy configuration options. + dedupeOnSubscribe = configurationCopy.dedupeOnSubscribe; + } + // @ts-expect-error Not documented legacy configuration options. + if (configurationCopy.useRequestId !== undefined && typeof configurationCopy.useRequestId === 'boolean') { + // @ts-expect-error Not documented legacy configuration options. + useRequestId = configurationCopy.useRequestId; + } + if ( + // @ts-expect-error Not documented legacy configuration options. + configurationCopy.announceSuccessfulHeartbeats !== undefined && + // @ts-expect-error Not documented legacy configuration options. + typeof configurationCopy.announceSuccessfulHeartbeats === 'boolean') { + // @ts-expect-error Not documented legacy configuration options. + announceSuccessfulHeartbeats = configurationCopy.announceSuccessfulHeartbeats; + } + if ( + // @ts-expect-error Not documented legacy configuration options. + configurationCopy.announceFailedHeartbeats !== undefined && + // @ts-expect-error Not documented legacy configuration options. + typeof configurationCopy.announceFailedHeartbeats === 'boolean') { + // @ts-expect-error Not documented legacy configuration options. + announceFailedHeartbeats = configurationCopy.announceFailedHeartbeats; + } + if ( + // @ts-expect-error Not documented legacy configuration options. + configurationCopy.fileUploadPublishRetryLimit !== undefined && + // @ts-expect-error Not documented legacy configuration options. + typeof configurationCopy.fileUploadPublishRetryLimit === 'number') { + // @ts-expect-error Not documented legacy configuration options. + fileUploadPublishRetryLimit = configurationCopy.fileUploadPublishRetryLimit; + } + return Object.assign(Object.assign({}, configurationCopy), { keySet, + dedupeOnSubscribe, + maximumCacheSize, + useRequestId, + announceSuccessfulHeartbeats, + announceFailedHeartbeats, + fileUploadPublishRetryLimit }); + }; + + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults + /** + * Whether PubNub client should update its state using browser's reachability events or not. + * + * If the browser fails to detect the network changes from Wi-Fi to LAN and vice versa, or you get + * reconnection issues, set the flag to `false`. This allows the SDK reconnection logic to take over. + */ + const LISTEN_TO_BROWSER_NETWORK_EVENTS = true; + /** + * Whether PubNub client should spawn `Subscription` service worker for better user presence + * experience or not. + */ + const ENABLE_SERVICE_WORKER = false; + /** + * Whether PubNub client should try to utilize existing TCP connection for new requests or not. + */ + const KEEP_ALIVE = true; + /** + * Apply configuration default values. + * + * @param configuration - User-provided configuration. + */ + const setDefaults = (configuration) => { + var _a, _b, _c, _d; + // Force disable service workers if environment doesn't support them. + if (((_a = configuration.enableServiceWorker) !== null && _a !== void 0 ? _a : ENABLE_SERVICE_WORKER) && !('serviceWorker' in navigator)) + configuration.enableServiceWorker = false; + return Object.assign(Object.assign({}, setDefaults$1(configuration)), { + // Set platform-specific options. + listenToBrowserNetworkEvents: (_b = configuration.listenToBrowserNetworkEvents) !== null && _b !== void 0 ? _b : LISTEN_TO_BROWSER_NETWORK_EVENTS, enableServiceWorker: (_c = configuration.enableServiceWorker) !== null && _c !== void 0 ? _c : ENABLE_SERVICE_WORKER, keepAlive: (_d = configuration.keepAlive) !== null && _d !== void 0 ? _d : KEEP_ALIVE }); + }; + + var uuid = {exports: {}}; + + /*! lil-uuid - v0.1 - MIT License - https://github.com/lil-js/uuid */ + uuid.exports; + + (function (module, exports) { + (function (root, factory) { + { + factory(exports); + if (module !== null) { + module.exports = exports.uuid; + } + } + }(commonjsGlobal, function (exports) { + var VERSION = '0.1.0'; + var uuidRegex = { + '3': /^[0-9A-F]{8}-[0-9A-F]{4}-3[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}$/i, + '4': /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i, + '5': /^[0-9A-F]{8}-[0-9A-F]{4}-5[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i, + all: /^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i + }; + + function uuid() { + var uuid = '', i, random; + for (i = 0; i < 32; i++) { + random = Math.random() * 16 | 0; + if (i === 8 || i === 12 || i === 16 || i === 20) uuid += '-'; + uuid += (i === 12 ? 4 : (i === 16 ? (random & 3 | 8) : random)).toString(16); + } + return uuid + } + + function isUUID(str, version) { + var pattern = uuidRegex[version || 'all']; + return pattern && pattern.test(str) || false + } + + uuid.isUUID = isUUID; + uuid.VERSION = VERSION; + + exports.uuid = uuid; + exports.isUUID = isUUID; + })); + } (uuid, uuid.exports)); + + var uuidExports = uuid.exports; + var uuidGenerator$1 = /*@__PURE__*/getDefaultExportFromCjs(uuidExports); + + var uuidGenerator = { + createUUID() { + if (uuidGenerator$1.uuid) { + return uuidGenerator$1.uuid(); + } + // @ts-expect-error Depending on module type it may be callable. + return uuidGenerator$1(); + }, + }; + + /** + * {@link PubNub} client configuration module. + */ + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults + /** + * Whether encryption (if set) should use random initialization vector or not. + */ + const USE_RANDOM_INITIALIZATION_VECTOR = true; + /** + * Create {@link PubNub} client private configuration object. + * + * @param base - User- and platform-provided configuration. + * @param setupCryptoModule - Platform-provided {@link CryptoModule} configuration block. + * + * @returns `PubNub` client private configuration. + */ + const makeConfiguration = (base, setupCryptoModule) => { + var _a, _b, _c; + // Ensure that retry policy has proper configuration (if has been set). + (_a = base.retryConfiguration) === null || _a === void 0 ? void 0 : _a.validate(); + (_b = base.useRandomIVs) !== null && _b !== void 0 ? _b : (base.useRandomIVs = USE_RANDOM_INITIALIZATION_VECTOR); + // Override origin value. + base.origin = standardOrigin((_c = base.ssl) !== null && _c !== void 0 ? _c : false, base.origin); + const cryptoModule = base.cryptoModule; + if (cryptoModule) + delete base.cryptoModule; + const clientConfiguration = Object.assign(Object.assign({}, base), { _pnsdkSuffix: {}, _instanceId: `pn-${uuidGenerator.createUUID()}`, _cryptoModule: undefined, _cipherKey: undefined, _setupCryptoModule: setupCryptoModule, get instanceId() { + if (this.useInstanceId) + return this._instanceId; + return undefined; + }, + getUserId() { + return this.userId; + }, + setUserId(value) { + if (!value || typeof value !== 'string' || value.trim().length === 0) + throw new Error('Missing or invalid userId parameter. Provide a valid string userId'); + this.userId = value; + }, + getAuthKey() { + return this.authKey; + }, + setAuthKey(authKey) { + this.authKey = authKey; + }, + getFilterExpression() { + return this.filterExpression; + }, + setFilterExpression(expression) { + this.filterExpression = expression; + }, + getCipherKey() { + return this._cipherKey; + }, + setCipherKey(key) { + this._cipherKey = key; + if (!key && this._cryptoModule) { + this._cryptoModule = undefined; + return; + } + else if (!key || !this._setupCryptoModule) + return; + this._cryptoModule = this._setupCryptoModule({ + cipherKey: key, + useRandomIVs: base.useRandomIVs, + customEncrypt: this.getCustomEncrypt(), + customDecrypt: this.getCustomDecrypt(), + }); + }, + getCryptoModule() { + return this._cryptoModule; + }, + getUseRandomIVs() { + return base.useRandomIVs; + }, + setPresenceTimeout(value) { + this.heartbeatInterval = value / 2 - 1; + this.presenceTimeout = value; + }, + getPresenceTimeout() { + return this.presenceTimeout; + }, + getHeartbeatInterval() { + return this.heartbeatInterval; + }, + setHeartbeatInterval(interval) { + this.heartbeatInterval = interval; + }, + getTransactionTimeout() { + return this.transactionalRequestTimeout; + }, + getSubscribeTimeout() { + return this.subscribeRequestTimeout; + }, + get PubNubFile() { + return base.PubNubFile; + }, + get version() { + return '7.6.3'; + }, + getVersion() { + return this.version; + }, + _addPnsdkSuffix(name, suffix) { + this._pnsdkSuffix[name] = `${suffix}`; + }, + _getPnsdkSuffix(separator) { + const sdk = Object.values(this._pnsdkSuffix).join(separator); + return sdk.length > 0 ? separator + sdk : ''; + }, + // -------------------------------------------------------- + // ---------------------- Deprecated ---------------------- + // -------------------------------------------------------- + // region Deprecated + getUUID() { + return this.getUserId(); + }, + setUUID(value) { + this.setUserId(value); + }, + getCustomEncrypt() { + return base.customEncrypt; + }, + getCustomDecrypt() { + return base.customDecrypt; + } }); + // Setup `CryptoModule` if possible. + if (base.cipherKey) + clientConfiguration.setCipherKey(base.cipherKey); + else if (cryptoModule) + clientConfiguration._cryptoModule = cryptoModule; + return clientConfiguration; + }; + /** + * Decide {@lin PubNub} service REST API origin. + * + * @param secure - Whether preferred to use secured connection or not. + * @param origin - User-provided or default origin. + * + * @returns `PubNub` REST API endpoints origin. + */ + const standardOrigin = (secure, origin) => { + const protocol = secure ? 'https://' : 'http://'; + if (typeof origin === 'string') + return `${protocol}${origin}`; + return `${protocol}${origin[Math.floor(Math.random() * origin.length)]}`; + }; + + /** + * PubNub Access Token Manager module. + */ + // endregion + /** + * REST API access token manager. + * + * Manager maintains active access token and let parse it to get information about permissions. + */ + class TokenManager { + constructor(cbor) { + this.cbor = cbor; + } + /** + * Update REST API access token. + * + * **Note:** Token will be applied only for next requests and won't affect ongoing requests. + * + * @param [token] - Access token which should be used to access PubNub REST API. + */ + setToken(token) { + if (token && token.length > 0) + this.token = token; + else + this.token = undefined; + } + /** + * REST API access token. + * + * @returns Previously configured REST API access token. + */ + getToken() { + return this.token; + } + /** + * Parse Base64-encoded access token. + * + * @param tokenString - Base64-encoded access token. + * + * @returns Information about resources and permissions which has been granted for them. + */ + parseToken(tokenString) { + const parsed = this.cbor.decodeToken(tokenString); + if (parsed !== undefined) { + const uuidResourcePermissions = parsed.res.uuid ? Object.keys(parsed.res.uuid) : []; + const channelResourcePermissions = Object.keys(parsed.res.chan); + const groupResourcePermissions = Object.keys(parsed.res.grp); + const uuidPatternPermissions = parsed.pat.uuid ? Object.keys(parsed.pat.uuid) : []; + const channelPatternPermissions = Object.keys(parsed.pat.chan); + const groupPatternPermissions = Object.keys(parsed.pat.grp); + const result = { + version: parsed.v, + timestamp: parsed.t, + ttl: parsed.ttl, + authorized_uuid: parsed.uuid, + signature: parsed.sig, + }; + const uuidResources = uuidResourcePermissions.length > 0; + const channelResources = channelResourcePermissions.length > 0; + const groupResources = groupResourcePermissions.length > 0; + if (uuidResources || channelResources || groupResources) { + result.resources = {}; + if (uuidResources) { + const uuids = (result.resources.uuids = {}); + uuidResourcePermissions.forEach((id) => (uuids[id] = this.extractPermissions(parsed.res.uuid[id]))); + } + if (channelResources) { + const channels = (result.resources.channels = {}); + channelResourcePermissions.forEach((id) => (channels[id] = this.extractPermissions(parsed.res.chan[id]))); + } + if (groupResources) { + const groups = (result.resources.groups = {}); + groupResourcePermissions.forEach((id) => (groups[id] = this.extractPermissions(parsed.res.grp[id]))); + } + } + const uuidPatterns = uuidPatternPermissions.length > 0; + const channelPatterns = channelPatternPermissions.length > 0; + const groupPatterns = groupPatternPermissions.length > 0; + if (uuidPatterns || channelPatterns || groupPatterns) { + result.patterns = {}; + if (uuidPatterns) { + const uuids = (result.patterns.uuids = {}); + uuidPatternPermissions.forEach((id) => (uuids[id] = this.extractPermissions(parsed.pat.uuid[id]))); + } + if (channelPatterns) { + const channels = (result.patterns.channels = {}); + channelPatternPermissions.forEach((id) => (channels[id] = this.extractPermissions(parsed.pat.chan[id]))); + } + if (groupPatterns) { + const groups = (result.patterns.groups = {}); + groupPatternPermissions.forEach((id) => (groups[id] = this.extractPermissions(parsed.pat.grp[id]))); + } + } + if (parsed.meta && Object.keys(parsed.meta).length > 0) + result.meta = parsed.meta; + return result; + } + return undefined; + } + /** + * Extract resource access permission information. + * + * @param permissions - Bit-encoded resource permissions. + * + * @returns Human-readable resource permissions. + */ + extractPermissions(permissions) { + const permissionsResult = { + read: false, + write: false, + manage: false, + delete: false, + get: false, + update: false, + join: false, + }; + if ((permissions & 128) === 128) + permissionsResult.join = true; + if ((permissions & 64) === 64) + permissionsResult.update = true; + if ((permissions & 32) === 32) + permissionsResult.get = true; + if ((permissions & 8) === 8) + permissionsResult.delete = true; + if ((permissions & 4) === 4) + permissionsResult.manage = true; + if ((permissions & 2) === 2) + permissionsResult.write = true; + if ((permissions & 1) === 1) + permissionsResult.read = true; + return permissionsResult; + } + } + + /** + * Enum representing possible transport methods for HTTP requests. + * + * @enum {number} + */ + var TransportMethod; + (function (TransportMethod) { + /** + * Request will be sent using `GET` method. + */ + TransportMethod["GET"] = "GET"; + /** + * Request will be sent using `POST` method. + */ + TransportMethod["POST"] = "POST"; + /** + * Request will be sent using `PATCH` method. + */ + TransportMethod["PATCH"] = "PATCH"; + /** + * Request will be sent using `DELETE` method. + */ + TransportMethod["DELETE"] = "DELETE"; + /** + * Local request. + * + * Request won't be sent to the service and probably used to compute URL. + */ + TransportMethod["LOCAL"] = "LOCAL"; + })(TransportMethod || (TransportMethod = {})); + + class RequestSignature { + constructor(publishKey, secretKey, hasher) { + this.publishKey = publishKey; + this.secretKey = secretKey; + this.hasher = hasher; + } + /** + * Compute request signature. + * + * @param req - Request which will be used to compute signature. + * @returns {string} `v2` request signature. + */ + signature(req) { + const method = req.path.startsWith('/publish') ? TransportMethod.GET : req.method; + let signatureInput = `${method}\n${this.publishKey}\n${req.path}\n${this.queryParameters(req.queryParameters)}\n`; + if (method === TransportMethod.POST || method === TransportMethod.PATCH) { + const body = req.body; + let payload; + if (body && body instanceof ArrayBuffer) { + payload = RequestSignature.textDecoder.decode(body); + } + else if (body && typeof body !== 'object') { + payload = body; + } + if (payload) + signatureInput += payload; + } + return `v2.${this.hasher(signatureInput, this.secretKey)}` + .replace(/\+/g, '-') + .replace(/\//g, '_') + .replace(/=+$/, ''); + } + /** + * Prepare request query parameters for signature. + * + * @param query - Key / value pair of the request query parameters. + * @private + */ + queryParameters(query) { + return Object.keys(query) + .sort() + .map((key) => { + const queryValue = query[key]; + if (!Array.isArray(queryValue)) + return `${key}=${encodeString(queryValue)}`; + return queryValue + .sort() + .map((value) => `${key}=${encodeString(value)}`) + .join('&'); + }) + .join('&'); + } + } + RequestSignature.textDecoder = new TextDecoder('utf-8'); + class PubNubMiddleware { + constructor(configuration) { + this.configuration = configuration; + const { clientConfiguration: { keySet }, shaHMAC, } = configuration; + if (keySet.secretKey && shaHMAC) + this.signatureGenerator = new RequestSignature(keySet.publishKey, keySet.secretKey, shaHMAC); + } + makeSendable(req) { + return this.configuration.transport.makeSendable(this.request(req)); + } + request(req) { + var _a; + const { clientConfiguration } = this.configuration; + // Get request patched by transport provider. + req = this.configuration.transport.request(req); + if (!req.queryParameters) + req.queryParameters = {}; + // Modify request with required information. + if (clientConfiguration.useInstanceId) + req.queryParameters['instanceid'] = clientConfiguration.instanceId; + if (!req.queryParameters['uuid']) + req.queryParameters['uuid'] = clientConfiguration.userId; + if (clientConfiguration.useRequestId) + req.queryParameters['requestid'] = req.identifier; + req.queryParameters['pnsdk'] = this.generatePNSDK(); + (_a = req.origin) !== null && _a !== void 0 ? _a : (req.origin = clientConfiguration.origin); + // Authenticate request if required. + this.authenticateRequest(req); + // Sign request if it is required. + this.signRequest(req); + return req; + } + authenticateRequest(req) { + var _a; + // Access management endpoints doesn't need authentication (signature required instead). + if (req.path.startsWith('/v2/auth/') || req.path.startsWith('/v3/pam/') || req.path.startsWith('/time')) + return; + const { clientConfiguration, tokenManager } = this.configuration; + const accessKey = (_a = tokenManager.getToken()) !== null && _a !== void 0 ? _a : clientConfiguration.authKey; + if (accessKey) + req.queryParameters['auth'] = accessKey; + } + /** + * Compute and append request signature. + * + * @param req - Transport request with information which should be used to generate signature. + */ + signRequest(req) { + if (!this.signatureGenerator || req.path.startsWith('/time')) + return; + req.queryParameters['timestamp'] = String(Math.floor(new Date().getTime() / 1000)); + req.queryParameters['signature'] = this.signatureGenerator.signature(req); + } + /** + * Compose `pnsdk` query parameter. + * + * SDK provides ability to set custom name or append vendor information to the `pnsdk` query + * parameter. + * + * @returns Finalized `pnsdk` query parameter value. + */ + generatePNSDK() { + const { clientConfiguration } = this.configuration; + if (clientConfiguration.sdkName) + return clientConfiguration.sdkName; + let base = `PubNub-JS-${clientConfiguration.sdkFamily}`; + if (clientConfiguration.partnerId) + base += `-${clientConfiguration.partnerId}`; + base += `/${clientConfiguration.getVersion()}`; + const pnsdkSuffix = clientConfiguration._getPnsdkSuffix(' '); + if (pnsdkSuffix.length > 0) + base += pnsdkSuffix; + return base; + } + } + + /** + * Events listener manager module. + */ + /** + * Real-time listeners' manager. + */ + class ListenerManager { + constructor() { + /** + * List of registered event listeners. + */ + this.listeners = []; + // endregion + } + /** + * Register new real-time events listener. + * + * @param listener - Listener with event callbacks to handle different types of events. + */ + addListener(listener) { + if (this.listeners.includes(listener)) + return; + this.listeners.push(listener); + } + /** + * Remove real-time event listener. + * + * @param listener - Event listeners which should be removed. + */ + removeListener(listener) { + this.listeners = this.listeners.filter((storedListener) => storedListener !== listener); + } + /** + * Clear all real-time event listeners. + */ + removeAllListeners() { + this.listeners = []; + } + /** + * Announce PubNub client status change event. + * + * @param status - PubNub client status. + */ + announceStatus(status) { + this.listeners.forEach((listener) => { + if (listener.status) + listener.status(status); + }); + } + /** + * Announce channel presence change event. + * + * @param presence - Channel presence change information. + */ + announcePresence(presence) { + this.listeners.forEach((listener) => { + if (listener.presence) + listener.presence(presence); + }); + } + /** + * Announce real-time message event. + * + * @param message - Received real-time message. + */ + announceMessage(message) { + this.listeners.forEach((listener) => { + if (listener.message) + listener.message(message); + }); + } + /** + * Announce real-time signal event. + * + * @param signal - Received real-time signal. + */ + announceSignal(signal) { + this.listeners.forEach((listener) => { + if (listener.signal) + listener.signal(signal); + }); + } + /** + * Announce message actions change event. + * + * @param messageAction - Message action change information. + */ + announceMessageAction(messageAction) { + this.listeners.forEach((listener) => { + if (listener.messageAction) + listener.messageAction(messageAction); + }); + } + /** + * Announce fie share event. + * + * @param file - Shared file information. + */ + announceFile(file) { + this.listeners.forEach((listener) => { + if (listener.file) + listener.file(file); + }); + } + /** + * Announce App Context Object change event. + * + * @param object - App Context change information. + */ + announceObjects(object) { + this.listeners.forEach((listener) => { + if (listener.objects) + listener.objects(object); + }); + } + /** + * Announce network up status. + */ + announceNetworkUp() { + this.listeners.forEach((listener) => { + if (listener.status) { + listener.status({ + category: StatusCategory$1.PNNetworkUpCategory, + }); + } + }); + } + /** + * Announce network down status. + */ + announceNetworkDown() { + this.listeners.forEach((listener) => { + if (listener.status) { + listener.status({ + category: StatusCategory$1.PNNetworkDownCategory, + }); + } + }); + } + // -------------------------------------------------------- + // ---------------------- Deprecated ---------------------- + // -------------------------------------------------------- + // region Deprecated + /** + * Announce User App Context Object change event. + * + * @param user - User App Context change information. + * + * @deprecated Use {@link announceObjects} method instead. + */ + announceUser(user) { + this.listeners.forEach((listener) => { + if (listener.user) + listener.user(user); + }); + } + /** + * Announce Space App Context Object change event. + * + * @param space - Space App Context change information. + * + * @deprecated Use {@link announceObjects} method instead. + */ + announceSpace(space) { + this.listeners.forEach((listener) => { + if (listener.space) + listener.space(space); + }); + } + /** + * Announce VSP Membership App Context Object change event. + * + * @param membership - VSP Membership App Context change information. + * + * @deprecated Use {@link announceObjects} method instead. + */ + announceMembership(membership) { + this.listeners.forEach((listener) => { + if (listener.membership) + listener.membership(membership); + }); + } + } + + /** + * Subscription reconnection-manager. + * + * **Note:** Reconnection manger rely on legacy time-based availability check. + */ + class ReconnectionManager { + constructor(time) { + this.time = time; + } + /** + * Configure reconnection handler. + * + * @param callback - Successful availability check notify callback. + */ + onReconnect(callback) { + this.callback = callback; + } + /** + * Start periodic "availability" check. + */ + startPolling() { + this.timeTimer = setInterval(() => this.callTime(), 3000); + } + /** + * Stop periodic "availability" check. + */ + stopPolling() { + if (this.timeTimer) + clearInterval(this.timeTimer); + this.timeTimer = null; + } + callTime() { + this.time((status) => { + if (!status.error) { + this.stopPolling(); + if (this.callback) + this.callback(); + } + }); + } + } + + /* */ + + const hashCode = (payload) => { + let hash = 0; + if (payload.length === 0) return hash; + for (let i = 0; i < payload.length; i += 1) { + const character = payload.charCodeAt(i); + hash = (hash << 5) - hash + character; // eslint-disable-line + hash = hash & hash; // eslint-disable-line + } + return hash; + }; + + class DedupingManager { + _config; + + hashHistory; + + constructor({ config }) { + this.hashHistory = []; + this._config = config; + } + + getKey(message) { + const hashedPayload = hashCode(JSON.stringify(message.message)).toString(); + const timetoken = message.timetoken; + return `${timetoken}-${hashedPayload}`; + } + + isDuplicate(message) { + return this.hashHistory.includes(this.getKey(message)); + } + + addEntry(message) { + if (this.hashHistory.length >= this._config.maximumCacheSize) { + this.hashHistory.shift(); + } + + this.hashHistory.push(this.getKey(message)); + } + + clearHistory() { + this.hashHistory = []; + } + } + + /** + * Subscription manager module. + */ + /** + * Subscription loop manager. + */ + class SubscriptionManager { + constructor(configuration, listenerManager, eventEmitter, subscribeCall, heartbeatCall, leaveCall, time) { + this.configuration = configuration; + this.listenerManager = listenerManager; + this.eventEmitter = eventEmitter; + this.subscribeCall = subscribeCall; + this.heartbeatCall = heartbeatCall; + this.leaveCall = leaveCall; + this.reconnectionManager = new ReconnectionManager(time); + this.dedupingManager = new DedupingManager({ config: this.configuration }); + this.heartbeatChannelGroups = {}; + this.heartbeatChannels = {}; + this.presenceChannelGroups = {}; + this.presenceChannels = {}; + this.heartbeatTimer = null; + this.presenceState = {}; + this.pendingChannelGroupSubscriptions = new Set(); + this.pendingChannelSubscriptions = new Set(); + this.channelGroups = {}; + this.channels = {}; + this.currentTimetoken = '0'; + this.lastTimetoken = '0'; + this.storedTimetoken = null; + this.subscriptionStatusAnnounced = false; + this.isOnline = true; + } + // region Information + get subscribedChannels() { + return Object.keys(this.channels); + } + get subscribedChannelGroups() { + return Object.keys(this.channelGroups); + } + get abort() { + return this._subscribeAbort; + } + set abort(call) { + this._subscribeAbort = call; + } + // endregion + // region Subscription + disconnect() { + this.stopSubscribeLoop(); + this.stopHeartbeatTimer(); + this.reconnectionManager.stopPolling(); + } + reconnect() { + this.startSubscribeLoop(); + this.startHeartbeatTimer(); + } + /** + * Update channels and groups used in subscription loop. + * + * @param parameters - Subscribe configuration parameters. + */ + subscribe(parameters) { + const { channels, channelGroups, timetoken, withPresence = false, withHeartbeats = false } = parameters; + if (timetoken) { + this.lastTimetoken = this.currentTimetoken; + this.currentTimetoken = timetoken; + } + if (this.currentTimetoken !== '0' && this.currentTimetoken !== 0) { + this.storedTimetoken = this.currentTimetoken; + this.currentTimetoken = 0; + } + channels === null || channels === void 0 ? void 0 : channels.forEach((channel) => { + this.pendingChannelSubscriptions.add(channel); + this.channels[channel] = {}; + if (withPresence) + this.presenceChannels[channel] = {}; + if (withHeartbeats || this.configuration.getHeartbeatInterval()) + this.heartbeatChannels[channel] = {}; + }); + channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.forEach((group) => { + this.pendingChannelGroupSubscriptions.add(group); + this.channelGroups[group] = {}; + if (withPresence) + this.presenceChannelGroups[group] = {}; + if (withHeartbeats || this.configuration.getHeartbeatInterval()) + this.heartbeatChannelGroups[group] = {}; + }); + this.subscriptionStatusAnnounced = false; + this.reconnect(); + } + unsubscribe(parameters, isOffline) { + let { channels, channelGroups } = parameters; + const actualChannelGroups = new Set(); + const actualChannels = new Set(); + channels === null || channels === void 0 ? void 0 : channels.forEach((channel) => { + if (channel in this.channels) { + delete this.channels[channel]; + actualChannels.add(channel); + if (channel in this.heartbeatChannels) + delete this.heartbeatChannels[channel]; + } + if (channel in this.presenceState) + delete this.presenceState[channel]; + if (channel in this.presenceChannels) { + delete this.presenceChannels[channel]; + actualChannels.add(channel); + } + }); + channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.forEach((group) => { + if (group in this.channelGroups) { + delete this.channelGroups[group]; + actualChannelGroups.add(group); + if (group in this.heartbeatChannelGroups) + delete this.heartbeatChannelGroups[group]; + } + if (group in this.presenceState) + delete this.presenceState[group]; + if (group in this.presenceChannelGroups) { + delete this.presenceChannelGroups[group]; + actualChannelGroups.add(group); + } + }); + // There is no need to unsubscribe to empty list of data sources. + if (actualChannels.size === 0 && actualChannelGroups.size === 0) + return; + if (this.configuration.suppressLeaveEvents === false && !isOffline) { + channelGroups = Array.from(actualChannelGroups); + channels = Array.from(actualChannels); + this.leaveCall({ channels, channelGroups }, (status) => { + const { error } = status, restOfStatus = __rest(status, ["error"]); + let errorMessage; + if (error) { + if (status.errorData && + typeof status.errorData === 'object' && + 'message' in status.errorData && + typeof status.errorData.message === 'string') + errorMessage = status.errorData.message; + else if ('message' in status && typeof status.message === 'string') + errorMessage = status.message; + } + this.listenerManager.announceStatus(Object.assign(Object.assign({}, restOfStatus), { error: errorMessage !== null && errorMessage !== void 0 ? errorMessage : false, affectedChannels: channels, affectedChannelGroups: channelGroups, currentTimetoken: this.currentTimetoken, lastTimetoken: this.lastTimetoken })); + }); + } + if (Object.keys(this.channels).length === 0 && + Object.keys(this.presenceChannels).length === 0 && + Object.keys(this.channelGroups).length === 0 && + Object.keys(this.presenceChannelGroups).length === 0) { + this.lastTimetoken = 0; + this.currentTimetoken = 0; + this.storedTimetoken = null; + this.region = null; + this.reconnectionManager.stopPolling(); + } + this.reconnect(); + } + unsubscribeAll(isOffline) { + this.unsubscribe({ + channels: this.subscribedChannels, + channelGroups: this.subscribedChannelGroups, + }, isOffline); + } + startSubscribeLoop() { + this.stopSubscribeLoop(); + const channelGroups = [...Object.keys(this.channelGroups)]; + const channels = [...Object.keys(this.channels)]; + Object.keys(this.presenceChannelGroups).forEach((group) => channelGroups.push(`${group}-pnpres`)); + Object.keys(this.presenceChannels).forEach((channel) => channels.push(`${channel}-pnpres`)); + // There is no need to start subscription loop for empty list of data sources. + if (channels.length === 0 && channelGroups.length === 0) + return; + this.subscribeCall({ + channels, + channelGroups, + state: this.presenceState, + heartbeat: this.configuration.getPresenceTimeout(), + timetoken: this.currentTimetoken, + region: this.region !== null ? this.region : undefined, + filterExpression: this.configuration.filterExpression, + }, (status, result) => { + this.processSubscribeResponse(status, result); + }); + } + stopSubscribeLoop() { + if (this._subscribeAbort) { + this._subscribeAbort(); + this._subscribeAbort = null; + } + } + /** + * Process subscribe REST API endpoint response. + */ + processSubscribeResponse(status, result) { + if (status.error) { + // Ignore aborted request. + if ((typeof status.errorData === 'object' && + 'name' in status.errorData && + status.errorData.name === 'AbortError') || + status.category === StatusCategory$1.PNCancelledCategory) + return; + if (status.category === StatusCategory$1.PNTimeoutCategory) { + this.startSubscribeLoop(); + } + else if (status.category === StatusCategory$1.PNNetworkIssuesCategory) { + this.disconnect(); + if (status.error && this.configuration.autoNetworkDetection && this.isOnline) { + this.isOnline = false; + this.listenerManager.announceNetworkDown(); + } + this.reconnectionManager.onReconnect(() => { + if (this.configuration.autoNetworkDetection && !this.isOnline) { + this.isOnline = true; + this.listenerManager.announceNetworkUp(); + } + this.reconnect(); + this.subscriptionStatusAnnounced = true; + const reconnectedAnnounce = { + category: StatusCategory$1.PNReconnectedCategory, + operation: status.operation, + lastTimetoken: this.lastTimetoken, + currentTimetoken: this.currentTimetoken, + }; + this.listenerManager.announceStatus(reconnectedAnnounce); + }); + this.reconnectionManager.startPolling(); + this.listenerManager.announceStatus(status); + } + else if (status.category === StatusCategory$1.PNBadRequestCategory) { + this.stopHeartbeatTimer(); + this.listenerManager.announceStatus(status); + } + else { + this.listenerManager.announceStatus(status); + } + return; + } + if (this.storedTimetoken) { + this.currentTimetoken = this.storedTimetoken; + this.storedTimetoken = null; + } + else { + this.lastTimetoken = this.currentTimetoken; + this.currentTimetoken = result.cursor.timetoken; + } + if (!this.subscriptionStatusAnnounced) { + const connected = { + category: StatusCategory$1.PNConnectedCategory, + operation: status.operation, + affectedChannels: Array.from(this.pendingChannelSubscriptions), + subscribedChannels: this.subscribedChannels, + affectedChannelGroups: Array.from(this.pendingChannelGroupSubscriptions), + lastTimetoken: this.lastTimetoken, + currentTimetoken: this.currentTimetoken, + }; + this.subscriptionStatusAnnounced = true; + this.listenerManager.announceStatus(connected); + // Clear pending channels and groups. + this.pendingChannelGroupSubscriptions.clear(); + this.pendingChannelSubscriptions.clear(); + } + const { messages } = result; + const { requestMessageCountThreshold, dedupeOnSubscribe } = this.configuration; + if (requestMessageCountThreshold && messages.length >= requestMessageCountThreshold) { + this.listenerManager.announceStatus({ + category: StatusCategory$1.PNRequestMessageCountExceededCategory, + operation: status.operation, + }); + } + try { + messages.forEach((message) => { + if (dedupeOnSubscribe) { + if (this.dedupingManager.isDuplicate(message.data)) + return; + this.dedupingManager.addEntry(message.data); + } + this.eventEmitter.emitEvent(message); + }); + } + catch (e) { + const errorStatus = { + error: true, + category: StatusCategory$1.PNUnknownCategory, + errorData: e, + statusCode: 0, + }; + this.listenerManager.announceStatus(errorStatus); + } + this.region = result.cursor.region; + this.startSubscribeLoop(); + } + // endregion + // region Presence + /** + * Update `uuid` state which should be sent with subscribe request. + * + * @param parameters - Channels and groups with state which should be associated to `uuid`. + */ + setState(parameters) { + const { state, channels, channelGroups } = parameters; + channels === null || channels === void 0 ? void 0 : channels.forEach((channel) => channel in this.channels && (this.presenceState[channel] = state)); + channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.forEach((group) => group in this.channelGroups && (this.presenceState[group] = state)); + } + /** + * Manual presence management. + * + * @param parameters - Desired presence state for provided list of channels and groups. + */ + changePresence(parameters) { + const { connected, channels, channelGroups } = parameters; + if (connected) { + channels === null || channels === void 0 ? void 0 : channels.forEach((channel) => (this.heartbeatChannels[channel] = {})); + channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.forEach((group) => (this.heartbeatChannelGroups[group] = {})); + } + else { + channels === null || channels === void 0 ? void 0 : channels.forEach((channel) => { + if (channel in this.heartbeatChannels) + delete this.heartbeatChannels[channel]; + }); + channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.forEach((group) => { + if (group in this.heartbeatChannelGroups) + delete this.heartbeatChannelGroups[group]; + }); + if (this.configuration.suppressLeaveEvents === false) { + this.leaveCall({ channels, channelGroups }, (status) => this.listenerManager.announceStatus(status)); + } + } + this.reconnect(); + } + startHeartbeatTimer() { + this.stopHeartbeatTimer(); + const heartbeatInterval = this.configuration.getHeartbeatInterval(); + if (!heartbeatInterval || heartbeatInterval === 0) + return; + this.sendHeartbeat(); + this.heartbeatTimer = setInterval(() => this.sendHeartbeat(), heartbeatInterval * 1000); + } + /** + * Stop heartbeat. + * + * Stop timer which trigger {@link HeartbeatRequest} sending with configured presence intervals. + */ + stopHeartbeatTimer() { + if (!this.heartbeatTimer) + return; + clearInterval(this.heartbeatTimer); + this.heartbeatTimer = null; + } + /** + * Send heartbeat request. + */ + sendHeartbeat() { + const heartbeatChannelGroups = Object.keys(this.heartbeatChannelGroups); + const heartbeatChannels = Object.keys(this.heartbeatChannels); + // There is no need to start heartbeat loop if there is no channels and groups to use. + if (heartbeatChannels.length === 0 && heartbeatChannelGroups.length === 0) + return; + this.heartbeatCall({ + channels: heartbeatChannels, + channelGroups: heartbeatChannelGroups, + heartbeat: this.configuration.getPresenceTimeout(), + state: this.presenceState, + }, (status) => { + if (status.error && this.configuration.announceFailedHeartbeats) + this.listenerManager.announceStatus(status); + if (status.error && this.configuration.autoNetworkDetection && this.isOnline) { + this.isOnline = false; + this.disconnect(); + this.listenerManager.announceNetworkDown(); + this.reconnect(); + } + if (!status.error && this.configuration.announceSuccessfulHeartbeats) + this.listenerManager.announceStatus(status); + }); + } + } + + // -------------------------------------------------------- + // ------------------------ Types ------------------------- + // -------------------------------------------------------- + // region Types + // endregion + // endregion + /** + * Base notification payload object. + */ + class BaseNotificationPayload { + constructor(payload, title, body) { + this._payload = payload; + this.setDefaultPayloadStructure(); + this.title = title; + this.body = body; + } + /** + * Retrieve resulting notification payload content for message. + * + * @returns Preformatted push notification payload data. + */ + get payload() { + return this._payload; + } + /** + * Update notification title. + * + * @param value - New notification title. + */ + set title(value) { + this._title = value; + } + /** + * Update notification subtitle. + * + * @param value - New second-line notification title. + */ + set subtitle(value) { + this._subtitle = value; + } + /** + * Update notification body. + * + * @param value - Update main notification message (shown when expanded). + */ + set body(value) { + this._body = value; + } + /** + * Update application badge number. + * + * @param value - Number which should be shown in application badge upon receiving notification. + */ + set badge(value) { + this._badge = value; + } + /** + * Update notification sound. + * + * @param value - Name of the sound file which should be played upon notification receive. + */ + set sound(value) { + this._sound = value; + } + /** + * Platform-specific structure initialization. + */ + setDefaultPayloadStructure() { } + /** + * Translate data object into PubNub push notification payload object. + * + * @returns Preformatted push notification payload. + */ + toObject() { + return {}; + } + } + /** + * Message payload for Apple Push Notification Service. + */ + class APNSNotificationPayload extends BaseNotificationPayload { + constructor() { + super(...arguments); + /** + * Type of push notification service for which payload will be created. + */ + this._apnsPushType = 'apns'; + /** + * Whether resulting payload should trigger silent notification or not. + */ + this._isSilent = false; + } + get payload() { + return this._payload; + } + /** + * Update notification receivers configuration. + * + * @param value - New APNS2 configurations. + */ + set configurations(value) { + if (!value || !value.length) + return; + this._configurations = value; + } + /** + * Notification payload. + * + * @returns Platform-specific part of PubNub notification payload. + */ + get notification() { + return this.payload.aps; + } + /** + * Notification title. + * + * @returns Main notification title. + */ + get title() { + return this._title; + } + /** + * Update notification title. + * + * @param value - New notification title. + */ + set title(value) { + if (!value || !value.length) + return; + this.payload.aps.alert.title = value; + this._title = value; + } + /** + * Notification subtitle. + * + * @returns Second-line notification title. + */ + get subtitle() { + return this._subtitle; + } + /** + * Update notification subtitle. + * + * @param value - New second-line notification title. + */ + set subtitle(value) { + if (!value || !value.length) + return; + this.payload.aps.alert.subtitle = value; + this._subtitle = value; + } + /** + * Notification body. + * + * @returns Main notification message (shown when expanded). + */ + get body() { + return this._body; + } + /** + * Update notification body. + * + * @param value - Update main notification message (shown when expanded). + */ + set body(value) { + if (!value || !value.length) + return; + this.payload.aps.alert.body = value; + this._body = value; + } + /** + * Retrieve unread notifications number. + * + * @returns Number of unread notifications which should be shown on application badge. + */ + get badge() { + return this._badge; + } + /** + * Update application badge number. + * + * @param value - Number which should be shown in application badge upon receiving notification. + */ + set badge(value) { + if (value === undefined || value === null) + return; + this.payload.aps.badge = value; + this._badge = value; + } + /** + * Retrieve notification sound file. + * + * @returns Notification sound file name from resource bundle. + */ + get sound() { + return this._sound; + } + /** + * Update notification sound. + * + * @param value - Name of the sound file which should be played upon notification receive. + */ + set sound(value) { + if (!value || !value.length) + return; + this.payload.aps.sound = value; + this._sound = value; + } + /** + * Set whether notification should be silent or not. + * + * `content-available` notification type will be used to deliver silent notification if set to `true`. + * + * @param value - Whether notification should be sent as silent or not. + */ + set silent(value) { + this._isSilent = value; + } + setDefaultPayloadStructure() { + this.payload.aps = { alert: {} }; + } + toObject() { + const payload = Object.assign({}, this.payload); + const { aps } = payload; + let { alert } = aps; + if (this._isSilent) + aps['content-available'] = 1; + if (this._apnsPushType === 'apns2') { + if (!this._configurations || !this._configurations.length) + throw new ReferenceError('APNS2 configuration is missing'); + const configurations = []; + this._configurations.forEach((configuration) => { + configurations.push(this.objectFromAPNS2Configuration(configuration)); + }); + if (configurations.length) + payload.pn_push = configurations; + } + if (!alert || !Object.keys(alert).length) + delete aps.alert; + if (this._isSilent) { + delete aps.alert; + delete aps.badge; + delete aps.sound; + alert = {}; + } + return this._isSilent || (alert && Object.keys(alert).length) ? payload : null; + } + /** + * Create PubNub push notification service APNS2 configuration information object. + * + * @param configuration - Source user-provided APNS2 configuration. + * + * @returns Preformatted for PubNub service APNS2 configuration information. + */ + objectFromAPNS2Configuration(configuration) { + if (!configuration.targets || !configuration.targets.length) + throw new ReferenceError('At least one APNS2 target should be provided'); + const { collapseId, expirationDate } = configuration; + const objectifiedConfiguration = { + auth_method: 'token', + targets: configuration.targets.map((target) => this.objectFromAPNSTarget(target)), + version: 'v2', + }; + if (collapseId && collapseId.length) + objectifiedConfiguration.collapse_id = collapseId; + if (expirationDate) + objectifiedConfiguration.expiration = expirationDate.toISOString(); + return objectifiedConfiguration; + } + /** + * Create PubNub push notification service APNS2 target information object. + * + * @param target - Source user-provided data. + * + * @returns Preformatted for PubNub service APNS2 target information. + */ + objectFromAPNSTarget(target) { + if (!target.topic || !target.topic.length) + throw new TypeError("Target 'topic' undefined."); + const { topic, environment = 'development', excludedDevices = [] } = target; + const objectifiedTarget = { topic, environment }; + if (excludedDevices.length) + objectifiedTarget.excluded_devices = excludedDevices; + return objectifiedTarget; + } + } + /** + * Message payload for Firebase Clouse Messaging service. + */ + class FCMNotificationPayload extends BaseNotificationPayload { + get payload() { + return this._payload; + } + /** + * Notification payload. + * + * @returns Platform-specific part of PubNub notification payload. + */ + get notification() { + return this.payload.notification; + } + /** + * Silent notification payload. + * + * @returns Silent notification payload (data notification). + */ + get data() { + return this.payload.data; + } + /** + * Notification title. + * + * @returns Main notification title. + */ + get title() { + return this._title; + } + /** + * Update notification title. + * + * @param value - New notification title. + */ + set title(value) { + if (!value || !value.length) + return; + this.payload.notification.title = value; + this._title = value; + } + /** + * Notification body. + * + * @returns Main notification message (shown when expanded). + */ + get body() { + return this._body; + } + /** + * Update notification body. + * + * @param value - Update main notification message (shown when expanded). + */ + set body(value) { + if (!value || !value.length) + return; + this.payload.notification.body = value; + this._body = value; + } + /** + * Retrieve notification sound file. + * + * @returns Notification sound file name from resource bundle. + */ + get sound() { + return this._sound; + } + /** + * Update notification sound. + * + * @param value - Name of the sound file which should be played upon notification receive. + */ + set sound(value) { + if (!value || !value.length) + return; + this.payload.notification.sound = value; + this._sound = value; + } + /** + * Retrieve notification icon file. + * + * @returns Notification icon file name from resource bundle. + */ + get icon() { + return this._icon; + } + /** + * Update notification icon. + * + * @param value - Name of the icon file which should be shown on notification. + */ + set icon(value) { + if (!value || !value.length) + return; + this.payload.notification.icon = value; + this._icon = value; + } + get tag() { + return this._tag; + } + set tag(value) { + if (!value || !value.length) + return; + this.payload.notification.tag = value; + this._tag = value; + } + /** + * Set whether notification should be silent or not. + * + * All notification data will be sent under `data` field if set to `true`. + * + * @param value - Whether notification should be sent as silent or not. + */ + set silent(value) { + this._isSilent = value; + } + setDefaultPayloadStructure() { + this.payload.notification = {}; + this.payload.data = {}; + } + toObject() { + let data = Object.assign({}, this.payload.data); + let notification = null; + const payload = {}; + // Check whether additional data has been passed outside 'data' object and put it into it if required. + if (Object.keys(this.payload).length > 2) { + const _a = this.payload, additionalData = __rest(_a, ["notification", "data"]); + data = Object.assign(Object.assign({}, data), additionalData); + } + if (this._isSilent) + data.notification = this.payload.notification; + else + notification = this.payload.notification; + if (Object.keys(data).length) + payload.data = data; + if (notification && Object.keys(notification).length) + payload.notification = notification; + return Object.keys(payload).length ? payload : null; + } + } + class NotificationsPayload { + constructor(title, body) { + this._payload = { apns: {}, fcm: {} }; + this._title = title; + this._body = body; + this.apns = new APNSNotificationPayload(this._payload.apns, title, body); + this.fcm = new FCMNotificationPayload(this._payload.fcm, title, body); + } + set debugging(value) { + this._debugging = value; + } + /** + * Notification title. + * + * @returns Main notification title. + */ + get title() { + return this._title; + } + /** + * Notification subtitle. + * + * @returns Second-line notification title. + */ + get subtitle() { + return this._subtitle; + } + /** + * Update notification subtitle. + * + * @param value - New second-line notification title. + */ + set subtitle(value) { + this._subtitle = value; + this.apns.subtitle = value; + this.fcm.subtitle = value; + } + /** + * Notification body. + * + * @returns Main notification message (shown when expanded). + */ + get body() { + return this._body; + } + /** + * Retrieve unread notifications number. + * + * @returns Number of unread notifications which should be shown on application badge. + */ + get badge() { + return this._badge; + } + /** + * Update application badge number. + * + * @param value - Number which should be shown in application badge upon receiving notification. + */ + set badge(value) { + this._badge = value; + this.apns.badge = value; + this.fcm.badge = value; + } + /** + * Retrieve notification sound file. + * + * @returns Notification sound file name from resource bundle. + */ + get sound() { + return this._sound; + } + /** + * Update notification sound. + * + * @param value - Name of the sound file which should be played upon notification receive. + */ + set sound(value) { + this._sound = value; + this.apns.sound = value; + this.fcm.sound = value; + } + /** + * Build notifications platform for requested platforms. + * + * @param platforms - List of platforms for which payload should be added to final dictionary. Supported values: + * gcm, apns, and apns2. + * + * @returns Object with data, which can be sent with publish method call and trigger remote notifications for + * specified platforms. + */ + buildPayload(platforms) { + const payload = {}; + if (platforms.includes('apns') || platforms.includes('apns2')) { + // @ts-expect-error Override APNS version. + this.apns._apnsPushType = platforms.includes('apns') ? 'apns' : 'apns2'; + const apnsPayload = this.apns.toObject(); + if (apnsPayload && Object.keys(apnsPayload).length) + payload.pn_apns = apnsPayload; + } + if (platforms.includes('fcm')) { + const fcmPayload = this.fcm.toObject(); + if (fcmPayload && Object.keys(fcmPayload).length) + payload.pn_gcm = fcmPayload; + } + if (Object.keys(payload).length && this._debugging) + payload.pn_debug = true; + return payload; + } + } + + /** + * Base REST API request class. + */ + class AbstractRequest { + /** + * Construct base request. + * + * Constructed request by default won't be cancellable and performed using `GET` HTTP method. + * + * @param params - Request configuration parameters. + */ + constructor(params) { + this.params = params; + /** + * Unique request identifier. + */ + this.requestIdentifier = uuidGenerator.createUUID(); + this._cancellationController = null; + } + /** + * Retrieve configured cancellation controller. + * + * @returns Cancellation controller. + */ + get cancellationController() { + return this._cancellationController; + } + /** + * Update request cancellation controller. + * + * Controller itself provided by transport provider implementation and set only when request + * sending has been scheduled. + * + * @param controller - Cancellation controller or `null` to reset it. + */ + set cancellationController(controller) { + this._cancellationController = controller; + } + /** + * Abort request if possible. + */ + abort() { + if (this && this.cancellationController) + this.cancellationController.abort(); + } + /** + * Target REST API endpoint operation type. + */ + operation() { + throw Error('Should be implemented by subclass.'); + } + /** + * Validate user-provided data before scheduling request. + * + * @returns Error message if request can't be sent without missing or malformed parameters. + */ + validate() { + return undefined; + } + /** + * Parse service response. + * + * @param _response - Raw service response which should be parsed. + */ + parse(_response) { + return __awaiter(this, void 0, void 0, function* () { + throw Error('Should be implemented by subclass.'); + }); + } + /** + * Create platform-agnostic request object. + * + * @returns Request object which can be processed using platform-specific requirements. + */ + request() { + var _a, _b, _c, _d; + const request = { + method: (_b = (_a = this.params) === null || _a === void 0 ? void 0 : _a.method) !== null && _b !== void 0 ? _b : TransportMethod.GET, + path: this.path, + queryParameters: this.queryParameters, + cancellable: (_d = (_c = this.params) === null || _c === void 0 ? void 0 : _c.cancellable) !== null && _d !== void 0 ? _d : false, + timeout: 10000, + identifier: this.requestIdentifier, + }; + // Attach headers (if required). + const headers = this.headers; + if (headers) + request.headers = headers; + // Attach body (if required). + if (request.method === TransportMethod.POST || request.method === TransportMethod.PATCH) { + const [body, formData] = [this.body, this.formData]; + if (formData) + request.formData = formData; + if (body) + request.body = body; + } + return request; + } + /** + * Target REST API endpoint request headers getter. + * + * @returns Key/value headers which should be used with request. + */ + get headers() { + return undefined; + } + /** + * Target REST API endpoint request path getter. + * + * @returns REST API path. + */ + get path() { + throw Error('`path` getter should be implemented by subclass.'); + } + /** + * Target REST API endpoint request query parameters getter. + * + * @returns Key/value pairs which should be appended to the REST API path. + */ + get queryParameters() { + return {}; + } + get formData() { + return undefined; + } + /** + * Target REST API Request body payload getter. + * + * @returns Buffer of stringified data which should be sent with `POST` or `PATCH` request. + */ + get body() { + return undefined; + } + /** + * Deserialize service response. + * + * @param response - Transparent response object with headers and body information. + * + * @returns Deserialized data or `undefined` in case of `JSON.parse(..)` error. + */ + deserializeResponse(response) { + const contentType = response.headers['content-type']; + if (!contentType || (contentType.indexOf('javascript') === -1 && contentType.indexOf('json') === -1)) + return undefined; + const json = AbstractRequest.decoder.decode(response.body); + try { + const parsedJson = JSON.parse(json); + return parsedJson; + } + catch (error) { + console.error('Error parsing JSON response:', error); + return undefined; + } + } + } + /** + * Service `ArrayBuffer` response decoder. + */ + AbstractRequest.decoder = new TextDecoder(); + + /* */ + var RequestOperation; + (function (RequestOperation) { + // -------------------------------------------------------- + // ---------------------- Publish API --------------------- + // -------------------------------------------------------- + /** + * Data publish REST API operation. + */ + RequestOperation["PNPublishOperation"] = "PNPublishOperation"; + /** + * Signal sending REST API operation. + */ + RequestOperation["PNSignalOperation"] = "PNSignalOperation"; + // -------------------------------------------------------- + // --------------------- Subscribe API -------------------- + // -------------------------------------------------------- + /** + * Subscribe for real-time updates REST API operation. + * + * User's presence change on specified entities will trigger `join` event. + */ + RequestOperation["PNSubscribeOperation"] = "PNSubscribeOperation"; + /** + * Unsubscribe from real-time updates REST API operation. + * + * User's presence change on specified entities will trigger `leave` event. + */ + RequestOperation["PNUnsubscribeOperation"] = "PNUnsubscribeOperation"; + // -------------------------------------------------------- + // --------------------- Presence API --------------------- + // -------------------------------------------------------- + /** + * Fetch user's presence information REST API operation. + */ + RequestOperation["PNWhereNowOperation"] = "PNWhereNowOperation"; + /** + * Fetch channel's presence information REST API operation. + */ + RequestOperation["PNHereNowOperation"] = "PNHereNowOperation"; + /** + * Fetch global presence information REST API operation. + */ + RequestOperation["PNGlobalHereNowOperation"] = "PNGlobalHereNowOperation"; + /** + * Update user's information associated with specified channel REST API operation. + */ + RequestOperation["PNSetStateOperation"] = "PNSetStateOperation"; + /** + * Fetch user's information associated with the specified channel REST API operation. + */ + RequestOperation["PNGetStateOperation"] = "PNGetStateOperation"; + /** + * Announce presence on managed channels REST API operation. + */ + RequestOperation["PNHeartbeatOperation"] = "PNHeartbeatOperation"; + // -------------------------------------------------------- + // ----------------- Message Reaction API ----------------- + // -------------------------------------------------------- + /** + * Add a reaction to the specified message REST API operation. + */ + RequestOperation["PNAddMessageActionOperation"] = "PNAddActionOperation"; + /** + * Remove reaction from the specified message REST API operation. + */ + RequestOperation["PNRemoveMessageActionOperation"] = "PNRemoveMessageActionOperation"; + /** + * Fetch reactions for specific message REST API operation. + */ + RequestOperation["PNGetMessageActionsOperation"] = "PNGetMessageActionsOperation"; + RequestOperation["PNTimeOperation"] = "PNTimeOperation"; + // -------------------------------------------------------- + // ---------------------- Storage API --------------------- + // -------------------------------------------------------- + /** + * Channel history REST API operation. + */ + RequestOperation["PNHistoryOperation"] = "PNHistoryOperation"; + /** + * Delete messages from channel history REST API operation. + */ + RequestOperation["PNDeleteMessagesOperation"] = "PNDeleteMessagesOperation"; + /** + * History for channels REST API operation. + */ + RequestOperation["PNFetchMessagesOperation"] = "PNFetchMessagesOperation"; + /** + * Number of messages for channels in specified time frame REST API operation. + */ + RequestOperation["PNMessageCounts"] = "PNMessageCountsOperation"; + // -------------------------------------------------------- + // -------------------- App Context API ------------------- + // -------------------------------------------------------- + /** + * Fetch users metadata REST API operation. + */ + RequestOperation["PNGetAllUUIDMetadataOperation"] = "PNGetAllUUIDMetadataOperation"; + /** + * Fetch user metadata REST API operation. + */ + RequestOperation["PNGetUUIDMetadataOperation"] = "PNGetUUIDMetadataOperation"; + /** + * Set user metadata REST API operation. + */ + RequestOperation["PNSetUUIDMetadataOperation"] = "PNSetUUIDMetadataOperation"; + /** + * Remove user metadata REST API operation. + */ + RequestOperation["PNRemoveUUIDMetadataOperation"] = "PNRemoveUUIDMetadataOperation"; + /** + * Fetch channels metadata REST API operation. + */ + RequestOperation["PNGetAllChannelMetadataOperation"] = "PNGetAllChannelMetadataOperation"; + /** + * Fetch channel metadata REST API operation. + */ + RequestOperation["PNGetChannelMetadataOperation"] = "PNGetChannelMetadataOperation"; + /** + * Set channel metadata REST API operation. + */ + RequestOperation["PNSetChannelMetadataOperation"] = "PNSetChannelMetadataOperation"; + /** + * Remove channel metadata REST API operation. + */ + RequestOperation["PNRemoveChannelMetadataOperation"] = "PNRemoveChannelMetadataOperation"; + /** + * Fetch channel members REST API operation. + */ + RequestOperation["PNGetMembersOperation"] = "PNGetMembersOperation"; + /** + * Update channel members REST API operation. + */ + RequestOperation["PNSetMembersOperation"] = "PNSetMembersOperation"; + /** + * Fetch channel memberships REST API operation. + */ + RequestOperation["PNGetMembershipsOperation"] = "PNGetMembershipsOperation"; + /** + * Update channel memberships REST API operation. + */ + RequestOperation["PNSetMembershipsOperation"] = "PNSetMembershipsOperation"; + // -------------------------------------------------------- + // -------------------- File Upload API ------------------- + // -------------------------------------------------------- + /** + * Fetch list of files sent to the channel REST API operation. + */ + RequestOperation["PNListFilesOperation"] = "PNListFilesOperation"; + /** + * Retrieve file upload URL REST API operation. + */ + RequestOperation["PNGenerateUploadUrlOperation"] = "PNGenerateUploadUrlOperation"; + /** + * Upload file to the channel REST API operation. + */ + RequestOperation["PNPublishFileOperation"] = "PNPublishFileOperation"; + /** + * Publish File Message to the channel REST API operation. + */ + RequestOperation["PNPublishFileMessageOperation"] = "PNPublishFileMessageOperation"; + /** + * Retrieve file download URL REST API operation. + */ + RequestOperation["PNGetFileUrlOperation"] = "PNGetFileUrlOperation"; + /** + * Download file from the channel REST API operation. + */ + RequestOperation["PNDownloadFileOperation"] = "PNDownloadFileOperation"; + /** + * Delete file sent to the channel REST API operation. + */ + RequestOperation["PNDeleteFileOperation"] = "PNDeleteFileOperation"; + // -------------------------------------------------------- + // -------------------- Mobile Push API ------------------- + // -------------------------------------------------------- + /** + * Register channels with device push notifications REST API operation. + */ + RequestOperation["PNAddPushNotificationEnabledChannelsOperation"] = "PNAddPushNotificationEnabledChannelsOperation"; + /** + * Unregister channels with device push notifications REST API operation. + */ + RequestOperation["PNRemovePushNotificationEnabledChannelsOperation"] = "PNRemovePushNotificationEnabledChannelsOperation"; + /** + * Fetch list of channels with enabled push notifications for device REST API operation. + */ + RequestOperation["PNPushNotificationEnabledChannelsOperation"] = "PNPushNotificationEnabledChannelsOperation"; + /** + * Disable push notifications for device REST API operation. + */ + RequestOperation["PNRemoveAllPushNotificationsOperation"] = "PNRemoveAllPushNotificationsOperation"; + // -------------------------------------------------------- + // ------------------ Channel Groups API ------------------ + // -------------------------------------------------------- + /** + * Fetch channels groups list REST API operation. + */ + RequestOperation["PNChannelGroupsOperation"] = "PNChannelGroupsOperation"; + /** + * Remove specified channel group REST API operation. + */ + RequestOperation["PNRemoveGroupOperation"] = "PNRemoveGroupOperation"; + /** + * Fetch list of channels for the specified channel group REST API operation. + */ + RequestOperation["PNChannelsForGroupOperation"] = "PNChannelsForGroupOperation"; + /** + * Add list of channels to the specified channel group REST API operation. + */ + RequestOperation["PNAddChannelsToGroupOperation"] = "PNAddChannelsToGroupOperation"; + /** + * Remove list of channels from the specified channel group REST API operation. + */ + RequestOperation["PNRemoveChannelsFromGroupOperation"] = "PNRemoveChannelsFromGroupOperation"; + // -------------------------------------------------------- + // ----------------------- PAM API ------------------------ + // -------------------------------------------------------- + /** + * Generate authorized token REST API operation. + */ + RequestOperation["PNAccessManagerGrant"] = "PNAccessManagerGrant"; + /** + * Generate authorized token REST API operation. + */ + RequestOperation["PNAccessManagerGrantToken"] = "PNAccessManagerGrantToken"; + RequestOperation["PNAccessManagerAudit"] = "PNAccessManagerAudit"; + /** + * Revoke authorized token REST API operation. + */ + RequestOperation["PNAccessManagerRevokeToken"] = "PNAccessManagerRevokeToken"; + // + // -------------------------------------------------------- + // ---------------- Subscription Utility ------------------ + // -------------------------------------------------------- + RequestOperation["PNHandshakeOperation"] = "PNHandshakeOperation"; + RequestOperation["PNReceiveMessagesOperation"] = "PNReceiveMessagesOperation"; + })(RequestOperation || (RequestOperation = {})); + var RequestOperation$1 = RequestOperation; + + /** + * Subscription REST API module. + */ + // -------------------------------------------------------- + // ---------------------- Defaults ------------------------ + // -------------------------------------------------------- + // region Defaults + /** + * Whether should subscribe to channels / groups presence announcements or not. + */ + const WITH_PRESENCE = false; + // endregion + // -------------------------------------------------------- + // ------------------------ Types ------------------------- + // -------------------------------------------------------- + // region Types + /** + * PubNub-defined event types by payload. + */ + var PubNubEventType; + (function (PubNubEventType) { + /** + * Presence change event. + */ + PubNubEventType[PubNubEventType["Presence"] = -2] = "Presence"; + /** + * Regular message event. + * + * **Note:** This is default type assigned for non-presence events if `e` field is missing. + */ + PubNubEventType[PubNubEventType["Message"] = -1] = "Message"; + /** + * Signal data event. + */ + PubNubEventType[PubNubEventType["Signal"] = 1] = "Signal"; + /** + * App Context object event. + */ + PubNubEventType[PubNubEventType["AppContext"] = 2] = "AppContext"; + /** + * Message reaction event. + */ + PubNubEventType[PubNubEventType["MessageAction"] = 3] = "MessageAction"; + /** + * Files event. + */ + PubNubEventType[PubNubEventType["Files"] = 4] = "Files"; + })(PubNubEventType || (PubNubEventType = {})); + // endregion + /** + * Base subscription request implementation. + * + * Subscription request used in small variations in two cases: + * - subscription manager + * - event engine + */ + class BaseSubscribeRequest extends AbstractRequest { + constructor(parameters) { + var _a, _b, _c; + var _d, _e, _f; + super({ cancellable: true }); + this.parameters = parameters; + // Apply default request parameters. + (_a = (_d = this.parameters).withPresence) !== null && _a !== void 0 ? _a : (_d.withPresence = WITH_PRESENCE); + (_b = (_e = this.parameters).channelGroups) !== null && _b !== void 0 ? _b : (_e.channelGroups = []); + (_c = (_f = this.parameters).channels) !== null && _c !== void 0 ? _c : (_f.channels = []); + } + operation() { + return RequestOperation$1.PNSubscribeOperation; + } + validate() { + const { keySet: { subscribeKey }, channels, channelGroups, } = this.parameters; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!channels && !channelGroups) + return '`channels` and `channelGroups` both should not be empty'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + let serviceResponse; + try { + const json = AbstractRequest.decoder.decode(response.body); + const parsedJson = JSON.parse(json); + serviceResponse = parsedJson; + } + catch (error) { + console.error('Error parsing JSON response:', error); + } + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + const events = serviceResponse.m.map((envelope) => { + let { e: eventType } = envelope; + // Resolve missing event type. + eventType !== null && eventType !== void 0 ? eventType : (eventType = envelope.c.endsWith('-pnpres') ? PubNubEventType.Presence : PubNubEventType.Message); + // Check whether payload is string (potentially encrypted data). + if (typeof envelope.d === 'string') { + if (eventType == PubNubEventType.Message) { + return { + type: PubNubEventType.Message, + data: this.messageFromEnvelope(envelope), + }; + } + return { + type: PubNubEventType.Files, + data: this.fileFromEnvelope(envelope), + }; + } + else if (eventType == PubNubEventType.Message) { + return { + type: PubNubEventType.Message, + data: this.messageFromEnvelope(envelope), + }; + } + else if (eventType === PubNubEventType.Presence) { + return { + type: PubNubEventType.Presence, + data: this.presenceEventFromEnvelope(envelope), + }; + } + else if (eventType == PubNubEventType.Signal) { + return { + type: PubNubEventType.Signal, + data: this.signalFromEnvelope(envelope), + }; + } + else if (eventType === PubNubEventType.AppContext) { + return { + type: PubNubEventType.AppContext, + data: this.appContextFromEnvelope(envelope), + }; + } + else if (eventType === PubNubEventType.MessageAction) { + return { + type: PubNubEventType.MessageAction, + data: this.messageActionFromEnvelope(envelope), + }; + } + return { + type: PubNubEventType.Files, + data: this.fileFromEnvelope(envelope), + }; + }); + return { + cursor: { timetoken: serviceResponse.t.t, region: serviceResponse.t.r }, + messages: events, + }; + }); + } + get headers() { + return { accept: 'text/javascript' }; + } + // -------------------------------------------------------- + // ------------------ Envelope parsing -------------------- + // -------------------------------------------------------- + // region Envelope parsing + presenceEventFromEnvelope(envelope) { + const { d: payload } = envelope; + const [channel, subscription] = this.subscriptionChannelFromEnvelope(envelope); + // Clean up channel and subscription name from presence suffix. + const trimmedChannel = channel.replace('-pnpres', ''); + // Backward compatibility with deprecated properties. + const actualChannel = subscription !== null ? trimmedChannel : null; + const subscribedChannel = subscription !== null ? subscription : trimmedChannel; + if (typeof payload !== 'string' && 'data' in payload) { + // @ts-expect-error This is `state-change` object which should have `state` field. + payload['state'] = payload.data; + delete payload.data; + } + return Object.assign({ channel: trimmedChannel, subscription, + actualChannel, + subscribedChannel, timetoken: envelope.p.t }, payload); + } + messageFromEnvelope(envelope) { + const [channel, subscription] = this.subscriptionChannelFromEnvelope(envelope); + const [message, decryptionError] = this.decryptedData(envelope.d); + // Backward compatibility with deprecated properties. + const actualChannel = subscription !== null ? channel : null; + const subscribedChannel = subscription !== null ? subscription : channel; + // Basic message event payload. + const event = { + channel, + subscription, + actualChannel, + subscribedChannel, + timetoken: envelope.p.t, + publisher: envelope.i, + message, + }; + if (envelope.u) + event.userMetadata = envelope.u; + if (decryptionError) + event.error = decryptionError; + return event; + } + signalFromEnvelope(envelope) { + const [channel, subscription] = this.subscriptionChannelFromEnvelope(envelope); + const event = { + channel, + subscription, + timetoken: envelope.p.t, + publisher: envelope.i, + message: envelope.d, + }; + if (envelope.u) + event.userMetadata = envelope.u; + return event; + } + messageActionFromEnvelope(envelope) { + const [channel, subscription] = this.subscriptionChannelFromEnvelope(envelope); + const action = envelope.d; + return { + channel, + subscription, + timetoken: envelope.p.t, + publisher: envelope.i, + event: action.event, + data: Object.assign(Object.assign({}, action.data), { uuid: envelope.i }), + }; + } + appContextFromEnvelope(envelope) { + const [channel, subscription] = this.subscriptionChannelFromEnvelope(envelope); + const object = envelope.d; + return { + channel, + subscription, + timetoken: envelope.p.t, + message: object, + }; + } + fileFromEnvelope(envelope) { + const [channel, subscription] = this.subscriptionChannelFromEnvelope(envelope); + const [file, decryptionError] = this.decryptedData(envelope.d); + let errorMessage = decryptionError; + // Basic file event payload. + const event = { + channel, + subscription, + timetoken: envelope.p.t, + publisher: envelope.i, + }; + if (envelope.u) + event.userMetadata = envelope.u; + if (!file) + errorMessage !== null && errorMessage !== void 0 ? errorMessage : (errorMessage = `File information payload is missing.`); + else if (typeof file === 'string') + errorMessage !== null && errorMessage !== void 0 ? errorMessage : (errorMessage = `Unexpected file information payload data type.`); + else { + event.message = file.message; + if (file.file) { + event.file = { + id: file.file.id, + name: file.file.name, + url: this.parameters.getFileUrl({ id: file.file.id, name: file.file.name, channel }), + }; + } + } + if (errorMessage) + event.error = errorMessage; + return event; + } + // endregion + subscriptionChannelFromEnvelope(envelope) { + return [envelope.c, envelope.b === undefined ? envelope.c : envelope.b]; + } + /** + * Decrypt provided `data`. + * + * @param [data] - Message or file information which should be decrypted if possible. + * + * @returns Tuple with decrypted data and decryption error (if any). + */ + decryptedData(data) { + if (!this.parameters.crypto || typeof data !== 'string') + return [data, undefined]; + let payload; + let error; + try { + const decryptedData = this.parameters.crypto.decrypt(data); + payload = + decryptedData instanceof ArrayBuffer + ? JSON.parse(SubscribeRequest.decoder.decode(decryptedData)) + : decryptedData; + } + catch (err) { + payload = null; + error = `Error while decrypting message content: ${err.message}`; + } + return [(payload !== null && payload !== void 0 ? payload : data), error]; + } + } + /** + * Subscribe request. + */ + class SubscribeRequest extends BaseSubscribeRequest { + get path() { + var _a; + const { keySet: { subscribeKey }, channels, } = this.parameters; + return `/v2/subscribe/${subscribeKey}/${encodeNames((_a = channels === null || channels === void 0 ? void 0 : channels.sort()) !== null && _a !== void 0 ? _a : [], ',')}/0`; + } + get queryParameters() { + const { channelGroups, filterExpression, heartbeat, state, timetoken, region } = this.parameters; + const query = {}; + if (channelGroups && channelGroups.length > 0) + query['channel-group'] = channelGroups.sort().join(','); + if (filterExpression && filterExpression.length > 0) + query['filter-expr'] = filterExpression; + if (heartbeat) + query.heartbeat = heartbeat; + if (state && Object.keys(state).length > 0) + query['state'] = JSON.stringify(state); + if (timetoken !== undefined && typeof timetoken === 'string') { + if (timetoken.length > 0 && timetoken !== '0') + query['tt'] = timetoken; + } + else if (timetoken !== undefined && timetoken > 0) + query['tt'] = timetoken; + if (region) + query['tr'] = region; + return query; + } + } + + class EventEmitter { + constructor(listenerManager) { + this.listenerManager = listenerManager; + /** + * Map of channels to listener callbacks for them. + */ + this.channelListenerMap = new Map(); + /** + * Map of channel group names to the listener callbacks for them. + */ + this.groupListenerMap = new Map(); + } + /** + * Emit specific real-time event. + * + * Proper listener will be notified basing on event `type`. + * + * @param event - Received real-time event. + */ + emitEvent(event) { + if (event.type === PubNubEventType.Message) { + this.listenerManager.announceMessage(event.data); + this.announce('message', event.data, event.data.channel, event.data.subscription); + } + else if (event.type === PubNubEventType.Signal) { + this.listenerManager.announceSignal(event.data); + this.announce('signal', event.data, event.data.channel, event.data.subscription); + } + else if (event.type === PubNubEventType.Presence) { + this.listenerManager.announcePresence(event.data); + this.announce('presence', event.data, event.data.channel, event.data.subscription); + } + else if (event.type === PubNubEventType.AppContext) { + const { data: objectEvent } = event; + const { message: object } = objectEvent; + this.listenerManager.announceObjects(objectEvent); + this.announce('objects', objectEvent, objectEvent.channel, objectEvent.subscription); + if (object.type === 'uuid') { + const { message, channel } = objectEvent, restEvent = __rest(objectEvent, ["message", "channel"]); + const { event, type } = object, restObject = __rest(object, ["event", "type"]); + const userEvent = Object.assign(Object.assign({}, restEvent), { spaceId: channel, message: Object.assign(Object.assign({}, restObject), { event: event === 'set' ? 'updated' : 'removed', type: 'user' }) }); + this.listenerManager.announceUser(userEvent); + this.announce('user', userEvent, userEvent.spaceId, userEvent.subscription); + } + else if (object.type === 'channel') { + const { message, channel } = objectEvent, restEvent = __rest(objectEvent, ["message", "channel"]); + const { event, type } = object, restObject = __rest(object, ["event", "type"]); + const spaceEvent = Object.assign(Object.assign({}, restEvent), { spaceId: channel, message: Object.assign(Object.assign({}, restObject), { event: event === 'set' ? 'updated' : 'removed', type: 'space' }) }); + this.listenerManager.announceSpace(spaceEvent); + this.announce('space', spaceEvent, spaceEvent.spaceId, spaceEvent.subscription); + } + else if (object.type === 'membership') { + const { message, channel } = objectEvent, restEvent = __rest(objectEvent, ["message", "channel"]); + const { event, data } = object, restObject = __rest(object, ["event", "data"]); + const { uuid, channel: channelMeta } = data, restData = __rest(data, ["uuid", "channel"]); + const membershipEvent = Object.assign(Object.assign({}, restEvent), { spaceId: channel, message: Object.assign(Object.assign({}, restObject), { event: event === 'set' ? 'updated' : 'removed', data: Object.assign(Object.assign({}, restData), { user: uuid, space: channelMeta }) }) }); + this.listenerManager.announceMembership(membershipEvent); + this.announce('membership', membershipEvent, membershipEvent.spaceId, membershipEvent.subscription); + } + } + else if (event.type === PubNubEventType.MessageAction) { + this.listenerManager.announceMessageAction(event.data); + this.announce('messageAction', event.data, event.data.channel, event.data.subscription); + } + else if (event.type === PubNubEventType.Files) { + this.listenerManager.announceFile(event.data); + this.announce('file', event.data, event.data.channel, event.data.subscription); + } + } + /** + * Register real-time event listener for specific channels and groups. + * + * @param listener - Listener with event callbacks to handle different types of events. + * @param channels - List of channels for which listener should be registered. + * @param groups - List of channel groups for which listener should be registered. + */ + addListener(listener, channels, groups) { + // Register event-listener listener globally. + if (!(channels && groups)) { + this.listenerManager.addListener(listener); + } + else { + channels === null || channels === void 0 ? void 0 : channels.forEach((channel) => { + if (this.channelListenerMap.has(channel)) { + const channelListeners = this.channelListenerMap.get(channel); + if (!channelListeners.includes(listener)) + channelListeners.push(listener); + } + else + this.channelListenerMap.set(channel, [listener]); + }); + groups === null || groups === void 0 ? void 0 : groups.forEach((group) => { + if (this.groupListenerMap.has(group)) { + const groupListeners = this.groupListenerMap.get(group); + if (!groupListeners.includes(listener)) + groupListeners.push(listener); + } + else + this.groupListenerMap.set(group, [listener]); + }); + } + } + /** + * Remove real-time event listener. + * + * @param listener - Event listeners which should be removed. + * @param channels - List of channels for which listener should be removed. + * @param groups - List of channel groups for which listener should be removed. + */ + removeListener(listener, channels, groups) { + if (!(channels && groups)) { + this.listenerManager.removeListener(listener); + } + else { + channels === null || channels === void 0 ? void 0 : channels.forEach((channel) => { + if (this.channelListenerMap.has(channel)) { + this.channelListenerMap.set(channel, this.channelListenerMap.get(channel).filter((channelListener) => channelListener !== listener)); + } + }); + groups === null || groups === void 0 ? void 0 : groups.forEach((group) => { + if (this.groupListenerMap.has(group)) { + this.groupListenerMap.set(group, this.groupListenerMap.get(group).filter((groupListener) => groupListener !== listener)); + } + }); + } + } + /** + * Clear all real-time event listeners. + */ + removeAllListeners() { + this.listenerManager.removeAllListeners(); + this.channelListenerMap.clear(); + this.groupListenerMap.clear(); + } + /** + * Announce real-time event to all listeners. + * + * @param type - Type of event which should be announced. + * @param event - Announced real-time event payload. + * @param channel - Name of the channel for which registered listeners should be notified. + * @param group - Name of the channel group for which registered listeners should be notified. + */ + announce(type, event, channel, group) { + if (event && this.channelListenerMap.has(channel)) + this.channelListenerMap.get(channel).forEach((listener) => { + const typedListener = listener[type]; + // @ts-expect-error Dynamic events mapping. + if (typedListener) + typedListener(event); + }); + if (group && this.groupListenerMap.has(group)) + this.groupListenerMap.get(group).forEach((listener) => { + const typedListener = listener[type]; + // @ts-expect-error Dynamic events mapping. + if (typedListener) + typedListener(event); + }); + } + } + + class Subject { + constructor(sync = false) { + this.sync = sync; + this.listeners = new Set(); + } + subscribe(listener) { + this.listeners.add(listener); + return () => { + this.listeners.delete(listener); + }; + } + notify(event) { + const wrapper = () => { + this.listeners.forEach((listener) => { + listener(event); + }); + }; + if (this.sync) { + wrapper(); + } + else { + setTimeout(wrapper, 0); + } + } + } + + /* eslint-disable @typescript-eslint/no-explicit-any */ + class State { + transition(context, event) { + var _a; + if (this.transitionMap.has(event.type)) { + return (_a = this.transitionMap.get(event.type)) === null || _a === void 0 ? void 0 : _a(context, event); + } + return undefined; + } + constructor(label) { + this.label = label; + this.transitionMap = new Map(); + this.enterEffects = []; + this.exitEffects = []; + } + on(eventType, transition) { + this.transitionMap.set(eventType, transition); + return this; + } + with(context, effects) { + return [this, context, effects !== null && effects !== void 0 ? effects : []]; + } + onEnter(effect) { + this.enterEffects.push(effect); + return this; + } + onExit(effect) { + this.exitEffects.push(effect); + return this; + } + } + + /* eslint-disable @typescript-eslint/no-explicit-any */ + class Engine extends Subject { + describe(label) { + return new State(label); + } + start(initialState, initialContext) { + this.currentState = initialState; + this.currentContext = initialContext; + this.notify({ + type: 'engineStarted', + state: initialState, + context: initialContext, + }); + return; + } + transition(event) { + if (!this.currentState) { + throw new Error('Start the engine first'); + } + this.notify({ + type: 'eventReceived', + event: event, + }); + const transition = this.currentState.transition(this.currentContext, event); + if (transition) { + const [newState, newContext, effects] = transition; + for (const effect of this.currentState.exitEffects) { + this.notify({ + type: 'invocationDispatched', + invocation: effect(this.currentContext), + }); + } + const oldState = this.currentState; + this.currentState = newState; + const oldContext = this.currentContext; + this.currentContext = newContext; + this.notify({ + type: 'transitionDone', + fromState: oldState, + fromContext: oldContext, + toState: newState, + toContext: newContext, + event: event, + }); + for (const effect of effects) { + this.notify({ + type: 'invocationDispatched', + invocation: effect, + }); + } + for (const effect of this.currentState.enterEffects) { + this.notify({ + type: 'invocationDispatched', + invocation: effect(this.currentContext), + }); + } + } + } + } + + /* eslint-disable @typescript-eslint/no-explicit-any */ + class Dispatcher { + constructor(dependencies) { + this.dependencies = dependencies; + this.instances = new Map(); + this.handlers = new Map(); + } + on(type, handlerCreator) { + this.handlers.set(type, handlerCreator); + } + dispatch(invocation) { + if (invocation.type === 'CANCEL') { + if (this.instances.has(invocation.payload)) { + const instance = this.instances.get(invocation.payload); + instance === null || instance === void 0 ? void 0 : instance.cancel(); + this.instances.delete(invocation.payload); + } + return; + } + const handlerCreator = this.handlers.get(invocation.type); + if (!handlerCreator) { + throw new Error(`Unhandled invocation '${invocation.type}'`); + } + const instance = handlerCreator(invocation.payload, this.dependencies); + if (invocation.managed) { + this.instances.set(invocation.type, instance); + } + instance.start(); + } + dispose() { + for (const [key, instance] of this.instances.entries()) { + instance.cancel(); + this.instances.delete(key); + } + } + } + + /* eslint-disable @typescript-eslint/no-explicit-any */ + function createEvent(type, fn) { + const creator = function (...args) { + return { + type, + payload: fn === null || fn === void 0 ? void 0 : fn(...args), + }; + }; + creator.type = type; + return creator; + } + function createEffect(type, fn) { + const creator = (...args) => { + return { type, payload: fn(...args), managed: false }; + }; + creator.type = type; + return creator; + } + function createManagedEffect(type, fn) { + const creator = (...args) => { + return { type, payload: fn(...args), managed: true }; + }; + creator.type = type; + creator.cancel = { type: 'CANCEL', payload: type, managed: false }; + return creator; + } + + class AbortError extends Error { + constructor() { + super('The operation was aborted.'); + this.name = 'AbortError'; + Object.setPrototypeOf(this, new.target.prototype); + } + } + class AbortSignal extends Subject { + constructor() { + super(...arguments); + this._aborted = false; + } + get aborted() { + return this._aborted; + } + throwIfAborted() { + if (this._aborted) { + throw new AbortError(); + } + } + abort() { + this._aborted = true; + this.notify(new AbortError()); + } + } + + class Handler { + constructor(payload, dependencies) { + this.payload = payload; + this.dependencies = dependencies; + } + } + class AsyncHandler extends Handler { + constructor(payload, dependencies, asyncFunction) { + super(payload, dependencies); + this.asyncFunction = asyncFunction; + this.abortSignal = new AbortSignal(); + } + start() { + this.asyncFunction(this.payload, this.abortSignal, this.dependencies).catch((error) => { + // console.log('Unhandled error:', error); + // swallow the error + }); + } + cancel() { + this.abortSignal.abort(); + } + } + const asyncHandler = (handlerFunction) => (payload, dependencies) => new AsyncHandler(payload, dependencies, handlerFunction); + + const reconnect$1 = createEvent('RECONNECT', () => ({})); + const disconnect$1 = createEvent('DISCONNECT', () => ({})); + const joined = createEvent('JOINED', (channels, groups) => ({ + channels, + groups, + })); + const left = createEvent('LEFT', (channels, groups) => ({ + channels, + groups, + })); + const leftAll = createEvent('LEFT_ALL', () => ({})); + const heartbeatSuccess = createEvent('HEARTBEAT_SUCCESS', (statusCode) => ({ statusCode })); + const heartbeatFailure = createEvent('HEARTBEAT_FAILURE', (error) => error); + const heartbeatGiveup = createEvent('HEARTBEAT_GIVEUP', () => ({})); + const timesUp = createEvent('TIMES_UP', () => ({})); + + const heartbeat = createEffect('HEARTBEAT', (channels, groups) => ({ + channels, + groups, + })); + const leave = createEffect('LEAVE', (channels, groups) => ({ + channels, + groups, + })); + /* eslint-disable @typescript-eslint/no-explicit-any */ + const emitStatus$1 = createEffect('EMIT_STATUS', (status) => status); + const wait = createManagedEffect('WAIT', () => ({})); + const delayedHeartbeat = createManagedEffect('DELAYED_HEARTBEAT', (context) => context); + + class PresenceEventEngineDispatcher extends Dispatcher { + constructor(engine, dependencies) { + super(dependencies); + this.on(heartbeat.type, asyncHandler((payload_1, _1, _a) => __awaiter(this, [payload_1, _1, _a], void 0, function* (payload, _, { heartbeat, presenceState, config }) { + try { + const result = yield heartbeat(Object.assign(Object.assign({ channels: payload.channels, channelGroups: payload.groups }, (config.maintainPresenceState && { state: presenceState })), { heartbeat: config.presenceTimeout })); + engine.transition(heartbeatSuccess(200)); + } + catch (e) { + if (e instanceof PubNubError) { + if (e.status && e.status.category == StatusCategory$1.PNCancelledCategory) + return; + return engine.transition(heartbeatFailure(e)); + } + } + }))); + this.on(leave.type, asyncHandler((payload_2, _2, _b) => __awaiter(this, [payload_2, _2, _b], void 0, function* (payload, _, { leave, config }) { + if (!config.suppressLeaveEvents) { + try { + leave({ + channels: payload.channels, + channelGroups: payload.groups, + }); + } + catch (e) { } + } + }))); + this.on(wait.type, asyncHandler((_3, abortSignal_1, _c) => __awaiter(this, [_3, abortSignal_1, _c], void 0, function* (_, abortSignal, { heartbeatDelay }) { + abortSignal.throwIfAborted(); + yield heartbeatDelay(); + abortSignal.throwIfAborted(); + return engine.transition(timesUp()); + }))); + this.on(delayedHeartbeat.type, asyncHandler((payload_3, abortSignal_2, _d) => __awaiter(this, [payload_3, abortSignal_2, _d], void 0, function* (payload, abortSignal, { heartbeat, retryDelay, presenceState, config }) { + if (config.retryConfiguration && config.retryConfiguration.shouldRetry(payload.reason, payload.attempts)) { + abortSignal.throwIfAborted(); + yield retryDelay(config.retryConfiguration.getDelay(payload.attempts, payload.reason)); + abortSignal.throwIfAborted(); + try { + const result = yield heartbeat(Object.assign(Object.assign({ channels: payload.channels, channelGroups: payload.groups }, (config.maintainPresenceState && { state: presenceState })), { heartbeat: config.presenceTimeout })); + return engine.transition(heartbeatSuccess(200)); + } + catch (e) { + if (e instanceof PubNubError) { + if (e.status && e.status.category == StatusCategory$1.PNCancelledCategory) + return; + return engine.transition(heartbeatFailure(e)); + } + } + } + else { + return engine.transition(heartbeatGiveup()); + } + }))); + this.on(emitStatus$1.type, asyncHandler((payload_4, _4, _e) => __awaiter(this, [payload_4, _4, _e], void 0, function* (payload, _, { emitStatus, config }) { + var _f; + if (config.announceFailedHeartbeats && ((_f = payload === null || payload === void 0 ? void 0 : payload.status) === null || _f === void 0 ? void 0 : _f.error) === true) { + emitStatus(payload.status); + } + else if (config.announceSuccessfulHeartbeats && payload.statusCode === 200) { + emitStatus(Object.assign(Object.assign({}, payload), { operation: RequestOperation$1.PNHeartbeatOperation, error: false })); + } + }))); + } + } + + const HeartbeatStoppedState = new State('HEARTBEAT_STOPPED'); + HeartbeatStoppedState.on(joined.type, (context, event) => HeartbeatStoppedState.with({ + channels: [...context.channels, ...event.payload.channels], + groups: [...context.groups, ...event.payload.groups], + })); + HeartbeatStoppedState.on(left.type, (context, event) => HeartbeatStoppedState.with({ + channels: context.channels.filter((channel) => !event.payload.channels.includes(channel)), + groups: context.groups.filter((group) => !event.payload.groups.includes(group)), + })); + HeartbeatStoppedState.on(reconnect$1.type, (context, _) => HeartbeatingState.with({ + channels: context.channels, + groups: context.groups, + })); + HeartbeatStoppedState.on(leftAll.type, (context, _) => HeartbeatInactiveState.with(undefined)); + + const HeartbeatCooldownState = new State('HEARTBEAT_COOLDOWN'); + HeartbeatCooldownState.onEnter(() => wait()); + HeartbeatCooldownState.onExit(() => wait.cancel); + HeartbeatCooldownState.on(timesUp.type, (context, _) => HeartbeatingState.with({ + channels: context.channels, + groups: context.groups, + })); + HeartbeatCooldownState.on(joined.type, (context, event) => HeartbeatingState.with({ + channels: [...context.channels, ...event.payload.channels], + groups: [...context.groups, ...event.payload.groups], + })); + HeartbeatCooldownState.on(left.type, (context, event) => HeartbeatingState.with({ + channels: context.channels.filter((channel) => !event.payload.channels.includes(channel)), + groups: context.groups.filter((group) => !event.payload.groups.includes(group)), + }, [leave(event.payload.channels, event.payload.groups)])); + HeartbeatCooldownState.on(disconnect$1.type, (context) => HeartbeatStoppedState.with({ + channels: context.channels, + groups: context.groups, + }, [leave(context.channels, context.groups)])); + HeartbeatCooldownState.on(leftAll.type, (context, _) => HeartbeatInactiveState.with(undefined, [leave(context.channels, context.groups)])); + + const HeartbeatFailedState = new State('HEARTBEAT_FAILED'); + HeartbeatFailedState.on(joined.type, (context, event) => HeartbeatingState.with({ + channels: [...context.channels, ...event.payload.channels], + groups: [...context.groups, ...event.payload.groups], + })); + HeartbeatFailedState.on(left.type, (context, event) => HeartbeatingState.with({ + channels: context.channels.filter((channel) => !event.payload.channels.includes(channel)), + groups: context.groups.filter((group) => !event.payload.groups.includes(group)), + }, [leave(event.payload.channels, event.payload.groups)])); + HeartbeatFailedState.on(reconnect$1.type, (context, _) => HeartbeatingState.with({ + channels: context.channels, + groups: context.groups, + })); + HeartbeatFailedState.on(disconnect$1.type, (context, _) => HeartbeatStoppedState.with({ + channels: context.channels, + groups: context.groups, + }, [leave(context.channels, context.groups)])); + HeartbeatFailedState.on(leftAll.type, (context, _) => HeartbeatInactiveState.with(undefined, [leave(context.channels, context.groups)])); + + const HearbeatReconnectingState = new State('HEARBEAT_RECONNECTING'); + HearbeatReconnectingState.onEnter((context) => delayedHeartbeat(context)); + HearbeatReconnectingState.onExit(() => delayedHeartbeat.cancel); + HearbeatReconnectingState.on(joined.type, (context, event) => HeartbeatingState.with({ + channels: [...context.channels, ...event.payload.channels], + groups: [...context.groups, ...event.payload.groups], + })); + HearbeatReconnectingState.on(left.type, (context, event) => HeartbeatingState.with({ + channels: context.channels.filter((channel) => !event.payload.channels.includes(channel)), + groups: context.groups.filter((group) => !event.payload.groups.includes(group)), + }, [leave(event.payload.channels, event.payload.groups)])); + HearbeatReconnectingState.on(disconnect$1.type, (context, _) => { + HeartbeatStoppedState.with({ + channels: context.channels, + groups: context.groups, + }, [leave(context.channels, context.groups)]); + }); + HearbeatReconnectingState.on(heartbeatSuccess.type, (context, event) => { + return HeartbeatCooldownState.with({ + channels: context.channels, + groups: context.groups, + }); + }); + HearbeatReconnectingState.on(heartbeatFailure.type, (context, event) => HearbeatReconnectingState.with(Object.assign(Object.assign({}, context), { attempts: context.attempts + 1, reason: event.payload }))); + HearbeatReconnectingState.on(heartbeatGiveup.type, (context, event) => { + return HeartbeatFailedState.with({ + channels: context.channels, + groups: context.groups, + }); + }); + HearbeatReconnectingState.on(leftAll.type, (context, _) => HeartbeatInactiveState.with(undefined, [leave(context.channels, context.groups)])); + + const HeartbeatingState = new State('HEARTBEATING'); + HeartbeatingState.onEnter((context) => heartbeat(context.channels, context.groups)); + HeartbeatingState.on(heartbeatSuccess.type, (context, event) => { + return HeartbeatCooldownState.with({ + channels: context.channels, + groups: context.groups, + }); + }); + HeartbeatingState.on(joined.type, (context, event) => HeartbeatingState.with({ + channels: [...context.channels, ...event.payload.channels], + groups: [...context.groups, ...event.payload.groups], + })); + HeartbeatingState.on(left.type, (context, event) => { + return HeartbeatingState.with({ + channels: context.channels.filter((channel) => !event.payload.channels.includes(channel)), + groups: context.groups.filter((group) => !event.payload.groups.includes(group)), + }, [leave(event.payload.channels, event.payload.groups)]); + }); + HeartbeatingState.on(heartbeatFailure.type, (context, event) => { + return HearbeatReconnectingState.with(Object.assign(Object.assign({}, context), { attempts: 0, reason: event.payload })); + }); + HeartbeatingState.on(disconnect$1.type, (context) => HeartbeatStoppedState.with({ + channels: context.channels, + groups: context.groups, + }, [leave(context.channels, context.groups)])); + HeartbeatingState.on(leftAll.type, (context, _) => HeartbeatInactiveState.with(undefined, [leave(context.channels, context.groups)])); + + const HeartbeatInactiveState = new State('HEARTBEAT_INACTIVE'); + HeartbeatInactiveState.on(joined.type, (_, event) => HeartbeatingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + })); + + class PresenceEventEngine { + get _engine() { + return this.engine; + } + constructor(dependencies) { + this.dependencies = dependencies; + this.engine = new Engine(); + this.channels = []; + this.groups = []; + this.dispatcher = new PresenceEventEngineDispatcher(this.engine, dependencies); + this._unsubscribeEngine = this.engine.subscribe((change) => { + if (change.type === 'invocationDispatched') { + this.dispatcher.dispatch(change.invocation); + } + }); + this.engine.start(HeartbeatInactiveState, undefined); + } + join({ channels, groups }) { + this.channels = [...this.channels, ...(channels !== null && channels !== void 0 ? channels : [])]; + this.groups = [...this.groups, ...(groups !== null && groups !== void 0 ? groups : [])]; + this.engine.transition(joined(this.channels.slice(0), this.groups.slice(0))); + } + leave({ channels, groups }) { + if (this.dependencies.presenceState) { + channels === null || channels === void 0 ? void 0 : channels.forEach((c) => delete this.dependencies.presenceState[c]); + groups === null || groups === void 0 ? void 0 : groups.forEach((g) => delete this.dependencies.presenceState[g]); + } + this.engine.transition(left(channels !== null && channels !== void 0 ? channels : [], groups !== null && groups !== void 0 ? groups : [])); + } + leaveAll() { + this.engine.transition(leftAll()); + } + dispose() { + this._unsubscribeEngine(); + this.dispatcher.dispose(); + } + } + + class RetryPolicy { + static LinearRetryPolicy(configuration) { + return { + delay: configuration.delay, + maximumRetry: configuration.maximumRetry, + /* eslint-disable @typescript-eslint/no-explicit-any */ + shouldRetry(error, attempt) { + var _a; + if (((_a = error === null || error === void 0 ? void 0 : error.status) === null || _a === void 0 ? void 0 : _a.statusCode) === 403) { + return false; + } + return this.maximumRetry > attempt; + }, + getDelay(_, reason) { + var _a; + const delay = (_a = reason.retryAfter) !== null && _a !== void 0 ? _a : this.delay; + return (delay + Math.random()) * 1000; + }, + /* eslint-disable @typescript-eslint/no-explicit-any */ + getGiveupReason(error, attempt) { + var _a; + if (this.maximumRetry <= attempt) { + return 'retry attempts exhaused.'; + } + if (((_a = error === null || error === void 0 ? void 0 : error.status) === null || _a === void 0 ? void 0 : _a.statusCode) === 403) { + return 'forbidden operation.'; + } + return 'unknown error'; + }, + validate() { + if (this.maximumRetry > 10) + throw new Error('Maximum retry for linear retry policy can not be more than 10'); + }, + }; + } + static ExponentialRetryPolicy(configuration) { + return { + minimumDelay: configuration.minimumDelay, + maximumDelay: configuration.maximumDelay, + maximumRetry: configuration.maximumRetry, + shouldRetry(reason, attempt) { + var _a; + if (((_a = reason === null || reason === void 0 ? void 0 : reason.status) === null || _a === void 0 ? void 0 : _a.statusCode) === 403) { + return false; + } + return this.maximumRetry > attempt; + }, + getDelay(attempt, reason) { + var _a; + const delay = (_a = reason.retryAfter) !== null && _a !== void 0 ? _a : Math.min(Math.pow(2, attempt), this.maximumDelay); + return (delay + Math.random()) * 1000; + }, + getGiveupReason(reason, attempt) { + var _a; + if (this.maximumRetry <= attempt) { + return 'retry attempts exhausted.'; + } + if (((_a = reason === null || reason === void 0 ? void 0 : reason.status) === null || _a === void 0 ? void 0 : _a.statusCode) === 403) { + return 'forbidden operation.'; + } + return 'unknown error'; + }, + validate() { + if (this.minimumDelay < 2) + throw new Error('Minimum delay can not be set less than 2 seconds for retry'); + else if (this.maximumDelay) + throw new Error('Maximum delay can not be set more than 150 seconds for retry'); + else if (this.maximumRetry > 6) + throw new Error('Maximum retry for exponential retry policy can not be more than 6'); + }, + }; + } + } + + const handshake = createManagedEffect('HANDSHAKE', (channels, groups) => ({ + channels, + groups, + })); + const receiveMessages = createManagedEffect('RECEIVE_MESSAGES', (channels, groups, cursor) => ({ channels, groups, cursor })); + const emitMessages = createEffect('EMIT_MESSAGES', (events) => events); + const emitStatus = createEffect('EMIT_STATUS', (status) => status); + const receiveReconnect = createManagedEffect('RECEIVE_RECONNECT', (context) => context); + const handshakeReconnect = createManagedEffect('HANDSHAKE_RECONNECT', (context) => context); + + const subscriptionChange = createEvent('SUBSCRIPTION_CHANGED', (channels, groups) => ({ + channels, + groups, + })); + const restore = createEvent('SUBSCRIPTION_RESTORED', (channels, groups, timetoken, region) => ({ + channels, + groups, + cursor: { + timetoken: timetoken, + region: region !== null && region !== void 0 ? region : 0, + }, + })); + const handshakeSuccess = createEvent('HANDSHAKE_SUCCESS', (cursor) => cursor); + const handshakeFailure = createEvent('HANDSHAKE_FAILURE', (error) => error); + const handshakeReconnectSuccess = createEvent('HANDSHAKE_RECONNECT_SUCCESS', (cursor) => ({ + cursor, + })); + const handshakeReconnectFailure = createEvent('HANDSHAKE_RECONNECT_FAILURE', (error) => error); + const handshakeReconnectGiveup = createEvent('HANDSHAKE_RECONNECT_GIVEUP', (error) => error); + const receiveSuccess = createEvent('RECEIVE_SUCCESS', (cursor, events) => ({ + cursor, + events, + })); + const receiveFailure = createEvent('RECEIVE_FAILURE', (error) => error); + const receiveReconnectSuccess = createEvent('RECEIVE_RECONNECT_SUCCESS', (cursor, events) => ({ + cursor, + events, + })); + const receiveReconnectFailure = createEvent('RECEIVE_RECONNECT_FAILURE', (error) => error); + const receiveReconnectGiveup = createEvent('RECEIVING_RECONNECT_GIVEUP', (error) => error); + const disconnect = createEvent('DISCONNECT', () => ({})); + const reconnect = createEvent('RECONNECT', (timetoken, region) => ({ + cursor: { + timetoken: timetoken !== null && timetoken !== void 0 ? timetoken : '', + region: region !== null && region !== void 0 ? region : 0, + }, + })); + const unsubscribeAll = createEvent('UNSUBSCRIBE_ALL', () => ({})); + + class EventEngineDispatcher extends Dispatcher { + constructor(engine, dependencies) { + super(dependencies); + this.on(handshake.type, asyncHandler((payload_1, abortSignal_1, _a) => __awaiter(this, [payload_1, abortSignal_1, _a], void 0, function* (payload, abortSignal, { handshake, presenceState, config }) { + abortSignal.throwIfAborted(); + try { + const result = yield handshake(Object.assign({ abortSignal: abortSignal, channels: payload.channels, channelGroups: payload.groups, filterExpression: config.filterExpression }, (config.maintainPresenceState && { state: presenceState }))); + return engine.transition(handshakeSuccess(result)); + } + catch (e) { + if (e instanceof PubNubError) { + if (e.status && e.status.category == StatusCategory$1.PNCancelledCategory) + return; + return engine.transition(handshakeFailure(e)); + } + } + }))); + this.on(receiveMessages.type, asyncHandler((payload_2, abortSignal_2, _b) => __awaiter(this, [payload_2, abortSignal_2, _b], void 0, function* (payload, abortSignal, { receiveMessages, config }) { + abortSignal.throwIfAborted(); + try { + const result = yield receiveMessages({ + abortSignal: abortSignal, + channels: payload.channels, + channelGroups: payload.groups, + timetoken: payload.cursor.timetoken, + region: payload.cursor.region, + filterExpression: config.filterExpression, + }); + engine.transition(receiveSuccess(result.cursor, result.messages)); + } + catch (error) { + if (error instanceof PubNubError) { + if (error.status && error.status.category == StatusCategory$1.PNCancelledCategory) + return; + if (!abortSignal.aborted) + return engine.transition(receiveFailure(error)); + } + } + }))); + this.on(emitMessages.type, asyncHandler((payload_3, _1, _c) => __awaiter(this, [payload_3, _1, _c], void 0, function* (payload, _, { emitMessages }) { + if (payload.length > 0) { + emitMessages(payload); + } + }))); + this.on(emitStatus.type, asyncHandler((payload_4, _2, _d) => __awaiter(this, [payload_4, _2, _d], void 0, function* (payload, _, { emitStatus }) { + emitStatus(payload); + }))); + this.on(receiveReconnect.type, asyncHandler((payload_5, abortSignal_3, _e) => __awaiter(this, [payload_5, abortSignal_3, _e], void 0, function* (payload, abortSignal, { receiveMessages, delay, config }) { + if (config.retryConfiguration && config.retryConfiguration.shouldRetry(payload.reason, payload.attempts)) { + abortSignal.throwIfAborted(); + yield delay(config.retryConfiguration.getDelay(payload.attempts, payload.reason)); + abortSignal.throwIfAborted(); + try { + const result = yield receiveMessages({ + abortSignal: abortSignal, + channels: payload.channels, + channelGroups: payload.groups, + timetoken: payload.cursor.timetoken, + region: payload.cursor.region, + filterExpression: config.filterExpression, + }); + return engine.transition(receiveReconnectSuccess(result.cursor, result.messages)); + } + catch (error) { + if (error instanceof PubNubError) { + if (error.status && error.status.category == StatusCategory$1.PNCancelledCategory) + return; + return engine.transition(receiveReconnectFailure(error)); + } + } + } + else { + return engine.transition(receiveReconnectGiveup(new PubNubError(config.retryConfiguration + ? config.retryConfiguration.getGiveupReason(payload.reason, payload.attempts) + : 'Unable to complete subscribe messages receive.'))); + } + }))); + this.on(handshakeReconnect.type, asyncHandler((payload_6, abortSignal_4, _f) => __awaiter(this, [payload_6, abortSignal_4, _f], void 0, function* (payload, abortSignal, { handshake, delay, presenceState, config }) { + if (config.retryConfiguration && config.retryConfiguration.shouldRetry(payload.reason, payload.attempts)) { + abortSignal.throwIfAborted(); + yield delay(config.retryConfiguration.getDelay(payload.attempts, payload.reason)); + abortSignal.throwIfAborted(); + try { + const result = yield handshake(Object.assign({ abortSignal: abortSignal, channels: payload.channels, channelGroups: payload.groups, filterExpression: config.filterExpression }, (config.maintainPresenceState && { state: presenceState }))); + return engine.transition(handshakeReconnectSuccess(result)); + } + catch (error) { + if (error instanceof PubNubError) { + if (error.status && error.status.category == StatusCategory$1.PNCancelledCategory) + return; + return engine.transition(handshakeReconnectFailure(error)); + } + } + } + else { + return engine.transition(handshakeReconnectGiveup(new PubNubError(config.retryConfiguration + ? config.retryConfiguration.getGiveupReason(payload.reason, payload.attempts) + : 'Unable to complete subscribe handshake'))); + } + }))); + } + } + + const HandshakeFailedState = new State('HANDSHAKE_FAILED'); + HandshakeFailedState.on(subscriptionChange.type, (context, event) => HandshakingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: context.cursor, + })); + HandshakeFailedState.on(reconnect.type, (context, event) => HandshakingState.with({ + channels: context.channels, + groups: context.groups, + cursor: event.payload.cursor || context.cursor, + })); + HandshakeFailedState.on(restore.type, (context, event) => { + var _a, _b; + return HandshakingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: { + timetoken: event.payload.cursor.timetoken, + region: event.payload.cursor.region ? event.payload.cursor.region : (_b = (_a = context === null || context === void 0 ? void 0 : context.cursor) === null || _a === void 0 ? void 0 : _a.region) !== null && _b !== void 0 ? _b : 0, + }, + }); + }); + HandshakeFailedState.on(unsubscribeAll.type, (_) => UnsubscribedState.with()); + + const HandshakeStoppedState = new State('HANDSHAKE_STOPPED'); + HandshakeStoppedState.on(subscriptionChange.type, (context, event) => HandshakeStoppedState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: context.cursor, + })); + HandshakeStoppedState.on(reconnect.type, (context, event) => HandshakingState.with(Object.assign(Object.assign({}, context), { cursor: event.payload.cursor || context.cursor }))); + HandshakeStoppedState.on(restore.type, (context, event) => { + var _a; + return HandshakeStoppedState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: { + timetoken: event.payload.cursor.timetoken, + region: event.payload.cursor.region || ((_a = context === null || context === void 0 ? void 0 : context.cursor) === null || _a === void 0 ? void 0 : _a.region) || 0, + }, + }); + }); + HandshakeStoppedState.on(unsubscribeAll.type, (_) => UnsubscribedState.with()); + + const ReceiveFailedState = new State('RECEIVE_FAILED'); + ReceiveFailedState.on(reconnect.type, (context, event) => { + var _a; + return HandshakingState.with({ + channels: context.channels, + groups: context.groups, + cursor: { + timetoken: !!event.payload.cursor.timetoken ? (_a = event.payload.cursor) === null || _a === void 0 ? void 0 : _a.timetoken : context.cursor.timetoken, + region: event.payload.cursor.region || context.cursor.region, + }, + }); + }); + ReceiveFailedState.on(subscriptionChange.type, (context, event) => HandshakingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: context.cursor, + })); + ReceiveFailedState.on(restore.type, (context, event) => HandshakingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: { + timetoken: event.payload.cursor.timetoken, + region: event.payload.cursor.region || context.cursor.region, + }, + })); + ReceiveFailedState.on(unsubscribeAll.type, (_) => UnsubscribedState.with(undefined)); + + const ReceiveStoppedState = new State('RECEIVE_STOPPED'); + ReceiveStoppedState.on(subscriptionChange.type, (context, event) => ReceiveStoppedState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: context.cursor, + })); + ReceiveStoppedState.on(restore.type, (context, event) => ReceiveStoppedState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: { + timetoken: event.payload.cursor.timetoken, + region: event.payload.cursor.region || context.cursor.region, + }, + })); + ReceiveStoppedState.on(reconnect.type, (context, event) => { + var _a; + return HandshakingState.with({ + channels: context.channels, + groups: context.groups, + cursor: { + timetoken: !!event.payload.cursor.timetoken ? (_a = event.payload.cursor) === null || _a === void 0 ? void 0 : _a.timetoken : context.cursor.timetoken, + region: event.payload.cursor.region || context.cursor.region, + }, + }); + }); + ReceiveStoppedState.on(unsubscribeAll.type, () => UnsubscribedState.with(undefined)); + + const ReceiveReconnectingState = new State('RECEIVE_RECONNECTING'); + ReceiveReconnectingState.onEnter((context) => receiveReconnect(context)); + ReceiveReconnectingState.onExit(() => receiveReconnect.cancel); + ReceiveReconnectingState.on(receiveReconnectSuccess.type, (context, event) => ReceivingState.with({ + channels: context.channels, + groups: context.groups, + cursor: event.payload.cursor, + }, [emitMessages(event.payload.events)])); + ReceiveReconnectingState.on(receiveReconnectFailure.type, (context, event) => ReceiveReconnectingState.with(Object.assign(Object.assign({}, context), { attempts: context.attempts + 1, reason: event.payload }))); + ReceiveReconnectingState.on(receiveReconnectGiveup.type, (context, event) => { + var _a; + return ReceiveFailedState.with({ + groups: context.groups, + channels: context.channels, + cursor: context.cursor, + reason: event.payload, + }, [emitStatus({ category: StatusCategory$1.PNDisconnectedUnexpectedlyCategory, error: (_a = event.payload) === null || _a === void 0 ? void 0 : _a.message })]); + }); + ReceiveReconnectingState.on(disconnect.type, (context) => ReceiveStoppedState.with({ + channels: context.channels, + groups: context.groups, + cursor: context.cursor, + }, [emitStatus({ category: StatusCategory$1.PNDisconnectedCategory })])); + ReceiveReconnectingState.on(restore.type, (context, event) => ReceivingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: { + timetoken: event.payload.cursor.timetoken, + region: event.payload.cursor.region || context.cursor.region, + }, + })); + ReceiveReconnectingState.on(subscriptionChange.type, (context, event) => ReceivingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: context.cursor, + })); + ReceiveReconnectingState.on(unsubscribeAll.type, (_) => UnsubscribedState.with(undefined, [emitStatus({ category: StatusCategory$1.PNDisconnectedCategory })])); + + const ReceivingState = new State('RECEIVING'); + ReceivingState.onEnter((context) => receiveMessages(context.channels, context.groups, context.cursor)); + ReceivingState.onExit(() => receiveMessages.cancel); + ReceivingState.on(receiveSuccess.type, (context, event) => { + return ReceivingState.with({ channels: context.channels, groups: context.groups, cursor: event.payload.cursor }, [ + emitMessages(event.payload.events), + ]); + }); + ReceivingState.on(subscriptionChange.type, (context, event) => { + if (event.payload.channels.length === 0 && event.payload.groups.length === 0) { + return UnsubscribedState.with(undefined); + } + return ReceivingState.with({ + cursor: context.cursor, + channels: event.payload.channels, + groups: event.payload.groups, + }); + }); + ReceivingState.on(restore.type, (context, event) => { + if (event.payload.channels.length === 0 && event.payload.groups.length === 0) { + return UnsubscribedState.with(undefined); + } + return ReceivingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: { + timetoken: event.payload.cursor.timetoken, + region: event.payload.cursor.region || context.cursor.region, + }, + }); + }); + ReceivingState.on(receiveFailure.type, (context, event) => { + return ReceiveReconnectingState.with(Object.assign(Object.assign({}, context), { attempts: 0, reason: event.payload })); + }); + ReceivingState.on(disconnect.type, (context) => { + return ReceiveStoppedState.with({ + channels: context.channels, + groups: context.groups, + cursor: context.cursor, + }, [emitStatus({ category: StatusCategory$1.PNDisconnectedCategory })]); + }); + ReceivingState.on(unsubscribeAll.type, (_) => UnsubscribedState.with(undefined, [emitStatus({ category: StatusCategory$1.PNDisconnectedCategory })])); + + const HandshakeReconnectingState = new State('HANDSHAKE_RECONNECTING'); + HandshakeReconnectingState.onEnter((context) => handshakeReconnect(context)); + HandshakeReconnectingState.onExit(() => handshakeReconnect.cancel); + HandshakeReconnectingState.on(handshakeReconnectSuccess.type, (context, event) => { + var _a, _b; + const cursor = { + timetoken: !!((_a = context.cursor) === null || _a === void 0 ? void 0 : _a.timetoken) ? (_b = context.cursor) === null || _b === void 0 ? void 0 : _b.timetoken : event.payload.cursor.timetoken, + region: event.payload.cursor.region, + }; + return ReceivingState.with({ + channels: context.channels, + groups: context.groups, + cursor: cursor, + }, [emitStatus({ category: StatusCategory$1.PNConnectedCategory })]); + }); + HandshakeReconnectingState.on(handshakeReconnectFailure.type, (context, event) => HandshakeReconnectingState.with(Object.assign(Object.assign({}, context), { attempts: context.attempts + 1, reason: event.payload }))); + HandshakeReconnectingState.on(handshakeReconnectGiveup.type, (context, event) => { + var _a; + return HandshakeFailedState.with({ + groups: context.groups, + channels: context.channels, + cursor: context.cursor, + reason: event.payload, + }, [emitStatus({ category: StatusCategory$1.PNConnectionErrorCategory, error: (_a = event.payload) === null || _a === void 0 ? void 0 : _a.message })]); + }); + HandshakeReconnectingState.on(disconnect.type, (context) => HandshakeStoppedState.with({ + channels: context.channels, + groups: context.groups, + cursor: context.cursor, + })); + HandshakeReconnectingState.on(subscriptionChange.type, (context, event) => HandshakingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: context.cursor, + })); + HandshakeReconnectingState.on(restore.type, (context, event) => { + var _a, _b; + return HandshakingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: { + timetoken: event.payload.cursor.timetoken, + region: ((_a = event.payload.cursor) === null || _a === void 0 ? void 0 : _a.region) || ((_b = context === null || context === void 0 ? void 0 : context.cursor) === null || _b === void 0 ? void 0 : _b.region) || 0, + }, + }); + }); + HandshakeReconnectingState.on(unsubscribeAll.type, (_) => UnsubscribedState.with(undefined)); + + const HandshakingState = new State('HANDSHAKING'); + HandshakingState.onEnter((context) => handshake(context.channels, context.groups)); + HandshakingState.onExit(() => handshake.cancel); + HandshakingState.on(subscriptionChange.type, (context, event) => { + if (event.payload.channels.length === 0 && event.payload.groups.length === 0) { + return UnsubscribedState.with(undefined); + } + return HandshakingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: context.cursor, + }); + }); + HandshakingState.on(handshakeSuccess.type, (context, event) => { + var _a, _b; + return ReceivingState.with({ + channels: context.channels, + groups: context.groups, + cursor: { + timetoken: !!((_a = context === null || context === void 0 ? void 0 : context.cursor) === null || _a === void 0 ? void 0 : _a.timetoken) ? (_b = context === null || context === void 0 ? void 0 : context.cursor) === null || _b === void 0 ? void 0 : _b.timetoken : event.payload.timetoken, + region: event.payload.region, + }, + }, [ + emitStatus({ + category: StatusCategory$1.PNConnectedCategory, + }), + ]); + }); + HandshakingState.on(handshakeFailure.type, (context, event) => { + return HandshakeReconnectingState.with({ + channels: context.channels, + groups: context.groups, + cursor: context.cursor, + attempts: 0, + reason: event.payload, + }); + }); + HandshakingState.on(disconnect.type, (context) => HandshakeStoppedState.with({ + channels: context.channels, + groups: context.groups, + cursor: context.cursor, + })); + HandshakingState.on(restore.type, (context, event) => { + var _a; + return HandshakingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: { + timetoken: event.payload.cursor.timetoken, + region: event.payload.cursor.region || ((_a = context === null || context === void 0 ? void 0 : context.cursor) === null || _a === void 0 ? void 0 : _a.region) || 0, + }, + }); + }); + HandshakingState.on(unsubscribeAll.type, (_) => UnsubscribedState.with()); + + const UnsubscribedState = new State('UNSUBSCRIBED'); + UnsubscribedState.on(subscriptionChange.type, (_, event) => HandshakingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + })); + UnsubscribedState.on(restore.type, (_, event) => { + return HandshakingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: event.payload.cursor, + }); + }); + + class EventEngine { + get _engine() { + return this.engine; + } + constructor(dependencies) { + this.engine = new Engine(); + this.channels = []; + this.groups = []; + this.dependencies = dependencies; + this.dispatcher = new EventEngineDispatcher(this.engine, dependencies); + this._unsubscribeEngine = this.engine.subscribe((change) => { + if (change.type === 'invocationDispatched') { + this.dispatcher.dispatch(change.invocation); + } + }); + this.engine.start(UnsubscribedState, undefined); + } + subscribe({ channels, channelGroups, timetoken, withPresence, }) { + this.channels = [...this.channels, ...(channels !== null && channels !== void 0 ? channels : [])]; + this.groups = [...this.groups, ...(channelGroups !== null && channelGroups !== void 0 ? channelGroups : [])]; + if (withPresence) { + this.channels.map((c) => this.channels.push(`${c}-pnpres`)); + this.groups.map((g) => this.groups.push(`${g}-pnpres`)); + } + if (timetoken) { + this.engine.transition(restore(Array.from(new Set([...this.channels, ...(channels !== null && channels !== void 0 ? channels : [])])), Array.from(new Set([...this.groups, ...(channelGroups !== null && channelGroups !== void 0 ? channelGroups : [])])), timetoken)); + } + else { + this.engine.transition(subscriptionChange(Array.from(new Set([...this.channels, ...(channels !== null && channels !== void 0 ? channels : [])])), Array.from(new Set([...this.groups, ...(channelGroups !== null && channelGroups !== void 0 ? channelGroups : [])])))); + } + if (this.dependencies.join) { + this.dependencies.join({ + channels: Array.from(new Set(this.channels.filter((c) => !c.endsWith('-pnpres')))), + groups: Array.from(new Set(this.groups.filter((g) => !g.endsWith('-pnpres')))), + }); + } + } + unsubscribe({ channels = [], channelGroups = [] }) { + const filteredChannels = removeSingleOccurance(this.channels, [ + ...channels, + ...channels.map((c) => `${c}-pnpres`), + ]); + const filteredGroups = removeSingleOccurance(this.groups, [ + ...channelGroups, + ...channelGroups.map((c) => `${c}-pnpres`), + ]); + if (new Set(this.channels).size !== new Set(filteredChannels).size || + new Set(this.groups).size !== new Set(filteredGroups).size) { + const channelsToLeave = findUniqueCommonElements(this.channels, channels); + const groupstoLeave = findUniqueCommonElements(this.groups, channelGroups); + if (this.dependencies.presenceState) { + channelsToLeave === null || channelsToLeave === void 0 ? void 0 : channelsToLeave.forEach((c) => delete this.dependencies.presenceState[c]); + groupstoLeave === null || groupstoLeave === void 0 ? void 0 : groupstoLeave.forEach((g) => delete this.dependencies.presenceState[g]); + } + this.channels = filteredChannels; + this.groups = filteredGroups; + this.engine.transition(subscriptionChange(Array.from(new Set(this.channels.slice(0))), Array.from(new Set(this.groups.slice(0))))); + if (this.dependencies.leave) { + this.dependencies.leave({ + channels: channelsToLeave.slice(0), + groups: groupstoLeave.slice(0), + }); + } + } + } + unsubscribeAll() { + this.channels = []; + this.groups = []; + if (this.dependencies.presenceState) { + Object.keys(this.dependencies.presenceState).forEach((objectName) => { + delete this.dependencies.presenceState[objectName]; + }); + } + this.engine.transition(subscriptionChange(this.channels.slice(0), this.groups.slice(0))); + if (this.dependencies.leaveAll) { + this.dependencies.leaveAll(); + } + } + reconnect({ timetoken, region }) { + this.engine.transition(reconnect(timetoken, region)); + } + disconnect() { + this.engine.transition(disconnect()); + if (this.dependencies.leaveAll) { + this.dependencies.leaveAll(); + } + } + getSubscribedChannels() { + return Array.from(new Set(this.channels.slice(0))); + } + getSubscribedChannelGroups() { + return Array.from(new Set(this.groups.slice(0))); + } + dispose() { + this.disconnect(); + this._unsubscribeEngine(); + this.dispatcher.dispose(); + } + } + + /** + * Publish REST API module. + */ + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults + /** + * Whether data is published used `POST` body or not. + */ + const SEND_BY_POST = false; + // endregion + /** + * Data publish request. + * + * Request will normalize and encrypt (if required) provided data and push it to the specified + * channel. + */ + class PublishRequest extends AbstractRequest { + /** + * Construct data publish request. + * + * @param parameters - Request configuration. + */ + constructor(parameters) { + var _a; + var _b; + super({ method: parameters.sendByPost ? TransportMethod.POST : TransportMethod.GET }); + this.parameters = parameters; + // Apply default request parameters. + (_a = (_b = this.parameters).sendByPost) !== null && _a !== void 0 ? _a : (_b.sendByPost = SEND_BY_POST); + } + operation() { + return RequestOperation$1.PNPublishOperation; + } + validate() { + const { message, channel, keySet: { publishKey }, } = this.parameters; + if (!channel) + return "Missing 'channel'"; + if (!message) + return "Missing 'message'"; + if (!publishKey) + return "Missing 'publishKey'"; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return { timetoken: serviceResponse[2] }; + }); + } + get path() { + const { message, channel, keySet } = this.parameters; + const stringifiedPayload = this.prepareMessagePayload(message); + return `/publish/${keySet.publishKey}/${keySet.subscribeKey}/0/${encodeString(channel)}/0${!this.parameters.sendByPost ? `/${encodeString(stringifiedPayload)}` : ''}`; + } + get queryParameters() { + const { meta, replicate, storeInHistory, ttl } = this.parameters; + const query = {}; + if (storeInHistory !== undefined) + query.store = storeInHistory ? '1' : '0'; + if (ttl !== undefined) + query.ttl = ttl; + if (replicate !== undefined && !replicate) + query.norep = 'true'; + if (meta && typeof meta === 'object') + query.meta = JSON.stringify(meta); + return query; + } + get headers() { + return { 'Content-Type': 'application/json' }; + } + get body() { + return this.prepareMessagePayload(this.parameters.message); + } + /** + * Pre-process provided data. + * + * Data will be "normalized" and encrypted if `cryptoModule` has been provided. + * + * @param payload - User-provided data which should be pre-processed before use. + * + * @returns Payload which can be used as part of request URL or body. + * + * @throws {Error} in case if provided `payload` or results of `encryption` can't be stringified. + */ + prepareMessagePayload(payload) { + const { crypto } = this.parameters; + if (!crypto) + return JSON.stringify(payload) || ''; + const encrypted = crypto.encrypt(JSON.stringify(payload)); + return JSON.stringify(typeof encrypted === 'string' ? encrypted : encode(encrypted)); + } + } + + /** + * Signal REST API module. + */ + // endregion + class SignalRequest extends AbstractRequest { + constructor(parameters) { + super(); + this.parameters = parameters; + } + operation() { + return RequestOperation$1.PNSignalOperation; + } + validate() { + const { message, channel, keySet: { publishKey }, } = this.parameters; + if (!channel) + return "Missing 'channel'"; + if (!message) + return "Missing 'message'"; + if (!publishKey) + return "Missing 'publishKey'"; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return { timetoken: serviceResponse[2] }; + }); + } + get path() { + const { keySet: { publishKey, subscribeKey }, channel, message, } = this.parameters; + const stringifiedPayload = JSON.stringify(message); + return `/signal/${publishKey}/${subscribeKey}/0/${encodeString(channel)}/0/${encodeString(stringifiedPayload)}`; + } + } + + /** + * Receive messages subscribe REST API module. + */ + /** + * Receive messages subscribe request. + */ + class ReceiveMessagesSubscribeRequest extends BaseSubscribeRequest { + operation() { + return RequestOperation$1.PNReceiveMessagesOperation; + } + validate() { + const validationResult = super.validate(); + if (validationResult) + return validationResult; + if (!this.parameters.timetoken) + return 'timetoken can not be empty'; + if (!this.parameters.region) + return 'region can not be empty'; + } + get path() { + const { keySet: { subscribeKey }, channels = [], } = this.parameters; + return `/v2/subscribe/${subscribeKey}/${encodeNames(channels.sort(), ',')}/0`; + } + get queryParameters() { + const { channelGroups, filterExpression, timetoken, region } = this.parameters; + const query = { ee: '' }; + if (channelGroups && channelGroups.length > 0) + query['channel-group'] = channelGroups.sort().join(','); + if (filterExpression && filterExpression.length > 0) + query['filter-expr'] = filterExpression; + if (typeof timetoken === 'string') { + if (timetoken && timetoken.length > 0) + query['tt'] = timetoken; + } + else if (timetoken && timetoken > 0) + query['tt'] = timetoken; + if (region) + query['tr'] = region; + return query; + } + } + + /** + * Handshake subscribe REST API module. + */ + /** + * Handshake subscribe request. + * + * Separate subscribe request required by Event Engine. + */ + class HandshakeSubscribeRequest extends BaseSubscribeRequest { + operation() { + return RequestOperation$1.PNHandshakeOperation; + } + get path() { + const { keySet: { subscribeKey }, channels = [], } = this.parameters; + return `/v2/subscribe/${subscribeKey}/${encodeNames(channels.sort(), ',')}/0`; + } + get queryParameters() { + const { channelGroups, filterExpression, state } = this.parameters; + const query = { tt: 0, ee: '' }; + if (channelGroups && channelGroups.length > 0) + query['channel-group'] = channelGroups.sort().join(','); + if (filterExpression && filterExpression.length > 0) + query['filter-expr'] = filterExpression; + if (state && Object.keys(state).length > 0) + query['state'] = JSON.stringify(state); + return query; + } + } + + /** + * Get Presence State REST API module. + */ + // endregion + /** + * Get `uuid` presence state request. + */ + class GetPresenceStateRequest extends AbstractRequest { + constructor(parameters) { + var _a, _b; + var _c, _d; + super(); + this.parameters = parameters; + // Apply defaults. + (_a = (_c = this.parameters).channels) !== null && _a !== void 0 ? _a : (_c.channels = []); + (_b = (_d = this.parameters).channelGroups) !== null && _b !== void 0 ? _b : (_d.channelGroups = []); + } + operation() { + return RequestOperation$1.PNGetStateOperation; + } + validate() { + const { keySet: { subscribeKey }, channels, channelGroups, } = this.parameters; + if (!subscribeKey) + return 'Missing Subscribe Key'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + const { channels = [], channelGroups = [] } = this.parameters; + const state = { channels: {} }; + if (channels.length === 1 && channelGroups.length === 0) + state.channels[channels[0]] = serviceResponse.payload; + else + state.channels = serviceResponse.payload; + return state; + }); + } + get path() { + const { keySet: { subscribeKey }, uuid, channels, } = this.parameters; + return `/v2/presence/sub-key/${subscribeKey}/channel/${encodeNames(channels !== null && channels !== void 0 ? channels : [], ',')}/uuid/${uuid}`; + } + get queryParameters() { + const { channelGroups } = this.parameters; + if (!channelGroups || channelGroups.length === 0) + return {}; + return { 'channel-group': channelGroups.join(',') }; + } + } + + /** + * Set Presence State REST API module. + */ + // endregion + /** + * Set `uuid` presence state request. + */ + class SetPresenceStateRequest extends AbstractRequest { + constructor(parameters) { + super(); + this.parameters = parameters; + } + operation() { + return RequestOperation$1.PNSetStateOperation; + } + validate() { + const { keySet: { subscribeKey }, state, channels = [], channelGroups = [], } = this.parameters; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!state) + return 'Missing State'; + if ((channels === null || channels === void 0 ? void 0 : channels.length) === 0 && (channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.length) === 0) + return 'Please provide a list of channels and/or channel-groups'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + return { state: serviceResponse.payload }; + }); + } + get path() { + const { keySet: { subscribeKey }, uuid, channels, } = this.parameters; + return `/v2/presence/sub-key/${subscribeKey}/channel/${encodeNames(channels !== null && channels !== void 0 ? channels : [], ',')}/uuid/${encodeString(uuid)}/data`; + } + get queryParameters() { + const { channelGroups, state } = this.parameters; + const query = { state: JSON.stringify(state) }; + if (channelGroups && channelGroups.length !== 0) + query['channel-group'] = channelGroups.join(','); + return query; + } + } + + /** + * Announce heartbeat REST API module. + */ + // endregion + class HeartbeatRequest extends AbstractRequest { + constructor(parameters) { + super(); + this.parameters = parameters; + } + operation() { + return RequestOperation$1.PNHeartbeatOperation; + } + validate() { + const { keySet: { subscribeKey }, channels = [], channelGroups = [], } = this.parameters; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (channels.length === 0 && channelGroups.length === 0) + return 'Please provide a list of channels and/or channel-groups'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + return {}; + }); + } + get path() { + const { keySet: { subscribeKey }, channels, } = this.parameters; + return `/v2/presence/sub-key/${subscribeKey}/channel/${encodeNames(channels !== null && channels !== void 0 ? channels : [], ',')}/heartbeat`; + } + get queryParameters() { + const { channelGroups, state, heartbeat } = this.parameters; + const query = { heartbeat: `${heartbeat}` }; + if (channelGroups && channelGroups.length !== 0) + query['channel-group'] = channelGroups.join(','); + if (state) + query.state = JSON.stringify(state); + return query; + } + } + + /** + * Announce leave REST API module. + */ + // endregion + class PresenceLeaveRequest extends AbstractRequest { + constructor(parameters) { + super(); + this.parameters = parameters; + if (this.parameters.channelGroups) + this.parameters.channelGroups = Array.from(new Set(this.parameters.channelGroups)); + if (this.parameters.channels) + this.parameters.channels = Array.from(new Set(this.parameters.channels)); + } + operation() { + return RequestOperation$1.PNUnsubscribeOperation; + } + validate() { + const { keySet: { subscribeKey }, channels = [], channelGroups = [], } = this.parameters; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (channels.length === 0 && channelGroups.length === 0) + return 'At least one `channel` or `channel group` should be provided.'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + return {}; + }); + } + get path() { + var _a; + const { keySet: { subscribeKey }, channels, } = this.parameters; + return `/v2/presence/sub-key/${subscribeKey}/channel/${encodeNames((_a = channels === null || channels === void 0 ? void 0 : channels.sort()) !== null && _a !== void 0 ? _a : [], ',')}/leave`; + } + get queryParameters() { + const { channelGroups } = this.parameters; + if (!channelGroups || channelGroups.length === 0) + return {}; + return { 'channel-group': channelGroups.sort().join(',') }; + } + } + + /** + * `uuid` presence REST API module. + */ + // endregion + class WhereNowRequest extends AbstractRequest { + constructor(parameters) { + super(); + this.parameters = parameters; + } + operation() { + return RequestOperation$1.PNWhereNowOperation; + } + validate() { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + if (!serviceResponse.payload) + return { channels: [] }; + return { channels: serviceResponse.payload.channels }; + }); + } + get path() { + const { keySet: { subscribeKey }, uuid, } = this.parameters; + return `/v2/presence/sub-key/${subscribeKey}/uuid/${encodeString(uuid)}`; + } + } + + /** + * Channels / channel groups presence REST API module. + */ + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults + /** + * Whether `uuid` should be included in response or not. + */ + const INCLUDE_UUID$1 = true; + /** + * Whether state associated with `uuid` should be included in response or not. + */ + const INCLUDE_STATE = false; + // endregion + class HereNowRequest extends AbstractRequest { + constructor(parameters) { + var _a, _b, _c; + var _d, _e, _f; + super(); + this.parameters = parameters; + // Apply defaults. + (_a = (_d = this.parameters).queryParameters) !== null && _a !== void 0 ? _a : (_d.queryParameters = {}); + (_b = (_e = this.parameters).includeUUIDs) !== null && _b !== void 0 ? _b : (_e.includeUUIDs = INCLUDE_UUID$1); + (_c = (_f = this.parameters).includeState) !== null && _c !== void 0 ? _c : (_f.includeState = INCLUDE_STATE); + } + operation() { + const { channels = [], channelGroups = [] } = this.parameters; + return channels.length === 0 && channelGroups.length === 0 + ? RequestOperation$1.PNGlobalHereNowOperation + : RequestOperation$1.PNHereNowOperation; + } + validate() { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + var _a, _b; + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + // Extract general presence information. + const totalChannels = 'occupancy' in serviceResponse ? 1 : serviceResponse.payload.total_channels; + const totalOccupancy = 'occupancy' in serviceResponse ? serviceResponse.occupancy : serviceResponse.payload.total_channels; + const channelsPresence = {}; + let channels = {}; + // Remap single channel presence to multiple channels presence response. + if ('occupancy' in serviceResponse) { + const channel = this.parameters.channels[0]; + channels[channel] = { uuids: (_a = serviceResponse.uuids) !== null && _a !== void 0 ? _a : [], occupancy: totalOccupancy }; + } + else + channels = (_b = serviceResponse.payload.channels) !== null && _b !== void 0 ? _b : {}; + Object.keys(channels).forEach((channel) => { + const channelEntry = channels[channel]; + channelsPresence[channel] = { + occupants: this.parameters.includeUUIDs + ? channelEntry.uuids.map((uuid) => { + if (typeof uuid === 'string') + return { uuid, state: null }; + return uuid; + }) + : [], + name: channel, + occupancy: channelEntry.occupancy, + }; + }); + return { + totalChannels, + totalOccupancy, + channels: channelsPresence, + }; + }); + } + get path() { + const { keySet: { subscribeKey }, channels, channelGroups, } = this.parameters; + let path = `/v2/presence/sub-key/${subscribeKey}`; + if ((channels && channels.length > 0) || (channelGroups && channelGroups.length > 0)) + path += `/channel/${encodeNames(channels !== null && channels !== void 0 ? channels : [], ',')}`; + return path; + } + get queryParameters() { + const { channelGroups, includeUUIDs, includeState, queryParameters } = this.parameters; + return Object.assign(Object.assign(Object.assign(Object.assign({}, (!includeUUIDs ? { disable_uuids: '1' } : {})), ((includeState !== null && includeState !== void 0 ? includeState : false) ? { state: '1' } : {})), (channelGroups && channelGroups.length > 0 ? { 'channel-group': channelGroups.join(',') } : {})), queryParameters); + } + } + + /** + * Delete messages REST API module. + */ + // endregion + /** + * Delete messages from channel history. + */ + class DeleteMessageRequest extends AbstractRequest { + constructor(parameters) { + super({ method: TransportMethod.DELETE }); + this.parameters = parameters; + } + operation() { + return RequestOperation$1.PNDeleteMessagesOperation; + } + validate() { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + if (!this.parameters.channel) + return 'Missing channel'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + return {}; + }); + } + get path() { + const { keySet: { subscribeKey }, channel, } = this.parameters; + return `/v3/history/sub-key/${subscribeKey}/channel/${encodeString(channel)}`; + } + get queryParameters() { + const { start, end } = this.parameters; + return Object.assign(Object.assign({}, (start ? { start } : {})), (end ? { end } : {})); + } + } + + /** + * Messages count REST API module. + */ + // endregion + class MessageCountRequest extends AbstractRequest { + constructor(parameters) { + super(); + this.parameters = parameters; + } + operation() { + return RequestOperation$1.PNMessageCounts; + } + validate() { + const { keySet: { subscribeKey }, channels, timetoken, channelTimetokens, } = this.parameters; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!channels) + return 'Missing channels'; + if (timetoken && channelTimetokens) + return '`timetoken` and `channelTimetokens` are incompatible together'; + if (!timetoken && !channelTimetokens) + return '`timetoken` or `channelTimetokens` need to be set'; + if (channelTimetokens && channelTimetokens.length > 1 && channelTimetokens.length !== channels.length) + return 'Length of `channelTimetokens` and `channels` do not match'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + return { channels: serviceResponse.channels }; + }); + } + get path() { + return `/v3/history/sub-key/${this.parameters.keySet.subscribeKey}/message-counts/${encodeNames(this.parameters.channels)}`; + } + get queryParameters() { + let { channelTimetokens } = this.parameters; + if (this.parameters.timetoken) + channelTimetokens = [this.parameters.timetoken]; + return Object.assign(Object.assign({}, (channelTimetokens.length === 1 ? { timetoken: channelTimetokens[0] } : {})), (channelTimetokens.length > 1 ? { channelsTimetoken: channelTimetokens.join(',') } : {})); + } + } + + /** + * Get history REST API module. + */ + // -------------------------------------------------------- + // ---------------------- Defaults ------------------------ + // -------------------------------------------------------- + // region Defaults + /** + * Whether verbose logging enabled or not. + */ + const LOG_VERBOSITY$1 = false; + /** + * Whether associated message metadata should be returned or not. + */ + const INCLUDE_METADATA = false; + /** + * Whether timetokens should be returned as strings by default or not. + */ + const STRINGIFY_TIMETOKENS$1 = false; + /** + * Default and maximum number of messages which should be returned. + */ + const MESSAGES_COUNT = 100; + // endregion + /** + * Get single channel messages request. + */ + class GetHistoryRequest extends AbstractRequest { + constructor(parameters) { + var _a, _b, _c; + super(); + this.parameters = parameters; + // Apply defaults. + if (parameters.count) + parameters.count = Math.min(parameters.count, MESSAGES_COUNT); + else + parameters.count = MESSAGES_COUNT; + (_a = parameters.stringifiedTimeToken) !== null && _a !== void 0 ? _a : (parameters.stringifiedTimeToken = STRINGIFY_TIMETOKENS$1); + (_b = parameters.includeMeta) !== null && _b !== void 0 ? _b : (parameters.includeMeta = INCLUDE_METADATA); + (_c = parameters.logVerbosity) !== null && _c !== void 0 ? _c : (parameters.logVerbosity = LOG_VERBOSITY$1); + } + operation() { + return RequestOperation$1.PNHistoryOperation; + } + validate() { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + if (!this.parameters.channel) + return 'Missing channel'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + const messages = serviceResponse[0]; + const startTimeToken = serviceResponse[1]; + const endTimeToken = serviceResponse[2]; + // Handle malformed get history response. + if (!Array.isArray(messages)) + return { messages: [], startTimeToken, endTimeToken }; + return { + messages: messages.map((payload) => { + const processedPayload = this.processPayload(payload.message); + const item = { + entry: processedPayload.payload, + timetoken: payload.timetoken, + }; + if (processedPayload.error) + item.error = processedPayload.error; + if (payload.meta) + item.meta = payload.meta; + return item; + }), + startTimeToken, + endTimeToken, + }; + }); + } + get path() { + const { keySet: { subscribeKey }, channel, } = this.parameters; + return `/v2/history/sub-key/${subscribeKey}/channel/${encodeString(channel)}`; + } + get queryParameters() { + const { start, end, reverse, count, stringifiedTimeToken, includeMeta } = this.parameters; + return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ count: count, include_token: 'true' }, (start ? { start } : {})), (end ? { end } : {})), (stringifiedTimeToken ? { string_message_token: 'true' } : {})), (reverse !== undefined && reverse !== null ? { reverse: reverse.toString() } : {})), (includeMeta ? { include_meta: 'true' } : {})); + } + processPayload(payload) { + const { crypto, logVerbosity } = this.parameters; + if (!crypto || typeof payload !== 'string') + return { payload }; + let decryptedPayload; + let error; + try { + const decryptedData = crypto.decrypt(payload); + decryptedPayload = + decryptedData instanceof ArrayBuffer + ? JSON.parse(GetHistoryRequest.decoder.decode(decryptedData)) + : decryptedData; + } + catch (err) { + if (logVerbosity) + console.log(`decryption error`, err.message); + decryptedPayload = payload; + error = `Error while decrypting message content: ${err.message}`; + } + return { + payload: decryptedPayload, + error, + }; + } + } + + // endregion + // -------------------------------------------------------- + // -------------------- Fetch Messages -------------------- + // -------------------------------------------------------- + // region Fetch Messages + /** + * PubNub-defined message type. + * + * Types of messages which can be retrieved with fetch messages REST API. + */ + var PubNubMessageType; + (function (PubNubMessageType) { + /** + * Regular message. + */ + PubNubMessageType[PubNubMessageType["Message"] = -1] = "Message"; + /** + * File message. + */ + PubNubMessageType[PubNubMessageType["Files"] = 4] = "Files"; + })(PubNubMessageType || (PubNubMessageType = {})); + // endregion + + /** + * Fetch messages REST API module. + */ + // -------------------------------------------------------- + // ---------------------- Defaults ------------------------ + // -------------------------------------------------------- + // region Defaults + /** + * Whether verbose logging enabled or not. + */ + const LOG_VERBOSITY = false; + /** + * Whether message type should be returned or not. + */ + const INCLUDE_MESSAGE_TYPE = true; + /** + * Whether timetokens should be returned as strings by default or not. + */ + const STRINGIFY_TIMETOKENS = false; + /** + * Whether message publisher `uuid` should be returned or not. + */ + const INCLUDE_UUID = true; + /** + * Default number of messages which can be returned for single channel, and it is maximum as well. + */ + const SINGLE_CHANNEL_MESSAGES_COUNT = 100; + /** + * Default number of messages which can be returned for multiple channels or when fetched + * message actions. + */ + const MULTIPLE_CHANNELS_MESSAGES_COUNT = 25; + // endregion + /** + * Fetch messages from channels request. + */ + class FetchMessagesRequest extends AbstractRequest { + constructor(parameters) { + var _a, _b, _c, _d, _e; + super(); + this.parameters = parameters; + // Apply defaults. + const includeMessageActions = (_a = parameters.includeMessageActions) !== null && _a !== void 0 ? _a : false; + const defaultCount = parameters.channels.length > 1 || includeMessageActions + ? MULTIPLE_CHANNELS_MESSAGES_COUNT + : SINGLE_CHANNEL_MESSAGES_COUNT; + if (!parameters.count) + parameters.count = defaultCount; + else + parameters.count = Math.min(parameters.count, defaultCount); + if (parameters.includeUuid) + parameters.includeUUID = parameters.includeUuid; + else + (_b = parameters.includeUUID) !== null && _b !== void 0 ? _b : (parameters.includeUUID = INCLUDE_UUID); + (_c = parameters.stringifiedTimeToken) !== null && _c !== void 0 ? _c : (parameters.stringifiedTimeToken = STRINGIFY_TIMETOKENS); + (_d = parameters.includeMessageType) !== null && _d !== void 0 ? _d : (parameters.includeMessageType = INCLUDE_MESSAGE_TYPE); + (_e = parameters.logVerbosity) !== null && _e !== void 0 ? _e : (parameters.logVerbosity = LOG_VERBOSITY); + } + operation() { + return RequestOperation$1.PNFetchMessagesOperation; + } + validate() { + const { keySet: { subscribeKey }, channels, includeMessageActions, } = this.parameters; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!channels) + return 'Missing channels'; + if (includeMessageActions !== undefined && includeMessageActions && channels.length > 1) + return ('History can return actions data for a single channel only. Either pass a single channel ' + + 'or disable the includeMessageActions flag.'); + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + var _a; + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + const responseChannels = (_a = serviceResponse.channels) !== null && _a !== void 0 ? _a : {}; + const channels = {}; + Object.keys(responseChannels).forEach((channel) => { + // Map service response to expected data object type structure. + channels[channel] = responseChannels[channel].map((payload) => { + // `null` message type means regular message. + if (payload.message_type === null) + payload.message_type = PubNubMessageType.Message; + const processedPayload = this.processPayload(channel, payload); + const item = { + channel, + timetoken: payload.timetoken, + message: processedPayload.payload, + messageType: payload.message_type, + uuid: payload.uuid, + }; + if (payload.actions) { + const itemWithActions = item; + itemWithActions.actions = payload.actions; + // Backward compatibility for existing users. + // TODO: Remove in next release. + itemWithActions.data = payload.actions; + } + if (payload.meta) + item.meta = payload.meta; + if (processedPayload.error) + item.error = processedPayload.error; + return item; + }); + }); + if (serviceResponse.more) + return { channels, more: serviceResponse.more }; + return { channels }; + }); + } + get path() { + const { keySet: { subscribeKey }, channels, includeMessageActions, } = this.parameters; + const endpoint = !includeMessageActions ? 'history' : 'history-with-actions'; + return `/v3/${endpoint}/sub-key/${subscribeKey}/channel/${encodeNames(channels)}`; + } + get queryParameters() { + const { start, end, count, includeMessageType, includeMeta, includeUUID, stringifiedTimeToken } = this.parameters; + return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ max: count }, (start ? { start } : {})), (end ? { end } : {})), (stringifiedTimeToken ? { string_message_token: 'true' } : {})), (includeMeta !== undefined && includeMeta ? { include_meta: 'true' } : {})), (includeUUID ? { include_uuid: 'true' } : {})), (includeMessageType ? { include_message_type: 'true' } : {})); + } + /** + * Parse single channel data entry. + * + * @param channel - Channel for which {@link payload} should be processed. + * @param payload - Source payload which should be processed and parsed to expected type. + * + * @returns + */ + processPayload(channel, payload) { + const { crypto, logVerbosity } = this.parameters; + if (!crypto || typeof payload.message !== 'string') + return { payload: payload.message }; + let decryptedPayload; + let error; + try { + const decryptedData = crypto.decrypt(payload.message); + decryptedPayload = + decryptedData instanceof ArrayBuffer + ? JSON.parse(FetchMessagesRequest.decoder.decode(decryptedData)) + : decryptedData; + } + catch (err) { + if (logVerbosity) + console.log(`decryption error`, err.message); + decryptedPayload = payload.message; + error = `Error while decrypting message content: ${err.message}`; + } + if (!error && + decryptedPayload && + payload.message_type == PubNubMessageType.Files && + typeof decryptedPayload === 'object' && + this.isFileMessage(decryptedPayload)) { + const fileMessage = decryptedPayload; + return { + payload: { + message: fileMessage.message, + file: Object.assign(Object.assign({}, fileMessage.file), { url: this.parameters.getFileUrl({ channel, id: fileMessage.file.id, name: fileMessage.file.name }) }), + }, + error, + }; + } + return { payload: decryptedPayload, error }; + } + /** + * Check whether `payload` potentially represents file message. + * + * @param payload - Fetched message payload. + * + * @returns `true` if payload can be {@link History#FileMessage|FileMessage}. + */ + isFileMessage(payload) { + return payload.file !== undefined; + } + } + + /** + * Get Message Actions REST API module. + */ + // endregion + /** + * Fetch channel message actions request. + */ + class GetMessageActionsRequest extends AbstractRequest { + constructor(parameters) { + super(); + this.parameters = parameters; + } + operation() { + return RequestOperation$1.PNGetMessageActionsOperation; + } + validate() { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + if (!this.parameters.channel) + return 'Missing message channel'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + let start = null; + let end = null; + if (serviceResponse.data.length > 0) { + start = serviceResponse.data[0].actionTimetoken; + end = serviceResponse.data[serviceResponse.data.length - 1].actionTimetoken; + } + return { + data: serviceResponse.data, + more: serviceResponse.more, + start, + end, + }; + }); + } + get path() { + const { keySet: { subscribeKey }, channel, } = this.parameters; + return `/v1/message-actions/${subscribeKey}/channel/${encodeString(channel)}`; + } + get queryParameters() { + const { limit, start, end } = this.parameters; + return Object.assign(Object.assign(Object.assign({}, (start ? { start } : {})), (end ? { end } : {})), (limit ? { limit } : {})); + } + } + + /** + * Add Message Action REST API module. + */ + // endregion + /** + * Add Message Reaction request. + */ + class AddMessageActionRequest extends AbstractRequest { + constructor(parameters) { + super({ method: TransportMethod.POST }); + this.parameters = parameters; + } + operation() { + return RequestOperation$1.PNAddMessageActionOperation; + } + validate() { + const { keySet: { subscribeKey }, action, channel, messageTimetoken, } = this.parameters; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!channel) + return 'Missing message channel'; + if (!messageTimetoken) + return 'Missing message timetoken'; + if (!action) + return 'Missing Action'; + if (!action.value) + return 'Missing Action.value'; + if (!action.type) + return 'Missing Action.type'; + if (action.type.length > 15) + return 'Action.type value exceed maximum length of 15'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + return { data: serviceResponse.data }; + }); + } + get headers() { + return { 'Content-Type': 'application/json' }; + } + get path() { + const { keySet: { subscribeKey }, channel, messageTimetoken, } = this.parameters; + return `/v1/message-actions/${subscribeKey}/channel/${encodeString(channel)}/message/${messageTimetoken}`; + } + get body() { + return JSON.stringify(this.parameters.action); + } + } + + /** + * Remove Message Action REST API module. + */ + // endregion + /** + * Remove specific message action request. + */ + class RemoveMessageAction extends AbstractRequest { + constructor(parameters) { + super({ method: TransportMethod.DELETE }); + this.parameters = parameters; + } + operation() { + return RequestOperation$1.PNRemoveMessageActionOperation; + } + validate() { + const { keySet: { subscribeKey }, channel, messageTimetoken, actionTimetoken, } = this.parameters; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!channel) + return 'Missing message action channel'; + if (!messageTimetoken) + return 'Missing message timetoken'; + if (!actionTimetoken) + return 'Missing action timetoken'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + return { data: serviceResponse.data }; + }); + } + get path() { + const { keySet: { subscribeKey }, channel, actionTimetoken, messageTimetoken, } = this.parameters; + return `/v1/message-actions/${subscribeKey}/channel/${encodeString(channel)}/message/${messageTimetoken}/action/${actionTimetoken}`; + } + } + + /** + * Publish File Message REST API module. + */ + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults + /** + * Whether published file messages should be stored in the channel's history. + */ + const STORE_IN_HISTORY = true; + // endregion + class PublishFileMessageRequest extends AbstractRequest { + constructor(parameters) { + var _a; + var _b; + super(); + this.parameters = parameters; + // Apply default request parameters. + (_a = (_b = this.parameters).storeInHistory) !== null && _a !== void 0 ? _a : (_b.storeInHistory = STORE_IN_HISTORY); + } + operation() { + return RequestOperation$1.PNPublishFileMessageOperation; + } + validate() { + const { channel, fileId, fileName } = this.parameters; + if (!channel) + return "channel can't be empty"; + if (!fileId) + return "file id can't be empty"; + if (!fileName) + return "file name can't be empty"; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return { timetoken: serviceResponse[2] }; + }); + } + get path() { + const { message, channel, keySet: { publishKey, subscribeKey }, fileId, fileName, } = this.parameters; + const fileMessage = Object.assign({ file: { + name: fileName, + id: fileId, + } }, (message ? { message } : {})); + return `/v1/files/publish-file/${publishKey}/${subscribeKey}/0/${encodeString(channel)}/0/${encodeString(this.prepareMessagePayload(fileMessage))}`; + } + get queryParameters() { + const { storeInHistory, ttl, meta } = this.parameters; + return Object.assign(Object.assign({ store: storeInHistory ? '1' : '0' }, (ttl ? { ttl } : {})), (meta && typeof meta === 'object' ? { meta: JSON.stringify(meta) } : {})); + } + /** + * Pre-process provided data. + * + * Data will be "normalized" and encrypted if `cryptoModule` has been provided. + * + * @param payload - User-provided data which should be pre-processed before use. + * + * @returns Payload which can be used as part of request URL or body. + * + * @throws {Error} in case if provided `payload` or results of `encryption` can't be stringified. + */ + prepareMessagePayload(payload) { + const { crypto } = this.parameters; + if (!crypto) + return JSON.stringify(payload) || ''; + const encrypted = crypto.encrypt(JSON.stringify(payload)); + return JSON.stringify(typeof encrypted === 'string' ? encrypted : encode(encrypted)); + } + } + + /** + * File sharing REST API module. + */ + // endregion + /** + * File download Url generation request. + * + * Local request which generates Url to download shared file from the specific channel. + */ + class GetFileDownloadUrlRequest extends AbstractRequest { + /** + * Construct file download Url generation request. + * + * @param parameters - Request configuration. + */ + constructor(parameters) { + super({ method: TransportMethod.LOCAL }); + this.parameters = parameters; + } + operation() { + return RequestOperation$1.PNGetFileUrlOperation; + } + validate() { + const { channel, id, name } = this.parameters; + if (!channel) + return "channel can't be empty"; + if (!id) + return "file id can't be empty"; + if (!name) + return "file name can't be empty"; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + return response.url; + }); + } + get path() { + const { channel, id, name, keySet: { subscribeKey }, } = this.parameters; + return `/v1/files/${subscribeKey}/channels/${encodeString(channel)}/files/${id}/${name}`; + } + } + + /** + * Delete file REST API module. + */ + // endregion + /** + * Delete File request. + */ + class DeleteFileRequest extends AbstractRequest { + constructor(parameters) { + super({ method: TransportMethod.DELETE }); + this.parameters = parameters; + } + operation() { + return RequestOperation$1.PNDeleteFileOperation; + } + validate() { + const { channel, id, name } = this.parameters; + if (!channel) + return "channel can't be empty"; + if (!id) + return "file id can't be empty"; + if (!name) + return "file name can't be empty"; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + return serviceResponse; + }); + } + get path() { + const { keySet: { subscribeKey }, id, channel, name, } = this.parameters; + return `/v1/files/${subscribeKey}/channels/${encodeString(channel)}/files/${id}/${name}`; + } + } + + /** + * List Files REST API module. + */ + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults + /** + * Number of files to return in response. + */ + const LIMIT$6 = 100; + // endregion + /** + * Files List request. + */ + class FilesListRequest extends AbstractRequest { + constructor(parameters) { + var _a; + var _b; + super(); + this.parameters = parameters; + // Apply default request parameters. + (_a = (_b = this.parameters).limit) !== null && _a !== void 0 ? _a : (_b.limit = LIMIT$6); + } + operation() { + return RequestOperation$1.PNListFilesOperation; + } + validate() { + if (!this.parameters.channel) + return "channel can't be empty"; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + return serviceResponse; + }); + } + get path() { + const { keySet: { subscribeKey }, channel, } = this.parameters; + return `/v1/files/${subscribeKey}/channels/${encodeString(channel)}/files`; + } + get queryParameters() { + const { limit, next } = this.parameters; + return Object.assign({ limit: limit }, (next ? { next } : {})); + } + } + + /** + * Generate file upload URL REST API request. + */ + // endregion + /** + * Generate File Upload Url request. + */ + class GenerateFileUploadUrlRequest extends AbstractRequest { + constructor(parameters) { + super({ method: TransportMethod.POST }); + this.parameters = parameters; + } + operation() { + return RequestOperation$1.PNGenerateUploadUrlOperation; + } + validate() { + if (!this.parameters.channel) + return "channel can't be empty"; + if (!this.parameters.name) + return "'name' can't be empty"; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + return { + id: serviceResponse.data.id, + name: serviceResponse.data.name, + url: serviceResponse.file_upload_request.url, + formFields: serviceResponse.file_upload_request.form_fields, + }; + }); + } + get path() { + const { keySet: { subscribeKey }, channel, } = this.parameters; + return `/v1/files/${subscribeKey}/channels/${encodeString(channel)}/generate-upload-url`; + } + get body() { + return JSON.stringify({ name: this.parameters.name }); + } + } + + /** + * Upload file REST API request. + */ + /** + * File Upload request. + */ + class UploadFileRequest extends AbstractRequest { + constructor(parameters) { + super({ method: TransportMethod.POST }); + this.parameters = parameters; + // Use file's actual mime type if available. + const mimeType = parameters.file.mimeType; + if (mimeType) { + parameters.formFields = parameters.formFields.map((entry) => { + if (entry.name === 'Content-Type') + return { name: entry.name, value: mimeType }; + return entry; + }); + } + } + operation() { + return RequestOperation$1.PNPublishFileOperation; + } + validate() { + const { fileId, fileName, file, uploadUrl } = this.parameters; + if (!fileId) + return "Validation failed: file 'id' can't be empty"; + if (!fileName) + return "Validation failed: file 'name' can't be empty"; + if (!file) + return "Validation failed: 'file' can't be empty"; + if (!uploadUrl) + return "Validation failed: file upload 'url' can't be empty"; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + return { + status: response.status, + message: response.body ? UploadFileRequest.decoder.decode(response.body) : 'OK', + }; + }); + } + request() { + return Object.assign(Object.assign({}, super.request()), { origin: new URL(this.parameters.uploadUrl).origin, timeout: 300 }); + } + get path() { + const { pathname, search } = new URL(this.parameters.uploadUrl); + return `${pathname}${search}`; + } + get body() { + return this.parameters.file; + } + get formData() { + return this.parameters.formFields; + } + } + + // endregion + /** + * Send file composed request. + */ + class SendFileRequest { + constructor(parameters) { + var _a; + this.parameters = parameters; + this.file = (_a = this.parameters.PubNubFile) === null || _a === void 0 ? void 0 : _a.create(parameters.file); + if (!this.file) + throw new Error('File upload error: unable to create File object.'); + } + /** + * Process user-input and upload file. + * + * @returns File upload request response. + */ + process() { + return __awaiter(this, void 0, void 0, function* () { + let fileName; + let fileId; + return this.generateFileUploadUrl() + .then((result) => { + fileName = result.name; + fileId = result.id; + return this.uploadFile(result); + }) + .then((result) => { + if (result.status !== 204) { + throw new PubNubError('Upload to bucket was unsuccessful', { + error: true, + statusCode: result.status, + category: StatusCategory$1.PNUnknownCategory, + operation: RequestOperation$1.PNPublishFileOperation, + errorData: { message: result.message }, + }); + } + }) + .then(() => this.publishFileMessage(fileId, fileName)) + .catch((error) => { + if (error instanceof PubNubError) + throw error; + const apiError = !(error instanceof PubNubAPIError) ? PubNubAPIError.create(error) : error; + throw new PubNubError('File upload error.', apiError.toStatus(RequestOperation$1.PNPublishFileOperation)); + }); + }); + } + /** + * Generate pre-signed file upload Url. + * + * @returns File upload credentials. + */ + generateFileUploadUrl() { + return __awaiter(this, void 0, void 0, function* () { + const request = new GenerateFileUploadUrlRequest(Object.assign(Object.assign({}, this.parameters), { name: this.file.name, keySet: this.parameters.keySet })); + return this.parameters.sendRequest(request); + }); + } + /** + * Prepare and upload {@link PubNub} File object to remote storage. + * + * @param uploadParameters - File upload request parameters. + * + * @returns + */ + uploadFile(uploadParameters) { + return __awaiter(this, void 0, void 0, function* () { + const { cipherKey, PubNubFile, crypto, cryptography } = this.parameters; + const { id, name, url, formFields } = uploadParameters; + // Encrypt file if possible. + if (this.parameters.PubNubFile.supportsEncryptFile) { + if (!cipherKey && crypto) + this.file = (yield crypto.encryptFile(this.file, PubNubFile)); + else if (cipherKey && cryptography) + this.file = (yield cryptography.encryptFile(cipherKey, this.file, PubNubFile)); + } + return this.parameters.sendRequest(new UploadFileRequest({ + fileId: id, + fileName: name, + file: this.file, + uploadUrl: url, + formFields, + })); + }); + } + publishFileMessage(fileId, fileName) { + return __awaiter(this, void 0, void 0, function* () { + var _a, _b, _c, _d; + let result = { timetoken: '0' }; + let retries = this.parameters.fileUploadPublishRetryLimit; + let publishError; + let wasSuccessful = false; + do { + try { + result = yield this.parameters.publishFile(Object.assign(Object.assign({}, this.parameters), { fileId, fileName })); + wasSuccessful = true; + } + catch (error) { + if (error instanceof PubNubError) + publishError = error; + retries -= 1; + } + } while (!wasSuccessful && retries > 0); + if (!wasSuccessful) { + throw new PubNubError('Publish failed. You may want to execute that operation manually using pubnub.publishFile', { + error: true, + category: (_b = (_a = publishError.status) === null || _a === void 0 ? void 0 : _a.category) !== null && _b !== void 0 ? _b : StatusCategory$1.PNUnknownCategory, + statusCode: (_d = (_c = publishError.status) === null || _c === void 0 ? void 0 : _c.statusCode) !== null && _d !== void 0 ? _d : 0, + channel: this.parameters.channel, + id: fileId, + name: fileName, + }); + } + else + return { status: 200, timetoken: result.timetoken, id: fileId, name: fileName }; + }); + } + } + + /** + * PAM Revoke Token REST API module. + */ + // endregion + /** + * Access token revoke request. + * + * Invalidate token and permissions which has been granted for it. + */ + class RevokeTokenRequest extends AbstractRequest { + constructor(parameters) { + super({ method: TransportMethod.DELETE }); + this.parameters = parameters; + } + operation() { + return RequestOperation$1.PNAccessManagerRevokeToken; + } + validate() { + if (!this.parameters.keySet.secretKey) + return 'Missing Secret Key'; + if (!this.parameters.token) + return "token can't be empty"; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + return {}; + }); + } + get path() { + const { keySet: { subscribeKey }, token, } = this.parameters; + return `/v3/pam/${subscribeKey}/grant/${encodeString(token)}`; + } + } + + /** + * PAM Grant Token REST API module. + */ + // endregion + /** + * Grant token permissions request. + */ + class GrantTokenRequest extends AbstractRequest { + constructor(parameters) { + var _a, _b; + var _c, _d; + super({ method: TransportMethod.POST }); + this.parameters = parameters; + // Apply defaults. + (_a = (_c = this.parameters).resources) !== null && _a !== void 0 ? _a : (_c.resources = {}); + (_b = (_d = this.parameters).patterns) !== null && _b !== void 0 ? _b : (_d.patterns = {}); + } + operation() { + return RequestOperation$1.PNAccessManagerGrantToken; + } + validate() { + var _a, _b, _c, _d, _e, _f; + const { keySet: { subscribeKey, publishKey, secretKey }, resources, patterns, } = this.parameters; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!publishKey) + return 'Missing Publish Key'; + if (!secretKey) + return 'Missing Secret Key'; + if (!resources && !patterns) + return 'Missing either Resources or Patterns'; + if (this.isVspPermissions(this.parameters) && + ('channels' in ((_a = this.parameters.resources) !== null && _a !== void 0 ? _a : {}) || + 'uuids' in ((_b = this.parameters.resources) !== null && _b !== void 0 ? _b : {}) || + 'groups' in ((_c = this.parameters.resources) !== null && _c !== void 0 ? _c : {}) || + 'channels' in ((_d = this.parameters.patterns) !== null && _d !== void 0 ? _d : {}) || + 'uuids' in ((_e = this.parameters.patterns) !== null && _e !== void 0 ? _e : {}) || + 'groups' in ((_f = this.parameters.patterns) !== null && _f !== void 0 ? _f : {}))) + return ('Cannot mix `users`, `spaces` and `authorizedUserId` with `uuids`, `channels`,' + + ' `groups` and `authorized_uuid`'); + let permissionsEmpty = true; + [this.parameters.resources, this.parameters.patterns].forEach((refPerm) => { + Object.keys(refPerm !== null && refPerm !== void 0 ? refPerm : {}).forEach((scope) => { + var _a; + // @ts-expect-error Permissions with backward compatibility. + if (refPerm && permissionsEmpty && Object.keys((_a = refPerm[scope]) !== null && _a !== void 0 ? _a : {}).length > 0) { + permissionsEmpty = false; + } + }); + }); + if (permissionsEmpty) + return 'Missing values for either Resources or Patterns'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + return serviceResponse.data.token; + }); + } + get path() { + return `/v3/pam/${this.parameters.keySet.subscribeKey}/grant`; + } + get body() { + const { ttl, meta } = this.parameters; + const body = Object.assign({}, (ttl || ttl === 0 ? { ttl } : {})); + const uuid = this.isVspPermissions(this.parameters) + ? this.parameters.authorizedUserId + : this.parameters.authorized_uuid; + const permissions = {}; + const resourcePermissions = {}; + const patternPermissions = {}; + const mapPermissions = (name, permissionBit, type, permissions) => { + if (!permissions[type]) + permissions[type] = {}; + permissions[type][name] = permissionBit; + }; + const { resources, patterns } = this.parameters; + [resources, patterns].forEach((refPerm, idx) => { + var _a, _b, _c, _d, _e; + const target = idx === 0 ? resourcePermissions : patternPermissions; + let channelsPermissions = {}; + let channelGroupsPermissions = {}; + let uuidsPermissions = {}; + if (!target.channels) + target.channels = {}; + if (!target.groups) + target.groups = {}; + if (!target.uuids) + target.uuids = {}; + // @ts-expect-error Not used, needed for api backward compatibility + if (!target.users) + target.users = {}; + // @ts-expect-error Not used, needed for api backward compatibility + if (!target.spaces) + target.spaces = {}; + if (refPerm) { + // Check whether working with legacy Objects permissions. + if ('spaces' in refPerm || 'users' in refPerm) { + channelsPermissions = (_a = refPerm.spaces) !== null && _a !== void 0 ? _a : {}; + uuidsPermissions = (_b = refPerm.users) !== null && _b !== void 0 ? _b : {}; + } + else if ('channels' in refPerm || 'uuids' in refPerm || 'groups' in refPerm) { + channelsPermissions = (_c = refPerm.channels) !== null && _c !== void 0 ? _c : {}; + channelGroupsPermissions = (_d = refPerm.groups) !== null && _d !== void 0 ? _d : {}; + uuidsPermissions = (_e = refPerm.uuids) !== null && _e !== void 0 ? _e : {}; + } + } + Object.keys(channelsPermissions).forEach((channel) => mapPermissions(channel, this.extractPermissions(channelsPermissions[channel]), 'channels', target)); + Object.keys(channelGroupsPermissions).forEach((groups) => mapPermissions(groups, this.extractPermissions(channelGroupsPermissions[groups]), 'groups', target)); + Object.keys(uuidsPermissions).forEach((uuids) => mapPermissions(uuids, this.extractPermissions(uuidsPermissions[uuids]), 'uuids', target)); + }); + if (uuid) + permissions.uuid = `${uuid}`; + permissions.resources = resourcePermissions; + permissions.patterns = patternPermissions; + permissions.meta = meta !== null && meta !== void 0 ? meta : {}; + body.permissions = permissions; + return JSON.stringify(body); + } + /** + * Extract permissions bit from permission configuration object. + * + * @param permissions - User provided scope-based permissions. + * + * @returns Permissions bit. + */ + extractPermissions(permissions) { + let permissionsResult = 0; + if ('join' in permissions && permissions.join) + permissionsResult |= 128; + if ('update' in permissions && permissions.update) + permissionsResult |= 64; + if ('get' in permissions && permissions.get) + permissionsResult |= 32; + if ('delete' in permissions && permissions.delete) + permissionsResult |= 8; + if ('manage' in permissions && permissions.manage) + permissionsResult |= 4; + if ('write' in permissions && permissions.write) + permissionsResult |= 2; + if ('read' in permissions && permissions.read) + permissionsResult |= 1; + return permissionsResult; + } + /** + * Check whether provided parameters is part of legacy VSP access token configuration. + * + * @param parameters - Parameters which should be checked. + * + * @returns VSP request parameters if it is legacy configuration. + */ + isVspPermissions(parameters) { + var _a, _b, _c, _d; + return ('authorizedUserId' in parameters || + 'spaces' in ((_a = parameters.resources) !== null && _a !== void 0 ? _a : {}) || + 'users' in ((_b = parameters.resources) !== null && _b !== void 0 ? _b : {}) || + 'spaces' in ((_c = parameters.patterns) !== null && _c !== void 0 ? _c : {}) || + 'users' in ((_d = parameters.patterns) !== null && _d !== void 0 ? _d : {})); + } + } + + /** + * PAM Grant REST API module. + */ + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults + /** + * Resources `read` permission. + */ + const READ_PERMISSION = false; + /** + * Resources `write` permission. + */ + const WRITE_PERMISSION = false; + /** + * Resources `delete` permission. + */ + const DELETE_PERMISSION = false; + /** + * Resources `get` permission. + */ + const GET_PERMISSION = false; + /** + * Resources `update` permission. + */ + const UPDATE_PERMISSION = false; + /** + * Resources `manage` permission. + */ + const MANAGE_PERMISSION = false; + /** + * Resources `join` permission. + */ + const JOIN_PERMISSION = false; + // endregion + /** + * Grant permissions request. + */ + class GrantRequest extends AbstractRequest { + constructor(parameters) { + var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k; + var _l, _m, _o, _p, _q, _r, _s, _t, _u, _v; + super(); + this.parameters = parameters; + // Apply defaults. + (_a = (_l = this.parameters).channels) !== null && _a !== void 0 ? _a : (_l.channels = []); + (_b = (_m = this.parameters).channelGroups) !== null && _b !== void 0 ? _b : (_m.channelGroups = []); + (_c = (_o = this.parameters).uuids) !== null && _c !== void 0 ? _c : (_o.uuids = []); + (_d = (_p = this.parameters).read) !== null && _d !== void 0 ? _d : (_p.read = READ_PERMISSION); + (_e = (_q = this.parameters).write) !== null && _e !== void 0 ? _e : (_q.write = WRITE_PERMISSION); + (_f = (_r = this.parameters).delete) !== null && _f !== void 0 ? _f : (_r.delete = DELETE_PERMISSION); + (_g = (_s = this.parameters).get) !== null && _g !== void 0 ? _g : (_s.get = GET_PERMISSION); + (_h = (_t = this.parameters).update) !== null && _h !== void 0 ? _h : (_t.update = UPDATE_PERMISSION); + (_j = (_u = this.parameters).manage) !== null && _j !== void 0 ? _j : (_u.manage = MANAGE_PERMISSION); + (_k = (_v = this.parameters).join) !== null && _k !== void 0 ? _k : (_v.join = JOIN_PERMISSION); + } + operation() { + return RequestOperation$1.PNAccessManagerGrant; + } + validate() { + const { keySet: { subscribeKey, publishKey, secretKey }, uuids = [], channels = [], channelGroups = [], authKeys = [], } = this.parameters; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!publishKey) + return 'Missing Publish Key'; + if (!secretKey) + return 'Missing Secret Key'; + if (uuids.length !== 0 && authKeys.length === 0) + return 'authKeys are required for grant request on uuids'; + if (uuids.length && (channels.length !== 0 || channelGroups.length !== 0)) + return 'Both channel/channel group and uuid cannot be used in the same request'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + return serviceResponse.payload; + }); + } + get path() { + return `/v2/auth/grant/sub-key/${this.parameters.keySet.subscribeKey}`; + } + get queryParameters() { + const { channels, channelGroups, authKeys, uuids, read, write, manage, delete: del, get, join, update, ttl, } = this.parameters; + return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (channels && (channels === null || channels === void 0 ? void 0 : channels.length) > 0 ? { channel: channels.join(',') } : {})), (channelGroups && (channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.length) > 0 ? { 'channel-group': channelGroups.join(',') } : {})), (authKeys && (authKeys === null || authKeys === void 0 ? void 0 : authKeys.length) > 0 ? { auth: authKeys.join(',') } : {})), (uuids && (uuids === null || uuids === void 0 ? void 0 : uuids.length) > 0 ? { 'target-uuid': uuids.join(',') } : {})), { r: read ? '1' : '0', w: write ? '1' : '0', m: manage ? '1' : '0', d: del ? '1' : '0', g: get ? '1' : '0', j: join ? '1' : '0', u: update ? '1' : '0' }), (ttl || ttl === 0 ? { ttl } : {})); + } + } + + /** + * PAM Audit REST API module. + */ + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults + /** + * Auth keys for which permissions should be audited. + */ + const AUTH_KEYS = []; + // endregion + /** + * Permissions audit request. + */ + class AuditRequest extends AbstractRequest { + constructor(parameters) { + var _a; + var _b; + super(); + this.parameters = parameters; + // Apply default request parameters. + (_a = (_b = this.parameters).authKeys) !== null && _a !== void 0 ? _a : (_b.authKeys = AUTH_KEYS); + } + operation() { + return RequestOperation$1.PNAccessManagerAudit; + } + validate() { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + return serviceResponse.payload; + }); + } + get path() { + return `/v2/auth/audit/sub-key/${this.parameters.keySet.subscribeKey}`; + } + get queryParameters() { + const { channel, channelGroup, authKeys } = this.parameters; + return Object.assign(Object.assign(Object.assign({}, (channel ? { channel } : {})), (channelGroup ? { 'channel-group': channelGroup } : {})), (authKeys && authKeys.length ? { auth: authKeys.join(',') } : {})); + } + } + + class SubscribeCapable { + subscribe() { + var _a, _b; + this.pubnub.subscribe(Object.assign({ channels: this.channelNames, channelGroups: this.groupNames }, (((_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.cursor) === null || _b === void 0 ? void 0 : _b.timetoken) && { timetoken: this.options.cursor.timetoken }))); + } + unsubscribe() { + this.pubnub.unsubscribe({ + channels: this.channelNames.filter((c) => !c.endsWith('-pnpres')), + channelGroups: this.groupNames.filter((cg) => !cg.endsWith('-pnpres')), + }); + } + set onMessage(onMessageListener) { + this.listener.message = onMessageListener; + } + set onPresence(onPresenceListener) { + this.listener.presence = onPresenceListener; + } + set onSignal(onSignalListener) { + this.listener.signal = onSignalListener; + } + set onObjects(onObjectsListener) { + this.listener.objects = onObjectsListener; + } + set onMessageAction(messageActionEventListener) { + this.listener.messageAction = messageActionEventListener; + } + set onFile(fileEventListener) { + this.listener.file = fileEventListener; + } + addListener(listener) { + this.eventEmitter.addListener(listener, this.channelNames.filter((c) => !c.endsWith('-pnpres')), this.groupNames.filter((cg) => !cg.endsWith('-pnpres'))); + } + removeListener(listener) { + this.eventEmitter.removeListener(listener, this.channelNames, this.groupNames); + } + get channels() { + return this.channelNames.slice(0); + } + get channelGroups() { + return this.groupNames.slice(0); + } + } + + class SubscriptionSet extends SubscribeCapable { + constructor({ channels = [], channelGroups = [], subscriptionOptions, eventEmitter, pubnub, }) { + super(); + this.channelNames = []; + this.groupNames = []; + this.subscriptionList = []; + this.options = subscriptionOptions; + this.eventEmitter = eventEmitter; + this.pubnub = pubnub; + channels + .filter((c) => !c.endsWith('-pnpres')) + .forEach((c) => { + const subscription = this.pubnub.channel(c).subscription(this.options); + this.channelNames = [...this.channelNames, ...subscription.channels]; + this.subscriptionList.push(subscription); + }); + channelGroups + .filter((cg) => !cg.endsWith('-pnpres')) + .forEach((cg) => { + const subscription = this.pubnub.channelGroup(cg).subscription(this.options); + this.groupNames = [...this.groupNames, ...subscription.channelGroups]; + this.subscriptionList.push(subscription); + }); + this.listener = {}; + eventEmitter.addListener(this.listener, this.channelNames.filter((c) => !c.endsWith('-pnpres')), this.groupNames.filter((cg) => !cg.endsWith('-pnpres'))); + } + addSubscription(subscription) { + this.subscriptionList.push(subscription); + this.channelNames = [...this.channelNames, ...subscription.channels]; + this.groupNames = [...this.groupNames, ...subscription.channelGroups]; + this.eventEmitter.addListener(this.listener, subscription.channels, subscription.channelGroups); + } + removeSubscription(subscription) { + const channelsToRemove = subscription.channels; + const groupsToRemove = subscription.channelGroups; + this.channelNames = this.channelNames.filter((c) => !channelsToRemove.includes(c)); + this.groupNames = this.groupNames.filter((cg) => !groupsToRemove.includes(cg)); + this.subscriptionList = this.subscriptionList.filter((s) => s !== subscription); + this.eventEmitter.removeListener(this.listener, channelsToRemove, groupsToRemove); + } + addSubscriptionSet(subscriptionSet) { + this.subscriptionList = [...this.subscriptionList, ...subscriptionSet.subscriptions]; + this.channelNames = [...this.channelNames, ...subscriptionSet.channels]; + this.groupNames = [...this.groupNames, ...subscriptionSet.channelGroups]; + this.eventEmitter.addListener(this.listener, subscriptionSet.channels, subscriptionSet.channelGroups); + } + removeSubscriptionSet(subscriptionSet) { + const channelsToRemove = subscriptionSet.channels; + const groupsToRemove = subscriptionSet.channelGroups; + this.channelNames = this.channelNames.filter((c) => !channelsToRemove.includes(c)); + this.groupNames = this.groupNames.filter((cg) => !groupsToRemove.includes(cg)); + this.subscriptionList = this.subscriptionList.filter((s) => !subscriptionSet.subscriptions.includes(s)); + this.eventEmitter.removeListener(this.listener, channelsToRemove, groupsToRemove); + } + get subscriptions() { + return this.subscriptionList.slice(0); + } + } + + class Subscription extends SubscribeCapable { + constructor({ channels, channelGroups, subscriptionOptions, eventEmitter, pubnub, }) { + super(); + this.channelNames = []; + this.groupNames = []; + this.channelNames = channels; + this.groupNames = channelGroups; + this.options = subscriptionOptions; + this.pubnub = pubnub; + this.eventEmitter = eventEmitter; + this.listener = {}; + eventEmitter.addListener(this.listener, this.channelNames.filter((c) => !c.endsWith('-pnpres')), this.groupNames.filter((cg) => !cg.endsWith('-pnpres'))); + } + addSubscription(subscription) { + return new SubscriptionSet({ + channels: [...this.channelNames, ...subscription.channels], + channelGroups: [...this.groupNames, ...subscription.channelGroups], + subscriptionOptions: Object.assign(Object.assign({}, this.options), subscription === null || subscription === void 0 ? void 0 : subscription.options), + eventEmitter: this.eventEmitter, + pubnub: this.pubnub, + }); + } + } + + class ChannelMetadata { + constructor(id, eventEmitter, pubnub) { + this.id = id; + this.eventEmitter = eventEmitter; + this.pubnub = pubnub; + } + subscription(subscriptionOptions) { + return new Subscription({ + channels: [this.id], + channelGroups: [], + subscriptionOptions: subscriptionOptions, + eventEmitter: this.eventEmitter, + pubnub: this.pubnub, + }); + } + } + + class ChannelGroup { + constructor(channelGroup, eventEmitter, pubnub) { + this.eventEmitter = eventEmitter; + this.pubnub = pubnub; + this.name = channelGroup; + } + subscription(subscriptionOptions) { + return new Subscription({ + channels: [], + channelGroups: (subscriptionOptions === null || subscriptionOptions === void 0 ? void 0 : subscriptionOptions.receivePresenceEvents) ? [this.name, `${this.name}-pnpres`] : [this.name], + subscriptionOptions: subscriptionOptions, + eventEmitter: this.eventEmitter, + pubnub: this.pubnub, + }); + } + } + + class UserMetadata { + constructor(id, eventEmitter, pubnub) { + this.id = id; + this.eventEmitter = eventEmitter; + this.pubnub = pubnub; + } + subscription(subscriptionOptions) { + return new Subscription({ + channels: [this.id], + channelGroups: [], + subscriptionOptions: subscriptionOptions, + eventEmitter: this.eventEmitter, + pubnub: this.pubnub, + }); + } + } + + class Channel { + constructor(channelName, eventEmitter, pubnub) { + this.eventEmitter = eventEmitter; + this.pubnub = pubnub; + this.name = channelName; + } + subscription(subscriptionOptions) { + return new Subscription({ + channels: (subscriptionOptions === null || subscriptionOptions === void 0 ? void 0 : subscriptionOptions.receivePresenceEvents) ? [this.name, `${this.name}-pnpres`] : [this.name], + channelGroups: [], + subscriptionOptions: subscriptionOptions, + eventEmitter: this.eventEmitter, + pubnub: this.pubnub, + }); + } + } + + /** + * Remove channel group channels REST API module. + */ + // endregion + /** + * Remove channel group channels request. + */ + // prettier-ignore + class RemoveChannelGroupChannelsRequest extends AbstractRequest { + constructor(parameters) { + super(); + this.parameters = parameters; + } + operation() { + return RequestOperation$1.PNRemoveChannelsFromGroupOperation; + } + validate() { + const { keySet: { subscribeKey }, channels, channelGroup, } = this.parameters; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!channelGroup) + return 'Missing Channel Group'; + if (!channels) + return 'Missing channels'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + return {}; + }); + } + get path() { + const { keySet: { subscribeKey }, channelGroup, } = this.parameters; + return `/v1/channel-registration/sub-key/${subscribeKey}/channel-group/${encodeString(channelGroup)}`; + } + get queryParameters() { + return { remove: this.parameters.channels.join(',') }; + } + } + + /** + * Add channel group channels REST API module. + */ + // endregion + /** + * Add channel group channels request. + */ + class AddChannelGroupChannelsRequest extends AbstractRequest { + constructor(parameters) { + super(); + this.parameters = parameters; + } + operation() { + return RequestOperation$1.PNAddChannelsToGroupOperation; + } + validate() { + const { keySet: { subscribeKey }, channels, channelGroup, } = this.parameters; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!channelGroup) + return 'Missing Channel Group'; + if (!channels) + return 'Missing channels'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + return {}; + }); + } + get path() { + const { keySet: { subscribeKey }, channelGroup, } = this.parameters; + return `/v1/channel-registration/sub-key/${subscribeKey}/channel-group/${encodeString(channelGroup)}`; + } + get queryParameters() { + return { add: this.parameters.channels.join(',') }; + } + } + + /** + * List channel group channels REST API module. + */ + // endregion + /** + * List Channel Group Channels request. + */ + class ListChannelGroupChannels extends AbstractRequest { + constructor(parameters) { + super(); + this.parameters = parameters; + } + operation() { + return RequestOperation$1.PNChannelsForGroupOperation; + } + validate() { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + if (!this.parameters.channelGroup) + return 'Missing Channel Group'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + return { channels: serviceResponse.payload.channels }; + }); + } + get path() { + const { keySet: { subscribeKey }, channelGroup, } = this.parameters; + return `/v1/channel-registration/sub-key/${subscribeKey}/channel-group/${encodeString(channelGroup)}`; + } + } + + /** + * Delete channel group REST API module. + */ + // endregion + /** + * Channel group delete request. + */ + class DeleteChannelGroupRequest extends AbstractRequest { + constructor(parameters) { + super(); + this.parameters = parameters; + } + operation() { + return RequestOperation$1.PNRemoveGroupOperation; + } + validate() { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + if (!this.parameters.channelGroup) + return 'Missing Channel Group'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + return {}; + }); + } + get path() { + const { keySet: { subscribeKey }, channelGroup, } = this.parameters; + return `/v1/channel-registration/sub-key/${subscribeKey}/channel-group/${encodeString(channelGroup)}/remove`; + } + } + + /** + * List All Channel Groups REST API module. + */ + // endregion + /** + * List all channel groups request. + */ + class ListChannelGroupsRequest extends AbstractRequest { + constructor(parameters) { + super(); + this.parameters = parameters; + } + operation() { + return RequestOperation$1.PNChannelGroupsOperation; + } + validate() { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + return { groups: serviceResponse.payload.groups }; + }); + } + get path() { + return `/v1/channel-registration/sub-key/${this.parameters.keySet.subscribeKey}/channel-group`; + } + } + + /** + * PubNub Channel Groups API module. + */ + class PubnubChannelGroups { + constructor(keySet, + /* eslint-disable @typescript-eslint/no-explicit-any */ + sendRequest) { + this.keySet = keySet; + this.sendRequest = sendRequest; + } + /** + * Fetch channel group channels. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get channel group channels response or `void` in case if `callback` + * provided. + */ + listChannels(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new ListChannelGroupChannels(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * Fetch all channel groups. + * + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all channel groups response or `void` in case if `callback` provided. + * + * @deprecated + */ + listGroups(callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new ListChannelGroupsRequest({ keySet: this.keySet }); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * Add channels to the channel group. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous add channels to the channel group response or `void` in case if + * `callback` provided. + */ + addChannels(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new AddChannelGroupChannelsRequest(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * Remove channels from the channel group. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous remove channels from the channel group response or `void` in + * case if `callback` provided. + */ + removeChannels(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new RemoveChannelGroupChannelsRequest(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * Remove channel group. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous remove channel group response or `void` in case if `callback` provided. + */ + deleteGroup(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new DeleteChannelGroupRequest(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + } + + /** + * Manage channels enabled for device push REST API module. + */ + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults + /** + * Environment for which APNS2 notifications + */ + const ENVIRONMENT = 'development'; + /** + * Maximum number of channels in `list` response. + */ + const MAX_COUNT = 1000; + // endregion + /** + * Base push notification request. + */ + class BasePushNotificationChannelsRequest extends AbstractRequest { + constructor(parameters) { + var _a; + var _b; + super(); + this.parameters = parameters; + // Apply request defaults + if (this.parameters.pushGateway === 'apns2') + (_a = (_b = this.parameters).environment) !== null && _a !== void 0 ? _a : (_b.environment = ENVIRONMENT); + if (this.parameters.count && this.parameters.count > MAX_COUNT) + this.parameters.count = MAX_COUNT; + } + operation() { + throw Error('Should be implemented in subclass.'); + } + validate() { + const { keySet: { subscribeKey }, action, device, pushGateway, } = this.parameters; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!device) + return 'Missing Device ID (device)'; + if ((action === 'add' || action === 'remove') && + (!('channels' in this.parameters) || this.parameters.channels.length === 0)) + return 'Missing Channels'; + if (!pushGateway) + return 'Missing GW Type (pushGateway: gcm or apns2)'; + if (this.parameters.pushGateway === 'apns2' && !this.parameters.topic) + return 'Missing APNS2 topic'; + } + parse(_response) { + return __awaiter(this, void 0, void 0, function* () { + throw Error('Should be implemented in subclass.'); + }); + } + get path() { + const { keySet: { subscribeKey }, action, device, pushGateway, } = this.parameters; + let path = pushGateway === 'apns2' + ? `/v2/push/sub-key/${subscribeKey}/devices-apns2/${device}` + : `/v1/push/sub-key/${subscribeKey}/devices/${device}`; + if (action === 'remove-device') + path = `${path}/remove`; + return path; + } + get queryParameters() { + const { start, count } = this.parameters; + let query = Object.assign(Object.assign({ type: this.parameters.pushGateway }, (start ? { start } : {})), (count && count > 0 ? { count } : {})); + if ('channels' in this.parameters) + query[this.parameters.action] = this.parameters.channels.join(','); + if (this.parameters.pushGateway === 'apns2') { + const { environment, topic } = this.parameters; + query = Object.assign(Object.assign({}, query), { environment: environment, topic }); + } + return query; + } + } + + /** + * Unregister Channels from Device push REST API module. + */ + // endregion + /** + * Unregister channels from device push request. + */ + // prettier-ignore + class RemoveDevicePushNotificationChannelsRequest extends BasePushNotificationChannelsRequest { + constructor(parameters) { + super(Object.assign(Object.assign({}, parameters), { action: 'remove' })); + } + operation() { + return RequestOperation$1.PNRemovePushNotificationEnabledChannelsOperation; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return {}; + }); + } + } + + /** + * List Device push enabled channels REST API module. + */ + // endregion + /** + * List device push enabled channels request. + */ + // prettier-ignore + class ListDevicePushNotificationChannelsRequest extends BasePushNotificationChannelsRequest { + constructor(parameters) { + super(Object.assign(Object.assign({}, parameters), { action: 'list' })); + } + operation() { + return RequestOperation$1.PNPushNotificationEnabledChannelsOperation; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return { channels: serviceResponse }; + }); + } + } + + /** + * Register Channels with Device push REST API module. + */ + // endregion + /** + * Register channels with device push request. + */ + // prettier-ignore + class AddDevicePushNotificationChannelsRequest extends BasePushNotificationChannelsRequest { + constructor(parameters) { + super(Object.assign(Object.assign({}, parameters), { action: 'add' })); + } + operation() { + return RequestOperation$1.PNAddPushNotificationEnabledChannelsOperation; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return {}; + }); + } + } + + /** + * Unregister Device push REST API module. + */ + // endregion + /** + * Unregister device push notifications request. + */ + // prettier-ignore + class RemoveDevicePushNotificationRequest extends BasePushNotificationChannelsRequest { + constructor(parameters) { + super(Object.assign(Object.assign({}, parameters), { action: 'remove-device' })); + } + operation() { + return RequestOperation$1.PNRemoveAllPushNotificationsOperation; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return {}; + }); + } + } + + /** + * PubNub Push Notifications API module. + */ + class PubNubPushNotifications { + constructor(keySet, + /* eslint-disable @typescript-eslint/no-explicit-any */ + sendRequest) { + this.keySet = keySet; + this.sendRequest = sendRequest; + } + /** + * Fetch device's push notification enabled channels. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get device channels response or `void` in case if `callback` provided. + */ + listChannels(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new ListDevicePushNotificationChannelsRequest(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * Enable push notifications on channels for device. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + */ + addChannels(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new AddDevicePushNotificationChannelsRequest(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * Disable push notifications on channels for device. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + */ + removeChannels(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new RemoveDevicePushNotificationChannelsRequest(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * Disable push notifications for device. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + */ + deleteDevice(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new RemoveDevicePushNotificationRequest(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + } + + /** + * Get All Channel Metadata REST API module. + */ + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults + /** + * Whether `Channel` custom fields should be included in response or not. + */ + const INCLUDE_CUSTOM_FIELDS$9 = false; + /** + * Whether total number of channels should be included in response or not. + */ + const INCLUDE_TOTAL_COUNT$4 = false; + /** + * Number of objects to return in response. + */ + const LIMIT$5 = 100; + // endregion + /** + * Get All Channels Metadata request. + */ + class GetAllChannelsMetadataRequest extends AbstractRequest { + constructor(parameters) { + var _a, _b, _c, _d; + var _e, _f; + super(); + this.parameters = parameters; + // Apply default request parameters. + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_e = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_e.customFields = INCLUDE_CUSTOM_FIELDS$9); + (_c = (_f = parameters.include).totalCount) !== null && _c !== void 0 ? _c : (_f.totalCount = INCLUDE_TOTAL_COUNT$4); + (_d = parameters.limit) !== null && _d !== void 0 ? _d : (parameters.limit = LIMIT$5); + } + operation() { + return RequestOperation$1.PNGetAllChannelMetadataOperation; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + return serviceResponse; + }); + } + get path() { + return `/v2/objects/${this.parameters.keySet.subscribeKey}/channels`; + } + get queryParameters() { + const { include, page, filter, sort, limit } = this.parameters; + const sorting = Object.entries(sort !== null && sort !== void 0 ? sort : {}).map(([option, order]) => order !== null ? `${option}:${order}` : option); + return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ include: ['status', 'type', ...(include.customFields ? ['custom'] : [])].join(','), count: `${include.totalCount}` }, (filter ? { filter } : {})), ((page === null || page === void 0 ? void 0 : page.next) ? { start: page.next } : {})), ((page === null || page === void 0 ? void 0 : page.prev) ? { end: page.prev } : {})), (limit ? { limit } : {})), (sorting.length ? { sort: sorting } : {})); + } + } + + /** + * Remove Channel Metadata REST API module. + */ + // endregion + /** + * Remove Channel Metadata request. + */ + class RemoveChannelMetadataRequest extends AbstractRequest { + constructor(parameters) { + super({ method: TransportMethod.DELETE }); + this.parameters = parameters; + } + operation() { + return RequestOperation$1.PNRemoveChannelMetadataOperation; + } + validate() { + if (!this.parameters.channel) + return 'Channel cannot be empty'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + return serviceResponse; + }); + } + get path() { + const { keySet: { subscribeKey }, channel, } = this.parameters; + return `/v2/objects/${subscribeKey}/channels/${encodeString(channel)}`; + } + } + + /** + * Get UUID Memberships REST API module. + */ + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults + /** + * Whether `Membership` custom field should be included in response or not. + */ + const INCLUDE_CUSTOM_FIELDS$8 = false; + /** + * Whether membership's status field should be included in response or not. + */ + const INCLUDE_STATUS$1 = false; + /** + * Whether total number of memberships should be included in response or not. + */ + const INCLUDE_TOTAL_COUNT$3 = false; + /** + * Whether `Channel` fields should be included in response or not. + */ + const INCLUDE_CHANNEL_FIELDS$1 = false; + /** + * Whether `Channel` status field should be included in response or not. + */ + const INCLUDE_CHANNEL_STATUS_FIELD = false; + /** + * Whether `Channel` type field should be included in response or not. + */ + const INCLUDE_CHANNEL_TYPE_FIELD = false; + /** + * Whether `Channel` custom field should be included in response or not. + */ + const INCLUDE_CHANNEL_CUSTOM_FIELDS$1 = false; + /** + * Number of objects to return in response. + */ + const LIMIT$4 = 100; + // endregion + /** + * Get UUID Memberships request. + */ + class GetUUIDMembershipsRequest extends AbstractRequest { + constructor(parameters) { + var _a, _b, _c, _d, _e, _f, _g, _h, _j; + var _k, _l, _m, _o, _p, _q, _r; + super(); + this.parameters = parameters; + // Apply default request parameters. + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_k = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_k.customFields = INCLUDE_CUSTOM_FIELDS$8); + (_c = (_l = parameters.include).totalCount) !== null && _c !== void 0 ? _c : (_l.totalCount = INCLUDE_TOTAL_COUNT$3); + (_d = (_m = parameters.include).statusField) !== null && _d !== void 0 ? _d : (_m.statusField = INCLUDE_STATUS$1); + (_e = (_o = parameters.include).channelFields) !== null && _e !== void 0 ? _e : (_o.channelFields = INCLUDE_CHANNEL_FIELDS$1); + (_f = (_p = parameters.include).customChannelFields) !== null && _f !== void 0 ? _f : (_p.customChannelFields = INCLUDE_CHANNEL_CUSTOM_FIELDS$1); + (_g = (_q = parameters.include).channelStatusField) !== null && _g !== void 0 ? _g : (_q.channelStatusField = INCLUDE_CHANNEL_STATUS_FIELD); + (_h = (_r = parameters.include).channelTypeField) !== null && _h !== void 0 ? _h : (_r.channelTypeField = INCLUDE_CHANNEL_TYPE_FIELD); + (_j = parameters.limit) !== null && _j !== void 0 ? _j : (parameters.limit = LIMIT$4); + // Remap for backward compatibility. + if (this.parameters.userId) + this.parameters.uuid = this.parameters.userId; + } + operation() { + return RequestOperation$1.PNGetMembershipsOperation; + } + validate() { + if (!this.parameters.uuid) + return "'uuid' cannot be empty"; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + return serviceResponse; + }); + } + get path() { + const { keySet: { subscribeKey }, uuid, } = this.parameters; + return `/v2/objects/${subscribeKey}/uuids/${encodeString(uuid)}/channels`; + } + get queryParameters() { + const { include, page, filter, sort, limit } = this.parameters; + const sorting = Object.entries(sort !== null && sort !== void 0 ? sort : {}).map(([option, order]) => order !== null ? `${option}:${order}` : option); + const includeFlags = []; + if (include.statusField) + includeFlags.push('status'); + if (include.customFields) + includeFlags.push('custom'); + if (include.channelFields) + includeFlags.push('channel'); + if (include.channelStatusField) + includeFlags.push('channel.status'); + if (include.channelTypeField) + includeFlags.push('channel.type'); + if (include.customChannelFields) + includeFlags.push('channel.custom'); + return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ count: `${include.totalCount}` }, (includeFlags.length > 0 ? { include: includeFlags.join(',') } : {})), (filter ? { filter } : {})), ((page === null || page === void 0 ? void 0 : page.next) ? { start: page.next } : {})), ((page === null || page === void 0 ? void 0 : page.prev) ? { end: page.prev } : {})), (limit ? { limit } : {})), (sorting.length ? { sort: sorting } : {})); + } + } + + /** + * Set UUID Memberships REST API module. + */ + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults + /** + * Whether `Membership` custom field should be included in response or not. + */ + const INCLUDE_CUSTOM_FIELDS$7 = false; + /** + * Whether total number of memberships should be included in response or not. + */ + const INCLUDE_TOTAL_COUNT$2 = false; + /** + * Whether `Channel` fields should be included in response or not. + */ + const INCLUDE_CHANNEL_FIELDS = false; + /** + * Whether `Channel` custom field should be included in response or not. + */ + const INCLUDE_CHANNEL_CUSTOM_FIELDS = false; + /** + * Number of objects to return in response. + */ + const LIMIT$3 = 100; + // endregion + /** + * Set UUID Memberships request. + */ + class SetUUIDMembershipsRequest extends AbstractRequest { + constructor(parameters) { + var _a, _b, _c, _d, _e, _f; + var _g, _h, _j, _k; + super({ method: TransportMethod.PATCH }); + this.parameters = parameters; + // Apply default request parameters. + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_g = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_g.customFields = INCLUDE_CUSTOM_FIELDS$7); + (_c = (_h = parameters.include).totalCount) !== null && _c !== void 0 ? _c : (_h.totalCount = INCLUDE_TOTAL_COUNT$2); + (_d = (_j = parameters.include).channelFields) !== null && _d !== void 0 ? _d : (_j.channelFields = INCLUDE_CHANNEL_FIELDS); + (_e = (_k = parameters.include).customChannelFields) !== null && _e !== void 0 ? _e : (_k.customChannelFields = INCLUDE_CHANNEL_CUSTOM_FIELDS); + (_f = parameters.limit) !== null && _f !== void 0 ? _f : (parameters.limit = LIMIT$3); + // Remap for backward compatibility. + if (this.parameters.userId) + this.parameters.uuid = this.parameters.userId; + } + operation() { + return RequestOperation$1.PNSetMembershipsOperation; + } + validate() { + const { uuid, channels } = this.parameters; + if (!uuid) + return "'uuid' cannot be empty"; + if (!channels || channels.length === 0) + return 'Channels cannot be empty'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + return serviceResponse; + }); + } + get path() { + const { keySet: { subscribeKey }, uuid, } = this.parameters; + return `/v2/objects/${subscribeKey}/uuids/${encodeString(uuid)}/channels`; + } + get queryParameters() { + const { include, page, filter, sort, limit } = this.parameters; + const sorting = Object.entries(sort !== null && sort !== void 0 ? sort : {}).map(([option, order]) => order !== null ? `${option}:${order}` : option); + const includeFlags = ['channel.status', 'channel.type', 'status']; + if (include.customFields) + includeFlags.push('custom'); + if (include.channelFields) + includeFlags.push('channel'); + if (include.customChannelFields) + includeFlags.push('channel.custom'); + return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ count: `${include.totalCount}` }, (includeFlags.length > 0 ? { include: includeFlags.join(',') } : {})), (filter ? { filter } : {})), ((page === null || page === void 0 ? void 0 : page.next) ? { start: page.next } : {})), ((page === null || page === void 0 ? void 0 : page.prev) ? { end: page.prev } : {})), (limit ? { limit } : {})), (sorting.length ? { sort: sorting } : {})); + } + get body() { + const { channels, type } = this.parameters; + return JSON.stringify({ + [`${type}`]: channels.map((channel) => { + if (typeof channel === 'string') { + return { channel: { id: channel } }; + } + else { + return { channel: { id: channel.id }, status: channel.status, custom: channel.custom }; + } + }), + }); + } + } + + /** + * Get All UUID Metadata REST API module. + */ + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults + /** + * Whether `Channel` custom field should be included by default or not. + */ + const INCLUDE_CUSTOM_FIELDS$6 = false; + /** + * Number of objects to return in response. + */ + const LIMIT$2 = 100; + // endregion + class GetAllUUIDMetadataRequest extends AbstractRequest { + constructor(parameters) { + var _a, _b, _c; + var _d; + super(); + this.parameters = parameters; + // Apply default request parameters. + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_d = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_d.customFields = INCLUDE_CUSTOM_FIELDS$6); + (_c = parameters.limit) !== null && _c !== void 0 ? _c : (parameters.limit = LIMIT$2); + } + operation() { + return RequestOperation$1.PNGetAllUUIDMetadataOperation; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + return serviceResponse; + }); + } + get path() { + return `/v2/objects/${this.parameters.keySet.subscribeKey}/uuids`; + } + get queryParameters() { + const { include, page, filter, sort, limit } = this.parameters; + const sorting = Object.entries(sort !== null && sort !== void 0 ? sort : {}).map(([option, order]) => order !== null ? `${option}:${order}` : option); + return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ include: ['status', 'type', ...(include.customFields ? ['custom'] : [])].join(',') }, (include.totalCount !== undefined ? { count: `${include.totalCount}` } : {})), (filter ? { filter } : {})), ((page === null || page === void 0 ? void 0 : page.next) ? { start: page.next } : {})), ((page === null || page === void 0 ? void 0 : page.prev) ? { end: page.prev } : {})), (limit ? { limit } : {})), (sorting.length ? { sort: sorting } : {})); + } + } + + /** + * Get Channel Metadata REST API module. + */ + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults + /** + * Whether `Channel` custom field should be included by default or not. + */ + const INCLUDE_CUSTOM_FIELDS$5 = true; + // endregion + /** + * Get Channel Metadata request. + */ + class GetChannelMetadataRequest extends AbstractRequest { + constructor(parameters) { + var _a, _b; + var _c; + super(); + this.parameters = parameters; + // Apply default request parameters. + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_c = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_c.customFields = INCLUDE_CUSTOM_FIELDS$5); + } + operation() { + return RequestOperation$1.PNGetChannelMetadataOperation; + } + validate() { + if (!this.parameters.channel) + return 'Channel cannot be empty'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + return serviceResponse; + }); + } + get path() { + const { keySet: { subscribeKey }, channel, } = this.parameters; + return `/v2/objects/${subscribeKey}/channels/${encodeString(channel)}`; + } + get queryParameters() { + return { + include: ['status', 'type', ...(this.parameters.include.customFields ? ['custom'] : [])].join(','), + }; + } + } + + /** + * Set Channel Metadata REST API module. + */ + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults + /** + * Whether `Channel` custom field should be included by default or not. + */ + const INCLUDE_CUSTOM_FIELDS$4 = true; + // endregion + /** + * Set Channel Metadata request. + */ + class SetChannelMetadataRequest extends AbstractRequest { + constructor(parameters) { + var _a, _b; + var _c; + super({ method: TransportMethod.PATCH }); + this.parameters = parameters; + // Apply default request parameters. + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_c = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_c.customFields = INCLUDE_CUSTOM_FIELDS$4); + } + operation() { + return RequestOperation$1.PNSetChannelMetadataOperation; + } + validate() { + if (!this.parameters.channel) + return 'Channel cannot be empty'; + if (!this.parameters.data) + return 'Data cannot be empty'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + return serviceResponse; + }); + } + get path() { + const { keySet: { subscribeKey }, channel, } = this.parameters; + return `/v2/objects/${subscribeKey}/channels/${encodeString(channel)}`; + } + get queryParameters() { + return { + include: ['status', 'type', ...(this.parameters.include.customFields ? ['custom'] : [])].join(','), + }; + } + get body() { + return JSON.stringify(this.parameters.data); + } + } + + /** + * Remove UUID Metadata REST API module. + */ + // endregion + /** + * Remove UUID Metadata request. + */ + class RemoveUUIDMetadataRequest extends AbstractRequest { + constructor(parameters) { + super({ method: TransportMethod.DELETE }); + this.parameters = parameters; + // Remap for backward compatibility. + if (this.parameters.userId) + this.parameters.uuid = this.parameters.userId; + } + operation() { + return RequestOperation$1.PNRemoveUUIDMetadataOperation; + } + validate() { + if (!this.parameters.uuid) + return "'uuid' cannot be empty"; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + return serviceResponse; + }); + } + get path() { + const { keySet: { subscribeKey }, uuid, } = this.parameters; + return `/v2/objects/${subscribeKey}/uuids/${encodeString(uuid)}`; + } + } + + /** + * Get Channel Members REST API module. + */ + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults + /** + * Whether `Member` custom field should be included in response or not. + */ + const INCLUDE_CUSTOM_FIELDS$3 = false; + /** + * Whether member's status field should be included in response or not. + */ + const INCLUDE_STATUS = false; + /** + * Whether total number of members should be included in response or not. + */ + const INCLUDE_TOTAL_COUNT$1 = false; + /** + * Whether `UUID` fields should be included in response or not. + */ + const INCLUDE_UUID_FIELDS$1 = false; + /** + * Whether `UUID` status field should be included in response or not. + */ + const INCLUDE_UUID_STATUS_FIELD = false; + /** + * Whether `UUID` type field should be included in response or not. + */ + const INCLUDE_UUID_TYPE_FIELD = false; + /** + * Whether `UUID` custom field should be included in response or not. + */ + const INCLUDE_UUID_CUSTOM_FIELDS$1 = false; + /** + * Number of objects to return in response. + */ + const LIMIT$1 = 100; + // endregion + /** + * Get Channel Members request. + */ + class GetChannelMembersRequest extends AbstractRequest { + constructor(parameters) { + var _a, _b, _c, _d, _e, _f, _g, _h, _j; + var _k, _l, _m, _o, _p, _q, _r; + super(); + this.parameters = parameters; + // Apply default request parameters. + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_k = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_k.customFields = INCLUDE_CUSTOM_FIELDS$3); + (_c = (_l = parameters.include).totalCount) !== null && _c !== void 0 ? _c : (_l.totalCount = INCLUDE_TOTAL_COUNT$1); + (_d = (_m = parameters.include).statusField) !== null && _d !== void 0 ? _d : (_m.statusField = INCLUDE_STATUS); + (_e = (_o = parameters.include).UUIDFields) !== null && _e !== void 0 ? _e : (_o.UUIDFields = INCLUDE_UUID_FIELDS$1); + (_f = (_p = parameters.include).customUUIDFields) !== null && _f !== void 0 ? _f : (_p.customUUIDFields = INCLUDE_UUID_CUSTOM_FIELDS$1); + (_g = (_q = parameters.include).UUIDStatusField) !== null && _g !== void 0 ? _g : (_q.UUIDStatusField = INCLUDE_UUID_STATUS_FIELD); + (_h = (_r = parameters.include).UUIDTypeField) !== null && _h !== void 0 ? _h : (_r.UUIDTypeField = INCLUDE_UUID_TYPE_FIELD); + (_j = parameters.limit) !== null && _j !== void 0 ? _j : (parameters.limit = LIMIT$1); + } + operation() { + return RequestOperation$1.PNSetMembersOperation; + } + validate() { + if (!this.parameters.channel) + return 'Channel cannot be empty'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + return serviceResponse; + }); + } + get path() { + const { keySet: { subscribeKey }, channel, } = this.parameters; + return `/v2/objects/${subscribeKey}/channels/${encodeString(channel)}/uuids`; + } + get queryParameters() { + const { include, page, filter, sort, limit } = this.parameters; + const sorting = Object.entries(sort !== null && sort !== void 0 ? sort : {}).map(([option, order]) => order !== null ? `${option}:${order}` : option); + const includeFlags = []; + if (include.statusField) + includeFlags.push('status'); + if (include.customFields) + includeFlags.push('custom'); + if (include.UUIDFields) + includeFlags.push('uuid'); + if (include.UUIDStatusField) + includeFlags.push('uuid.status'); + if (include.UUIDTypeField) + includeFlags.push('uuid.type'); + if (include.customUUIDFields) + includeFlags.push('uuid.custom'); + return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ count: `${include.totalCount}` }, (includeFlags.length > 0 ? { include: includeFlags.join(',') } : {})), (filter ? { filter } : {})), ((page === null || page === void 0 ? void 0 : page.next) ? { start: page.next } : {})), ((page === null || page === void 0 ? void 0 : page.prev) ? { end: page.prev } : {})), (limit ? { limit } : {})), (sorting.length ? { sort: sorting } : {})); + } + } + + /** + * Set Channel Members REST API module. + */ + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults + /** + * Whether `Member` custom field should be included in response or not. + */ + const INCLUDE_CUSTOM_FIELDS$2 = false; + /** + * Whether total number of members should be included in response or not. + */ + const INCLUDE_TOTAL_COUNT = false; + /** + * Whether `UUID` fields should be included in response or not. + */ + const INCLUDE_UUID_FIELDS = false; + /** + * Whether `UUID` custom field should be included in response or not. + */ + const INCLUDE_UUID_CUSTOM_FIELDS = false; + /** + * Number of objects to return in response. + */ + const LIMIT = 100; + // endregion + /** + * Set Channel Members request. + */ + class SetChannelMembersRequest extends AbstractRequest { + constructor(parameters) { + var _a, _b, _c, _d, _e, _f; + var _g, _h, _j, _k; + super({ method: TransportMethod.PATCH }); + this.parameters = parameters; + // Apply default request parameters. + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_g = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_g.customFields = INCLUDE_CUSTOM_FIELDS$2); + (_c = (_h = parameters.include).totalCount) !== null && _c !== void 0 ? _c : (_h.totalCount = INCLUDE_TOTAL_COUNT); + (_d = (_j = parameters.include).UUIDFields) !== null && _d !== void 0 ? _d : (_j.UUIDFields = INCLUDE_UUID_FIELDS); + (_e = (_k = parameters.include).customUUIDFields) !== null && _e !== void 0 ? _e : (_k.customUUIDFields = INCLUDE_UUID_CUSTOM_FIELDS); + (_f = parameters.limit) !== null && _f !== void 0 ? _f : (parameters.limit = LIMIT); + } + operation() { + return RequestOperation$1.PNSetMembersOperation; + } + validate() { + const { channel, uuids } = this.parameters; + if (!channel) + return 'Channel cannot be empty'; + if (!uuids || uuids.length === 0) + return 'UUIDs cannot be empty'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + return serviceResponse; + }); + } + get path() { + const { keySet: { subscribeKey }, channel, } = this.parameters; + return `/v2/objects/${subscribeKey}/channels/${encodeString(channel)}/uuids`; + } + get queryParameters() { + const { include, page, filter, sort, limit } = this.parameters; + const sorting = Object.entries(sort !== null && sort !== void 0 ? sort : {}).map(([option, order]) => order !== null ? `${option}:${order}` : option); + const includeFlags = ['uuid.status', 'uuid.type', 'type']; + if (include.customFields) + includeFlags.push('custom'); + if (include.UUIDFields) + includeFlags.push('uuid'); + if (include.customUUIDFields) + includeFlags.push('uuid.custom'); + return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ count: `${include.totalCount}` }, (includeFlags.length > 0 ? { include: includeFlags.join(',') } : {})), (filter ? { filter } : {})), ((page === null || page === void 0 ? void 0 : page.next) ? { start: page.next } : {})), ((page === null || page === void 0 ? void 0 : page.prev) ? { end: page.prev } : {})), (limit ? { limit } : {})), (sorting.length ? { sort: sorting } : {})); + } + get body() { + const { uuids, type } = this.parameters; + return JSON.stringify({ + [`${type}`]: uuids.map((uuid) => { + if (typeof uuid === 'string') { + return { uuid: { id: uuid } }; + } + else { + return { uuid: { id: uuid.id }, status: uuid.status, custom: uuid.custom }; + } + }), + }); + } + } + + /** + * Get UUID Metadata REST API module. + */ + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults + /** + * Whether UUID custom field should be included by default or not. + */ + const INCLUDE_CUSTOM_FIELDS$1 = true; + // endregion + /** + * Get UUID Metadata request. + */ + class GetUUIDMetadataRequest extends AbstractRequest { + constructor(parameters) { + var _a, _b; + var _c; + super(); + this.parameters = parameters; + // Apply default request parameters. + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_c = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_c.customFields = INCLUDE_CUSTOM_FIELDS$1); + // Remap for backward compatibility. + if (this.parameters.userId) + this.parameters.uuid = this.parameters.userId; + } + operation() { + return RequestOperation$1.PNGetUUIDMetadataOperation; + } + validate() { + if (!this.parameters.uuid) + return "'uuid' cannot be empty"; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + return serviceResponse; + }); + } + get path() { + const { keySet: { subscribeKey }, uuid, } = this.parameters; + return `/v2/objects/${subscribeKey}/uuids/${encodeString(uuid)}`; + } + get queryParameters() { + const { include } = this.parameters; + return { include: ['status', 'type', ...(include.customFields ? ['custom'] : [])].join(',') }; + } + } + + /** + * Set UUID Metadata REST API module. + */ + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults + /** + * Whether `Channel` custom field should be included by default or not. + */ + const INCLUDE_CUSTOM_FIELDS = true; + // endregion + /** + * Set UUID Metadata request. + */ + class SetUUIDMetadataRequest extends AbstractRequest { + constructor(parameters) { + var _a, _b; + var _c; + super({ method: TransportMethod.PATCH }); + this.parameters = parameters; + // Apply default request parameters. + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_c = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_c.customFields = INCLUDE_CUSTOM_FIELDS); + // Remap for backward compatibility. + if (this.parameters.userId) + this.parameters.uuid = this.parameters.userId; + } + operation() { + return RequestOperation$1.PNSetUUIDMetadataOperation; + } + validate() { + if (!this.parameters.uuid) + return "'uuid' cannot be empty"; + if (!this.parameters.data) + return 'Data cannot be empty'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw PubNubAPIError.create(response); + return serviceResponse; + }); + } + get path() { + const { keySet: { subscribeKey }, uuid, } = this.parameters; + return `/v2/objects/${subscribeKey}/uuids/${encodeString(uuid)}`; + } + get queryParameters() { + return { + include: ['status', 'type', ...(this.parameters.include.customFields ? ['custom'] : [])].join(','), + }; + } + get body() { + return JSON.stringify(this.parameters.data); + } + } + + /** + * PubNub Objects API module. + */ + class PubNubObjects { + constructor(configuration, + /* eslint-disable @typescript-eslint/no-explicit-any */ + sendRequest) { + this.configuration = configuration; + this.sendRequest = sendRequest; + this.keySet = configuration.keySet; + } + /** + * Fetch a paginated list of UUID Metadata objects. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all UUID metadata response or `void` in case if `callback` provided. + */ + getAllUUIDMetadata(parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this._getAllUUIDMetadata(parametersOrCallback, callback); + }); + } + /** + * Fetch a paginated list of UUID Metadata objects. + * + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all UUID metadata response or `void` in case if `callback` provided. + */ + _getAllUUIDMetadata(parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function* () { + // Get user request parameters. + const parameters = parametersOrCallback && typeof parametersOrCallback !== 'function' ? parametersOrCallback : {}; + callback !== null && callback !== void 0 ? callback : (callback = typeof parametersOrCallback === 'function' ? parametersOrCallback : undefined); + const request = new GetAllUUIDMetadataRequest(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * Fetch a specific UUID Metadata object. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get UUID metadata response or `void` in case if `callback` provided. + */ + getUUIDMetadata(parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this._getUUIDMetadata(parametersOrCallback, callback); + }); + } + /** + * Fetch a specific UUID Metadata object. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get UUID metadata response or `void` in case if `callback` provided. + */ + _getUUIDMetadata(parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function* () { + var _a; + // Get user request parameters. + const parameters = parametersOrCallback && typeof parametersOrCallback !== 'function' ? parametersOrCallback : {}; + callback !== null && callback !== void 0 ? callback : (callback = typeof parametersOrCallback === 'function' ? parametersOrCallback : undefined); + if (parameters.userId) + parameters.uuid = parameters.userId; + (_a = parameters.uuid) !== null && _a !== void 0 ? _a : (parameters.uuid = this.configuration.userId); + const request = new GetUUIDMetadataRequest(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * Update specific UUID Metadata object. + * + * @param parameters - Request configuration parameters. Will set UUID metadata for currently + * configured PubNub client `uuid` if not set. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous set UUID metadata response or `void` in case if `callback` provided. + */ + setUUIDMetadata(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this._setUUIDMetadata(parameters, callback); + }); + } + /** + * Update specific UUID Metadata object. + * + * @param parameters - Request configuration parameters. Will set UUID metadata for currently + * configured PubNub client `uuid` if not set. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous set UUID metadata response or `void` in case if `callback` provided. + */ + _setUUIDMetadata(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + var _a; + if (parameters.userId) + parameters.uuid = parameters.userId; + (_a = parameters.uuid) !== null && _a !== void 0 ? _a : (parameters.uuid = this.configuration.userId); + const request = new SetUUIDMetadataRequest(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * Remove a specific UUID Metadata object. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous UUID metadata remove response or `void` in case if `callback` provided. + */ + removeUUIDMetadata(parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this._removeUUIDMetadata(parametersOrCallback, callback); + }); + } + /** + * Remove a specific UUID Metadata object. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous UUID metadata remove response or `void` in case if `callback` provided. + */ + _removeUUIDMetadata(parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function* () { + var _a; + // Get user request parameters. + const parameters = parametersOrCallback && typeof parametersOrCallback !== 'function' ? parametersOrCallback : {}; + callback !== null && callback !== void 0 ? callback : (callback = typeof parametersOrCallback === 'function' ? parametersOrCallback : undefined); + if (parameters.userId) + parameters.uuid = parameters.userId; + (_a = parameters.uuid) !== null && _a !== void 0 ? _a : (parameters.uuid = this.configuration.userId); + const request = new RemoveUUIDMetadataRequest(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * Fetch a paginated list of Channel Metadata objects. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all Channel metadata response or `void` in case if `callback` + * provided. + */ + getAllChannelMetadata(parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this._getAllChannelMetadata(parametersOrCallback, callback); + }); + } + /** + * Fetch a paginated list of Channel Metadata objects. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all Channel metadata response or `void` in case if `callback` + * provided. + */ + _getAllChannelMetadata(parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function* () { + // Get user request parameters. + const parameters = parametersOrCallback && typeof parametersOrCallback !== 'function' ? parametersOrCallback : {}; + callback !== null && callback !== void 0 ? callback : (callback = typeof parametersOrCallback === 'function' ? parametersOrCallback : undefined); + const request = new GetAllChannelsMetadataRequest(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * Fetch Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get Channel metadata response or `void` in case if `callback` provided. + */ + getChannelMetadata(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this._getChannelMetadata(parameters, callback); + }); + } + /** + * Fetch Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get Channel metadata response or `void` in case if `callback` provided. + */ + _getChannelMetadata(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new GetChannelMetadataRequest(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * Update specific Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous set Channel metadata response or `void` in case if `callback` provided. + */ + setChannelMetadata(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this._setChannelMetadata(parameters, callback); + }); + } + /** + * Update specific Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous set Channel metadata response or `void` in case if `callback` provided. + */ + _setChannelMetadata(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new SetChannelMetadataRequest(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * Remove a specific Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous Channel metadata remove response or `void` in case if `callback` + * provided. + */ + removeChannelMetadata(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this._removeChannelMetadata(parameters, callback); + }); + } + /** + * Remove a specific Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous Channel metadata remove response or `void` in case if `callback` + * provided. + */ + _removeChannelMetadata(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new RemoveChannelMetadataRequest(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * Fetch a paginated list of Channel Member objects. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get Channel Members response or `void` in case if `callback` provided. + */ + getChannelMembers(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new GetChannelMembersRequest(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * Update specific Channel Members list. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous update Channel members list response or `void` in case if `callback` + * provided. + */ + setChannelMembers(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new SetChannelMembersRequest(Object.assign(Object.assign({}, parameters), { type: 'set', keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * Remove Members from the Channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous Channel Members remove response or `void` in case if `callback` provided. + */ + removeChannelMembers(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new SetChannelMembersRequest(Object.assign(Object.assign({}, parameters), { type: 'delete', keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * Fetch a specific UUID Memberships list. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get UUID Memberships response or `void` in case if `callback` provided. + */ + getMemberships(parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function* () { + var _a; + // Get user request parameters. + const parameters = parametersOrCallback && typeof parametersOrCallback !== 'function' ? parametersOrCallback : {}; + callback !== null && callback !== void 0 ? callback : (callback = typeof parametersOrCallback === 'function' ? parametersOrCallback : undefined); + if (parameters.userId) + parameters.uuid = parameters.userId; + (_a = parameters.uuid) !== null && _a !== void 0 ? _a : (parameters.uuid = this.configuration.userId); + const request = new GetUUIDMembershipsRequest(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * Update specific UUID Memberships list. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous update UUID Memberships list response or `void` in case if `callback` + * provided. + */ + setMemberships(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + var _a; + if (parameters.userId) + parameters.uuid = parameters.userId; + (_a = parameters.uuid) !== null && _a !== void 0 ? _a : (parameters.uuid = this.configuration.userId); + const request = new SetUUIDMembershipsRequest(Object.assign(Object.assign({}, parameters), { type: 'set', keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * Remove a specific UUID Memberships. + * + * @param parameters - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous UUID Memberships remove response or `void` in case if `callback` + * provided. + */ + removeMemberships(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + var _a; + if (parameters.userId) + parameters.uuid = parameters.userId; + (_a = parameters.uuid) !== null && _a !== void 0 ? _a : (parameters.uuid = this.configuration.userId); + const request = new SetUUIDMembershipsRequest(Object.assign(Object.assign({}, parameters), { type: 'delete', keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + // endregion + // endregion + // -------------------------------------------------------- + // --------------------- Deprecated API ------------------- + // -------------------------------------------------------- + // region Deprecated + /** + * Fetch paginated list of specific Space members or specific User memberships. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get specific Space members or specific User memberships response. + * + * @deprecated Use {@link PubNubObjects#getChannelMembers} or {@link PubNubObjects#getMemberships} methods instead. + */ + fetchMemberships(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + var _a, _b; + if ('spaceId' in parameters) { + const spaceParameters = parameters; + const mappedParameters = { + channel: (_a = spaceParameters.spaceId) !== null && _a !== void 0 ? _a : spaceParameters.channel, + filter: spaceParameters.filter, + limit: spaceParameters.limit, + page: spaceParameters.page, + include: Object.assign({}, spaceParameters.include), + sort: spaceParameters.sort + ? Object.fromEntries(Object.entries(spaceParameters.sort).map(([key, value]) => [key.replace('user', 'uuid'), value])) + : undefined, + }; + // Map Members object to the older version. + const mapMembers = (response) => ({ + status: response.status, + data: response.data.map((members) => ({ + user: members.uuid, + custom: members.custom, + updated: members.updated, + eTag: members.eTag, + })), + totalCount: response.totalCount, + next: response.next, + prev: response.prev, + }); + if (callback) + return this.getChannelMembers(mappedParameters, (status, result) => { + callback(status, result ? mapMembers(result) : result); + }); + return this.getChannelMembers(mappedParameters).then(mapMembers); + } + const userParameters = parameters; + const mappedParameters = { + uuid: (_b = userParameters.userId) !== null && _b !== void 0 ? _b : userParameters.uuid, + filter: userParameters.filter, + limit: userParameters.limit, + page: userParameters.page, + include: Object.assign({}, userParameters.include), + sort: userParameters.sort + ? Object.fromEntries(Object.entries(userParameters.sort).map(([key, value]) => [key.replace('space', 'channel'), value])) + : undefined, + }; + // Map Memberships object to the older version. + const mapMemberships = (response) => ({ + status: response.status, + data: response.data.map((membership) => ({ + space: membership.channel, + custom: membership.custom, + updated: membership.updated, + eTag: membership.eTag, + })), + totalCount: response.totalCount, + next: response.next, + prev: response.prev, + }); + if (callback) + return this.getMemberships(mappedParameters, (status, result) => { + callback(status, result ? mapMemberships(result) : result); + }); + return this.getMemberships(mappedParameters).then(mapMemberships); + }); + } + /** + * Add members to specific Space or memberships specific User. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous add members to specific Space or memberships specific User response or + * `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubObjects#setChannelMembers} or {@link PubNubObjects#setMemberships} methods instead. + */ + addMemberships(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + var _a, _b, _c, _d, _e, _f; + if ('spaceId' in parameters) { + const spaceParameters = parameters; + const mappedParameters = { + channel: (_a = spaceParameters.spaceId) !== null && _a !== void 0 ? _a : spaceParameters.channel, + uuids: (_c = (_b = spaceParameters.users) === null || _b === void 0 ? void 0 : _b.map((user) => { + if (typeof user === 'string') + return user; + user.userId; + return { id: user.userId, custom: user.custom }; + })) !== null && _c !== void 0 ? _c : spaceParameters.uuids, + limit: 0, + }; + if (callback) + return this.setChannelMembers(mappedParameters, callback); + return this.setChannelMembers(mappedParameters); + } + const userParameters = parameters; + const mappedParameters = { + uuid: (_d = userParameters.userId) !== null && _d !== void 0 ? _d : userParameters.uuid, + channels: (_f = (_e = userParameters.spaces) === null || _e === void 0 ? void 0 : _e.map((space) => { + if (typeof space === 'string') + return space; + return { + id: space.spaceId, + custom: space.custom, + }; + })) !== null && _f !== void 0 ? _f : userParameters.channels, + limit: 0, + }; + if (callback) + return this.setMemberships(mappedParameters, callback); + return this.setMemberships(mappedParameters); + }); + } + } + + /** + * Time REST API module. + */ + // endregion + class TimeRequest extends AbstractRequest { + constructor() { + super(); + } + operation() { + return RequestOperation$1.PNTimeOperation; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return { timetoken: serviceResponse[0] }; + }); + } + get path() { + return '/time/0'; + } + } + + /** + * Download File REST API module. + */ + // endregion + /** + * Download File request. + */ + class DownloadFileRequest extends AbstractRequest { + constructor(parameters) { + super(); + this.parameters = parameters; + } + operation() { + return RequestOperation$1.PNDownloadFileOperation; + } + validate() { + const { channel, id, name } = this.parameters; + if (!channel) + return "channel can't be empty"; + if (!id) + return "file id can't be empty"; + if (!name) + return "file name can't be empty"; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const { cipherKey, crypto, cryptography, name, PubNubFile } = this.parameters; + const mimeType = response.headers['content-type']; + let decryptedFile; + let body = response.body; + if (PubNubFile.supportsEncryptFile && (cipherKey || crypto)) { + if (cipherKey && cryptography) + body = yield cryptography.decrypt(cipherKey, body); + else if (!cipherKey && crypto) + decryptedFile = yield crypto.decryptFile(PubNubFile.create({ data: body, name: name, mimeType }), PubNubFile); + } + return (decryptedFile + ? decryptedFile + : PubNubFile.create({ + data: body, + name, + mimeType, + })); + }); + } + get path() { + const { keySet: { subscribeKey }, channel, id, name, } = this.parameters; + return `/v1/files/${subscribeKey}/channels/${encodeString(channel)}/files/${id}/${name}`; + } + } + + // endregion + /** + * Platform-agnostic PubNub client core. + */ + class PubNubCore { + /** + * Construct notification payload which will trigger push notification. + * + * @param title - Title which will be shown on notification. + * @param body - Payload which will be sent as part of notification. + * + * @returns Pre-formatted message payload which will trigger push notification. + */ + static notificationPayload(title, body) { + return new NotificationsPayload(title, body); + } + /** + * Generate unique identifier. + * + * @returns Unique identifier. + */ + static generateUUID() { + return uuidGenerator.createUUID(); + } + // endregion + constructor(configuration) { + this._configuration = configuration.configuration; + this.cryptography = configuration.cryptography; + this.tokenManager = configuration.tokenManager; + this.transport = configuration.transport; + this.crypto = configuration.crypto; + // API group entry points initialization. + this._objects = new PubNubObjects(this._configuration, this.sendRequest.bind(this)); + this._channelGroups = new PubnubChannelGroups(this._configuration.keySet, this.sendRequest.bind(this)); + this._push = new PubNubPushNotifications(this._configuration.keySet, this.sendRequest.bind(this)); + // Prepare for real-time events announcement. + this.listenerManager = new ListenerManager(); + this.eventEmitter = new EventEmitter(this.listenerManager); + if (this._configuration.enableEventEngine) { + let heartbeatInterval = this._configuration.getHeartbeatInterval(); + this.presenceState = {}; + if (heartbeatInterval) { + this.presenceEventEngine = new PresenceEventEngine({ + heartbeat: this.heartbeat.bind(this), + leave: (parameters) => this.makeUnsubscribe(parameters, () => { }), + heartbeatDelay: () => new Promise((resolve, reject) => { + heartbeatInterval = this._configuration.getHeartbeatInterval(); + if (!heartbeatInterval) + reject(new PubNubError('Heartbeat interval has been reset.')); + else + setTimeout(resolve, heartbeatInterval * 1000); + }), + retryDelay: (amount) => new Promise((resolve) => setTimeout(resolve, amount)), + emitStatus: (status) => this.listenerManager.announceStatus(status), + config: this._configuration, + presenceState: this.presenceState, + }); + } + this.eventEngine = new EventEngine({ + handshake: this.subscribeHandshake.bind(this), + receiveMessages: this.subscribeReceiveMessages.bind(this), + delay: (amount) => new Promise((resolve) => setTimeout(resolve, amount)), + join: this.join.bind(this), + leave: this.leave.bind(this), + leaveAll: this.leaveAll.bind(this), + presenceState: this.presenceState, + config: this._configuration, + emitMessages: (events) => { + try { + events.forEach((event) => this.eventEmitter.emitEvent(event)); + } + catch (e) { + const errorStatus = { + error: true, + category: StatusCategory$1.PNUnknownCategory, + errorData: e, + statusCode: 0, + }; + this.listenerManager.announceStatus(errorStatus); + } + }, + emitStatus: (status) => this.listenerManager.announceStatus(status), + }); + } + else { + this.subscriptionManager = new SubscriptionManager(this._configuration, this.listenerManager, this.eventEmitter, this.makeSubscribe.bind(this), this.heartbeat.bind(this), this.makeUnsubscribe.bind(this), this.time.bind(this)); + } + } + // -------------------------------------------------------- + // -------------------- Configuration ---------------------- + // -------------------------------------------------------- + // region Configuration + /** + * PubNub client configuration. + * + * @returns Currently user PubNub client configuration. + */ + get configuration() { + return this._configuration; + } + /** + * Current PubNub client configuration. + * + * @returns Currently user PubNub client configuration. + * + * @deprecated Use {@link configuration} getter instead. + */ + get _config() { + return this.configuration; + } + /** + * REST API endpoint access authorization key. + * + * It is required to have `authorization key` with required permissions to access REST API + * endpoints when `PAM` enabled for user key set. + */ + get authKey() { + var _a; + return (_a = this._configuration.authKey) !== null && _a !== void 0 ? _a : undefined; + } + /** + * REST API endpoint access authorization key. + * + * It is required to have `authorization key` with required permissions to access REST API + * endpoints when `PAM` enabled for user key set. + */ + getAuthKey() { + return this.authKey; + } + /** + * Change REST API endpoint access authorization key. + * + * @param authKey - New authorization key which should be used with new requests. + */ + setAuthKey(authKey) { + this._configuration.setAuthKey(authKey); + } + /** + * Get a PubNub client user identifier. + * + * @returns Current PubNub client user identifier. + */ + get userId() { + return this._configuration.userId; + } + /** + * Change the current PubNub client user identifier. + * + * **Important:** Change won't affect ongoing REST API calls. + * + * @param value - New PubNub client user identifier. + * + * @throws Error empty user identifier has been provided. + */ + set userId(value) { + if (!value || typeof value !== 'string' || value.trim().length === 0) + throw new Error('Missing or invalid userId parameter. Provide a valid string userId'); + this._configuration.userId = value; + } + /** + * Get a PubNub client user identifier. + * + * @returns Current PubNub client user identifier. + */ + getUserId() { + return this._configuration.userId; + } + /** + * Change the current PubNub client user identifier. + * + * **Important:** Change won't affect ongoing REST API calls. + * + * @param value - New PubNub client user identifier. + * + * @throws Error empty user identifier has been provided. + */ + setUserId(value) { + if (!value || typeof value !== 'string' || value.trim().length === 0) + throw new Error('Missing or invalid userId parameter. Provide a valid string userId'); + this._configuration.userId = value; + } + /** + * Real-time updates filtering expression. + * + * @returns Filtering expression. + */ + get filterExpression() { + var _a; + return (_a = this._configuration.getFilterExpression()) !== null && _a !== void 0 ? _a : undefined; + } + /** + * Real-time updates filtering expression. + * + * @returns Filtering expression. + */ + getFilterExpression() { + return this.filterExpression; + } + /** + * Update real-time updates filtering expression. + * + * @param expression - New expression which should be used or `undefined` to disable filtering. + */ + set filterExpression(expression) { + this._configuration.setFilterExpression(expression); + } + /** + * Update real-time updates filtering expression. + * + * @param expression - New expression which should be used or `undefined` to disable filtering. + */ + setFilterExpression(expression) { + this.filterExpression = expression; + } + /** + * Dta encryption / decryption key. + * + * @returns Currently used key for data encryption / decryption. + */ + get cipherKey() { + return this._configuration.getCipherKey(); + } + /** + * Change data encryption / decryption key. + * + * @param key - New key which should be used for data encryption / decryption. + */ + set cipherKey(key) { + this._configuration.setCipherKey(key); + } + /** + * Change data encryption / decryption key. + * + * @param key - New key which should be used for data encryption / decryption. + */ + setCipherKey(key) { + this.cipherKey = key; + } + /** + * Change heartbeat requests interval. + * + * @param interval - New presence request heartbeat intervals. + */ + set heartbeatInterval(interval) { + this._configuration.setHeartbeatInterval(interval); + } + /** + * Change heartbeat requests interval. + * + * @param interval - New presence request heartbeat intervals. + */ + setHeartbeatInterval(interval) { + this.heartbeatInterval = interval; + } + /** + * Get PubNub SDK version. + * + * @returns Current SDK version. + */ + getVersion() { + return this._configuration.getVersion(); + } + /** + * Add framework's prefix. + * + * @param name - Name of the framework which would want to add own data into `pnsdk` suffix. + * @param suffix - Suffix with information about framework. + */ + _addPnsdkSuffix(name, suffix) { + this._configuration._addPnsdkSuffix(name, suffix); + } + // -------------------------------------------------------- + // ---------------------- Deprecated ---------------------- + // -------------------------------------------------------- + // region Deprecated + /** + * Get a PubNub client user identifier. + * + * @returns Current PubNub client user identifier. + * + * @deprecated Use the {@link getUserId} or {@link userId} getter instead. + */ + getUUID() { + return this.userId; + } + /** + * Change the current PubNub client user identifier. + * + * **Important:** Change won't affect ongoing REST API calls. + * + * @param value - New PubNub client user identifier. + * + * @throws Error empty user identifier has been provided. + * + * @deprecated Use the {@link PubNubCore#setUserId} or {@link PubNubCore#userId} setter instead. + */ + setUUID(value) { + this.userId = value; + } + /** + * Custom data encryption method. + * + * @deprecated Instead use {@link cryptoModule} for data encryption. + */ + get customEncrypt() { + return this._configuration.getCustomEncrypt(); + } + /** + * Custom data decryption method. + * + * @deprecated Instead use {@link cryptoModule} for data decryption. + */ + get customDecrypt() { + return this._configuration.getCustomDecrypt(); + } + // endregion + // endregion + // -------------------------------------------------------- + // ---------------------- Entities ------------------------ + // -------------------------------------------------------- + // region Entities + /** + * Create a `Channel` entity. + * + * Entity can be used for the interaction with the following API: + * - `subscribe` + * + * @param name - Unique channel name. + * @returns `Channel` entity. + */ + channel(name) { + return new Channel(name, this.eventEmitter, this); + } + /** + * Create a `ChannelGroup` entity. + * + * Entity can be used for the interaction with the following API: + * - `subscribe` + * + * @param name - Unique channel group name. + * @returns `ChannelGroup` entity. + */ + channelGroup(name) { + return new ChannelGroup(name, this.eventEmitter, this); + } + /** + * Create a `ChannelMetadata` entity. + * + * Entity can be used for the interaction with the following API: + * - `subscribe` + * + * @param id - Unique channel metadata object identifier. + * @returns `ChannelMetadata` entity. + */ + channelMetadata(id) { + return new ChannelMetadata(id, this.eventEmitter, this); + } + /** + * Create a `UserMetadata` entity. + * + * Entity can be used for the interaction with the following API: + * - `subscribe` + * + * @param id - Unique user metadata object identifier. + * @returns `UserMetadata` entity. + */ + userMetadata(id) { + return new UserMetadata(id, this.eventEmitter, this); + } + /** + * Create subscriptions set object. + * + * @param parameters - Subscriptions set configuration parameters. + */ + subscriptionSet(parameters) { + return new SubscriptionSet(Object.assign(Object.assign({}, parameters), { eventEmitter: this.eventEmitter, pubnub: this })); + } + /** + * Schedule request execution. + * + * @param request - REST API request. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous request execution and response parsing result or `void` in case if + * `callback` provided. + * + * @throws PubNubError in case of request processing error. + */ + sendRequest(request, callback) { + return __awaiter(this, void 0, void 0, function* () { + // Validate user-input. + const validationResult = request.validate(); + if (validationResult) { + if (callback) + return callback(createValidationError(validationResult), null); + throw new PubNubError('Validation failed, check status for details', createValidationError(validationResult)); + } + // Complete request configuration. + const transportRequest = request.request(); + if (transportRequest.formData && transportRequest.formData.length > 0) { + // Set 300 seconds file upload request delay. + transportRequest.timeout = 300; + } + else { + if (request.operation() === RequestOperation$1.PNSubscribeOperation) + transportRequest.timeout = this._configuration.getSubscribeTimeout(); + else + transportRequest.timeout = this._configuration.getTransactionTimeout(); + } + // API request processing status. + const status = { + error: false, + operation: request.operation(), + category: StatusCategory$1.PNAcknowledgmentCategory, + statusCode: 0, + }; + const [sendableRequest, cancellationController] = this.transport.makeSendable(transportRequest); + /** + * **Important:** Because of multiple environments where JS SDK can be used control over + * cancellation had to be inverted to let transport provider solve request cancellation task + * more efficiently. As result, cancellation controller can be retrieved and used only after + * request will be scheduled by transport provider. + */ + request.cancellationController = cancellationController ? cancellationController : null; + return sendableRequest + .then((response) => { + status.statusCode = response.status; + // Handle special case when request completed but not fully processed by PubNub service. + if (response.status !== 200 && response.status !== 204) { + const contentType = response.headers['content-type']; + if (contentType || contentType.indexOf('javascript') !== -1 || contentType.indexOf('json') !== -1) { + const json = JSON.parse(PubNubCore.decoder.decode(response.body)); + if (typeof json === 'object' && 'error' in json && json.error && typeof json.error === 'object') + status.errorData = json.error; + } + } + return request.parse(response); + }) + .then((parsed) => { + // Notify callback (if possible). + if (callback) + return callback(status, parsed); + return parsed; + }) + .catch((error) => { + const apiError = !(error instanceof PubNubAPIError) ? PubNubAPIError.create(error) : error; + // Notify callback (if possible). + if (callback) + return callback(apiError.toStatus(request.operation()), null); + throw apiError.toPubNubError(request.operation(), 'REST API request processing error, check status for details'); + }); + }); + } + /** + * Unsubscribe from all channels and groups. + * + * @param [isOffline] - Whether `offline` presence should be notified or not. + */ + destroy(isOffline) { + if (this.subscriptionManager) { + this.subscriptionManager.unsubscribeAll(isOffline); + this.subscriptionManager.disconnect(); + } + else if (this.eventEngine) + this.eventEngine.dispose(); + } + /** + * Unsubscribe from all channels and groups. + * + * @deprecated Use {@link destroy} method instead. + */ + stop() { + this.destroy(); + } + // endregion + // -------------------------------------------------------- + // ----------------------- Listener ----------------------- + // -------------------------------------------------------- + // region Listener + /** + * Register real-time events listener. + * + * @param listener - Listener with event callbacks to handle different types of events. + */ + addListener(listener) { + this.listenerManager.addListener(listener); + } + /** + * Remove real-time event listener. + * + * @param listener - Event listeners which should be removed. + */ + removeListener(listener) { + this.listenerManager.removeListener(listener); + } + /** + * Clear all real-time event listeners. + */ + removeAllListeners() { + this.listenerManager.removeAllListeners(); + } + /** + * Publish data to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous publish data response or `void` in case if `callback` provided. + */ + publish(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new PublishRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet, crypto: this._configuration.getCryptoModule() })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * Signal data to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous signal data response or `void` in case if `callback` provided. + */ + signal(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new SignalRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * `Fire` a data to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous signal data response or `void` in case if `callback` provided. + * + * @deprecated Use {@link publish} method instead. + */ + fire(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + callback !== null && callback !== void 0 ? callback : (callback = () => { }); + return this.publish(Object.assign(Object.assign({}, parameters), { replicate: false, storeInHistory: false }), callback); + }); + } + // endregion + // -------------------------------------------------------- + // -------------------- Subscribe API --------------------- + // -------------------------------------------------------- + // region Subscribe API + /** + * Get list of channels on which PubNub client currently subscribed. + * + * @returns List of active channels. + */ + getSubscribedChannels() { + if (this.subscriptionManager) + return this.subscriptionManager.subscribedChannels; + else if (this.eventEngine) + return this.eventEngine.getSubscribedChannels(); + return []; + } + /** + * Get list of channel groups on which PubNub client currently subscribed. + * + * @returns List of active channel groups. + */ + getSubscribedChannelGroups() { + if (this.subscriptionManager) + return this.subscriptionManager.subscribedChannelGroups; + else if (this.eventEngine) + return this.eventEngine.getSubscribedChannelGroups(); + return []; + } + /** + * Subscribe to specified channels and groups real-time events. + * + * @param parameters - Request configuration parameters. + */ + subscribe(parameters) { + if (this.subscriptionManager) + this.subscriptionManager.subscribe(parameters); + else if (this.eventEngine) + this.eventEngine.subscribe(parameters); + } + /** + * Perform subscribe request. + * + * **Note:** Method passed into managers to let them use it when required. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + makeSubscribe(parameters, callback) { + const request = new SubscribeRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet, crypto: this._configuration.getCryptoModule(), getFileUrl: this.getFileUrl.bind(this) })); + this.sendRequest(request, (status, result) => { + var _a; + if (this.subscriptionManager && ((_a = this.subscriptionManager.abort) === null || _a === void 0 ? void 0 : _a.identifier) === request.requestIdentifier) + this.subscriptionManager.abort = null; + callback(status, result); + }); + /** + * Allow subscription cancellation. + * + * **Note:** Had to be done after scheduling because transport provider return cancellation + * controller only when schedule new request. + */ + if (this.subscriptionManager) { + // Creating identifiable abort caller. + const callableAbort = () => request.abort(); + callableAbort.identifier = request.requestIdentifier; + this.subscriptionManager.abort = callableAbort; + } + } + /** + * Unsubscribe from specified channels and groups real-time events. + * + * @param parameters - Request configuration parameters. + */ + unsubscribe(parameters) { + if (this.subscriptionManager) + this.subscriptionManager.unsubscribe(parameters); + else if (this.eventEngine) + this.eventEngine.unsubscribe(parameters); + } + /** + * Perform unsubscribe request. + * + * **Note:** Method passed into managers to let them use it when required. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + makeUnsubscribe(parameters, callback) { + this.sendRequest(new PresenceLeaveRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet })), callback); + } + /** + * Unsubscribe from all channels and groups. + */ + unsubscribeAll() { + if (this.subscriptionManager) + this.subscriptionManager.unsubscribeAll(); + else if (this.eventEngine) + this.eventEngine.unsubscribeAll(); + } + /** + * Temporarily disconnect from real-time events stream. + */ + disconnect() { + if (this.subscriptionManager) + this.subscriptionManager.disconnect(); + else if (this.eventEngine) + this.eventEngine.disconnect(); + } + /** + * Restore connection to the real-time events stream. + * + * @param parameters - Reconnection catch up configuration. **Note:** available only with + * enabled event engine. + */ + reconnect(parameters) { + if (this.subscriptionManager) + this.subscriptionManager.reconnect(); + else if (this.eventEngine) + this.eventEngine.reconnect(parameters !== null && parameters !== void 0 ? parameters : {}); + } + /** + * Event engine handshake subscribe. + * + * @param parameters - Request configuration parameters. + */ + subscribeHandshake(parameters) { + return __awaiter(this, void 0, void 0, function* () { + const request = new HandshakeSubscribeRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet, crypto: this._configuration.getCryptoModule(), getFileUrl: this.getFileUrl.bind(this) })); + const abortUnsubscribe = parameters.abortSignal.subscribe((err) => { + request.abort(); + }); + /** + * Allow subscription cancellation. + * + * **Note:** Had to be done after scheduling because transport provider return cancellation + * controller only when schedule new request. + */ + const handshakeResponse = this.sendRequest(request); + return handshakeResponse.then((response) => { + abortUnsubscribe(); + return response.cursor; + }); + }); + } + /** + * Event engine receive messages subscribe. + * + * @param parameters - Request configuration parameters. + */ + subscribeReceiveMessages(parameters) { + return __awaiter(this, void 0, void 0, function* () { + const request = new ReceiveMessagesSubscribeRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet, crypto: this._configuration.getCryptoModule(), getFileUrl: this.getFileUrl.bind(this) })); + const abortUnsubscribe = parameters.abortSignal.subscribe((err) => { + request.abort(); + }); + /** + * Allow subscription cancellation. + * + * **Note:** Had to be done after scheduling because transport provider return cancellation + * controller only when schedule new request. + */ + const handshakeResponse = this.sendRequest(request); + return handshakeResponse.then((response) => { + abortUnsubscribe(); + return response; + }); + }); + } + /** + * Get reactions to a specific message. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get reactions response or `void` in case if `callback` provided. + */ + getMessageActions(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new GetMessageActionsRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * Add a reaction to a specific message. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous add a reaction response or `void` in case if `callback` provided. + */ + addMessageAction(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new AddMessageActionRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * Remove a reaction from a specific message. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous remove a reaction response or `void` in case if `callback` provided. + */ + removeMessageAction(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new RemoveMessageAction(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * Fetch messages history for channels. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous fetch messages response or `void` in case if `callback` provided. + */ + fetchMessages(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new FetchMessagesRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet, crypto: this._configuration.getCryptoModule(), getFileUrl: this.getFileUrl.bind(this) })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * Delete messages from the channel history. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous delete messages response or `void` in case if `callback` provided. + * + * @deprecated + */ + deleteMessages(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new DeleteMessageRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * Count messages from the channels' history. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous count messages response or `void` in case if `callback` provided. + */ + messageCounts(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new MessageCountRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * Fetch single channel history. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous fetch channel history response or `void` in case if `callback` provided. + * + * @deprecated + */ + history(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new GetHistoryRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet, crypto: this._configuration.getCryptoModule() })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * Get channel's presence information. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get channel's presence response or `void` in case if `callback` provided. + */ + hereNow(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new HereNowRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * Get user's presence information. + * + * Get list of channels to which `uuid` currently subscribed. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get user's presence response or `void` in case if `callback` provided. + */ + whereNow(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + var _a; + const request = new WhereNowRequest({ + uuid: (_a = parameters.uuid) !== null && _a !== void 0 ? _a : this._configuration.userId, + keySet: this._configuration.keySet, + }); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * Get associated user's data for channels and groups. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get user's data response or `void` in case if `callback` provided. + */ + getState(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + var _a; + const request = new GetPresenceStateRequest(Object.assign(Object.assign({}, parameters), { uuid: (_a = parameters.uuid) !== null && _a !== void 0 ? _a : this._configuration.userId, keySet: this._configuration.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * Set associated user's data for channels and groups. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous set user's data response or `void` in case if `callback` provided. + */ + setState(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + var _a, _b; + const { keySet, userId: userId } = this._configuration; + const heartbeat = this._configuration.getPresenceTimeout(); + let request; + // Maintain presence information (if required). + if (this._configuration.enableEventEngine && this.presenceState) { + const presenceState = this.presenceState; + (_a = parameters.channels) === null || _a === void 0 ? void 0 : _a.forEach((channel) => (presenceState[channel] = parameters.state)); + if ('channelGroups' in parameters) { + (_b = parameters.channelGroups) === null || _b === void 0 ? void 0 : _b.forEach((group) => (presenceState[group] = parameters.state)); + } + } + // Check whether state should be set with heartbeat or not. + if ('withHeartbeat' in parameters) { + request = new HeartbeatRequest(Object.assign(Object.assign({}, parameters), { keySet, heartbeat })); + } + else { + request = new SetPresenceStateRequest(Object.assign(Object.assign({}, parameters), { keySet, uuid: userId })); + } + // Update state used by subscription manager. + if (this.subscriptionManager) + this.subscriptionManager.setState(parameters); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + // endregion + // region Change presence state + /** + * Manual presence management. + * + * @param parameters - Desired presence state for provided list of channels and groups. + */ + presence(parameters) { + var _a; + (_a = this.subscriptionManager) === null || _a === void 0 ? void 0 : _a.changePresence(parameters); + } + // endregion + // region Heartbeat + /** + * Announce user presence + * + * @param parameters - Desired presence state for provided list of channels and groups. + * @param callback - Request completion handler callback. + */ + heartbeat(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new HeartbeatRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + // endregion + // region Join + /** + * Announce user `join` on specified list of channels and groups. + * + * @param parameters - List of channels and groups where `join` event should be sent. + */ + join(parameters) { + var _a; + (_a = this.presenceEventEngine) === null || _a === void 0 ? void 0 : _a.join(parameters); + } + // endregion + // region Leave + /** + * Announce user `leave` on specified list of channels and groups. + * + * @param parameters - List of channels and groups where `leave` event should be sent. + */ + leave(parameters) { + var _a; + (_a = this.presenceEventEngine) === null || _a === void 0 ? void 0 : _a.leave(parameters); + } + /** + * Announce user `leave` on all subscribed channels. + */ + leaveAll() { + var _a; + (_a = this.presenceEventEngine) === null || _a === void 0 ? void 0 : _a.leaveAll(); + } + /** + * Grant token permission. + * + * Generate access token with requested permissions. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous grant token response or `void` in case if `callback` provided. + */ + grantToken(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new GrantTokenRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * Revoke token permission. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous revoke token response or `void` in case if `callback` provided. + */ + revokeToken(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new RevokeTokenRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + // endregion + // region Token Manipulation + /** + * Get current access token. + * + * @returns Previously configured access token using {@link setToken} method. + */ + get token() { + return this.tokenManager.getToken(); + } + /** + * Get current access token. + * + * @returns Previously configured access token using {@link setToken} method. + */ + getToken() { + return this.token; + } + /** + * Set current access token. + * + * @param token - New access token which should be used with next REST API endpoint calls. + */ + set token(token) { + this.tokenManager.setToken(token); + } + /** + * Set current access token. + * + * @param token - New access token which should be used with next REST API endpoint calls. + */ + setToken(token) { + this.token = token; + } + /** + * Parse access token. + * + * Parse token to see what permissions token owner has. + * + * @param token - Token which should be parsed. + * + * @returns Token's permissions information for the resources. + */ + parseToken(token) { + return this.tokenManager.parseToken(token); + } + /** + * Grant auth key(s) permission. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous grant auth key(s) permissions or `void` in case if `callback` provided. + * + * @deprecated Use {@link grantToken} and {@link setToken} methods instead. + */ + grant(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new GrantRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * Audit auth key(s) permission. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @deprecated + * + * @deprecated Use {@link grantToken} and {@link setToken} methods instead. + */ + audit(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new AuditRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + // endregion + // endregion + // endregion + // -------------------------------------------------------- + // ------------------- App Context API -------------------- + // -------------------------------------------------------- + // region App Context API + /** + * PubNub App Context API group. + */ + get objects() { + return this._objects; + } + /** + Fetch a paginated list of User objects. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all User objects response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.getAllUUIDMetadata} method instead. + */ + fetchUsers(parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this.objects._getAllUUIDMetadata(parametersOrCallback, callback); + }); + } + /** + * Fetch User object for currently configured PubNub client `uuid`. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get User object response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.getUUIDMetadata} method instead. + */ + fetchUser(parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this.objects._getUUIDMetadata(parametersOrCallback, callback); + }); + } + /** + * Create User object. + * + * @param parameters - Request configuration parameters. Will create User object for currently + * configured PubNub client `uuid` if not set. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous create User object response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.setUUIDMetadata} method instead. + */ + createUser(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this.objects._setUUIDMetadata(parameters, callback); + }); + } + /** + * Update User object. + * + * @param parameters - Request configuration parameters. Will update User object for currently + * configured PubNub client `uuid` if not set. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous update User object response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.setUUIDMetadata} method instead. + */ + updateUser(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this.objects._setUUIDMetadata(parameters, callback); + }); + } + /** + * Remove a specific User object. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous User object remove response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.removeUUIDMetadata} method instead. + */ + removeUser(parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this.objects._removeUUIDMetadata(parametersOrCallback, callback); + }); + } + /** + * Fetch a paginated list of Space objects. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all Space objects response or `void` in case if `callback` + * provided. + * + * @deprecated Use {@link PubNubCore#objects.getAllChannelMetadata} method instead. + */ + fetchSpaces(parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this.objects._getAllChannelMetadata(parametersOrCallback, callback); + }); + } + /** + * Fetch a specific Space object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get Space object response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.getChannelMetadata} method instead. + */ + fetchSpace(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this.objects._getChannelMetadata(parameters, callback); + }); + } + /** + * Create specific Space object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous create Space object response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMetadata} method instead. + */ + createSpace(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this.objects._setChannelMetadata(parameters, callback); + }); + } + /** + * Update specific Space object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous update Space object response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMetadata} method instead. + */ + updateSpace(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this.objects._setChannelMetadata(parameters, callback); + }); + } + /** + * Remove a specific Space object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous Space object remove response or `void` in case if `callback` + * provided. + * + * @deprecated Use {@link PubNubCore#objects.removeChannelMetadata} method instead. + */ + removeSpace(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this.objects._removeChannelMetadata(parameters, callback); + }); + } + /** + * Fetch paginated list of specific Space members or specific User memberships. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get specific Space members or specific User memberships response or + * `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.getChannelMembers} or {@link PubNubCore#objects.getMemberships} + * methods instead. + */ + fetchMemberships(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this.objects.fetchMemberships(parameters, callback); + }); + } + /** + * Add members to specific Space or memberships specific User. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous add members to specific Space or memberships specific User response or + * `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMembers} or {@link PubNubCore#objects.setMemberships} + * methods instead. + */ + addMemberships(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this.objects.addMemberships(parameters, callback); + }); + } + /** + * Update specific Space members or User memberships. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous update Space members or User memberships response or `void` in case + * if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMembers} or {@link PubNubCore#objects.setMemberships} + * methods instead. + */ + updateMemberships(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this.objects.addMemberships(parameters, callback); + }); + } + /** + * Remove User membership. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous memberships modification response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.removeMemberships} or {@link PubNubCore#objects.removeChannelMembers} + * methods instead + * from `objects` API group.. + */ + removeMemberships(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + var _a, _b, _c; + if ('spaceId' in parameters) { + const spaceParameters = parameters; + const requestParameters = { + channel: (_a = spaceParameters.spaceId) !== null && _a !== void 0 ? _a : spaceParameters.channel, + uuids: (_b = spaceParameters.userIds) !== null && _b !== void 0 ? _b : spaceParameters.uuids, + limit: 0, + }; + if (callback) + return this.objects.removeChannelMembers(requestParameters, callback); + return this.objects.removeChannelMembers(requestParameters); + } + const userParameters = parameters; + const requestParameters = { + uuid: userParameters.userId, + channels: (_c = userParameters.spaceIds) !== null && _c !== void 0 ? _c : userParameters.channels, + limit: 0, + }; + if (callback) + return this.objects.removeMemberships(requestParameters, callback); + return this.objects.removeMemberships(requestParameters); + }); + } + // endregion + // endregion + // -------------------------------------------------------- + // ----------------- Channel Groups API ------------------- + // -------------------------------------------------------- + // region Channel Groups API + /** + * PubNub Channel Groups API group. + */ + get channelGroups() { + return this._channelGroups; + } + // endregion + // -------------------------------------------------------- + // ---------------- Push Notifications API ----------------- + // -------------------------------------------------------- + // region Push Notifications API + /** + * PubNub Push Notifications API group. + */ + get push() { + return this._push; + } + /** + * Share file to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous file sharing response or `void` in case if `callback` provided. + */ + sendFile(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + if (!this._configuration.PubNubFile) + throw new Error("Validation failed: 'PubNubFile' not configured or file upload not supported by the platform."); + const sendFileRequest = new SendFileRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet, PubNubFile: this._configuration.PubNubFile, fileUploadPublishRetryLimit: this._configuration.fileUploadPublishRetryLimit, file: parameters.file, sendRequest: this.sendRequest.bind(this), publishFile: this.publishFile.bind(this), crypto: this._configuration.getCryptoModule(), cryptography: this.cryptography ? this.cryptography : undefined })); + const status = { + error: false, + operation: RequestOperation$1.PNPublishFileOperation, + category: StatusCategory$1.PNAcknowledgmentCategory, + statusCode: 0, + }; + return sendFileRequest + .process() + .then((response) => { + status.statusCode = response.status; + if (callback) + return callback(status, response); + return response; + }) + .catch((error) => { + let errorStatus; + if (error instanceof PubNubError) + errorStatus = error.status; + else if (error instanceof PubNubAPIError) + errorStatus = error.toStatus(status.operation); + // Notify callback (if possible). + if (callback && errorStatus) + callback(errorStatus, null); + throw new PubNubError('REST API request processing error, check status for details', errorStatus); + }); + }); + } + /** + * Publish file message to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous publish file message response or `void` in case if `callback` provided. + */ + publishFile(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + if (!this._configuration.PubNubFile) + throw new Error("Validation failed: 'PubNubFile' not configured or file upload not supported by the platform."); + const request = new PublishFileMessageRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet, crypto: this._configuration.getCryptoModule() })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + * Retrieve list of shared files in specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous shared files list response or `void` in case if `callback` provided. + */ + listFiles(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new FilesListRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + // endregion + // region Get Download Url + /** + * Get file download Url. + * + * @param parameters - Request configuration parameters. + * + * @returns File download Url. + */ + getFileUrl(parameters) { + var _a; + const request = this.transport.request(new GetFileDownloadUrlRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet })).request()); + const query = (_a = request.queryParameters) !== null && _a !== void 0 ? _a : {}; + const queryString = Object.keys(query) + .map((key) => { + const queryValue = query[key]; + if (!Array.isArray(queryValue)) + return `${key}=${encodeString(queryValue)}`; + return queryValue.map((value) => `${key}=${encodeString(value)}`).join('&'); + }) + .join('&'); + return `${request.origin}${request.path}?${queryString}`; + } + /** + * Download shared file from specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous download shared file response or `void` in case if `callback` provided. + */ + downloadFile(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + if (!this._configuration.PubNubFile) + throw new Error("Validation failed: 'PubNubFile' not configured or file upload not supported by the platform."); + const request = new DownloadFileRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet, PubNubFile: this._configuration.PubNubFile, cryptography: this.cryptography ? this.cryptography : undefined, crypto: this._configuration.getCryptoModule() })); + if (callback) + return this.sendRequest(request, callback); + return (yield this.sendRequest(request)); + }); + } + /** + * Delete shared file from specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous delete shared file response or `void` in case if `callback` provided. + */ + deleteFile(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new DeleteFileRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + /** + Get current high-precision timetoken. + * + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get current timetoken response or `void` in case if `callback` provided. + */ + time(callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new TimeRequest(); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + // endregion + // -------------------------------------------------------- + // ------------------ Cryptography API -------------------- + // -------------------------------------------------------- + // region Cryptography + // region Common + /** + * Encrypt data. + * + * @param data - Stringified data which should be encrypted using `CryptoModule`. + * @deprecated + * @param [customCipherKey] - Cipher key which should be used to encrypt data. **Deprecated:** + * use {@link Configuration#cryptoModule|cryptoModule} instead. + * + * @returns Data encryption result as a string. + */ + encrypt(data, customCipherKey) { + const cryptoModule = this._configuration.getCryptoModule(); + if (!customCipherKey && cryptoModule && typeof data === 'string') { + const encrypted = cryptoModule.encrypt(data); + return typeof encrypted === 'string' ? encrypted : encode(encrypted); + } + if (!this.crypto) + throw new Error('Encryption error: cypher key not set'); + return this.crypto.encrypt(data, customCipherKey); + } + /** + * Decrypt data. + * + * @param data - Stringified data which should be encrypted using `CryptoModule`. + * @param [customCipherKey] - Cipher key which should be used to decrypt data. **Deprecated:** + * use {@link Configuration#cryptoModule|cryptoModule} instead. + * + * @returns Data decryption result as an object. + */ + decrypt(data, customCipherKey) { + const cryptoModule = this._configuration.getCryptoModule(); + if (!customCipherKey && cryptoModule) { + const decrypted = cryptoModule.decrypt(data); + return decrypted instanceof ArrayBuffer ? JSON.parse(new TextDecoder().decode(decrypted)) : decrypted; + } + if (!this.crypto) + throw new Error('Decryption error: cypher key not set'); + return this.crypto.decrypt(data, customCipherKey); + } + /** + * Encrypt file content. + * + * @param keyOrFile - Cipher key which should be used to encrypt data or file which should be + * encrypted using `CryptoModule`. + * @param [file] - File which should be encrypted using legacy cryptography. + * + * @returns Asynchronous file encryption result. + * + * @throws Error if source file not provided. + * @throws File constructor not provided. + * @throws Crypto module is missing (if non-legacy flow used). + */ + encryptFile(keyOrFile, file) { + return __awaiter(this, void 0, void 0, function* () { + var _a; + if (typeof keyOrFile !== 'string') + file = keyOrFile; + if (!file) + throw new Error('File encryption error. Source file is missing.'); + if (!this._configuration.PubNubFile) + throw new Error('File encryption error. File constructor not configured.'); + if (typeof keyOrFile !== 'string' && !this._configuration.getCryptoModule()) + throw new Error('File encryption error. Crypto module not configured.'); + if (typeof keyOrFile === 'string') { + if (!this.cryptography) + throw new Error('File encryption error. File encryption not available'); + return this.cryptography.encryptFile(keyOrFile, file, this._configuration.PubNubFile); + } + return (_a = this._configuration.getCryptoModule()) === null || _a === void 0 ? void 0 : _a.encryptFile(file, this._configuration.PubNubFile); + }); + } + /** + * Decrypt file content. + * + * @param keyOrFile - Cipher key which should be used to decrypt data or file which should be + * decrypted using `CryptoModule`. + * @param [file] - File which should be decrypted using legacy cryptography. + * + * @returns Asynchronous file decryption result. + * + * @throws Error if source file not provided. + * @throws File constructor not provided. + * @throws Crypto module is missing (if non-legacy flow used). + */ + decryptFile(keyOrFile, file) { + return __awaiter(this, void 0, void 0, function* () { + var _a; + if (typeof keyOrFile !== 'string') + file = keyOrFile; + if (!file) + throw new Error('File encryption error. Source file is missing.'); + if (!this._configuration.PubNubFile) + throw new Error('File decryption error. File constructor' + ' not configured.'); + if (typeof keyOrFile === 'string' && !this._configuration.getCryptoModule()) + throw new Error('File decryption error. Crypto module not configured.'); + if (typeof keyOrFile === 'string') { + if (!this.cryptography) + throw new Error('File decryption error. File decryption not available'); + return this.cryptography.decryptFile(keyOrFile, file, this._configuration.PubNubFile); + } + return (_a = this._configuration.getCryptoModule()) === null || _a === void 0 ? void 0 : _a.decryptFile(file, this._configuration.PubNubFile); + }); + } + } + /** + * {@link ArrayBuffer} to {@link string} decoder. + */ + PubNubCore.decoder = new TextDecoder(); + // -------------------------------------------------------- + // ----------------------- Static ------------------------- + // -------------------------------------------------------- + // region Static + /** + * Type of REST API endpoint which reported status. + */ + PubNubCore.OPERATIONS = RequestOperation$1; + /** + * API call status category. + */ + PubNubCore.CATEGORIES = StatusCategory$1; + /** + * Exponential retry policy constructor. + */ + PubNubCore.ExponentialRetryPolicy = RetryPolicy.ExponentialRetryPolicy; + /** + * Linear retry policy constructor. + */ + PubNubCore.LinearRetryPolicy = RetryPolicy.LinearRetryPolicy; + + /** + * Cbor decoder module. + */ + /** + * CBOR data decoder. + */ + class Cbor { + constructor(decode, base64ToBinary) { + this.decode = decode; + this.base64ToBinary = base64ToBinary; + } + /** + * Decode CBOR base64-encoded object. + * + * @param tokenString - Base64-encoded token. + * + * @returns Token object decoded from CBOR. + */ + decodeToken(tokenString) { + let padding = ''; + if (tokenString.length % 4 === 3) + padding = '='; + else if (tokenString.length % 4 === 2) + padding = '=='; + const cleaned = tokenString.replace(/-/gi, '+').replace(/_/gi, '/') + padding; + const result = this.decode(this.base64ToBinary(cleaned)); + return typeof result === 'object' ? result : undefined; + } + } + + /* eslint no-bitwise: ["error", { "allow": ["~", "&", ">>"] }] */ + /* global navigator */ + /** + * PubNub client for browser platform. + */ + class PubNub extends PubNubCore { + constructor(configuration) { + var _a; + const configurationCopy = setDefaults(configuration); + const platformConfiguration = Object.assign(Object.assign({}, configurationCopy), { sdkFamily: 'Web', PubNubFile }); + // Prepare full client configuration. + const clientConfiguration = makeConfiguration(platformConfiguration, (cryptoConfiguration) => { + if (!cryptoConfiguration.cipherKey) + return undefined; + return new WebCryptoModule({ + default: new LegacyCryptor(Object.assign({}, cryptoConfiguration)), + cryptors: [new AesCbcCryptor({ cipherKey: cryptoConfiguration.cipherKey })], + }); + }); + // Prepare Token manager. + const tokenManager = new TokenManager(new Cbor((arrayBuffer) => stringifyBufferKeys(CborReader.decode(arrayBuffer)), decode)); + // Legacy crypto (legacy data encryption / decryption and request signature support). + let crypto; + if (clientConfiguration.getCipherKey() || clientConfiguration.secretKey) { + crypto = new Crypto({ + secretKey: clientConfiguration.secretKey, + cipherKey: clientConfiguration.getCipherKey(), + useRandomIVs: clientConfiguration.getUseRandomIVs(), + customEncrypt: clientConfiguration.getCustomEncrypt(), + customDecrypt: clientConfiguration.getCustomDecrypt(), + }); + } + // Setup transport provider. + let transport = new WebReactNativeTransport(clientConfiguration.keepAlive, clientConfiguration.logVerbosity); + if (configurationCopy.enableServiceWorker) { + // Inject subscription service worker into transport provider stack. + transport = new SubscriptionServiceWorkerMiddleware({ + clientIdentifier: clientConfiguration._instanceId, + subscriptionKey: clientConfiguration.subscribeKey, + sdkVersion: clientConfiguration.getVersion(), + logVerbosity: clientConfiguration.logVerbosity, + transport, + }); + } + const transportMiddleware = new PubNubMiddleware({ + clientConfiguration, + tokenManager, + transport, + }); + super({ + configuration: clientConfiguration, + transport: transportMiddleware, + cryptography: new WebCryptography(), + tokenManager, + crypto, + }); + if ((_a = configuration.listenToBrowserNetworkEvents) !== null && _a !== void 0 ? _a : true) { + window.addEventListener('offline', () => { + this.networkDownDetected(); + }); + window.addEventListener('online', () => { + this.networkUpDetected(); + }); + } + } + networkDownDetected() { + this.listenerManager.announceNetworkDown(); + if (this._configuration.restore) + this.disconnect(); + else + this.destroy(true); + } + networkUpDetected() { + this.listenerManager.announceNetworkUp(); + this.reconnect(); + } + } + /** + * Data encryption / decryption module constructor. + */ + PubNub.CryptoModule = WebCryptoModule; + + return PubNub; })); diff --git a/dist/web/pubnub.min.js b/dist/web/pubnub.min.js index 9efac6f66..4e1a1a155 100644 --- a/dist/web/pubnub.min.js +++ b/dist/web/pubnub.min.js @@ -1,17 +1,2 @@ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).PubNub=t()}(this,(function(){"use strict"; -/*! ***************************************************************************** - 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. - ***************************************************************************** */var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])},e(t,n)};function t(t,n){if("function"!=typeof n&&null!==n)throw new TypeError("Class extends value "+String(n)+" is not a constructor or null");function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}var n=function(){return n=Object.assign||function(e){for(var t,n=1,r=arguments.length;n0&&o[o.length-1])||6!==i[0]&&2!==i[0])){s=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]=e.length&&(e=void 0),{value:e&&e[r++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function a(e,t){var n="function"==typeof Symbol&&e[Symbol.iterator];if(!n)return e;var r,o,i=n.call(e),s=[];try{for(;(void 0===t||t-- >0)&&!(r=i.next()).done;)s.push(r.value)}catch(e){o={error:e}}finally{try{r&&!r.done&&(n=i.return)&&n.call(i)}finally{if(o)throw o.error}}return s}function u(e,t,n){if(n||2===arguments.length)for(var r,o=0,i=t.length;o>2,c=0;c>6),o.push(128|63&s)):s<55296?(o.push(224|s>>12),o.push(128|s>>6&63),o.push(128|63&s)):(s=(1023&s)<<10,s|=1023&t.charCodeAt(++r),s+=65536,o.push(240|s>>18),o.push(128|s>>12&63),o.push(128|s>>6&63),o.push(128|63&s))}return h(3,o.length),p(o);default:var f;if(Array.isArray(t))for(h(4,f=t.length),r=0;r>5!==e)throw"Invalid indefinite length element";return n}function g(e,t){for(var n=0;n>10),e.push(56320|1023&r))}}"function"!=typeof t&&(t=function(e){return e}),"function"!=typeof i&&(i=function(){return n});var m=function e(){var o,h,m=l(),b=m>>5,v=31&m;if(7===b)switch(v){case 25:return function(){var e=new ArrayBuffer(4),t=new DataView(e),n=p(),o=32768&n,i=31744&n,s=1023&n;if(31744===i)i=261120;else if(0!==i)i+=114688;else if(0!==s)return s*r;return t.setUint32(0,o<<16|i<<13|s<<13),t.getFloat32(0)}();case 26:return u(s.getFloat32(a),4);case 27:return u(s.getFloat64(a),8)}if((h=d(v))<0&&(b<2||6=0;)S+=h,_.push(c(h));var w=new Uint8Array(S),O=0;for(o=0;o<_.length;++o)w.set(_[o],O),O+=_[o].length;return w}return c(h);case 3:var P=[];if(h<0)for(;(h=y(b))>=0;)g(P,h);else g(P,h);return String.fromCharCode.apply(null,P);case 4:var E;if(h<0)for(E=[];!f();)E.push(e());else for(E=new Array(h),o=0;o=20?this._presenceTimeout=e:(this._presenceTimeout=20,console.log("WARNING: Presence timeout is less than the minimum. Using minimum value: ",this._presenceTimeout)),this.setHeartbeatInterval(this._presenceTimeout/2-1),this},e.prototype.setProxy=function(e){this.proxy=e},e.prototype.getHeartbeatInterval=function(){return this._heartbeatInterval},e.prototype.setHeartbeatInterval=function(e){return this._heartbeatInterval=e,this},e.prototype.getSubscribeTimeout=function(){return this._subscribeRequestTimeout},e.prototype.setSubscribeTimeout=function(e){return this._subscribeRequestTimeout=e,this},e.prototype.getTransactionTimeout=function(){return this._transactionalRequestTimeout},e.prototype.setTransactionTimeout=function(e){return this._transactionalRequestTimeout=e,this},e.prototype.isSendBeaconEnabled=function(){return this._useSendBeacon},e.prototype.setSendBeaconConfig=function(e){return this._useSendBeacon=e,this},e.prototype.getVersion=function(){return"7.6.3"},e.prototype._setRetryConfiguration=function(e){if(e.minimumdelay<2)throw new Error("Minimum delay can not be set less than 2 seconds for retry");if(e.maximumDelay>150)throw new Error("Maximum delay can not be set more than 150 seconds for retry");if(e.maximumDelay&&maximumRetry>6)throw new Error("Maximum retry for exponential retry policy can not be more than 6");if(e.maximumRetry>10)throw new Error("Maximum retry for linear retry policy can not be more than 10");this.retryConfiguration=e},e.prototype._addPnsdkSuffix=function(e,t){this._PNSDKSuffix[e]=t},e.prototype._getPnsdkSuffix=function(e){var t=this;return Object.keys(this._PNSDKSuffix).reduce((function(n,r){return n+e+t._PNSDKSuffix[r]}),"")},e}();function m(e){var t=e.replace(/==?$/,""),n=Math.floor(t.length/4*3),r=new ArrayBuffer(n),o=new Uint8Array(r),i=0;function s(){var e=t.charAt(i++),n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(e);if(-1===n)throw new Error("Illegal character at ".concat(i,": ").concat(t.charAt(i-1)));return n}for(var a=0;a>4,f=(15&c)<<4|l>>2,d=(3&l)<<6|p>>0;o[a]=h,64!=l&&(o[a+1]=f),64!=p&&(o[a+2]=d)}return r}function b(e){for(var t,n="",r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",o=new Uint8Array(e),i=o.byteLength,s=i%3,a=i-s,u=0;u>18]+r[(258048&t)>>12]+r[(4032&t)>>6]+r[63&t];return 1==s?n+=r[(252&(t=o[a]))>>2]+r[(3&t)<<4]+"==":2==s&&(n+=r[(64512&(t=o[a]<<8|o[a+1]))>>10]+r[(1008&t)>>4]+r[(15&t)<<2]+"="),n}var v,_,S,w,O,P=P||function(e,t){var n={},r=n.lib={},o=function(){},i=r.Base={extend:function(e){o.prototype=this;var t=new o;return e&&t.mixIn(e),t.hasOwnProperty("init")||(t.init=function(){t.$super.init.apply(this,arguments)}),t.init.prototype=t,t.$super=this,t},create:function(){var e=this.extend();return e.init.apply(e,arguments),e},init:function(){},mixIn:function(e){for(var t in e)e.hasOwnProperty(t)&&(this[t]=e[t]);e.hasOwnProperty("toString")&&(this.toString=e.toString)},clone:function(){return this.init.prototype.extend(this)}},s=r.WordArray=i.extend({init:function(e,t){e=this.words=e||[],this.sigBytes=null!=t?t:4*e.length},toString:function(e){return(e||u).stringify(this)},concat:function(e){var t=this.words,n=e.words,r=this.sigBytes;if(e=e.sigBytes,this.clamp(),r%4)for(var o=0;o>>2]|=(n[o>>>2]>>>24-o%4*8&255)<<24-(r+o)%4*8;else if(65535>>2]=n[o>>>2];else t.push.apply(t,n);return this.sigBytes+=e,this},clamp:function(){var t=this.words,n=this.sigBytes;t[n>>>2]&=4294967295<<32-n%4*8,t.length=e.ceil(n/4)},clone:function(){var e=i.clone.call(this);return e.words=this.words.slice(0),e},random:function(t){for(var n=[],r=0;r>>2]>>>24-r%4*8&255;n.push((o>>>4).toString(16)),n.push((15&o).toString(16))}return n.join("")},parse:function(e){for(var t=e.length,n=[],r=0;r>>3]|=parseInt(e.substr(r,2),16)<<24-r%8*4;return new s.init(n,t/2)}},c=a.Latin1={stringify:function(e){var t=e.words;e=e.sigBytes;for(var n=[],r=0;r>>2]>>>24-r%4*8&255));return n.join("")},parse:function(e){for(var t=e.length,n=[],r=0;r>>2]|=(255&e.charCodeAt(r))<<24-r%4*8;return new s.init(n,t)}},l=a.Utf8={stringify:function(e){try{return decodeURIComponent(escape(c.stringify(e)))}catch(e){throw Error("Malformed UTF-8 data")}},parse:function(e){return c.parse(unescape(encodeURIComponent(e)))}},p=r.BufferedBlockAlgorithm=i.extend({reset:function(){this._data=new s.init,this._nDataBytes=0},_append:function(e){"string"==typeof e&&(e=l.parse(e)),this._data.concat(e),this._nDataBytes+=e.sigBytes},_process:function(t){var n=this._data,r=n.words,o=n.sigBytes,i=this.blockSize,a=o/(4*i);if(t=(a=t?e.ceil(a):e.max((0|a)-this._minBufferSize,0))*i,o=e.min(4*t,o),t){for(var u=0;uc;){var l;e:{l=u;for(var p=e.sqrt(l),h=2;h<=p;h++)if(!(l%h)){l=!1;break e}l=!0}l&&(8>c&&(i[c]=a(e.pow(u,.5))),s[c]=a(e.pow(u,1/3)),c++),u++}var f=[];o=o.SHA256=r.extend({_doReset:function(){this._hash=new n.init(i.slice(0))},_doProcessBlock:function(e,t){for(var n=this._hash.words,r=n[0],o=n[1],i=n[2],a=n[3],u=n[4],c=n[5],l=n[6],p=n[7],h=0;64>h;h++){if(16>h)f[h]=0|e[t+h];else{var d=f[h-15],y=f[h-2];f[h]=((d<<25|d>>>7)^(d<<14|d>>>18)^d>>>3)+f[h-7]+((y<<15|y>>>17)^(y<<13|y>>>19)^y>>>10)+f[h-16]}d=p+((u<<26|u>>>6)^(u<<21|u>>>11)^(u<<7|u>>>25))+(u&c^~u&l)+s[h]+f[h],y=((r<<30|r>>>2)^(r<<19|r>>>13)^(r<<10|r>>>22))+(r&o^r&i^o&i),p=l,l=c,c=u,u=a+d|0,a=i,i=o,o=r,r=d+y|0}n[0]=n[0]+r|0,n[1]=n[1]+o|0,n[2]=n[2]+i|0,n[3]=n[3]+a|0,n[4]=n[4]+u|0,n[5]=n[5]+c|0,n[6]=n[6]+l|0,n[7]=n[7]+p|0},_doFinalize:function(){var t=this._data,n=t.words,r=8*this._nDataBytes,o=8*t.sigBytes;return n[o>>>5]|=128<<24-o%32,n[14+(o+64>>>9<<4)]=e.floor(r/4294967296),n[15+(o+64>>>9<<4)]=r,t.sigBytes=4*n.length,this._process(),this._hash},clone:function(){var e=r.clone.call(this);return e._hash=this._hash.clone(),e}});t.SHA256=r._createHelper(o),t.HmacSHA256=r._createHmacHelper(o)}(Math),_=(v=P).enc.Utf8,v.algo.HMAC=v.lib.Base.extend({init:function(e,t){e=this._hasher=new e.init,"string"==typeof t&&(t=_.parse(t));var n=e.blockSize,r=4*n;t.sigBytes>r&&(t=e.finalize(t)),t.clamp();for(var o=this._oKey=t.clone(),i=this._iKey=t.clone(),s=o.words,a=i.words,u=0;u>>2]>>>24-o%4*8&255)<<16|(t[o+1>>>2]>>>24-(o+1)%4*8&255)<<8|t[o+2>>>2]>>>24-(o+2)%4*8&255,s=0;4>s&&o+.75*s>>6*(3-s)&63));if(t=r.charAt(64))for(;e.length%4;)e.push(t);return e.join("")},parse:function(e){var t=e.length,n=this._map;(r=n.charAt(64))&&-1!=(r=e.indexOf(r))&&(t=r);for(var r=[],o=0,i=0;i>>6-i%4*2;r[o>>>2]|=(s|a)<<24-o%4*8,o++}return w.create(r,o)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="},function(e){function t(e,t,n,r,o,i,s){return((e=e+(t&n|~t&r)+o+s)<>>32-i)+t}function n(e,t,n,r,o,i,s){return((e=e+(t&r|n&~r)+o+s)<>>32-i)+t}function r(e,t,n,r,o,i,s){return((e=e+(t^n^r)+o+s)<>>32-i)+t}function o(e,t,n,r,o,i,s){return((e=e+(n^(t|~r))+o+s)<>>32-i)+t}for(var i=P,s=(u=i.lib).WordArray,a=u.Hasher,u=i.algo,c=[],l=0;64>l;l++)c[l]=4294967296*e.abs(e.sin(l+1))|0;u=u.MD5=a.extend({_doReset:function(){this._hash=new s.init([1732584193,4023233417,2562383102,271733878])},_doProcessBlock:function(e,i){for(var s=0;16>s;s++){var a=e[u=i+s];e[u]=16711935&(a<<8|a>>>24)|4278255360&(a<<24|a>>>8)}s=this._hash.words;var u=e[i+0],l=(a=e[i+1],e[i+2]),p=e[i+3],h=e[i+4],f=e[i+5],d=e[i+6],y=e[i+7],g=e[i+8],m=e[i+9],b=e[i+10],v=e[i+11],_=e[i+12],S=e[i+13],w=e[i+14],O=e[i+15],P=t(P=s[0],T=s[1],A=s[2],E=s[3],u,7,c[0]),E=t(E,P,T,A,a,12,c[1]),A=t(A,E,P,T,l,17,c[2]),T=t(T,A,E,P,p,22,c[3]);P=t(P,T,A,E,h,7,c[4]),E=t(E,P,T,A,f,12,c[5]),A=t(A,E,P,T,d,17,c[6]),T=t(T,A,E,P,y,22,c[7]),P=t(P,T,A,E,g,7,c[8]),E=t(E,P,T,A,m,12,c[9]),A=t(A,E,P,T,b,17,c[10]),T=t(T,A,E,P,v,22,c[11]),P=t(P,T,A,E,_,7,c[12]),E=t(E,P,T,A,S,12,c[13]),A=t(A,E,P,T,w,17,c[14]),P=n(P,T=t(T,A,E,P,O,22,c[15]),A,E,a,5,c[16]),E=n(E,P,T,A,d,9,c[17]),A=n(A,E,P,T,v,14,c[18]),T=n(T,A,E,P,u,20,c[19]),P=n(P,T,A,E,f,5,c[20]),E=n(E,P,T,A,b,9,c[21]),A=n(A,E,P,T,O,14,c[22]),T=n(T,A,E,P,h,20,c[23]),P=n(P,T,A,E,m,5,c[24]),E=n(E,P,T,A,w,9,c[25]),A=n(A,E,P,T,p,14,c[26]),T=n(T,A,E,P,g,20,c[27]),P=n(P,T,A,E,S,5,c[28]),E=n(E,P,T,A,l,9,c[29]),A=n(A,E,P,T,y,14,c[30]),P=r(P,T=n(T,A,E,P,_,20,c[31]),A,E,f,4,c[32]),E=r(E,P,T,A,g,11,c[33]),A=r(A,E,P,T,v,16,c[34]),T=r(T,A,E,P,w,23,c[35]),P=r(P,T,A,E,a,4,c[36]),E=r(E,P,T,A,h,11,c[37]),A=r(A,E,P,T,y,16,c[38]),T=r(T,A,E,P,b,23,c[39]),P=r(P,T,A,E,S,4,c[40]),E=r(E,P,T,A,u,11,c[41]),A=r(A,E,P,T,p,16,c[42]),T=r(T,A,E,P,d,23,c[43]),P=r(P,T,A,E,m,4,c[44]),E=r(E,P,T,A,_,11,c[45]),A=r(A,E,P,T,O,16,c[46]),P=o(P,T=r(T,A,E,P,l,23,c[47]),A,E,u,6,c[48]),E=o(E,P,T,A,y,10,c[49]),A=o(A,E,P,T,w,15,c[50]),T=o(T,A,E,P,f,21,c[51]),P=o(P,T,A,E,_,6,c[52]),E=o(E,P,T,A,p,10,c[53]),A=o(A,E,P,T,b,15,c[54]),T=o(T,A,E,P,a,21,c[55]),P=o(P,T,A,E,g,6,c[56]),E=o(E,P,T,A,O,10,c[57]),A=o(A,E,P,T,d,15,c[58]),T=o(T,A,E,P,S,21,c[59]),P=o(P,T,A,E,h,6,c[60]),E=o(E,P,T,A,v,10,c[61]),A=o(A,E,P,T,l,15,c[62]),T=o(T,A,E,P,m,21,c[63]);s[0]=s[0]+P|0,s[1]=s[1]+T|0,s[2]=s[2]+A|0,s[3]=s[3]+E|0},_doFinalize:function(){var t=this._data,n=t.words,r=8*this._nDataBytes,o=8*t.sigBytes;n[o>>>5]|=128<<24-o%32;var i=e.floor(r/4294967296);for(n[15+(o+64>>>9<<4)]=16711935&(i<<8|i>>>24)|4278255360&(i<<24|i>>>8),n[14+(o+64>>>9<<4)]=16711935&(r<<8|r>>>24)|4278255360&(r<<24|r>>>8),t.sigBytes=4*(n.length+1),this._process(),n=(t=this._hash).words,r=0;4>r;r++)o=n[r],n[r]=16711935&(o<<8|o>>>24)|4278255360&(o<<24|o>>>8);return t},clone:function(){var e=a.clone.call(this);return e._hash=this._hash.clone(),e}}),i.MD5=a._createHelper(u),i.HmacMD5=a._createHmacHelper(u)}(Math),function(){var e,t=P,n=(e=t.lib).Base,r=e.WordArray,o=(e=t.algo).EvpKDF=n.extend({cfg:n.extend({keySize:4,hasher:e.MD5,iterations:1}),init:function(e){this.cfg=this.cfg.extend(e)},compute:function(e,t){for(var n=(a=this.cfg).hasher.create(),o=r.create(),i=o.words,s=a.keySize,a=a.iterations;i.length>>2]}},t.BlockCipher=a.extend({cfg:a.cfg.extend({mode:u,padding:l}),reset:function(){a.reset.call(this);var e=(t=this.cfg).iv,t=t.mode;if(this._xformMode==this._ENC_XFORM_MODE)var n=t.createEncryptor;else n=t.createDecryptor,this._minBufferSize=1;this._mode=n.call(t,this,e&&e.words)},_doProcessBlock:function(e,t){this._mode.processBlock(e,t)},_doFinalize:function(){var e=this.cfg.padding;if(this._xformMode==this._ENC_XFORM_MODE){e.pad(this._data,this.blockSize);var t=this._process(!0)}else t=this._process(!0),e.unpad(t);return t},blockSize:4});var p=t.CipherParams=n.extend({init:function(e){this.mixIn(e)},toString:function(e){return(e||this.formatter).stringify(this)}}),h=(u=(f.format={}).OpenSSL={stringify:function(e){var t=e.ciphertext;return((e=e.salt)?r.create([1398893684,1701076831]).concat(e).concat(t):t).toString(i)},parse:function(e){var t=(e=i.parse(e)).words;if(1398893684==t[0]&&1701076831==t[1]){var n=r.create(t.slice(2,4));t.splice(0,4),e.sigBytes-=16}return p.create({ciphertext:e,salt:n})}},t.SerializableCipher=n.extend({cfg:n.extend({format:u}),encrypt:function(e,t,n,r){r=this.cfg.extend(r);var o=e.createEncryptor(n,r);return t=o.finalize(t),o=o.cfg,p.create({ciphertext:t,key:n,iv:o.iv,algorithm:e,mode:o.mode,padding:o.padding,blockSize:e.blockSize,formatter:r.format})},decrypt:function(e,t,n,r){return r=this.cfg.extend(r),t=this._parse(t,r.format),e.createDecryptor(n,r).finalize(t.ciphertext)},_parse:function(e,t){return"string"==typeof e?t.parse(e,this):e}})),f=(f.kdf={}).OpenSSL={execute:function(e,t,n,o){return o||(o=r.random(8)),e=s.create({keySize:t+n}).compute(e,o),n=r.create(e.words.slice(t),4*n),e.sigBytes=4*t,p.create({key:e,iv:n,salt:o})}},d=t.PasswordBasedCipher=h.extend({cfg:h.cfg.extend({kdf:f}),encrypt:function(e,t,n,r){return n=(r=this.cfg.extend(r)).kdf.execute(n,e.keySize,e.ivSize),r.iv=n.iv,(e=h.encrypt.call(this,e,t,n.key,r)).mixIn(n),e},decrypt:function(e,t,n,r){return r=this.cfg.extend(r),t=this._parse(t,r.format),n=r.kdf.execute(n,e.keySize,e.ivSize,t.salt),r.iv=n.iv,h.decrypt.call(this,e,t,n.key,r)}})}(),function(){for(var e=P,t=e.lib.BlockCipher,n=e.algo,r=[],o=[],i=[],s=[],a=[],u=[],c=[],l=[],p=[],h=[],f=[],d=0;256>d;d++)f[d]=128>d?d<<1:d<<1^283;var y=0,g=0;for(d=0;256>d;d++){var m=(m=g^g<<1^g<<2^g<<3^g<<4)>>>8^255&m^99;r[y]=m,o[m]=y;var b=f[y],v=f[b],_=f[v],S=257*f[m]^16843008*m;i[y]=S<<24|S>>>8,s[y]=S<<16|S>>>16,a[y]=S<<8|S>>>24,u[y]=S,S=16843009*_^65537*v^257*b^16843008*y,c[m]=S<<24|S>>>8,l[m]=S<<16|S>>>16,p[m]=S<<8|S>>>24,h[m]=S,y?(y=b^f[f[f[_^b]]],g^=f[f[g]]):y=g=1}var w=[0,1,2,4,8,16,32,64,128,27,54];n=n.AES=t.extend({_doReset:function(){for(var e=(n=this._key).words,t=n.sigBytes/4,n=4*((this._nRounds=t+6)+1),o=this._keySchedule=[],i=0;i>>24]<<24|r[s>>>16&255]<<16|r[s>>>8&255]<<8|r[255&s]):(s=r[(s=s<<8|s>>>24)>>>24]<<24|r[s>>>16&255]<<16|r[s>>>8&255]<<8|r[255&s],s^=w[i/t|0]<<24),o[i]=o[i-t]^s}for(e=this._invKeySchedule=[],t=0;tt||4>=i?s:c[r[s>>>24]]^l[r[s>>>16&255]]^p[r[s>>>8&255]]^h[r[255&s]]},encryptBlock:function(e,t){this._doCryptBlock(e,t,this._keySchedule,i,s,a,u,r)},decryptBlock:function(e,t){var n=e[t+1];e[t+1]=e[t+3],e[t+3]=n,this._doCryptBlock(e,t,this._invKeySchedule,c,l,p,h,o),n=e[t+1],e[t+1]=e[t+3],e[t+3]=n},_doCryptBlock:function(e,t,n,r,o,i,s,a){for(var u=this._nRounds,c=e[t]^n[0],l=e[t+1]^n[1],p=e[t+2]^n[2],h=e[t+3]^n[3],f=4,d=1;d>>24]^o[l>>>16&255]^i[p>>>8&255]^s[255&h]^n[f++],g=r[l>>>24]^o[p>>>16&255]^i[h>>>8&255]^s[255&c]^n[f++],m=r[p>>>24]^o[h>>>16&255]^i[c>>>8&255]^s[255&l]^n[f++];h=r[h>>>24]^o[c>>>16&255]^i[l>>>8&255]^s[255&p]^n[f++],c=y,l=g,p=m}y=(a[c>>>24]<<24|a[l>>>16&255]<<16|a[p>>>8&255]<<8|a[255&h])^n[f++],g=(a[l>>>24]<<24|a[p>>>16&255]<<16|a[h>>>8&255]<<8|a[255&c])^n[f++],m=(a[p>>>24]<<24|a[h>>>16&255]<<16|a[c>>>8&255]<<8|a[255&l])^n[f++],h=(a[h>>>24]<<24|a[c>>>16&255]<<16|a[l>>>8&255]<<8|a[255&p])^n[f++],e[t]=y,e[t+1]=g,e[t+2]=m,e[t+3]=h},keySize:8});e.AES=t._createHelper(n)}(),P.mode.ECB=((O=P.lib.BlockCipherMode.extend()).Encryptor=O.extend({processBlock:function(e,t){this._cipher.encryptBlock(e,t)}}),O.Decryptor=O.extend({processBlock:function(e,t){this._cipher.decryptBlock(e,t)}}),O);var E=P;function A(e){var t,n=[];for(t=0;t=this._config.maximumCacheSize&&this.hashHistory.shift(),this.hashHistory.push(this.getKey(e))},e.prototype.clearHistory=function(){this.hashHistory=[]},e}(),k={PNNetworkUpCategory:"PNNetworkUpCategory",PNNetworkDownCategory:"PNNetworkDownCategory",PNNetworkIssuesCategory:"PNNetworkIssuesCategory",PNTimeoutCategory:"PNTimeoutCategory",PNBadRequestCategory:"PNBadRequestCategory",PNAccessDeniedCategory:"PNAccessDeniedCategory",PNUnknownCategory:"PNUnknownCategory",PNReconnectedCategory:"PNReconnectedCategory",PNConnectedCategory:"PNConnectedCategory",PNRequestMessageCountExceededCategory:"PNRequestMessageCountExceededCategory",PNDisconnectedCategory:"PNDisconnectedCategory",PNConnectionErrorCategory:"PNConnectionErrorCategory",PNDisconnectedUnexpectedlyCategory:"PNDisconnectedUnexpectedlyCategory"},M=function(){function e(e){var t=e.subscribeEndpoint,n=e.leaveEndpoint,r=e.heartbeatEndpoint,o=e.setStateEndpoint,i=e.timeEndpoint,s=e.getFileUrl,a=e.config,u=e.crypto,c=e.listenerManager,l=e.cryptoModule,p=e.eventEmitter;this._listenerManager=c,this._config=a,this._leaveEndpoint=n,this._heartbeatEndpoint=r,this._setStateEndpoint=o,this._subscribeEndpoint=t,this._getFileUrl=s,this._crypto=u,this._cryptoModule=l,this._channels={},this._presenceChannels={},this._heartbeatChannels={},this._heartbeatChannelGroups={},this._channelGroups={},this._presenceChannelGroups={},this._pendingChannelSubscriptions=[],this._pendingChannelGroupSubscriptions=[],this._currentTimetoken=0,this._lastTimetoken=0,this._storedTimetoken=null,this._subscriptionStatusAnnounced=!1,this._isOnline=!0,this._reconnectionManager=new N({timeEndpoint:i}),this._dedupingManager=new C({config:a}),this._cryptoModule&&(this._decoder=new TextDecoder),this._eventEmitter=p}return e.prototype.adaptStateChange=function(e,t){var n=this,r=e.state,o=e.channels,i=void 0===o?[]:o,s=e.channelGroups,a=void 0===s?[]:s,u=e.withHeartbeat,c=void 0!==u&&u;if(i.forEach((function(e){e in n._channels&&(n._channels[e].state=r)})),a.forEach((function(e){e in n._channelGroups&&(n._channelGroups[e].state=r)})),c){var l={};return i.forEach((function(e){return l[e]=r})),a.forEach((function(e){return l[e]=r})),this._heartbeatEndpoint({channels:i,channelGroups:a,state:l},t)}return this._setStateEndpoint({state:r,channels:i,channelGroups:a},t)},e.prototype.adaptPresenceChange=function(e){var t=this,n=e.connected,r=e.channels,o=void 0===r?[]:r,i=e.channelGroups,s=void 0===i?[]:i;n?(o.forEach((function(e){t._heartbeatChannels[e]={state:{}}})),s.forEach((function(e){t._heartbeatChannelGroups[e]={state:{}}}))):(o.forEach((function(e){e in t._heartbeatChannels&&delete t._heartbeatChannels[e]})),s.forEach((function(e){e in t._heartbeatChannelGroups&&delete t._heartbeatChannelGroups[e]})),!1===this._config.suppressLeaveEvents&&this._leaveEndpoint({channels:o,channelGroups:s},(function(e){t._listenerManager.announceStatus(e)}))),this.reconnect()},e.prototype.adaptSubscribeChange=function(e){var t=this,n=e.timetoken,r=e.channels,o=void 0===r?[]:r,i=e.channelGroups,s=void 0===i?[]:i,a=e.withPresence,u=void 0!==a&&a,c=e.withHeartbeats,l=void 0!==c&&c;this._config.subscribeKey&&""!==this._config.subscribeKey?(n&&(this._lastTimetoken=this._currentTimetoken,this._currentTimetoken=n),"0"!==this._currentTimetoken&&0!==this._currentTimetoken&&(this._storedTimetoken=this._currentTimetoken,this._currentTimetoken=0),o.forEach((function(e){t._channels[e]={state:{}},u&&(t._presenceChannels[e]={}),(l||t._config.getHeartbeatInterval())&&(t._heartbeatChannels[e]={}),t._pendingChannelSubscriptions.push(e)})),s.forEach((function(e){t._channelGroups[e]={state:{}},u&&(t._presenceChannelGroups[e]={}),(l||t._config.getHeartbeatInterval())&&(t._heartbeatChannelGroups[e]={}),t._pendingChannelGroupSubscriptions.push(e)})),this._subscriptionStatusAnnounced=!1,this.reconnect()):console&&console.log&&console.log("subscribe key missing; aborting subscribe")},e.prototype.adaptUnsubscribeChange=function(e,t){var n=this,r=e.channels,o=void 0===r?[]:r,i=e.channelGroups,s=void 0===i?[]:i,a=[],u=[];o.forEach((function(e){e in n._channels&&(delete n._channels[e],a.push(e),e in n._heartbeatChannels&&delete n._heartbeatChannels[e]),e in n._presenceChannels&&(delete n._presenceChannels[e],a.push(e))})),s.forEach((function(e){e in n._channelGroups&&(delete n._channelGroups[e],u.push(e),e in n._heartbeatChannelGroups&&delete n._heartbeatChannelGroups[e]),e in n._presenceChannelGroups&&(delete n._presenceChannelGroups[e],u.push(e))})),0===a.length&&0===u.length||(!1!==this._config.suppressLeaveEvents||t||this._leaveEndpoint({channels:a,channelGroups:u},(function(e){e.affectedChannels=a,e.affectedChannelGroups=u,e.currentTimetoken=n._currentTimetoken,e.lastTimetoken=n._lastTimetoken,n._listenerManager.announceStatus(e)})),0===Object.keys(this._channels).length&&0===Object.keys(this._presenceChannels).length&&0===Object.keys(this._channelGroups).length&&0===Object.keys(this._presenceChannelGroups).length&&(this._lastTimetoken=0,this._currentTimetoken=0,this._storedTimetoken=null,this._region=null,this._reconnectionManager.stopPolling()),this.reconnect())},e.prototype.unsubscribeAll=function(e){this.adaptUnsubscribeChange({channels:this.getSubscribedChannels(),channelGroups:this.getSubscribedChannelGroups()},e)},e.prototype.getHeartbeatChannels=function(){return Object.keys(this._heartbeatChannels)},e.prototype.getHeartbeatChannelGroups=function(){return Object.keys(this._heartbeatChannelGroups)},e.prototype.getSubscribedChannels=function(){return Object.keys(this._channels)},e.prototype.getSubscribedChannelGroups=function(){return Object.keys(this._channelGroups)},e.prototype.reconnect=function(){this._startSubscribeLoop(),this._registerHeartbeatTimer()},e.prototype.disconnect=function(){this._stopSubscribeLoop(),this._stopHeartbeatTimer(),this._reconnectionManager.stopPolling()},e.prototype._registerHeartbeatTimer=function(){this._stopHeartbeatTimer(),0!==this._config.getHeartbeatInterval()&&void 0!==this._config.getHeartbeatInterval()&&(this._performHeartbeatLoop(),this._heartbeatTimer=setInterval(this._performHeartbeatLoop.bind(this),1e3*this._config.getHeartbeatInterval()))},e.prototype._stopHeartbeatTimer=function(){this._heartbeatTimer&&(clearInterval(this._heartbeatTimer),this._heartbeatTimer=null)},e.prototype._performHeartbeatLoop=function(){var e=this,t=this.getHeartbeatChannels(),n=this.getHeartbeatChannelGroups(),r={};if(0!==t.length||0!==n.length){this.getSubscribedChannels().forEach((function(t){var n=e._channels[t].state;Object.keys(n).length&&(r[t]=n)})),this.getSubscribedChannelGroups().forEach((function(t){var n=e._channelGroups[t].state;Object.keys(n).length&&(r[t]=n)}));this._heartbeatEndpoint({channels:t,channelGroups:n,state:r},function(t){t.error&&e._config.announceFailedHeartbeats&&e._listenerManager.announceStatus(t),t.error&&e._config.autoNetworkDetection&&e._isOnline&&(e._isOnline=!1,e.disconnect(),e._listenerManager.announceNetworkDown(),e.reconnect()),!t.error&&e._config.announceSuccessfulHeartbeats&&e._listenerManager.announceStatus(t)}.bind(this))}},e.prototype._startSubscribeLoop=function(){var e=this;this._stopSubscribeLoop();var t={},n=[],r=[];if(Object.keys(this._channels).forEach((function(r){var o=e._channels[r].state;Object.keys(o).length&&(t[r]=o),n.push(r)})),Object.keys(this._presenceChannels).forEach((function(e){n.push("".concat(e,"-pnpres"))})),Object.keys(this._channelGroups).forEach((function(n){var o=e._channelGroups[n].state;Object.keys(o).length&&(t[n]=o),r.push(n)})),Object.keys(this._presenceChannelGroups).forEach((function(e){r.push("".concat(e,"-pnpres"))})),0!==n.length||0!==r.length){var o={channels:n,channelGroups:r,state:t,timetoken:this._currentTimetoken,filterExpression:this._config.filterExpression,region:this._region};this._subscribeCall=this._subscribeEndpoint(o,this._processSubscribeResponse.bind(this))}},e.prototype._processSubscribeResponse=function(e,t){var n=this;if(e.error){if(e.errorData&&"Aborted"===e.errorData.message)return;e.category===k.PNTimeoutCategory?this._startSubscribeLoop():e.category===k.PNNetworkIssuesCategory?(this.disconnect(),e.error&&this._config.autoNetworkDetection&&this._isOnline&&(this._isOnline=!1,this._listenerManager.announceNetworkDown()),this._reconnectionManager.onReconnection((function(){n._config.autoNetworkDetection&&!n._isOnline&&(n._isOnline=!0,n._listenerManager.announceNetworkUp()),n.reconnect(),n._subscriptionStatusAnnounced=!0;var t={category:k.PNReconnectedCategory,operation:e.operation,lastTimetoken:n._lastTimetoken,currentTimetoken:n._currentTimetoken};n._listenerManager.announceStatus(t)})),this._reconnectionManager.startPolling(),this._listenerManager.announceStatus(e)):e.category===k.PNBadRequestCategory?(this._stopHeartbeatTimer(),this._listenerManager.announceStatus(e)):this._listenerManager.announceStatus(e)}else{if(this._storedTimetoken?(this._currentTimetoken=this._storedTimetoken,this._storedTimetoken=null):(this._lastTimetoken=this._currentTimetoken,this._currentTimetoken=t.metadata.timetoken),!this._subscriptionStatusAnnounced){var r={};r.category=k.PNConnectedCategory,r.operation=e.operation,r.affectedChannels=this._pendingChannelSubscriptions,r.subscribedChannels=this.getSubscribedChannels(),r.affectedChannelGroups=this._pendingChannelGroupSubscriptions,r.lastTimetoken=this._lastTimetoken,r.currentTimetoken=this._currentTimetoken,this._subscriptionStatusAnnounced=!0,this._listenerManager.announceStatus(r),this._pendingChannelSubscriptions=[],this._pendingChannelGroupSubscriptions=[]}var o=t.messages||[],i=this._config,s=i.requestMessageCountThreshold,a=i.dedupeOnSubscribe;if(s&&o.length>=s){var u={};u.category=k.PNRequestMessageCountExceededCategory,u.operation=e.operation,this._listenerManager.announceStatus(u)}o.forEach((function(e){if(e.channel,e.subscriptionMatch,a){if(n._dedupingManager.isDuplicate(e))return;n._dedupingManager.addEntry(e)}n._eventEmitter.emitEvent(e)})),this._region=t.metadata.region,this._startSubscribeLoop()}},e.prototype._stopSubscribeLoop=function(){this._subscribeCall&&("function"==typeof this._subscribeCall.abort&&this._subscribeCall.abort(),this._subscribeCall=null)},e.prototype._renameEvent=function(e){return"set"===e?"updated":"removed"},e.prototype._renameChannelField=function(e){var t=e.channel,n=r(e,["channel"]);return n.spaceId=t,n},e}(),j={PNTimeOperation:"PNTimeOperation",PNHistoryOperation:"PNHistoryOperation",PNDeleteMessagesOperation:"PNDeleteMessagesOperation",PNFetchMessagesOperation:"PNFetchMessagesOperation",PNMessageCounts:"PNMessageCountsOperation",PNSubscribeOperation:"PNSubscribeOperation",PNUnsubscribeOperation:"PNUnsubscribeOperation",PNPublishOperation:"PNPublishOperation",PNSignalOperation:"PNSignalOperation",PNAddMessageActionOperation:"PNAddActionOperation",PNRemoveMessageActionOperation:"PNRemoveMessageActionOperation",PNGetMessageActionsOperation:"PNGetMessageActionsOperation",PNCreateUserOperation:"PNCreateUserOperation",PNUpdateUserOperation:"PNUpdateUserOperation",PNDeleteUserOperation:"PNDeleteUserOperation",PNGetUserOperation:"PNGetUsersOperation",PNGetUsersOperation:"PNGetUsersOperation",PNCreateSpaceOperation:"PNCreateSpaceOperation",PNUpdateSpaceOperation:"PNUpdateSpaceOperation",PNDeleteSpaceOperation:"PNDeleteSpaceOperation",PNGetSpaceOperation:"PNGetSpacesOperation",PNGetSpacesOperation:"PNGetSpacesOperation",PNGetMembersOperation:"PNGetMembersOperation",PNUpdateMembersOperation:"PNUpdateMembersOperation",PNGetMembershipsOperation:"PNGetMembershipsOperation",PNUpdateMembershipsOperation:"PNUpdateMembershipsOperation",PNListFilesOperation:"PNListFilesOperation",PNGenerateUploadUrlOperation:"PNGenerateUploadUrlOperation",PNPublishFileOperation:"PNPublishFileOperation",PNGetFileUrlOperation:"PNGetFileUrlOperation",PNDownloadFileOperation:"PNDownloadFileOperation",PNGetAllUUIDMetadataOperation:"PNGetAllUUIDMetadataOperation",PNGetUUIDMetadataOperation:"PNGetUUIDMetadataOperation",PNSetUUIDMetadataOperation:"PNSetUUIDMetadataOperation",PNRemoveUUIDMetadataOperation:"PNRemoveUUIDMetadataOperation",PNGetAllChannelMetadataOperation:"PNGetAllChannelMetadataOperation",PNGetChannelMetadataOperation:"PNGetChannelMetadataOperation",PNSetChannelMetadataOperation:"PNSetChannelMetadataOperation",PNRemoveChannelMetadataOperation:"PNRemoveChannelMetadataOperation",PNSetMembersOperation:"PNSetMembersOperation",PNSetMembershipsOperation:"PNSetMembershipsOperation",PNPushNotificationEnabledChannelsOperation:"PNPushNotificationEnabledChannelsOperation",PNRemoveAllPushNotificationsOperation:"PNRemoveAllPushNotificationsOperation",PNWhereNowOperation:"PNWhereNowOperation",PNSetStateOperation:"PNSetStateOperation",PNHereNowOperation:"PNHereNowOperation",PNGetStateOperation:"PNGetStateOperation",PNHeartbeatOperation:"PNHeartbeatOperation",PNChannelGroupsOperation:"PNChannelGroupsOperation",PNRemoveGroupOperation:"PNRemoveGroupOperation",PNChannelsForGroupOperation:"PNChannelsForGroupOperation",PNAddChannelsToGroupOperation:"PNAddChannelsToGroupOperation",PNRemoveChannelsFromGroupOperation:"PNRemoveChannelsFromGroupOperation",PNAccessManagerGrant:"PNAccessManagerGrant",PNAccessManagerGrantToken:"PNAccessManagerGrantToken",PNAccessManagerAudit:"PNAccessManagerAudit",PNAccessManagerRevokeToken:"PNAccessManagerRevokeToken",PNHandshakeOperation:"PNHandshakeOperation",PNReceiveMessagesOperation:"PNReceiveMessagesOperation"},R=function(){function e(e){this._maximumSamplesCount=100,this._trackedLatencies={},this._latencies={},this._telemetryExcludeOperations=[j.PNSubscribeOperation,j.PNReceiveMessagesOperation,j.PNHandshakeOperation],this._maximumSamplesCount=e.maximumSamplesCount||this._maximumSamplesCount}return e.prototype.operationsLatencyForRequest=function(){var e=this,t={};return Object.keys(this._latencies).forEach((function(n){var r=e._latencies[n],o=e._averageLatency(r);o>0&&(t["l_".concat(n)]=o)})),t},e.prototype.startLatencyMeasure=function(e,t){!this._telemetryExcludeOperations.includes(e)&&t&&(this._trackedLatencies[t]=Date.now())},e.prototype.stopLatencyMeasure=function(e,t){if(!this._telemetryExcludeOperations.includes(e)&&t){var n=this._endpointName(e),r=this._latencies[n],o=this._trackedLatencies[t];r||(this._latencies[n]=[],r=this._latencies[n]),r.push(Date.now()-o),r.length>this._maximumSamplesCount&&r.splice(0,r.length-this._maximumSamplesCount),delete this._trackedLatencies[t]}},e.prototype._averageLatency=function(e){return Math.floor(e.reduce((function(e,t){return e+t}),0)/e.length)},e.prototype._endpointName=function(e){var t=null;switch(e){case j.PNPublishOperation:t="pub";break;case j.PNSignalOperation:t="sig";break;case j.PNHistoryOperation:case j.PNFetchMessagesOperation:case j.PNDeleteMessagesOperation:case j.PNMessageCounts:t="hist";break;case j.PNUnsubscribeOperation:case j.PNWhereNowOperation:case j.PNHereNowOperation:case j.PNHeartbeatOperation:case j.PNSetStateOperation:case j.PNGetStateOperation:t="pres";break;case j.PNAddChannelsToGroupOperation:case j.PNRemoveChannelsFromGroupOperation:case j.PNChannelGroupsOperation:case j.PNRemoveGroupOperation:case j.PNChannelsForGroupOperation:t="cg";break;case j.PNPushNotificationEnabledChannelsOperation:case j.PNRemoveAllPushNotificationsOperation:t="push";break;case j.PNCreateUserOperation:case j.PNUpdateUserOperation:case j.PNDeleteUserOperation:case j.PNGetUserOperation:case j.PNGetUsersOperation:case j.PNCreateSpaceOperation:case j.PNUpdateSpaceOperation:case j.PNDeleteSpaceOperation:case j.PNGetSpaceOperation:case j.PNGetSpacesOperation:case j.PNGetMembersOperation:case j.PNUpdateMembersOperation:case j.PNGetMembershipsOperation:case j.PNUpdateMembershipsOperation:t="obj";break;case j.PNAddMessageActionOperation:case j.PNRemoveMessageActionOperation:case j.PNGetMessageActionsOperation:t="msga";break;case j.PNAccessManagerGrant:case j.PNAccessManagerAudit:t="pam";break;case j.PNAccessManagerGrantToken:case j.PNAccessManagerRevokeToken:t="pamv3";break;default:t="time"}return t},e}(),x=function(){function e(e,t,n){this._payload=e,this._setDefaultPayloadStructure(),this.title=t,this.body=n}return Object.defineProperty(e.prototype,"payload",{get:function(){return this._payload},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"title",{set:function(e){this._title=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"subtitle",{set:function(e){this._subtitle=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"body",{set:function(e){this._body=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"badge",{set:function(e){this._badge=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"sound",{set:function(e){this._sound=e},enumerable:!1,configurable:!0}),e.prototype._setDefaultPayloadStructure=function(){},e.prototype.toObject=function(){return{}},e}(),U=function(e){function r(){return null!==e&&e.apply(this,arguments)||this}return t(r,e),Object.defineProperty(r.prototype,"configurations",{set:function(e){e&&e.length&&(this._configurations=e)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"notification",{get:function(){return this._payload.aps},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"title",{get:function(){return this._title},set:function(e){e&&e.length&&(this._payload.aps.alert.title=e,this._title=e)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"subtitle",{get:function(){return this._subtitle},set:function(e){e&&e.length&&(this._payload.aps.alert.subtitle=e,this._subtitle=e)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"body",{get:function(){return this._body},set:function(e){e&&e.length&&(this._payload.aps.alert.body=e,this._body=e)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"badge",{get:function(){return this._badge},set:function(e){null!=e&&(this._payload.aps.badge=e,this._badge=e)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"sound",{get:function(){return this._sound},set:function(e){e&&e.length&&(this._payload.aps.sound=e,this._sound=e)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"silent",{set:function(e){this._isSilent=e},enumerable:!1,configurable:!0}),r.prototype._setDefaultPayloadStructure=function(){this._payload.aps={alert:{}}},r.prototype.toObject=function(){var e=this,t=n({},this._payload),r=t.aps,o=r.alert;if(this._isSilent&&(r["content-available"]=1),"apns2"===this._apnsPushType){if(!this._configurations||!this._configurations.length)throw new ReferenceError("APNS2 configuration is missing");var i=[];this._configurations.forEach((function(t){i.push(e._objectFromAPNS2Configuration(t))})),i.length&&(t.pn_push=i)}return o&&Object.keys(o).length||delete r.alert,this._isSilent&&(delete r.alert,delete r.badge,delete r.sound,o={}),this._isSilent||Object.keys(o).length?t:null},r.prototype._objectFromAPNS2Configuration=function(e){var t=this;if(!e.targets||!e.targets.length)throw new ReferenceError("At least one APNS2 target should be provided");var n=[];e.targets.forEach((function(e){n.push(t._objectFromAPNSTarget(e))}));var r=e.collapseId,o=e.expirationDate,i={auth_method:"token",targets:n,version:"v2"};return r&&r.length&&(i.collapse_id=r),o&&(i.expiration=o.toISOString()),i},r.prototype._objectFromAPNSTarget=function(e){if(!e.topic||!e.topic.length)throw new TypeError("Target 'topic' undefined.");var t=e.topic,n=e.environment,r=void 0===n?"development":n,o=e.excludedDevices,i=void 0===o?[]:o,s={topic:t,environment:r};return i.length&&(s.excluded_devices=i),s},r}(x),I=function(e){function r(){return null!==e&&e.apply(this,arguments)||this}return t(r,e),Object.defineProperty(r.prototype,"backContent",{get:function(){return this._backContent},set:function(e){e&&e.length&&(this._payload.back_content=e,this._backContent=e)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"backTitle",{get:function(){return this._backTitle},set:function(e){e&&e.length&&(this._payload.back_title=e,this._backTitle=e)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"count",{get:function(){return this._count},set:function(e){null!=e&&(this._payload.count=e,this._count=e)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"title",{get:function(){return this._title},set:function(e){e&&e.length&&(this._payload.title=e,this._title=e)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"type",{get:function(){return this._type},set:function(e){e&&e.length&&(this._payload.type=e,this._type=e)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"subtitle",{get:function(){return this.backTitle},set:function(e){this.backTitle=e},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"body",{get:function(){return this.backContent},set:function(e){this.backContent=e},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"badge",{get:function(){return this.count},set:function(e){this.count=e},enumerable:!1,configurable:!0}),r.prototype.toObject=function(){return Object.keys(this._payload).length?n({},this._payload):null},r}(x),D=function(e){function o(){return null!==e&&e.apply(this,arguments)||this}return t(o,e),Object.defineProperty(o.prototype,"notification",{get:function(){return this._payload.notification},enumerable:!1,configurable:!0}),Object.defineProperty(o.prototype,"data",{get:function(){return this._payload.data},enumerable:!1,configurable:!0}),Object.defineProperty(o.prototype,"title",{get:function(){return this._title},set:function(e){e&&e.length&&(this._payload.notification.title=e,this._title=e)},enumerable:!1,configurable:!0}),Object.defineProperty(o.prototype,"body",{get:function(){return this._body},set:function(e){e&&e.length&&(this._payload.notification.body=e,this._body=e)},enumerable:!1,configurable:!0}),Object.defineProperty(o.prototype,"sound",{get:function(){return this._sound},set:function(e){e&&e.length&&(this._payload.notification.sound=e,this._sound=e)},enumerable:!1,configurable:!0}),Object.defineProperty(o.prototype,"icon",{get:function(){return this._icon},set:function(e){e&&e.length&&(this._payload.notification.icon=e,this._icon=e)},enumerable:!1,configurable:!0}),Object.defineProperty(o.prototype,"tag",{get:function(){return this._tag},set:function(e){e&&e.length&&(this._payload.notification.tag=e,this._tag=e)},enumerable:!1,configurable:!0}),Object.defineProperty(o.prototype,"silent",{set:function(e){this._isSilent=e},enumerable:!1,configurable:!0}),o.prototype._setDefaultPayloadStructure=function(){this._payload.notification={},this._payload.data={}},o.prototype.toObject=function(){var e=n({},this._payload.data),t=null,o={};if(Object.keys(this._payload).length>2){var i=this._payload;i.notification,i.data;var s=r(i,["notification","data"]);e=n(n({},e),s)}return this._isSilent?e.notification=this._payload.notification:t=this._payload.notification,Object.keys(e).length&&(o.data=e),t&&Object.keys(t).length&&(o.notification=t),Object.keys(o).length?o:null},o}(x),F=function(){function e(e,t){this._payload={apns:{},mpns:{},fcm:{}},this._title=e,this._body=t,this.apns=new U(this._payload.apns,e,t),this.mpns=new I(this._payload.mpns,e,t),this.fcm=new D(this._payload.fcm,e,t)}return Object.defineProperty(e.prototype,"debugging",{set:function(e){this._debugging=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"title",{get:function(){return this._title},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"body",{get:function(){return this._body},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"subtitle",{get:function(){return this._subtitle},set:function(e){this._subtitle=e,this.apns.subtitle=e,this.mpns.subtitle=e,this.fcm.subtitle=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"badge",{get:function(){return this._badge},set:function(e){this._badge=e,this.apns.badge=e,this.mpns.badge=e,this.fcm.badge=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"sound",{get:function(){return this._sound},set:function(e){this._sound=e,this.apns.sound=e,this.mpns.sound=e,this.fcm.sound=e},enumerable:!1,configurable:!0}),e.prototype.buildPayload=function(e){var t={};if(e.includes("apns")||e.includes("apns2")){this.apns._apnsPushType=e.includes("apns")?"apns":"apns2";var n=this.apns.toObject();n&&Object.keys(n).length&&(t.pn_apns=n)}if(e.includes("mpns")){var r=this.mpns.toObject();r&&Object.keys(r).length&&(t.pn_mpns=r)}if(e.includes("fcm")){var o=this.fcm.toObject();o&&Object.keys(o).length&&(t.pn_gcm=o)}return Object.keys(t).length&&this._debugging&&(t.pn_debug=!0),t},e}(),L=function(){function e(){this._listeners=[]}return e.prototype.addListener=function(e){this._listeners.includes(e)||this._listeners.push(e)},e.prototype.removeListener=function(e){var t=[];this._listeners.forEach((function(n){n!==e&&t.push(n)})),this._listeners=t},e.prototype.removeAllListeners=function(){this._listeners=[]},e.prototype.announcePresence=function(e){this._listeners.forEach((function(t){t.presence&&t.presence(e)}))},e.prototype.announceStatus=function(e){this._listeners.forEach((function(t){t.status&&t.status(e)}))},e.prototype.announceMessage=function(e){this._listeners.forEach((function(t){t.message&&t.message(e)}))},e.prototype.announceSignal=function(e){this._listeners.forEach((function(t){t.signal&&t.signal(e)}))},e.prototype.announceMessageAction=function(e){this._listeners.forEach((function(t){t.messageAction&&t.messageAction(e)}))},e.prototype.announceFile=function(e){this._listeners.forEach((function(t){t.file&&t.file(e)}))},e.prototype.announceObjects=function(e){this._listeners.forEach((function(t){t.objects&&t.objects(e)}))},e.prototype.announceUser=function(e){this._listeners.forEach((function(t){t.user&&t.user(e)}))},e.prototype.announceSpace=function(e){this._listeners.forEach((function(t){t.space&&t.space(e)}))},e.prototype.announceMembership=function(e){this._listeners.forEach((function(t){t.membership&&t.membership(e)}))},e.prototype.announceNetworkUp=function(){var e={};e.category=k.PNNetworkUpCategory,this.announceStatus(e)},e.prototype.announceNetworkDown=function(){var e={};e.category=k.PNNetworkDownCategory,this.announceStatus(e)},e}(),G=function(){function e(e,t){this._config=e,this._cbor=t}return e.prototype.setToken=function(e){e&&e.length>0?this._token=e:this._token=void 0},e.prototype.getToken=function(){return this._token},e.prototype.extractPermissions=function(e){var t={read:!1,write:!1,manage:!1,delete:!1,get:!1,update:!1,join:!1};return 128==(128&e)&&(t.join=!0),64==(64&e)&&(t.update=!0),32==(32&e)&&(t.get=!0),8==(8&e)&&(t.delete=!0),4==(4&e)&&(t.manage=!0),2==(2&e)&&(t.write=!0),1==(1&e)&&(t.read=!0),t},e.prototype.parseToken=function(e){var t=this,n=this._cbor.decodeToken(e);if(void 0!==n){var r=n.res.uuid?Object.keys(n.res.uuid):[],o=Object.keys(n.res.chan),i=Object.keys(n.res.grp),s=n.pat.uuid?Object.keys(n.pat.uuid):[],a=Object.keys(n.pat.chan),u=Object.keys(n.pat.grp),c={version:n.v,timestamp:n.t,ttl:n.ttl,authorized_uuid:n.uuid},l=r.length>0,p=o.length>0,h=i.length>0;(l||p||h)&&(c.resources={},l&&(c.resources.uuids={},r.forEach((function(e){c.resources.uuids[e]=t.extractPermissions(n.res.uuid[e])}))),p&&(c.resources.channels={},o.forEach((function(e){c.resources.channels[e]=t.extractPermissions(n.res.chan[e])}))),h&&(c.resources.groups={},i.forEach((function(e){c.resources.groups[e]=t.extractPermissions(n.res.grp[e])}))));var f=s.length>0,d=a.length>0,y=u.length>0;return(f||d||y)&&(c.patterns={},f&&(c.patterns.uuids={},s.forEach((function(e){c.patterns.uuids[e]=t.extractPermissions(n.pat.uuid[e])}))),d&&(c.patterns.channels={},a.forEach((function(e){c.patterns.channels[e]=t.extractPermissions(n.pat.chan[e])}))),y&&(c.patterns.groups={},u.forEach((function(e){c.patterns.groups[e]=t.extractPermissions(n.pat.grp[e])})))),Object.keys(n.meta).length>0&&(c.meta=n.meta),c.signature=n.sig,c}},e}();function K(e){return encodeURIComponent(e).replace(/[!~*'()]/g,(function(e){return"%".concat(e.charCodeAt(0).toString(16).toUpperCase())}))}function B(e){return function(e){var t=[];return Object.keys(e).forEach((function(e){return t.push(e)})),t}(e).sort()}var H={signPamFromParams:function(e){return B(e).map((function(t){return"".concat(t,"=").concat(K(e[t]))})).join("&")},endsWith:function(e,t){return-1!==e.indexOf(t,this.length-t.length)},createPromise:function(){var e,t;return{promise:new Promise((function(n,r){e=n,t=r})),reject:t,fulfill:e}},encodeString:K,stringToArrayBuffer:function(e){for(var t=new ArrayBuffer(2*e.length),n=new Uint16Array(t),r=0,o=e.length;r0&&(t+=n),t}function J(e,t,n){return t.usePost&&t.usePost(e,n)?"POST":t.usePatch&&t.usePatch(e,n)?"PATCH":t.useDelete&&t.useDelete(e,n)?"DELETE":t.useGetFile&&t.useGetFile(e,n)?"GETFILE":"GET"}function $(e,t,n,r,o){var i=e.config,s=e.crypto,a=J(e,o,r);n.timestamp=Math.floor((new Date).getTime()/1e3),"PNPublishOperation"===o.getOperation()&&o.usePost&&o.usePost(e,r)&&(a="GET"),"GETFILE"===a&&(a="GET");var u="".concat(a,"\n").concat(i.publishKey,"\n").concat(t,"\n").concat(H.signPamFromParams(n),"\n");if("POST"===a)u+="string"==typeof(c=o.postPayload(e,r))?c:JSON.stringify(c);else if("PATCH"===a){var c;u+="string"==typeof(c=o.patchPayload(e,r))?c:JSON.stringify(c)}var l="v2.".concat(s.HMACSHA256(u));l=(l=(l=l.replace(/\+/g,"-")).replace(/\//g,"_")).replace(/=+$/,""),n.signature=l}function Q(e,t){for(var r=[],o=2;o0&&(c.count=u),c},handleResponse:function(e,t){return{channels:t}}});var ie=Object.freeze({__proto__:null,getOperation:function(){return j.PNRemoveAllPushNotificationsOperation},validateParams:function(e,t){var n=t.device,r=t.pushGateway,o=t.topic,i=e.config;return n?r?"apns2"!==r||o?i.subscribeKey?void 0:"Missing Subscribe Key":"Missing APNS2 topic":"Missing GW Type (pushGateway: gcm, apns or apns2)":"Missing Device ID (device)"},getURL:function(e,t){var n=t.device,r=t.pushGateway,o=e.config;return"apns2"===r?"/v2/push/sub-key/".concat(o.subscribeKey,"/devices-apns2/").concat(n,"/remove"):"/v1/push/sub-key/".concat(o.subscribeKey,"/devices/").concat(n,"/remove")},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var r=t.pushGateway,o=t.environment,i=void 0===o?"development":o,s=t.topic,a={type:r};return"apns2"===r&&delete(a=n(n({},a),{environment:i,topic:s})).type,a},handleResponse:function(){return{}}});var se=Object.freeze({__proto__:null,getOperation:function(){return j.PNUnsubscribeOperation},validateParams:function(e){if(!e.config.subscribeKey)return"Missing Subscribe Key"},getURL:function(e,t){var n=e.config,r=t.channels,o=void 0===r?[]:r,i=o.length>0?o.join(","):",";return"/v2/presence/sub-key/".concat(n.subscribeKey,"/channel/").concat(H.encodeString(i),"/leave")},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n=t.channelGroups,r=void 0===n?[]:n,o={};return r.length>0&&(o["channel-group"]=r.join(",")),o},handleResponse:function(){return{}}});var ae=Object.freeze({__proto__:null,getOperation:function(){return j.PNWhereNowOperation},validateParams:function(e){if(!e.config.subscribeKey)return"Missing Subscribe Key"},getURL:function(e,t){var n=e.config,r=t.uuid,o=void 0===r?n.UUID:r;return"/v2/presence/sub-key/".concat(n.subscribeKey,"/uuid/").concat(H.encodeString(o))},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(){return{}},handleResponse:function(e,t){return t.payload?{channels:t.payload.channels}:{channels:[]}}});var ue=Object.freeze({__proto__:null,getOperation:function(){return j.PNHeartbeatOperation},validateParams:function(e){if(!e.config.subscribeKey)return"Missing Subscribe Key"},getURL:function(e,t){var n=e.config,r=t.channels,o=void 0===r?[]:r,i=o.length>0?o.join(","):",";return"/v2/presence/sub-key/".concat(n.subscribeKey,"/channel/").concat(H.encodeString(i),"/heartbeat")},isAuthSupported:function(){return!0},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},prepareParams:function(e,t){var n=t.channelGroups,r=void 0===n?[]:n,o=t.state,i=e.config,s={};return r.length>0&&(s["channel-group"]=r.join(",")),o&&(s.state=JSON.stringify(o)),s.heartbeat=i.getPresenceTimeout(),s},handleResponse:function(){return{}}});var ce=Object.freeze({__proto__:null,getOperation:function(){return j.PNGetStateOperation},validateParams:function(e){if(!e.config.subscribeKey)return"Missing Subscribe Key"},getURL:function(e,t){var n=e.config,r=t.uuid,o=void 0===r?n.UUID:r,i=t.channels,s=void 0===i?[]:i,a=s.length>0?s.join(","):",";return"/v2/presence/sub-key/".concat(n.subscribeKey,"/channel/").concat(H.encodeString(a),"/uuid/").concat(o)},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n=t.channelGroups,r=void 0===n?[]:n,o={};return r.length>0&&(o["channel-group"]=r.join(",")),o},handleResponse:function(e,t,n){var r=n.channels,o=void 0===r?[]:r,i=n.channelGroups,s=void 0===i?[]:i,a={};return 1===o.length&&0===s.length?a[o[0]]=t.payload:a=t.payload,{channels:a}}});var le=Object.freeze({__proto__:null,getOperation:function(){return j.PNSetStateOperation},validateParams:function(e,t){var n=e.config,r=t.state,o=t.channels,i=void 0===o?[]:o,s=t.channelGroups,a=void 0===s?[]:s;return r?n.subscribeKey?0===i.length&&0===a.length?"Please provide a list of channels and/or channel-groups":void 0:"Missing Subscribe Key":"Missing State"},getURL:function(e,t){var n=e.config,r=t.channels,o=void 0===r?[]:r,i=o.length>0?o.join(","):",";return"/v2/presence/sub-key/".concat(n.subscribeKey,"/channel/").concat(H.encodeString(i),"/uuid/").concat(H.encodeString(n.UUID),"/data")},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n=t.state,r=t.channelGroups,o=void 0===r?[]:r,i={};return i.state=JSON.stringify(n),o.length>0&&(i["channel-group"]=o.join(",")),i},handleResponse:function(e,t){return{state:t.payload}}});var pe=Object.freeze({__proto__:null,getOperation:function(){return j.PNHereNowOperation},validateParams:function(e){if(!e.config.subscribeKey)return"Missing Subscribe Key"},getURL:function(e,t){var n=e.config,r=t.channels,o=void 0===r?[]:r,i=t.channelGroups,s=void 0===i?[]:i,a="/v2/presence/sub-key/".concat(n.subscribeKey);if(o.length>0||s.length>0){var u=o.length>0?o.join(","):",";a+="/channel/".concat(H.encodeString(u))}return a},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var r=t.channelGroups,o=void 0===r?[]:r,i=t.includeUUIDs,s=void 0===i||i,a=t.includeState,u=void 0!==a&&a,c=t.queryParameters,l=void 0===c?{}:c,p={};return s||(p.disable_uuids=1),u&&(p.state=1),o.length>0&&(p["channel-group"]=o.join(",")),p=n(n({},p),l)},handleResponse:function(e,t,n){var r=n.channels,o=void 0===r?[]:r,i=n.channelGroups,s=void 0===i?[]:i,a=n.includeUUIDs,u=void 0===a||a,c=n.includeState,l=void 0!==c&&c;return o.length>1||s.length>0||0===s.length&&0===o.length?function(){var e={};return e.totalChannels=t.payload.total_channels,e.totalOccupancy=t.payload.total_occupancy,e.channels={},Object.keys(t.payload.channels).forEach((function(n){var r=t.payload.channels[n],o=[];return e.channels[n]={occupants:o,name:n,occupancy:r.occupancy},u&&r.uuids.forEach((function(e){l?o.push({state:e.state,uuid:e.uuid}):o.push({state:null,uuid:e})})),e})),e}():function(){var e={},n=[];return e.totalChannels=1,e.totalOccupancy=t.occupancy,e.channels={},e.channels[o[0]]={occupants:n,name:o[0],occupancy:t.occupancy},u&&t.uuids&&t.uuids.forEach((function(e){l?n.push({state:e.state,uuid:e.uuid}):n.push({state:null,uuid:e})})),e}()},handleError:function(e,t,n){402!==n.statusCode||this.getURL(e,t).includes("channel")||(n.errorData.message="You have tried to perform a Global Here Now operation, your keyset configuration does not support that. Please provide a channel, or enable the Global Here Now feature from the Portal.")}});var he=Object.freeze({__proto__:null,getOperation:function(){return j.PNAddMessageActionOperation},validateParams:function(e,t){var n=e.config,r=t.action,o=t.channel;return t.messageTimetoken?n.subscribeKey?o?r?r.value?r.type?r.type.length>15?"Action.type value exceed maximum length of 15":void 0:"Missing Action.type":"Missing Action.value":"Missing Action":"Missing message channel":"Missing Subscribe Key":"Missing message timetoken"},usePost:function(){return!0},postURL:function(e,t){var n=e.config,r=t.channel,o=t.messageTimetoken;return"/v1/message-actions/".concat(n.subscribeKey,"/channel/").concat(H.encodeString(r),"/message/").concat(o)},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},getRequestHeaders:function(){return{"Content-Type":"application/json"}},isAuthSupported:function(){return!0},prepareParams:function(){return{}},postPayload:function(e,t){return t.action},handleResponse:function(e,t){return{data:t.data}}});var fe=Object.freeze({__proto__:null,getOperation:function(){return j.PNRemoveMessageActionOperation},validateParams:function(e,t){var n=e.config,r=t.channel,o=t.actionTimetoken;return t.messageTimetoken?o?n.subscribeKey?r?void 0:"Missing message channel":"Missing Subscribe Key":"Missing action timetoken":"Missing message timetoken"},useDelete:function(){return!0},getURL:function(e,t){var n=e.config,r=t.channel,o=t.actionTimetoken,i=t.messageTimetoken;return"/v1/message-actions/".concat(n.subscribeKey,"/channel/").concat(H.encodeString(r),"/message/").concat(i,"/action/").concat(o)},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(){return{}},handleResponse:function(e,t){return{data:t.data}}});var de=Object.freeze({__proto__:null,getOperation:function(){return j.PNGetMessageActionsOperation},validateParams:function(e,t){var n=e.config,r=t.channel;return n.subscribeKey?r?void 0:"Missing message channel":"Missing Subscribe Key"},getURL:function(e,t){var n=e.config,r=t.channel;return"/v1/message-actions/".concat(n.subscribeKey,"/channel/").concat(H.encodeString(r))},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n=t.limit,r=t.start,o=t.end,i={};return n&&(i.limit=n),r&&(i.start=r),o&&(i.end=o),i},handleResponse:function(e,t){var n={data:t.data,start:null,end:null};return n.data.length&&(n.end=n.data[n.data.length-1].actionTimetoken,n.start=n.data[0].actionTimetoken),n}}),ye={getOperation:function(){return j.PNListFilesOperation},validateParams:function(e,t){if(!(null==t?void 0:t.channel))return"channel can't be empty"},getURL:function(e,t){var n=e.config;return"/v1/files/".concat(n.subscribeKey,"/channels/").concat(H.encodeString(t.channel),"/files")},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n={};return t.limit&&(n.limit=t.limit),t.next&&(n.next=t.next),n},handleResponse:function(e,t){return{status:t.status,data:t.data,next:t.next,count:t.count}}},ge={getOperation:function(){return j.PNGenerateUploadUrlOperation},validateParams:function(e,t){return(null==t?void 0:t.channel)?(null==t?void 0:t.name)?void 0:"name can't be empty":"channel can't be empty"},usePost:function(){return!0},postURL:function(e,t){var n=e.config;return"/v1/files/".concat(n.subscribeKey,"/channels/").concat(H.encodeString(t.channel),"/generate-upload-url")},postPayload:function(e,t){return{name:t.name}},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(){return{}},handleResponse:function(e,t){return{status:t.status,data:t.data,file_upload_request:t.file_upload_request}}},me={getOperation:function(){return j.PNPublishFileOperation},validateParams:function(e,t){return(null==t?void 0:t.channel)?(null==t?void 0:t.fileId)?(null==t?void 0:t.fileName)?void 0:"file name can't be empty":"file id can't be empty":"channel can't be empty"},getURL:function(e,t){var n=e.config,r=n.publishKey,o=n.subscribeKey,i=function(e,t){var n=JSON.stringify(t);if(e.cryptoModule){var r=e.cryptoModule.encrypt(n);n="string"==typeof r?r:b(r),n=JSON.stringify(n)}return n||""}(e,{message:t.message,file:{name:t.fileName,id:t.fileId}});return"/v1/files/publish-file/".concat(r,"/").concat(o,"/0/").concat(H.encodeString(t.channel),"/0/").concat(H.encodeString(i))},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n={};return t.ttl&&(n.ttl=t.ttl),void 0!==t.storeInHistory&&(n.store=t.storeInHistory?"1":"0"),t.meta&&"object"==typeof t.meta&&(n.meta=JSON.stringify(t.meta)),n},handleResponse:function(e,t){return{timetoken:t[2]}}},be=function(e){var t=function(e){var t=this,n=e.generateUploadUrl,r=e.publishFile,s=e.modules,a=s.PubNubFile,u=s.config,c=s.cryptography,l=s.cryptoModule,p=s.networking;return function(e){var s=e.channel,h=e.file,f=e.message,d=e.cipherKey,y=e.meta,g=e.ttl,m=e.storeInHistory;return o(t,void 0,void 0,(function(){var e,t,o,b,v,_,S,w,O,P,E,A,T,N,C,k,M,j,R,x,U,I,D,F,L,G,K,B,H;return i(this,(function(i){switch(i.label){case 0:if(!s)throw new q("Validation failed, check status for details",z("channel can't be empty"));if(!h)throw new q("Validation failed, check status for details",z("file can't be empty"));return e=a.create(h),[4,n({channel:s,name:e.name})];case 1:return t=i.sent(),o=t.file_upload_request,b=o.url,v=o.form_fields,_=t.data,S=_.id,w=_.name,a.supportsEncryptFile&&(d||l)?null!=d?[3,3]:[4,l.encryptFile(e,a)]:[3,6];case 2:return O=i.sent(),[3,5];case 3:return[4,c.encryptFile(d,e,a)];case 4:O=i.sent(),i.label=5;case 5:e=O,i.label=6;case 6:P=v,e.mimeType&&(P=v.map((function(t){return"Content-Type"===t.key?{key:t.key,value:e.mimeType}:t}))),i.label=7;case 7:return i.trys.push([7,21,,22]),a.supportsFileUri&&h.uri?(T=(A=p).POSTFILE,N=[b,P],[4,e.toFileUri()]):[3,10];case 8:return[4,T.apply(A,N.concat([i.sent()]))];case 9:return E=i.sent(),[3,20];case 10:return a.supportsFile?(k=(C=p).POSTFILE,M=[b,P],[4,e.toFile()]):[3,13];case 11:return[4,k.apply(C,M.concat([i.sent()]))];case 12:return E=i.sent(),[3,20];case 13:return a.supportsBuffer?(R=(j=p).POSTFILE,x=[b,P],[4,e.toBuffer()]):[3,16];case 14:return[4,R.apply(j,x.concat([i.sent()]))];case 15:return E=i.sent(),[3,20];case 16:return a.supportsBlob?(I=(U=p).POSTFILE,D=[b,P],[4,e.toBlob()]):[3,19];case 17:return[4,I.apply(U,D.concat([i.sent()]))];case 18:return E=i.sent(),[3,20];case 19:throw new Error("Unsupported environment");case 20:return[3,22];case 21:throw(F=i.sent()).response&&"string"==typeof F.response.text?(L=F.response.text,G=/(.*)<\/Message>/gi.exec(L),new q(G?"Upload to bucket failed: ".concat(G[1]):"Upload to bucket failed.",F)):new q("Upload to bucket failed.",F);case 22:if(204!==E.status)throw new q("Upload to bucket was unsuccessful",E);K=u.fileUploadPublishRetryLimit,B=!1,H={timetoken:"0"},i.label=23;case 23:return i.trys.push([23,25,,26]),[4,r({channel:s,message:f,fileId:S,fileName:w,meta:y,storeInHistory:m,ttl:g})];case 24:return H=i.sent(),B=!0,[3,26];case 25:return i.sent(),K-=1,[3,26];case 26:if(!B&&K>0)return[3,23];i.label=27;case 27:if(B)return[2,{timetoken:H.timetoken,id:S,name:w}];throw new q("Publish failed. You may want to execute that operation manually using pubnub.publishFile",{channel:s,id:S,name:w})}}))}))}}(e);return function(e,n){var r=t(e);return"function"==typeof n?(r.then((function(e){return n(null,e)})).catch((function(e){return n(e,null)})),r):r}},ve=function(e,t){var n=t.channel,r=t.id,o=t.name,i=e.config,s=e.networking,a=e.tokenManager;if(!n)throw new q("Validation failed, check status for details",z("channel can't be empty"));if(!r)throw new q("Validation failed, check status for details",z("file id can't be empty"));if(!o)throw new q("Validation failed, check status for details",z("file name can't be empty"));var u="/v1/files/".concat(i.subscribeKey,"/channels/").concat(H.encodeString(n),"/files/").concat(r,"/").concat(o),c={};c.uuid=i.getUUID(),c.pnsdk=W(i);var l=a.getToken()||i.getAuthKey();l&&(c.auth=l),i.secretKey&&$(e,u,c,{},{getOperation:function(){return"PubNubGetFileUrlOperation"}});var p=Object.keys(c).map((function(e){return"".concat(encodeURIComponent(e),"=").concat(encodeURIComponent(c[e]))})).join("&");return""!==p?"".concat(s.getStandardOrigin()).concat(u,"?").concat(p):"".concat(s.getStandardOrigin()).concat(u)},_e={getOperation:function(){return j.PNDownloadFileOperation},validateParams:function(e,t){return(null==t?void 0:t.channel)?(null==t?void 0:t.name)?(null==t?void 0:t.id)?void 0:"id can't be empty":"name can't be empty":"channel can't be empty"},useGetFile:function(){return!0},getFileURL:function(e,t){var n=e.config;return"/v1/files/".concat(n.subscribeKey,"/channels/").concat(H.encodeString(t.channel),"/files/").concat(t.id,"/").concat(t.name)},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},ignoreBody:function(){return!0},forceBuffered:function(){return!0},prepareParams:function(){return{}},handleResponse:function(e,t,n){var r=e.PubNubFile,s=e.config,a=e.cryptography,u=e.cryptoModule;return o(void 0,void 0,void 0,(function(){var e,o,c,l;return i(this,(function(i){switch(i.label){case 0:return e=t.response.body,r.supportsEncryptFile&&(n.cipherKey||u)?null!=n.cipherKey?[3,2]:[4,u.decryptFile(r.create({data:e,name:n.name}),r)]:[3,5];case 1:return o=i.sent().data,[3,4];case 2:return[4,a.decrypt(null!==(c=n.cipherKey)&&void 0!==c?c:s.cipherKey,e)];case 3:o=i.sent(),i.label=4;case 4:e=o,i.label=5;case 5:return[2,r.create({data:e,name:null!==(l=t.response.name)&&void 0!==l?l:n.name,mimeType:t.response.type})]}}))}))}},Se={getOperation:function(){return j.PNListFilesOperation},validateParams:function(e,t){return(null==t?void 0:t.channel)?(null==t?void 0:t.id)?(null==t?void 0:t.name)?void 0:"file name can't be empty":"file id can't be empty":"channel can't be empty"},useDelete:function(){return!0},getURL:function(e,t){var n=e.config;return"/v1/files/".concat(n.subscribeKey,"/channels/").concat(H.encodeString(t.channel),"/files/").concat(t.id,"/").concat(t.name)},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(){return{}},handleResponse:function(e,t){return{status:t.status}}},we={getOperation:function(){return j.PNGetAllUUIDMetadataOperation},validateParams:function(){},getURL:function(e){var t=e.config;return"/v2/objects/".concat(t.subscribeKey,"/uuids")},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n,r,o,i,s,u,c,l,p,h={include:["status","type"]};return(null==t?void 0:t.include)&&(null===(n=t.include)||void 0===n?void 0:n.customFields)&&h.include.push("custom"),h.include=h.include.join(","),(null===(r=null==t?void 0:t.include)||void 0===r?void 0:r.totalCount)&&(h.count=null===(o=t.include)||void 0===o?void 0:o.totalCount),(null===(i=null==t?void 0:t.page)||void 0===i?void 0:i.next)&&(h.start=null===(s=t.page)||void 0===s?void 0:s.next),(null===(u=null==t?void 0:t.page)||void 0===u?void 0:u.prev)&&(h.end=null===(c=t.page)||void 0===c?void 0:c.prev),(null==t?void 0:t.filter)&&(h.filter=t.filter),h.limit=null!==(l=null==t?void 0:t.limit)&&void 0!==l?l:100,(null==t?void 0:t.sort)&&(h.sort=Object.entries(null!==(p=t.sort)&&void 0!==p?p:{}).map((function(e){var t=a(e,2),n=t[0],r=t[1];return"asc"===r||"desc"===r?"".concat(n,":").concat(r):n}))),h},handleResponse:function(e,t){return{status:t.status,data:t.data,totalCount:t.totalCount,next:t.next,prev:t.prev}}},Oe={getOperation:function(){return j.PNGetUUIDMetadataOperation},validateParams:function(){},getURL:function(e,t){var n,r=e.config;return"/v2/objects/".concat(r.subscribeKey,"/uuids/").concat(H.encodeString(null!==(n=null==t?void 0:t.uuid)&&void 0!==n?n:r.getUUID()))},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n,r,o=e.config,i={};return i.uuid=null!==(n=null==t?void 0:t.uuid)&&void 0!==n?n:o.getUUID(),i.include=["status","type","custom"],(null==t?void 0:t.include)&&!1===(null===(r=t.include)||void 0===r?void 0:r.customFields)&&i.include.pop(),i.include=i.include.join(","),i},handleResponse:function(e,t){return{status:t.status,data:t.data}}},Pe={getOperation:function(){return j.PNSetUUIDMetadataOperation},validateParams:function(e,t){if(!(null==t?void 0:t.data))return"Data cannot be empty"},usePatch:function(){return!0},patchURL:function(e,t){var n,r=e.config;return"/v2/objects/".concat(r.subscribeKey,"/uuids/").concat(H.encodeString(null!==(n=t.uuid)&&void 0!==n?n:r.getUUID()))},patchPayload:function(e,t){return t.data},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n,r,o=e.config,i={};return i.uuid=null!==(n=null==t?void 0:t.uuid)&&void 0!==n?n:o.getUUID(),i.include=["status","type","custom"],(null==t?void 0:t.include)&&!1===(null===(r=t.include)||void 0===r?void 0:r.customFields)&&i.include.pop(),i.include=i.include.join(","),i},handleResponse:function(e,t){return{status:t.status,data:t.data}}},Ee={getOperation:function(){return j.PNRemoveUUIDMetadataOperation},validateParams:function(){},getURL:function(e,t){var n,r=e.config;return"/v2/objects/".concat(r.subscribeKey,"/uuids/").concat(H.encodeString(null!==(n=null==t?void 0:t.uuid)&&void 0!==n?n:r.getUUID()))},useDelete:function(){return!0},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n,r=e.config;return{uuid:null!==(n=null==t?void 0:t.uuid)&&void 0!==n?n:r.getUUID()}},handleResponse:function(e,t){return{status:t.status,data:t.data}}},Ae={getOperation:function(){return j.PNGetAllChannelMetadataOperation},validateParams:function(){},getURL:function(e){var t=e.config;return"/v2/objects/".concat(t.subscribeKey,"/channels")},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n,r,o,i,s,u,c,l,p,h={include:["status","type"]};return(null==t?void 0:t.include)&&(null===(n=t.include)||void 0===n?void 0:n.customFields)&&h.include.push("custom"),h.include=h.include.join(","),(null===(r=null==t?void 0:t.include)||void 0===r?void 0:r.totalCount)&&(h.count=null===(o=t.include)||void 0===o?void 0:o.totalCount),(null===(i=null==t?void 0:t.page)||void 0===i?void 0:i.next)&&(h.start=null===(s=t.page)||void 0===s?void 0:s.next),(null===(u=null==t?void 0:t.page)||void 0===u?void 0:u.prev)&&(h.end=null===(c=t.page)||void 0===c?void 0:c.prev),(null==t?void 0:t.filter)&&(h.filter=t.filter),h.limit=null!==(l=null==t?void 0:t.limit)&&void 0!==l?l:100,(null==t?void 0:t.sort)&&(h.sort=Object.entries(null!==(p=t.sort)&&void 0!==p?p:{}).map((function(e){var t=a(e,2),n=t[0],r=t[1];return"asc"===r||"desc"===r?"".concat(n,":").concat(r):n}))),h},handleResponse:function(e,t){return{status:t.status,data:t.data,totalCount:t.totalCount,prev:t.prev,next:t.next}}},Te={getOperation:function(){return j.PNGetChannelMetadataOperation},validateParams:function(e,t){if(!(null==t?void 0:t.channel))return"Channel cannot be empty"},getURL:function(e,t){var n=e.config;return"/v2/objects/".concat(n.subscribeKey,"/channels/").concat(H.encodeString(t.channel))},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n,r={include:["status","type","custom"]};return(null==t?void 0:t.include)&&!1===(null===(n=t.include)||void 0===n?void 0:n.customFields)&&r.include.pop(),r.include=r.include.join(","),r},handleResponse:function(e,t){return{status:t.status,data:t.data}}},Ne={getOperation:function(){return j.PNSetChannelMetadataOperation},validateParams:function(e,t){return(null==t?void 0:t.channel)?(null==t?void 0:t.data)?void 0:"Data cannot be empty":"Channel cannot be empty"},usePatch:function(){return!0},patchURL:function(e,t){var n=e.config;return"/v2/objects/".concat(n.subscribeKey,"/channels/").concat(H.encodeString(t.channel))},patchPayload:function(e,t){return t.data},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n,r={include:["status","type","custom"]};return(null==t?void 0:t.include)&&!1===(null===(n=t.include)||void 0===n?void 0:n.customFields)&&r.include.pop(),r.include=r.include.join(","),r},handleResponse:function(e,t){return{status:t.status,data:t.data}}},Ce={getOperation:function(){return j.PNRemoveChannelMetadataOperation},validateParams:function(e,t){if(!(null==t?void 0:t.channel))return"Channel cannot be empty"},getURL:function(e,t){var n=e.config;return"/v2/objects/".concat(n.subscribeKey,"/channels/").concat(H.encodeString(t.channel))},useDelete:function(){return!0},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(){return{}},handleResponse:function(e,t){return{status:t.status,data:t.data}}},ke={getOperation:function(){return j.PNGetMembersOperation},validateParams:function(e,t){if(!(null==t?void 0:t.channel))return"channel cannot be empty"},getURL:function(e,t){var n=e.config;return"/v2/objects/".concat(n.subscribeKey,"/channels/").concat(H.encodeString(t.channel),"/uuids")},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n,r,o,i,s,u,c,l,p,h,f,d,y,g,m={include:[]};return(null==t?void 0:t.include)&&((null===(n=t.include)||void 0===n?void 0:n.statusField)&&m.include.push("status"),(null===(r=t.include)||void 0===r?void 0:r.customFields)&&m.include.push("custom"),(null===(o=t.include)||void 0===o?void 0:o.UUIDFields)&&m.include.push("uuid"),(null===(i=t.include)||void 0===i?void 0:i.customUUIDFields)&&m.include.push("uuid.custom"),(null===(s=t.include)||void 0===s?void 0:s.UUIDStatusField)&&m.include.push("uuid.status"),(null===(u=t.include)||void 0===u?void 0:u.UUIDTypeField)&&m.include.push("uuid.type")),m.include=m.include.join(","),(null===(c=null==t?void 0:t.include)||void 0===c?void 0:c.totalCount)&&(m.count=null===(l=t.include)||void 0===l?void 0:l.totalCount),(null===(p=null==t?void 0:t.page)||void 0===p?void 0:p.next)&&(m.start=null===(h=t.page)||void 0===h?void 0:h.next),(null===(f=null==t?void 0:t.page)||void 0===f?void 0:f.prev)&&(m.end=null===(d=t.page)||void 0===d?void 0:d.prev),(null==t?void 0:t.filter)&&(m.filter=t.filter),m.limit=null!==(y=null==t?void 0:t.limit)&&void 0!==y?y:100,(null==t?void 0:t.sort)&&(m.sort=Object.entries(null!==(g=t.sort)&&void 0!==g?g:{}).map((function(e){var t=a(e,2),n=t[0],r=t[1];return"asc"===r||"desc"===r?"".concat(n,":").concat(r):n}))),m},handleResponse:function(e,t){return{status:t.status,data:t.data,totalCount:t.totalCount,prev:t.prev,next:t.next}}},Me={getOperation:function(){return j.PNSetMembersOperation},validateParams:function(e,t){return(null==t?void 0:t.channel)?(null==t?void 0:t.uuids)&&0!==(null==t?void 0:t.uuids.length)?void 0:"UUIDs cannot be empty":"Channel cannot be empty"},usePatch:function(){return!0},patchURL:function(e,t){var n=e.config;return"/v2/objects/".concat(n.subscribeKey,"/channels/").concat(H.encodeString(t.channel),"/uuids")},patchPayload:function(e,t){var n;return(n={set:[],delete:[]})[t.type]=t.uuids.map((function(e){return"string"==typeof e?{uuid:{id:e}}:{uuid:{id:e.id},custom:e.custom,status:e.status}})),n},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n,r,o,i,s,u,c,l,p,h={include:["uuid.status","uuid.type","type"]};return(null==t?void 0:t.include)&&((null===(n=t.include)||void 0===n?void 0:n.customFields)&&h.include.push("custom"),(null===(r=t.include)||void 0===r?void 0:r.customUUIDFields)&&h.include.push("uuid.custom"),(null===(o=t.include)||void 0===o?void 0:o.UUIDFields)&&h.include.push("uuid")),h.include=h.include.join(","),(null===(i=null==t?void 0:t.include)||void 0===i?void 0:i.totalCount)&&(h.count=!0),(null===(s=null==t?void 0:t.page)||void 0===s?void 0:s.next)&&(h.start=null===(u=t.page)||void 0===u?void 0:u.next),(null===(c=null==t?void 0:t.page)||void 0===c?void 0:c.prev)&&(h.end=null===(l=t.page)||void 0===l?void 0:l.prev),(null==t?void 0:t.filter)&&(h.filter=t.filter),null!=t.limit&&(h.limit=t.limit),(null==t?void 0:t.sort)&&(h.sort=Object.entries(null!==(p=t.sort)&&void 0!==p?p:{}).map((function(e){var t=a(e,2),n=t[0],r=t[1];return"asc"===r||"desc"===r?"".concat(n,":").concat(r):n}))),h},handleResponse:function(e,t){return{status:t.status,data:t.data,totalCount:t.totalCount,prev:t.prev,next:t.next}}},je={getOperation:function(){return j.PNGetMembershipsOperation},validateParams:function(){},getURL:function(e,t){var n,r=e.config;return"/v2/objects/".concat(r.subscribeKey,"/uuids/").concat(H.encodeString(null!==(n=null==t?void 0:t.uuid)&&void 0!==n?n:r.getUUID()),"/channels")},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n,r,o,i,s,u,c,l,p,h,f,d,y,g,m={include:[]};return(null==t?void 0:t.include)&&((null===(n=t.include)||void 0===n?void 0:n.statusField)&&m.include.push("status"),(null===(r=t.include)||void 0===r?void 0:r.customFields)&&m.include.push("custom"),(null===(o=t.include)||void 0===o?void 0:o.channelFields)&&m.include.push("channel"),(null===(i=t.include)||void 0===i?void 0:i.customChannelFields)&&m.include.push("channel.custom"),(null===(s=t.include)||void 0===s?void 0:s.channelStatusField)&&m.include.push("channel.status"),(null===(u=t.include)||void 0===u?void 0:u.channelTypeField)&&m.include.push("channel.type")),m.include=m.include.join(","),(null===(c=null==t?void 0:t.include)||void 0===c?void 0:c.totalCount)&&(m.count=null===(l=t.include)||void 0===l?void 0:l.totalCount),(null===(p=null==t?void 0:t.page)||void 0===p?void 0:p.next)&&(m.start=null===(h=t.page)||void 0===h?void 0:h.next),(null===(f=null==t?void 0:t.page)||void 0===f?void 0:f.prev)&&(m.end=null===(d=t.page)||void 0===d?void 0:d.prev),(null==t?void 0:t.filter)&&(m.filter=t.filter),m.limit=null!==(y=null==t?void 0:t.limit)&&void 0!==y?y:100,(null==t?void 0:t.sort)&&(m.sort=Object.entries(null!==(g=t.sort)&&void 0!==g?g:{}).map((function(e){var t=a(e,2),n=t[0],r=t[1];return"asc"===r||"desc"===r?"".concat(n,":").concat(r):n}))),m},handleResponse:function(e,t){return{status:t.status,data:t.data,totalCount:t.totalCount,prev:t.prev,next:t.next}}},Re={getOperation:function(){return j.PNSetMembershipsOperation},validateParams:function(e,t){if(!(null==t?void 0:t.channels)||0===(null==t?void 0:t.channels.length))return"Channels cannot be empty"},usePatch:function(){return!0},patchURL:function(e,t){var n,r=e.config;return"/v2/objects/".concat(r.subscribeKey,"/uuids/").concat(H.encodeString(null!==(n=t.uuid)&&void 0!==n?n:r.getUUID()),"/channels")},patchPayload:function(e,t){var n;return(n={set:[],delete:[]})[t.type]=t.channels.map((function(e){return"string"==typeof e?{channel:{id:e}}:{channel:{id:e.id},custom:e.custom,status:e.status}})),n},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n,r,o,i,s,u,c,l,p,h={include:["channel.status","channel.type","status"]};return(null==t?void 0:t.include)&&((null===(n=t.include)||void 0===n?void 0:n.customFields)&&h.include.push("custom"),(null===(r=t.include)||void 0===r?void 0:r.customChannelFields)&&h.include.push("channel.custom"),(null===(o=t.include)||void 0===o?void 0:o.channelFields)&&h.include.push("channel")),h.include=h.include.join(","),(null===(i=null==t?void 0:t.include)||void 0===i?void 0:i.totalCount)&&(h.count=!0),(null===(s=null==t?void 0:t.page)||void 0===s?void 0:s.next)&&(h.start=null===(u=t.page)||void 0===u?void 0:u.next),(null===(c=null==t?void 0:t.page)||void 0===c?void 0:c.prev)&&(h.end=null===(l=t.page)||void 0===l?void 0:l.prev),(null==t?void 0:t.filter)&&(h.filter=t.filter),null!=t.limit&&(h.limit=t.limit),(null==t?void 0:t.sort)&&(h.sort=Object.entries(null!==(p=t.sort)&&void 0!==p?p:{}).map((function(e){var t=a(e,2),n=t[0],r=t[1];return"asc"===r||"desc"===r?"".concat(n,":").concat(r):n}))),h},handleResponse:function(e,t){return{status:t.status,data:t.data,totalCount:t.totalCount,prev:t.prev,next:t.next}}};var xe=Object.freeze({__proto__:null,getOperation:function(){return j.PNAccessManagerAudit},validateParams:function(e){if(!e.config.subscribeKey)return"Missing Subscribe Key"},getURL:function(e){var t=e.config;return"/v2/auth/audit/sub-key/".concat(t.subscribeKey)},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!1},prepareParams:function(e,t){var n=t.channel,r=t.channelGroup,o=t.authKeys,i=void 0===o?[]:o,s={};return n&&(s.channel=n),r&&(s["channel-group"]=r),i.length>0&&(s.auth=i.join(",")),s},handleResponse:function(e,t){return t.payload}});var Ue=Object.freeze({__proto__:null,getOperation:function(){return j.PNAccessManagerGrant},validateParams:function(e,t){var n=e.config;return n.subscribeKey?n.publishKey?n.secretKey?null==t.uuids||t.authKeys?null==t.uuids||null==t.channels&&null==t.channelGroups?void 0:"Both channel/channelgroup and uuid cannot be used in the same request":"authKeys are required for grant request on uuids":"Missing Secret Key":"Missing Publish Key":"Missing Subscribe Key"},getURL:function(e){var t=e.config;return"/v2/auth/grant/sub-key/".concat(t.subscribeKey)},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!1},prepareParams:function(e,t){var n=t.channels,r=void 0===n?[]:n,o=t.channelGroups,i=void 0===o?[]:o,s=t.uuids,a=void 0===s?[]:s,u=t.ttl,c=t.read,l=void 0!==c&&c,p=t.write,h=void 0!==p&&p,f=t.manage,d=void 0!==f&&f,y=t.get,g=void 0!==y&&y,m=t.join,b=void 0!==m&&m,v=t.update,_=void 0!==v&&v,S=t.authKeys,w=void 0===S?[]:S,O=t.delete,P={};return P.r=l?"1":"0",P.w=h?"1":"0",P.m=d?"1":"0",P.d=O?"1":"0",P.g=g?"1":"0",P.j=b?"1":"0",P.u=_?"1":"0",r.length>0&&(P.channel=r.join(",")),i.length>0&&(P["channel-group"]=i.join(",")),w.length>0&&(P.auth=w.join(",")),a.length>0&&(P["target-uuid"]=a.join(",")),(u||0===u)&&(P.ttl=u),P},handleResponse:function(){return{}}});function Ie(e){var t,n,r,o,i=void 0!==(null==e?void 0:e.authorizedUserId),s=void 0!==(null===(t=null==e?void 0:e.resources)||void 0===t?void 0:t.users),a=void 0!==(null===(n=null==e?void 0:e.resources)||void 0===n?void 0:n.spaces),u=void 0!==(null===(r=null==e?void 0:e.patterns)||void 0===r?void 0:r.users),c=void 0!==(null===(o=null==e?void 0:e.patterns)||void 0===o?void 0:o.spaces);return u||s||c||a||i}function De(e){var t=0;return e.join&&(t|=128),e.update&&(t|=64),e.get&&(t|=32),e.delete&&(t|=8),e.manage&&(t|=4),e.write&&(t|=2),e.read&&(t|=1),t}function Fe(e,t){if(Ie(t))return function(e,t){var n=t.ttl,r=t.resources,o=t.patterns,i=t.meta,s=t.authorizedUserId,a={ttl:0,permissions:{resources:{channels:{},groups:{},uuids:{},users:{},spaces:{}},patterns:{channels:{},groups:{},uuids:{},users:{},spaces:{}},meta:{}}};if(r){var u=r.users,c=r.spaces,l=r.groups;u&&Object.keys(u).forEach((function(e){a.permissions.resources.uuids[e]=De(u[e])})),c&&Object.keys(c).forEach((function(e){a.permissions.resources.channels[e]=De(c[e])})),l&&Object.keys(l).forEach((function(e){a.permissions.resources.groups[e]=De(l[e])}))}if(o){var p=o.users,h=o.spaces,f=o.groups;p&&Object.keys(p).forEach((function(e){a.permissions.patterns.uuids[e]=De(p[e])})),h&&Object.keys(h).forEach((function(e){a.permissions.patterns.channels[e]=De(h[e])})),f&&Object.keys(f).forEach((function(e){a.permissions.patterns.groups[e]=De(f[e])}))}return(n||0===n)&&(a.ttl=n),i&&(a.permissions.meta=i),s&&(a.permissions.uuid="".concat(s)),a}(0,t);var n=t.ttl,r=t.resources,o=t.patterns,i=t.meta,s=t.authorized_uuid,a={ttl:0,permissions:{resources:{channels:{},groups:{},uuids:{},users:{},spaces:{}},patterns:{channels:{},groups:{},uuids:{},users:{},spaces:{}},meta:{}}};if(r){var u=r.uuids,c=r.channels,l=r.groups;u&&Object.keys(u).forEach((function(e){a.permissions.resources.uuids[e]=De(u[e])})),c&&Object.keys(c).forEach((function(e){a.permissions.resources.channels[e]=De(c[e])})),l&&Object.keys(l).forEach((function(e){a.permissions.resources.groups[e]=De(l[e])}))}if(o){var p=o.uuids,h=o.channels,f=o.groups;p&&Object.keys(p).forEach((function(e){a.permissions.patterns.uuids[e]=De(p[e])})),h&&Object.keys(h).forEach((function(e){a.permissions.patterns.channels[e]=De(h[e])})),f&&Object.keys(f).forEach((function(e){a.permissions.patterns.groups[e]=De(f[e])}))}return(n||0===n)&&(a.ttl=n),i&&(a.permissions.meta=i),s&&(a.permissions.uuid="".concat(s)),a}var Le=Object.freeze({__proto__:null,getOperation:function(){return j.PNAccessManagerGrantToken},extractPermissions:De,validateParams:function(e,t){var n,r,o,i,s,a,u=e.config;if(!u.subscribeKey)return"Missing Subscribe Key";if(!u.publishKey)return"Missing Publish Key";if(!u.secretKey)return"Missing Secret Key";if(!t.resources&&!t.patterns)return"Missing either Resources or Patterns.";var c=void 0!==(null==t?void 0:t.authorized_uuid),l=void 0!==(null===(n=null==t?void 0:t.resources)||void 0===n?void 0:n.uuids),p=void 0!==(null===(r=null==t?void 0:t.resources)||void 0===r?void 0:r.channels),h=void 0!==(null===(o=null==t?void 0:t.resources)||void 0===o?void 0:o.groups),f=void 0!==(null===(i=null==t?void 0:t.patterns)||void 0===i?void 0:i.uuids),d=void 0!==(null===(s=null==t?void 0:t.patterns)||void 0===s?void 0:s.channels),y=void 0!==(null===(a=null==t?void 0:t.patterns)||void 0===a?void 0:a.groups),g=c||l||f||p||d||h||y;return Ie(t)&&g?"Cannot mix `users`, `spaces` and `authorizedUserId` with `uuids`, `channels`, `groups` and `authorized_uuid`":(!t.resources||t.resources.uuids&&0!==Object.keys(t.resources.uuids).length||t.resources.channels&&0!==Object.keys(t.resources.channels).length||t.resources.groups&&0!==Object.keys(t.resources.groups).length||t.resources.users&&0!==Object.keys(t.resources.users).length||t.resources.spaces&&0!==Object.keys(t.resources.spaces).length)&&(!t.patterns||t.patterns.uuids&&0!==Object.keys(t.patterns.uuids).length||t.patterns.channels&&0!==Object.keys(t.patterns.channels).length||t.patterns.groups&&0!==Object.keys(t.patterns.groups).length||t.patterns.users&&0!==Object.keys(t.patterns.users).length||t.patterns.spaces&&0!==Object.keys(t.patterns.spaces).length)?void 0:"Missing values for either Resources or Patterns."},postURL:function(e){var t=e.config;return"/v3/pam/".concat(t.subscribeKey,"/grant")},usePost:function(){return!0},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!1},prepareParams:function(){return{}},postPayload:function(e,t){return Fe(0,t)},handleResponse:function(e,t){return t.data.token}}),Ge={getOperation:function(){return j.PNAccessManagerRevokeToken},validateParams:function(e,t){return e.config.secretKey?t?void 0:"token can't be empty":"Missing Secret Key"},getURL:function(e,t){var n=e.config;return"/v3/pam/".concat(n.subscribeKey,"/grant/").concat(H.encodeString(t))},useDelete:function(){return!0},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!1},prepareParams:function(e){return{uuid:e.config.getUUID()}},handleResponse:function(e,t){return{status:t.status,data:t.data}}};function Ke(e,t){var n=JSON.stringify(t);if(e.cryptoModule){var r=e.cryptoModule.encrypt(n);n="string"==typeof r?r:b(r),n=JSON.stringify(n)}return n||""}var Be=Object.freeze({__proto__:null,getOperation:function(){return j.PNPublishOperation},validateParams:function(e,t){var n=e.config,r=t.message;return t.channel?r?n.subscribeKey?void 0:"Missing Subscribe Key":"Missing Message":"Missing Channel"},usePost:function(e,t){var n=t.sendByPost;return void 0!==n&&n},getURL:function(e,t){var n=e.config,r=t.channel,o=Ke(e,t.message);return"/publish/".concat(n.publishKey,"/").concat(n.subscribeKey,"/0/").concat(H.encodeString(r),"/0/").concat(H.encodeString(o))},postURL:function(e,t){var n=e.config,r=t.channel;return"/publish/".concat(n.publishKey,"/").concat(n.subscribeKey,"/0/").concat(H.encodeString(r),"/0")},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},postPayload:function(e,t){return Ke(e,t.message)},prepareParams:function(e,t){var n=t.meta,r=t.replicate,o=void 0===r||r,i=t.storeInHistory,s=t.ttl,a={};return null!=i&&(a.store=i?"1":"0"),s&&(a.ttl=s),!1===o&&(a.norep="true"),n&&"object"==typeof n&&(a.meta=JSON.stringify(n)),a},handleResponse:function(e,t){return{timetoken:t[2]}}});var He=Object.freeze({__proto__:null,getOperation:function(){return j.PNSignalOperation},validateParams:function(e,t){var n=e.config,r=t.message;return t.channel?r?n.subscribeKey?void 0:"Missing Subscribe Key":"Missing Message":"Missing Channel"},getURL:function(e,t){var n,r=e.config,o=t.channel,i=t.message,s=(n=i,JSON.stringify(n));return"/signal/".concat(r.publishKey,"/").concat(r.subscribeKey,"/0/").concat(H.encodeString(o),"/0/").concat(H.encodeString(s))},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(){return{}},handleResponse:function(e,t){return{timetoken:t[2]}}});var qe=Object.freeze({__proto__:null,getOperation:function(){return j.PNHistoryOperation},validateParams:function(e,t){var n=t.channel,r=e.config;return n?r.subscribeKey?void 0:"Missing Subscribe Key":"Missing channel"},getURL:function(e,t){var n=t.channel,r=e.config;return"/v2/history/sub-key/".concat(r.subscribeKey,"/channel/").concat(H.encodeString(n))},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n=t.start,r=t.end,o=t.reverse,i=t.count,s=void 0===i?100:i,a=t.stringifiedTimeToken,u=void 0!==a&&a,c=t.includeMeta,l=void 0!==c&&c,p={include_token:"true"};return p.count=s,n&&(p.start=n),r&&(p.end=r),u&&(p.string_message_token="true"),null!=o&&(p.reverse=o.toString()),l&&(p.include_meta="true"),p},handleResponse:function(e,t){var n={messages:[],startTimeToken:t[1],endTimeToken:t[2]};return Array.isArray(t[0])&&t[0].forEach((function(t){var r=function(e,t){var n={};if(!e.cryptoModule)return n.payload=t,n;try{var r=e.cryptoModule.decrypt(t),o=r instanceof ArrayBuffer?JSON.parse((new TextDecoder).decode(r)):r;return n.payload=o,n}catch(r){e.config.logVerbosity&&console&&console.log&&console.log("decryption error",r.message),n.payload=t,n.error="Error while decrypting message content: ".concat(r.message)}return n}(e,t.message),o={timetoken:t.timetoken,entry:r.payload};t.meta&&(o.meta=t.meta),r.error&&(o.error=r.error),n.messages.push(o)})),n}});var ze=Object.freeze({__proto__:null,getOperation:function(){return j.PNDeleteMessagesOperation},validateParams:function(e,t){var n=t.channel,r=e.config;return n?r.subscribeKey?void 0:"Missing Subscribe Key":"Missing channel"},useDelete:function(){return!0},getURL:function(e,t){var n=t.channel,r=e.config;return"/v3/history/sub-key/".concat(r.subscribeKey,"/channel/").concat(H.encodeString(n))},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n=t.start,r=t.end,o={};return n&&(o.start=n),r&&(o.end=r),o},handleResponse:function(e,t){return t.payload}});var Ve=Object.freeze({__proto__:null,getOperation:function(){return j.PNMessageCounts},validateParams:function(e,t){var n=t.channels,r=t.timetoken,o=t.channelTimetokens,i=e.config;return n?r&&o?"timetoken and channelTimetokens are incompatible together":o&&o.length>1&&n.length!==o.length?"Length of channelTimetokens and channels do not match":i.subscribeKey?void 0:"Missing Subscribe Key":"Missing channel"},getURL:function(e,t){var n=t.channels,r=e.config,o=n.join(",");return"/v3/history/sub-key/".concat(r.subscribeKey,"/message-counts/").concat(H.encodeString(o))},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n=t.timetoken,r=t.channelTimetokens,o={};if(r&&1===r.length){var i=a(r,1)[0];o.timetoken=i}else r?o.channelsTimetoken=r.join(","):n&&(o.timetoken=n);return o},handleResponse:function(e,t){return{channels:t.channels}}});var We=Object.freeze({__proto__:null,getOperation:function(){return j.PNFetchMessagesOperation},validateParams:function(e,t){var n=t.channels,r=t.includeMessageActions,o=void 0!==r&&r,i=e.config;if(!n||0===n.length)return"Missing channels";if(!i.subscribeKey)return"Missing Subscribe Key";if(o&&n.length>1)throw new TypeError("History can return actions data for a single channel only. Either pass a single channel or disable the includeMessageActions flag.")},getURL:function(e,t){var n=t.channels,r=void 0===n?[]:n,o=t.includeMessageActions,i=void 0!==o&&o,s=e.config,a=i?"history-with-actions":"history",u=r.length>0?r.join(","):",";return"/v3/".concat(a,"/sub-key/").concat(s.subscribeKey,"/channel/").concat(H.encodeString(u))},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n=t.channels,r=t.start,o=t.end,i=t.includeMessageActions,s=t.count,a=t.stringifiedTimeToken,u=void 0!==a&&a,c=t.includeMeta,l=void 0!==c&&c,p=t.includeUuid,h=t.includeUUID,f=void 0===h||h,d=t.includeMessageType,y=void 0===d||d,g={};return g.max=s||(n.length>1||!0===i?25:100),r&&(g.start=r),o&&(g.end=o),u&&(g.string_message_token="true"),l&&(g.include_meta="true"),f&&!1!==p&&(g.include_uuid="true"),y&&(g.include_message_type="true"),g},handleResponse:function(e,t){var n={channels:{}};return Object.keys(t.channels||{}).forEach((function(r){n.channels[r]=[],(t.channels[r]||[]).forEach((function(t){var o={},i=function(e,t){var n={};if(!e.cryptoModule)return n.payload=t,n;try{var r=e.cryptoModule.decrypt(t),o=r instanceof ArrayBuffer?JSON.parse((new TextDecoder).decode(r)):r;return n.payload=o,n}catch(r){e.config.logVerbosity&&console&&console.log&&console.log("decryption error",r.message),n.payload=t,n.error="Error while decrypting message content: ".concat(r.message)}return n}(e,t.message);o.channel=r,o.timetoken=t.timetoken,o.message=i.payload,o.messageType=t.message_type,o.uuid=t.uuid,t.actions&&(o.actions=t.actions,o.data=t.actions),t.meta&&(o.meta=t.meta),i.error&&(o.error=i.error),n.channels[r].push(o)}))})),t.more&&(n.more=t.more),n}});var Je=Object.freeze({__proto__:null,getOperation:function(){return j.PNTimeOperation},getURL:function(){return"/time/0"},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},prepareParams:function(){return{}},isAuthSupported:function(){return!1},handleResponse:function(e,t){return{timetoken:t[0]}},validateParams:function(){}});var $e=Object.freeze({__proto__:null,getOperation:function(){return j.PNSubscribeOperation},validateParams:function(e){if(!e.config.subscribeKey)return"Missing Subscribe Key"},getURL:function(e,t){var n=e.config,r=t.channels,o=void 0===r?[]:r,i=o.length>0?o.join(","):",";return"/v2/subscribe/".concat(n.subscribeKey,"/").concat(H.encodeString(i),"/0")},getRequestTimeout:function(e){return e.config.getSubscribeTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n=e.config,r=t.state,o=t.channelGroups,i=void 0===o?[]:o,s=t.timetoken,a=t.filterExpression,u=t.region,c={heartbeat:n.getPresenceTimeout()};return i.length>0&&(c["channel-group"]=i.join(",")),a&&a.length>0&&(c["filter-expr"]=a),Object.keys(r).length&&(c.state=JSON.stringify(r)),s&&(c.tt=s),u&&(c.tr=u),c},handleResponse:function(e,t){var n=[];t.m.forEach((function(e){var t={timetoken:e.p.t,region:e.p.r},r={shard:parseInt(e.a,10),subscriptionMatch:e.b,channel:e.c,messageType:e.e,payload:e.d,flags:e.f,issuingClientId:e.i,subscribeKey:e.k,originationTimetoken:e.o,userMetadata:e.u,publishMetaData:t};n.push(r)}));var r={timetoken:t.t.t,region:t.t.r};return{messages:n,metadata:r}}}),Qe={getOperation:function(){return j.PNHandshakeOperation},validateParams:function(e,t){if(!(null==t?void 0:t.channels)&&!(null==t?void 0:t.channelGroups))return"channels and channleGroups both should not be empty"},getURL:function(e,t){var n=e.config,r=t.channels,o=void 0===r?[]:r,i=o.length>0?o.join(","):",";return"/v2/subscribe/".concat(n.subscribeKey,"/").concat(H.encodeString(i),"/0")},getRequestTimeout:function(e){return e.config.getSubscribeTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n={};return t.channelGroups&&t.channelGroups.length>0&&(n["channel-group"]=t.channelGroups.join(",")),n.tt=0,t.state&&(n.state=JSON.stringify(t.state)),t.filterExpression&&t.filterExpression.length>0&&(n["filter-expr"]=t.filterExpression),n.ee="",n},handleResponse:function(e,t){return{region:t.t.r,timetoken:t.t.t}}},Xe={getOperation:function(){return j.PNReceiveMessagesOperation},validateParams:function(e,t){return(null==t?void 0:t.channels)||(null==t?void 0:t.channelGroups)?(null==t?void 0:t.timetoken)?(null==t?void 0:t.region)?void 0:"region can not be empty":"timetoken can not be empty":"channels and channleGroups both should not be empty"},getURL:function(e,t){var n=e.config,r=t.channels,o=void 0===r?[]:r,i=o.length>0?o.join(","):",";return"/v2/subscribe/".concat(n.subscribeKey,"/").concat(H.encodeString(i),"/0")},getRequestTimeout:function(e){return e.config.getSubscribeTimeout()},isAuthSupported:function(){return!0},getAbortSignal:function(e,t){return t.abortSignal},prepareParams:function(e,t){var n={};return t.channelGroups&&t.channelGroups.length>0&&(n["channel-group"]=t.channelGroups.join(",")),t.filterExpression&&t.filterExpression.length>0&&(n["filter-expr"]=t.filterExpression),n.tt=t.timetoken,n.tr=t.region,n.ee="",n},handleResponse:function(e,t){var n=[];return t.m.forEach((function(e){var t={shard:parseInt(e.a,10),subscriptionMatch:e.b,channel:e.c,messageType:e.e,payload:e.d,flags:e.f,issuingClientId:e.i,subscribeKey:e.k,originationTimetoken:e.o,userMetadata:e.u,publishMetaData:{timetoken:e.p.t,region:e.p.r}};n.push(t)})),{messages:n,metadata:{region:t.t.r,timetoken:t.t.t}}}},Ye=function(){function e(e){void 0===e&&(e=!1),this.sync=e,this.listeners=new Set}return e.prototype.subscribe=function(e){var t=this;return this.listeners.add(e),function(){t.listeners.delete(e)}},e.prototype.notify=function(e){var t=this,n=function(){t.listeners.forEach((function(t){t(e)}))};this.sync?n():setTimeout(n,0)},e}(),Ze=function(){function e(e){this.label=e,this.transitionMap=new Map,this.enterEffects=[],this.exitEffects=[]}return e.prototype.transition=function(e,t){var n;if(this.transitionMap.has(t.type))return null===(n=this.transitionMap.get(t.type))||void 0===n?void 0:n(e,t)},e.prototype.on=function(e,t){return this.transitionMap.set(e,t),this},e.prototype.with=function(e,t){return[this,e,null!=t?t:[]]},e.prototype.onEnter=function(e){return this.enterEffects.push(e),this},e.prototype.onExit=function(e){return this.exitEffects.push(e),this},e}(),et=function(e){function n(){return null!==e&&e.apply(this,arguments)||this}return t(n,e),n.prototype.describe=function(e){return new Ze(e)},n.prototype.start=function(e,t){this.currentState=e,this.currentContext=t,this.notify({type:"engineStarted",state:e,context:t})},n.prototype.transition=function(e){var t,n,r,o,i,u;if(!this.currentState)throw new Error("Start the engine first");this.notify({type:"eventReceived",event:e});var c=this.currentState.transition(this.currentContext,e);if(c){var l=a(c,3),p=l[0],h=l[1],f=l[2];try{for(var d=s(this.currentState.exitEffects),y=d.next();!y.done;y=d.next()){var g=y.value;this.notify({type:"invocationDispatched",invocation:g(this.currentContext)})}}catch(e){t={error:e}}finally{try{y&&!y.done&&(n=d.return)&&n.call(d)}finally{if(t)throw t.error}}var m=this.currentState;this.currentState=p;var b=this.currentContext;this.currentContext=h,this.notify({type:"transitionDone",fromState:m,fromContext:b,toState:p,toContext:h,event:e});try{for(var v=s(f),_=v.next();!_.done;_=v.next()){g=_.value;this.notify({type:"invocationDispatched",invocation:g})}}catch(e){r={error:e}}finally{try{_&&!_.done&&(o=v.return)&&o.call(v)}finally{if(r)throw r.error}}try{for(var S=s(this.currentState.enterEffects),w=S.next();!w.done;w=S.next()){g=w.value;this.notify({type:"invocationDispatched",invocation:g(this.currentContext)})}}catch(e){i={error:e}}finally{try{w&&!w.done&&(u=S.return)&&u.call(S)}finally{if(i)throw i.error}}}},n}(Ye),tt=function(){function e(e){this.dependencies=e,this.instances=new Map,this.handlers=new Map}return e.prototype.on=function(e,t){this.handlers.set(e,t)},e.prototype.dispatch=function(e){if("CANCEL"!==e.type){var t=this.handlers.get(e.type);if(!t)throw new Error("Unhandled invocation '".concat(e.type,"'"));var n=t(e.payload,this.dependencies);e.managed&&this.instances.set(e.type,n),n.start()}else if(this.instances.has(e.payload)){var r=this.instances.get(e.payload);null==r||r.cancel(),this.instances.delete(e.payload)}},e.prototype.dispose=function(){var e,t;try{for(var n=s(this.instances.entries()),r=n.next();!r.done;r=n.next()){var o=a(r.value,2),i=o[0];o[1].cancel(),this.instances.delete(i)}}catch(t){e={error:t}}finally{try{r&&!r.done&&(t=n.return)&&t.call(n)}finally{if(e)throw e.error}}},e}();function nt(e,t){var n=function(){for(var n=[],r=0;r0&&r(e),[2]}))}))}))),s.on(ht.type,ut((function(e,t,n){var r=n.emitStatus;return o(s,void 0,void 0,(function(){return i(this,(function(t){return r(e),[2]}))}))}))),s.on(ft.type,ut((function(e,n,r){var a=r.receiveMessages,u=r.delay,c=r.config;return o(s,void 0,void 0,(function(){var r,o;return i(this,(function(i){switch(i.label){case 0:return c.retryConfiguration&&c.retryConfiguration.shouldRetry(e.reason,e.attempts)?(n.throwIfAborted(),[4,u(c.retryConfiguration.getDelay(e.attempts,e.reason))]):[3,6];case 1:i.sent(),n.throwIfAborted(),i.label=2;case 2:return i.trys.push([2,4,,5]),[4,a({abortSignal:n,channels:e.channels,channelGroups:e.groups,timetoken:e.cursor.timetoken,region:e.cursor.region,filterExpression:c.filterExpression})];case 3:return r=i.sent(),[2,t.transition(Pt(r.metadata,r.messages))];case 4:return(o=i.sent())instanceof Error&&"Aborted"===o.message?[2]:o instanceof q?[2,t.transition(Et(o))]:[3,5];case 5:return[3,7];case 6:return[2,t.transition(At(new q(c.retryConfiguration.getGiveupReason(e.reason,e.attempts))))];case 7:return[2]}}))}))}))),s.on(dt.type,ut((function(e,r,a){var u=a.handshake,c=a.delay,l=a.presenceState,p=a.config;return o(s,void 0,void 0,(function(){var o,s;return i(this,(function(i){switch(i.label){case 0:return p.retryConfiguration&&p.retryConfiguration.shouldRetry(e.reason,e.attempts)?(r.throwIfAborted(),[4,c(p.retryConfiguration.getDelay(e.attempts,e.reason))]):[3,6];case 1:i.sent(),r.throwIfAborted(),i.label=2;case 2:return i.trys.push([2,4,,5]),[4,u(n({abortSignal:r,channels:e.channels,channelGroups:e.groups,filterExpression:p.filterExpression},p.maintainPresenceState&&{state:l}))];case 3:return o=i.sent(),[2,t.transition(vt(o))];case 4:return(s=i.sent())instanceof Error&&"Aborted"===s.message?[2]:s instanceof q?[2,t.transition(_t(s))]:[3,5];case 5:return[3,7];case 6:return[2,t.transition(St(new q(p.retryConfiguration.getGiveupReason(e.reason,e.attempts))))];case 7:return[2]}}))}))}))),s}return t(r,e),r}(tt),Mt=new Ze("HANDSHAKE_FAILED");Mt.on(yt.type,(function(e,t){return Ft.with({channels:t.payload.channels,groups:t.payload.groups,cursor:e.cursor})})),Mt.on(Nt.type,(function(e,t){return Ft.with({channels:e.channels,groups:e.groups,cursor:t.payload.cursor||e.cursor})})),Mt.on(gt.type,(function(e,t){var n,r;return Ft.with({channels:t.payload.channels,groups:t.payload.groups,cursor:{timetoken:t.payload.cursor.timetoken,region:t.payload.cursor.region?t.payload.cursor.region:null!==(r=null===(n=null==e?void 0:e.cursor)||void 0===n?void 0:n.region)&&void 0!==r?r:0}})})),Mt.on(Ct.type,(function(e){return Lt.with()}));var jt=new Ze("HANDSHAKE_STOPPED");jt.on(yt.type,(function(e,t){return jt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:e.cursor})})),jt.on(Nt.type,(function(e,t){return Ft.with(n(n({},e),{cursor:t.payload.cursor||e.cursor}))})),jt.on(gt.type,(function(e,t){var n;return jt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:{timetoken:t.payload.cursor.timetoken,region:t.payload.cursor.region||(null===(n=null==e?void 0:e.cursor)||void 0===n?void 0:n.region)||0}})})),jt.on(Ct.type,(function(e){return Lt.with()}));var Rt=new Ze("RECEIVE_FAILED");Rt.on(Nt.type,(function(e,t){var n;return Ft.with({channels:e.channels,groups:e.groups,cursor:{timetoken:t.payload.cursor.timetoken?null===(n=t.payload.cursor)||void 0===n?void 0:n.timetoken:e.cursor.timetoken,region:t.payload.cursor.region||e.cursor.region}})})),Rt.on(yt.type,(function(e,t){return Ft.with({channels:t.payload.channels,groups:t.payload.groups,cursor:e.cursor})})),Rt.on(gt.type,(function(e,t){return Ft.with({channels:t.payload.channels,groups:t.payload.groups,cursor:{timetoken:t.payload.cursor.timetoken,region:t.payload.cursor.region||e.cursor.region}})})),Rt.on(Ct.type,(function(e){return Lt.with(void 0)}));var xt=new Ze("RECEIVE_STOPPED");xt.on(yt.type,(function(e,t){return xt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:e.cursor})})),xt.on(gt.type,(function(e,t){return xt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:{timetoken:t.payload.cursor.timetoken,region:t.payload.cursor.region||e.cursor.region}})})),xt.on(Nt.type,(function(e,t){var n;return Ft.with({channels:e.channels,groups:e.groups,cursor:{timetoken:t.payload.cursor.timetoken?null===(n=t.payload.cursor)||void 0===n?void 0:n.timetoken:e.cursor.timetoken,region:t.payload.cursor.region||e.cursor.region}})})),xt.on(Ct.type,(function(){return Lt.with(void 0)}));var Ut=new Ze("RECEIVE_RECONNECTING");Ut.onEnter((function(e){return ft(e)})),Ut.onExit((function(){return ft.cancel})),Ut.on(Pt.type,(function(e,t){return It.with({channels:e.channels,groups:e.groups,cursor:t.payload.cursor},[pt(t.payload.events)])})),Ut.on(Et.type,(function(e,t){return Ut.with(n(n({},e),{attempts:e.attempts+1,reason:t.payload}))})),Ut.on(At.type,(function(e,t){var n;return Rt.with({groups:e.groups,channels:e.channels,cursor:e.cursor,reason:t.payload},[ht({category:k.PNDisconnectedUnexpectedlyCategory,error:null===(n=t.payload)||void 0===n?void 0:n.message})])})),Ut.on(Tt.type,(function(e){return xt.with({channels:e.channels,groups:e.groups,cursor:e.cursor},[ht({category:k.PNDisconnectedCategory})])})),Ut.on(gt.type,(function(e,t){return It.with({channels:t.payload.channels,groups:t.payload.groups,cursor:{timetoken:t.payload.cursor.timetoken,region:t.payload.cursor.region||e.cursor.region}})})),Ut.on(yt.type,(function(e,t){return It.with({channels:t.payload.channels,groups:t.payload.groups,cursor:e.cursor})})),Ut.on(Ct.type,(function(e){return Lt.with(void 0,[ht({category:k.PNDisconnectedCategory})])}));var It=new Ze("RECEIVING");It.onEnter((function(e){return lt(e.channels,e.groups,e.cursor)})),It.onExit((function(){return lt.cancel})),It.on(wt.type,(function(e,t){return It.with({channels:e.channels,groups:e.groups,cursor:t.payload.cursor},[pt(t.payload.events)])})),It.on(yt.type,(function(e,t){return 0===t.payload.channels.length&&0===t.payload.groups.length?Lt.with(void 0):It.with({cursor:e.cursor,channels:t.payload.channels,groups:t.payload.groups})})),It.on(gt.type,(function(e,t){return 0===t.payload.channels.length&&0===t.payload.groups.length?Lt.with(void 0):It.with({channels:t.payload.channels,groups:t.payload.groups,cursor:{timetoken:t.payload.cursor.timetoken,region:t.payload.cursor.region||e.cursor.region}})})),It.on(Ot.type,(function(e,t){return Ut.with(n(n({},e),{attempts:0,reason:t.payload}))})),It.on(Tt.type,(function(e){return xt.with({channels:e.channels,groups:e.groups,cursor:e.cursor},[ht({category:k.PNDisconnectedCategory})])})),It.on(Ct.type,(function(e){return Lt.with(void 0,[ht({category:k.PNDisconnectedCategory})])}));var Dt=new Ze("HANDSHAKE_RECONNECTING");Dt.onEnter((function(e){return dt(e)})),Dt.onExit((function(){return dt.cancel})),Dt.on(vt.type,(function(e,t){var n,r,o={timetoken:(null===(n=e.cursor)||void 0===n?void 0:n.timetoken)?null===(r=e.cursor)||void 0===r?void 0:r.timetoken:t.payload.cursor.timetoken,region:t.payload.cursor.region};return It.with({channels:e.channels,groups:e.groups,cursor:o},[ht({category:k.PNConnectedCategory})])})),Dt.on(_t.type,(function(e,t){return Dt.with(n(n({},e),{attempts:e.attempts+1,reason:t.payload}))})),Dt.on(St.type,(function(e,t){var n;return Mt.with({groups:e.groups,channels:e.channels,cursor:e.cursor,reason:t.payload},[ht({category:k.PNConnectionErrorCategory,error:null===(n=t.payload)||void 0===n?void 0:n.message})])})),Dt.on(Tt.type,(function(e){return jt.with({channels:e.channels,groups:e.groups,cursor:e.cursor})})),Dt.on(yt.type,(function(e,t){return Ft.with({channels:t.payload.channels,groups:t.payload.groups,cursor:e.cursor})})),Dt.on(gt.type,(function(e,t){var n,r;return Ft.with({channels:t.payload.channels,groups:t.payload.groups,cursor:{timetoken:t.payload.cursor.timetoken,region:(null===(n=t.payload.cursor)||void 0===n?void 0:n.region)||(null===(r=null==e?void 0:e.cursor)||void 0===r?void 0:r.region)||0}})})),Dt.on(Ct.type,(function(e){return Lt.with(void 0)}));var Ft=new Ze("HANDSHAKING");Ft.onEnter((function(e){return ct(e.channels,e.groups)})),Ft.onExit((function(){return ct.cancel})),Ft.on(yt.type,(function(e,t){return 0===t.payload.channels.length&&0===t.payload.groups.length?Lt.with(void 0):Ft.with({channels:t.payload.channels,groups:t.payload.groups,cursor:e.cursor})})),Ft.on(mt.type,(function(e,t){var n,r;return It.with({channels:e.channels,groups:e.groups,cursor:{timetoken:(null===(n=null==e?void 0:e.cursor)||void 0===n?void 0:n.timetoken)?null===(r=null==e?void 0:e.cursor)||void 0===r?void 0:r.timetoken:t.payload.timetoken,region:t.payload.region}},[ht({category:k.PNConnectedCategory})])})),Ft.on(bt.type,(function(e,t){return Dt.with({channels:e.channels,groups:e.groups,cursor:e.cursor,attempts:0,reason:t.payload})})),Ft.on(Tt.type,(function(e){return jt.with({channels:e.channels,groups:e.groups,cursor:e.cursor})})),Ft.on(gt.type,(function(e,t){var n;return Ft.with({channels:t.payload.channels,groups:t.payload.groups,cursor:{timetoken:t.payload.cursor.timetoken,region:t.payload.cursor.region||(null===(n=null==e?void 0:e.cursor)||void 0===n?void 0:n.region)||0}})})),Ft.on(Ct.type,(function(e){return Lt.with()}));var Lt=new Ze("UNSUBSCRIBED");Lt.on(yt.type,(function(e,t){return Ft.with({channels:t.payload.channels,groups:t.payload.groups})})),Lt.on(gt.type,(function(e,t){return Ft.with({channels:t.payload.channels,groups:t.payload.groups,cursor:t.payload.cursor})}));var Gt=function(){function e(e){var t=this;this.engine=new et,this.channels=[],this.groups=[],this.dependencies=e,this.dispatcher=new kt(this.engine,e),this._unsubscribeEngine=this.engine.subscribe((function(e){"invocationDispatched"===e.type&&t.dispatcher.dispatch(e.invocation)})),this.engine.start(Lt,void 0)}return Object.defineProperty(e.prototype,"_engine",{get:function(){return this.engine},enumerable:!1,configurable:!0}),e.prototype.subscribe=function(e){var t=this,n=e.channels,r=e.channelGroups,o=e.timetoken,i=e.withPresence;this.channels=u(u([],a(this.channels),!1),a(null!=n?n:[]),!1),this.groups=u(u([],a(this.groups),!1),a(null!=r?r:[]),!1),i&&(this.channels.map((function(e){return t.channels.push("".concat(e,"-pnpres"))})),this.groups.map((function(e){return t.groups.push("".concat(e,"-pnpres"))}))),o?this.engine.transition(gt(Array.from(new Set(u(u([],a(this.channels),!1),a(null!=n?n:[]),!1))),Array.from(new Set(u(u([],a(this.groups),!1),a(null!=r?r:[]),!1))),o)):this.engine.transition(yt(Array.from(new Set(u(u([],a(this.channels),!1),a(null!=n?n:[]),!1))),Array.from(new Set(u(u([],a(this.groups),!1),a(null!=r?r:[]),!1))))),this.dependencies.join&&this.dependencies.join({channels:Array.from(new Set(this.channels.filter((function(e){return!e.endsWith("-pnpres")})))),groups:Array.from(new Set(this.groups.filter((function(e){return!e.endsWith("-pnpres")}))))})},e.prototype.unsubscribe=function(e){var t=this,n=e.channels,r=void 0===n?[]:n,o=e.channelGroups,i=void 0===o?[]:o,s=H.removeSingleOccurance(this.channels,u(u([],a(r),!1),a(r.map((function(e){return"".concat(e,"-pnpres")}))),!1)),c=H.removeSingleOccurance(this.groups,u(u([],a(i),!1),a(i.map((function(e){return"".concat(e,"-pnpres")}))),!1));if(new Set(this.channels).size!==new Set(s).size||new Set(this.groups).size!==new Set(c).size){var l=H.findUniqueCommonElements(this.channels,r),p=H.findUniqueCommonElements(this.groups,i);this.dependencies.presenceState&&(null==l||l.forEach((function(e){return delete t.dependencies.presenceState[e]})),null==p||p.forEach((function(e){return delete t.dependencies.presenceState[e]}))),this.channels=s,this.groups=c,this.engine.transition(yt(Array.from(new Set(this.channels.slice(0))),Array.from(new Set(this.groups.slice(0))))),this.dependencies.leave&&this.dependencies.leave({channels:l.slice(0),groups:p.slice(0)})}},e.prototype.unsubscribeAll=function(){this.channels=[],this.groups=[],this.dependencies.presenceState&&(this.dependencies.presenceState={}),this.engine.transition(yt(this.channels.slice(0),this.groups.slice(0))),this.dependencies.leaveAll&&this.dependencies.leaveAll()},e.prototype.reconnect=function(e){var t=e.timetoken,n=e.region;this.engine.transition(Nt(t,n))},e.prototype.disconnect=function(){this.engine.transition(Tt()),this.dependencies.leaveAll&&this.dependencies.leaveAll()},e.prototype.getSubscribedChannels=function(){return Array.from(new Set(this.channels))},e.prototype.getSubscribedChannelGroups=function(){return Array.from(new Set(this.groups))},e.prototype.dispose=function(){this.disconnect(),this._unsubscribeEngine(),this.dispatcher.dispose()},e}(),Kt=nt("RECONNECT",(function(){return{}})),Bt=nt("DISCONNECT",(function(){return{}})),Ht=nt("JOINED",(function(e,t){return{channels:e,groups:t}})),qt=nt("LEFT",(function(e,t){return{channels:e,groups:t}})),zt=nt("LEFT_ALL",(function(){return{}})),Vt=nt("HEARTBEAT_SUCCESS",(function(e){return{statusCode:e}})),Wt=nt("HEARTBEAT_FAILURE",(function(e){return e})),Jt=nt("HEARTBEAT_GIVEUP",(function(){return{}})),$t=nt("TIMES_UP",(function(){return{}})),Qt=rt("HEARTBEAT",(function(e,t){return{channels:e,groups:t}})),Xt=rt("LEAVE",(function(e,t){return{channels:e,groups:t}})),Yt=rt("EMIT_STATUS",(function(e){return e})),Zt=ot("WAIT",(function(){return{}})),en=ot("DELAYED_HEARTBEAT",(function(e){return e})),tn=function(e){function r(t,r){var s=e.call(this,r)||this;return s.on(Qt.type,ut((function(e,r,a){var u=a.heartbeat,c=a.presenceState,l=a.config;return o(s,void 0,void 0,(function(){var r;return i(this,(function(o){switch(o.label){case 0:return o.trys.push([0,2,,3]),[4,u(n({channels:e.channels,channelGroups:e.groups},l.maintainPresenceState&&{state:c}))];case 1:return o.sent(),t.transition(Vt(200)),[3,3];case 2:return(r=o.sent())instanceof q?[2,t.transition(Wt(r))]:[3,3];case 3:return[2]}}))}))}))),s.on(Xt.type,ut((function(e,t,n){var r=n.leave,a=n.config;return o(s,void 0,void 0,(function(){return i(this,(function(t){switch(t.label){case 0:if(a.suppressLeaveEvents)return[3,4];t.label=1;case 1:return t.trys.push([1,3,,4]),[4,r({channels:e.channels,channelGroups:e.groups})];case 2:case 3:return t.sent(),[3,4];case 4:return[2]}}))}))}))),s.on(Zt.type,ut((function(e,n,r){var a=r.heartbeatDelay;return o(s,void 0,void 0,(function(){return i(this,(function(e){switch(e.label){case 0:return n.throwIfAborted(),[4,a()];case 1:return e.sent(),n.throwIfAborted(),[2,t.transition($t())]}}))}))}))),s.on(en.type,ut((function(e,r,a){var u=a.heartbeat,c=a.retryDelay,l=a.presenceState,p=a.config;return o(s,void 0,void 0,(function(){var o;return i(this,(function(i){switch(i.label){case 0:return p.retryConfiguration&&p.retryConfiguration.shouldRetry(e.reason,e.attempts)?(r.throwIfAborted(),[4,c(p.retryConfiguration.getDelay(e.attempts,e.reason))]):[3,6];case 1:i.sent(),r.throwIfAborted(),i.label=2;case 2:return i.trys.push([2,4,,5]),[4,u(n({channels:e.channels,channelGroups:e.groups},p.maintainPresenceState&&{state:l}))];case 3:return i.sent(),[2,t.transition(Vt(200))];case 4:return(o=i.sent())instanceof Error&&"Aborted"===o.message?[2]:o instanceof q?[2,t.transition(Wt(o))]:[3,5];case 5:return[3,7];case 6:return[2,t.transition(Jt())];case 7:return[2]}}))}))}))),s.on(Yt.type,ut((function(e,t,r){var a=r.emitStatus,u=r.config;return o(s,void 0,void 0,(function(){var t;return i(this,(function(r){return u.announceFailedHeartbeats&&!0===(null===(t=null==e?void 0:e.status)||void 0===t?void 0:t.error)?a(e.status):u.announceSuccessfulHeartbeats&&200===e.statusCode&&a(n(n({},e),{operation:j.PNHeartbeatOperation,error:!1})),[2]}))}))}))),s}return t(r,e),r}(tt),nn=new Ze("HEARTBEAT_STOPPED");nn.on(Ht.type,(function(e,t){return nn.with({channels:u(u([],a(e.channels),!1),a(t.payload.channels),!1),groups:u(u([],a(e.groups),!1),a(t.payload.groups),!1)})})),nn.on(qt.type,(function(e,t){return nn.with({channels:e.channels.filter((function(e){return!t.payload.channels.includes(e)})),groups:e.groups.filter((function(e){return!t.payload.groups.includes(e)}))})})),nn.on(Kt.type,(function(e,t){return an.with({channels:e.channels,groups:e.groups})})),nn.on(zt.type,(function(e,t){return un.with(void 0)}));var rn=new Ze("HEARTBEAT_COOLDOWN");rn.onEnter((function(){return Zt()})),rn.onExit((function(){return Zt.cancel})),rn.on($t.type,(function(e,t){return an.with({channels:e.channels,groups:e.groups})})),rn.on(Ht.type,(function(e,t){return an.with({channels:u(u([],a(e.channels),!1),a(t.payload.channels),!1),groups:u(u([],a(e.groups),!1),a(t.payload.groups),!1)})})),rn.on(qt.type,(function(e,t){return an.with({channels:e.channels.filter((function(e){return!t.payload.channels.includes(e)})),groups:e.groups.filter((function(e){return!t.payload.groups.includes(e)}))},[Xt(t.payload.channels,t.payload.groups)])})),rn.on(Bt.type,(function(e){return nn.with({channels:e.channels,groups:e.groups},[Xt(e.channels,e.groups)])})),rn.on(zt.type,(function(e,t){return un.with(void 0,[Xt(e.channels,e.groups)])}));var on=new Ze("HEARTBEAT_FAILED");on.on(Ht.type,(function(e,t){return an.with({channels:u(u([],a(e.channels),!1),a(t.payload.channels),!1),groups:u(u([],a(e.groups),!1),a(t.payload.groups),!1)})})),on.on(qt.type,(function(e,t){return an.with({channels:e.channels.filter((function(e){return!t.payload.channels.includes(e)})),groups:e.groups.filter((function(e){return!t.payload.groups.includes(e)}))},[Xt(t.payload.channels,t.payload.groups)])})),on.on(Kt.type,(function(e,t){return an.with({channels:e.channels,groups:e.groups})})),on.on(Bt.type,(function(e,t){return nn.with({channels:e.channels,groups:e.groups},[Xt(e.channels,e.groups)])})),on.on(zt.type,(function(e,t){return un.with(void 0,[Xt(e.channels,e.groups)])}));var sn=new Ze("HEARBEAT_RECONNECTING");sn.onEnter((function(e){return en(e)})),sn.onExit((function(){return en.cancel})),sn.on(Ht.type,(function(e,t){return an.with({channels:u(u([],a(e.channels),!1),a(t.payload.channels),!1),groups:u(u([],a(e.groups),!1),a(t.payload.groups),!1)})})),sn.on(qt.type,(function(e,t){return an.with({channels:e.channels.filter((function(e){return!t.payload.channels.includes(e)})),groups:e.groups.filter((function(e){return!t.payload.groups.includes(e)}))},[Xt(t.payload.channels,t.payload.groups)])})),sn.on(Bt.type,(function(e,t){nn.with({channels:e.channels,groups:e.groups},[Xt(e.channels,e.groups)])})),sn.on(Vt.type,(function(e,t){return rn.with({channels:e.channels,groups:e.groups})})),sn.on(Wt.type,(function(e,t){return sn.with(n(n({},e),{attempts:e.attempts+1,reason:t.payload}))})),sn.on(Jt.type,(function(e,t){return on.with({channels:e.channels,groups:e.groups})})),sn.on(zt.type,(function(e,t){return un.with(void 0,[Xt(e.channels,e.groups)])}));var an=new Ze("HEARTBEATING");an.onEnter((function(e){return Qt(e.channels,e.groups)})),an.on(Vt.type,(function(e,t){return rn.with({channels:e.channels,groups:e.groups})})),an.on(Ht.type,(function(e,t){return an.with({channels:u(u([],a(e.channels),!1),a(t.payload.channels),!1),groups:u(u([],a(e.groups),!1),a(t.payload.groups),!1)})})),an.on(qt.type,(function(e,t){return an.with({channels:e.channels.filter((function(e){return!t.payload.channels.includes(e)})),groups:e.groups.filter((function(e){return!t.payload.groups.includes(e)}))},[Xt(t.payload.channels,t.payload.groups)])})),an.on(Wt.type,(function(e,t){return sn.with(n(n({},e),{attempts:0,reason:t.payload}))})),an.on(Bt.type,(function(e){return nn.with({channels:e.channels,groups:e.groups},[Xt(e.channels,e.groups)])})),an.on(zt.type,(function(e,t){return un.with(void 0,[Xt(e.channels,e.groups)])}));var un=new Ze("HEARTBEAT_INACTIVE");un.on(Ht.type,(function(e,t){return an.with({channels:t.payload.channels,groups:t.payload.groups})}));var cn=function(){function e(e){var t=this;this.engine=new et,this.channels=[],this.groups=[],this.dispatcher=new tn(this.engine,e),this.dependencies=e,this._unsubscribeEngine=this.engine.subscribe((function(e){"invocationDispatched"===e.type&&t.dispatcher.dispatch(e.invocation)})),this.engine.start(un,void 0)}return Object.defineProperty(e.prototype,"_engine",{get:function(){return this.engine},enumerable:!1,configurable:!0}),e.prototype.join=function(e){var t=e.channels,n=e.groups;this.channels=u(u([],a(this.channels),!1),a(null!=t?t:[]),!1),this.groups=u(u([],a(this.groups),!1),a(null!=n?n:[]),!1),this.engine.transition(Ht(this.channels.slice(0),this.groups.slice(0)))},e.prototype.leave=function(e){var t=this,n=e.channels,r=e.groups;this.dependencies.presenceState&&(null==n||n.forEach((function(e){return delete t.dependencies.presenceState[e]})),null==r||r.forEach((function(e){return delete t.dependencies.presenceState[e]}))),this.engine.transition(qt(null!=n?n:[],null!=r?r:[]))},e.prototype.leaveAll=function(){this.engine.transition(zt())},e.prototype.dispose=function(){this._unsubscribeEngine(),this.dispatcher.dispose()},e}(),ln=function(){function e(){}return e.LinearRetryPolicy=function(e){return{delay:e.delay,maximumRetry:e.maximumRetry,shouldRetry:function(e,t){var n;return 403!==(null===(n=null==e?void 0:e.status)||void 0===n?void 0:n.statusCode)&&this.maximumRetry>t},getDelay:function(e,t){var n;return 1e3*((null!==(n=t.retryAfter)&&void 0!==n?n:this.delay)+Math.random())},getGiveupReason:function(e,t){var n;return this.maximumRetry<=t?"retry attempts exhaused.":403===(null===(n=null==e?void 0:e.status)||void 0===n?void 0:n.statusCode)?"forbidden operation.":"unknown error"}}},e.ExponentialRetryPolicy=function(e){return{minimumDelay:e.minimumDelay,maximumDelay:e.maximumDelay,maximumRetry:e.maximumRetry,shouldRetry:function(e,t){var n;return 403!==(null===(n=null==e?void 0:e.status)||void 0===n?void 0:n.statusCode)&&this.maximumRetry>t},getDelay:function(e,t){var n;return 1e3*((null!==(n=t.retryAfter)&&void 0!==n?n:Math.min(Math.pow(2,e),this.maximumDelay))+Math.random())},getGiveupReason:function(e,t){var n;return this.maximumRetry<=t?"retry attempts exhaused.":403===(null===(n=null==e?void 0:e.status)||void 0===n?void 0:n.statusCode)?"forbidden operation.":"unknown error"}}},e}(),pn=function(){function e(e){var t=e.modules,n=e.listenerManager,r=e.getFileUrl;this.modules=t,this.listenerManager=n,this.getFileUrl=r,this._channelListenerMap=new Map,this._groupListenerMap=new Map,t.cryptoModule&&(this._decoder=new TextDecoder)}return e.prototype.emitEvent=function(e){var t=e.channel,o=e.publishMetaData,i=e.subscriptionMatch;if(t===i&&(i=null),e.channel.endsWith("-pnpres")){var s={channel:null,subscription:null};t&&(s.channel=t.substring(0,t.lastIndexOf("-pnpres"))),i&&(s.subscription=i.substring(0,i.lastIndexOf("-pnpres"))),s.action=e.payload.action,s.state=e.payload.data,s.timetoken=o.timetoken,s.occupancy=e.payload.occupancy,s.uuid=e.payload.uuid,s.timestamp=e.payload.timestamp,e.payload.join&&(s.join=e.payload.join),e.payload.leave&&(s.leave=e.payload.leave),e.payload.timeout&&(s.timeout=e.payload.timeout),s.actualChannel=null!=i?t:null,s.subscribedChannel=null!=i?i:t,this.listenerManager.announcePresence(s),this._announce("presence",s,s.channel,s.subscription)}else if(1===e.messageType){(s={channel:null,subscription:null}).channel=t,s.subscription=i,s.timetoken=o.timetoken,s.publisher=e.issuingClientId,e.userMetadata&&(s.userMetadata=e.userMetadata),s.message=e.payload,this.listenerManager.announceSignal(s),this._announce("signal",s,s.channel,s.subscription)}else if(2===e.messageType){if((s={channel:null,subscription:null}).channel=t,s.subscription=i,s.timetoken=o.timetoken,s.publisher=e.issuingClientId,e.userMetadata&&(s.userMetadata=e.userMetadata),s.message={event:e.payload.event,type:e.payload.type,data:e.payload.data},this.listenerManager.announceObjects(s),this._announce("objects",s,s.channel,s.subscription),"uuid"===e.payload.type){var a=this._renameChannelField(s),u=n(n({},a),{message:n(n({},a.message),{event:this._renameEvent(a.message.event),type:"user"})});this.listenerManager.announceUser(u),this._announce("user",u,s.channel,s.subscription)}else if("channel"===e.payload.type){a=this._renameChannelField(s);var c=n(n({},a),{message:n(n({},a.message),{event:this._renameEvent(a.message.event),type:"space"})});this.listenerManager.announceSpace(c),this._announce("space",c,s.channel,s.subscription)}else if("membership"===e.payload.type){var l=(a=this._renameChannelField(s)).message.data,p=l.uuid,h=l.channel,f=r(l,["uuid","channel"]);f.user=p,f.space=h;var d=n(n({},a),{message:n(n({},a.message),{event:this._renameEvent(a.message.event),data:f})});this.listenerManager.announceMembership(d),this._announce("membership",d,s.channel,s.subscription)}}else if(3===e.messageType){(s={}).channel=t,s.subscription=i,s.timetoken=o.timetoken,s.publisher=e.issuingClientId,s.data={messageTimetoken:e.payload.data.messageTimetoken,actionTimetoken:e.payload.data.actionTimetoken,type:e.payload.data.type,uuid:e.issuingClientId,value:e.payload.data.value},s.event=e.payload.event,this.listenerManager.announceMessageAction(s),this._announce("messageAction",s,s.channel,s.subscription)}else if(4===e.messageType){(s={}).channel=t,s.subscription=i,s.timetoken=o.timetoken,s.publisher=e.issuingClientId;var y=e.payload;if(this.modules.cryptoModule){var g=void 0;try{g=(m=this.modules.cryptoModule.decrypt(e.payload))instanceof ArrayBuffer?JSON.parse(this._decoder.decode(m)):m}catch(e){g=null,s.error="Error while decrypting message content: ".concat(e.message)}null!==g&&(y=g)}e.userMetadata&&(s.userMetadata=e.userMetadata),s.message=y.message,s.file={id:y.file.id,name:y.file.name,url:this.getFileUrl({id:y.file.id,name:y.file.name,channel:t})},this.listenerManager.announceFile(s),this._announce("file",s,s.channel,s.subscription)}else{if((s={channel:null,subscription:null}).channel=t,s.subscription=i,s.timetoken=o.timetoken,s.publisher=e.issuingClientId,e.userMetadata&&(s.userMetadata=e.userMetadata),this.modules.cryptoModule){g=void 0;try{var m;g=(m=this.modules.cryptoModule.decrypt(e.payload))instanceof ArrayBuffer?JSON.parse(this._decoder.decode(m)):m}catch(e){g=null,s.error="Error while decrypting message content: ".concat(e.message)}s.message=null!=g?g:e.payload}else s.message=e.payload;s.actualChannel=null!=i?t:null,s.subscribedChannel=null!=i?i:t,this.listenerManager.announceMessage(s),this._announce("message",s,s.channel,s.subscription)}},e.prototype.addListener=function(e,t,n){var r=this;t&&n?(null==t||t.forEach((function(t){r._channelListenerMap[t]?r._channelListenerMap[t].includes(e)||r._channelListenerMap[t].push(e):r._channelListenerMap[t]=[e]})),null==n||n.forEach((function(t){r._groupListenerMap[t]?r._groupListenerMap[t].includes(e)||r._groupListenerMap[t].push(e):r._groupListenerMap[t]=[e]}))):this.listenerManager.addListener(e)},e.prototype.removeListener=function(e,t,n){var r=this;t&&n?(null==t||t.forEach((function(t){var n;r._channelListenerMap[t]=null===(n=r._channelListenerMap[t])||void 0===n?void 0:n.filter((function(t){return t!==e}))})),null==n||n.forEach((function(t){var n;r._groupListenerMap[t]=null===(n=r._groupListenerMap[t])||void 0===n?void 0:n.filter((function(t){return t!==e}))}))):this.listenerManager.removeListener(e)},e.prototype.removeAllListeners=function(){this.listenerManager.removeAllListeners()},e.prototype._renameEvent=function(e){return"set"===e?"updated":"removed"},e.prototype._renameChannelField=function(e){var t=e.channel,n=r(e,["channel"]);return n.spaceId=t,n},e.prototype._announce=function(e,t,n,r){var o,i;null===(o=this._channelListenerMap[n])||void 0===o||o.forEach((function(n){return n[e]&&n[e](t)})),null===(i=this._groupListenerMap[r])||void 0===i||i.forEach((function(n){return n[e]&&n[e](t)}))},e}(),hn=function(){function e(){}return e.prototype.subscribe=function(){var e,t;this.pubnub.subscribe(n({channels:this.channelNames,channelGroups:this.groupNames},(null===(t=null===(e=this.options)||void 0===e?void 0:e.cursor)||void 0===t?void 0:t.timetoken)&&{timetoken:this.options.cursor.timetoken}))},e.prototype.unsubscribe=function(){this.pubnub.unsubscribe({channels:this.channelNames.filter((function(e){return!e.endsWith("-pnpres")})),channelGroups:this.groupNames.filter((function(e){return!e.endsWith("-pnpres")}))})},Object.defineProperty(e.prototype,"onMessage",{set:function(e){this.listener.message=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"onPresence",{set:function(e){this.listener.presence=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"onSignal",{set:function(e){this.listener.signal=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"onObjects",{set:function(e){this.listener.objects=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"onMessageAction",{set:function(e){this.listener.messageAction=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"onFile",{set:function(e){this.listener.file=e},enumerable:!1,configurable:!0}),e.prototype.addListener=function(e){this.eventEmitter.addListener(e,this.channelNames.filter((function(e){return!e.endsWith("-pnpres")})),this.groupNames.filter((function(e){return!e.endsWith("-pnpres")})))},e.prototype.removeListener=function(e){this.eventEmitter.removeListener(e,this.channelNames,this.groupNames)},Object.defineProperty(e.prototype,"channels",{get:function(){return this.channelNames.slice(0)},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"channelGroups",{get:function(){return this.groupNames.slice(0)},enumerable:!1,configurable:!0}),e}(),fn=function(e){function n(t){var n=t.channels,r=void 0===n?[]:n,o=t.channelGroups,i=void 0===o?[]:o,s=t.subscriptionOptions,c=t.eventEmitter,l=t.pubnub,p=e.call(this)||this;return p.channelNames=[],p.groupNames=[],p.subscriptionList=[],p.options=s,p.eventEmitter=c,p.pubnub=l,r.filter((function(e){return!e.endsWith("-pnpres")})).forEach((function(e){var t=p.pubnub.channel(e).subscription(p.options);p.channelNames=u(u([],a(p.channelNames),!1),a(t.channels),!1),p.subscriptionList.push(t)})),i.filter((function(e){return!e.endsWith("-pnpres")})).forEach((function(e){var t=p.pubnub.channelGroup(e).subscription(p.options);p.groupNames=u(u([],a(p.groupNames),!1),a(t.channelGroups),!1),p.subscriptionList.push(t)})),p.listener={},c.addListener(p.listener,p.channelNames.filter((function(e){return!e.endsWith("-pnpres")})),p.groupNames.filter((function(e){return!e.endsWith("-pnpres")}))),p}return t(n,e),n.prototype.addSubscription=function(e){this.subscriptionList.push(e),this.channelNames=u(u([],a(this.channelNames),!1),a(e.channels),!1),this.groupNames=u(u([],a(this.groupNames),!1),a(e.channelGroups),!1),this.eventEmitter.addListener(this.listener,e.channels,e.channelGroups)},n.prototype.removeSubscription=function(e){var t=e.channels,n=e.channelGroups;this.channelNames=this.channelNames.filter((function(e){return!t.includes(e)})),this.groupNames=this.groupNames.filter((function(e){return!n.includes(e)})),this.subscriptionList=this.subscriptionList.filter((function(t){return t!==e})),this.eventEmitter.removeListener(this.listener,t,n)},n.prototype.addSubscriptionSet=function(e){this.subscriptionList=u(u([],a(this.subscriptionList),!1),a(e.subscriptions),!1),this.channelNames=u(u([],a(this.channelNames),!1),a(e.channels),!1),this.groupNames=u(u([],a(this.groupNames),!1),a(e.channelGroups),!1),this.eventEmitter.addListener(this.listener,e.channels,e.channelGroups)},n.prototype.removeSubscriptionSet=function(e){var t=e.channels,n=e.channelGroups;this.channelNames=this.channelNames.filter((function(e){return!t.includes(e)})),this.groupNames=this.groupNames.filter((function(e){return!n.includes(e)})),this.subscriptionList=this.subscriptionList.filter((function(t){return!e.subscriptions.includes(t)})),this.eventEmitter.removeListener(this.listener,t,n)},Object.defineProperty(n.prototype,"subscriptions",{get:function(){return this.subscriptionList.slice(0)},enumerable:!1,configurable:!0}),n}(hn),dn=function(e){function r(t){var n=t.channels,r=t.channelGroups,o=t.subscriptionOptions,i=t.eventEmitter,s=t.pubnub,a=e.call(this)||this;return a.channelNames=[],a.groupNames=[],a.channelNames=n,a.groupNames=r,a.options=o,a.pubnub=s,a.eventEmitter=i,a.listener={},i.addListener(a.listener,a.channelNames.filter((function(e){return!e.endsWith("-pnpres")})),a.groupNames.filter((function(e){return!e.endsWith("-pnpres")}))),a}return t(r,e),r.prototype.addSubscription=function(e){return new fn({channels:u(u([],a(this.channelNames),!1),a(e.channels),!1),channelGroups:u(u([],a(this.groupNames),!1),a(e.channelGroups),!1),subscriptionOptions:n(n({},this.options),null==e?void 0:e.options),eventEmitter:this.eventEmitter,pubnub:this.pubnub})},r}(hn),yn=function(){function e(e,t,n){this.name=e,this.eventEmitter=t,this.pubnub=n}return e.prototype.subscription=function(e){return new dn({channels:(null==e?void 0:e.receivePresenceEvents)?[this.name,"".concat(this.name,"-pnpres")]:[this.name],channelGroups:[],subscriptionOptions:e,eventEmitter:this.eventEmitter,pubnub:this.pubnub})},e}(),gn=function(){function e(e,t,n){this.name=e,this.eventEmitter=t,this.pubnub=n}return e.prototype.subscription=function(e){return new dn({channels:[],channelGroups:(null==e?void 0:e.receivePresenceEvents)?[this.name,"".concat(this.name,"-pnpres")]:[this.name],subscriptionOptions:e,eventEmitter:this.eventEmitter,pubnub:this.pubnub})},e}(),mn=function(){function e(e,t,n){this.id=e,this.eventEmitter=t,this.pubnub=n}return e.prototype.subscription=function(e){return new dn({channels:[this.id],channelGroups:[],subscriptionOptions:e,eventEmitter:this.eventEmitter,pubnub:this.pubnub})},e}(),bn=function(){function e(e,t,n){this.id=e,this.eventEmitter=t,this.pubnub=n}return e.prototype.subscription=function(e){return new dn({channels:[this.id],channelGroups:[],subscriptionOptions:e,eventEmitter:this.eventEmitter,pubnub:this.pubnub})},e}(),vn=function(){function e(e){var t=this,r=e.networking,o=e.cbor,i=new g({setup:e});this._config=i;var c=new T({config:i}),l=e.cryptography;r.init(i);var p=new G(i,o);this._tokenManager=p;var h=new R({maximumSamplesCount:6e4});this._telemetryManager=h;var f=this._config.cryptoModule,d={config:i,networking:r,crypto:c,cryptography:l,tokenManager:p,telemetryManager:h,PubNubFile:e.PubNubFile,cryptoModule:f};this.File=e.PubNubFile,this.encryptFile=function(e,t){return 1==arguments.length&&"string"!=typeof e&&d.cryptoModule?(t=e,d.cryptoModule.encryptFile(t,this.File)):l.encryptFile(e,t,this.File)},this.decryptFile=function(e,t){return 1==arguments.length&&"string"!=typeof e&&d.cryptoModule?(t=e,d.cryptoModule.decryptFile(t,this.File)):l.decryptFile(e,t,this.File)};var y=Q.bind(this,d,Je),m=Q.bind(this,d,se),v=Q.bind(this,d,ue),_=Q.bind(this,d,le),S=Q.bind(this,d,$e),w=new L;if(this._listenerManager=w,this.iAmHere=Q.bind(this,d,ue),this.iAmAway=Q.bind(this,d,se),this.setPresenceState=Q.bind(this,d,le),this.handshake=Q.bind(this,d,Qe),this.receiveMessages=Q.bind(this,d,Xe),this._eventEmitter=new pn({modules:d,listenerManager:this._listenerManager,getFileUrl:function(e){return ve(d,e)}}),!0===i.enableEventEngine){if(i.maintainPresenceState&&(this.presenceState={},this.setState=function(e){var n,r;return null===(n=e.channels)||void 0===n||n.forEach((function(n){return t.presenceState[n]=e.state})),null===(r=e.channelGroups)||void 0===r||r.forEach((function(n){return t.presenceState[n]=e.state})),t.setPresenceState({channels:e.channels,channelGroups:e.channelGroups,state:t.presenceState})}),i.getHeartbeatInterval()){var O=new cn({heartbeat:this.iAmHere,leave:this.iAmAway,heartbeatDelay:function(){return new Promise((function(e){return setTimeout(e,1e3*d.config.getHeartbeatInterval())}))},retryDelay:function(e){return new Promise((function(t){return setTimeout(t,e)}))},config:d.config,presenceState:this.presenceState,emitStatus:function(e){w.announceStatus(e)}});this.presenceEventEngine=O,this.join=this.presenceEventEngine.join.bind(O),this.leave=this.presenceEventEngine.leave.bind(O),this.leaveAll=this.presenceEventEngine.leaveAll.bind(O)}var P=new Gt({handshake:this.handshake,receiveMessages:this.receiveMessages,delay:function(e){return new Promise((function(t){return setTimeout(t,e)}))},join:this.join,leave:this.leave,leaveAll:this.leaveAll,presenceState:this.presenceState,config:d.config,emitMessages:function(e){var n,r;try{for(var o=s(e),i=o.next();!i.done;i=o.next()){var a=i.value;t._eventEmitter.emitEvent(a)}}catch(e){n={error:e}}finally{try{i&&!i.done&&(r=o.return)&&r.call(o)}finally{if(n)throw n.error}}},emitStatus:function(e){w.announceStatus(e)}});this.subscribe=P.subscribe.bind(P),this.unsubscribe=P.unsubscribe.bind(P),this.unsubscribeAll=P.unsubscribeAll.bind(P),this.reconnect=P.reconnect.bind(P),this.disconnect=P.disconnect.bind(P),this.destroy=P.dispose.bind(P),this.getSubscribedChannels=P.getSubscribedChannels.bind(P),this.getSubscribedChannelGroups=P.getSubscribedChannelGroups.bind(P),this.eventEngine=P}else{var E=new M({timeEndpoint:y,leaveEndpoint:m,heartbeatEndpoint:v,setStateEndpoint:_,subscribeEndpoint:S,crypto:d.crypto,config:d.config,listenerManager:w,getFileUrl:function(e){return ve(d,e)},cryptoModule:d.cryptoModule,eventEmitter:this._eventEmitter});this.subscribe=E.adaptSubscribeChange.bind(E),this.unsubscribe=E.adaptUnsubscribeChange.bind(E),this.disconnect=E.disconnect.bind(E),this.reconnect=E.reconnect.bind(E),this.unsubscribeAll=E.unsubscribeAll.bind(E),this.getSubscribedChannels=E.getSubscribedChannels.bind(E),this.getSubscribedChannelGroups=E.getSubscribedChannelGroups.bind(E),this.setState=E.adaptStateChange.bind(E),this.presence=E.adaptPresenceChange.bind(E),this.destroy=function(e){E.unsubscribeAll(e),E.disconnect()}}this.addListener=this._eventEmitter.addListener.bind(this._eventEmitter),this.removeListener=this._eventEmitter.removeListener.bind(this._eventEmitter),this.removeAllListeners=this._eventEmitter.removeAllListeners.bind(this._eventEmitter),this.parseToken=p.parseToken.bind(p),this.setToken=p.setToken.bind(p),this.getToken=p.getToken.bind(p),this.channelGroups={listGroups:Q.bind(this,d,ee),listChannels:Q.bind(this,d,te),addChannels:Q.bind(this,d,X),removeChannels:Q.bind(this,d,Y),deleteGroup:Q.bind(this,d,Z)},this.push={addChannels:Q.bind(this,d,ne),removeChannels:Q.bind(this,d,re),deleteDevice:Q.bind(this,d,ie),listChannels:Q.bind(this,d,oe)},this.hereNow=Q.bind(this,d,pe),this.whereNow=Q.bind(this,d,ae),this.getState=Q.bind(this,d,ce),this.grant=Q.bind(this,d,Ue),this.grantToken=Q.bind(this,d,Le),this.audit=Q.bind(this,d,xe),this.revokeToken=Q.bind(this,d,Ge),this.publish=Q.bind(this,d,Be),this.fire=function(e,n){return e.replicate=!1,e.storeInHistory=!1,t.publish(e,n)},this.signal=Q.bind(this,d,He),this.history=Q.bind(this,d,qe),this.deleteMessages=Q.bind(this,d,ze),this.messageCounts=Q.bind(this,d,Ve),this.fetchMessages=Q.bind(this,d,We),this.addMessageAction=Q.bind(this,d,he),this.removeMessageAction=Q.bind(this,d,fe),this.getMessageActions=Q.bind(this,d,de),this.listFiles=Q.bind(this,d,ye);var A=Q.bind(this,d,ge);this.publishFile=Q.bind(this,d,me),this.sendFile=be({generateUploadUrl:A,publishFile:this.publishFile,modules:d}),this.getFileUrl=function(e){return ve(d,e)},this.downloadFile=Q.bind(this,d,_e),this.deleteFile=Q.bind(this,d,Se),this.channel=function(e){return new yn(e,t._eventEmitter,t)},this.channelGroup=function(e){return new gn(e,t._eventEmitter,t)},this.channelMetadata=function(e){return new mn(e,t._eventEmitter,t)},this.userMetadata=function(e){return new bn(e,t._eventEmitter,t)},this.subscriptionSet=function(e){return new fn({channels:e.channels,channelGroups:e.channelGroups,subscriptionOptions:e.subscriptionOptions,eventEmitter:t._eventEmitter,pubnub:t})},this.objects={getAllUUIDMetadata:Q.bind(this,d,we),getUUIDMetadata:Q.bind(this,d,Oe),setUUIDMetadata:Q.bind(this,d,Pe),removeUUIDMetadata:Q.bind(this,d,Ee),getAllChannelMetadata:Q.bind(this,d,Ae),getChannelMetadata:Q.bind(this,d,Te),setChannelMetadata:Q.bind(this,d,Ne),removeChannelMetadata:Q.bind(this,d,Ce),getChannelMembers:Q.bind(this,d,ke),setChannelMembers:function(e){for(var r=[],o=1;o=this._config.origin.length&&(this._currentSubDomain=0);var t=this._config.origin[this._currentSubDomain];return"".concat(e).concat(t)},e.prototype.hasModule=function(e){return e in this._modules},e.prototype.shiftStandardOrigin=function(){return this._standardOrigin=this.nextOrigin(),this._standardOrigin},e.prototype.getStandardOrigin=function(){return this._standardOrigin},e.prototype.POSTFILE=function(e,t,n){return this._modules.postfile(e,t,n)},e.prototype.GETFILE=function(e,t,n){return this._modules.getfile(e,t,n)},e.prototype.POST=function(e,t,n,r){return this._modules.post(e,t,n,r)},e.prototype.PATCH=function(e,t,n,r){return this._modules.patch(e,t,n,r)},e.prototype.GET=function(e,t,n){return this._modules.get(e,t,n)},e.prototype.DELETE=function(e,t,n){return this._modules.del(e,t,n)},e.prototype._detectErrorCategory=function(e){if("ENOTFOUND"===e.code)return k.PNNetworkIssuesCategory;if("ECONNREFUSED"===e.code)return k.PNNetworkIssuesCategory;if("ECONNRESET"===e.code)return k.PNNetworkIssuesCategory;if("EAI_AGAIN"===e.code)return k.PNNetworkIssuesCategory;if(0===e.status||e.hasOwnProperty("status")&&void 0===e.status)return k.PNNetworkIssuesCategory;if(e.timeout)return k.PNTimeoutCategory;if("ETIMEDOUT"===e.code)return k.PNNetworkIssuesCategory;if(e.response){if(e.response.badRequest)return k.PNBadRequestCategory;if(e.response.forbidden)return k.PNAccessDeniedCategory}return k.PNUnknownCategory},e}();function Sn(e){var t=function(e){return e&&"object"==typeof e&&e.constructor===Object};if(!t(e))return e;var n={};return Object.keys(e).forEach((function(r){var o=function(e){return"string"==typeof e||e instanceof String}(r),i=r,s=e[r];Array.isArray(r)||o&&r.indexOf(",")>=0?i=(o?r.split(","):r).reduce((function(e,t){return e+=String.fromCharCode(t)}),""):(function(e){return"number"==typeof e&&isFinite(e)}(r)||o&&!isNaN(r))&&(i=String.fromCharCode(o?parseInt(r,10):10));n[i]=t(s)?Sn(s):s})),n}var wn=function(){function e(e,t){this._base64ToBinary=t,this._decode=e}return e.prototype.decodeToken=function(e){var t="";e.length%4==3?t="=":e.length%4==2&&(t="==");var n=e.replace(/-/gi,"+").replace(/_/gi,"/")+t,r=this._decode(this._base64ToBinary(n));if("object"==typeof r)return r},e}(),On={exports:{}},Pn={exports:{}};!function(e){function t(e){if(e)return function(e){for(var n in t.prototype)e[n]=t.prototype[n];return e}(e)}e.exports=t,t.prototype.on=t.prototype.addEventListener=function(e,t){return this._callbacks=this._callbacks||{},(this._callbacks["$"+e]=this._callbacks["$"+e]||[]).push(t),this},t.prototype.once=function(e,t){function n(){this.off(e,n),t.apply(this,arguments)}return n.fn=t,this.on(e,n),this},t.prototype.off=t.prototype.removeListener=t.prototype.removeAllListeners=t.prototype.removeEventListener=function(e,t){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var n,r=this._callbacks["$"+e];if(!r)return this;if(1==arguments.length)return delete this._callbacks["$"+e],this;for(var o=0;os.depthLimit)return void jn(An,e,t,o);if(void 0!==s.edgesLimit&&n+1>s.edgesLimit)return void jn(An,e,t,o);if(r.push(e),Array.isArray(e))for(a=0;at?1:0}function Un(e,t,n,r){void 0===r&&(r=kn());var o,i=In(e,"",0,[],void 0,0,r)||e;try{o=0===Cn.length?JSON.stringify(i,t,n):JSON.stringify(i,Dn(t),n)}catch(e){return JSON.stringify("[unable to serialize, circular reference is too complex to analyze]")}finally{for(;0!==Nn.length;){var s=Nn.pop();4===s.length?Object.defineProperty(s[0],s[1],s[3]):s[0][s[1]]=s[2]}}return o}function In(e,t,n,r,o,i,s){var a;if(i+=1,"object"==typeof e&&null!==e){for(a=0;as.depthLimit)return void jn(An,e,t,o);if(void 0!==s.edgesLimit&&n+1>s.edgesLimit)return void jn(An,e,t,o);if(r.push(e),Array.isArray(e))for(a=0;a0)for(var r=0;r1&&"boolean"!=typeof t)throw new Qn('"allowMissing" argument must be a boolean');var n=gr(e),r=n.length>0?n[0]:"",o=mr("%"+r+"%",t),i=o.name,s=o.value,a=!1,u=o.alias;u&&(r=u[0],pr(n,lr([0,1],u)));for(var c=1,l=!0;c=n.length){var d=Yn(s,p);s=(l=!!d)&&"get"in d&&!("originalValue"in d.get)?d.get:s[p]}else l=cr(s,p),s=s[p];l&&!a&&(ir[i]=s)}}return s},vr={exports:{}};!function(e){var t=Vn,n=br,r=n("%Function.prototype.apply%"),o=n("%Function.prototype.call%"),i=n("%Reflect.apply%",!0)||t.call(o,r),s=n("%Object.getOwnPropertyDescriptor%",!0),a=n("%Object.defineProperty%",!0),u=n("%Math.max%");if(a)try{a({},"a",{value:1})}catch(e){a=null}e.exports=function(e){var n=i(t,o,arguments);if(s&&a){var r=s(n,"length");r.configurable&&a(n,"length",{value:1+u(0,e.length-(arguments.length-1))})}return n};var c=function(){return i(t,r,arguments)};a?a(e.exports,"apply",{value:c}):e.exports.apply=c}(vr);var _r=br,Sr=vr.exports,wr=Sr(_r("String.prototype.indexOf")),Or=l(Object.freeze({__proto__:null,default:{}})),Pr="function"==typeof Map&&Map.prototype,Er=Object.getOwnPropertyDescriptor&&Pr?Object.getOwnPropertyDescriptor(Map.prototype,"size"):null,Ar=Pr&&Er&&"function"==typeof Er.get?Er.get:null,Tr=Pr&&Map.prototype.forEach,Nr="function"==typeof Set&&Set.prototype,Cr=Object.getOwnPropertyDescriptor&&Nr?Object.getOwnPropertyDescriptor(Set.prototype,"size"):null,kr=Nr&&Cr&&"function"==typeof Cr.get?Cr.get:null,Mr=Nr&&Set.prototype.forEach,jr="function"==typeof WeakMap&&WeakMap.prototype?WeakMap.prototype.has:null,Rr="function"==typeof WeakSet&&WeakSet.prototype?WeakSet.prototype.has:null,xr="function"==typeof WeakRef&&WeakRef.prototype?WeakRef.prototype.deref:null,Ur=Boolean.prototype.valueOf,Ir=Object.prototype.toString,Dr=Function.prototype.toString,Fr=String.prototype.match,Lr=String.prototype.slice,Gr=String.prototype.replace,Kr=String.prototype.toUpperCase,Br=String.prototype.toLowerCase,Hr=RegExp.prototype.test,qr=Array.prototype.concat,zr=Array.prototype.join,Vr=Array.prototype.slice,Wr=Math.floor,Jr="function"==typeof BigInt?BigInt.prototype.valueOf:null,$r=Object.getOwnPropertySymbols,Qr="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?Symbol.prototype.toString:null,Xr="function"==typeof Symbol&&"object"==typeof Symbol.iterator,Yr="function"==typeof Symbol&&Symbol.toStringTag&&(typeof Symbol.toStringTag===Xr||"symbol")?Symbol.toStringTag:null,Zr=Object.prototype.propertyIsEnumerable,eo=("function"==typeof Reflect?Reflect.getPrototypeOf:Object.getPrototypeOf)||([].__proto__===Array.prototype?function(e){return e.__proto__}:null);function to(e,t){if(e===1/0||e===-1/0||e!=e||e&&e>-1e3&&e<1e3||Hr.call(/e/,t))return t;var n=/[0-9](?=(?:[0-9]{3})+(?![0-9]))/g;if("number"==typeof e){var r=e<0?-Wr(-e):Wr(e);if(r!==e){var o=String(r),i=Lr.call(t,o.length+1);return Gr.call(o,n,"$&_")+"."+Gr.call(Gr.call(i,/([0-9]{3})/g,"$&_"),/_$/,"")}}return Gr.call(t,n,"$&_")}var no=Or,ro=no.custom,oo=co(ro)?ro:null;function io(e,t,n){var r="double"===(n.quoteStyle||t)?'"':"'";return r+e+r}function so(e){return Gr.call(String(e),/"/g,""")}function ao(e){return!("[object Array]"!==ho(e)||Yr&&"object"==typeof e&&Yr in e)}function uo(e){return!("[object RegExp]"!==ho(e)||Yr&&"object"==typeof e&&Yr in e)}function co(e){if(Xr)return e&&"object"==typeof e&&e instanceof Symbol;if("symbol"==typeof e)return!0;if(!e||"object"!=typeof e||!Qr)return!1;try{return Qr.call(e),!0}catch(e){}return!1}var lo=Object.prototype.hasOwnProperty||function(e){return e in this};function po(e,t){return lo.call(e,t)}function ho(e){return Ir.call(e)}function fo(e,t){if(e.indexOf)return e.indexOf(t);for(var n=0,r=e.length;nt.maxStringLength){var n=e.length-t.maxStringLength,r="... "+n+" more character"+(n>1?"s":"");return yo(Lr.call(e,0,t.maxStringLength),t)+r}return io(Gr.call(Gr.call(e,/(['\\])/g,"\\$1"),/[\x00-\x1f]/g,go),"single",t)}function go(e){var t=e.charCodeAt(0),n={8:"b",9:"t",10:"n",12:"f",13:"r"}[t];return n?"\\"+n:"\\x"+(t<16?"0":"")+Kr.call(t.toString(16))}function mo(e){return"Object("+e+")"}function bo(e){return e+" { ? }"}function vo(e,t,n,r){return e+" ("+t+") {"+(r?_o(n,r):zr.call(n,", "))+"}"}function _o(e,t){if(0===e.length)return"";var n="\n"+t.prev+t.base;return n+zr.call(e,","+n)+"\n"+t.prev}function So(e,t){var n=ao(e),r=[];if(n){r.length=e.length;for(var o=0;o-1?Sr(n):n},Po=function e(t,n,r,o){var i=n||{};if(po(i,"quoteStyle")&&"single"!==i.quoteStyle&&"double"!==i.quoteStyle)throw new TypeError('option "quoteStyle" must be "single" or "double"');if(po(i,"maxStringLength")&&("number"==typeof i.maxStringLength?i.maxStringLength<0&&i.maxStringLength!==1/0:null!==i.maxStringLength))throw new TypeError('option "maxStringLength", if provided, must be a positive integer, Infinity, or `null`');var s=!po(i,"customInspect")||i.customInspect;if("boolean"!=typeof s&&"symbol"!==s)throw new TypeError("option \"customInspect\", if provided, must be `true`, `false`, or `'symbol'`");if(po(i,"indent")&&null!==i.indent&&"\t"!==i.indent&&!(parseInt(i.indent,10)===i.indent&&i.indent>0))throw new TypeError('option "indent" must be "\\t", an integer > 0, or `null`');if(po(i,"numericSeparator")&&"boolean"!=typeof i.numericSeparator)throw new TypeError('option "numericSeparator", if provided, must be `true` or `false`');var a=i.numericSeparator;if(void 0===t)return"undefined";if(null===t)return"null";if("boolean"==typeof t)return t?"true":"false";if("string"==typeof t)return yo(t,i);if("number"==typeof t){if(0===t)return 1/0/t>0?"0":"-0";var u=String(t);return a?to(t,u):u}if("bigint"==typeof t){var l=String(t)+"n";return a?to(t,l):l}var p=void 0===i.depth?5:i.depth;if(void 0===r&&(r=0),r>=p&&p>0&&"object"==typeof t)return ao(t)?"[Array]":"[Object]";var h=function(e,t){var n;if("\t"===e.indent)n="\t";else{if(!("number"==typeof e.indent&&e.indent>0))return null;n=zr.call(Array(e.indent+1)," ")}return{base:n,prev:zr.call(Array(t+1),n)}}(i,r);if(void 0===o)o=[];else if(fo(o,t)>=0)return"[Circular]";function f(t,n,s){if(n&&(o=Vr.call(o)).push(n),s){var a={depth:i.depth};return po(i,"quoteStyle")&&(a.quoteStyle=i.quoteStyle),e(t,a,r+1,o)}return e(t,i,r+1,o)}if("function"==typeof t&&!uo(t)){var d=function(e){if(e.name)return e.name;var t=Fr.call(Dr.call(e),/^function\s*([\w$]+)/);if(t)return t[1];return null}(t),y=So(t,f);return"[Function"+(d?": "+d:" (anonymous)")+"]"+(y.length>0?" { "+zr.call(y,", ")+" }":"")}if(co(t)){var g=Xr?Gr.call(String(t),/^(Symbol\(.*\))_[^)]*$/,"$1"):Qr.call(t);return"object"!=typeof t||Xr?g:mo(g)}if(function(e){if(!e||"object"!=typeof e)return!1;if("undefined"!=typeof HTMLElement&&e instanceof HTMLElement)return!0;return"string"==typeof e.nodeName&&"function"==typeof e.getAttribute}(t)){for(var m="<"+Br.call(String(t.nodeName)),b=t.attributes||[],v=0;v"}if(ao(t)){if(0===t.length)return"[]";var _=So(t,f);return h&&!function(e){for(var t=0;t=0)return!1;return!0}(_)?"["+_o(_,h)+"]":"[ "+zr.call(_,", ")+" ]"}if(function(e){return!("[object Error]"!==ho(e)||Yr&&"object"==typeof e&&Yr in e)}(t)){var S=So(t,f);return"cause"in Error.prototype||!("cause"in t)||Zr.call(t,"cause")?0===S.length?"["+String(t)+"]":"{ ["+String(t)+"] "+zr.call(S,", ")+" }":"{ ["+String(t)+"] "+zr.call(qr.call("[cause]: "+f(t.cause),S),", ")+" }"}if("object"==typeof t&&s){if(oo&&"function"==typeof t[oo]&&no)return no(t,{depth:p-r});if("symbol"!==s&&"function"==typeof t.inspect)return t.inspect()}if(function(e){if(!Ar||!e||"object"!=typeof e)return!1;try{Ar.call(e);try{kr.call(e)}catch(e){return!0}return e instanceof Map}catch(e){}return!1}(t)){var w=[];return Tr&&Tr.call(t,(function(e,n){w.push(f(n,t,!0)+" => "+f(e,t))})),vo("Map",Ar.call(t),w,h)}if(function(e){if(!kr||!e||"object"!=typeof e)return!1;try{kr.call(e);try{Ar.call(e)}catch(e){return!0}return e instanceof Set}catch(e){}return!1}(t)){var O=[];return Mr&&Mr.call(t,(function(e){O.push(f(e,t))})),vo("Set",kr.call(t),O,h)}if(function(e){if(!jr||!e||"object"!=typeof e)return!1;try{jr.call(e,jr);try{Rr.call(e,Rr)}catch(e){return!0}return e instanceof WeakMap}catch(e){}return!1}(t))return bo("WeakMap");if(function(e){if(!Rr||!e||"object"!=typeof e)return!1;try{Rr.call(e,Rr);try{jr.call(e,jr)}catch(e){return!0}return e instanceof WeakSet}catch(e){}return!1}(t))return bo("WeakSet");if(function(e){if(!xr||!e||"object"!=typeof e)return!1;try{return xr.call(e),!0}catch(e){}return!1}(t))return bo("WeakRef");if(function(e){return!("[object Number]"!==ho(e)||Yr&&"object"==typeof e&&Yr in e)}(t))return mo(f(Number(t)));if(function(e){if(!e||"object"!=typeof e||!Jr)return!1;try{return Jr.call(e),!0}catch(e){}return!1}(t))return mo(f(Jr.call(t)));if(function(e){return!("[object Boolean]"!==ho(e)||Yr&&"object"==typeof e&&Yr in e)}(t))return mo(Ur.call(t));if(function(e){return!("[object String]"!==ho(e)||Yr&&"object"==typeof e&&Yr in e)}(t))return mo(f(String(t)));if("undefined"!=typeof window&&t===window)return"{ [object Window] }";if(t===c)return"{ [object globalThis] }";if(!function(e){return!("[object Date]"!==ho(e)||Yr&&"object"==typeof e&&Yr in e)}(t)&&!uo(t)){var P=So(t,f),E=eo?eo(t)===Object.prototype:t instanceof Object||t.constructor===Object,A=t instanceof Object?"":"null prototype",T=!E&&Yr&&Object(t)===t&&Yr in t?Lr.call(ho(t),8,-1):A?"Object":"",N=(E||"function"!=typeof t.constructor?"":t.constructor.name?t.constructor.name+" ":"")+(T||A?"["+zr.call(qr.call([],T||[],A||[]),": ")+"] ":"");return 0===P.length?N+"{}":h?N+"{"+_o(P,h)+"}":N+"{ "+zr.call(P,", ")+" }"}return String(t)},Eo=wo("%TypeError%"),Ao=wo("%WeakMap%",!0),To=wo("%Map%",!0),No=Oo("WeakMap.prototype.get",!0),Co=Oo("WeakMap.prototype.set",!0),ko=Oo("WeakMap.prototype.has",!0),Mo=Oo("Map.prototype.get",!0),jo=Oo("Map.prototype.set",!0),Ro=Oo("Map.prototype.has",!0),xo=function(e,t){for(var n,r=e;null!==(n=r.next);r=n)if(n.key===t)return r.next=n.next,n.next=e.next,e.next=n,n},Uo=String.prototype.replace,Io=/%20/g,Do="RFC3986",Fo={default:Do,formatters:{RFC1738:function(e){return Uo.call(e,Io,"+")},RFC3986:function(e){return String(e)}},RFC1738:"RFC1738",RFC3986:Do},Lo=Fo,Go=Object.prototype.hasOwnProperty,Ko=Array.isArray,Bo=function(){for(var e=[],t=0;t<256;++t)e.push("%"+((t<16?"0":"")+t.toString(16)).toUpperCase());return e}(),Ho=function(e,t){for(var n=t&&t.plainObjects?Object.create(null):{},r=0;r1;){var t=e.pop(),n=t.obj[t.prop];if(Ko(n)){for(var r=[],o=0;o=48&&u<=57||u>=65&&u<=90||u>=97&&u<=122||o===Lo.RFC1738&&(40===u||41===u)?s+=i.charAt(a):u<128?s+=Bo[u]:u<2048?s+=Bo[192|u>>6]+Bo[128|63&u]:u<55296||u>=57344?s+=Bo[224|u>>12]+Bo[128|u>>6&63]+Bo[128|63&u]:(a+=1,u=65536+((1023&u)<<10|1023&i.charCodeAt(a)),s+=Bo[240|u>>18]+Bo[128|u>>12&63]+Bo[128|u>>6&63]+Bo[128|63&u])}return s},isBuffer:function(e){return!(!e||"object"!=typeof e)&&!!(e.constructor&&e.constructor.isBuffer&&e.constructor.isBuffer(e))},isRegExp:function(e){return"[object RegExp]"===Object.prototype.toString.call(e)},maybeMap:function(e,t){if(Ko(e)){for(var n=[],r=0;r0?b.join(",")||null:void 0}];else if(Qo(u))O=u;else{var E=Object.keys(b);O=c?E.sort(c):E}for(var A=o&&Qo(b)&&1===b.length?n+"[]":n,T=0;T-1?e.split(","):e},li=function(e,t,n,r){if(e){var o=n.allowDots?e.replace(/\.([^.[]+)/g,"[$1]"):e,i=/(\[[^[\]]*])/g,s=n.depth>0&&/(\[[^[\]]*])/.exec(o),a=s?o.slice(0,s.index):o,u=[];if(a){if(!n.plainObjects&&ii.call(Object.prototype,a)&&!n.allowPrototypes)return;u.push(a)}for(var c=0;n.depth>0&&null!==(s=i.exec(o))&&c=0;--i){var s,a=e[i];if("[]"===a&&n.parseArrays)s=[].concat(o);else{s=n.plainObjects?Object.create(null):{};var u="["===a.charAt(0)&&"]"===a.charAt(a.length-1)?a.slice(1,-1):a,c=parseInt(u,10);n.parseArrays||""!==u?!isNaN(c)&&a!==u&&String(c)===u&&c>=0&&n.parseArrays&&c<=n.arrayLimit?(s=[])[c]=o:"__proto__"!==u&&(s[u]=o):s={0:o}}o=s}return o}(u,t,n,r)}},pi=function(e,t){var n,r=e,o=function(e){if(!e)return ti;if(null!==e.encoder&&void 0!==e.encoder&&"function"!=typeof e.encoder)throw new TypeError("Encoder has to be a function.");var t=e.charset||ti.charset;if(void 0!==e.charset&&"utf-8"!==e.charset&&"iso-8859-1"!==e.charset)throw new TypeError("The charset option must be either utf-8, iso-8859-1, or undefined");var n=Wo.default;if(void 0!==e.format){if(!Jo.call(Wo.formatters,e.format))throw new TypeError("Unknown format option provided.");n=e.format}var r=Wo.formatters[n],o=ti.filter;return("function"==typeof e.filter||Qo(e.filter))&&(o=e.filter),{addQueryPrefix:"boolean"==typeof e.addQueryPrefix?e.addQueryPrefix:ti.addQueryPrefix,allowDots:void 0===e.allowDots?ti.allowDots:!!e.allowDots,charset:t,charsetSentinel:"boolean"==typeof e.charsetSentinel?e.charsetSentinel:ti.charsetSentinel,delimiter:void 0===e.delimiter?ti.delimiter:e.delimiter,encode:"boolean"==typeof e.encode?e.encode:ti.encode,encoder:"function"==typeof e.encoder?e.encoder:ti.encoder,encodeValuesOnly:"boolean"==typeof e.encodeValuesOnly?e.encodeValuesOnly:ti.encodeValuesOnly,filter:o,format:n,formatter:r,serializeDate:"function"==typeof e.serializeDate?e.serializeDate:ti.serializeDate,skipNulls:"boolean"==typeof e.skipNulls?e.skipNulls:ti.skipNulls,sort:"function"==typeof e.sort?e.sort:null,strictNullHandling:"boolean"==typeof e.strictNullHandling?e.strictNullHandling:ti.strictNullHandling}}(t);"function"==typeof o.filter?r=(0,o.filter)("",r):Qo(o.filter)&&(n=o.filter);var i,s=[];if("object"!=typeof r||null===r)return"";i=t&&t.arrayFormat in $o?t.arrayFormat:t&&"indices"in t?t.indices?"indices":"repeat":"indices";var a=$o[i];if(t&&"commaRoundTrip"in t&&"boolean"!=typeof t.commaRoundTrip)throw new TypeError("`commaRoundTrip` must be a boolean, or absent");var u="comma"===a&&t&&t.commaRoundTrip;n||(n=Object.keys(r)),o.sort&&n.sort(o.sort);for(var c=zo(),l=0;l0?f+h:""},hi={formats:Fo,parse:function(e,t){var n=function(e){if(!e)return ai;if(null!==e.decoder&&void 0!==e.decoder&&"function"!=typeof e.decoder)throw new TypeError("Decoder has to be a function.");if(void 0!==e.charset&&"utf-8"!==e.charset&&"iso-8859-1"!==e.charset)throw new TypeError("The charset option must be either utf-8, iso-8859-1, or undefined");var t=void 0===e.charset?ai.charset:e.charset;return{allowDots:void 0===e.allowDots?ai.allowDots:!!e.allowDots,allowPrototypes:"boolean"==typeof e.allowPrototypes?e.allowPrototypes:ai.allowPrototypes,allowSparse:"boolean"==typeof e.allowSparse?e.allowSparse:ai.allowSparse,arrayLimit:"number"==typeof e.arrayLimit?e.arrayLimit:ai.arrayLimit,charset:t,charsetSentinel:"boolean"==typeof e.charsetSentinel?e.charsetSentinel:ai.charsetSentinel,comma:"boolean"==typeof e.comma?e.comma:ai.comma,decoder:"function"==typeof e.decoder?e.decoder:ai.decoder,delimiter:"string"==typeof e.delimiter||oi.isRegExp(e.delimiter)?e.delimiter:ai.delimiter,depth:"number"==typeof e.depth||!1===e.depth?+e.depth:ai.depth,ignoreQueryPrefix:!0===e.ignoreQueryPrefix,interpretNumericEntities:"boolean"==typeof e.interpretNumericEntities?e.interpretNumericEntities:ai.interpretNumericEntities,parameterLimit:"number"==typeof e.parameterLimit?e.parameterLimit:ai.parameterLimit,parseArrays:!1!==e.parseArrays,plainObjects:"boolean"==typeof e.plainObjects?e.plainObjects:ai.plainObjects,strictNullHandling:"boolean"==typeof e.strictNullHandling?e.strictNullHandling:ai.strictNullHandling}}(t);if(""===e||null==e)return n.plainObjects?Object.create(null):{};for(var r="string"==typeof e?function(e,t){var n,r={__proto__:null},o=t.ignoreQueryPrefix?e.replace(/^\?/,""):e,i=t.parameterLimit===1/0?void 0:t.parameterLimit,s=o.split(t.delimiter,i),a=-1,u=t.charset;if(t.charsetSentinel)for(n=0;n-1&&(l=si(l)?[l]:l),ii.call(r,c)?r[c]=oi.combine(r[c],l):r[c]=l}return r}(e,n):e,o=n.plainObjects?Object.create(null):{},i=Object.keys(r),s=0;s=e.length?{done:!0}:{done:!1,value:e[o++]}},e:function(e){throw e},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var s,a=!0,u=!1;return{s:function(){r=r.call(e)},n:function(){var e=r.next();return a=e.done,e},e:function(e){u=!0,s=e},f:function(){try{a||null==r.return||r.return()}finally{if(u)throw s}}}}function n(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);ne.split(/ *; */).shift(),e.params=e=>{const n={};var r,o=t(e.split(/ *; */));try{for(o.s();!(r=o.n()).done;){const e=r.value.split(/ *= */),t=e.shift(),o=e.shift();t&&o&&(n[t]=o)}}catch(e){o.e(e)}finally{o.f()}return n},e.parseLinks=e=>{const n={};var r,o=t(e.split(/ *, */));try{for(o.s();!(r=o.n()).done;){const e=r.value.split(/ *; */),t=e[0].slice(1,-1);n[e[1].split(/ *= */)[1].slice(1,-1)]=t}}catch(e){o.e(e)}finally{o.f()}return n},e.cleanHeader=(e,t)=>(delete e["content-type"],delete e["content-length"],delete e["transfer-encoding"],delete e.host,t&&(delete e.authorization,delete e.cookie),e),e.isObject=e=>null!==e&&"object"==typeof e,e.hasOwn=Object.hasOwn||function(e,t){if(null==e)throw new TypeError("Cannot convert undefined or null to object");return Object.prototype.hasOwnProperty.call(new Object(e),t)},e.mixin=(t,n)=>{for(const r in n)e.hasOwn(n,r)&&(t[r]=n[r])}}(fi);const di=Or,yi=fi.isObject,gi=fi.hasOwn;var mi=bi;function bi(){}bi.prototype.clearTimeout=function(){return clearTimeout(this._timer),clearTimeout(this._responseTimeoutTimer),clearTimeout(this._uploadTimeoutTimer),delete this._timer,delete this._responseTimeoutTimer,delete this._uploadTimeoutTimer,this},bi.prototype.parse=function(e){return this._parser=e,this},bi.prototype.responseType=function(e){return this._responseType=e,this},bi.prototype.serialize=function(e){return this._serializer=e,this},bi.prototype.timeout=function(e){if(!e||"object"!=typeof e)return this._timeout=e,this._responseTimeout=0,this._uploadTimeout=0,this;for(const t in e)if(gi(e,t))switch(t){case"deadline":this._timeout=e.deadline;break;case"response":this._responseTimeout=e.response;break;case"upload":this._uploadTimeout=e.upload;break;default:console.warn("Unknown timeout option",t)}return this},bi.prototype.retry=function(e,t){return 0!==arguments.length&&!0!==e||(e=1),e<=0&&(e=0),this._maxRetries=e,this._retries=0,this._retryCallback=t,this};const vi=new Set(["ETIMEDOUT","ECONNRESET","EADDRINUSE","ECONNREFUSED","EPIPE","ENOTFOUND","ENETUNREACH","EAI_AGAIN"]),_i=new Set([408,413,429,500,502,503,504,521,522,524]);bi.prototype._shouldRetry=function(e,t){if(!this._maxRetries||this._retries++>=this._maxRetries)return!1;if(this._retryCallback)try{const n=this._retryCallback(e,t);if(!0===n)return!0;if(!1===n)return!1}catch(e){console.error(e)}if(t&&t.status&&_i.has(t.status))return!0;if(e){if(e.code&&vi.has(e.code))return!0;if(e.timeout&&"ECONNABORTED"===e.code)return!0;if(e.crossDomain)return!0}return!1},bi.prototype._retry=function(){return this.clearTimeout(),this.req&&(this.req=null,this.req=this.request()),this._aborted=!1,this.timedout=!1,this.timedoutError=null,this._end()},bi.prototype.then=function(e,t){if(!this._fullfilledPromise){const e=this;this._endCalled&&console.warn("Warning: superagent request was sent twice, because both .end() and .then() were called. Never call .end() if you use promises"),this._fullfilledPromise=new Promise(((t,n)=>{e.on("abort",(()=>{if(this._maxRetries&&this._maxRetries>this._retries)return;if(this.timedout&&this.timedoutError)return void n(this.timedoutError);const e=new Error("Aborted");e.code="ABORTED",e.status=this.status,e.method=this.method,e.url=this.url,n(e)})),e.end(((e,r)=>{e?n(e):t(r)}))}))}return this._fullfilledPromise.then(e,t)},bi.prototype.catch=function(e){return this.then(void 0,e)},bi.prototype.use=function(e){return e(this),this},bi.prototype.ok=function(e){if("function"!=typeof e)throw new Error("Callback required");return this._okCallback=e,this},bi.prototype._isResponseOK=function(e){return!!e&&(this._okCallback?this._okCallback(e):e.status>=200&&e.status<300)},bi.prototype.get=function(e){return this._header[e.toLowerCase()]},bi.prototype.getHeader=bi.prototype.get,bi.prototype.set=function(e,t){if(yi(e)){for(const t in e)gi(e,t)&&this.set(t,e[t]);return this}return this._header[e.toLowerCase()]=t,this.header[e]=t,this},bi.prototype.unset=function(e){return delete this._header[e.toLowerCase()],delete this.header[e],this},bi.prototype.field=function(e,t,n){if(null==e)throw new Error(".field(name, val) name can not be empty");if(this._data)throw new Error(".field() can't be used if .send() is used. Please use only .send() or only .field() & .attach()");if(yi(e)){for(const t in e)gi(e,t)&&this.field(t,e[t]);return this}if(Array.isArray(t)){for(const n in t)gi(t,n)&&this.field(e,t[n]);return this}if(null==t)throw new Error(".field(name, val) val can not be empty");return"boolean"==typeof t&&(t=String(t)),n?this._getFormData().append(e,t,n):this._getFormData().append(e,t),this},bi.prototype.abort=function(){if(this._aborted)return this;if(this._aborted=!0,this.xhr&&this.xhr.abort(),this.req){if(di.gte(process.version,"v13.0.0")&&di.lt(process.version,"v14.0.0"))throw new Error("Superagent does not work in v13 properly with abort() due to Node.js core changes");this.req.abort()}return this.clearTimeout(),this.emit("abort"),this},bi.prototype._auth=function(e,t,n,r){switch(n.type){case"basic":this.set("Authorization",`Basic ${r(`${e}:${t}`)}`);break;case"auto":this.username=e,this.password=t;break;case"bearer":this.set("Authorization",`Bearer ${e}`)}return this},bi.prototype.withCredentials=function(e){return void 0===e&&(e=!0),this._withCredentials=e,this},bi.prototype.redirects=function(e){return this._maxRedirects=e,this},bi.prototype.maxResponseSize=function(e){if("number"!=typeof e)throw new TypeError("Invalid argument");return this._maxResponseSize=e,this},bi.prototype.toJSON=function(){return{method:this.method,url:this.url,data:this._data,headers:this._header}},bi.prototype.send=function(e){const t=yi(e);let n=this._header["content-type"];if(this._formData)throw new Error(".send() can't be used if .attach() or .field() is used. Please use only .send() or only .field() & .attach()");if(t&&!this._data)Array.isArray(e)?this._data=[]:this._isHost(e)||(this._data={});else if(e&&this._data&&this._isHost(this._data))throw new Error("Can't merge these send calls");if(t&&yi(this._data))for(const t in e){if("bigint"==typeof e[t]&&!e[t].toJSON)throw new Error("Cannot serialize BigInt value to json");gi(e,t)&&(this._data[t]=e[t])}else{if("bigint"==typeof e)throw new Error("Cannot send value of type BigInt");"string"==typeof e?(n||this.type("form"),n=this._header["content-type"],n&&(n=n.toLowerCase().trim()),this._data="application/x-www-form-urlencoded"===n?this._data?`${this._data}&${e}`:e:(this._data||"")+e):this._data=e}return!t||this._isHost(e)||n||this.type("json"),this},bi.prototype.sortQuery=function(e){return this._sort=void 0===e||e,this},bi.prototype._finalizeQueryString=function(){const e=this._query.join("&");if(e&&(this.url+=(this.url.includes("?")?"&":"?")+e),this._query.length=0,this._sort){const e=this.url.indexOf("?");if(e>=0){const t=this.url.slice(e+1).split("&");"function"==typeof this._sort?t.sort(this._sort):t.sort(),this.url=this.url.slice(0,e)+"?"+t.join("&")}}},bi.prototype._appendQueryString=()=>{console.warn("Unsupported")},bi.prototype._timeoutError=function(e,t,n){if(this._aborted)return;const r=new Error(`${e+t}ms exceeded`);r.timeout=t,r.code="ECONNABORTED",r.errno=n,this.timedout=!0,this.timedoutError=r,this.abort(),this.callback(r)},bi.prototype._setTimeouts=function(){const e=this;this._timeout&&!this._timer&&(this._timer=setTimeout((()=>{e._timeoutError("Timeout of ",e._timeout,"ETIME")}),this._timeout)),this._responseTimeout&&!this._responseTimeoutTimer&&(this._responseTimeoutTimer=setTimeout((()=>{e._timeoutError("Response timeout of ",e._responseTimeout,"ETIMEDOUT")}),this._responseTimeout))};const Si=fi;var wi=Oi;function Oi(){}function Pi(e,t){var n="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(!n){if(Array.isArray(e)||(n=function(e,t){if(!e)return;if("string"==typeof e)return Ei(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return Ei(e,t)}(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var r=0,o=function(){};return{s:o,n:function(){return r>=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:o}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var i,s=!0,a=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return s=e.done,e},e:function(e){a=!0,i=e},f:function(){try{s||null==n.return||n.return()}finally{if(a)throw i}}}}function Ei(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n=e.length?{done:!0}:{done:!1,value:e[o++]}},e:function(e){throw e},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var s,a=!0,u=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return a=e.done,e},e:function(e){u=!0,s=e},f:function(){try{a||null==n.return||n.return()}finally{if(u)throw s}}}}function r(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n{if(o.XMLHttpRequest)return new o.XMLHttpRequest;throw new Error("Browser-only version of superagent could not find XHR")};const g="".trim?e=>e.trim():e=>e.replace(/(^\s*|\s*$)/g,"");function m(e){if(!c(e))return e;const t=[];for(const n in e)p(e,n)&&b(t,n,e[n]);return t.join("&")}function b(e,t,r){if(void 0!==r)if(null!==r)if(Array.isArray(r)){var o,i=n(r);try{for(i.s();!(o=i.n()).done;){b(e,t,o.value)}}catch(e){i.e(e)}finally{i.f()}}else if(c(r))for(const n in r)p(r,n)&&b(e,`${t}[${n}]`,r[n]);else e.push(encodeURI(t)+"="+encodeURIComponent(r));else e.push(encodeURI(t))}function v(e){const t={},n=e.split("&");let r,o;for(let e=0,i=n.length;e{let e,t=null,r=null;try{r=new S(n)}catch(e){return t=new Error("Parser is unable to parse the response"),t.parse=!0,t.original=e,n.xhr?(t.rawResponse=void 0===n.xhr.responseType?n.xhr.responseText:n.xhr.response,t.status=n.xhr.status?n.xhr.status:null,t.statusCode=t.status):(t.rawResponse=null,t.status=null),n.callback(t)}n.emit("response",r);try{n._isResponseOK(r)||(e=new Error(r.statusText||r.text||"Unsuccessful HTTP response"))}catch(t){e=t}e?(e.original=t,e.response=r,e.status=e.status||r.status,n.callback(e,r)):n.callback(null,r)}))}y.serializeObject=m,y.parseString=v,y.types={html:"text/html",json:"application/json",xml:"text/xml",urlencoded:"application/x-www-form-urlencoded",form:"application/x-www-form-urlencoded","form-data":"application/x-www-form-urlencoded"},y.serialize={"application/x-www-form-urlencoded":a.stringify,"application/json":s},y.parse={"application/x-www-form-urlencoded":v,"application/json":JSON.parse},l(S.prototype,h.prototype),S.prototype._parseBody=function(e){let t=y.parse[this.type];return this.req._parser?this.req._parser(this,e):(!t&&_(this.type)&&(t=y.parse["application/json"]),t&&e&&(e.length>0||e instanceof Object)?t(e):null)},S.prototype.toError=function(){const e=this.req,t=e.method,n=e.url,r=`cannot ${t} ${n} (${this.status})`,o=new Error(r);return o.status=this.status,o.method=t,o.url=n,o},y.Response=S,i(w.prototype),l(w.prototype,u.prototype),w.prototype.type=function(e){return this.set("Content-Type",y.types[e]||e),this},w.prototype.accept=function(e){return this.set("Accept",y.types[e]||e),this},w.prototype.auth=function(e,t,n){1===arguments.length&&(t=""),"object"==typeof t&&null!==t&&(n=t,t=""),n||(n={type:"function"==typeof btoa?"basic":"auto"});const r=n.encoder?n.encoder:e=>{if("function"==typeof btoa)return btoa(e);throw new Error("Cannot use basic auth, btoa is not a function")};return this._auth(e,t,n,r)},w.prototype.query=function(e){return"string"!=typeof e&&(e=m(e)),e&&this._query.push(e),this},w.prototype.attach=function(e,t,n){if(t){if(this._data)throw new Error("superagent can't mix .send() and .attach()");this._getFormData().append(e,t,n||t.name)}return this},w.prototype._getFormData=function(){return this._formData||(this._formData=new o.FormData),this._formData},w.prototype.callback=function(e,t){if(this._shouldRetry(e,t))return this._retry();const n=this._callback;this.clearTimeout(),e&&(this._maxRetries&&(e.retries=this._retries-1),this.emit("error",e)),n(e,t)},w.prototype.crossDomainError=function(){const e=new Error("Request has been terminated\nPossible causes: the network is offline, Origin is not allowed by Access-Control-Allow-Origin, the page is being unloaded, etc.");e.crossDomain=!0,e.status=this.status,e.method=this.method,e.url=this.url,this.callback(e)},w.prototype.agent=function(){return console.warn("This is not supported in browser version of superagent"),this},w.prototype.ca=w.prototype.agent,w.prototype.buffer=w.prototype.ca,w.prototype.write=()=>{throw new Error("Streaming is not supported in browser version of superagent")},w.prototype.pipe=w.prototype.write,w.prototype._isHost=function(e){return e&&"object"==typeof e&&!Array.isArray(e)&&"[object Object]"!==Object.prototype.toString.call(e)},w.prototype.end=function(e){this._endCalled&&console.warn("Warning: .end() was called twice. This is not supported in superagent"),this._endCalled=!0,this._callback=e||d,this._finalizeQueryString(),this._end()},w.prototype._setUploadTimeout=function(){const e=this;this._uploadTimeout&&!this._uploadTimeoutTimer&&(this._uploadTimeoutTimer=setTimeout((()=>{e._timeoutError("Upload timeout of ",e._uploadTimeout,"ETIMEDOUT")}),this._uploadTimeout))},w.prototype._end=function(){if(this._aborted)return this.callback(new Error("The request has been aborted even before .end() was called"));const e=this;this.xhr=y.getXHR();const t=this.xhr;let n=this._formData||this._data;this._setTimeouts(),t.addEventListener("readystatechange",(()=>{const n=t.readyState;if(n>=2&&e._responseTimeoutTimer&&clearTimeout(e._responseTimeoutTimer),4!==n)return;let r;try{r=t.status}catch(e){r=0}if(!r){if(e.timedout||e._aborted)return;return e.crossDomainError()}e.emit("end")}));const r=(t,n)=>{n.total>0&&(n.percent=n.loaded/n.total*100,100===n.percent&&clearTimeout(e._uploadTimeoutTimer)),n.direction=t,e.emit("progress",n)};if(this.hasListeners("progress"))try{t.addEventListener("progress",r.bind(null,"download")),t.upload&&t.upload.addEventListener("progress",r.bind(null,"upload"))}catch(e){}t.upload&&this._setUploadTimeout();try{this.username&&this.password?t.open(this.method,this.url,!0,this.username,this.password):t.open(this.method,this.url,!0)}catch(e){return this.callback(e)}if(this._withCredentials&&(t.withCredentials=!0),!this._formData&&"GET"!==this.method&&"HEAD"!==this.method&&"string"!=typeof n&&!this._isHost(n)){const e=this._header["content-type"];let t=this._serializer||y.serialize[e?e.split(";")[0]:""];!t&&_(e)&&(t=y.serialize["application/json"]),t&&(n=t(n))}for(const e in this.header)null!==this.header[e]&&p(this.header,e)&&t.setRequestHeader(e,this.header[e]);this._responseType&&(t.responseType=this._responseType),this.emit("request",this),t.send(void 0===n?null:n)},y.agent=()=>new f;for(var O=0,P=["GET","POST","OPTIONS","PATCH","PUT","DELETE"];O{const r=y("GET",e);return"function"==typeof t&&(n=t,t=null),t&&r.query(t),n&&r.end(n),r},y.head=(e,t,n)=>{const r=y("HEAD",e);return"function"==typeof t&&(n=t,t=null),t&&r.query(t),n&&r.end(n),r},y.options=(e,t,n)=>{const r=y("OPTIONS",e);return"function"==typeof t&&(n=t,t=null),t&&r.send(t),n&&r.end(n),r},y.del=E,y.delete=E,y.patch=(e,t,n)=>{const r=y("PATCH",e);return"function"==typeof t&&(n=t,t=null),t&&r.send(t),n&&r.end(n),r},y.post=(e,t,n)=>{const r=y("POST",e);return"function"==typeof t&&(n=t,t=null),t&&r.send(t),n&&r.end(n),r},y.put=(e,t,n)=>{const r=y("PUT",e);return"function"==typeof t&&(n=t,t=null),t&&r.send(t),n&&r.end(n),r}}(On,On.exports);var ki=On.exports;function Mi(e){var t=(new Date).getTime(),n=(new Date).toISOString(),r=console&&console.log?console:window&&window.console&&window.console.log?window.console:console;r.log("<<<<<"),r.log("[".concat(n,"]"),"\n",e.url,"\n",e.qs),r.log("-----"),e.on("response",(function(n){var o=(new Date).getTime()-t,i=(new Date).toISOString();r.log(">>>>>>"),r.log("[".concat(i," / ").concat(o,"]"),"\n",e.url,"\n",e.qs,"\n",n.text),r.log("-----")}))}function ji(e,t,n){var r=this;this._config.logVerbosity&&(e=e.use(Mi)),this._config.proxy&&this._modules.proxy&&(e=this._modules.proxy.call(this,e)),this._config.keepAlive&&this._modules.keepAlive&&(e=this._modules.keepAlive(e));var o=e;if(t.abortSignal)var i=t.abortSignal.subscribe((function(){o.abort(),i()}));return!0===t.forceBuffered?o="undefined"==typeof Blob?o.buffer().responseType("arraybuffer"):o.responseType("arraybuffer"):!1===t.forceBuffered&&(o=o.buffer(!1)),(o=o.timeout(t.timeout)).on("abort",(function(){return n({category:k.PNUnknownCategory,error:!0,operation:t.operation,errorData:new Error("Aborted")},null)})),o.end((function(e,o){var i,s={};if(s.error=null!==e,s.operation=t.operation,o&&o.status&&(s.statusCode=o.status),e){if(e.response&&e.response.text&&!r._config.logVerbosity)try{s.errorData=JSON.parse(e.response.text)}catch(t){s.errorData=e}else s.errorData=e;return s.category=r._detectErrorCategory(e),n(s,null)}if(t.ignoreBody)i={headers:o.headers,redirects:o.redirects,response:o};else try{i=JSON.parse(o.text)}catch(e){return s.errorData=o,s.error=!0,n(s,null)}return i.error&&1===i.error&&i.status&&i.message&&i.service?(s.errorData=i,s.statusCode=i.status,s.error=!0,s.category=r._detectErrorCategory(s),n(s,null)):(i.error&&i.error.message&&(s.errorData=i.error),n(s,i))})),o}function Ri(e,t,n){return o(this,void 0,void 0,(function(){var r;return i(this,(function(o){switch(o.label){case 0:return r=ki.post(e),t.forEach((function(e){var t=e.key,n=e.value;r=r.field(t,n)})),r.attach("file",n,{contentType:"application/octet-stream"}),[4,r];case 1:return[2,o.sent()]}}))}))}function xi(e,t,n){var r=ki.get(this.getStandardOrigin()+t.url).set(t.headers).query(e);return ji.call(this,r,t,n)}function Ui(e,t,n){var r=ki.get(this.getStandardOrigin()+t.url).set(t.headers).query(e);return ji.call(this,r,t,n)}function Ii(e,t,n,r){var o=ki.post(this.getStandardOrigin()+n.url).query(e).set(n.headers).send(t);return ji.call(this,o,n,r)}function Di(e,t,n,r){var o=ki.patch(this.getStandardOrigin()+n.url).query(e).set(n.headers).send(t);return ji.call(this,o,n,r)}function Fi(e,t,n){var r=ki.delete(this.getStandardOrigin()+t.url).set(t.headers).query(e);return ji.call(this,r,t,n)}function Li(e,t){var n=new Uint8Array(e.byteLength+t.byteLength);return n.set(new Uint8Array(e),0),n.set(new Uint8Array(t),e.byteLength),n.buffer}var Gi,Ki=function(){function e(){}return Object.defineProperty(e.prototype,"algo",{get:function(){return"aes-256-cbc"},enumerable:!1,configurable:!0}),e.prototype.encrypt=function(e,t){return o(this,void 0,void 0,(function(){var n;return i(this,(function(r){switch(r.label){case 0:return[4,this.getKey(e)];case 1:if(n=r.sent(),t instanceof ArrayBuffer)return[2,this.encryptArrayBuffer(n,t)];if("string"==typeof t)return[2,this.encryptString(n,t)];throw new Error("Cannot encrypt this file. In browsers file encryption supports only string or ArrayBuffer")}}))}))},e.prototype.decrypt=function(e,t){return o(this,void 0,void 0,(function(){var n;return i(this,(function(r){switch(r.label){case 0:return[4,this.getKey(e)];case 1:if(n=r.sent(),t instanceof ArrayBuffer)return[2,this.decryptArrayBuffer(n,t)];if("string"==typeof t)return[2,this.decryptString(n,t)];throw new Error("Cannot decrypt this file. In browsers file decryption supports only string or ArrayBuffer")}}))}))},e.prototype.encryptFile=function(e,t,n){return o(this,void 0,void 0,(function(){var r,o,s;return i(this,(function(i){switch(i.label){case 0:if(t.data.byteLength<=0)throw new Error("encryption error. empty content");return[4,this.getKey(e)];case 1:return r=i.sent(),[4,t.data.arrayBuffer()];case 2:return o=i.sent(),[4,this.encryptArrayBuffer(r,o)];case 3:return s=i.sent(),[2,n.create({name:t.name,mimeType:"application/octet-stream",data:s})]}}))}))},e.prototype.decryptFile=function(e,t,n){return o(this,void 0,void 0,(function(){var r,o,s;return i(this,(function(i){switch(i.label){case 0:return[4,this.getKey(e)];case 1:return r=i.sent(),[4,t.data.arrayBuffer()];case 2:return o=i.sent(),[4,this.decryptArrayBuffer(r,o)];case 3:return s=i.sent(),[2,n.create({name:t.name,data:s})]}}))}))},e.prototype.getKey=function(t){return o(this,void 0,void 0,(function(){var n,r,o;return i(this,(function(i){switch(i.label){case 0:return[4,crypto.subtle.digest("SHA-256",e.encoder.encode(t))];case 1:return n=i.sent(),r=Array.from(new Uint8Array(n)).map((function(e){return e.toString(16).padStart(2,"0")})).join(""),o=e.encoder.encode(r.slice(0,32)).buffer,[2,crypto.subtle.importKey("raw",o,"AES-CBC",!0,["encrypt","decrypt"])]}}))}))},e.prototype.encryptArrayBuffer=function(e,t){return o(this,void 0,void 0,(function(){var n,r,o;return i(this,(function(i){switch(i.label){case 0:return n=crypto.getRandomValues(new Uint8Array(16)),r=Li,o=[n.buffer],[4,crypto.subtle.encrypt({name:"AES-CBC",iv:n},e,t)];case 1:return[2,r.apply(void 0,o.concat([i.sent()]))]}}))}))},e.prototype.decryptArrayBuffer=function(t,n){return o(this,void 0,void 0,(function(){var r;return i(this,(function(o){switch(o.label){case 0:if(r=n.slice(0,16),n.slice(e.IV_LENGTH).byteLength<=0)throw new Error("decryption error: empty content");return[4,crypto.subtle.decrypt({name:"AES-CBC",iv:r},t,n.slice(e.IV_LENGTH))];case 1:return[2,o.sent()]}}))}))},e.prototype.encryptString=function(t,n){return o(this,void 0,void 0,(function(){var r,o,s,a;return i(this,(function(i){switch(i.label){case 0:return r=crypto.getRandomValues(new Uint8Array(16)),o=e.encoder.encode(n).buffer,[4,crypto.subtle.encrypt({name:"AES-CBC",iv:r},t,o)];case 1:return s=i.sent(),a=Li(r.buffer,s),[2,e.decoder.decode(a)]}}))}))},e.prototype.decryptString=function(t,n){return o(this,void 0,void 0,(function(){var r,o,s,a;return i(this,(function(i){switch(i.label){case 0:return r=e.encoder.encode(n).buffer,o=r.slice(0,16),s=r.slice(16),[4,crypto.subtle.decrypt({name:"AES-CBC",iv:o},t,s)];case 1:return a=i.sent(),[2,e.decoder.decode(a)]}}))}))},e.IV_LENGTH=16,e.encoder=new TextEncoder,e.decoder=new TextDecoder,e}(),Bi=(Gi=function(){function e(e){if(e instanceof File)this.data=e,this.name=this.data.name,this.mimeType=this.data.type;else if(e.data){var t=e.data;this.data=new File([t],e.name,{type:e.mimeType}),this.name=e.name,e.mimeType&&(this.mimeType=e.mimeType)}if(void 0===this.data)throw new Error("Couldn't construct a file out of supplied options.");if(void 0===this.name)throw new Error("Couldn't guess filename out of the options. Please provide one.")}return e.create=function(e){return new this(e)},e.prototype.toBuffer=function(){return o(this,void 0,void 0,(function(){return i(this,(function(e){throw new Error("This feature is only supported in Node.js environments.")}))}))},e.prototype.toStream=function(){return o(this,void 0,void 0,(function(){return i(this,(function(e){throw new Error("This feature is only supported in Node.js environments.")}))}))},e.prototype.toFileUri=function(){return o(this,void 0,void 0,(function(){return i(this,(function(e){throw new Error("This feature is only supported in react native environments.")}))}))},e.prototype.toBlob=function(){return o(this,void 0,void 0,(function(){return i(this,(function(e){return[2,this.data]}))}))},e.prototype.toArrayBuffer=function(){return o(this,void 0,void 0,(function(){var e=this;return i(this,(function(t){return[2,new Promise((function(t,n){var r=new FileReader;r.addEventListener("load",(function(){if(r.result instanceof ArrayBuffer)return t(r.result)})),r.addEventListener("error",(function(){n(r.error)})),r.readAsArrayBuffer(e.data)}))]}))}))},e.prototype.toString=function(){return o(this,void 0,void 0,(function(){var e=this;return i(this,(function(t){return[2,new Promise((function(t,n){var r=new FileReader;r.addEventListener("load",(function(){if("string"==typeof r.result)return t(r.result)})),r.addEventListener("error",(function(){n(r.error)})),r.readAsBinaryString(e.data)}))]}))}))},e.prototype.toFile=function(){return o(this,void 0,void 0,(function(){return i(this,(function(e){return[2,this.data]}))}))},e}(),Gi.supportsFile="undefined"!=typeof File,Gi.supportsBlob="undefined"!=typeof Blob,Gi.supportsArrayBuffer="undefined"!=typeof ArrayBuffer,Gi.supportsBuffer=!1,Gi.supportsStream=!1,Gi.supportsString=!0,Gi.supportsEncryptFile=!0,Gi.supportsFileUri=!1,Gi),Hi=function(){function e(e){this.config=e,this.cryptor=new T({config:e}),this.fileCryptor=new Ki}return Object.defineProperty(e.prototype,"identifier",{get:function(){return""},enumerable:!1,configurable:!0}),e.prototype.encrypt=function(e){var t="string"==typeof e?e:(new TextDecoder).decode(e);return{data:this.cryptor.encrypt(t),metadata:null}},e.prototype.decrypt=function(e){var t="string"==typeof e.data?e.data:b(e.data);return this.cryptor.decrypt(t)},e.prototype.encryptFile=function(e,t){var n;return o(this,void 0,void 0,(function(){return i(this,(function(r){return[2,this.fileCryptor.encryptFile(null===(n=this.config)||void 0===n?void 0:n.cipherKey,e,t)]}))}))},e.prototype.decryptFile=function(e,t){return o(this,void 0,void 0,(function(){return i(this,(function(n){return[2,this.fileCryptor.decryptFile(this.config.cipherKey,e,t)]}))}))},e}(),qi=function(){function e(e){this.cipherKey=e.cipherKey,this.CryptoJS=E,this.encryptedKey=this.CryptoJS.SHA256(this.cipherKey)}return Object.defineProperty(e.prototype,"algo",{get:function(){return"AES-CBC"},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"identifier",{get:function(){return"ACRH"},enumerable:!1,configurable:!0}),e.prototype.getIv=function(){return crypto.getRandomValues(new Uint8Array(e.BLOCK_SIZE))},e.prototype.getKey=function(){return o(this,void 0,void 0,(function(){var t,n;return i(this,(function(r){switch(r.label){case 0:return t=e.encoder.encode(this.cipherKey),[4,crypto.subtle.digest("SHA-256",t.buffer)];case 1:return n=r.sent(),[2,crypto.subtle.importKey("raw",n,this.algo,!0,["encrypt","decrypt"])]}}))}))},e.prototype.encrypt=function(t){if(0===("string"==typeof t?t:e.decoder.decode(t)).length)throw new Error("encryption error. empty content");var n=this.getIv();return{metadata:n,data:m(this.CryptoJS.AES.encrypt(t,this.encryptedKey,{iv:this.bufferToWordArray(n),mode:this.CryptoJS.mode.CBC}).ciphertext.toString(this.CryptoJS.enc.Base64))}},e.prototype.decrypt=function(t){var n=this.bufferToWordArray(new Uint8ClampedArray(t.metadata)),r=this.bufferToWordArray(new Uint8ClampedArray(t.data));return e.encoder.encode(this.CryptoJS.AES.decrypt({ciphertext:r},this.encryptedKey,{iv:n,mode:this.CryptoJS.mode.CBC}).toString(this.CryptoJS.enc.Utf8)).buffer},e.prototype.encryptFileData=function(e){return o(this,void 0,void 0,(function(){var t,n,r;return i(this,(function(o){switch(o.label){case 0:return[4,this.getKey()];case 1:return t=o.sent(),n=this.getIv(),r={},[4,crypto.subtle.encrypt({name:this.algo,iv:n},t,e)];case 2:return[2,(r.data=o.sent(),r.metadata=n,r)]}}))}))},e.prototype.decryptFileData=function(e){return o(this,void 0,void 0,(function(){var t;return i(this,(function(n){switch(n.label){case 0:return[4,this.getKey()];case 1:return t=n.sent(),[2,crypto.subtle.decrypt({name:this.algo,iv:e.metadata},t,e.data)]}}))}))},e.prototype.bufferToWordArray=function(e){var t,n=[];for(t=0;t0?t.slice(n.length-n.metadataLength,n.length):null;if(t.slice(n.length).byteLength<=0)throw new Error("decryption error. empty content");return r.decrypt({data:t.slice(n.length),metadata:o})},e.prototype.encryptFile=function(e,t){return o(this,void 0,void 0,(function(){var n,r;return i(this,(function(o){switch(o.label){case 0:return this.defaultCryptor.identifier===Vi.LEGACY_IDENTIFIER?[2,this.defaultCryptor.encryptFile(e,t)]:[4,this.getFileData(e.data)];case 1:return n=o.sent(),[4,this.defaultCryptor.encryptFileData(n)];case 2:return r=o.sent(),[2,t.create({name:e.name,mimeType:"application/octet-stream",data:this.concatArrayBuffer(this.getHeaderData(r),r.data)})]}}))}))},e.prototype.decryptFile=function(t,n){return o(this,void 0,void 0,(function(){var r,o,s,a,u,c,l,p;return i(this,(function(i){switch(i.label){case 0:return[4,t.data.arrayBuffer()];case 1:return r=i.sent(),o=Vi.tryParse(r),(null==(s=this.getCryptor(o))?void 0:s.identifier)===e.LEGACY_IDENTIFIER?[2,s.decryptFile(t,n)]:[4,this.getFileData(r)];case 2:return a=i.sent(),u=a.slice(o.length-o.metadataLength,o.length),l=(c=n).create,p={name:t.name},[4,this.defaultCryptor.decryptFileData({data:r.slice(o.length),metadata:u})];case 3:return[2,l.apply(c,[(p.data=i.sent(),p)])]}}))}))},e.prototype.getCryptor=function(e){if(""===e){var t=this.getAllCryptors().find((function(e){return""===e.identifier}));if(t)return t;throw new Error("unknown cryptor error")}if(e instanceof Wi)return this.getCryptorFromId(e.identifier)},e.prototype.getCryptorFromId=function(e){var t=this.getAllCryptors().find((function(t){return e===t.identifier}));if(t)return t;throw Error("unknown cryptor error")},e.prototype.concatArrayBuffer=function(e,t){var n=new Uint8Array(e.byteLength+t.byteLength);return n.set(new Uint8Array(e),0),n.set(new Uint8Array(t),e.byteLength),n.buffer},e.prototype.getHeaderData=function(e){if(e.metadata){var t=Vi.from(this.defaultCryptor.identifier,e.metadata),n=new Uint8Array(t.length),r=0;return n.set(t.data,r),r+=t.length-e.metadata.byteLength,n.set(new Uint8Array(e.metadata),r),n.buffer}},e.prototype.getFileData=function(t){return o(this,void 0,void 0,(function(){return i(this,(function(n){switch(n.label){case 0:return t instanceof Blob?[4,t.arrayBuffer()]:[3,2];case 1:return[2,n.sent()];case 2:if(t instanceof ArrayBuffer)return[2,t];if("string"==typeof t)return[2,e.encoder.encode(t)];throw new Error("Cannot decrypt/encrypt file. In browsers file encrypt/decrypt supported for string, ArrayBuffer or Blob")}}))}))},e.LEGACY_IDENTIFIER="",e.encoder=new TextEncoder,e.decoder=new TextDecoder,e}(),Vi=function(){function e(){}return e.from=function(t,n){if(t!==e.LEGACY_IDENTIFIER)return new Wi(t,n.byteLength)},e.tryParse=function(t){var n=new Uint8Array(t),r="";if(n.byteLength>=4&&(r=n.slice(0,4),this.decoder.decode(r)!==e.SENTINEL))return"";if(!(n.byteLength>=5))throw new Error("decryption error. invalid header version");if(n[4]>e.MAX_VERSION)throw new Error("unknown cryptor error");var o="",i=5+e.IDENTIFIER_LENGTH;if(!(n.byteLength>=i))throw new Error("decryption error. invalid crypto identifier");o=n.slice(5,i);var s=null;if(!(n.byteLength>=i+1))throw new Error("decryption error. invalid metadata length");return s=n[i],i+=1,255===s&&n.byteLength>=i+2&&(s=new Uint16Array(n.slice(i,i+2)).reduce((function(e,t){return(e<<8)+t}),0),i+=2),new Wi(this.decoder.decode(o),s)},e.SENTINEL="PNED",e.LEGACY_IDENTIFIER="",e.IDENTIFIER_LENGTH=4,e.VERSION=1,e.MAX_VERSION=1,e.decoder=new TextDecoder,e}(),Wi=function(){function e(e,t){this._identifier=e,this._metadataLength=t}return Object.defineProperty(e.prototype,"identifier",{get:function(){return this._identifier},set:function(e){this._identifier=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"metadataLength",{get:function(){return this._metadataLength},set:function(e){this._metadataLength=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"version",{get:function(){return Vi.VERSION},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"length",{get:function(){return Vi.SENTINEL.length+1+Vi.IDENTIFIER_LENGTH+(this.metadataLength<255?1:3)+this.metadataLength},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"data",{get:function(){var e=0,t=new Uint8Array(this.length),n=new TextEncoder;t.set(n.encode(Vi.SENTINEL)),t[e+=Vi.SENTINEL.length]=this.version,e++,this.identifier&&t.set(n.encode(this.identifier),e),e+=Vi.IDENTIFIER_LENGTH;var r=this.metadataLength;return r<255?t[e]=r:t.set([255,r>>8,255&r],e),t},enumerable:!1,configurable:!0}),e.IDENTIFIER_LENGTH=4,e.SENTINEL="PNED",e}();function Ji(e){if(!navigator||!navigator.sendBeacon)return!1;navigator.sendBeacon(e)}var $i=function(e){function n(t){var n=this,r=t.listenToBrowserNetworkEvents,o=void 0===r||r;return t.sdkFamily="Web",t.networking=new _n({del:Fi,get:Ui,post:Ii,patch:Di,sendBeacon:Ji,getfile:xi,postfile:Ri}),t.cbor=new wn((function(e){return Sn(h.decode(e))}),m),t.PubNubFile=Bi,t.cryptography=new Ki,t.initCryptoModule=function(e){return new zi({default:new Hi({cipherKey:e.cipherKey,useRandomIVs:e.useRandomIVs}),cryptors:[new qi({cipherKey:e.cipherKey})]})},n=e.call(this,t)||this,o&&(window.addEventListener("offline",(function(){n.networkDownDetected()})),window.addEventListener("online",(function(){n.networkUpDetected()}))),n}return t(n,e),n.CryptoModule=zi,n}(vn);return $i})); +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).PubNub=t()}(this,(function(){"use strict";var e="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};function t(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var s={exports:{}};!function(t){!function(e,s){var n=Math.pow(2,-24),r=Math.pow(2,32),i=Math.pow(2,53);var o={encode:function(e){var t,n=new ArrayBuffer(256),o=new DataView(n),a=0;function c(e){for(var s=n.byteLength,r=a+e;s>2,u=0;u>6),r.push(128|63&o)):o<55296?(r.push(224|o>>12),r.push(128|o>>6&63),r.push(128|63&o)):(o=(1023&o)<<10,o|=1023&t.charCodeAt(++n),o+=65536,r.push(240|o>>18),r.push(128|o>>12&63),r.push(128|o>>6&63),r.push(128|63&o))}return d(3,r.length),h(r);default:var p;if(Array.isArray(t))for(d(4,p=t.length),n=0;n>5!==e)throw"Invalid indefinite length element";return s}function f(e,t){for(var s=0;s>10),e.push(56320|1023&n))}}"function"!=typeof t&&(t=function(e){return e}),"function"!=typeof i&&(i=function(){return s});var m=function e(){var r,d,m=l(),b=m>>5,v=31&m;if(7===b)switch(v){case 25:return function(){var e=new ArrayBuffer(4),t=new DataView(e),s=h(),r=32768&s,i=31744&s,o=1023&s;if(31744===i)i=261120;else if(0!==i)i+=114688;else if(0!==o)return o*n;return t.setUint32(0,r<<16|i<<13|o<<13),t.getFloat32(0)}();case 26:return c(o.getFloat32(a),4);case 27:return c(o.getFloat64(a),8)}if((d=g(v))<0&&(b<2||6=0;)S+=d,w.push(u(d));var k=new Uint8Array(S),E=0;for(r=0;r=0;)f(O,d);else f(O,d);return String.fromCharCode.apply(null,O);case 4:var C;if(d<0)for(C=[];!p();)C.push(e());else for(C=new Array(d),r=0;r0){const n=(new TextDecoder).decode(t);if(-1!==e.headers["content-type"].indexOf("text/javascript")||-1!==e.headers["content-type"].indexOf("application/json"))try{const e=JSON.parse(n);"object"!=typeof e||Array.isArray(e)||("error"in e&&(1===e.error||!0===e.error)&&"status"in e&&"number"==typeof e.status&&"message"in e&&"service"in e?(s=e,o=e.status):s=e,"error"in e&&e.error instanceof Error&&(s=e.error))}catch(e){s=n}else if(-1!==e.headers["content-type"].indexOf("xml")){const e=/(.*)<\/Message>/gi.exec(n);r=e?`Upload to bucket failed: ${e[1]}`:"Upload to bucket failed."}else s=n}return new c(r,n,o,s)}constructor(e,t,s,n){super(e),this.category=t,this.statusCode=s,this.errorData=n,this.name="PubNubAPIError"}toStatus(e){return{error:!0,category:this.category,operation:e,statusCode:this.statusCode,errorData:this.errorData}}toPubNubError(e,t){return new o(null!=t?t:this.message,this.toStatus(e))}}class u{constructor(e){this.configuration=e,this.serviceWorkerEventsQueue=[],this.callbacks=new Map,this.setupServiceWorker()}makeSendable(e){if(!e.path.startsWith("/v2/subscribe")&&!e.path.endsWith("/leave"))return this.configuration.transport.makeSendable(e);let t;const s={type:"send-request",clientIdentifier:this.configuration.clientIdentifier,subscriptionKey:this.configuration.subscriptionKey,logVerbosity:this.configuration.logVerbosity,request:e};return e.cancellable&&(t={abort:()=>{const t={type:"cancel-request",clientIdentifier:this.configuration.clientIdentifier,subscriptionKey:this.configuration.subscriptionKey,logVerbosity:this.configuration.logVerbosity,identifier:e.identifier};this.scheduleEventPost(t)}}),[new Promise(((t,n)=>{this.callbacks.set(e.identifier,{resolve:t,reject:n}),this.scheduleEventPost(s)})),t]}request(e){return e}scheduleEventPost(e,t=!1){const s=this.serviceWorker;s?s.postMessage(e):t?this.serviceWorkerEventsQueue.splice(0,0,e):this.serviceWorkerEventsQueue.push(e)}flushScheduledEvents(){const e=this.serviceWorker;if(!e||0===this.serviceWorkerEventsQueue.length)return;const t=[];for(let e=0;e!t.includes(e))),this.serviceWorkerEventsQueue.forEach((t=>e.postMessage(t))),this.serviceWorkerEventsQueue=[]}get serviceWorker(){return this.serviceWorkerRegistration?this.serviceWorkerRegistration.active:null}setupServiceWorker(){if(!("serviceWorker"in navigator))return;const e=navigator.serviceWorker;e.register("https://cdn.pubnub.com/sdk/javascript/dist/web/pubnub.worker.min.js",{scope:`/pubnub-${this.configuration.sdkVersion}`}).then((e=>{this.serviceWorkerRegistration=e,e.active&&this.flushScheduledEvents(),this.serviceWorkerRegistration.addEventListener("updatefound",(()=>{if(!this.serviceWorkerRegistration)return;const e=this.serviceWorkerRegistration.installing,t=()=>{"activated"===e.state?this.flushScheduledEvents():"redundant"===e.state&&e.removeEventListener("statechange",t)};e.addEventListener("statechange",t)}))})),e.addEventListener("message",(e=>this.handleServiceWorkerEvent(e)))}handleServiceWorkerEvent(e){const{data:t}=e;if(t.clientIdentifier===this.configuration.clientIdentifier)if("request-progress-start"===t.type||"request-progress-end"===t.type)this.logRequestProgress(t);else if("request-process-success"===t.type||"request-process-error"===t.type){const{resolve:e,reject:s}=this.callbacks.get(t.identifier);if("request-process-success"===t.type)e({status:t.response.status,url:t.url,headers:t.response.headers,body:t.response.body});else{let e=i.PNUnknownCategory,n="Unknown error";if(t.error)"NETWORK_ISSUE"===t.error.type?e=i.PNNetworkIssuesCategory:"TIMEOUT"===t.error.type?e=i.PNTimeoutCategory:"ABORTED"===t.error.type&&(e=i.PNCancelledCategory),n=`${t.error.message} (${t.identifier})`;else if(t.response)return s(c.create({url:t.url,headers:t.response.headers,body:t.response.body,status:t.response.status},t.response.body));s(new c(n,e,0,new Error(n)))}}}logRequestProgress(e){var t,s;"request-progress-start"===e.type?(console.log("<<<<<"),console.log(`[${e.timestamp}] ${e.url}\n${JSON.stringify(null!==(t=e.query)&&void 0!==t?t:{})}`),console.log("-----")):(console.log(">>>>>>"),console.log(`[${e.timestamp} / ${e.duration}] ${e.url}\n${JSON.stringify(null!==(s=e.query)&&void 0!==s?s:{})}\n${e.response}`),console.log("-----"))}}function l(e,t){var s={};for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&t.indexOf(n)<0&&(s[n]=e[n]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var r=0;for(n=Object.getOwnPropertySymbols(e);r{const s=new FileReader;s.addEventListener("load",(()=>{if(s.result instanceof ArrayBuffer)return e(s.result)})),s.addEventListener("error",(()=>t(s.error))),s.readAsArrayBuffer(this.data)}))}))}toString(){return h(this,void 0,void 0,(function*(){return new Promise(((e,t)=>{const s=new FileReader;s.addEventListener("load",(()=>{if("string"==typeof s.result)return e(s.result)})),s.addEventListener("error",(()=>{t(s.error)})),s.readAsBinaryString(this.data)}))}))}toStream(){return h(this,void 0,void 0,(function*(){throw new Error("This feature is only supported in Node.js environments.")}))}toFile(){return h(this,void 0,void 0,(function*(){return this.data}))}toFileUri(){return h(this,void 0,void 0,(function*(){throw new Error("This feature is only supported in React Native environments.")}))}toBlob(){return h(this,void 0,void 0,(function*(){return this.data}))}}p.supportsBlob="undefined"!=typeof Blob,p.supportsFile="undefined"!=typeof File,p.supportsBuffer=!1,p.supportsStream=!1,p.supportsString=!0,p.supportsArrayBuffer=!0,p.supportsEncryptFile=!0,p.supportsFileUri=!1;function g(e){const t=e.replace(/==?$/,""),s=Math.floor(t.length/4*3),n=new ArrayBuffer(s),r=new Uint8Array(n);let i=0;function o(){const e=t.charAt(i++),s="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(e);if(-1===s)throw new Error(`Illegal character at ${i}: ${t.charAt(i-1)}`);return s}for(let e=0;e>4,c=(15&s)<<4|n>>2,u=(3&n)<<6|i;r[e]=a,64!=n&&(r[e+1]=c),64!=i&&(r[e+2]=u)}return n}function y(e){let t="";const s="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",n=new Uint8Array(e),r=n.byteLength,i=r%3,o=r-i;let a,c,u,l,h;for(let e=0;e>18,c=(258048&h)>>12,u=(4032&h)>>6,l=63&h,t+=s[a]+s[c]+s[u]+s[l];return 1==i?(h=n[o],a=(252&h)>>2,c=(3&h)<<4,t+=s[a]+s[c]+"=="):2==i&&(h=n[o]<<8|n[o+1],a=(64512&h)>>10,c=(1008&h)>>4,u=(15&h)<<2,t+=s[a]+s[c]+s[u]+"="),t}var f,m,b,v,w,S=S||function(e,t){var s={},n=s.lib={},r=function(){},i=n.Base={extend:function(e){r.prototype=this;var t=new r;return e&&t.mixIn(e),t.hasOwnProperty("init")||(t.init=function(){t.$super.init.apply(this,arguments)}),t.init.prototype=t,t.$super=this,t},create:function(){var e=this.extend();return e.init.apply(e,arguments),e},init:function(){},mixIn:function(e){for(var t in e)e.hasOwnProperty(t)&&(this[t]=e[t]);e.hasOwnProperty("toString")&&(this.toString=e.toString)},clone:function(){return this.init.prototype.extend(this)}},o=n.WordArray=i.extend({init:function(e,t){e=this.words=e||[],this.sigBytes=null!=t?t:4*e.length},toString:function(e){return(e||c).stringify(this)},concat:function(e){var t=this.words,s=e.words,n=this.sigBytes;if(e=e.sigBytes,this.clamp(),n%4)for(var r=0;r>>2]|=(s[r>>>2]>>>24-r%4*8&255)<<24-(n+r)%4*8;else if(65535>>2]=s[r>>>2];else t.push.apply(t,s);return this.sigBytes+=e,this},clamp:function(){var t=this.words,s=this.sigBytes;t[s>>>2]&=4294967295<<32-s%4*8,t.length=e.ceil(s/4)},clone:function(){var e=i.clone.call(this);return e.words=this.words.slice(0),e},random:function(t){for(var s=[],n=0;n>>2]>>>24-n%4*8&255;s.push((r>>>4).toString(16)),s.push((15&r).toString(16))}return s.join("")},parse:function(e){for(var t=e.length,s=[],n=0;n>>3]|=parseInt(e.substr(n,2),16)<<24-n%8*4;return new o.init(s,t/2)}},u=a.Latin1={stringify:function(e){var t=e.words;e=e.sigBytes;for(var s=[],n=0;n>>2]>>>24-n%4*8&255));return s.join("")},parse:function(e){for(var t=e.length,s=[],n=0;n>>2]|=(255&e.charCodeAt(n))<<24-n%4*8;return new o.init(s,t)}},l=a.Utf8={stringify:function(e){try{return decodeURIComponent(escape(u.stringify(e)))}catch(e){throw Error("Malformed UTF-8 data")}},parse:function(e){return u.parse(unescape(encodeURIComponent(e)))}},h=n.BufferedBlockAlgorithm=i.extend({reset:function(){this._data=new o.init,this._nDataBytes=0},_append:function(e){"string"==typeof e&&(e=l.parse(e)),this._data.concat(e),this._nDataBytes+=e.sigBytes},_process:function(t){var s=this._data,n=s.words,r=s.sigBytes,i=this.blockSize,a=r/(4*i);if(t=(a=t?e.ceil(a):e.max((0|a)-this._minBufferSize,0))*i,r=e.min(4*t,r),t){for(var c=0;cu;){var l;e:{l=c;for(var h=e.sqrt(l),d=2;d<=h;d++)if(!(l%d)){l=!1;break e}l=!0}l&&(8>u&&(i[u]=a(e.pow(c,.5))),o[u]=a(e.pow(c,1/3)),u++),c++}var p=[];r=r.SHA256=n.extend({_doReset:function(){this._hash=new s.init(i.slice(0))},_doProcessBlock:function(e,t){for(var s=this._hash.words,n=s[0],r=s[1],i=s[2],a=s[3],c=s[4],u=s[5],l=s[6],h=s[7],d=0;64>d;d++){if(16>d)p[d]=0|e[t+d];else{var g=p[d-15],y=p[d-2];p[d]=((g<<25|g>>>7)^(g<<14|g>>>18)^g>>>3)+p[d-7]+((y<<15|y>>>17)^(y<<13|y>>>19)^y>>>10)+p[d-16]}g=h+((c<<26|c>>>6)^(c<<21|c>>>11)^(c<<7|c>>>25))+(c&u^~c&l)+o[d]+p[d],y=((n<<30|n>>>2)^(n<<19|n>>>13)^(n<<10|n>>>22))+(n&r^n&i^r&i),h=l,l=u,u=c,c=a+g|0,a=i,i=r,r=n,n=g+y|0}s[0]=s[0]+n|0,s[1]=s[1]+r|0,s[2]=s[2]+i|0,s[3]=s[3]+a|0,s[4]=s[4]+c|0,s[5]=s[5]+u|0,s[6]=s[6]+l|0,s[7]=s[7]+h|0},_doFinalize:function(){var t=this._data,s=t.words,n=8*this._nDataBytes,r=8*t.sigBytes;return s[r>>>5]|=128<<24-r%32,s[14+(r+64>>>9<<4)]=e.floor(n/4294967296),s[15+(r+64>>>9<<4)]=n,t.sigBytes=4*s.length,this._process(),this._hash},clone:function(){var e=n.clone.call(this);return e._hash=this._hash.clone(),e}});t.SHA256=n._createHelper(r),t.HmacSHA256=n._createHmacHelper(r)}(Math),m=(f=S).enc.Utf8,f.algo.HMAC=f.lib.Base.extend({init:function(e,t){e=this._hasher=new e.init,"string"==typeof t&&(t=m.parse(t));var s=e.blockSize,n=4*s;t.sigBytes>n&&(t=e.finalize(t)),t.clamp();for(var r=this._oKey=t.clone(),i=this._iKey=t.clone(),o=r.words,a=i.words,c=0;c>>2]>>>24-r%4*8&255)<<16|(t[r+1>>>2]>>>24-(r+1)%4*8&255)<<8|t[r+2>>>2]>>>24-(r+2)%4*8&255,o=0;4>o&&r+.75*o>>6*(3-o)&63));if(t=n.charAt(64))for(;e.length%4;)e.push(t);return e.join("")},parse:function(e){var t=e.length,s=this._map;(n=s.charAt(64))&&-1!=(n=e.indexOf(n))&&(t=n);for(var n=[],r=0,i=0;i>>6-i%4*2;n[r>>>2]|=(o|a)<<24-r%4*8,r++}return v.create(n,r)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="},function(e){function t(e,t,s,n,r,i,o){return((e=e+(t&s|~t&n)+r+o)<>>32-i)+t}function s(e,t,s,n,r,i,o){return((e=e+(t&n|s&~n)+r+o)<>>32-i)+t}function n(e,t,s,n,r,i,o){return((e=e+(t^s^n)+r+o)<>>32-i)+t}function r(e,t,s,n,r,i,o){return((e=e+(s^(t|~n))+r+o)<>>32-i)+t}for(var i=S,o=(c=i.lib).WordArray,a=c.Hasher,c=i.algo,u=[],l=0;64>l;l++)u[l]=4294967296*e.abs(e.sin(l+1))|0;c=c.MD5=a.extend({_doReset:function(){this._hash=new o.init([1732584193,4023233417,2562383102,271733878])},_doProcessBlock:function(e,i){for(var o=0;16>o;o++){var a=e[c=i+o];e[c]=16711935&(a<<8|a>>>24)|4278255360&(a<<24|a>>>8)}o=this._hash.words;var c=e[i+0],l=(a=e[i+1],e[i+2]),h=e[i+3],d=e[i+4],p=e[i+5],g=e[i+6],y=e[i+7],f=e[i+8],m=e[i+9],b=e[i+10],v=e[i+11],w=e[i+12],S=e[i+13],k=e[i+14],E=e[i+15],O=t(O=o[0],P=o[1],N=o[2],C=o[3],c,7,u[0]),C=t(C,O,P,N,a,12,u[1]),N=t(N,C,O,P,l,17,u[2]),P=t(P,N,C,O,h,22,u[3]);O=t(O,P,N,C,d,7,u[4]),C=t(C,O,P,N,p,12,u[5]),N=t(N,C,O,P,g,17,u[6]),P=t(P,N,C,O,y,22,u[7]),O=t(O,P,N,C,f,7,u[8]),C=t(C,O,P,N,m,12,u[9]),N=t(N,C,O,P,b,17,u[10]),P=t(P,N,C,O,v,22,u[11]),O=t(O,P,N,C,w,7,u[12]),C=t(C,O,P,N,S,12,u[13]),N=t(N,C,O,P,k,17,u[14]),O=s(O,P=t(P,N,C,O,E,22,u[15]),N,C,a,5,u[16]),C=s(C,O,P,N,g,9,u[17]),N=s(N,C,O,P,v,14,u[18]),P=s(P,N,C,O,c,20,u[19]),O=s(O,P,N,C,p,5,u[20]),C=s(C,O,P,N,b,9,u[21]),N=s(N,C,O,P,E,14,u[22]),P=s(P,N,C,O,d,20,u[23]),O=s(O,P,N,C,m,5,u[24]),C=s(C,O,P,N,k,9,u[25]),N=s(N,C,O,P,h,14,u[26]),P=s(P,N,C,O,f,20,u[27]),O=s(O,P,N,C,S,5,u[28]),C=s(C,O,P,N,l,9,u[29]),N=s(N,C,O,P,y,14,u[30]),O=n(O,P=s(P,N,C,O,w,20,u[31]),N,C,p,4,u[32]),C=n(C,O,P,N,f,11,u[33]),N=n(N,C,O,P,v,16,u[34]),P=n(P,N,C,O,k,23,u[35]),O=n(O,P,N,C,a,4,u[36]),C=n(C,O,P,N,d,11,u[37]),N=n(N,C,O,P,y,16,u[38]),P=n(P,N,C,O,b,23,u[39]),O=n(O,P,N,C,S,4,u[40]),C=n(C,O,P,N,c,11,u[41]),N=n(N,C,O,P,h,16,u[42]),P=n(P,N,C,O,g,23,u[43]),O=n(O,P,N,C,m,4,u[44]),C=n(C,O,P,N,w,11,u[45]),N=n(N,C,O,P,E,16,u[46]),O=r(O,P=n(P,N,C,O,l,23,u[47]),N,C,c,6,u[48]),C=r(C,O,P,N,y,10,u[49]),N=r(N,C,O,P,k,15,u[50]),P=r(P,N,C,O,p,21,u[51]),O=r(O,P,N,C,w,6,u[52]),C=r(C,O,P,N,h,10,u[53]),N=r(N,C,O,P,b,15,u[54]),P=r(P,N,C,O,a,21,u[55]),O=r(O,P,N,C,f,6,u[56]),C=r(C,O,P,N,E,10,u[57]),N=r(N,C,O,P,g,15,u[58]),P=r(P,N,C,O,S,21,u[59]),O=r(O,P,N,C,d,6,u[60]),C=r(C,O,P,N,v,10,u[61]),N=r(N,C,O,P,l,15,u[62]),P=r(P,N,C,O,m,21,u[63]);o[0]=o[0]+O|0,o[1]=o[1]+P|0,o[2]=o[2]+N|0,o[3]=o[3]+C|0},_doFinalize:function(){var t=this._data,s=t.words,n=8*this._nDataBytes,r=8*t.sigBytes;s[r>>>5]|=128<<24-r%32;var i=e.floor(n/4294967296);for(s[15+(r+64>>>9<<4)]=16711935&(i<<8|i>>>24)|4278255360&(i<<24|i>>>8),s[14+(r+64>>>9<<4)]=16711935&(n<<8|n>>>24)|4278255360&(n<<24|n>>>8),t.sigBytes=4*(s.length+1),this._process(),s=(t=this._hash).words,n=0;4>n;n++)r=s[n],s[n]=16711935&(r<<8|r>>>24)|4278255360&(r<<24|r>>>8);return t},clone:function(){var e=a.clone.call(this);return e._hash=this._hash.clone(),e}}),i.MD5=a._createHelper(c),i.HmacMD5=a._createHmacHelper(c)}(Math),function(){var e,t=S,s=(e=t.lib).Base,n=e.WordArray,r=(e=t.algo).EvpKDF=s.extend({cfg:s.extend({keySize:4,hasher:e.MD5,iterations:1}),init:function(e){this.cfg=this.cfg.extend(e)},compute:function(e,t){for(var s=(a=this.cfg).hasher.create(),r=n.create(),i=r.words,o=a.keySize,a=a.iterations;i.length>>2]}},t.BlockCipher=a.extend({cfg:a.cfg.extend({mode:c,padding:l}),reset:function(){a.reset.call(this);var e=(t=this.cfg).iv,t=t.mode;if(this._xformMode==this._ENC_XFORM_MODE)var s=t.createEncryptor;else s=t.createDecryptor,this._minBufferSize=1;this._mode=s.call(t,this,e&&e.words)},_doProcessBlock:function(e,t){this._mode.processBlock(e,t)},_doFinalize:function(){var e=this.cfg.padding;if(this._xformMode==this._ENC_XFORM_MODE){e.pad(this._data,this.blockSize);var t=this._process(!0)}else t=this._process(!0),e.unpad(t);return t},blockSize:4});var h=t.CipherParams=s.extend({init:function(e){this.mixIn(e)},toString:function(e){return(e||this.formatter).stringify(this)}}),d=(c=(p.format={}).OpenSSL={stringify:function(e){var t=e.ciphertext;return((e=e.salt)?n.create([1398893684,1701076831]).concat(e).concat(t):t).toString(i)},parse:function(e){var t=(e=i.parse(e)).words;if(1398893684==t[0]&&1701076831==t[1]){var s=n.create(t.slice(2,4));t.splice(0,4),e.sigBytes-=16}return h.create({ciphertext:e,salt:s})}},t.SerializableCipher=s.extend({cfg:s.extend({format:c}),encrypt:function(e,t,s,n){n=this.cfg.extend(n);var r=e.createEncryptor(s,n);return t=r.finalize(t),r=r.cfg,h.create({ciphertext:t,key:s,iv:r.iv,algorithm:e,mode:r.mode,padding:r.padding,blockSize:e.blockSize,formatter:n.format})},decrypt:function(e,t,s,n){return n=this.cfg.extend(n),t=this._parse(t,n.format),e.createDecryptor(s,n).finalize(t.ciphertext)},_parse:function(e,t){return"string"==typeof e?t.parse(e,this):e}})),p=(p.kdf={}).OpenSSL={execute:function(e,t,s,r){return r||(r=n.random(8)),e=o.create({keySize:t+s}).compute(e,r),s=n.create(e.words.slice(t),4*s),e.sigBytes=4*t,h.create({key:e,iv:s,salt:r})}},g=t.PasswordBasedCipher=d.extend({cfg:d.cfg.extend({kdf:p}),encrypt:function(e,t,s,n){return s=(n=this.cfg.extend(n)).kdf.execute(s,e.keySize,e.ivSize),n.iv=s.iv,(e=d.encrypt.call(this,e,t,s.key,n)).mixIn(s),e},decrypt:function(e,t,s,n){return n=this.cfg.extend(n),t=this._parse(t,n.format),s=n.kdf.execute(s,e.keySize,e.ivSize,t.salt),n.iv=s.iv,d.decrypt.call(this,e,t,s.key,n)}})}(),function(){for(var e=S,t=e.lib.BlockCipher,s=e.algo,n=[],r=[],i=[],o=[],a=[],c=[],u=[],l=[],h=[],d=[],p=[],g=0;256>g;g++)p[g]=128>g?g<<1:g<<1^283;var y=0,f=0;for(g=0;256>g;g++){var m=(m=f^f<<1^f<<2^f<<3^f<<4)>>>8^255&m^99;n[y]=m,r[m]=y;var b=p[y],v=p[b],w=p[v],k=257*p[m]^16843008*m;i[y]=k<<24|k>>>8,o[y]=k<<16|k>>>16,a[y]=k<<8|k>>>24,c[y]=k,k=16843009*w^65537*v^257*b^16843008*y,u[m]=k<<24|k>>>8,l[m]=k<<16|k>>>16,h[m]=k<<8|k>>>24,d[m]=k,y?(y=b^p[p[p[w^b]]],f^=p[p[f]]):y=f=1}var E=[0,1,2,4,8,16,32,64,128,27,54];s=s.AES=t.extend({_doReset:function(){for(var e=(s=this._key).words,t=s.sigBytes/4,s=4*((this._nRounds=t+6)+1),r=this._keySchedule=[],i=0;i>>24]<<24|n[o>>>16&255]<<16|n[o>>>8&255]<<8|n[255&o]):(o=n[(o=o<<8|o>>>24)>>>24]<<24|n[o>>>16&255]<<16|n[o>>>8&255]<<8|n[255&o],o^=E[i/t|0]<<24),r[i]=r[i-t]^o}for(e=this._invKeySchedule=[],t=0;tt||4>=i?o:u[n[o>>>24]]^l[n[o>>>16&255]]^h[n[o>>>8&255]]^d[n[255&o]]},encryptBlock:function(e,t){this._doCryptBlock(e,t,this._keySchedule,i,o,a,c,n)},decryptBlock:function(e,t){var s=e[t+1];e[t+1]=e[t+3],e[t+3]=s,this._doCryptBlock(e,t,this._invKeySchedule,u,l,h,d,r),s=e[t+1],e[t+1]=e[t+3],e[t+3]=s},_doCryptBlock:function(e,t,s,n,r,i,o,a){for(var c=this._nRounds,u=e[t]^s[0],l=e[t+1]^s[1],h=e[t+2]^s[2],d=e[t+3]^s[3],p=4,g=1;g>>24]^r[l>>>16&255]^i[h>>>8&255]^o[255&d]^s[p++],f=n[l>>>24]^r[h>>>16&255]^i[d>>>8&255]^o[255&u]^s[p++],m=n[h>>>24]^r[d>>>16&255]^i[u>>>8&255]^o[255&l]^s[p++];d=n[d>>>24]^r[u>>>16&255]^i[l>>>8&255]^o[255&h]^s[p++],u=y,l=f,h=m}y=(a[u>>>24]<<24|a[l>>>16&255]<<16|a[h>>>8&255]<<8|a[255&d])^s[p++],f=(a[l>>>24]<<24|a[h>>>16&255]<<16|a[d>>>8&255]<<8|a[255&u])^s[p++],m=(a[h>>>24]<<24|a[d>>>16&255]<<16|a[u>>>8&255]<<8|a[255&l])^s[p++],d=(a[d>>>24]<<24|a[u>>>16&255]<<16|a[l>>>8&255]<<8|a[255&h])^s[p++],e[t]=y,e[t+1]=f,e[t+2]=m,e[t+3]=d},keySize:8});e.AES=t._createHelper(s)}(),S.mode.ECB=((w=S.lib.BlockCipherMode.extend()).Encryptor=w.extend({processBlock:function(e,t){this._cipher.encryptBlock(e,t)}}),w.Decryptor=w.extend({processBlock:function(e,t){this._cipher.decryptBlock(e,t)}}),w);var k=t(S);class E{constructor({cipherKey:e}){this.cipherKey=e,this.CryptoJS=k,this.encryptedKey=this.CryptoJS.SHA256(e)}encrypt(e){if(0===("string"==typeof e?e:E.decoder.decode(e)).length)throw new Error("encryption error. empty content");const t=this.getIv();return{metadata:t,data:g(this.CryptoJS.AES.encrypt(e,this.encryptedKey,{iv:this.bufferToWordArray(t),mode:this.CryptoJS.mode.CBC}).ciphertext.toString(this.CryptoJS.enc.Base64))}}encryptFileData(e){return h(this,void 0,void 0,(function*(){const t=yield this.getKey(),s=this.getIv();return{data:yield crypto.subtle.encrypt({name:this.algo,iv:s},t,e),metadata:s}}))}decrypt(e){if("string"==typeof e.data)throw new Error("Decryption error: data for decryption should be ArrayBuffed.");const t=this.bufferToWordArray(new Uint8ClampedArray(e.metadata)),s=this.bufferToWordArray(new Uint8ClampedArray(e.data));return E.encoder.encode(this.CryptoJS.AES.decrypt({ciphertext:s},this.encryptedKey,{iv:t,mode:this.CryptoJS.mode.CBC}).toString(this.CryptoJS.enc.Utf8)).buffer}decryptFileData(e){return h(this,void 0,void 0,(function*(){if("string"==typeof e.data)throw new Error("Decryption error: data for decryption should be ArrayBuffed.");const t=yield this.getKey();return crypto.subtle.decrypt({name:this.algo,iv:e.metadata},t,e.data)}))}get identifier(){return"ACRH"}get algo(){return"AES-CBC"}getIv(){return crypto.getRandomValues(new Uint8Array(E.BLOCK_SIZE))}getKey(){return h(this,void 0,void 0,(function*(){const e=E.encoder.encode(this.cipherKey),t=yield crypto.subtle.digest("SHA-256",e.buffer);return crypto.subtle.importKey("raw",t,this.algo,!0,["encrypt","decrypt"])}))}bufferToWordArray(e){const t=[];let s;for(s=0;se.toString(16).padStart(2,"0"))).join(""),n=P.encoder.encode(s.slice(0,32)).buffer;return crypto.subtle.importKey("raw",n,"AES-CBC",!0,["encrypt","decrypt"])}))}}P.IV_LENGTH=16,P.encoder=new TextEncoder,P.decoder=new TextDecoder;class M{constructor(e){this.config=e,this.cryptor=new C(Object.assign({},e)),this.fileCryptor=new P}encrypt(e){const t="string"==typeof e?e:M.decoder.decode(e);return{data:this.cryptor.encrypt(t),metadata:null}}encryptFile(e,t){return h(this,void 0,void 0,(function*(){var s;if(!this.config.cipherKey)throw new o("File encryption error: cipher key not set.");return this.fileCryptor.encryptFile(null===(s=this.config)||void 0===s?void 0:s.cipherKey,e,t)}))}decrypt(e){const t="string"==typeof e.data?e.data:y(e.data);return this.cryptor.decrypt(t)}decryptFile(e,t){return h(this,void 0,void 0,(function*(){if(!this.config.cipherKey)throw new o("File encryption error: cipher key not set.");return this.fileCryptor.decryptFile(this.config.cipherKey,e,t)}))}get identifier(){return""}}M.encoder=new TextEncoder,M.decoder=new TextDecoder;class j extends d{static legacyCryptoModule(e){var t;if(!e.cipherKey)throw new o("Crypto module error: cipher key not set.");return new j({default:new M(Object.assign(Object.assign({},e),{useRandomIVs:null===(t=e.useRandomIVs)||void 0===t||t})),cryptors:[new E({cipherKey:e.cipherKey})]})}static aesCbcCryptoModule(e){var t;if(!e.cipherKey)throw new o("Crypto module error: cipher key not set.");return new j({default:new E({cipherKey:e.cipherKey}),cryptors:[new M(Object.assign(Object.assign({},e),{useRandomIVs:null===(t=e.useRandomIVs)||void 0===t||t}))]})}static withDefaultCryptor(e){return new this({default:e})}encrypt(e){const t=e instanceof ArrayBuffer&&this.defaultCryptor.identifier===j.LEGACY_IDENTIFIER?this.defaultCryptor.encrypt(j.decoder.decode(e)):this.defaultCryptor.encrypt(e);if(!t.metadata)return t.data;if("string"==typeof t.data)throw new Error("Encryption error: encrypted data should be ArrayBuffed.");const s=this.getHeaderData(t);return this.concatArrayBuffer(s,t.data)}encryptFile(e,t){return h(this,void 0,void 0,(function*(){if(this.defaultCryptor.identifier===_.LEGACY_IDENTIFIER)return this.defaultCryptor.encryptFile(e,t);const s=yield this.getFileData(e),n=yield this.defaultCryptor.encryptFileData(s);if("string"==typeof n.data)throw new Error("Encryption error: encrypted data should be ArrayBuffed.");return t.create({name:e.name,mimeType:"application/octet-stream",data:this.concatArrayBuffer(this.getHeaderData(n),n.data)})}))}decrypt(e){const t="string"==typeof e?g(e):e,s=_.tryParse(t),n=this.getCryptor(s),r=s.length>0?t.slice(s.length-s.metadataLength,s.length):null;if(t.slice(s.length).byteLength<=0)throw new Error("Decryption error: empty content");return n.decrypt({data:t.slice(s.length),metadata:r})}decryptFile(e,t){return h(this,void 0,void 0,(function*(){const s=yield e.data.arrayBuffer(),n=_.tryParse(s),r=this.getCryptor(n);if((null==r?void 0:r.identifier)===_.LEGACY_IDENTIFIER)return r.decryptFile(e,t);const i=(yield this.getFileData(s)).slice(n.length-n.metadataLength,n.length);return t.create({name:e.name,data:yield this.defaultCryptor.decryptFileData({data:s.slice(n.length),metadata:i})})}))}getCryptorFromId(e){const t=this.getAllCryptors().find((t=>e===t.identifier));if(t)return t;throw Error("Unknown cryptor error")}getCryptor(e){if("string"==typeof e){const t=this.getAllCryptors().find((t=>t.identifier===e));if(t)return t;throw new Error("Unknown cryptor error")}if(e instanceof A)return this.getCryptorFromId(e.identifier)}getHeaderData(e){if(!e.metadata)return;const t=_.from(this.defaultCryptor.identifier,e.metadata),s=new Uint8Array(t.length);let n=0;return s.set(t.data,n),n+=t.length-e.metadata.byteLength,s.set(new Uint8Array(e.metadata),n),s.buffer}concatArrayBuffer(e,t){const s=new Uint8Array(e.byteLength+t.byteLength);return s.set(new Uint8Array(e),0),s.set(new Uint8Array(t),e.byteLength),s.buffer}getFileData(e){return h(this,void 0,void 0,(function*(){if(e instanceof ArrayBuffer)return e;if(e instanceof p)return e.toArrayBuffer();throw new Error("Cannot decrypt/encrypt file. In browsers file encrypt/decrypt supported for string, ArrayBuffer or Blob")}))}}j.LEGACY_IDENTIFIER="";class _{static from(e,t){if(e!==_.LEGACY_IDENTIFIER)return new A(e,t.byteLength)}static tryParse(e){const t=new Uint8Array(e);let s,n,r=null;if(t.byteLength>=4&&(s=t.slice(0,4),this.decoder.decode(s)!==_.SENTINEL))return j.LEGACY_IDENTIFIER;if(!(t.byteLength>=5))throw new Error("Decryption error: invalid header version");if(r=t[4],r>_.MAX_VERSION)throw new Error("Decryption error: Unknown cryptor error");let i=5+_.IDENTIFIER_LENGTH;if(!(t.byteLength>=i))throw new Error("Decryption error: invalid crypto identifier");n=t.slice(5,i);let o=null;if(!(t.byteLength>=i+1))throw new Error("Decryption error: invalid metadata length");return o=t[i],i+=1,255===o&&t.byteLength>=i+2&&(o=new Uint16Array(t.slice(i,i+2)).reduce(((e,t)=>(e<<8)+t),0)),new A(this.decoder.decode(n),o)}}_.SENTINEL="PNED",_.LEGACY_IDENTIFIER="",_.IDENTIFIER_LENGTH=4,_.VERSION=1,_.MAX_VERSION=1,_.decoder=new TextDecoder;class A{constructor(e,t){this._identifier=e,this._metadataLength=t}get identifier(){return this._identifier}set identifier(e){this._identifier=e}get metadataLength(){return this._metadataLength}set metadataLength(e){this._metadataLength=e}get version(){return _.VERSION}get length(){return _.SENTINEL.length+1+_.IDENTIFIER_LENGTH+(this.metadataLength<255?1:3)+this.metadataLength}get data(){let e=0;const t=new Uint8Array(this.length),s=new TextEncoder;t.set(s.encode(_.SENTINEL)),e+=_.SENTINEL.length,t[e]=this.version,e++,this.identifier&&t.set(s.encode(this.identifier),e);const n=this.metadataLength;return e+=_.IDENTIFIER_LENGTH,n<255?t[e]=n:t.set([255,n>>8,255&n],e),t}}A.IDENTIFIER_LENGTH=4,A.SENTINEL="PNED";const R=e=>encodeURIComponent(e).replace(/[!~*'()]/g,(e=>`%${e.charCodeAt(0).toString(16).toUpperCase()}`)),I=(e,t)=>{const s=e.map((e=>R(e)));return s.length?s.join(","):null!=t?t:""},U=(e,t)=>{const s=Object.fromEntries(t.map((e=>[e,!1])));return e.filter((e=>!(t.includes(e)&&!s[e])||(s[e]=!0,!1)))},T=(e,t)=>[...e].filter((s=>t.includes(s)&&e.indexOf(s)===e.lastIndexOf(s)&&t.indexOf(s)===t.lastIndexOf(s)));class F{constructor(e=!1,t){this.keepAlive=e,this.logVerbosity=t}makeSendable(e){let t,s;return e.cancellable&&(s=new AbortController,t={abortController:s,abort:()=>null==s?void 0:s.abort()}),[this.requestFromTransportRequest(e).then((t=>{const n=(new Date).getTime();this.logRequestProcessProgress(t);const r=new Promise(((t,s)=>{const n=setTimeout((()=>{clearTimeout(n),s(new Error("Request timeout"))}),1e3*e.timeout)}));return Promise.race([fetch(t,{signal:null==s?void 0:s.signal}),r]).then((e=>e.arrayBuffer().then((t=>[e,t])))).then((e=>{const s=e[1].byteLength>0?e[1]:void 0,{status:r,headers:i}=e[0],o={};i.forEach(((e,t)=>o[t]=e.toLowerCase()));const a={status:r,url:t.url,headers:o,body:s};if(r>=400)throw c.create(a);return this.logRequestProcessProgress(t,(new Date).getTime()-n,s),a})).catch((e=>{throw c.create(e)}))})),t]}request(e){return e}requestFromTransportRequest(e){return h(this,void 0,void 0,(function*(){let t,s=e.path;if(e.formData&&e.formData.length>0){e.queryParameters={};const s=e.body,n=new FormData;for(const{key:t,value:s}of e.formData)n.append(t,s);try{const e=yield s.toArrayBuffer();n.append("file",new Blob([e],{type:"application/octet-stream"}),s.name)}catch(e){try{const e=yield s.toFileUri();n.append("file",e,s.name)}catch(e){}}t=n}else e.body&&("string"==typeof e.body||e.body instanceof ArrayBuffer)&&(t=e.body);var n;return e.queryParameters&&0!==Object.keys(e.queryParameters).length&&(s=`${s}?${n=e.queryParameters,Object.keys(n).map((e=>{const t=n[e];return Array.isArray(t)?t.map((t=>`${e}=${R(t)}`)).join("&"):`${e}=${R(t)}`})).join("&")}`),new Request(`${e.origin}${s}`,{method:e.method,headers:e.headers,redirect:"follow",body:t})}))}logRequestProcessProgress(e,t,s){if(!this.logVerbosity)return;const{protocol:n,host:r,pathname:i,search:o}=new URL(e.url),a=(new Date).toISOString();if(t){const e=s?F.decoder.decode(s):void 0;console.log(">>>>>>"),console.log(`[${a} / ${t}]`,`\n${n}//${r}${i}`,`\n${o}`,`\n${e}`),console.log("-----")}else console.log("<<<<<"),console.log(`[${a}]`,`\n${n}//${r}${i}`,`\n${o}`),console.log("-----")}}function x(e){const t=e=>"object"==typeof e&&null!==e&&e.constructor===Object,s=e=>"number"==typeof e&&isFinite(e);if(!t(e))return e;const n={};return Object.keys(e).forEach((r=>{const i=(e=>"string"==typeof e||e instanceof String)(r);let o=r;const a=e[r];if(i&&r.indexOf(",")>=0){o=r.split(",").map(Number).reduce(((e,t)=>e+String.fromCharCode(t)),"")}else(s(r)||i&&!isNaN(Number(r)))&&(o=String.fromCharCode(s(r)?r:parseInt(r,10)));n[o]=t(a)?x(a):a})),n}F.decoder=new TextDecoder;const D=!1,K=e=>{var t,s,n,r;return(null!==(t=e.enableServiceWorker)&&void 0!==t?t:D)&&!("serviceWorker"in navigator)&&(e.enableServiceWorker=!1),Object.assign(Object.assign({},(e=>{var t,s,n,r,i,a,c,u,l,h,d,p,g,y,f;const m=Object.assign({},e);if(null!==(t=m.logVerbosity)&&void 0!==t||(m.logVerbosity=!1),null!==(s=m.ssl)&&void 0!==s||(m.ssl=!0),null!==(n=m.transactionalRequestTimeout)&&void 0!==n||(m.transactionalRequestTimeout=15),null!==(r=m.subscribeRequestTimeout)&&void 0!==r||(m.subscribeRequestTimeout=310),null!==(i=m.restore)&&void 0!==i||(m.restore=!1),null!==(a=m.useInstanceId)&&void 0!==a||(m.useInstanceId=!1),null!==(c=m.suppressLeaveEvents)&&void 0!==c||(m.suppressLeaveEvents=!1),null!==(u=m.requestMessageCountThreshold)&&void 0!==u||(m.requestMessageCountThreshold=100),null!==(l=m.autoNetworkDetection)&&void 0!==l||(m.autoNetworkDetection=!1),null!==(h=m.enableEventEngine)&&void 0!==h||(m.enableEventEngine=!1),null!==(d=m.maintainPresenceState)&&void 0!==d||(m.maintainPresenceState=!0),null!==(p=m.keepAlive)&&void 0!==p||(m.keepAlive=!1),m.userId&&m.uuid)throw new o("PubNub client configuration error: use only 'userId'");if(null!==(g=m.userId)&&void 0!==g||(m.userId=m.uuid),!m.userId)throw new o("PubNub client configuration error: 'userId' not set");if(0===(null===(y=m.userId)||void 0===y?void 0:y.trim().length))throw new o("PubNub client configuration error: 'userId' is empty");m.origin||(m.origin=Array.from({length:20},((e,t)=>`ps${t+1}.pndsn.com`)));const b={subscribeKey:m.subscribeKey,publishKey:m.publishKey,secretKey:m.secretKey};void 0!==m.presenceTimeout&&m.presenceTimeout<20&&(m.presenceTimeout=20,console.log("WARNING: Presence timeout is less than the minimum. Using minimum value: ",20)),null!==(f=m.presenceTimeout)&&void 0!==f||(m.presenceTimeout=300);let v=!1,w=!0,S=5,k=!1,E=!0;return void 0!==m.dedupeOnSubscribe&&"boolean"==typeof m.dedupeOnSubscribe&&(k=m.dedupeOnSubscribe),void 0!==m.useRequestId&&"boolean"==typeof m.useRequestId&&(E=m.useRequestId),void 0!==m.announceSuccessfulHeartbeats&&"boolean"==typeof m.announceSuccessfulHeartbeats&&(v=m.announceSuccessfulHeartbeats),void 0!==m.announceFailedHeartbeats&&"boolean"==typeof m.announceFailedHeartbeats&&(w=m.announceFailedHeartbeats),void 0!==m.fileUploadPublishRetryLimit&&"number"==typeof m.fileUploadPublishRetryLimit&&(S=m.fileUploadPublishRetryLimit),Object.assign(Object.assign({},m),{keySet:b,dedupeOnSubscribe:k,maximumCacheSize:100,useRequestId:E,announceSuccessfulHeartbeats:v,announceFailedHeartbeats:w,fileUploadPublishRetryLimit:S})})(e)),{listenToBrowserNetworkEvents:null===(s=e.listenToBrowserNetworkEvents)||void 0===s||s,enableServiceWorker:null!==(n=e.enableServiceWorker)&&void 0!==n?n:D,keepAlive:null===(r=e.keepAlive)||void 0===r||r})};var q={exports:{}}; +/*! lil-uuid - v0.1 - MIT License - https://github.com/lil-js/uuid */!function(e,t){!function(e){var t="0.1.0",s={3:/^[0-9A-F]{8}-[0-9A-F]{4}-3[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}$/i,4:/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,5:/^[0-9A-F]{8}-[0-9A-F]{4}-5[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,all:/^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i};function n(){var e,t,s="";for(e=0;e<32;e++)t=16*Math.random()|0,8!==e&&12!==e&&16!==e&&20!==e||(s+="-"),s+=(12===e?4:16===e?3&t|8:t).toString(16);return s}function r(e,t){var n=s[t||"all"];return n&&n.test(e)||!1}n.isUUID=r,n.VERSION=t,e.uuid=n,e.isUUID=r}(t),null!==e&&(e.exports=t.uuid)}(q,q.exports);var G=t(q.exports),$={createUUID:()=>G.uuid?G.uuid():G()};const L=(e,t)=>{var s,n,r;null===(s=e.retryConfiguration)||void 0===s||s.validate(),null!==(n=e.useRandomIVs)&&void 0!==n||(e.useRandomIVs=true),e.origin=B(null!==(r=e.ssl)&&void 0!==r&&r,e.origin);const i=e.cryptoModule;i&&delete e.cryptoModule;const o=Object.assign(Object.assign({},e),{_pnsdkSuffix:{},_instanceId:`pn-${$.createUUID()}`,_cryptoModule:void 0,_cipherKey:void 0,_setupCryptoModule:t,get instanceId(){if(this.useInstanceId)return this._instanceId},getUserId(){return this.userId},setUserId(e){if(!e||"string"!=typeof e||0===e.trim().length)throw new Error("Missing or invalid userId parameter. Provide a valid string userId");this.userId=e},getAuthKey(){return this.authKey},setAuthKey(e){this.authKey=e},getFilterExpression(){return this.filterExpression},setFilterExpression(e){this.filterExpression=e},getCipherKey(){return this._cipherKey},setCipherKey(t){this._cipherKey=t,t||!this._cryptoModule?t&&this._setupCryptoModule&&(this._cryptoModule=this._setupCryptoModule({cipherKey:t,useRandomIVs:e.useRandomIVs,customEncrypt:this.getCustomEncrypt(),customDecrypt:this.getCustomDecrypt()})):this._cryptoModule=void 0},getCryptoModule(){return this._cryptoModule},getUseRandomIVs:()=>e.useRandomIVs,setPresenceTimeout(e){this.heartbeatInterval=e/2-1,this.presenceTimeout=e},getPresenceTimeout(){return this.presenceTimeout},getHeartbeatInterval(){return this.heartbeatInterval},setHeartbeatInterval(e){this.heartbeatInterval=e},getTransactionTimeout(){return this.transactionalRequestTimeout},getSubscribeTimeout(){return this.subscribeRequestTimeout},get PubNubFile(){return e.PubNubFile},get version(){return"7.6.3"},getVersion(){return this.version},_addPnsdkSuffix(e,t){this._pnsdkSuffix[e]=`${t}`},_getPnsdkSuffix(e){const t=Object.values(this._pnsdkSuffix).join(e);return t.length>0?e+t:""},getUUID(){return this.getUserId()},setUUID(e){this.setUserId(e)},getCustomEncrypt:()=>e.customEncrypt,getCustomDecrypt:()=>e.customDecrypt});return e.cipherKey?o.setCipherKey(e.cipherKey):i&&(o._cryptoModule=i),o},B=(e,t)=>{const s=e?"https://":"http://";return"string"==typeof t?`${s}${t}`:`${s}${t[Math.floor(Math.random()*t.length)]}`};class H{constructor(e){this.cbor=e}setToken(e){e&&e.length>0?this.token=e:this.token=void 0}getToken(){return this.token}parseToken(e){const t=this.cbor.decodeToken(e);if(void 0!==t){const e=t.res.uuid?Object.keys(t.res.uuid):[],s=Object.keys(t.res.chan),n=Object.keys(t.res.grp),r=t.pat.uuid?Object.keys(t.pat.uuid):[],i=Object.keys(t.pat.chan),o=Object.keys(t.pat.grp),a={version:t.v,timestamp:t.t,ttl:t.ttl,authorized_uuid:t.uuid,signature:t.sig},c=e.length>0,u=s.length>0,l=n.length>0;if(c||u||l){if(a.resources={},c){const s=a.resources.uuids={};e.forEach((e=>s[e]=this.extractPermissions(t.res.uuid[e])))}if(u){const e=a.resources.channels={};s.forEach((s=>e[s]=this.extractPermissions(t.res.chan[s])))}if(l){const e=a.resources.groups={};n.forEach((s=>e[s]=this.extractPermissions(t.res.grp[s])))}}const h=r.length>0,d=i.length>0,p=o.length>0;if(h||d||p){if(a.patterns={},h){const e=a.patterns.uuids={};r.forEach((s=>e[s]=this.extractPermissions(t.pat.uuid[s])))}if(d){const e=a.patterns.channels={};i.forEach((s=>e[s]=this.extractPermissions(t.pat.chan[s])))}if(p){const e=a.patterns.groups={};o.forEach((s=>e[s]=this.extractPermissions(t.pat.grp[s])))}}return t.meta&&Object.keys(t.meta).length>0&&(a.meta=t.meta),a}}extractPermissions(e){const t={read:!1,write:!1,manage:!1,delete:!1,get:!1,update:!1,join:!1};return 128&~e||(t.join=!0),64&~e||(t.update=!0),32&~e||(t.get=!0),8&~e||(t.delete=!0),4&~e||(t.manage=!0),2&~e||(t.write=!0),1&~e||(t.read=!0),t}}var z;!function(e){e.GET="GET",e.POST="POST",e.PATCH="PATCH",e.DELETE="DELETE",e.LOCAL="LOCAL"}(z||(z={}));class V{constructor(e,t,s){this.publishKey=e,this.secretKey=t,this.hasher=s}signature(e){const t=e.path.startsWith("/publish")?z.GET:e.method;let s=`${t}\n${this.publishKey}\n${e.path}\n${this.queryParameters(e.queryParameters)}\n`;if(t===z.POST||t===z.PATCH){const t=e.body;let n;t&&t instanceof ArrayBuffer?n=V.textDecoder.decode(t):t&&"object"!=typeof t&&(n=t),n&&(s+=n)}return`v2.${this.hasher(s,this.secretKey)}`.replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}queryParameters(e){return Object.keys(e).sort().map((t=>{const s=e[t];return Array.isArray(s)?s.sort().map((e=>`${t}=${R(e)}`)).join("&"):`${t}=${R(s)}`})).join("&")}}V.textDecoder=new TextDecoder("utf-8");class W{constructor(e){this.configuration=e;const{clientConfiguration:{keySet:t},shaHMAC:s}=e;t.secretKey&&s&&(this.signatureGenerator=new V(t.publishKey,t.secretKey,s))}makeSendable(e){return this.configuration.transport.makeSendable(this.request(e))}request(e){var t;const{clientConfiguration:s}=this.configuration;return(e=this.configuration.transport.request(e)).queryParameters||(e.queryParameters={}),s.useInstanceId&&(e.queryParameters.instanceid=s.instanceId),e.queryParameters.uuid||(e.queryParameters.uuid=s.userId),s.useRequestId&&(e.queryParameters.requestid=e.identifier),e.queryParameters.pnsdk=this.generatePNSDK(),null!==(t=e.origin)&&void 0!==t||(e.origin=s.origin),this.authenticateRequest(e),this.signRequest(e),e}authenticateRequest(e){var t;if(e.path.startsWith("/v2/auth/")||e.path.startsWith("/v3/pam/")||e.path.startsWith("/time"))return;const{clientConfiguration:s,tokenManager:n}=this.configuration,r=null!==(t=n.getToken())&&void 0!==t?t:s.authKey;r&&(e.queryParameters.auth=r)}signRequest(e){this.signatureGenerator&&!e.path.startsWith("/time")&&(e.queryParameters.timestamp=String(Math.floor((new Date).getTime()/1e3)),e.queryParameters.signature=this.signatureGenerator.signature(e))}generatePNSDK(){const{clientConfiguration:e}=this.configuration;if(e.sdkName)return e.sdkName;let t=`PubNub-JS-${e.sdkFamily}`;e.partnerId&&(t+=`-${e.partnerId}`),t+=`/${e.getVersion()}`;const s=e._getPnsdkSuffix(" ");return s.length>0&&(t+=s),t}}class J{constructor(){this.listeners=[]}addListener(e){this.listeners.includes(e)||this.listeners.push(e)}removeListener(e){this.listeners=this.listeners.filter((t=>t!==e))}removeAllListeners(){this.listeners=[]}announceStatus(e){this.listeners.forEach((t=>{t.status&&t.status(e)}))}announcePresence(e){this.listeners.forEach((t=>{t.presence&&t.presence(e)}))}announceMessage(e){this.listeners.forEach((t=>{t.message&&t.message(e)}))}announceSignal(e){this.listeners.forEach((t=>{t.signal&&t.signal(e)}))}announceMessageAction(e){this.listeners.forEach((t=>{t.messageAction&&t.messageAction(e)}))}announceFile(e){this.listeners.forEach((t=>{t.file&&t.file(e)}))}announceObjects(e){this.listeners.forEach((t=>{t.objects&&t.objects(e)}))}announceNetworkUp(){this.listeners.forEach((e=>{e.status&&e.status({category:i.PNNetworkUpCategory})}))}announceNetworkDown(){this.listeners.forEach((e=>{e.status&&e.status({category:i.PNNetworkDownCategory})}))}announceUser(e){this.listeners.forEach((t=>{t.user&&t.user(e)}))}announceSpace(e){this.listeners.forEach((t=>{t.space&&t.space(e)}))}announceMembership(e){this.listeners.forEach((t=>{t.membership&&t.membership(e)}))}}class Q{constructor(e){this.time=e}onReconnect(e){this.callback=e}startPolling(){this.timeTimer=setInterval((()=>this.callTime()),3e3)}stopPolling(){this.timeTimer&&clearInterval(this.timeTimer),this.timeTimer=null}callTime(){this.time((e=>{e.error||(this.stopPolling(),this.callback&&this.callback())}))}}class Y{_config;hashHistory;constructor({config:e}){this.hashHistory=[],this._config=e}getKey(e){const t=(e=>{let t=0;if(0===e.length)return t;for(let s=0;s=this._config.maximumCacheSize&&this.hashHistory.shift(),this.hashHistory.push(this.getKey(e))}clearHistory(){this.hashHistory=[]}}class X{constructor(e,t,s,n,r,i,o){this.configuration=e,this.listenerManager=t,this.eventEmitter=s,this.subscribeCall=n,this.heartbeatCall=r,this.leaveCall=i,this.reconnectionManager=new Q(o),this.dedupingManager=new Y({config:this.configuration}),this.heartbeatChannelGroups={},this.heartbeatChannels={},this.presenceChannelGroups={},this.presenceChannels={},this.heartbeatTimer=null,this.presenceState={},this.pendingChannelGroupSubscriptions=new Set,this.pendingChannelSubscriptions=new Set,this.channelGroups={},this.channels={},this.currentTimetoken="0",this.lastTimetoken="0",this.storedTimetoken=null,this.subscriptionStatusAnnounced=!1,this.isOnline=!0}get subscribedChannels(){return Object.keys(this.channels)}get subscribedChannelGroups(){return Object.keys(this.channelGroups)}get abort(){return this._subscribeAbort}set abort(e){this._subscribeAbort=e}disconnect(){this.stopSubscribeLoop(),this.stopHeartbeatTimer(),this.reconnectionManager.stopPolling()}reconnect(){this.startSubscribeLoop(),this.startHeartbeatTimer()}subscribe(e){const{channels:t,channelGroups:s,timetoken:n,withPresence:r=!1,withHeartbeats:i=!1}=e;n&&(this.lastTimetoken=this.currentTimetoken,this.currentTimetoken=n),"0"!==this.currentTimetoken&&0!==this.currentTimetoken&&(this.storedTimetoken=this.currentTimetoken,this.currentTimetoken=0),null==t||t.forEach((e=>{this.pendingChannelSubscriptions.add(e),this.channels[e]={},r&&(this.presenceChannels[e]={}),(i||this.configuration.getHeartbeatInterval())&&(this.heartbeatChannels[e]={})})),null==s||s.forEach((e=>{this.pendingChannelGroupSubscriptions.add(e),this.channelGroups[e]={},r&&(this.presenceChannelGroups[e]={}),(i||this.configuration.getHeartbeatInterval())&&(this.heartbeatChannelGroups[e]={})})),this.subscriptionStatusAnnounced=!1,this.reconnect()}unsubscribe(e,t){let{channels:s,channelGroups:n}=e;const r=new Set,i=new Set;null==s||s.forEach((e=>{e in this.channels&&(delete this.channels[e],i.add(e),e in this.heartbeatChannels&&delete this.heartbeatChannels[e]),e in this.presenceState&&delete this.presenceState[e],e in this.presenceChannels&&(delete this.presenceChannels[e],i.add(e))})),null==n||n.forEach((e=>{e in this.channelGroups&&(delete this.channelGroups[e],r.add(e),e in this.heartbeatChannelGroups&&delete this.heartbeatChannelGroups[e]),e in this.presenceState&&delete this.presenceState[e],e in this.presenceChannelGroups&&(delete this.presenceChannelGroups[e],r.add(e))})),0===i.size&&0===r.size||(!1!==this.configuration.suppressLeaveEvents||t||(n=Array.from(r),s=Array.from(i),this.leaveCall({channels:s,channelGroups:n},(e=>{const{error:t}=e,r=l(e,["error"]);let i;t&&(e.errorData&&"object"==typeof e.errorData&&"message"in e.errorData&&"string"==typeof e.errorData.message?i=e.errorData.message:"message"in e&&"string"==typeof e.message&&(i=e.message)),this.listenerManager.announceStatus(Object.assign(Object.assign({},r),{error:null!=i&&i,affectedChannels:s,affectedChannelGroups:n,currentTimetoken:this.currentTimetoken,lastTimetoken:this.lastTimetoken}))}))),0===Object.keys(this.channels).length&&0===Object.keys(this.presenceChannels).length&&0===Object.keys(this.channelGroups).length&&0===Object.keys(this.presenceChannelGroups).length&&(this.lastTimetoken=0,this.currentTimetoken=0,this.storedTimetoken=null,this.region=null,this.reconnectionManager.stopPolling()),this.reconnect())}unsubscribeAll(e){this.unsubscribe({channels:this.subscribedChannels,channelGroups:this.subscribedChannelGroups},e)}startSubscribeLoop(){this.stopSubscribeLoop();const e=[...Object.keys(this.channelGroups)],t=[...Object.keys(this.channels)];Object.keys(this.presenceChannelGroups).forEach((t=>e.push(`${t}-pnpres`))),Object.keys(this.presenceChannels).forEach((e=>t.push(`${e}-pnpres`))),0===t.length&&0===e.length||this.subscribeCall({channels:t,channelGroups:e,state:this.presenceState,heartbeat:this.configuration.getPresenceTimeout(),timetoken:this.currentTimetoken,region:null!==this.region?this.region:void 0,filterExpression:this.configuration.filterExpression},((e,t)=>{this.processSubscribeResponse(e,t)}))}stopSubscribeLoop(){this._subscribeAbort&&(this._subscribeAbort(),this._subscribeAbort=null)}processSubscribeResponse(e,t){if(e.error){if("object"==typeof e.errorData&&"name"in e.errorData&&"AbortError"===e.errorData.name||e.category===i.PNCancelledCategory)return;return void(e.category===i.PNTimeoutCategory?this.startSubscribeLoop():e.category===i.PNNetworkIssuesCategory?(this.disconnect(),e.error&&this.configuration.autoNetworkDetection&&this.isOnline&&(this.isOnline=!1,this.listenerManager.announceNetworkDown()),this.reconnectionManager.onReconnect((()=>{this.configuration.autoNetworkDetection&&!this.isOnline&&(this.isOnline=!0,this.listenerManager.announceNetworkUp()),this.reconnect(),this.subscriptionStatusAnnounced=!0;const t={category:i.PNReconnectedCategory,operation:e.operation,lastTimetoken:this.lastTimetoken,currentTimetoken:this.currentTimetoken};this.listenerManager.announceStatus(t)})),this.reconnectionManager.startPolling(),this.listenerManager.announceStatus(e)):e.category===i.PNBadRequestCategory?(this.stopHeartbeatTimer(),this.listenerManager.announceStatus(e)):this.listenerManager.announceStatus(e))}if(this.storedTimetoken?(this.currentTimetoken=this.storedTimetoken,this.storedTimetoken=null):(this.lastTimetoken=this.currentTimetoken,this.currentTimetoken=t.cursor.timetoken),!this.subscriptionStatusAnnounced){const t={category:i.PNConnectedCategory,operation:e.operation,affectedChannels:Array.from(this.pendingChannelSubscriptions),subscribedChannels:this.subscribedChannels,affectedChannelGroups:Array.from(this.pendingChannelGroupSubscriptions),lastTimetoken:this.lastTimetoken,currentTimetoken:this.currentTimetoken};this.subscriptionStatusAnnounced=!0,this.listenerManager.announceStatus(t),this.pendingChannelGroupSubscriptions.clear(),this.pendingChannelSubscriptions.clear()}const{messages:s}=t,{requestMessageCountThreshold:n,dedupeOnSubscribe:r}=this.configuration;n&&s.length>=n&&this.listenerManager.announceStatus({category:i.PNRequestMessageCountExceededCategory,operation:e.operation});try{s.forEach((e=>{if(r){if(this.dedupingManager.isDuplicate(e.data))return;this.dedupingManager.addEntry(e.data)}this.eventEmitter.emitEvent(e)}))}catch(e){const t={error:!0,category:i.PNUnknownCategory,errorData:e,statusCode:0};this.listenerManager.announceStatus(t)}this.region=t.cursor.region,this.startSubscribeLoop()}setState(e){const{state:t,channels:s,channelGroups:n}=e;null==s||s.forEach((e=>e in this.channels&&(this.presenceState[e]=t))),null==n||n.forEach((e=>e in this.channelGroups&&(this.presenceState[e]=t)))}changePresence(e){const{connected:t,channels:s,channelGroups:n}=e;t?(null==s||s.forEach((e=>this.heartbeatChannels[e]={})),null==n||n.forEach((e=>this.heartbeatChannelGroups[e]={}))):(null==s||s.forEach((e=>{e in this.heartbeatChannels&&delete this.heartbeatChannels[e]})),null==n||n.forEach((e=>{e in this.heartbeatChannelGroups&&delete this.heartbeatChannelGroups[e]})),!1===this.configuration.suppressLeaveEvents&&this.leaveCall({channels:s,channelGroups:n},(e=>this.listenerManager.announceStatus(e)))),this.reconnect()}startHeartbeatTimer(){this.stopHeartbeatTimer();const e=this.configuration.getHeartbeatInterval();e&&0!==e&&(this.sendHeartbeat(),this.heartbeatTimer=setInterval((()=>this.sendHeartbeat()),1e3*e))}stopHeartbeatTimer(){this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null)}sendHeartbeat(){const e=Object.keys(this.heartbeatChannelGroups),t=Object.keys(this.heartbeatChannels);0===t.length&&0===e.length||this.heartbeatCall({channels:t,channelGroups:e,heartbeat:this.configuration.getPresenceTimeout(),state:this.presenceState},(e=>{e.error&&this.configuration.announceFailedHeartbeats&&this.listenerManager.announceStatus(e),e.error&&this.configuration.autoNetworkDetection&&this.isOnline&&(this.isOnline=!1,this.disconnect(),this.listenerManager.announceNetworkDown(),this.reconnect()),!e.error&&this.configuration.announceSuccessfulHeartbeats&&this.listenerManager.announceStatus(e)}))}}class Z{constructor(e,t,s){this._payload=e,this.setDefaultPayloadStructure(),this.title=t,this.body=s}get payload(){return this._payload}set title(e){this._title=e}set subtitle(e){this._subtitle=e}set body(e){this._body=e}set badge(e){this._badge=e}set sound(e){this._sound=e}setDefaultPayloadStructure(){}toObject(){return{}}}class ee extends Z{constructor(){super(...arguments),this._apnsPushType="apns",this._isSilent=!1}get payload(){return this._payload}set configurations(e){e&&e.length&&(this._configurations=e)}get notification(){return this.payload.aps}get title(){return this._title}set title(e){e&&e.length&&(this.payload.aps.alert.title=e,this._title=e)}get subtitle(){return this._subtitle}set subtitle(e){e&&e.length&&(this.payload.aps.alert.subtitle=e,this._subtitle=e)}get body(){return this._body}set body(e){e&&e.length&&(this.payload.aps.alert.body=e,this._body=e)}get badge(){return this._badge}set badge(e){null!=e&&(this.payload.aps.badge=e,this._badge=e)}get sound(){return this._sound}set sound(e){e&&e.length&&(this.payload.aps.sound=e,this._sound=e)}set silent(e){this._isSilent=e}setDefaultPayloadStructure(){this.payload.aps={alert:{}}}toObject(){const e=Object.assign({},this.payload),{aps:t}=e;let{alert:s}=t;if(this._isSilent&&(t["content-available"]=1),"apns2"===this._apnsPushType){if(!this._configurations||!this._configurations.length)throw new ReferenceError("APNS2 configuration is missing");const t=[];this._configurations.forEach((e=>{t.push(this.objectFromAPNS2Configuration(e))})),t.length&&(e.pn_push=t)}return s&&Object.keys(s).length||delete t.alert,this._isSilent&&(delete t.alert,delete t.badge,delete t.sound,s={}),this._isSilent||s&&Object.keys(s).length?e:null}objectFromAPNS2Configuration(e){if(!e.targets||!e.targets.length)throw new ReferenceError("At least one APNS2 target should be provided");const{collapseId:t,expirationDate:s}=e,n={auth_method:"token",targets:e.targets.map((e=>this.objectFromAPNSTarget(e))),version:"v2"};return t&&t.length&&(n.collapse_id=t),s&&(n.expiration=s.toISOString()),n}objectFromAPNSTarget(e){if(!e.topic||!e.topic.length)throw new TypeError("Target 'topic' undefined.");const{topic:t,environment:s="development",excludedDevices:n=[]}=e,r={topic:t,environment:s};return n.length&&(r.excluded_devices=n),r}}class te extends Z{get payload(){return this._payload}get notification(){return this.payload.notification}get data(){return this.payload.data}get title(){return this._title}set title(e){e&&e.length&&(this.payload.notification.title=e,this._title=e)}get body(){return this._body}set body(e){e&&e.length&&(this.payload.notification.body=e,this._body=e)}get sound(){return this._sound}set sound(e){e&&e.length&&(this.payload.notification.sound=e,this._sound=e)}get icon(){return this._icon}set icon(e){e&&e.length&&(this.payload.notification.icon=e,this._icon=e)}get tag(){return this._tag}set tag(e){e&&e.length&&(this.payload.notification.tag=e,this._tag=e)}set silent(e){this._isSilent=e}setDefaultPayloadStructure(){this.payload.notification={},this.payload.data={}}toObject(){let e=Object.assign({},this.payload.data),t=null;const s={};if(Object.keys(this.payload).length>2){const t=l(this.payload,["notification","data"]);e=Object.assign(Object.assign({},e),t)}return this._isSilent?e.notification=this.payload.notification:t=this.payload.notification,Object.keys(e).length&&(s.data=e),t&&Object.keys(t).length&&(s.notification=t),Object.keys(s).length?s:null}}class se{constructor(e,t){this._payload={apns:{},fcm:{}},this._title=e,this._body=t,this.apns=new ee(this._payload.apns,e,t),this.fcm=new te(this._payload.fcm,e,t)}set debugging(e){this._debugging=e}get title(){return this._title}get subtitle(){return this._subtitle}set subtitle(e){this._subtitle=e,this.apns.subtitle=e,this.fcm.subtitle=e}get body(){return this._body}get badge(){return this._badge}set badge(e){this._badge=e,this.apns.badge=e,this.fcm.badge=e}get sound(){return this._sound}set sound(e){this._sound=e,this.apns.sound=e,this.fcm.sound=e}buildPayload(e){const t={};if(e.includes("apns")||e.includes("apns2")){this.apns._apnsPushType=e.includes("apns")?"apns":"apns2";const s=this.apns.toObject();s&&Object.keys(s).length&&(t.pn_apns=s)}if(e.includes("fcm")){const e=this.fcm.toObject();e&&Object.keys(e).length&&(t.pn_gcm=e)}return Object.keys(t).length&&this._debugging&&(t.pn_debug=!0),t}}class ne{constructor(e){this.params=e,this.requestIdentifier=$.createUUID(),this._cancellationController=null}get cancellationController(){return this._cancellationController}set cancellationController(e){this._cancellationController=e}abort(){this&&this.cancellationController&&this.cancellationController.abort()}operation(){throw Error("Should be implemented by subclass.")}validate(){}parse(e){return h(this,void 0,void 0,(function*(){throw Error("Should be implemented by subclass.")}))}request(){var e,t,s,n;const r={method:null!==(t=null===(e=this.params)||void 0===e?void 0:e.method)&&void 0!==t?t:z.GET,path:this.path,queryParameters:this.queryParameters,cancellable:null!==(n=null===(s=this.params)||void 0===s?void 0:s.cancellable)&&void 0!==n&&n,timeout:1e4,identifier:this.requestIdentifier},i=this.headers;if(i&&(r.headers=i),r.method===z.POST||r.method===z.PATCH){const[e,t]=[this.body,this.formData];t&&(r.formData=t),e&&(r.body=e)}return r}get headers(){}get path(){throw Error("`path` getter should be implemented by subclass.")}get queryParameters(){return{}}get formData(){}get body(){}deserializeResponse(e){const t=e.headers["content-type"];if(!t||-1===t.indexOf("javascript")&&-1===t.indexOf("json"))return;const s=ne.decoder.decode(e.body);try{return JSON.parse(s)}catch(e){return void console.error("Error parsing JSON response:",e)}}}var re;ne.decoder=new TextDecoder,function(e){e.PNPublishOperation="PNPublishOperation",e.PNSignalOperation="PNSignalOperation",e.PNSubscribeOperation="PNSubscribeOperation",e.PNUnsubscribeOperation="PNUnsubscribeOperation",e.PNWhereNowOperation="PNWhereNowOperation",e.PNHereNowOperation="PNHereNowOperation",e.PNGlobalHereNowOperation="PNGlobalHereNowOperation",e.PNSetStateOperation="PNSetStateOperation",e.PNGetStateOperation="PNGetStateOperation",e.PNHeartbeatOperation="PNHeartbeatOperation",e.PNAddMessageActionOperation="PNAddActionOperation",e.PNRemoveMessageActionOperation="PNRemoveMessageActionOperation",e.PNGetMessageActionsOperation="PNGetMessageActionsOperation",e.PNTimeOperation="PNTimeOperation",e.PNHistoryOperation="PNHistoryOperation",e.PNDeleteMessagesOperation="PNDeleteMessagesOperation",e.PNFetchMessagesOperation="PNFetchMessagesOperation",e.PNMessageCounts="PNMessageCountsOperation",e.PNGetAllUUIDMetadataOperation="PNGetAllUUIDMetadataOperation",e.PNGetUUIDMetadataOperation="PNGetUUIDMetadataOperation",e.PNSetUUIDMetadataOperation="PNSetUUIDMetadataOperation",e.PNRemoveUUIDMetadataOperation="PNRemoveUUIDMetadataOperation",e.PNGetAllChannelMetadataOperation="PNGetAllChannelMetadataOperation",e.PNGetChannelMetadataOperation="PNGetChannelMetadataOperation",e.PNSetChannelMetadataOperation="PNSetChannelMetadataOperation",e.PNRemoveChannelMetadataOperation="PNRemoveChannelMetadataOperation",e.PNGetMembersOperation="PNGetMembersOperation",e.PNSetMembersOperation="PNSetMembersOperation",e.PNGetMembershipsOperation="PNGetMembershipsOperation",e.PNSetMembershipsOperation="PNSetMembershipsOperation",e.PNListFilesOperation="PNListFilesOperation",e.PNGenerateUploadUrlOperation="PNGenerateUploadUrlOperation",e.PNPublishFileOperation="PNPublishFileOperation",e.PNPublishFileMessageOperation="PNPublishFileMessageOperation",e.PNGetFileUrlOperation="PNGetFileUrlOperation",e.PNDownloadFileOperation="PNDownloadFileOperation",e.PNDeleteFileOperation="PNDeleteFileOperation",e.PNAddPushNotificationEnabledChannelsOperation="PNAddPushNotificationEnabledChannelsOperation",e.PNRemovePushNotificationEnabledChannelsOperation="PNRemovePushNotificationEnabledChannelsOperation",e.PNPushNotificationEnabledChannelsOperation="PNPushNotificationEnabledChannelsOperation",e.PNRemoveAllPushNotificationsOperation="PNRemoveAllPushNotificationsOperation",e.PNChannelGroupsOperation="PNChannelGroupsOperation",e.PNRemoveGroupOperation="PNRemoveGroupOperation",e.PNChannelsForGroupOperation="PNChannelsForGroupOperation",e.PNAddChannelsToGroupOperation="PNAddChannelsToGroupOperation",e.PNRemoveChannelsFromGroupOperation="PNRemoveChannelsFromGroupOperation",e.PNAccessManagerGrant="PNAccessManagerGrant",e.PNAccessManagerGrantToken="PNAccessManagerGrantToken",e.PNAccessManagerAudit="PNAccessManagerAudit",e.PNAccessManagerRevokeToken="PNAccessManagerRevokeToken",e.PNHandshakeOperation="PNHandshakeOperation",e.PNReceiveMessagesOperation="PNReceiveMessagesOperation"}(re||(re={}));var ie=re;var oe;!function(e){e[e.Presence=-2]="Presence",e[e.Message=-1]="Message",e[e.Signal=1]="Signal",e[e.AppContext=2]="AppContext",e[e.MessageAction=3]="MessageAction",e[e.Files=4]="Files"}(oe||(oe={}));class ae extends ne{constructor(e){var t,s,n,r,i,o;super({cancellable:!0}),this.parameters=e,null!==(t=(r=this.parameters).withPresence)&&void 0!==t||(r.withPresence=false),null!==(s=(i=this.parameters).channelGroups)&&void 0!==s||(i.channelGroups=[]),null!==(n=(o=this.parameters).channels)&&void 0!==n||(o.channels=[])}operation(){return ie.PNSubscribeOperation}validate(){const{keySet:{subscribeKey:e},channels:t,channelGroups:s}=this.parameters;return e?t||s?void 0:"`channels` and `channelGroups` both should not be empty":"Missing Subscribe Key"}parse(e){return h(this,void 0,void 0,(function*(){let t;try{const s=ne.decoder.decode(e.body);t=JSON.parse(s)}catch(e){console.error("Error parsing JSON response:",e)}if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));const s=t.m.map((e=>{let{e:t}=e;return null!=t||(t=e.c.endsWith("-pnpres")?oe.Presence:oe.Message),"string"==typeof e.d?t==oe.Message?{type:oe.Message,data:this.messageFromEnvelope(e)}:{type:oe.Files,data:this.fileFromEnvelope(e)}:t==oe.Message?{type:oe.Message,data:this.messageFromEnvelope(e)}:t===oe.Presence?{type:oe.Presence,data:this.presenceEventFromEnvelope(e)}:t==oe.Signal?{type:oe.Signal,data:this.signalFromEnvelope(e)}:t===oe.AppContext?{type:oe.AppContext,data:this.appContextFromEnvelope(e)}:t===oe.MessageAction?{type:oe.MessageAction,data:this.messageActionFromEnvelope(e)}:{type:oe.Files,data:this.fileFromEnvelope(e)}}));return{cursor:{timetoken:t.t.t,region:t.t.r},messages:s}}))}get headers(){return{accept:"text/javascript"}}presenceEventFromEnvelope(e){const{d:t}=e,[s,n]=this.subscriptionChannelFromEnvelope(e),r=s.replace("-pnpres",""),i=null!==n?r:null,o=null!==n?n:r;return"string"!=typeof t&&"data"in t&&(t.state=t.data,delete t.data),Object.assign({channel:r,subscription:n,actualChannel:i,subscribedChannel:o,timetoken:e.p.t},t)}messageFromEnvelope(e){const[t,s]=this.subscriptionChannelFromEnvelope(e),[n,r]=this.decryptedData(e.d),i={channel:t,subscription:s,actualChannel:null!==s?t:null,subscribedChannel:null!==s?s:t,timetoken:e.p.t,publisher:e.i,message:n};return e.u&&(i.userMetadata=e.u),r&&(i.error=r),i}signalFromEnvelope(e){const[t,s]=this.subscriptionChannelFromEnvelope(e),n={channel:t,subscription:s,timetoken:e.p.t,publisher:e.i,message:e.d};return e.u&&(n.userMetadata=e.u),n}messageActionFromEnvelope(e){const[t,s]=this.subscriptionChannelFromEnvelope(e),n=e.d;return{channel:t,subscription:s,timetoken:e.p.t,publisher:e.i,event:n.event,data:Object.assign(Object.assign({},n.data),{uuid:e.i})}}appContextFromEnvelope(e){const[t,s]=this.subscriptionChannelFromEnvelope(e),n=e.d;return{channel:t,subscription:s,timetoken:e.p.t,message:n}}fileFromEnvelope(e){const[t,s]=this.subscriptionChannelFromEnvelope(e),[n,r]=this.decryptedData(e.d);let i=r;const o={channel:t,subscription:s,timetoken:e.p.t,publisher:e.i};return e.u&&(o.userMetadata=e.u),n?"string"==typeof n?null!=i||(i="Unexpected file information payload data type."):(o.message=n.message,n.file&&(o.file={id:n.file.id,name:n.file.name,url:this.parameters.getFileUrl({id:n.file.id,name:n.file.name,channel:t})})):null!=i||(i="File information payload is missing."),i&&(o.error=i),o}subscriptionChannelFromEnvelope(e){return[e.c,void 0===e.b?e.c:e.b]}decryptedData(e){if(!this.parameters.crypto||"string"!=typeof e)return[e,void 0];let t,s;try{const s=this.parameters.crypto.decrypt(e);t=s instanceof ArrayBuffer?JSON.parse(ce.decoder.decode(s)):s}catch(e){t=null,s=`Error while decrypting message content: ${e.message}`}return[null!=t?t:e,s]}}class ce extends ae{get path(){var e;const{keySet:{subscribeKey:t},channels:s}=this.parameters;return`/v2/subscribe/${t}/${I(null!==(e=null==s?void 0:s.sort())&&void 0!==e?e:[],",")}/0`}get queryParameters(){const{channelGroups:e,filterExpression:t,heartbeat:s,state:n,timetoken:r,region:i}=this.parameters,o={};return e&&e.length>0&&(o["channel-group"]=e.sort().join(",")),t&&t.length>0&&(o["filter-expr"]=t),s&&(o.heartbeat=s),n&&Object.keys(n).length>0&&(o.state=JSON.stringify(n)),void 0!==r&&"string"==typeof r?r.length>0&&"0"!==r&&(o.tt=r):void 0!==r&&r>0&&(o.tt=r),i&&(o.tr=i),o}}class ue{constructor(e){this.listenerManager=e,this.channelListenerMap=new Map,this.groupListenerMap=new Map}emitEvent(e){if(e.type===oe.Message)this.listenerManager.announceMessage(e.data),this.announce("message",e.data,e.data.channel,e.data.subscription);else if(e.type===oe.Signal)this.listenerManager.announceSignal(e.data),this.announce("signal",e.data,e.data.channel,e.data.subscription);else if(e.type===oe.Presence)this.listenerManager.announcePresence(e.data),this.announce("presence",e.data,e.data.channel,e.data.subscription);else if(e.type===oe.AppContext){const{data:t}=e,{message:s}=t;if(this.listenerManager.announceObjects(t),this.announce("objects",t,t.channel,t.subscription),"uuid"===s.type){const{message:e,channel:n}=t,r=l(t,["message","channel"]),{event:i,type:o}=s,a=l(s,["event","type"]),c=Object.assign(Object.assign({},r),{spaceId:n,message:Object.assign(Object.assign({},a),{event:"set"===i?"updated":"removed",type:"user"})});this.listenerManager.announceUser(c),this.announce("user",c,c.spaceId,c.subscription)}else if("channel"===s.type){const{message:e,channel:n}=t,r=l(t,["message","channel"]),{event:i,type:o}=s,a=l(s,["event","type"]),c=Object.assign(Object.assign({},r),{spaceId:n,message:Object.assign(Object.assign({},a),{event:"set"===i?"updated":"removed",type:"space"})});this.listenerManager.announceSpace(c),this.announce("space",c,c.spaceId,c.subscription)}else if("membership"===s.type){const{message:e,channel:n}=t,r=l(t,["message","channel"]),{event:i,data:o}=s,a=l(s,["event","data"]),{uuid:c,channel:u}=o,h=l(o,["uuid","channel"]),d=Object.assign(Object.assign({},r),{spaceId:n,message:Object.assign(Object.assign({},a),{event:"set"===i?"updated":"removed",data:Object.assign(Object.assign({},h),{user:c,space:u})})});this.listenerManager.announceMembership(d),this.announce("membership",d,d.spaceId,d.subscription)}}else e.type===oe.MessageAction?(this.listenerManager.announceMessageAction(e.data),this.announce("messageAction",e.data,e.data.channel,e.data.subscription)):e.type===oe.Files&&(this.listenerManager.announceFile(e.data),this.announce("file",e.data,e.data.channel,e.data.subscription))}addListener(e,t,s){t&&s?(null==t||t.forEach((t=>{if(this.channelListenerMap.has(t)){const s=this.channelListenerMap.get(t);s.includes(e)||s.push(e)}else this.channelListenerMap.set(t,[e])})),null==s||s.forEach((t=>{if(this.groupListenerMap.has(t)){const s=this.groupListenerMap.get(t);s.includes(e)||s.push(e)}else this.groupListenerMap.set(t,[e])}))):this.listenerManager.addListener(e)}removeListener(e,t,s){t&&s?(null==t||t.forEach((t=>{this.channelListenerMap.has(t)&&this.channelListenerMap.set(t,this.channelListenerMap.get(t).filter((t=>t!==e)))})),null==s||s.forEach((t=>{this.groupListenerMap.has(t)&&this.groupListenerMap.set(t,this.groupListenerMap.get(t).filter((t=>t!==e)))}))):this.listenerManager.removeListener(e)}removeAllListeners(){this.listenerManager.removeAllListeners(),this.channelListenerMap.clear(),this.groupListenerMap.clear()}announce(e,t,s,n){t&&this.channelListenerMap.has(s)&&this.channelListenerMap.get(s).forEach((s=>{const n=s[e];n&&n(t)})),n&&this.groupListenerMap.has(n)&&this.groupListenerMap.get(n).forEach((s=>{const n=s[e];n&&n(t)}))}}class le{constructor(e=!1){this.sync=e,this.listeners=new Set}subscribe(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}notify(e){const t=()=>{this.listeners.forEach((t=>{t(e)}))};this.sync?t():setTimeout(t,0)}}class he{transition(e,t){var s;if(this.transitionMap.has(t.type))return null===(s=this.transitionMap.get(t.type))||void 0===s?void 0:s(e,t)}constructor(e){this.label=e,this.transitionMap=new Map,this.enterEffects=[],this.exitEffects=[]}on(e,t){return this.transitionMap.set(e,t),this}with(e,t){return[this,e,null!=t?t:[]]}onEnter(e){return this.enterEffects.push(e),this}onExit(e){return this.exitEffects.push(e),this}}class de extends le{describe(e){return new he(e)}start(e,t){this.currentState=e,this.currentContext=t,this.notify({type:"engineStarted",state:e,context:t})}transition(e){if(!this.currentState)throw new Error("Start the engine first");this.notify({type:"eventReceived",event:e});const t=this.currentState.transition(this.currentContext,e);if(t){const[s,n,r]=t;for(const e of this.currentState.exitEffects)this.notify({type:"invocationDispatched",invocation:e(this.currentContext)});const i=this.currentState;this.currentState=s;const o=this.currentContext;this.currentContext=n,this.notify({type:"transitionDone",fromState:i,fromContext:o,toState:s,toContext:n,event:e});for(const e of r)this.notify({type:"invocationDispatched",invocation:e});for(const e of this.currentState.enterEffects)this.notify({type:"invocationDispatched",invocation:e(this.currentContext)})}}}class pe{constructor(e){this.dependencies=e,this.instances=new Map,this.handlers=new Map}on(e,t){this.handlers.set(e,t)}dispatch(e){if("CANCEL"===e.type){if(this.instances.has(e.payload)){const t=this.instances.get(e.payload);null==t||t.cancel(),this.instances.delete(e.payload)}return}const t=this.handlers.get(e.type);if(!t)throw new Error(`Unhandled invocation '${e.type}'`);const s=t(e.payload,this.dependencies);e.managed&&this.instances.set(e.type,s),s.start()}dispose(){for(const[e,t]of this.instances.entries())t.cancel(),this.instances.delete(e)}}function ge(e,t){const s=function(...s){return{type:e,payload:null==t?void 0:t(...s)}};return s.type=e,s}function ye(e,t){const s=(...s)=>({type:e,payload:t(...s),managed:!1});return s.type=e,s}function fe(e,t){const s=(...s)=>({type:e,payload:t(...s),managed:!0});return s.type=e,s.cancel={type:"CANCEL",payload:e,managed:!1},s}class me extends Error{constructor(){super("The operation was aborted."),this.name="AbortError",Object.setPrototypeOf(this,new.target.prototype)}}class be extends le{constructor(){super(...arguments),this._aborted=!1}get aborted(){return this._aborted}throwIfAborted(){if(this._aborted)throw new me}abort(){this._aborted=!0,this.notify(new me)}}class ve{constructor(e,t){this.payload=e,this.dependencies=t}}class we extends ve{constructor(e,t,s){super(e,t),this.asyncFunction=s,this.abortSignal=new be}start(){this.asyncFunction(this.payload,this.abortSignal,this.dependencies).catch((e=>{}))}cancel(){this.abortSignal.abort()}}const Se=e=>(t,s)=>new we(t,s,e),ke=ge("RECONNECT",(()=>({}))),Ee=ge("DISCONNECT",(()=>({}))),Oe=ge("JOINED",((e,t)=>({channels:e,groups:t}))),Ce=ge("LEFT",((e,t)=>({channels:e,groups:t}))),Ne=ge("LEFT_ALL",(()=>({}))),Pe=ge("HEARTBEAT_SUCCESS",(e=>({statusCode:e}))),Me=ge("HEARTBEAT_FAILURE",(e=>e)),je=ge("HEARTBEAT_GIVEUP",(()=>({}))),_e=ge("TIMES_UP",(()=>({}))),Ae=ye("HEARTBEAT",((e,t)=>({channels:e,groups:t}))),Re=ye("LEAVE",((e,t)=>({channels:e,groups:t}))),Ie=ye("EMIT_STATUS",(e=>e)),Ue=fe("WAIT",(()=>({}))),Te=fe("DELAYED_HEARTBEAT",(e=>e));class Fe extends pe{constructor(e,t){super(t),this.on(Ae.type,Se(((t,s,n)=>h(this,[t,s,n],void 0,(function*(t,s,{heartbeat:n,presenceState:r,config:a}){try{yield n(Object.assign(Object.assign({channels:t.channels,channelGroups:t.groups},a.maintainPresenceState&&{state:r}),{heartbeat:a.presenceTimeout}));e.transition(Pe(200))}catch(t){if(t instanceof o){if(t.status&&t.status.category==i.PNCancelledCategory)return;return e.transition(Me(t))}}}))))),this.on(Re.type,Se(((e,t,s)=>h(this,[e,t,s],void 0,(function*(e,t,{leave:s,config:n}){if(!n.suppressLeaveEvents)try{s({channels:e.channels,channelGroups:e.groups})}catch(e){}}))))),this.on(Ue.type,Se(((t,s,n)=>h(this,[t,s,n],void 0,(function*(t,s,{heartbeatDelay:n}){return s.throwIfAborted(),yield n(),s.throwIfAborted(),e.transition(_e())}))))),this.on(Te.type,Se(((t,s,n)=>h(this,[t,s,n],void 0,(function*(t,s,{heartbeat:n,retryDelay:r,presenceState:a,config:c}){if(!c.retryConfiguration||!c.retryConfiguration.shouldRetry(t.reason,t.attempts))return e.transition(je());s.throwIfAborted(),yield r(c.retryConfiguration.getDelay(t.attempts,t.reason)),s.throwIfAborted();try{yield n(Object.assign(Object.assign({channels:t.channels,channelGroups:t.groups},c.maintainPresenceState&&{state:a}),{heartbeat:c.presenceTimeout}));return e.transition(Pe(200))}catch(t){if(t instanceof o){if(t.status&&t.status.category==i.PNCancelledCategory)return;return e.transition(Me(t))}}}))))),this.on(Ie.type,Se(((e,t,s)=>h(this,[e,t,s],void 0,(function*(e,t,{emitStatus:s,config:n}){var r;n.announceFailedHeartbeats&&!0===(null===(r=null==e?void 0:e.status)||void 0===r?void 0:r.error)?s(e.status):n.announceSuccessfulHeartbeats&&200===e.statusCode&&s(Object.assign(Object.assign({},e),{operation:ie.PNHeartbeatOperation,error:!1}))})))))}}const xe=new he("HEARTBEAT_STOPPED");xe.on(Oe.type,((e,t)=>xe.with({channels:[...e.channels,...t.payload.channels],groups:[...e.groups,...t.payload.groups]}))),xe.on(Ce.type,((e,t)=>xe.with({channels:e.channels.filter((e=>!t.payload.channels.includes(e))),groups:e.groups.filter((e=>!t.payload.groups.includes(e)))}))),xe.on(ke.type,((e,t)=>Ge.with({channels:e.channels,groups:e.groups}))),xe.on(Ne.type,((e,t)=>$e.with(void 0)));const De=new he("HEARTBEAT_COOLDOWN");De.onEnter((()=>Ue())),De.onExit((()=>Ue.cancel)),De.on(_e.type,((e,t)=>Ge.with({channels:e.channels,groups:e.groups}))),De.on(Oe.type,((e,t)=>Ge.with({channels:[...e.channels,...t.payload.channels],groups:[...e.groups,...t.payload.groups]}))),De.on(Ce.type,((e,t)=>Ge.with({channels:e.channels.filter((e=>!t.payload.channels.includes(e))),groups:e.groups.filter((e=>!t.payload.groups.includes(e)))},[Re(t.payload.channels,t.payload.groups)]))),De.on(Ee.type,(e=>xe.with({channels:e.channels,groups:e.groups},[Re(e.channels,e.groups)]))),De.on(Ne.type,((e,t)=>$e.with(void 0,[Re(e.channels,e.groups)])));const Ke=new he("HEARTBEAT_FAILED");Ke.on(Oe.type,((e,t)=>Ge.with({channels:[...e.channels,...t.payload.channels],groups:[...e.groups,...t.payload.groups]}))),Ke.on(Ce.type,((e,t)=>Ge.with({channels:e.channels.filter((e=>!t.payload.channels.includes(e))),groups:e.groups.filter((e=>!t.payload.groups.includes(e)))},[Re(t.payload.channels,t.payload.groups)]))),Ke.on(ke.type,((e,t)=>Ge.with({channels:e.channels,groups:e.groups}))),Ke.on(Ee.type,((e,t)=>xe.with({channels:e.channels,groups:e.groups},[Re(e.channels,e.groups)]))),Ke.on(Ne.type,((e,t)=>$e.with(void 0,[Re(e.channels,e.groups)])));const qe=new he("HEARBEAT_RECONNECTING");qe.onEnter((e=>Te(e))),qe.onExit((()=>Te.cancel)),qe.on(Oe.type,((e,t)=>Ge.with({channels:[...e.channels,...t.payload.channels],groups:[...e.groups,...t.payload.groups]}))),qe.on(Ce.type,((e,t)=>Ge.with({channels:e.channels.filter((e=>!t.payload.channels.includes(e))),groups:e.groups.filter((e=>!t.payload.groups.includes(e)))},[Re(t.payload.channels,t.payload.groups)]))),qe.on(Ee.type,((e,t)=>{xe.with({channels:e.channels,groups:e.groups},[Re(e.channels,e.groups)])})),qe.on(Pe.type,((e,t)=>De.with({channels:e.channels,groups:e.groups}))),qe.on(Me.type,((e,t)=>qe.with(Object.assign(Object.assign({},e),{attempts:e.attempts+1,reason:t.payload})))),qe.on(je.type,((e,t)=>Ke.with({channels:e.channels,groups:e.groups}))),qe.on(Ne.type,((e,t)=>$e.with(void 0,[Re(e.channels,e.groups)])));const Ge=new he("HEARTBEATING");Ge.onEnter((e=>Ae(e.channels,e.groups))),Ge.on(Pe.type,((e,t)=>De.with({channels:e.channels,groups:e.groups}))),Ge.on(Oe.type,((e,t)=>Ge.with({channels:[...e.channels,...t.payload.channels],groups:[...e.groups,...t.payload.groups]}))),Ge.on(Ce.type,((e,t)=>Ge.with({channels:e.channels.filter((e=>!t.payload.channels.includes(e))),groups:e.groups.filter((e=>!t.payload.groups.includes(e)))},[Re(t.payload.channels,t.payload.groups)]))),Ge.on(Me.type,((e,t)=>qe.with(Object.assign(Object.assign({},e),{attempts:0,reason:t.payload})))),Ge.on(Ee.type,(e=>xe.with({channels:e.channels,groups:e.groups},[Re(e.channels,e.groups)]))),Ge.on(Ne.type,((e,t)=>$e.with(void 0,[Re(e.channels,e.groups)])));const $e=new he("HEARTBEAT_INACTIVE");$e.on(Oe.type,((e,t)=>Ge.with({channels:t.payload.channels,groups:t.payload.groups})));class Le{get _engine(){return this.engine}constructor(e){this.dependencies=e,this.engine=new de,this.channels=[],this.groups=[],this.dispatcher=new Fe(this.engine,e),this._unsubscribeEngine=this.engine.subscribe((e=>{"invocationDispatched"===e.type&&this.dispatcher.dispatch(e.invocation)})),this.engine.start($e,void 0)}join({channels:e,groups:t}){this.channels=[...this.channels,...null!=e?e:[]],this.groups=[...this.groups,...null!=t?t:[]],this.engine.transition(Oe(this.channels.slice(0),this.groups.slice(0)))}leave({channels:e,groups:t}){this.dependencies.presenceState&&(null==e||e.forEach((e=>delete this.dependencies.presenceState[e])),null==t||t.forEach((e=>delete this.dependencies.presenceState[e]))),this.engine.transition(Ce(null!=e?e:[],null!=t?t:[]))}leaveAll(){this.engine.transition(Ne())}dispose(){this._unsubscribeEngine(),this.dispatcher.dispose()}}class Be{static LinearRetryPolicy(e){return{delay:e.delay,maximumRetry:e.maximumRetry,shouldRetry(e,t){var s;return 403!==(null===(s=null==e?void 0:e.status)||void 0===s?void 0:s.statusCode)&&this.maximumRetry>t},getDelay(e,t){var s;return 1e3*((null!==(s=t.retryAfter)&&void 0!==s?s:this.delay)+Math.random())},getGiveupReason(e,t){var s;return this.maximumRetry<=t?"retry attempts exhaused.":403===(null===(s=null==e?void 0:e.status)||void 0===s?void 0:s.statusCode)?"forbidden operation.":"unknown error"},validate(){if(this.maximumRetry>10)throw new Error("Maximum retry for linear retry policy can not be more than 10")}}}static ExponentialRetryPolicy(e){return{minimumDelay:e.minimumDelay,maximumDelay:e.maximumDelay,maximumRetry:e.maximumRetry,shouldRetry(e,t){var s;return 403!==(null===(s=null==e?void 0:e.status)||void 0===s?void 0:s.statusCode)&&this.maximumRetry>t},getDelay(e,t){var s;return 1e3*((null!==(s=t.retryAfter)&&void 0!==s?s:Math.min(Math.pow(2,e),this.maximumDelay))+Math.random())},getGiveupReason(e,t){var s;return this.maximumRetry<=t?"retry attempts exhausted.":403===(null===(s=null==e?void 0:e.status)||void 0===s?void 0:s.statusCode)?"forbidden operation.":"unknown error"},validate(){if(this.minimumDelay<2)throw new Error("Minimum delay can not be set less than 2 seconds for retry");if(this.maximumDelay)throw new Error("Maximum delay can not be set more than 150 seconds for retry");if(this.maximumRetry>6)throw new Error("Maximum retry for exponential retry policy can not be more than 6")}}}}const He=fe("HANDSHAKE",((e,t)=>({channels:e,groups:t}))),ze=fe("RECEIVE_MESSAGES",((e,t,s)=>({channels:e,groups:t,cursor:s}))),Ve=ye("EMIT_MESSAGES",(e=>e)),We=ye("EMIT_STATUS",(e=>e)),Je=fe("RECEIVE_RECONNECT",(e=>e)),Qe=fe("HANDSHAKE_RECONNECT",(e=>e)),Ye=ge("SUBSCRIPTION_CHANGED",((e,t)=>({channels:e,groups:t}))),Xe=ge("SUBSCRIPTION_RESTORED",((e,t,s,n)=>({channels:e,groups:t,cursor:{timetoken:s,region:null!=n?n:0}}))),Ze=ge("HANDSHAKE_SUCCESS",(e=>e)),et=ge("HANDSHAKE_FAILURE",(e=>e)),tt=ge("HANDSHAKE_RECONNECT_SUCCESS",(e=>({cursor:e}))),st=ge("HANDSHAKE_RECONNECT_FAILURE",(e=>e)),nt=ge("HANDSHAKE_RECONNECT_GIVEUP",(e=>e)),rt=ge("RECEIVE_SUCCESS",((e,t)=>({cursor:e,events:t}))),it=ge("RECEIVE_FAILURE",(e=>e)),ot=ge("RECEIVE_RECONNECT_SUCCESS",((e,t)=>({cursor:e,events:t}))),at=ge("RECEIVE_RECONNECT_FAILURE",(e=>e)),ct=ge("RECEIVING_RECONNECT_GIVEUP",(e=>e)),ut=ge("DISCONNECT",(()=>({}))),lt=ge("RECONNECT",((e,t)=>({cursor:{timetoken:null!=e?e:"",region:null!=t?t:0}}))),ht=ge("UNSUBSCRIBE_ALL",(()=>({})));class dt extends pe{constructor(e,t){super(t),this.on(He.type,Se(((t,s,n)=>h(this,[t,s,n],void 0,(function*(t,s,{handshake:n,presenceState:r,config:a}){s.throwIfAborted();try{const i=yield n(Object.assign({abortSignal:s,channels:t.channels,channelGroups:t.groups,filterExpression:a.filterExpression},a.maintainPresenceState&&{state:r}));return e.transition(Ze(i))}catch(t){if(t instanceof o){if(t.status&&t.status.category==i.PNCancelledCategory)return;return e.transition(et(t))}}}))))),this.on(ze.type,Se(((t,s,n)=>h(this,[t,s,n],void 0,(function*(t,s,{receiveMessages:n,config:r}){s.throwIfAborted();try{const i=yield n({abortSignal:s,channels:t.channels,channelGroups:t.groups,timetoken:t.cursor.timetoken,region:t.cursor.region,filterExpression:r.filterExpression});e.transition(rt(i.cursor,i.messages))}catch(t){if(t instanceof o){if(t.status&&t.status.category==i.PNCancelledCategory)return;if(!s.aborted)return e.transition(it(t))}}}))))),this.on(Ve.type,Se(((e,t,s)=>h(this,[e,t,s],void 0,(function*(e,t,{emitMessages:s}){e.length>0&&s(e)}))))),this.on(We.type,Se(((e,t,s)=>h(this,[e,t,s],void 0,(function*(e,t,{emitStatus:s}){s(e)}))))),this.on(Je.type,Se(((t,s,n)=>h(this,[t,s,n],void 0,(function*(t,s,{receiveMessages:n,delay:r,config:a}){if(!a.retryConfiguration||!a.retryConfiguration.shouldRetry(t.reason,t.attempts))return e.transition(ct(new o(a.retryConfiguration?a.retryConfiguration.getGiveupReason(t.reason,t.attempts):"Unable to complete subscribe messages receive.")));s.throwIfAborted(),yield r(a.retryConfiguration.getDelay(t.attempts,t.reason)),s.throwIfAborted();try{const r=yield n({abortSignal:s,channels:t.channels,channelGroups:t.groups,timetoken:t.cursor.timetoken,region:t.cursor.region,filterExpression:a.filterExpression});return e.transition(ot(r.cursor,r.messages))}catch(t){if(t instanceof o){if(t.status&&t.status.category==i.PNCancelledCategory)return;return e.transition(at(t))}}}))))),this.on(Qe.type,Se(((t,s,n)=>h(this,[t,s,n],void 0,(function*(t,s,{handshake:n,delay:r,presenceState:a,config:c}){if(!c.retryConfiguration||!c.retryConfiguration.shouldRetry(t.reason,t.attempts))return e.transition(nt(new o(c.retryConfiguration?c.retryConfiguration.getGiveupReason(t.reason,t.attempts):"Unable to complete subscribe handshake")));s.throwIfAborted(),yield r(c.retryConfiguration.getDelay(t.attempts,t.reason)),s.throwIfAborted();try{const r=yield n(Object.assign({abortSignal:s,channels:t.channels,channelGroups:t.groups,filterExpression:c.filterExpression},c.maintainPresenceState&&{state:a}));return e.transition(tt(r))}catch(t){if(t instanceof o){if(t.status&&t.status.category==i.PNCancelledCategory)return;return e.transition(st(t))}}})))))}}const pt=new he("HANDSHAKE_FAILED");pt.on(Ye.type,((e,t)=>wt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:e.cursor}))),pt.on(lt.type,((e,t)=>wt.with({channels:e.channels,groups:e.groups,cursor:t.payload.cursor||e.cursor}))),pt.on(Xe.type,((e,t)=>{var s,n;return wt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:{timetoken:t.payload.cursor.timetoken,region:t.payload.cursor.region?t.payload.cursor.region:null!==(n=null===(s=null==e?void 0:e.cursor)||void 0===s?void 0:s.region)&&void 0!==n?n:0}})})),pt.on(ht.type,(e=>St.with()));const gt=new he("HANDSHAKE_STOPPED");gt.on(Ye.type,((e,t)=>gt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:e.cursor}))),gt.on(lt.type,((e,t)=>wt.with(Object.assign(Object.assign({},e),{cursor:t.payload.cursor||e.cursor})))),gt.on(Xe.type,((e,t)=>{var s;return gt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:{timetoken:t.payload.cursor.timetoken,region:t.payload.cursor.region||(null===(s=null==e?void 0:e.cursor)||void 0===s?void 0:s.region)||0}})})),gt.on(ht.type,(e=>St.with()));const yt=new he("RECEIVE_FAILED");yt.on(lt.type,((e,t)=>{var s;return wt.with({channels:e.channels,groups:e.groups,cursor:{timetoken:t.payload.cursor.timetoken?null===(s=t.payload.cursor)||void 0===s?void 0:s.timetoken:e.cursor.timetoken,region:t.payload.cursor.region||e.cursor.region}})})),yt.on(Ye.type,((e,t)=>wt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:e.cursor}))),yt.on(Xe.type,((e,t)=>wt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:{timetoken:t.payload.cursor.timetoken,region:t.payload.cursor.region||e.cursor.region}}))),yt.on(ht.type,(e=>St.with(void 0)));const ft=new he("RECEIVE_STOPPED");ft.on(Ye.type,((e,t)=>ft.with({channels:t.payload.channels,groups:t.payload.groups,cursor:e.cursor}))),ft.on(Xe.type,((e,t)=>ft.with({channels:t.payload.channels,groups:t.payload.groups,cursor:{timetoken:t.payload.cursor.timetoken,region:t.payload.cursor.region||e.cursor.region}}))),ft.on(lt.type,((e,t)=>{var s;return wt.with({channels:e.channels,groups:e.groups,cursor:{timetoken:t.payload.cursor.timetoken?null===(s=t.payload.cursor)||void 0===s?void 0:s.timetoken:e.cursor.timetoken,region:t.payload.cursor.region||e.cursor.region}})})),ft.on(ht.type,(()=>St.with(void 0)));const mt=new he("RECEIVE_RECONNECTING");mt.onEnter((e=>Je(e))),mt.onExit((()=>Je.cancel)),mt.on(ot.type,((e,t)=>bt.with({channels:e.channels,groups:e.groups,cursor:t.payload.cursor},[Ve(t.payload.events)]))),mt.on(at.type,((e,t)=>mt.with(Object.assign(Object.assign({},e),{attempts:e.attempts+1,reason:t.payload})))),mt.on(ct.type,((e,t)=>{var s;return yt.with({groups:e.groups,channels:e.channels,cursor:e.cursor,reason:t.payload},[We({category:i.PNDisconnectedUnexpectedlyCategory,error:null===(s=t.payload)||void 0===s?void 0:s.message})])})),mt.on(ut.type,(e=>ft.with({channels:e.channels,groups:e.groups,cursor:e.cursor},[We({category:i.PNDisconnectedCategory})]))),mt.on(Xe.type,((e,t)=>bt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:{timetoken:t.payload.cursor.timetoken,region:t.payload.cursor.region||e.cursor.region}}))),mt.on(Ye.type,((e,t)=>bt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:e.cursor}))),mt.on(ht.type,(e=>St.with(void 0,[We({category:i.PNDisconnectedCategory})])));const bt=new he("RECEIVING");bt.onEnter((e=>ze(e.channels,e.groups,e.cursor))),bt.onExit((()=>ze.cancel)),bt.on(rt.type,((e,t)=>bt.with({channels:e.channels,groups:e.groups,cursor:t.payload.cursor},[Ve(t.payload.events)]))),bt.on(Ye.type,((e,t)=>0===t.payload.channels.length&&0===t.payload.groups.length?St.with(void 0):bt.with({cursor:e.cursor,channels:t.payload.channels,groups:t.payload.groups}))),bt.on(Xe.type,((e,t)=>0===t.payload.channels.length&&0===t.payload.groups.length?St.with(void 0):bt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:{timetoken:t.payload.cursor.timetoken,region:t.payload.cursor.region||e.cursor.region}}))),bt.on(it.type,((e,t)=>mt.with(Object.assign(Object.assign({},e),{attempts:0,reason:t.payload})))),bt.on(ut.type,(e=>ft.with({channels:e.channels,groups:e.groups,cursor:e.cursor},[We({category:i.PNDisconnectedCategory})]))),bt.on(ht.type,(e=>St.with(void 0,[We({category:i.PNDisconnectedCategory})])));const vt=new he("HANDSHAKE_RECONNECTING");vt.onEnter((e=>Qe(e))),vt.onExit((()=>Qe.cancel)),vt.on(tt.type,((e,t)=>{var s,n;const r={timetoken:(null===(s=e.cursor)||void 0===s?void 0:s.timetoken)?null===(n=e.cursor)||void 0===n?void 0:n.timetoken:t.payload.cursor.timetoken,region:t.payload.cursor.region};return bt.with({channels:e.channels,groups:e.groups,cursor:r},[We({category:i.PNConnectedCategory})])})),vt.on(st.type,((e,t)=>vt.with(Object.assign(Object.assign({},e),{attempts:e.attempts+1,reason:t.payload})))),vt.on(nt.type,((e,t)=>{var s;return pt.with({groups:e.groups,channels:e.channels,cursor:e.cursor,reason:t.payload},[We({category:i.PNConnectionErrorCategory,error:null===(s=t.payload)||void 0===s?void 0:s.message})])})),vt.on(ut.type,(e=>gt.with({channels:e.channels,groups:e.groups,cursor:e.cursor}))),vt.on(Ye.type,((e,t)=>wt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:e.cursor}))),vt.on(Xe.type,((e,t)=>{var s,n;return wt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:{timetoken:t.payload.cursor.timetoken,region:(null===(s=t.payload.cursor)||void 0===s?void 0:s.region)||(null===(n=null==e?void 0:e.cursor)||void 0===n?void 0:n.region)||0}})})),vt.on(ht.type,(e=>St.with(void 0)));const wt=new he("HANDSHAKING");wt.onEnter((e=>He(e.channels,e.groups))),wt.onExit((()=>He.cancel)),wt.on(Ye.type,((e,t)=>0===t.payload.channels.length&&0===t.payload.groups.length?St.with(void 0):wt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:e.cursor}))),wt.on(Ze.type,((e,t)=>{var s,n;return bt.with({channels:e.channels,groups:e.groups,cursor:{timetoken:(null===(s=null==e?void 0:e.cursor)||void 0===s?void 0:s.timetoken)?null===(n=null==e?void 0:e.cursor)||void 0===n?void 0:n.timetoken:t.payload.timetoken,region:t.payload.region}},[We({category:i.PNConnectedCategory})])})),wt.on(et.type,((e,t)=>vt.with({channels:e.channels,groups:e.groups,cursor:e.cursor,attempts:0,reason:t.payload}))),wt.on(ut.type,(e=>gt.with({channels:e.channels,groups:e.groups,cursor:e.cursor}))),wt.on(Xe.type,((e,t)=>{var s;return wt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:{timetoken:t.payload.cursor.timetoken,region:t.payload.cursor.region||(null===(s=null==e?void 0:e.cursor)||void 0===s?void 0:s.region)||0}})})),wt.on(ht.type,(e=>St.with()));const St=new he("UNSUBSCRIBED");St.on(Ye.type,((e,t)=>wt.with({channels:t.payload.channels,groups:t.payload.groups}))),St.on(Xe.type,((e,t)=>wt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:t.payload.cursor})));class kt{get _engine(){return this.engine}constructor(e){this.engine=new de,this.channels=[],this.groups=[],this.dependencies=e,this.dispatcher=new dt(this.engine,e),this._unsubscribeEngine=this.engine.subscribe((e=>{"invocationDispatched"===e.type&&this.dispatcher.dispatch(e.invocation)})),this.engine.start(St,void 0)}subscribe({channels:e,channelGroups:t,timetoken:s,withPresence:n}){this.channels=[...this.channels,...null!=e?e:[]],this.groups=[...this.groups,...null!=t?t:[]],n&&(this.channels.map((e=>this.channels.push(`${e}-pnpres`))),this.groups.map((e=>this.groups.push(`${e}-pnpres`)))),s?this.engine.transition(Xe(Array.from(new Set([...this.channels,...null!=e?e:[]])),Array.from(new Set([...this.groups,...null!=t?t:[]])),s)):this.engine.transition(Ye(Array.from(new Set([...this.channels,...null!=e?e:[]])),Array.from(new Set([...this.groups,...null!=t?t:[]])))),this.dependencies.join&&this.dependencies.join({channels:Array.from(new Set(this.channels.filter((e=>!e.endsWith("-pnpres"))))),groups:Array.from(new Set(this.groups.filter((e=>!e.endsWith("-pnpres")))))})}unsubscribe({channels:e=[],channelGroups:t=[]}){const s=U(this.channels,[...e,...e.map((e=>`${e}-pnpres`))]),n=U(this.groups,[...t,...t.map((e=>`${e}-pnpres`))]);if(new Set(this.channels).size!==new Set(s).size||new Set(this.groups).size!==new Set(n).size){const r=T(this.channels,e),i=T(this.groups,t);this.dependencies.presenceState&&(null==r||r.forEach((e=>delete this.dependencies.presenceState[e])),null==i||i.forEach((e=>delete this.dependencies.presenceState[e]))),this.channels=s,this.groups=n,this.engine.transition(Ye(Array.from(new Set(this.channels.slice(0))),Array.from(new Set(this.groups.slice(0))))),this.dependencies.leave&&this.dependencies.leave({channels:r.slice(0),groups:i.slice(0)})}}unsubscribeAll(){this.channels=[],this.groups=[],this.dependencies.presenceState&&Object.keys(this.dependencies.presenceState).forEach((e=>{delete this.dependencies.presenceState[e]})),this.engine.transition(Ye(this.channels.slice(0),this.groups.slice(0))),this.dependencies.leaveAll&&this.dependencies.leaveAll()}reconnect({timetoken:e,region:t}){this.engine.transition(lt(e,t))}disconnect(){this.engine.transition(ut()),this.dependencies.leaveAll&&this.dependencies.leaveAll()}getSubscribedChannels(){return Array.from(new Set(this.channels.slice(0)))}getSubscribedChannelGroups(){return Array.from(new Set(this.groups.slice(0)))}dispose(){this.disconnect(),this._unsubscribeEngine(),this.dispatcher.dispose()}}class Et extends ne{constructor(e){var t,s;super({method:e.sendByPost?z.POST:z.GET}),this.parameters=e,null!==(t=(s=this.parameters).sendByPost)&&void 0!==t||(s.sendByPost=false)}operation(){return ie.PNPublishOperation}validate(){const{message:e,channel:t,keySet:{publishKey:s}}=this.parameters;return t?e?s?void 0:"Missing 'publishKey'":"Missing 'message'":"Missing 'channel'"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));return{timetoken:t[2]}}))}get path(){const{message:e,channel:t,keySet:s}=this.parameters,n=this.prepareMessagePayload(e);return`/publish/${s.publishKey}/${s.subscribeKey}/0/${R(t)}/0${this.parameters.sendByPost?"":`/${R(n)}`}`}get queryParameters(){const{meta:e,replicate:t,storeInHistory:s,ttl:n}=this.parameters,r={};return void 0!==s&&(r.store=s?"1":"0"),void 0!==n&&(r.ttl=n),void 0===t||t||(r.norep="true"),e&&"object"==typeof e&&(r.meta=JSON.stringify(e)),r}get headers(){return{"Content-Type":"application/json"}}get body(){return this.prepareMessagePayload(this.parameters.message)}prepareMessagePayload(e){const{crypto:t}=this.parameters;if(!t)return JSON.stringify(e)||"";const s=t.encrypt(JSON.stringify(e));return JSON.stringify("string"==typeof s?s:y(s))}}class Ot extends ne{constructor(e){super(),this.parameters=e}operation(){return ie.PNSignalOperation}validate(){const{message:e,channel:t,keySet:{publishKey:s}}=this.parameters;return t?e?s?void 0:"Missing 'publishKey'":"Missing 'message'":"Missing 'channel'"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));return{timetoken:t[2]}}))}get path(){const{keySet:{publishKey:e,subscribeKey:t},channel:s,message:n}=this.parameters,r=JSON.stringify(n);return`/signal/${e}/${t}/0/${R(s)}/0/${R(r)}`}}class Ct extends ae{operation(){return ie.PNReceiveMessagesOperation}validate(){const e=super.validate();return e||(this.parameters.timetoken?this.parameters.region?void 0:"region can not be empty":"timetoken can not be empty")}get path(){const{keySet:{subscribeKey:e},channels:t=[]}=this.parameters;return`/v2/subscribe/${e}/${I(t.sort(),",")}/0`}get queryParameters(){const{channelGroups:e,filterExpression:t,timetoken:s,region:n}=this.parameters,r={ee:""};return e&&e.length>0&&(r["channel-group"]=e.sort().join(",")),t&&t.length>0&&(r["filter-expr"]=t),"string"==typeof s?s&&s.length>0&&(r.tt=s):s&&s>0&&(r.tt=s),n&&(r.tr=n),r}}class Nt extends ae{operation(){return ie.PNHandshakeOperation}get path(){const{keySet:{subscribeKey:e},channels:t=[]}=this.parameters;return`/v2/subscribe/${e}/${I(t.sort(),",")}/0`}get queryParameters(){const{channelGroups:e,filterExpression:t,state:s}=this.parameters,n={tt:0,ee:""};return e&&e.length>0&&(n["channel-group"]=e.sort().join(",")),t&&t.length>0&&(n["filter-expr"]=t),s&&Object.keys(s).length>0&&(n.state=JSON.stringify(s)),n}}class Pt extends ne{constructor(e){var t,s,n,r;super(),this.parameters=e,null!==(t=(n=this.parameters).channels)&&void 0!==t||(n.channels=[]),null!==(s=(r=this.parameters).channelGroups)&&void 0!==s||(r.channelGroups=[])}operation(){return ie.PNGetStateOperation}validate(){const{keySet:{subscribeKey:e},channels:t,channelGroups:s}=this.parameters;if(!e)return"Missing Subscribe Key"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(t.status>=400)throw c.create(e);const{channels:s=[],channelGroups:n=[]}=this.parameters,r={channels:{}};return 1===s.length&&0===n.length?r.channels[s[0]]=t.payload:r.channels=t.payload,r}))}get path(){const{keySet:{subscribeKey:e},uuid:t,channels:s}=this.parameters;return`/v2/presence/sub-key/${e}/channel/${I(null!=s?s:[],",")}/uuid/${t}`}get queryParameters(){const{channelGroups:e}=this.parameters;return e&&0!==e.length?{"channel-group":e.join(",")}:{}}}class Mt extends ne{constructor(e){super(),this.parameters=e}operation(){return ie.PNSetStateOperation}validate(){const{keySet:{subscribeKey:e},state:t,channels:s=[],channelGroups:n=[]}=this.parameters;return e?t?0===(null==s?void 0:s.length)&&0===(null==n?void 0:n.length)?"Please provide a list of channels and/or channel-groups":void 0:"Missing State":"Missing Subscribe Key"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(t.status>=400)throw c.create(e);return{state:t.payload}}))}get path(){const{keySet:{subscribeKey:e},uuid:t,channels:s}=this.parameters;return`/v2/presence/sub-key/${e}/channel/${I(null!=s?s:[],",")}/uuid/${R(t)}/data`}get queryParameters(){const{channelGroups:e,state:t}=this.parameters,s={state:JSON.stringify(t)};return e&&0!==e.length&&(s["channel-group"]=e.join(",")),s}}class jt extends ne{constructor(e){super(),this.parameters=e}operation(){return ie.PNHeartbeatOperation}validate(){const{keySet:{subscribeKey:e},channels:t=[],channelGroups:s=[]}=this.parameters;return e?0===t.length&&0===s.length?"Please provide a list of channels and/or channel-groups":void 0:"Missing Subscribe Key"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(t.status>=400)throw c.create(e);return{}}))}get path(){const{keySet:{subscribeKey:e},channels:t}=this.parameters;return`/v2/presence/sub-key/${e}/channel/${I(null!=t?t:[],",")}/heartbeat`}get queryParameters(){const{channelGroups:e,state:t,heartbeat:s}=this.parameters,n={heartbeat:`${s}`};return e&&0!==e.length&&(n["channel-group"]=e.join(",")),t&&(n.state=JSON.stringify(t)),n}}class _t extends ne{constructor(e){super(),this.parameters=e,this.parameters.channelGroups&&(this.parameters.channelGroups=Array.from(new Set(this.parameters.channelGroups))),this.parameters.channels&&(this.parameters.channels=Array.from(new Set(this.parameters.channels)))}operation(){return ie.PNUnsubscribeOperation}validate(){const{keySet:{subscribeKey:e},channels:t=[],channelGroups:s=[]}=this.parameters;return e?0===t.length&&0===s.length?"At least one `channel` or `channel group` should be provided.":void 0:"Missing Subscribe Key"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(t.status>=400)throw c.create(e);return{}}))}get path(){var e;const{keySet:{subscribeKey:t},channels:s}=this.parameters;return`/v2/presence/sub-key/${t}/channel/${I(null!==(e=null==s?void 0:s.sort())&&void 0!==e?e:[],",")}/leave`}get queryParameters(){const{channelGroups:e}=this.parameters;return e&&0!==e.length?{"channel-group":e.sort().join(",")}:{}}}class At extends ne{constructor(e){super(),this.parameters=e}operation(){return ie.PNWhereNowOperation}validate(){if(!this.parameters.keySet.subscribeKey)return"Missing Subscribe Key"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(t.status>=400)throw c.create(e);return t.payload?{channels:t.payload.channels}:{channels:[]}}))}get path(){const{keySet:{subscribeKey:e},uuid:t}=this.parameters;return`/v2/presence/sub-key/${e}/uuid/${R(t)}`}}class Rt extends ne{constructor(e){var t,s,n,r,i,o;super(),this.parameters=e,null!==(t=(r=this.parameters).queryParameters)&&void 0!==t||(r.queryParameters={}),null!==(s=(i=this.parameters).includeUUIDs)&&void 0!==s||(i.includeUUIDs=true),null!==(n=(o=this.parameters).includeState)&&void 0!==n||(o.includeState=false)}operation(){const{channels:e=[],channelGroups:t=[]}=this.parameters;return 0===e.length&&0===t.length?ie.PNGlobalHereNowOperation:ie.PNHereNowOperation}validate(){if(!this.parameters.keySet.subscribeKey)return"Missing Subscribe Key"}parse(e){return h(this,void 0,void 0,(function*(){var t,s;const n=this.deserializeResponse(e);if(!n)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(n.status>=400)throw c.create(e);const r="occupancy"in n?1:n.payload.total_channels,i="occupancy"in n?n.occupancy:n.payload.total_channels,u={};let l={};if("occupancy"in n){const e=this.parameters.channels[0];l[e]={uuids:null!==(t=n.uuids)&&void 0!==t?t:[],occupancy:i}}else l=null!==(s=n.payload.channels)&&void 0!==s?s:{};return Object.keys(l).forEach((e=>{const t=l[e];u[e]={occupants:this.parameters.includeUUIDs?t.uuids.map((e=>"string"==typeof e?{uuid:e,state:null}:e)):[],name:e,occupancy:t.occupancy}})),{totalChannels:r,totalOccupancy:i,channels:u}}))}get path(){const{keySet:{subscribeKey:e},channels:t,channelGroups:s}=this.parameters;let n=`/v2/presence/sub-key/${e}`;return(t&&t.length>0||s&&s.length>0)&&(n+=`/channel/${I(null!=t?t:[],",")}`),n}get queryParameters(){const{channelGroups:e,includeUUIDs:t,includeState:s,queryParameters:n}=this.parameters;return Object.assign(Object.assign(Object.assign(Object.assign({},t?{}:{disable_uuids:"1"}),null!=s&&s?{state:"1"}:{}),e&&e.length>0?{"channel-group":e.join(",")}:{}),n)}}class It extends ne{constructor(e){super({method:z.DELETE}),this.parameters=e}operation(){return ie.PNDeleteMessagesOperation}validate(){return this.parameters.keySet.subscribeKey?this.parameters.channel?void 0:"Missing channel":"Missing Subscribe Key"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(t.status>=400)throw c.create(e);return{}}))}get path(){const{keySet:{subscribeKey:e},channel:t}=this.parameters;return`/v3/history/sub-key/${e}/channel/${R(t)}`}get queryParameters(){const{start:e,end:t}=this.parameters;return Object.assign(Object.assign({},e?{start:e}:{}),t?{end:t}:{})}}class Ut extends ne{constructor(e){super(),this.parameters=e}operation(){return ie.PNMessageCounts}validate(){const{keySet:{subscribeKey:e},channels:t,timetoken:s,channelTimetokens:n}=this.parameters;return e?t?s&&n?"`timetoken` and `channelTimetokens` are incompatible together":s||n?n&&n.length>1&&n.length!==t.length?"Length of `channelTimetokens` and `channels` do not match":void 0:"`timetoken` or `channelTimetokens` need to be set":"Missing channels":"Missing Subscribe Key"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(t.status>=400)throw c.create(e);return{channels:t.channels}}))}get path(){return`/v3/history/sub-key/${this.parameters.keySet.subscribeKey}/message-counts/${I(this.parameters.channels)}`}get queryParameters(){let{channelTimetokens:e}=this.parameters;return this.parameters.timetoken&&(e=[this.parameters.timetoken]),Object.assign(Object.assign({},1===e.length?{timetoken:e[0]}:{}),e.length>1?{channelsTimetoken:e.join(",")}:{})}}class Tt extends ne{constructor(e){var t,s,n;super(),this.parameters=e,e.count?e.count=Math.min(e.count,100):e.count=100,null!==(t=e.stringifiedTimeToken)&&void 0!==t||(e.stringifiedTimeToken=false),null!==(s=e.includeMeta)&&void 0!==s||(e.includeMeta=false),null!==(n=e.logVerbosity)&&void 0!==n||(e.logVerbosity=false)}operation(){return ie.PNHistoryOperation}validate(){return this.parameters.keySet.subscribeKey?this.parameters.channel?void 0:"Missing channel":"Missing Subscribe Key"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));const s=t[0],n=t[1],r=t[2];return Array.isArray(s)?{messages:s.map((e=>{const t=this.processPayload(e.message),s={entry:t.payload,timetoken:e.timetoken};return t.error&&(s.error=t.error),e.meta&&(s.meta=e.meta),s})),startTimeToken:n,endTimeToken:r}:{messages:[],startTimeToken:n,endTimeToken:r}}))}get path(){const{keySet:{subscribeKey:e},channel:t}=this.parameters;return`/v2/history/sub-key/${e}/channel/${R(t)}`}get queryParameters(){const{start:e,end:t,reverse:s,count:n,stringifiedTimeToken:r,includeMeta:i}=this.parameters;return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({count:n,include_token:"true"},e?{start:e}:{}),t?{end:t}:{}),r?{string_message_token:"true"}:{}),null!=s?{reverse:s.toString()}:{}),i?{include_meta:"true"}:{})}processPayload(e){const{crypto:t,logVerbosity:s}=this.parameters;if(!t||"string"!=typeof e)return{payload:e};let n,r;try{const s=t.decrypt(e);n=s instanceof ArrayBuffer?JSON.parse(Tt.decoder.decode(s)):s}catch(t){s&&console.log("decryption error",t.message),n=e,r=`Error while decrypting message content: ${t.message}`}return{payload:n,error:r}}}var Ft;!function(e){e[e.Message=-1]="Message",e[e.Files=4]="Files"}(Ft||(Ft={}));class xt extends ne{constructor(e){var t,s,n,r,i;super(),this.parameters=e;const o=null!==(t=e.includeMessageActions)&&void 0!==t&&t,a=e.channels.length>1||o?25:100;e.count?e.count=Math.min(e.count,a):e.count=a,e.includeUuid?e.includeUUID=e.includeUuid:null!==(s=e.includeUUID)&&void 0!==s||(e.includeUUID=true),null!==(n=e.stringifiedTimeToken)&&void 0!==n||(e.stringifiedTimeToken=false),null!==(r=e.includeMessageType)&&void 0!==r||(e.includeMessageType=true),null!==(i=e.logVerbosity)&&void 0!==i||(e.logVerbosity=false)}operation(){return ie.PNFetchMessagesOperation}validate(){const{keySet:{subscribeKey:e},channels:t,includeMessageActions:s}=this.parameters;return e?t?void 0!==s&&s&&t.length>1?"History can return actions data for a single channel only. Either pass a single channel or disable the includeMessageActions flag.":void 0:"Missing channels":"Missing Subscribe Key"}parse(e){return h(this,void 0,void 0,(function*(){var t;const s=this.deserializeResponse(e);if(!s)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(s.status>=400)throw c.create(e);const n=null!==(t=s.channels)&&void 0!==t?t:{},r={};return Object.keys(n).forEach((e=>{r[e]=n[e].map((t=>{null===t.message_type&&(t.message_type=Ft.Message);const s=this.processPayload(e,t),n={channel:e,timetoken:t.timetoken,message:s.payload,messageType:t.message_type,uuid:t.uuid};if(t.actions){const e=n;e.actions=t.actions,e.data=t.actions}return t.meta&&(n.meta=t.meta),s.error&&(n.error=s.error),n}))})),s.more?{channels:r,more:s.more}:{channels:r}}))}get path(){const{keySet:{subscribeKey:e},channels:t,includeMessageActions:s}=this.parameters;return`/v3/${s?"history-with-actions":"history"}/sub-key/${e}/channel/${I(t)}`}get queryParameters(){const{start:e,end:t,count:s,includeMessageType:n,includeMeta:r,includeUUID:i,stringifiedTimeToken:o}=this.parameters;return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({max:s},e?{start:e}:{}),t?{end:t}:{}),o?{string_message_token:"true"}:{}),void 0!==r&&r?{include_meta:"true"}:{}),i?{include_uuid:"true"}:{}),n?{include_message_type:"true"}:{})}processPayload(e,t){const{crypto:s,logVerbosity:n}=this.parameters;if(!s||"string"!=typeof t.message)return{payload:t.message};let r,i;try{const e=s.decrypt(t.message);r=e instanceof ArrayBuffer?JSON.parse(xt.decoder.decode(e)):e}catch(e){n&&console.log("decryption error",e.message),r=t.message,i=`Error while decrypting message content: ${e.message}`}if(!i&&r&&t.message_type==Ft.Files&&"object"==typeof r&&this.isFileMessage(r)){const t=r;return{payload:{message:t.message,file:Object.assign(Object.assign({},t.file),{url:this.parameters.getFileUrl({channel:e,id:t.file.id,name:t.file.name})})},error:i}}return{payload:r,error:i}}isFileMessage(e){return void 0!==e.file}}class Dt extends ne{constructor(e){super(),this.parameters=e}operation(){return ie.PNGetMessageActionsOperation}validate(){return this.parameters.keySet.subscribeKey?this.parameters.channel?void 0:"Missing message channel":"Missing Subscribe Key"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(t.status>=400)throw c.create(e);let s=null,n=null;return t.data.length>0&&(s=t.data[0].actionTimetoken,n=t.data[t.data.length-1].actionTimetoken),{data:t.data,more:t.more,start:s,end:n}}))}get path(){const{keySet:{subscribeKey:e},channel:t}=this.parameters;return`/v1/message-actions/${e}/channel/${R(t)}`}get queryParameters(){const{limit:e,start:t,end:s}=this.parameters;return Object.assign(Object.assign(Object.assign({},t?{start:t}:{}),s?{end:s}:{}),e?{limit:e}:{})}}class Kt extends ne{constructor(e){super({method:z.POST}),this.parameters=e}operation(){return ie.PNAddMessageActionOperation}validate(){const{keySet:{subscribeKey:e},action:t,channel:s,messageTimetoken:n}=this.parameters;return e?s?n?t?t.value?t.type?t.type.length>15?"Action.type value exceed maximum length of 15":void 0:"Missing Action.type":"Missing Action.value":"Missing Action":"Missing message timetoken":"Missing message channel":"Missing Subscribe Key"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(t.status>=400)throw c.create(e);return{data:t.data}}))}get headers(){return{"Content-Type":"application/json"}}get path(){const{keySet:{subscribeKey:e},channel:t,messageTimetoken:s}=this.parameters;return`/v1/message-actions/${e}/channel/${R(t)}/message/${s}`}get body(){return JSON.stringify(this.parameters.action)}}class qt extends ne{constructor(e){super({method:z.DELETE}),this.parameters=e}operation(){return ie.PNRemoveMessageActionOperation}validate(){const{keySet:{subscribeKey:e},channel:t,messageTimetoken:s,actionTimetoken:n}=this.parameters;return e?t?s?n?void 0:"Missing action timetoken":"Missing message timetoken":"Missing message action channel":"Missing Subscribe Key"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(t.status>=400)throw c.create(e);return{data:t.data}}))}get path(){const{keySet:{subscribeKey:e},channel:t,actionTimetoken:s,messageTimetoken:n}=this.parameters;return`/v1/message-actions/${e}/channel/${R(t)}/message/${n}/action/${s}`}}class Gt extends ne{constructor(e){var t,s;super(),this.parameters=e,null!==(t=(s=this.parameters).storeInHistory)&&void 0!==t||(s.storeInHistory=true)}operation(){return ie.PNPublishFileMessageOperation}validate(){const{channel:e,fileId:t,fileName:s}=this.parameters;return e?t?s?void 0:"file name can't be empty":"file id can't be empty":"channel can't be empty"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));return{timetoken:t[2]}}))}get path(){const{message:e,channel:t,keySet:{publishKey:s,subscribeKey:n},fileId:r,fileName:i}=this.parameters,o=Object.assign({file:{name:i,id:r}},e?{message:e}:{});return`/v1/files/publish-file/${s}/${n}/0/${R(t)}/0/${R(this.prepareMessagePayload(o))}`}get queryParameters(){const{storeInHistory:e,ttl:t,meta:s}=this.parameters;return Object.assign(Object.assign({store:e?"1":"0"},t?{ttl:t}:{}),s&&"object"==typeof s?{meta:JSON.stringify(s)}:{})}prepareMessagePayload(e){const{crypto:t}=this.parameters;if(!t)return JSON.stringify(e)||"";const s=t.encrypt(JSON.stringify(e));return JSON.stringify("string"==typeof s?s:y(s))}}class $t extends ne{constructor(e){super({method:z.LOCAL}),this.parameters=e}operation(){return ie.PNGetFileUrlOperation}validate(){const{channel:e,id:t,name:s}=this.parameters;return e?t?s?void 0:"file name can't be empty":"file id can't be empty":"channel can't be empty"}parse(e){return h(this,void 0,void 0,(function*(){return e.url}))}get path(){const{channel:e,id:t,name:s,keySet:{subscribeKey:n}}=this.parameters;return`/v1/files/${n}/channels/${R(e)}/files/${t}/${s}`}}class Lt extends ne{constructor(e){super({method:z.DELETE}),this.parameters=e}operation(){return ie.PNDeleteFileOperation}validate(){const{channel:e,id:t,name:s}=this.parameters;return e?t?s?void 0:"file name can't be empty":"file id can't be empty":"channel can't be empty"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(t.status>=400)throw c.create(e);return t}))}get path(){const{keySet:{subscribeKey:e},id:t,channel:s,name:n}=this.parameters;return`/v1/files/${e}/channels/${R(s)}/files/${t}/${n}`}}class Bt extends ne{constructor(e){var t,s;super(),this.parameters=e,null!==(t=(s=this.parameters).limit)&&void 0!==t||(s.limit=100)}operation(){return ie.PNListFilesOperation}validate(){if(!this.parameters.channel)return"channel can't be empty"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(t.status>=400)throw c.create(e);return t}))}get path(){const{keySet:{subscribeKey:e},channel:t}=this.parameters;return`/v1/files/${e}/channels/${R(t)}/files`}get queryParameters(){const{limit:e,next:t}=this.parameters;return Object.assign({limit:e},t?{next:t}:{})}}class Ht extends ne{constructor(e){super({method:z.POST}),this.parameters=e}operation(){return ie.PNGenerateUploadUrlOperation}validate(){return this.parameters.channel?this.parameters.name?void 0:"'name' can't be empty":"channel can't be empty"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(t.status>=400)throw c.create(e);return{id:t.data.id,name:t.data.name,url:t.file_upload_request.url,formFields:t.file_upload_request.form_fields}}))}get path(){const{keySet:{subscribeKey:e},channel:t}=this.parameters;return`/v1/files/${e}/channels/${R(t)}/generate-upload-url`}get body(){return JSON.stringify({name:this.parameters.name})}}class zt extends ne{constructor(e){super({method:z.POST}),this.parameters=e;const t=e.file.mimeType;t&&(e.formFields=e.formFields.map((e=>"Content-Type"===e.name?{name:e.name,value:t}:e)))}operation(){return ie.PNPublishFileOperation}validate(){const{fileId:e,fileName:t,file:s,uploadUrl:n}=this.parameters;return e?t?s?n?void 0:"Validation failed: file upload 'url' can't be empty":"Validation failed: 'file' can't be empty":"Validation failed: file 'name' can't be empty":"Validation failed: file 'id' can't be empty"}parse(e){return h(this,void 0,void 0,(function*(){return{status:e.status,message:e.body?zt.decoder.decode(e.body):"OK"}}))}request(){return Object.assign(Object.assign({},super.request()),{origin:new URL(this.parameters.uploadUrl).origin,timeout:300})}get path(){const{pathname:e,search:t}=new URL(this.parameters.uploadUrl);return`${e}${t}`}get body(){return this.parameters.file}get formData(){return this.parameters.formFields}}class Vt{constructor(e){var t;if(this.parameters=e,this.file=null===(t=this.parameters.PubNubFile)||void 0===t?void 0:t.create(e.file),!this.file)throw new Error("File upload error: unable to create File object.")}process(){return h(this,void 0,void 0,(function*(){let e,t;return this.generateFileUploadUrl().then((s=>(e=s.name,t=s.id,this.uploadFile(s)))).then((e=>{if(204!==e.status)throw new o("Upload to bucket was unsuccessful",{error:!0,statusCode:e.status,category:i.PNUnknownCategory,operation:ie.PNPublishFileOperation,errorData:{message:e.message}})})).then((()=>this.publishFileMessage(t,e))).catch((e=>{if(e instanceof o)throw e;const t=e instanceof c?e:c.create(e);throw new o("File upload error.",t.toStatus(ie.PNPublishFileOperation))}))}))}generateFileUploadUrl(){return h(this,void 0,void 0,(function*(){const e=new Ht(Object.assign(Object.assign({},this.parameters),{name:this.file.name,keySet:this.parameters.keySet}));return this.parameters.sendRequest(e)}))}uploadFile(e){return h(this,void 0,void 0,(function*(){const{cipherKey:t,PubNubFile:s,crypto:n,cryptography:r}=this.parameters,{id:i,name:o,url:a,formFields:c}=e;return this.parameters.PubNubFile.supportsEncryptFile&&(!t&&n?this.file=yield n.encryptFile(this.file,s):t&&r&&(this.file=yield r.encryptFile(t,this.file,s))),this.parameters.sendRequest(new zt({fileId:i,fileName:o,file:this.file,uploadUrl:a,formFields:c}))}))}publishFileMessage(e,t){return h(this,void 0,void 0,(function*(){var s,n,r,a;let c,u={timetoken:"0"},l=this.parameters.fileUploadPublishRetryLimit,h=!1;do{try{u=yield this.parameters.publishFile(Object.assign(Object.assign({},this.parameters),{fileId:e,fileName:t})),h=!0}catch(e){e instanceof o&&(c=e),l-=1}}while(!h&&l>0);if(h)return{status:200,timetoken:u.timetoken,id:e,name:t};throw new o("Publish failed. You may want to execute that operation manually using pubnub.publishFile",{error:!0,category:null!==(n=null===(s=c.status)||void 0===s?void 0:s.category)&&void 0!==n?n:i.PNUnknownCategory,statusCode:null!==(a=null===(r=c.status)||void 0===r?void 0:r.statusCode)&&void 0!==a?a:0,channel:this.parameters.channel,id:e,name:t})}))}}class Wt extends ne{constructor(e){super({method:z.DELETE}),this.parameters=e}operation(){return ie.PNAccessManagerRevokeToken}validate(){return this.parameters.keySet.secretKey?this.parameters.token?void 0:"token can't be empty":"Missing Secret Key"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(t.status>=400)throw c.create(e);return{}}))}get path(){const{keySet:{subscribeKey:e},token:t}=this.parameters;return`/v3/pam/${e}/grant/${R(t)}`}}class Jt extends ne{constructor(e){var t,s,n,r;super({method:z.POST}),this.parameters=e,null!==(t=(n=this.parameters).resources)&&void 0!==t||(n.resources={}),null!==(s=(r=this.parameters).patterns)&&void 0!==s||(r.patterns={})}operation(){return ie.PNAccessManagerGrantToken}validate(){var e,t,s,n,r,i;const{keySet:{subscribeKey:o,publishKey:a,secretKey:c},resources:u,patterns:l}=this.parameters;if(!o)return"Missing Subscribe Key";if(!a)return"Missing Publish Key";if(!c)return"Missing Secret Key";if(!u&&!l)return"Missing either Resources or Patterns";if(this.isVspPermissions(this.parameters)&&("channels"in(null!==(e=this.parameters.resources)&&void 0!==e?e:{})||"uuids"in(null!==(t=this.parameters.resources)&&void 0!==t?t:{})||"groups"in(null!==(s=this.parameters.resources)&&void 0!==s?s:{})||"channels"in(null!==(n=this.parameters.patterns)&&void 0!==n?n:{})||"uuids"in(null!==(r=this.parameters.patterns)&&void 0!==r?r:{})||"groups"in(null!==(i=this.parameters.patterns)&&void 0!==i?i:{})))return"Cannot mix `users`, `spaces` and `authorizedUserId` with `uuids`, `channels`, `groups` and `authorized_uuid`";let h=!0;return[this.parameters.resources,this.parameters.patterns].forEach((e=>{Object.keys(null!=e?e:{}).forEach((t=>{var s;e&&h&&Object.keys(null!==(s=e[t])&&void 0!==s?s:{}).length>0&&(h=!1)}))})),h?"Missing values for either Resources or Patterns":void 0}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(t.status>=400)throw c.create(e);return t.data.token}))}get path(){return`/v3/pam/${this.parameters.keySet.subscribeKey}/grant`}get body(){const{ttl:e,meta:t}=this.parameters,s=Object.assign({},e||0===e?{ttl:e}:{}),n=this.isVspPermissions(this.parameters)?this.parameters.authorizedUserId:this.parameters.authorized_uuid,r={},i={},o={},a=(e,t,s,n)=>{n[s]||(n[s]={}),n[s][e]=t},{resources:c,patterns:u}=this.parameters;return[c,u].forEach(((e,t)=>{var s,n,r,c,u;const l=0===t?i:o;let h={},d={},p={};l.channels||(l.channels={}),l.groups||(l.groups={}),l.uuids||(l.uuids={}),l.users||(l.users={}),l.spaces||(l.spaces={}),e&&("spaces"in e||"users"in e?(h=null!==(s=e.spaces)&&void 0!==s?s:{},p=null!==(n=e.users)&&void 0!==n?n:{}):("channels"in e||"uuids"in e||"groups"in e)&&(h=null!==(r=e.channels)&&void 0!==r?r:{},d=null!==(c=e.groups)&&void 0!==c?c:{},p=null!==(u=e.uuids)&&void 0!==u?u:{})),Object.keys(h).forEach((e=>a(e,this.extractPermissions(h[e]),"channels",l))),Object.keys(d).forEach((e=>a(e,this.extractPermissions(d[e]),"groups",l))),Object.keys(p).forEach((e=>a(e,this.extractPermissions(p[e]),"uuids",l)))})),n&&(r.uuid=`${n}`),r.resources=i,r.patterns=o,r.meta=null!=t?t:{},s.permissions=r,JSON.stringify(s)}extractPermissions(e){let t=0;return"join"in e&&e.join&&(t|=128),"update"in e&&e.update&&(t|=64),"get"in e&&e.get&&(t|=32),"delete"in e&&e.delete&&(t|=8),"manage"in e&&e.manage&&(t|=4),"write"in e&&e.write&&(t|=2),"read"in e&&e.read&&(t|=1),t}isVspPermissions(e){var t,s,n,r;return"authorizedUserId"in e||"spaces"in(null!==(t=e.resources)&&void 0!==t?t:{})||"users"in(null!==(s=e.resources)&&void 0!==s?s:{})||"spaces"in(null!==(n=e.patterns)&&void 0!==n?n:{})||"users"in(null!==(r=e.patterns)&&void 0!==r?r:{})}}class Qt extends ne{constructor(e){var t,s,n,r,i,o,a,c,u,l,h,d,p,g,y,f,m,b,v,w;super(),this.parameters=e,null!==(t=(h=this.parameters).channels)&&void 0!==t||(h.channels=[]),null!==(s=(d=this.parameters).channelGroups)&&void 0!==s||(d.channelGroups=[]),null!==(n=(p=this.parameters).uuids)&&void 0!==n||(p.uuids=[]),null!==(r=(g=this.parameters).read)&&void 0!==r||(g.read=false),null!==(i=(y=this.parameters).write)&&void 0!==i||(y.write=false),null!==(o=(f=this.parameters).delete)&&void 0!==o||(f.delete=false),null!==(a=(m=this.parameters).get)&&void 0!==a||(m.get=false),null!==(c=(b=this.parameters).update)&&void 0!==c||(b.update=false),null!==(u=(v=this.parameters).manage)&&void 0!==u||(v.manage=false),null!==(l=(w=this.parameters).join)&&void 0!==l||(w.join=false)}operation(){return ie.PNAccessManagerGrant}validate(){const{keySet:{subscribeKey:e,publishKey:t,secretKey:s},uuids:n=[],channels:r=[],channelGroups:i=[],authKeys:o=[]}=this.parameters;return e?t?s?0!==n.length&&0===o.length?"authKeys are required for grant request on uuids":!n.length||0===r.length&&0===i.length?void 0:"Both channel/channel group and uuid cannot be used in the same request":"Missing Secret Key":"Missing Publish Key":"Missing Subscribe Key"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(t.status>=400)throw c.create(e);return t.payload}))}get path(){return`/v2/auth/grant/sub-key/${this.parameters.keySet.subscribeKey}`}get queryParameters(){const{channels:e,channelGroups:t,authKeys:s,uuids:n,read:r,write:i,manage:o,delete:a,get:c,join:u,update:l,ttl:h}=this.parameters;return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({},e&&(null==e?void 0:e.length)>0?{channel:e.join(",")}:{}),t&&(null==t?void 0:t.length)>0?{"channel-group":t.join(",")}:{}),s&&(null==s?void 0:s.length)>0?{auth:s.join(",")}:{}),n&&(null==n?void 0:n.length)>0?{"target-uuid":n.join(",")}:{}),{r:r?"1":"0",w:i?"1":"0",m:o?"1":"0",d:a?"1":"0",g:c?"1":"0",j:u?"1":"0",u:l?"1":"0"}),h||0===h?{ttl:h}:{})}}const Yt=[];class Xt extends ne{constructor(e){var t,s;super(),this.parameters=e,null!==(t=(s=this.parameters).authKeys)&&void 0!==t||(s.authKeys=Yt)}operation(){return ie.PNAccessManagerAudit}validate(){if(!this.parameters.keySet.subscribeKey)return"Missing Subscribe Key"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(t.status>=400)throw c.create(e);return t.payload}))}get path(){return`/v2/auth/audit/sub-key/${this.parameters.keySet.subscribeKey}`}get queryParameters(){const{channel:e,channelGroup:t,authKeys:s}=this.parameters;return Object.assign(Object.assign(Object.assign({},e?{channel:e}:{}),t?{"channel-group":t}:{}),s&&s.length?{auth:s.join(",")}:{})}}class Zt{subscribe(){var e,t;this.pubnub.subscribe(Object.assign({channels:this.channelNames,channelGroups:this.groupNames},(null===(t=null===(e=this.options)||void 0===e?void 0:e.cursor)||void 0===t?void 0:t.timetoken)&&{timetoken:this.options.cursor.timetoken}))}unsubscribe(){this.pubnub.unsubscribe({channels:this.channelNames.filter((e=>!e.endsWith("-pnpres"))),channelGroups:this.groupNames.filter((e=>!e.endsWith("-pnpres")))})}set onMessage(e){this.listener.message=e}set onPresence(e){this.listener.presence=e}set onSignal(e){this.listener.signal=e}set onObjects(e){this.listener.objects=e}set onMessageAction(e){this.listener.messageAction=e}set onFile(e){this.listener.file=e}addListener(e){this.eventEmitter.addListener(e,this.channelNames.filter((e=>!e.endsWith("-pnpres"))),this.groupNames.filter((e=>!e.endsWith("-pnpres"))))}removeListener(e){this.eventEmitter.removeListener(e,this.channelNames,this.groupNames)}get channels(){return this.channelNames.slice(0)}get channelGroups(){return this.groupNames.slice(0)}}class es extends Zt{constructor({channels:e=[],channelGroups:t=[],subscriptionOptions:s,eventEmitter:n,pubnub:r}){super(),this.channelNames=[],this.groupNames=[],this.subscriptionList=[],this.options=s,this.eventEmitter=n,this.pubnub=r,e.filter((e=>!e.endsWith("-pnpres"))).forEach((e=>{const t=this.pubnub.channel(e).subscription(this.options);this.channelNames=[...this.channelNames,...t.channels],this.subscriptionList.push(t)})),t.filter((e=>!e.endsWith("-pnpres"))).forEach((e=>{const t=this.pubnub.channelGroup(e).subscription(this.options);this.groupNames=[...this.groupNames,...t.channelGroups],this.subscriptionList.push(t)})),this.listener={},n.addListener(this.listener,this.channelNames.filter((e=>!e.endsWith("-pnpres"))),this.groupNames.filter((e=>!e.endsWith("-pnpres"))))}addSubscription(e){this.subscriptionList.push(e),this.channelNames=[...this.channelNames,...e.channels],this.groupNames=[...this.groupNames,...e.channelGroups],this.eventEmitter.addListener(this.listener,e.channels,e.channelGroups)}removeSubscription(e){const t=e.channels,s=e.channelGroups;this.channelNames=this.channelNames.filter((e=>!t.includes(e))),this.groupNames=this.groupNames.filter((e=>!s.includes(e))),this.subscriptionList=this.subscriptionList.filter((t=>t!==e)),this.eventEmitter.removeListener(this.listener,t,s)}addSubscriptionSet(e){this.subscriptionList=[...this.subscriptionList,...e.subscriptions],this.channelNames=[...this.channelNames,...e.channels],this.groupNames=[...this.groupNames,...e.channelGroups],this.eventEmitter.addListener(this.listener,e.channels,e.channelGroups)}removeSubscriptionSet(e){const t=e.channels,s=e.channelGroups;this.channelNames=this.channelNames.filter((e=>!t.includes(e))),this.groupNames=this.groupNames.filter((e=>!s.includes(e))),this.subscriptionList=this.subscriptionList.filter((t=>!e.subscriptions.includes(t))),this.eventEmitter.removeListener(this.listener,t,s)}get subscriptions(){return this.subscriptionList.slice(0)}}class ts extends Zt{constructor({channels:e,channelGroups:t,subscriptionOptions:s,eventEmitter:n,pubnub:r}){super(),this.channelNames=[],this.groupNames=[],this.channelNames=e,this.groupNames=t,this.options=s,this.pubnub=r,this.eventEmitter=n,this.listener={},n.addListener(this.listener,this.channelNames.filter((e=>!e.endsWith("-pnpres"))),this.groupNames.filter((e=>!e.endsWith("-pnpres"))))}addSubscription(e){return new es({channels:[...this.channelNames,...e.channels],channelGroups:[...this.groupNames,...e.channelGroups],subscriptionOptions:Object.assign(Object.assign({},this.options),null==e?void 0:e.options),eventEmitter:this.eventEmitter,pubnub:this.pubnub})}}class ss{constructor(e,t,s){this.id=e,this.eventEmitter=t,this.pubnub=s}subscription(e){return new ts({channels:[this.id],channelGroups:[],subscriptionOptions:e,eventEmitter:this.eventEmitter,pubnub:this.pubnub})}}class ns{constructor(e,t,s){this.eventEmitter=t,this.pubnub=s,this.name=e}subscription(e){return new ts({channels:[],channelGroups:(null==e?void 0:e.receivePresenceEvents)?[this.name,`${this.name}-pnpres`]:[this.name],subscriptionOptions:e,eventEmitter:this.eventEmitter,pubnub:this.pubnub})}}class rs{constructor(e,t,s){this.id=e,this.eventEmitter=t,this.pubnub=s}subscription(e){return new ts({channels:[this.id],channelGroups:[],subscriptionOptions:e,eventEmitter:this.eventEmitter,pubnub:this.pubnub})}}class is{constructor(e,t,s){this.eventEmitter=t,this.pubnub=s,this.name=e}subscription(e){return new ts({channels:(null==e?void 0:e.receivePresenceEvents)?[this.name,`${this.name}-pnpres`]:[this.name],channelGroups:[],subscriptionOptions:e,eventEmitter:this.eventEmitter,pubnub:this.pubnub})}}class os extends ne{constructor(e){super(),this.parameters=e}operation(){return ie.PNRemoveChannelsFromGroupOperation}validate(){const{keySet:{subscribeKey:e},channels:t,channelGroup:s}=this.parameters;return e?s?t?void 0:"Missing channels":"Missing Channel Group":"Missing Subscribe Key"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(t.status>=400)throw c.create(e);return{}}))}get path(){const{keySet:{subscribeKey:e},channelGroup:t}=this.parameters;return`/v1/channel-registration/sub-key/${e}/channel-group/${R(t)}`}get queryParameters(){return{remove:this.parameters.channels.join(",")}}}class as extends ne{constructor(e){super(),this.parameters=e}operation(){return ie.PNAddChannelsToGroupOperation}validate(){const{keySet:{subscribeKey:e},channels:t,channelGroup:s}=this.parameters;return e?s?t?void 0:"Missing channels":"Missing Channel Group":"Missing Subscribe Key"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(t.status>=400)throw c.create(e);return{}}))}get path(){const{keySet:{subscribeKey:e},channelGroup:t}=this.parameters;return`/v1/channel-registration/sub-key/${e}/channel-group/${R(t)}`}get queryParameters(){return{add:this.parameters.channels.join(",")}}}class cs extends ne{constructor(e){super(),this.parameters=e}operation(){return ie.PNChannelsForGroupOperation}validate(){return this.parameters.keySet.subscribeKey?this.parameters.channelGroup?void 0:"Missing Channel Group":"Missing Subscribe Key"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(t.status>=400)throw c.create(e);return{channels:t.payload.channels}}))}get path(){const{keySet:{subscribeKey:e},channelGroup:t}=this.parameters;return`/v1/channel-registration/sub-key/${e}/channel-group/${R(t)}`}}class us extends ne{constructor(e){super(),this.parameters=e}operation(){return ie.PNRemoveGroupOperation}validate(){return this.parameters.keySet.subscribeKey?this.parameters.channelGroup?void 0:"Missing Channel Group":"Missing Subscribe Key"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(t.status>=400)throw c.create(e);return{}}))}get path(){const{keySet:{subscribeKey:e},channelGroup:t}=this.parameters;return`/v1/channel-registration/sub-key/${e}/channel-group/${R(t)}/remove`}}class ls extends ne{constructor(e){super(),this.parameters=e}operation(){return ie.PNChannelGroupsOperation}validate(){if(!this.parameters.keySet.subscribeKey)return"Missing Subscribe Key"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(t.status>=400)throw c.create(e);return{groups:t.payload.groups}}))}get path(){return`/v1/channel-registration/sub-key/${this.parameters.keySet.subscribeKey}/channel-group`}}class hs{constructor(e,t){this.keySet=e,this.sendRequest=t}listChannels(e,t){return h(this,void 0,void 0,(function*(){const s=new cs(Object.assign(Object.assign({},e),{keySet:this.keySet}));return t?this.sendRequest(s,t):this.sendRequest(s)}))}listGroups(e){return h(this,void 0,void 0,(function*(){const t=new ls({keySet:this.keySet});return e?this.sendRequest(t,e):this.sendRequest(t)}))}addChannels(e,t){return h(this,void 0,void 0,(function*(){const s=new as(Object.assign(Object.assign({},e),{keySet:this.keySet}));return t?this.sendRequest(s,t):this.sendRequest(s)}))}removeChannels(e,t){return h(this,void 0,void 0,(function*(){const s=new os(Object.assign(Object.assign({},e),{keySet:this.keySet}));return t?this.sendRequest(s,t):this.sendRequest(s)}))}deleteGroup(e,t){return h(this,void 0,void 0,(function*(){const s=new us(Object.assign(Object.assign({},e),{keySet:this.keySet}));return t?this.sendRequest(s,t):this.sendRequest(s)}))}}class ds extends ne{constructor(e){var t,s;super(),this.parameters=e,"apns2"===this.parameters.pushGateway&&(null!==(t=(s=this.parameters).environment)&&void 0!==t||(s.environment="development")),this.parameters.count&&this.parameters.count>1e3&&(this.parameters.count=1e3)}operation(){throw Error("Should be implemented in subclass.")}validate(){const{keySet:{subscribeKey:e},action:t,device:s,pushGateway:n}=this.parameters;return e?s?"add"!==t&&"remove"!==t||"channels"in this.parameters&&0!==this.parameters.channels.length?n?"apns2"!==this.parameters.pushGateway||this.parameters.topic?void 0:"Missing APNS2 topic":"Missing GW Type (pushGateway: gcm or apns2)":"Missing Channels":"Missing Device ID (device)":"Missing Subscribe Key"}parse(e){return h(this,void 0,void 0,(function*(){throw Error("Should be implemented in subclass.")}))}get path(){const{keySet:{subscribeKey:e},action:t,device:s,pushGateway:n}=this.parameters;let r="apns2"===n?`/v2/push/sub-key/${e}/devices-apns2/${s}`:`/v1/push/sub-key/${e}/devices/${s}`;return"remove-device"===t&&(r=`${r}/remove`),r}get queryParameters(){const{start:e,count:t}=this.parameters;let s=Object.assign(Object.assign({type:this.parameters.pushGateway},e?{start:e}:{}),t&&t>0?{count:t}:{});if("channels"in this.parameters&&(s[this.parameters.action]=this.parameters.channels.join(",")),"apns2"===this.parameters.pushGateway){const{environment:e,topic:t}=this.parameters;s=Object.assign(Object.assign({},s),{environment:e,topic:t})}return s}}class ps extends ds{constructor(e){super(Object.assign(Object.assign({},e),{action:"remove"}))}operation(){return ie.PNRemovePushNotificationEnabledChannelsOperation}parse(e){return h(this,void 0,void 0,(function*(){if(!this.deserializeResponse(e))throw new o("Service response error, check status for details",a("Unable to deserialize service response"));return{}}))}}class gs extends ds{constructor(e){super(Object.assign(Object.assign({},e),{action:"list"}))}operation(){return ie.PNPushNotificationEnabledChannelsOperation}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));return{channels:t}}))}}class ys extends ds{constructor(e){super(Object.assign(Object.assign({},e),{action:"add"}))}operation(){return ie.PNAddPushNotificationEnabledChannelsOperation}parse(e){return h(this,void 0,void 0,(function*(){if(!this.deserializeResponse(e))throw new o("Service response error, check status for details",a("Unable to deserialize service response"));return{}}))}}class fs extends ds{constructor(e){super(Object.assign(Object.assign({},e),{action:"remove-device"}))}operation(){return ie.PNRemoveAllPushNotificationsOperation}parse(e){return h(this,void 0,void 0,(function*(){if(!this.deserializeResponse(e))throw new o("Service response error, check status for details",a("Unable to deserialize service response"));return{}}))}}class ms{constructor(e,t){this.keySet=e,this.sendRequest=t}listChannels(e,t){return h(this,void 0,void 0,(function*(){const s=new gs(Object.assign(Object.assign({},e),{keySet:this.keySet}));return t?this.sendRequest(s,t):this.sendRequest(s)}))}addChannels(e,t){return h(this,void 0,void 0,(function*(){const s=new ys(Object.assign(Object.assign({},e),{keySet:this.keySet}));return t?this.sendRequest(s,t):this.sendRequest(s)}))}removeChannels(e,t){return h(this,void 0,void 0,(function*(){const s=new ps(Object.assign(Object.assign({},e),{keySet:this.keySet}));return t?this.sendRequest(s,t):this.sendRequest(s)}))}deleteDevice(e,t){return h(this,void 0,void 0,(function*(){const s=new fs(Object.assign(Object.assign({},e),{keySet:this.keySet}));return t?this.sendRequest(s,t):this.sendRequest(s)}))}}class bs extends ne{constructor(e){var t,s,n,r,i,o;super(),this.parameters=e,null!==(t=e.include)&&void 0!==t||(e.include={}),null!==(s=(i=e.include).customFields)&&void 0!==s||(i.customFields=false),null!==(n=(o=e.include).totalCount)&&void 0!==n||(o.totalCount=false),null!==(r=e.limit)&&void 0!==r||(e.limit=100)}operation(){return ie.PNGetAllChannelMetadataOperation}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(t.status>=400)throw c.create(e);return t}))}get path(){return`/v2/objects/${this.parameters.keySet.subscribeKey}/channels`}get queryParameters(){const{include:e,page:t,filter:s,sort:n,limit:r}=this.parameters,i=Object.entries(null!=n?n:{}).map((([e,t])=>null!==t?`${e}:${t}`:e));return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({include:["status","type",...e.customFields?["custom"]:[]].join(","),count:`${e.totalCount}`},s?{filter:s}:{}),(null==t?void 0:t.next)?{start:t.next}:{}),(null==t?void 0:t.prev)?{end:t.prev}:{}),r?{limit:r}:{}),i.length?{sort:i}:{})}}class vs extends ne{constructor(e){super({method:z.DELETE}),this.parameters=e}operation(){return ie.PNRemoveChannelMetadataOperation}validate(){if(!this.parameters.channel)return"Channel cannot be empty"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(t.status>=400)throw c.create(e);return t}))}get path(){const{keySet:{subscribeKey:e},channel:t}=this.parameters;return`/v2/objects/${e}/channels/${R(t)}`}}class ws extends ne{constructor(e){var t,s,n,r,i,o,a,c,u,l,h,d,p,g,y,f;super(),this.parameters=e,null!==(t=e.include)&&void 0!==t||(e.include={}),null!==(s=(l=e.include).customFields)&&void 0!==s||(l.customFields=false),null!==(n=(h=e.include).totalCount)&&void 0!==n||(h.totalCount=false),null!==(r=(d=e.include).statusField)&&void 0!==r||(d.statusField=false),null!==(i=(p=e.include).channelFields)&&void 0!==i||(p.channelFields=false),null!==(o=(g=e.include).customChannelFields)&&void 0!==o||(g.customChannelFields=false),null!==(a=(y=e.include).channelStatusField)&&void 0!==a||(y.channelStatusField=false),null!==(c=(f=e.include).channelTypeField)&&void 0!==c||(f.channelTypeField=false),null!==(u=e.limit)&&void 0!==u||(e.limit=100),this.parameters.userId&&(this.parameters.uuid=this.parameters.userId)}operation(){return ie.PNGetMembershipsOperation}validate(){if(!this.parameters.uuid)return"'uuid' cannot be empty"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(t.status>=400)throw c.create(e);return t}))}get path(){const{keySet:{subscribeKey:e},uuid:t}=this.parameters;return`/v2/objects/${e}/uuids/${R(t)}/channels`}get queryParameters(){const{include:e,page:t,filter:s,sort:n,limit:r}=this.parameters,i=Object.entries(null!=n?n:{}).map((([e,t])=>null!==t?`${e}:${t}`:e)),o=[];return e.statusField&&o.push("status"),e.customFields&&o.push("custom"),e.channelFields&&o.push("channel"),e.channelStatusField&&o.push("channel.status"),e.channelTypeField&&o.push("channel.type"),e.customChannelFields&&o.push("channel.custom"),Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({count:`${e.totalCount}`},o.length>0?{include:o.join(",")}:{}),s?{filter:s}:{}),(null==t?void 0:t.next)?{start:t.next}:{}),(null==t?void 0:t.prev)?{end:t.prev}:{}),r?{limit:r}:{}),i.length?{sort:i}:{})}}class Ss extends ne{constructor(e){var t,s,n,r,i,o,a,c,u,l;super({method:z.PATCH}),this.parameters=e,null!==(t=e.include)&&void 0!==t||(e.include={}),null!==(s=(a=e.include).customFields)&&void 0!==s||(a.customFields=false),null!==(n=(c=e.include).totalCount)&&void 0!==n||(c.totalCount=false),null!==(r=(u=e.include).channelFields)&&void 0!==r||(u.channelFields=false),null!==(i=(l=e.include).customChannelFields)&&void 0!==i||(l.customChannelFields=false),null!==(o=e.limit)&&void 0!==o||(e.limit=100),this.parameters.userId&&(this.parameters.uuid=this.parameters.userId)}operation(){return ie.PNSetMembershipsOperation}validate(){const{uuid:e,channels:t}=this.parameters;return e?t&&0!==t.length?void 0:"Channels cannot be empty":"'uuid' cannot be empty"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(t.status>=400)throw c.create(e);return t}))}get path(){const{keySet:{subscribeKey:e},uuid:t}=this.parameters;return`/v2/objects/${e}/uuids/${R(t)}/channels`}get queryParameters(){const{include:e,page:t,filter:s,sort:n,limit:r}=this.parameters,i=Object.entries(null!=n?n:{}).map((([e,t])=>null!==t?`${e}:${t}`:e)),o=["channel.status","channel.type","status"];return e.customFields&&o.push("custom"),e.channelFields&&o.push("channel"),e.customChannelFields&&o.push("channel.custom"),Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({count:`${e.totalCount}`},o.length>0?{include:o.join(",")}:{}),s?{filter:s}:{}),(null==t?void 0:t.next)?{start:t.next}:{}),(null==t?void 0:t.prev)?{end:t.prev}:{}),r?{limit:r}:{}),i.length?{sort:i}:{})}get body(){const{channels:e,type:t}=this.parameters;return JSON.stringify({[`${t}`]:e.map((e=>"string"==typeof e?{channel:{id:e}}:{channel:{id:e.id},status:e.status,custom:e.custom}))})}}class ks extends ne{constructor(e){var t,s,n,r;super(),this.parameters=e,null!==(t=e.include)&&void 0!==t||(e.include={}),null!==(s=(r=e.include).customFields)&&void 0!==s||(r.customFields=false),null!==(n=e.limit)&&void 0!==n||(e.limit=100)}operation(){return ie.PNGetAllUUIDMetadataOperation}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(t.status>=400)throw c.create(e);return t}))}get path(){return`/v2/objects/${this.parameters.keySet.subscribeKey}/uuids`}get queryParameters(){const{include:e,page:t,filter:s,sort:n,limit:r}=this.parameters,i=Object.entries(null!=n?n:{}).map((([e,t])=>null!==t?`${e}:${t}`:e));return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({include:["status","type",...e.customFields?["custom"]:[]].join(",")},void 0!==e.totalCount?{count:`${e.totalCount}`}:{}),s?{filter:s}:{}),(null==t?void 0:t.next)?{start:t.next}:{}),(null==t?void 0:t.prev)?{end:t.prev}:{}),r?{limit:r}:{}),i.length?{sort:i}:{})}}class Es extends ne{constructor(e){var t,s,n;super(),this.parameters=e,null!==(t=e.include)&&void 0!==t||(e.include={}),null!==(s=(n=e.include).customFields)&&void 0!==s||(n.customFields=true)}operation(){return ie.PNGetChannelMetadataOperation}validate(){if(!this.parameters.channel)return"Channel cannot be empty"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(t.status>=400)throw c.create(e);return t}))}get path(){const{keySet:{subscribeKey:e},channel:t}=this.parameters;return`/v2/objects/${e}/channels/${R(t)}`}get queryParameters(){return{include:["status","type",...this.parameters.include.customFields?["custom"]:[]].join(",")}}}class Os extends ne{constructor(e){var t,s,n;super({method:z.PATCH}),this.parameters=e,null!==(t=e.include)&&void 0!==t||(e.include={}),null!==(s=(n=e.include).customFields)&&void 0!==s||(n.customFields=true)}operation(){return ie.PNSetChannelMetadataOperation}validate(){return this.parameters.channel?this.parameters.data?void 0:"Data cannot be empty":"Channel cannot be empty"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(t.status>=400)throw c.create(e);return t}))}get path(){const{keySet:{subscribeKey:e},channel:t}=this.parameters;return`/v2/objects/${e}/channels/${R(t)}`}get queryParameters(){return{include:["status","type",...this.parameters.include.customFields?["custom"]:[]].join(",")}}get body(){return JSON.stringify(this.parameters.data)}}class Cs extends ne{constructor(e){super({method:z.DELETE}),this.parameters=e,this.parameters.userId&&(this.parameters.uuid=this.parameters.userId)}operation(){return ie.PNRemoveUUIDMetadataOperation}validate(){if(!this.parameters.uuid)return"'uuid' cannot be empty"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(t.status>=400)throw c.create(e);return t}))}get path(){const{keySet:{subscribeKey:e},uuid:t}=this.parameters;return`/v2/objects/${e}/uuids/${R(t)}`}}class Ns extends ne{constructor(e){var t,s,n,r,i,o,a,c,u,l,h,d,p,g,y,f;super(),this.parameters=e,null!==(t=e.include)&&void 0!==t||(e.include={}),null!==(s=(l=e.include).customFields)&&void 0!==s||(l.customFields=false),null!==(n=(h=e.include).totalCount)&&void 0!==n||(h.totalCount=false),null!==(r=(d=e.include).statusField)&&void 0!==r||(d.statusField=false),null!==(i=(p=e.include).UUIDFields)&&void 0!==i||(p.UUIDFields=false),null!==(o=(g=e.include).customUUIDFields)&&void 0!==o||(g.customUUIDFields=false),null!==(a=(y=e.include).UUIDStatusField)&&void 0!==a||(y.UUIDStatusField=false),null!==(c=(f=e.include).UUIDTypeField)&&void 0!==c||(f.UUIDTypeField=false),null!==(u=e.limit)&&void 0!==u||(e.limit=100)}operation(){return ie.PNSetMembersOperation}validate(){if(!this.parameters.channel)return"Channel cannot be empty"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(t.status>=400)throw c.create(e);return t}))}get path(){const{keySet:{subscribeKey:e},channel:t}=this.parameters;return`/v2/objects/${e}/channels/${R(t)}/uuids`}get queryParameters(){const{include:e,page:t,filter:s,sort:n,limit:r}=this.parameters,i=Object.entries(null!=n?n:{}).map((([e,t])=>null!==t?`${e}:${t}`:e)),o=[];return e.statusField&&o.push("status"),e.customFields&&o.push("custom"),e.UUIDFields&&o.push("uuid"),e.UUIDStatusField&&o.push("uuid.status"),e.UUIDTypeField&&o.push("uuid.type"),e.customUUIDFields&&o.push("uuid.custom"),Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({count:`${e.totalCount}`},o.length>0?{include:o.join(",")}:{}),s?{filter:s}:{}),(null==t?void 0:t.next)?{start:t.next}:{}),(null==t?void 0:t.prev)?{end:t.prev}:{}),r?{limit:r}:{}),i.length?{sort:i}:{})}}class Ps extends ne{constructor(e){var t,s,n,r,i,o,a,c,u,l;super({method:z.PATCH}),this.parameters=e,null!==(t=e.include)&&void 0!==t||(e.include={}),null!==(s=(a=e.include).customFields)&&void 0!==s||(a.customFields=false),null!==(n=(c=e.include).totalCount)&&void 0!==n||(c.totalCount=false),null!==(r=(u=e.include).UUIDFields)&&void 0!==r||(u.UUIDFields=false),null!==(i=(l=e.include).customUUIDFields)&&void 0!==i||(l.customUUIDFields=false),null!==(o=e.limit)&&void 0!==o||(e.limit=100)}operation(){return ie.PNSetMembersOperation}validate(){const{channel:e,uuids:t}=this.parameters;return e?t&&0!==t.length?void 0:"UUIDs cannot be empty":"Channel cannot be empty"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(t.status>=400)throw c.create(e);return t}))}get path(){const{keySet:{subscribeKey:e},channel:t}=this.parameters;return`/v2/objects/${e}/channels/${R(t)}/uuids`}get queryParameters(){const{include:e,page:t,filter:s,sort:n,limit:r}=this.parameters,i=Object.entries(null!=n?n:{}).map((([e,t])=>null!==t?`${e}:${t}`:e)),o=["uuid.status","uuid.type","type"];return e.customFields&&o.push("custom"),e.UUIDFields&&o.push("uuid"),e.customUUIDFields&&o.push("uuid.custom"),Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({count:`${e.totalCount}`},o.length>0?{include:o.join(",")}:{}),s?{filter:s}:{}),(null==t?void 0:t.next)?{start:t.next}:{}),(null==t?void 0:t.prev)?{end:t.prev}:{}),r?{limit:r}:{}),i.length?{sort:i}:{})}get body(){const{uuids:e,type:t}=this.parameters;return JSON.stringify({[`${t}`]:e.map((e=>"string"==typeof e?{uuid:{id:e}}:{uuid:{id:e.id},status:e.status,custom:e.custom}))})}}class Ms extends ne{constructor(e){var t,s,n;super(),this.parameters=e,null!==(t=e.include)&&void 0!==t||(e.include={}),null!==(s=(n=e.include).customFields)&&void 0!==s||(n.customFields=true),this.parameters.userId&&(this.parameters.uuid=this.parameters.userId)}operation(){return ie.PNGetUUIDMetadataOperation}validate(){if(!this.parameters.uuid)return"'uuid' cannot be empty"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(t.status>=400)throw c.create(e);return t}))}get path(){const{keySet:{subscribeKey:e},uuid:t}=this.parameters;return`/v2/objects/${e}/uuids/${R(t)}`}get queryParameters(){const{include:e}=this.parameters;return{include:["status","type",...e.customFields?["custom"]:[]].join(",")}}}class js extends ne{constructor(e){var t,s,n;super({method:z.PATCH}),this.parameters=e,null!==(t=e.include)&&void 0!==t||(e.include={}),null!==(s=(n=e.include).customFields)&&void 0!==s||(n.customFields=true),this.parameters.userId&&(this.parameters.uuid=this.parameters.userId)}operation(){return ie.PNSetUUIDMetadataOperation}validate(){return this.parameters.uuid?this.parameters.data?void 0:"Data cannot be empty":"'uuid' cannot be empty"}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));if(t.status>=400)throw c.create(e);return t}))}get path(){const{keySet:{subscribeKey:e},uuid:t}=this.parameters;return`/v2/objects/${e}/uuids/${R(t)}`}get queryParameters(){return{include:["status","type",...this.parameters.include.customFields?["custom"]:[]].join(",")}}get body(){return JSON.stringify(this.parameters.data)}}class _s{constructor(e,t){this.configuration=e,this.sendRequest=t,this.keySet=e.keySet}getAllUUIDMetadata(e,t){return h(this,void 0,void 0,(function*(){return this._getAllUUIDMetadata(e,t)}))}_getAllUUIDMetadata(e,t){return h(this,void 0,void 0,(function*(){const s=e&&"function"!=typeof e?e:{};null!=t||(t="function"==typeof e?e:void 0);const n=new ks(Object.assign(Object.assign({},s),{keySet:this.keySet}));return t?this.sendRequest(n,t):this.sendRequest(n)}))}getUUIDMetadata(e,t){return h(this,void 0,void 0,(function*(){return this._getUUIDMetadata(e,t)}))}_getUUIDMetadata(e,t){return h(this,void 0,void 0,(function*(){var s;const n=e&&"function"!=typeof e?e:{};null!=t||(t="function"==typeof e?e:void 0),n.userId&&(n.uuid=n.userId),null!==(s=n.uuid)&&void 0!==s||(n.uuid=this.configuration.userId);const r=new Ms(Object.assign(Object.assign({},n),{keySet:this.keySet}));return t?this.sendRequest(r,t):this.sendRequest(r)}))}setUUIDMetadata(e,t){return h(this,void 0,void 0,(function*(){return this._setUUIDMetadata(e,t)}))}_setUUIDMetadata(e,t){return h(this,void 0,void 0,(function*(){var s;e.userId&&(e.uuid=e.userId),null!==(s=e.uuid)&&void 0!==s||(e.uuid=this.configuration.userId);const n=new js(Object.assign(Object.assign({},e),{keySet:this.keySet}));return t?this.sendRequest(n,t):this.sendRequest(n)}))}removeUUIDMetadata(e,t){return h(this,void 0,void 0,(function*(){return this._removeUUIDMetadata(e,t)}))}_removeUUIDMetadata(e,t){return h(this,void 0,void 0,(function*(){var s;const n=e&&"function"!=typeof e?e:{};null!=t||(t="function"==typeof e?e:void 0),n.userId&&(n.uuid=n.userId),null!==(s=n.uuid)&&void 0!==s||(n.uuid=this.configuration.userId);const r=new Cs(Object.assign(Object.assign({},n),{keySet:this.keySet}));return t?this.sendRequest(r,t):this.sendRequest(r)}))}getAllChannelMetadata(e,t){return h(this,void 0,void 0,(function*(){return this._getAllChannelMetadata(e,t)}))}_getAllChannelMetadata(e,t){return h(this,void 0,void 0,(function*(){const s=e&&"function"!=typeof e?e:{};null!=t||(t="function"==typeof e?e:void 0);const n=new bs(Object.assign(Object.assign({},s),{keySet:this.keySet}));return t?this.sendRequest(n,t):this.sendRequest(n)}))}getChannelMetadata(e,t){return h(this,void 0,void 0,(function*(){return this._getChannelMetadata(e,t)}))}_getChannelMetadata(e,t){return h(this,void 0,void 0,(function*(){const s=new Es(Object.assign(Object.assign({},e),{keySet:this.keySet}));return t?this.sendRequest(s,t):this.sendRequest(s)}))}setChannelMetadata(e,t){return h(this,void 0,void 0,(function*(){return this._setChannelMetadata(e,t)}))}_setChannelMetadata(e,t){return h(this,void 0,void 0,(function*(){const s=new Os(Object.assign(Object.assign({},e),{keySet:this.keySet}));return t?this.sendRequest(s,t):this.sendRequest(s)}))}removeChannelMetadata(e,t){return h(this,void 0,void 0,(function*(){return this._removeChannelMetadata(e,t)}))}_removeChannelMetadata(e,t){return h(this,void 0,void 0,(function*(){const s=new vs(Object.assign(Object.assign({},e),{keySet:this.keySet}));return t?this.sendRequest(s,t):this.sendRequest(s)}))}getChannelMembers(e,t){return h(this,void 0,void 0,(function*(){const s=new Ns(Object.assign(Object.assign({},e),{keySet:this.keySet}));return t?this.sendRequest(s,t):this.sendRequest(s)}))}setChannelMembers(e,t){return h(this,void 0,void 0,(function*(){const s=new Ps(Object.assign(Object.assign({},e),{type:"set",keySet:this.keySet}));return t?this.sendRequest(s,t):this.sendRequest(s)}))}removeChannelMembers(e,t){return h(this,void 0,void 0,(function*(){const s=new Ps(Object.assign(Object.assign({},e),{type:"delete",keySet:this.keySet}));return t?this.sendRequest(s,t):this.sendRequest(s)}))}getMemberships(e,t){return h(this,void 0,void 0,(function*(){var s;const n=e&&"function"!=typeof e?e:{};null!=t||(t="function"==typeof e?e:void 0),n.userId&&(n.uuid=n.userId),null!==(s=n.uuid)&&void 0!==s||(n.uuid=this.configuration.userId);const r=new ws(Object.assign(Object.assign({},n),{keySet:this.keySet}));return t?this.sendRequest(r,t):this.sendRequest(r)}))}setMemberships(e,t){return h(this,void 0,void 0,(function*(){var s;e.userId&&(e.uuid=e.userId),null!==(s=e.uuid)&&void 0!==s||(e.uuid=this.configuration.userId);const n=new Ss(Object.assign(Object.assign({},e),{type:"set",keySet:this.keySet}));return t?this.sendRequest(n,t):this.sendRequest(n)}))}removeMemberships(e,t){return h(this,void 0,void 0,(function*(){var s;e.userId&&(e.uuid=e.userId),null!==(s=e.uuid)&&void 0!==s||(e.uuid=this.configuration.userId);const n=new Ss(Object.assign(Object.assign({},e),{type:"delete",keySet:this.keySet}));return t?this.sendRequest(n,t):this.sendRequest(n)}))}fetchMemberships(e,t){return h(this,void 0,void 0,(function*(){var s,n;if("spaceId"in e){const n=e,r={channel:null!==(s=n.spaceId)&&void 0!==s?s:n.channel,filter:n.filter,limit:n.limit,page:n.page,include:Object.assign({},n.include),sort:n.sort?Object.fromEntries(Object.entries(n.sort).map((([e,t])=>[e.replace("user","uuid"),t]))):void 0},i=e=>({status:e.status,data:e.data.map((e=>({user:e.uuid,custom:e.custom,updated:e.updated,eTag:e.eTag}))),totalCount:e.totalCount,next:e.next,prev:e.prev});return t?this.getChannelMembers(r,((e,s)=>{t(e,s?i(s):s)})):this.getChannelMembers(r).then(i)}const r=e,i={uuid:null!==(n=r.userId)&&void 0!==n?n:r.uuid,filter:r.filter,limit:r.limit,page:r.page,include:Object.assign({},r.include),sort:r.sort?Object.fromEntries(Object.entries(r.sort).map((([e,t])=>[e.replace("space","channel"),t]))):void 0},o=e=>({status:e.status,data:e.data.map((e=>({space:e.channel,custom:e.custom,updated:e.updated,eTag:e.eTag}))),totalCount:e.totalCount,next:e.next,prev:e.prev});return t?this.getMemberships(i,((e,s)=>{t(e,s?o(s):s)})):this.getMemberships(i).then(o)}))}addMemberships(e,t){return h(this,void 0,void 0,(function*(){var s,n,r,i,o,a;if("spaceId"in e){const i=e,o={channel:null!==(s=i.spaceId)&&void 0!==s?s:i.channel,uuids:null!==(r=null===(n=i.users)||void 0===n?void 0:n.map((e=>"string"==typeof e?e:(e.userId,{id:e.userId,custom:e.custom}))))&&void 0!==r?r:i.uuids,limit:0};return t?this.setChannelMembers(o,t):this.setChannelMembers(o)}const c=e,u={uuid:null!==(i=c.userId)&&void 0!==i?i:c.uuid,channels:null!==(a=null===(o=c.spaces)||void 0===o?void 0:o.map((e=>"string"==typeof e?e:{id:e.spaceId,custom:e.custom})))&&void 0!==a?a:c.channels,limit:0};return t?this.setMemberships(u,t):this.setMemberships(u)}))}}class As extends ne{constructor(){super()}operation(){return ie.PNTimeOperation}parse(e){return h(this,void 0,void 0,(function*(){const t=this.deserializeResponse(e);if(!t)throw new o("Service response error, check status for details",a("Unable to deserialize service response"));return{timetoken:t[0]}}))}get path(){return"/time/0"}}class Rs extends ne{constructor(e){super(),this.parameters=e}operation(){return ie.PNDownloadFileOperation}validate(){const{channel:e,id:t,name:s}=this.parameters;return e?t?s?void 0:"file name can't be empty":"file id can't be empty":"channel can't be empty"}parse(e){return h(this,void 0,void 0,(function*(){const{cipherKey:t,crypto:s,cryptography:n,name:r,PubNubFile:i}=this.parameters,o=e.headers["content-type"];let a,c=e.body;return i.supportsEncryptFile&&(t||s)&&(t&&n?c=yield n.decrypt(t,c):!t&&s&&(a=yield s.decryptFile(i.create({data:c,name:r,mimeType:o}),i))),a||i.create({data:c,name:r,mimeType:o})}))}get path(){const{keySet:{subscribeKey:e},channel:t,id:s,name:n}=this.parameters;return`/v1/files/${e}/channels/${R(t)}/files/${s}/${n}`}}class Is{static notificationPayload(e,t){return new se(e,t)}static generateUUID(){return $.createUUID()}constructor(e){if(this._configuration=e.configuration,this.cryptography=e.cryptography,this.tokenManager=e.tokenManager,this.transport=e.transport,this.crypto=e.crypto,this._objects=new _s(this._configuration,this.sendRequest.bind(this)),this._channelGroups=new hs(this._configuration.keySet,this.sendRequest.bind(this)),this._push=new ms(this._configuration.keySet,this.sendRequest.bind(this)),this.listenerManager=new J,this.eventEmitter=new ue(this.listenerManager),this._configuration.enableEventEngine){let e=this._configuration.getHeartbeatInterval();this.presenceState={},e&&(this.presenceEventEngine=new Le({heartbeat:this.heartbeat.bind(this),leave:e=>this.makeUnsubscribe(e,(()=>{})),heartbeatDelay:()=>new Promise(((t,s)=>{e=this._configuration.getHeartbeatInterval(),e?setTimeout(t,1e3*e):s(new o("Heartbeat interval has been reset."))})),retryDelay:e=>new Promise((t=>setTimeout(t,e))),emitStatus:e=>this.listenerManager.announceStatus(e),config:this._configuration,presenceState:this.presenceState})),this.eventEngine=new kt({handshake:this.subscribeHandshake.bind(this),receiveMessages:this.subscribeReceiveMessages.bind(this),delay:e=>new Promise((t=>setTimeout(t,e))),join:this.join.bind(this),leave:this.leave.bind(this),leaveAll:this.leaveAll.bind(this),presenceState:this.presenceState,config:this._configuration,emitMessages:e=>{try{e.forEach((e=>this.eventEmitter.emitEvent(e)))}catch(e){const t={error:!0,category:i.PNUnknownCategory,errorData:e,statusCode:0};this.listenerManager.announceStatus(t)}},emitStatus:e=>this.listenerManager.announceStatus(e)})}else this.subscriptionManager=new X(this._configuration,this.listenerManager,this.eventEmitter,this.makeSubscribe.bind(this),this.heartbeat.bind(this),this.makeUnsubscribe.bind(this),this.time.bind(this))}get configuration(){return this._configuration}get _config(){return this.configuration}get authKey(){var e;return null!==(e=this._configuration.authKey)&&void 0!==e?e:void 0}getAuthKey(){return this.authKey}setAuthKey(e){this._configuration.setAuthKey(e)}get userId(){return this._configuration.userId}set userId(e){if(!e||"string"!=typeof e||0===e.trim().length)throw new Error("Missing or invalid userId parameter. Provide a valid string userId");this._configuration.userId=e}getUserId(){return this._configuration.userId}setUserId(e){if(!e||"string"!=typeof e||0===e.trim().length)throw new Error("Missing or invalid userId parameter. Provide a valid string userId");this._configuration.userId=e}get filterExpression(){var e;return null!==(e=this._configuration.getFilterExpression())&&void 0!==e?e:void 0}getFilterExpression(){return this.filterExpression}set filterExpression(e){this._configuration.setFilterExpression(e)}setFilterExpression(e){this.filterExpression=e}get cipherKey(){return this._configuration.getCipherKey()}set cipherKey(e){this._configuration.setCipherKey(e)}setCipherKey(e){this.cipherKey=e}set heartbeatInterval(e){this._configuration.setHeartbeatInterval(e)}setHeartbeatInterval(e){this.heartbeatInterval=e}getVersion(){return this._configuration.getVersion()}_addPnsdkSuffix(e,t){this._configuration._addPnsdkSuffix(e,t)}getUUID(){return this.userId}setUUID(e){this.userId=e}get customEncrypt(){return this._configuration.getCustomEncrypt()}get customDecrypt(){return this._configuration.getCustomDecrypt()}channel(e){return new is(e,this.eventEmitter,this)}channelGroup(e){return new ns(e,this.eventEmitter,this)}channelMetadata(e){return new ss(e,this.eventEmitter,this)}userMetadata(e){return new rs(e,this.eventEmitter,this)}subscriptionSet(e){return new es(Object.assign(Object.assign({},e),{eventEmitter:this.eventEmitter,pubnub:this}))}sendRequest(e,t){return h(this,void 0,void 0,(function*(){const s=e.validate();if(s){if(t)return t(a(s),null);throw new o("Validation failed, check status for details",a(s))}const n=e.request();n.formData&&n.formData.length>0?n.timeout=300:e.operation()===ie.PNSubscribeOperation?n.timeout=this._configuration.getSubscribeTimeout():n.timeout=this._configuration.getTransactionTimeout();const r={error:!1,operation:e.operation(),category:i.PNAcknowledgmentCategory,statusCode:0},[u,l]=this.transport.makeSendable(n);return e.cancellationController=l||null,u.then((t=>{if(r.statusCode=t.status,200!==t.status&&204!==t.status){const e=t.headers["content-type"];if(e||-1!==e.indexOf("javascript")||-1!==e.indexOf("json")){const e=JSON.parse(Is.decoder.decode(t.body));"object"==typeof e&&"error"in e&&e.error&&"object"==typeof e.error&&(r.errorData=e.error)}}return e.parse(t)})).then((e=>t?t(r,e):e)).catch((s=>{const n=s instanceof c?s:c.create(s);if(t)return t(n.toStatus(e.operation()),null);throw n.toPubNubError(e.operation(),"REST API request processing error, check status for details")}))}))}destroy(e){this.subscriptionManager?(this.subscriptionManager.unsubscribeAll(e),this.subscriptionManager.disconnect()):this.eventEngine&&this.eventEngine.dispose()}stop(){this.destroy()}addListener(e){this.listenerManager.addListener(e)}removeListener(e){this.listenerManager.removeListener(e)}removeAllListeners(){this.listenerManager.removeAllListeners()}publish(e,t){return h(this,void 0,void 0,(function*(){const s=new Et(Object.assign(Object.assign({},e),{keySet:this._configuration.keySet,crypto:this._configuration.getCryptoModule()}));return t?this.sendRequest(s,t):this.sendRequest(s)}))}signal(e,t){return h(this,void 0,void 0,(function*(){const s=new Ot(Object.assign(Object.assign({},e),{keySet:this._configuration.keySet}));return t?this.sendRequest(s,t):this.sendRequest(s)}))}fire(e,t){return h(this,void 0,void 0,(function*(){return null!=t||(t=()=>{}),this.publish(Object.assign(Object.assign({},e),{replicate:!1,storeInHistory:!1}),t)}))}getSubscribedChannels(){return this.subscriptionManager?this.subscriptionManager.subscribedChannels:this.eventEngine?this.eventEngine.getSubscribedChannels():[]}getSubscribedChannelGroups(){return this.subscriptionManager?this.subscriptionManager.subscribedChannelGroups:this.eventEngine?this.eventEngine.getSubscribedChannelGroups():[]}subscribe(e){this.subscriptionManager?this.subscriptionManager.subscribe(e):this.eventEngine&&this.eventEngine.subscribe(e)}makeSubscribe(e,t){const s=new ce(Object.assign(Object.assign({},e),{keySet:this._configuration.keySet,crypto:this._configuration.getCryptoModule(),getFileUrl:this.getFileUrl.bind(this)}));if(this.sendRequest(s,((e,n)=>{var r;this.subscriptionManager&&(null===(r=this.subscriptionManager.abort)||void 0===r?void 0:r.identifier)===s.requestIdentifier&&(this.subscriptionManager.abort=null),t(e,n)})),this.subscriptionManager){const e=()=>s.abort();e.identifier=s.requestIdentifier,this.subscriptionManager.abort=e}}unsubscribe(e){this.subscriptionManager?this.subscriptionManager.unsubscribe(e):this.eventEngine&&this.eventEngine.unsubscribe(e)}makeUnsubscribe(e,t){this.sendRequest(new _t(Object.assign(Object.assign({},e),{keySet:this._configuration.keySet})),t)}unsubscribeAll(){this.subscriptionManager?this.subscriptionManager.unsubscribeAll():this.eventEngine&&this.eventEngine.unsubscribeAll()}disconnect(){this.subscriptionManager?this.subscriptionManager.disconnect():this.eventEngine&&this.eventEngine.disconnect()}reconnect(e){this.subscriptionManager?this.subscriptionManager.reconnect():this.eventEngine&&this.eventEngine.reconnect(null!=e?e:{})}subscribeHandshake(e){return h(this,void 0,void 0,(function*(){const t=new Nt(Object.assign(Object.assign({},e),{keySet:this._configuration.keySet,crypto:this._configuration.getCryptoModule(),getFileUrl:this.getFileUrl.bind(this)})),s=e.abortSignal.subscribe((e=>{t.abort()}));return this.sendRequest(t).then((e=>(s(),e.cursor)))}))}subscribeReceiveMessages(e){return h(this,void 0,void 0,(function*(){const t=new Ct(Object.assign(Object.assign({},e),{keySet:this._configuration.keySet,crypto:this._configuration.getCryptoModule(),getFileUrl:this.getFileUrl.bind(this)})),s=e.abortSignal.subscribe((e=>{t.abort()}));return this.sendRequest(t).then((e=>(s(),e)))}))}getMessageActions(e,t){return h(this,void 0,void 0,(function*(){const s=new Dt(Object.assign(Object.assign({},e),{keySet:this._configuration.keySet}));return t?this.sendRequest(s,t):this.sendRequest(s)}))}addMessageAction(e,t){return h(this,void 0,void 0,(function*(){const s=new Kt(Object.assign(Object.assign({},e),{keySet:this._configuration.keySet}));return t?this.sendRequest(s,t):this.sendRequest(s)}))}removeMessageAction(e,t){return h(this,void 0,void 0,(function*(){const s=new qt(Object.assign(Object.assign({},e),{keySet:this._configuration.keySet}));return t?this.sendRequest(s,t):this.sendRequest(s)}))}fetchMessages(e,t){return h(this,void 0,void 0,(function*(){const s=new xt(Object.assign(Object.assign({},e),{keySet:this._configuration.keySet,crypto:this._configuration.getCryptoModule(),getFileUrl:this.getFileUrl.bind(this)}));return t?this.sendRequest(s,t):this.sendRequest(s)}))}deleteMessages(e,t){return h(this,void 0,void 0,(function*(){const s=new It(Object.assign(Object.assign({},e),{keySet:this._configuration.keySet}));return t?this.sendRequest(s,t):this.sendRequest(s)}))}messageCounts(e,t){return h(this,void 0,void 0,(function*(){const s=new Ut(Object.assign(Object.assign({},e),{keySet:this._configuration.keySet}));return t?this.sendRequest(s,t):this.sendRequest(s)}))}history(e,t){return h(this,void 0,void 0,(function*(){const s=new Tt(Object.assign(Object.assign({},e),{keySet:this._configuration.keySet,crypto:this._configuration.getCryptoModule()}));return t?this.sendRequest(s,t):this.sendRequest(s)}))}hereNow(e,t){return h(this,void 0,void 0,(function*(){const s=new Rt(Object.assign(Object.assign({},e),{keySet:this._configuration.keySet}));return t?this.sendRequest(s,t):this.sendRequest(s)}))}whereNow(e,t){return h(this,void 0,void 0,(function*(){var s;const n=new At({uuid:null!==(s=e.uuid)&&void 0!==s?s:this._configuration.userId,keySet:this._configuration.keySet});return t?this.sendRequest(n,t):this.sendRequest(n)}))}getState(e,t){return h(this,void 0,void 0,(function*(){var s;const n=new Pt(Object.assign(Object.assign({},e),{uuid:null!==(s=e.uuid)&&void 0!==s?s:this._configuration.userId,keySet:this._configuration.keySet}));return t?this.sendRequest(n,t):this.sendRequest(n)}))}setState(e,t){return h(this,void 0,void 0,(function*(){var s,n;const{keySet:r,userId:i}=this._configuration,o=this._configuration.getPresenceTimeout();let a;if(this._configuration.enableEventEngine&&this.presenceState){const t=this.presenceState;null===(s=e.channels)||void 0===s||s.forEach((s=>t[s]=e.state)),"channelGroups"in e&&(null===(n=e.channelGroups)||void 0===n||n.forEach((s=>t[s]=e.state)))}return a="withHeartbeat"in e?new jt(Object.assign(Object.assign({},e),{keySet:r,heartbeat:o})):new Mt(Object.assign(Object.assign({},e),{keySet:r,uuid:i})),this.subscriptionManager&&this.subscriptionManager.setState(e),t?this.sendRequest(a,t):this.sendRequest(a)}))}presence(e){var t;null===(t=this.subscriptionManager)||void 0===t||t.changePresence(e)}heartbeat(e,t){return h(this,void 0,void 0,(function*(){const s=new jt(Object.assign(Object.assign({},e),{keySet:this._configuration.keySet}));return t?this.sendRequest(s,t):this.sendRequest(s)}))}join(e){var t;null===(t=this.presenceEventEngine)||void 0===t||t.join(e)}leave(e){var t;null===(t=this.presenceEventEngine)||void 0===t||t.leave(e)}leaveAll(){var e;null===(e=this.presenceEventEngine)||void 0===e||e.leaveAll()}grantToken(e,t){return h(this,void 0,void 0,(function*(){const s=new Jt(Object.assign(Object.assign({},e),{keySet:this._configuration.keySet}));return t?this.sendRequest(s,t):this.sendRequest(s)}))}revokeToken(e,t){return h(this,void 0,void 0,(function*(){const s=new Wt(Object.assign(Object.assign({},e),{keySet:this._configuration.keySet}));return t?this.sendRequest(s,t):this.sendRequest(s)}))}get token(){return this.tokenManager.getToken()}getToken(){return this.token}set token(e){this.tokenManager.setToken(e)}setToken(e){this.token=e}parseToken(e){return this.tokenManager.parseToken(e)}grant(e,t){return h(this,void 0,void 0,(function*(){const s=new Qt(Object.assign(Object.assign({},e),{keySet:this._configuration.keySet}));return t?this.sendRequest(s,t):this.sendRequest(s)}))}audit(e,t){return h(this,void 0,void 0,(function*(){const s=new Xt(Object.assign(Object.assign({},e),{keySet:this._configuration.keySet}));return t?this.sendRequest(s,t):this.sendRequest(s)}))}get objects(){return this._objects}fetchUsers(e,t){return h(this,void 0,void 0,(function*(){return this.objects._getAllUUIDMetadata(e,t)}))}fetchUser(e,t){return h(this,void 0,void 0,(function*(){return this.objects._getUUIDMetadata(e,t)}))}createUser(e,t){return h(this,void 0,void 0,(function*(){return this.objects._setUUIDMetadata(e,t)}))}updateUser(e,t){return h(this,void 0,void 0,(function*(){return this.objects._setUUIDMetadata(e,t)}))}removeUser(e,t){return h(this,void 0,void 0,(function*(){return this.objects._removeUUIDMetadata(e,t)}))}fetchSpaces(e,t){return h(this,void 0,void 0,(function*(){return this.objects._getAllChannelMetadata(e,t)}))}fetchSpace(e,t){return h(this,void 0,void 0,(function*(){return this.objects._getChannelMetadata(e,t)}))}createSpace(e,t){return h(this,void 0,void 0,(function*(){return this.objects._setChannelMetadata(e,t)}))}updateSpace(e,t){return h(this,void 0,void 0,(function*(){return this.objects._setChannelMetadata(e,t)}))}removeSpace(e,t){return h(this,void 0,void 0,(function*(){return this.objects._removeChannelMetadata(e,t)}))}fetchMemberships(e,t){return h(this,void 0,void 0,(function*(){return this.objects.fetchMemberships(e,t)}))}addMemberships(e,t){return h(this,void 0,void 0,(function*(){return this.objects.addMemberships(e,t)}))}updateMemberships(e,t){return h(this,void 0,void 0,(function*(){return this.objects.addMemberships(e,t)}))}removeMemberships(e,t){return h(this,void 0,void 0,(function*(){var s,n,r;if("spaceId"in e){const r=e,i={channel:null!==(s=r.spaceId)&&void 0!==s?s:r.channel,uuids:null!==(n=r.userIds)&&void 0!==n?n:r.uuids,limit:0};return t?this.objects.removeChannelMembers(i,t):this.objects.removeChannelMembers(i)}const i=e,o={uuid:i.userId,channels:null!==(r=i.spaceIds)&&void 0!==r?r:i.channels,limit:0};return t?this.objects.removeMemberships(o,t):this.objects.removeMemberships(o)}))}get channelGroups(){return this._channelGroups}get push(){return this._push}sendFile(e,t){return h(this,void 0,void 0,(function*(){if(!this._configuration.PubNubFile)throw new Error("Validation failed: 'PubNubFile' not configured or file upload not supported by the platform.");const s=new Vt(Object.assign(Object.assign({},e),{keySet:this._configuration.keySet,PubNubFile:this._configuration.PubNubFile,fileUploadPublishRetryLimit:this._configuration.fileUploadPublishRetryLimit,file:e.file,sendRequest:this.sendRequest.bind(this),publishFile:this.publishFile.bind(this),crypto:this._configuration.getCryptoModule(),cryptography:this.cryptography?this.cryptography:void 0})),n={error:!1,operation:ie.PNPublishFileOperation,category:i.PNAcknowledgmentCategory,statusCode:0};return s.process().then((e=>(n.statusCode=e.status,t?t(n,e):e))).catch((e=>{let s;throw e instanceof o?s=e.status:e instanceof c&&(s=e.toStatus(n.operation)),t&&s&&t(s,null),new o("REST API request processing error, check status for details",s)}))}))}publishFile(e,t){return h(this,void 0,void 0,(function*(){if(!this._configuration.PubNubFile)throw new Error("Validation failed: 'PubNubFile' not configured or file upload not supported by the platform.");const s=new Gt(Object.assign(Object.assign({},e),{keySet:this._configuration.keySet,crypto:this._configuration.getCryptoModule()}));return t?this.sendRequest(s,t):this.sendRequest(s)}))}listFiles(e,t){return h(this,void 0,void 0,(function*(){const s=new Bt(Object.assign(Object.assign({},e),{keySet:this._configuration.keySet}));return t?this.sendRequest(s,t):this.sendRequest(s)}))}getFileUrl(e){var t;const s=this.transport.request(new $t(Object.assign(Object.assign({},e),{keySet:this._configuration.keySet})).request()),n=null!==(t=s.queryParameters)&&void 0!==t?t:{},r=Object.keys(n).map((e=>{const t=n[e];return Array.isArray(t)?t.map((t=>`${e}=${R(t)}`)).join("&"):`${e}=${R(t)}`})).join("&");return`${s.origin}${s.path}?${r}`}downloadFile(e,t){return h(this,void 0,void 0,(function*(){if(!this._configuration.PubNubFile)throw new Error("Validation failed: 'PubNubFile' not configured or file upload not supported by the platform.");const s=new Rs(Object.assign(Object.assign({},e),{keySet:this._configuration.keySet,PubNubFile:this._configuration.PubNubFile,cryptography:this.cryptography?this.cryptography:void 0,crypto:this._configuration.getCryptoModule()}));return t?this.sendRequest(s,t):yield this.sendRequest(s)}))}deleteFile(e,t){return h(this,void 0,void 0,(function*(){const s=new Lt(Object.assign(Object.assign({},e),{keySet:this._configuration.keySet}));return t?this.sendRequest(s,t):this.sendRequest(s)}))}time(e){return h(this,void 0,void 0,(function*(){const t=new As;return e?this.sendRequest(t,e):this.sendRequest(t)}))}encrypt(e,t){const s=this._configuration.getCryptoModule();if(!t&&s&&"string"==typeof e){const t=s.encrypt(e);return"string"==typeof t?t:y(t)}if(!this.crypto)throw new Error("Encryption error: cypher key not set");return this.crypto.encrypt(e,t)}decrypt(e,t){const s=this._configuration.getCryptoModule();if(!t&&s){const t=s.decrypt(e);return t instanceof ArrayBuffer?JSON.parse((new TextDecoder).decode(t)):t}if(!this.crypto)throw new Error("Decryption error: cypher key not set");return this.crypto.decrypt(e,t)}encryptFile(e,t){return h(this,void 0,void 0,(function*(){var s;if("string"!=typeof e&&(t=e),!t)throw new Error("File encryption error. Source file is missing.");if(!this._configuration.PubNubFile)throw new Error("File encryption error. File constructor not configured.");if("string"!=typeof e&&!this._configuration.getCryptoModule())throw new Error("File encryption error. Crypto module not configured.");if("string"==typeof e){if(!this.cryptography)throw new Error("File encryption error. File encryption not available");return this.cryptography.encryptFile(e,t,this._configuration.PubNubFile)}return null===(s=this._configuration.getCryptoModule())||void 0===s?void 0:s.encryptFile(t,this._configuration.PubNubFile)}))}decryptFile(e,t){return h(this,void 0,void 0,(function*(){var s;if("string"!=typeof e&&(t=e),!t)throw new Error("File encryption error. Source file is missing.");if(!this._configuration.PubNubFile)throw new Error("File decryption error. File constructor not configured.");if("string"==typeof e&&!this._configuration.getCryptoModule())throw new Error("File decryption error. Crypto module not configured.");if("string"==typeof e){if(!this.cryptography)throw new Error("File decryption error. File decryption not available");return this.cryptography.decryptFile(e,t,this._configuration.PubNubFile)}return null===(s=this._configuration.getCryptoModule())||void 0===s?void 0:s.decryptFile(t,this._configuration.PubNubFile)}))}}Is.decoder=new TextDecoder,Is.OPERATIONS=ie,Is.CATEGORIES=i,Is.ExponentialRetryPolicy=Be.ExponentialRetryPolicy,Is.LinearRetryPolicy=Be.LinearRetryPolicy;class Us{constructor(e,t){this.decode=e,this.base64ToBinary=t}decodeToken(e){let t="";e.length%4==3?t="=":e.length%4==2&&(t="==");const s=e.replace(/-/gi,"+").replace(/_/gi,"/")+t,n=this.decode(this.base64ToBinary(s));return"object"==typeof n?n:void 0}}class Ts extends Is{constructor(e){var t;const s=K(e),n=Object.assign(Object.assign({},s),{sdkFamily:"Web",PubNubFile:p}),i=L(n,(e=>{if(e.cipherKey)return new j({default:new M(Object.assign({},e)),cryptors:[new E({cipherKey:e.cipherKey})]})})),o=new H(new Us((e=>x(r.decode(e))),g));let a;(i.getCipherKey()||i.secretKey)&&(a=new C({secretKey:i.secretKey,cipherKey:i.getCipherKey(),useRandomIVs:i.getUseRandomIVs(),customEncrypt:i.getCustomEncrypt(),customDecrypt:i.getCustomDecrypt()}));let c=new F(i.keepAlive,i.logVerbosity);s.enableServiceWorker&&(c=new u({clientIdentifier:i._instanceId,subscriptionKey:i.subscribeKey,sdkVersion:i.getVersion(),logVerbosity:i.logVerbosity,transport:c}));super({configuration:i,transport:new W({clientConfiguration:i,tokenManager:o,transport:c}),cryptography:new P,tokenManager:o,crypto:a}),(null===(t=e.listenToBrowserNetworkEvents)||void 0===t||t)&&(window.addEventListener("offline",(()=>{this.networkDownDetected()})),window.addEventListener("online",(()=>{this.networkUpDetected()})))}networkDownDetected(){this.listenerManager.announceNetworkDown(),this._configuration.restore?this.disconnect():this.destroy(!0)}networkUpDetected(){this.listenerManager.announceNetworkUp(),this.reconnect()}}return Ts.CryptoModule=j,Ts})); diff --git a/dist/web/pubnub.worker.js b/dist/web/pubnub.worker.js new file mode 100644 index 000000000..31a3ef3ac --- /dev/null +++ b/dist/web/pubnub.worker.js @@ -0,0 +1,979 @@ +(function (factory) { + typeof define === 'function' && define.amd ? define(factory) : + factory(); +})((function () { 'use strict'; + + /****************************************************************************** + 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 */ + + + 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()); + }); + } + + 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 commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; + + function getDefaultExportFromCjs (x) { + return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; + } + + var uuid = {exports: {}}; + + /*! lil-uuid - v0.1 - MIT License - https://github.com/lil-js/uuid */ + uuid.exports; + + (function (module, exports) { + (function (root, factory) { + { + factory(exports); + if (module !== null) { + module.exports = exports.uuid; + } + } + }(commonjsGlobal, function (exports) { + var VERSION = '0.1.0'; + var uuidRegex = { + '3': /^[0-9A-F]{8}-[0-9A-F]{4}-3[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}$/i, + '4': /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i, + '5': /^[0-9A-F]{8}-[0-9A-F]{4}-5[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i, + all: /^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i + }; + + function uuid() { + var uuid = '', i, random; + for (i = 0; i < 32; i++) { + random = Math.random() * 16 | 0; + if (i === 8 || i === 12 || i === 16 || i === 20) uuid += '-'; + uuid += (i === 12 ? 4 : (i === 16 ? (random & 3 | 8) : random)).toString(16); + } + return uuid + } + + function isUUID(str, version) { + var pattern = uuidRegex[version || 'all']; + return pattern && pattern.test(str) || false + } + + uuid.isUUID = isUUID; + uuid.VERSION = VERSION; + + exports.uuid = uuid; + exports.isUUID = isUUID; + })); + } (uuid, uuid.exports)); + + var uuidExports = uuid.exports; + var uuidGenerator$1 = /*@__PURE__*/getDefaultExportFromCjs(uuidExports); + + var uuidGenerator = { + createUUID() { + if (uuidGenerator$1.uuid) { + return uuidGenerator$1.uuid(); + } + // @ts-expect-error Depending on module type it may be callable. + return uuidGenerator$1(); + }, + }; + + /// + /** + * Subscription Service Worker Transport provider. + * + * Service worker provides support for PubNub subscription feature to give better user experience across + * multiple opened pages. + */ + // region State + /** + * Service `ArrayBuffer` response decoder. + */ + const decoder = new TextDecoder(); + /** + * Map of identifiers, scheduled by the Service Worker, to their abort controllers. + * + * **Note:** Because of message-based nature of interaction it will be impossible to pass actual {@link AbortController} + * to the transport provider code. + */ + const abortControllers = new Map(); + /** + * Map of PubNub client identifiers to their state in the current Service Worker. + */ + const pubNubClients = {}; + /** + * Per-subscription key list of PubNub client state. + */ + const pubNubClientsBySubscriptionKey = {}; + /** + * Per-subscription key presence state associated with unique user identifiers with which {@link pubNubClients|clients} + * scheduled subscription request. + */ + const presenceState = {}; + /** + * Per-subscription key map of client identifiers to the Service Worker {@link Client} identifier. + * + * Service Worker {@link Client} represent pages at which PubNub clients registered Service Workers. + */ + const serviceWorkerClients = {}; + /** + * List of ongoing subscription requests. + * + * **Node:** Identifiers differ from request identifiers received in {@link SendRequestEvent} object. + */ + const serviceRequests = {}; + // endregion + // -------------------------------------------------------- + // ------------------- Event Handlers --------------------- + // -------------------------------------------------------- + // region Event Handlers + /** + * Listen for Service Worker activation. + */ + self.addEventListener('activate', (event) => { + event.waitUntil(self.clients.claim()); + }); + /** + * Listen for events from the client. + */ + self.addEventListener('message', (event) => { + // Ignoring requests sent from other service workers. + if (!validateEventPayload(event)) + return; + const data = event.data; + if (data.type === 'send-request') { + if (data.request.path.startsWith('/v2/subscribe')) { + registerClientIfRequired(event); + handleSendSubscribeRequestEvent(data); + } + else { + if (!pubNubClients[data.clientIdentifier]) + registerClientIfRequired(event); + handleSendLeaveRequestEvent(event); + } + } + else if (data.type === 'cancel-request') + handleCancelRequestEvent(data); + }); + /** + * Handle client request to send subscription request. + * + * @param event - Subscription event details. + */ + const handleSendSubscribeRequestEvent = (event) => { + const requestOrId = subscribeTransportRequestFromEvent(event); + const client = pubNubClients[event.clientIdentifier]; + if (client) + notifyRequestProcessing('start', [client], new Date().toISOString()); + if (typeof requestOrId === 'string') { + if (client) { + // Updating client timetoken information. + client.subscription.previousTimetoken = client.subscription.timetoken; + client.subscription.timetoken = serviceRequests[requestOrId].timetoken; + client.subscription.serviceRequestId = requestOrId; + } + return; + } + if (event.request.cancellable) + abortControllers.set(requestOrId.identifier, new AbortController()); + sendRequest(requestOrId, () => clientsForRequest(requestOrId.identifier), (clients, response) => { + // Notify each PubNub client which awaited for response. + notifyRequestProcessingResult(clients, response); + // Clean up scheduled request and client references to it. + markRequestCompleted(clients, requestOrId.identifier); + }, (clients, error) => { + // Notify each PubNub client which awaited for response. + notifyRequestProcessingResult(clients, null, requestOrId, requestProcessingError(error)); + // Clean up scheduled request and client references to it. + markRequestCompleted(clients, requestOrId.identifier); + }); + }; + /** + * Handle client request to leave request. + * + * @param event - Leave event details. + */ + const handleSendLeaveRequestEvent = (event) => { + const data = event.data; + const request = leaveTransportRequestFromEvent(data); + const client = pubNubClients[data.clientIdentifier]; + if (!client) + return; + if (!request) { + const body = new TextEncoder().encode('{"status": 200, "action": "leave", "message": "OK", "service":"Presence"}'); + const headers = new Headers({ 'Content-Type': 'text/javascript; charset="UTF-8"', 'Content-Length': '74' }); + const response = new Response(body, { status: 200, headers }); + const result = requestProcessingSuccess([response, body]); + result.url = `${data.request.origin}${data.request.path}`; + result.clientIdentifier = data.clientIdentifier; + result.identifier = data.request.identifier; + publishClientEvent(event.source.id, result).then((sent) => { + if (sent) + invalidateClient(client.subscriptionKey, client.clientIdentifier, client.userId); + }); + return; + } + sendRequest(request, () => [client], (clients, response) => { + // Notify each PubNub client which awaited for response. + notifyRequestProcessingResult(clients, response, data.request); + }, (clients, error) => { + // Notify each PubNub client which awaited for response. + notifyRequestProcessingResult(clients, null, data.request, requestProcessingError(error)); + }); + }; + /** + * Handle cancel request event. + * + * Try cancel request if there is no other observers. + * + * @param event - Request cancellation event details. + */ + const handleCancelRequestEvent = (event) => { + const client = pubNubClients[event.clientIdentifier]; + const serviceRequestId = client ? client.subscription.serviceRequestId : undefined; + if (!client || !serviceRequestId) + return; + // Unset awaited requests. + delete client.subscription.serviceRequestId; + delete client.subscription.request; + if (clientsForRequest(serviceRequestId).length === 0) { + const controller = abortControllers.get(serviceRequestId); + abortControllers.delete(serviceRequestId); + // Clean up scheduled requests. + delete serviceRequests[serviceRequestId]; + // Abort request if possible. + if (controller) + controller.abort(); + } + }; + // endregion + // -------------------------------------------------------- + // ------------------------ Common ------------------------ + // -------------------------------------------------------- + // region Common + /** + * Process transport request. + * + * @param request - Transport request with required information for {@link Request} creation. + * @param getClients - Request completion PubNub client observers getter. + * @param success - Request success completion handler. + * @param failure - Request failure handler. + */ + const sendRequest = (request, getClients, success, failure) => { + (() => __awaiter(void 0, void 0, void 0, function* () { + var _a; + // Request progress support. + const start = new Date().getTime(); + Promise.race([ + fetch(requestFromTransportRequest(request), { + signal: (_a = abortControllers.get(request.identifier)) === null || _a === void 0 ? void 0 : _a.signal, + keepalive: true, + }), + requestTimeoutTimer(request.identifier, request.timeout), + ]) + .then((response) => response.arrayBuffer().then((buffer) => [response, buffer])) + .then((response) => { + const responseBody = response[1].byteLength > 0 ? response[1] : undefined; + const clients = getClients(); + if (clients.length === 0) + return; + notifyRequestProcessing('end', clients, new Date().toISOString(), request, responseBody, response[0].headers.get('Content-Type'), new Date().getTime() - start); + success(clients, response); + }) + .catch((error) => { + const clients = getClients(); + if (clients.length === 0) + return; + failure(clients, error); + }); + }))(); + }; + /** + * Create request timeout timer. + * + * **Note:** Native Fetch API doesn't support `timeout` out-of-box and {@link Promise} used to emulate it. + * + * @param requestId - Unique identifier of request which will time out after {@link requestTimeout} seconds. + * @param requestTimeout - Number of seconds after which request with specified identifier will time out. + * + * @returns Promise which rejects after time out will fire. + */ + const requestTimeoutTimer = (requestId, requestTimeout) => new Promise((_, reject) => { + const timeoutId = setTimeout(() => { + // Clean up. + abortControllers.delete(requestId); + clearTimeout(timeoutId); + reject(new Error('Request timeout')); + }, requestTimeout * 1000); + }); + /** + * Retrieve list of PubNub clients which is pending for service worker request completion. + * + * @param identifier - Identifier of the subscription request which has been scheduled by the Service Worker. + * + * @returns List of PubNub client state objects for Service Worker. + */ + const clientsForRequest = (identifier) => { + return Object.values(pubNubClients).filter((client) => client !== undefined && client.subscription.serviceRequestId === identifier); + }; + /** + * Clean up PubNub client states from ongoing request. + * + * Reset requested and scheduled request information to make PubNub client "free" for neext requests. + * + * @param clients - List of PubNub clients which awaited for scheduled request completion. + * @param requestId - Unique subscribe request identifier for which {@link clients} has been provided. + */ + const markRequestCompleted = (clients, requestId) => { + delete serviceRequests[requestId]; + clients.forEach((client) => { + delete client.subscription.request; + delete client.subscription.serviceRequestId; + }); + }; + /** + * Creates a Request object from a given {@link TransportRequest} object. + * + * @param req - The {@link TransportRequest} object containing request information. + * + * @returns `Request` object generated from the {@link TransportRequest} object or `undefined` if no request + * should be sent. + */ + const requestFromTransportRequest = (req) => { + let headers = undefined; + const queryParameters = req.queryParameters; + let path = req.path; + if (req.headers) { + headers = {}; + for (const [key, value] of Object.entries(req.headers)) + headers[key] = value; + } + if (queryParameters && Object.keys(queryParameters).length !== 0) + path = `${path}?${queryStringFromObject(queryParameters)}`; + return new Request(`${req.origin}${path}`, { + method: req.method, + headers, + redirect: 'follow', + }); + }; + /** + * Construct transport request from send subscription request event. + * + * Update transport request to aggregate channels and groups if possible. + * + * @param event - Client's send subscription event request. + * + * @returns Final transport request or identifier from active request which will provide response to required + * channels and groups. + */ + const subscribeTransportRequestFromEvent = (event) => { + var _a, _b, _c, _d; + const client = pubNubClients[event.clientIdentifier]; + const clients = clientsForSendSubscribeRequestEvent(client.subscription.previousTimetoken, event); + const serviceRequestId = uuidGenerator.createUUID(); + const request = Object.assign({}, event.request); + if (clients.length > 1) { + const activeRequestId = activeSubscriptionForEvent(clients, event); + // Return identifier of the ongoing request. + if (activeRequestId) + return activeRequestId; + const state = ((_a = presenceState[client.subscriptionKey]) !== null && _a !== void 0 ? _a : {})[client.userId]; + const aggregatedState = {}; + const channelGroups = new Set(client.subscription.channelGroups); + const channels = new Set(client.subscription.channels); + if (state && client.subscription.objectsWithState.length) { + client.subscription.objectsWithState.forEach((name) => { + const objectState = state[name]; + if (objectState) + aggregatedState[name] = objectState; + }); + } + for (const client of clients) { + const { subscription } = client; + // Skip clients which already have active subscription request. + if (subscription.serviceRequestId) + continue; + subscription.channelGroups.forEach(channelGroups.add, channelGroups); + subscription.channels.forEach(channels.add, channels); + // Set awaited service worker request identifier. + subscription.serviceRequestId = serviceRequestId; + if (!state) + continue; + subscription.objectsWithState.forEach((name) => { + const objectState = state[name]; + if (objectState && !aggregatedState[name]) + aggregatedState[name] = objectState; + }); + } + const serviceRequest = ((_b = serviceRequests[serviceRequestId]) !== null && _b !== void 0 ? _b : (serviceRequests[serviceRequestId] = { + requestId: serviceRequestId, + timetoken: (_c = request.queryParameters.tt) !== null && _c !== void 0 ? _c : '0', + channelGroups: [], + channels: [], + })); + // Update request channels list (if required). + if (channels.size) { + serviceRequest.channels = Array.from(channels).sort(); + const pathComponents = request.path.split('/'); + pathComponents[4] = serviceRequest.channels.join(','); + request.path = pathComponents.join('/'); + } + // Update request channel groups list (if required). + if (channelGroups.size) { + serviceRequest.channelGroups = Array.from(channelGroups).sort(); + request.queryParameters['channel-group'] = serviceRequest.channelGroups.join(','); + } + // Update request `state` (if required). + if (Object.keys(aggregatedState).length) + request.queryParameters['state'] = JSON.stringify(aggregatedState); + } + else { + serviceRequests[serviceRequestId] = { + requestId: serviceRequestId, + timetoken: (_d = request.queryParameters.tt) !== null && _d !== void 0 ? _d : '0', + channelGroups: client.subscription.channelGroups, + channels: client.subscription.channels, + }; + } + client.subscription.serviceRequestId = serviceRequestId; + request.identifier = serviceRequestId; + return request; + }; + /** + * Construct transport request from send leave request event. + * + * Filter out channels and groups, which is still in use by other PubNub client instances from leave request. + * + * @param event - Client's send leave event request. + * + * @returns Final transport request or `undefined` in case if there is no channels and groups for which request can be + * done. + */ + const leaveTransportRequestFromEvent = (event) => { + const client = pubNubClients[event.clientIdentifier]; + const clients = clientsForSendLeaveRequestEvent(event); + let channelGroups = channelGroupsFromRequest(event.request); + let channels = channelsFromRequest(event.request); + const request = Object.assign({}, event.request); + if (client) { + const { subscription } = client; + if (channels.length) + subscription.channels = subscription.channels.filter((channel) => !channels.includes(channel)); + if (channelGroups.length) { + subscription.channelGroups = subscription.channelGroups.filter((group) => !channelGroups.includes(group)); + } + } + // Filter out channels and groups which is still in use by the other PubNub client instances. + for (const client of clients) { + if (client.clientIdentifier === event.clientIdentifier) + continue; + if (channels.length) + channels = channels.filter((channel) => !client.subscription.channels.includes(channel)); + if (channelGroups.length) + channelGroups = channelGroups.filter((group) => !client.subscription.channelGroups.includes(group)); + } + if (channels.length === 0 && channelGroups.length === 0) + return undefined; + // Update request channels list (if required). + if (channels.length) { + const pathComponents = request.path.split('/'); + pathComponents[4] = channels.join(','); + request.path = pathComponents.join('/'); + } + // Update request channel groups list (if required). + if (channelGroups.length) + request.queryParameters['channel-group'] = channelGroups.join(','); + return request; + }; + /** + * Send event to all service worker clients. + * + * @param identifier - Service Worker receiving {@link Client} identifier. + * @param event - Service worker event object. + */ + const publishClientEvent = (identifier, event) => { + return self.clients.get(identifier).then((client) => { + if (!client) + return false; + client.postMessage(event); + return true; + }); + }; + /** + * Send request processing update. + * + * @param type - Type of processing event. + * @param clients - List of PubNub clients which should be notified about request progress. + * @param timestamp - Date and time when request processing update happened. + * @param [request] - Processed request information. + * @param [responseBody] - PubNub service response. + * @param [contentType] - PubNub service response content type. + * @param [duration] - How long it took to complete request. + */ + const notifyRequestProcessing = (type, clients, timestamp, request, responseBody, contentType, duration) => { + var _a; + if (clients.length === 0) + return; + const clientIds = (_a = serviceWorkerClients[clients[0].subscriptionKey]) !== null && _a !== void 0 ? _a : {}; + let event; + if (type === 'start') { + event = { + type: 'request-progress-start', + clientIdentifier: '', + url: '', + timestamp, + }; + } + else { + let response; + if (responseBody && + contentType && + (contentType.indexOf('text/javascript') !== -1 || + contentType.indexOf('application/json') !== -1 || + contentType.indexOf('text/plain') !== -1 || + contentType.indexOf('text/html') !== -1)) { + response = decoder.decode(responseBody); + } + event = { + type: 'request-progress-end', + clientIdentifier: '', + url: '', + response, + timestamp, + duration: duration, + }; + } + clients.forEach((client) => { + const serviceWorkerClientId = clientIds[client.clientIdentifier]; + const { request: clientRequest } = client.subscription; + const decidedRequest = clientRequest !== null && clientRequest !== void 0 ? clientRequest : request; + if (client.logVerbosity && serviceWorkerClientId && decidedRequest) { + publishClientEvent(serviceWorkerClientId, Object.assign(Object.assign({}, event), { clientIdentifier: client.clientIdentifier, url: `${decidedRequest.origin}${decidedRequest.path}`, query: decidedRequest.queryParameters })).then((sent) => { + if (sent) + invalidateClient(client.subscriptionKey, client.clientIdentifier, client.userId); + }); + } + }); + }; + /** + * Send request processing result event. + * + * @param clients - List of PubNub clients which should be notified about request result. + * @param [response] - PubNub service response. + * @param [request] - Processed request information. + * @param [result] - Explicit request processing result which should be notified. + */ + const notifyRequestProcessingResult = (clients, response, request, result) => { + var _a; + if (clients.length === 0) + return; + if (!result && !response) + return; + const clientIds = (_a = serviceWorkerClients[clients[0].subscriptionKey]) !== null && _a !== void 0 ? _a : {}; + if (!result && response) { + result = + response[0].status >= 400 + ? // Treat 4xx and 5xx status codes as errors. + requestProcessingError(undefined, response) + : requestProcessingSuccess(response); + } + clients.forEach((client) => { + const serviceWorkerClientId = clientIds[client.clientIdentifier]; + const { request: clientRequest } = client.subscription; + const decidedRequest = clientRequest !== null && clientRequest !== void 0 ? clientRequest : request; + if (serviceWorkerClientId && decidedRequest) { + publishClientEvent(serviceWorkerClientId, Object.assign(Object.assign({}, result), { clientIdentifier: client.clientIdentifier, identifier: decidedRequest.identifier, url: `${decidedRequest.origin}${decidedRequest.path}` })).then((sent) => { + if (sent) + invalidateClient(client.subscriptionKey, client.clientIdentifier, client.userId); + }); + } + }); + }; + /** + * Create processing success event from service response. + * + * **Note:** The rest of information like `clientIdentifier`,`identifier`, and `url` will be added later for each + * specific PubNub client state. + * + * @param res - Service response for used REST API endpoint along with response body. + * + * @returns Request processing success event object. + */ + const requestProcessingSuccess = (res) => { + var _a; + const [response, body] = res; + const responseBody = body.byteLength > 0 ? body : undefined; + const contentLength = parseInt((_a = response.headers.get('Content-Length')) !== null && _a !== void 0 ? _a : '0', 10); + const contentType = response.headers.get('Content-Type'); + const headers = {}; + // Copy Headers object content into plain Record. + response.headers.forEach((value, key) => (headers[key] = value.toLowerCase())); + return { + type: 'request-process-success', + clientIdentifier: '', + identifier: '', + url: '', + response: { + contentLength, + contentType, + headers, + status: response.status, + body: responseBody, + }, + }; + }; + /** + * Create processing error event from service response. + * + * **Note:** The rest of information like `clientIdentifier`,`identifier`, and `url` will be added later for each + * specific PubNub client state. + * + * @param [error] - Client-side request processing error (for example network issues). + * @param [res] - Service error response (for example permissions error or malformed + * payload) along with service body. + * + * @returns Request processing error event object. + */ + const requestProcessingError = (error, res) => { + // User service response as error information source. + if (res) { + return Object.assign(Object.assign({}, requestProcessingSuccess(res)), { type: 'request-process-error' }); + } + let type = 'NETWORK_ISSUE'; + let message = 'Unknown error'; + let name = 'Error'; + if (error && error instanceof Error) { + message = error.message; + name = error.name; + } + if (name === 'AbortError') { + message = 'Request aborted'; + type = 'ABORTED'; + } + else if (message === 'Request timeout') + type = 'TIMEOUT'; + return { + type: 'request-process-error', + clientIdentifier: '', + identifier: '', + url: '', + error: { name, type, message }, + }; + }; + // endregion + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + // region Helpers + /** + * Register client if it didn't use Service Worker before. + * + * The registration process updates the Service Worker state with information about channels and groups in which + * particular PubNub clients are interested, and uses this information when another subscribe request is made to build + * shared requests. + * + * @param event - Base information about PubNub client instance and Service Worker {@link Client}. + */ + const registerClientIfRequired = (event) => { + var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u; + var _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5; + const information = event.data; + const { clientIdentifier } = information; + const query = information.request.queryParameters; + let client = pubNubClients[clientIdentifier]; + if (!client) { + const isPresenceLeave = !information.request.path.startsWith('/v2/subscribe'); + const channelGroupQuery = !isPresenceLeave ? ((_a = query['channel-group']) !== null && _a !== void 0 ? _a : '') : ''; + const state = !isPresenceLeave ? ((_b = query.state) !== null && _b !== void 0 ? _b : '') : ''; + client = pubNubClients[clientIdentifier] = { + clientIdentifier, + subscriptionKey: information.subscriptionKey, + userId: query.uuid, + authKey: ((_c = query.auth) !== null && _c !== void 0 ? _c : ''), + logVerbosity: information.logVerbosity, + subscription: { + path: !isPresenceLeave ? information.request.path : '', + channelGroupQuery: !isPresenceLeave ? channelGroupQuery : '', + channels: !isPresenceLeave ? channelsFromRequest(information.request) : [], + channelGroups: !isPresenceLeave ? channelGroupsFromRequest(information.request) : [], + previousTimetoken: !isPresenceLeave ? ((_d = query.tt) !== null && _d !== void 0 ? _d : '0') : '0', + timetoken: !isPresenceLeave ? ((_e = query.tt) !== null && _e !== void 0 ? _e : '0') : '0', + request: !isPresenceLeave ? information.request : undefined, + objectsWithState: [], + filterExpression: !isPresenceLeave ? ((_f = query['filter-expr']) !== null && _f !== void 0 ? _f : '') : undefined, + }, + }; + if (!isPresenceLeave && state.length > 0) { + const parsedState = JSON.parse(state); + const userState = ((_h = (_w = ((_g = presenceState[_v = client.subscriptionKey]) !== null && _g !== void 0 ? _g : (presenceState[_v] = {})))[_x = client.userId]) !== null && _h !== void 0 ? _h : (_w[_x] = {})); + Object.entries(parsedState).forEach(([objectName, value]) => (userState[objectName] = value)); + client.subscription.objectsWithState = Object.keys(parsedState); + } + // Map registered PubNub client to its subscription key. + const clientsBySubscriptionKey = ((_j = pubNubClientsBySubscriptionKey[_y = information.subscriptionKey]) !== null && _j !== void 0 ? _j : (pubNubClientsBySubscriptionKey[_y] = [])); + if (clientsBySubscriptionKey.every((entry) => entry.clientIdentifier !== clientIdentifier)) + clientsBySubscriptionKey.push(client); + // Binding PubNub client to the page (Service Worker Client). + ((_k = serviceWorkerClients[_z = information.subscriptionKey]) !== null && _k !== void 0 ? _k : (serviceWorkerClients[_z] = {}))[clientIdentifier] = event.source.id; + } + else { + const channelGroupQuery = ((_l = query['channel-group']) !== null && _l !== void 0 ? _l : ''); + const state = ((_m = query.state) !== null && _m !== void 0 ? _m : ''); + client.subscription.filterExpression = ((_o = query['filter-expr']) !== null && _o !== void 0 ? _o : ''); + client.subscription.previousTimetoken = client.subscription.timetoken; + client.subscription.timetoken = ((_p = query.tt) !== null && _p !== void 0 ? _p : '0'); + client.subscription.request = information.request; + client.authKey = ((_q = query.auth) !== null && _q !== void 0 ? _q : ''); + client.userId = query.uuid; + if (client.subscription.path !== information.request.path) { + client.subscription.path = information.request.path; + client.subscription.channels = channelsFromRequest(information.request); + } + if (client.subscription.channelGroupQuery !== channelGroupQuery) { + client.subscription.channelGroupQuery = channelGroupQuery; + client.subscription.channelGroups = channelGroupsFromRequest(information.request); + } + if (state.length > 0) { + const parsedState = JSON.parse(state); + const userState = ((_s = (_1 = ((_r = presenceState[_0 = client.subscriptionKey]) !== null && _r !== void 0 ? _r : (presenceState[_0] = {})))[_2 = client.userId]) !== null && _s !== void 0 ? _s : (_1[_2] = {})); + Object.entries(parsedState).forEach(([objectName, value]) => (userState[objectName] = value)); + // Clean up state for objects where presence state has been reset. + for (const objectName of client.subscription.objectsWithState) + if (!parsedState[objectName]) + delete userState[objectName]; + client.subscription.objectsWithState = Object.keys(parsedState); + } + // Handle potential presence state reset. + else if (client.subscription.objectsWithState.length) { + const userState = ((_u = (_4 = ((_t = presenceState[_3 = client.subscriptionKey]) !== null && _t !== void 0 ? _t : (presenceState[_3] = {})))[_5 = client.userId]) !== null && _u !== void 0 ? _u : (_4[_5] = {})); + for (const objectName of client.subscription.objectsWithState) + delete userState[objectName]; + client.subscription.objectsWithState = []; + } + } + }; + /** + * Clean up resources used by registered PubNub client instance. + * + * @param subscriptionKey - Subscription key which has been used by the + * invalidated instance. + * @param clientId - Unique PubNub client identifier. + * @param userId - Unique identifier of the user used by PubNub client instance. + */ + const invalidateClient = (subscriptionKey, clientId, userId) => { + delete pubNubClients[clientId]; + let clients = pubNubClientsBySubscriptionKey[subscriptionKey]; + if (clients) { + // Clean up linkage between client and subscription key. + clients = clients.filter((client) => client.clientIdentifier !== clientId); + if (clients.length > 0) + pubNubClientsBySubscriptionKey[subscriptionKey] = clients; + else + delete pubNubClientsBySubscriptionKey[subscriptionKey]; + // Clean up presence state information if not in use anymore. + if (clients.length === 0) + delete presenceState[subscriptionKey]; + // Clean up service workers client linkage to PubNub clients. + if (clients.length > 0) { + const workerClients = serviceWorkerClients[subscriptionKey]; + if (workerClients) { + delete workerClients[clientId]; + if (Object.keys(workerClients).length === 0) + delete serviceWorkerClients[subscriptionKey]; + } + } + else + delete serviceWorkerClients[subscriptionKey]; + } + }; + /** + * Validate received event payload. + */ + const validateEventPayload = (event) => { + if (!event.source || !(event.source instanceof Client)) + return false; + const data = event.data; + const { clientIdentifier, subscriptionKey, logVerbosity } = data; + if (logVerbosity === undefined || typeof logVerbosity !== 'boolean') + return false; + if (!clientIdentifier || typeof clientIdentifier !== 'string') + return false; + return !(!subscriptionKey || typeof subscriptionKey !== 'string'); + }; + /** + * Search for active subscription for one of the passed {@link serviceWorkerClients}. + * + * @param activeClients - List of suitable registered PubNub clients. + * @param event - Send Subscriber Request event data. + * + * @returns Unique identifier of the active request which will receive real-time updates for channels and groups + * requested in received subscription request or `undefined` if none of active (or not scheduled) request can be used. + */ + const activeSubscriptionForEvent = (activeClients, event) => { + var _a; + const query = event.request.queryParameters; + const channelGroupQuery = ((_a = query['channel-group']) !== null && _a !== void 0 ? _a : ''); + const requestPath = event.request.path; + let channelGroups; + let channels; + for (const client of activeClients) { + const { subscription } = client; + // Skip PubNub clients which doesn't await for subscription response. + if (!subscription.serviceRequestId) + continue; + if (subscription.path === requestPath && subscription.channelGroupQuery === channelGroupQuery) { + return subscription.serviceRequestId; + } + else { + const scheduledRequest = serviceRequests[subscription.serviceRequestId]; + if (!channelGroups) + channelGroups = channelGroupsFromRequest(event.request); + if (!channels) + channels = channelsFromRequest(event.request); + // Checking whether all required channels and groups are handled already by active request or not. + if (channels.length && !includesStrings(scheduledRequest.channels, channels)) + continue; + if (channelGroups.length && !includesStrings(scheduledRequest.channelGroups, channelGroups)) + continue; + return subscription.serviceRequestId; + } + } + return undefined; + }; + /** + * Find PubNub client states with configuration compatible with the one in request. + * + * Method allow to find information about all PubNub client instances which use same: + * - subscription key + * - `userId` + * - `auth` key + * - `filter expression` + * - `timetoken` (compare should be done against previous timetoken of the client which requested new subscribe). + * + * @param timetoken - Previous timetoken used by the PubNub client which requested to send new subscription request + * (it will be the same as 'current' timetoken of the other PubNub clients). + * @param event - Send subscribe request event information. + * + * @returns List of PubNub client states which works from other pages for the same user. + */ + const clientsForSendSubscribeRequestEvent = (timetoken, event) => { + var _a, _b, _c; + const query = event.request.queryParameters; + const filterExpression = ((_a = query['filter-expr']) !== null && _a !== void 0 ? _a : ''); + const authKey = ((_b = query.auth) !== null && _b !== void 0 ? _b : ''); + const userId = query.uuid; + return ((_c = pubNubClientsBySubscriptionKey[event.subscriptionKey]) !== null && _c !== void 0 ? _c : []).filter((client) => client.userId === userId && + client.authKey === authKey && + client.subscription.filterExpression === filterExpression && + (timetoken === '0' || + client.subscription.previousTimetoken === '0' || + client.subscription.previousTimetoken === timetoken)); + }; + /** + * Find PubNub client states with configuration compatible with the one in request. + * + * Method allow to find information about all PubNub client instances which use same: + * - subscription key + * - `userId` + * - `auth` key + * + * @param event - Send leave request event information. + * + * @returns List of PubNub client states which works from other pages for the same user. + */ + const clientsForSendLeaveRequestEvent = (event) => { + var _a, _b; + const query = event.request.queryParameters; + const authKey = ((_a = query.auth) !== null && _a !== void 0 ? _a : ''); + const userId = query.uuid; + return ((_b = pubNubClientsBySubscriptionKey[event.subscriptionKey]) !== null && _b !== void 0 ? _b : []).filter((client) => client.userId === userId && client.authKey === authKey); + }; + /** + * Extract list of channels from request URI path. + * + * @param request - Transport request which should provide `path` for parsing. + * + * @returns List of channel names (not percent-decoded) for which `subscribe` or `leave` has been called. + */ + const channelsFromRequest = (request) => { + const channels = request.path.split('/')[request.path.startsWith('/v2/subscribe/') ? 4 : 6]; + return channels === ',' ? [] : channels.split(',').filter((name) => name.length > 0); + }; + /** + * Extract list of channel groups from request query. + * + * @param request - Transport request which should provide `query` for parsing. + * + * @returns List of channel group names (not percent-decoded) for which `subscribe` or `leave` has been called. + */ + const channelGroupsFromRequest = (request) => { + var _a; + const group = ((_a = request.queryParameters['channel-group']) !== null && _a !== void 0 ? _a : ''); + return group.length === 0 ? [] : group.split(',').filter((name) => name.length > 0); + }; + /** + * Check whether {@link main} array contains all entries from {@link sub} array. + * + * @param main - Main array with which `intersection` with {@link sub} should be checked. + * @param sub - Sub-array whose values should be checked in {@link main}. + * + * @returns `true` if all entries from {@link sub} is present in {@link main}. + */ + const includesStrings = (main, sub) => { + const set = new Set(main); + return sub.every(set.has, set); + }; + /** + * Stringify request query key / value pairs. + * + * @param query - Request query object. + * + * @returns Stringified query object. + */ + const queryStringFromObject = (query) => { + return Object.keys(query) + .map((key) => { + const queryValue = query[key]; + if (!Array.isArray(queryValue)) + return `${key}=${encodeString(queryValue)}`; + return queryValue.map((value) => `${key}=${encodeString(value)}`).join('&'); + }) + .join('&'); + }; + /** + * Percent-encode input string. + * + * **Note:** Encode content in accordance of the `PubNub` service requirements. + * + * @param input - Source string or number for encoding. + * + * @returns Percent-encoded string. + */ + const encodeString = (input) => { + return encodeURIComponent(input).replace(/[!~*'()]/g, (x) => `%${x.charCodeAt(0).toString(16).toUpperCase()}`); + }; + // endregion + // endregion + +})); diff --git a/dist/web/pubnub.worker.min.js b/dist/web/pubnub.worker.min.js new file mode 100644 index 000000000..864385802 --- /dev/null +++ b/dist/web/pubnub.worker.min.js @@ -0,0 +1,2 @@ +!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";function e(e,t,n,i){return new(n||(n=Promise))((function(s,r){function o(e){try{c(i.next(e))}catch(e){r(e)}}function u(e){try{c(i.throw(e))}catch(e){r(e)}}function c(e){var t;e.done?s(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(o,u)}c((i=i.apply(e,t||[])).next())}))}"function"==typeof SuppressedError&&SuppressedError;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self&&self;function t(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var n,i,s={exports:{}}; +/*! lil-uuid - v0.1 - MIT License - https://github.com/lil-js/uuid */n=s,function(e){var t="0.1.0",n={3:/^[0-9A-F]{8}-[0-9A-F]{4}-3[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}$/i,4:/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,5:/^[0-9A-F]{8}-[0-9A-F]{4}-5[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,all:/^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i};function i(){var e,t,n="";for(e=0;e<32;e++)t=16*Math.random()|0,8!==e&&12!==e&&16!==e&&20!==e||(n+="-"),n+=(12===e?4:16===e?3&t|8:t).toString(16);return n}function s(e,t){var i=n[t||"all"];return i&&i.test(e)||!1}i.isUUID=s,i.VERSION=t,e.uuid=i,e.isUUID=s}(i=s.exports),null!==n&&(n.exports=i.uuid);var r=t(s.exports),o={createUUID:()=>r.uuid?r.uuid():r()};const u=new TextDecoder,c=new Map,l={},a={},d={},p={},f={};self.addEventListener("activate",(e=>{e.waitUntil(self.clients.claim())})),self.addEventListener("message",(e=>{if(!K(e))return;const t=e.data;"send-request"===t.type?t.request.path.startsWith("/v2/subscribe")?(k(e),h(t)):(l[t.clientIdentifier]||k(e),b(e)):"cancel-request"===t.type&&v(t)}));const h=e=>{const t=j(e),n=l[e.clientIdentifier];n&&w("start",[n],(new Date).toISOString()),"string"!=typeof t?(e.request.cancellable&&c.set(t.identifier,new AbortController),g(t,(()=>q(t.identifier)),((e,n)=>{E(e,n),I(e,t.identifier)}),((e,n)=>{E(e,null,t,T(n)),I(e,t.identifier)}))):n&&(n.subscription.previousTimetoken=n.subscription.timetoken,n.subscription.timetoken=f[t].timetoken,n.subscription.serviceRequestId=t)},b=e=>{const t=e.data,n=O(t),i=l[t.clientIdentifier];if(i){if(!n){const n=(new TextEncoder).encode('{"status": 200, "action": "leave", "message": "OK", "service":"Presence"}'),s=new Headers({"Content-Type":'text/javascript; charset="UTF-8"',"Content-Length":"74"}),r=new Response(n,{status:200,headers:s}),o=S([r,n]);return o.url=`${t.request.origin}${t.request.path}`,o.clientIdentifier=t.clientIdentifier,o.identifier=t.request.identifier,void A(e.source.id,o).then((e=>{e&&x(i.subscriptionKey,i.clientIdentifier,i.userId)}))}g(n,(()=>[i]),((e,n)=>{E(e,n,t.request)}),((e,n)=>{E(e,null,t.request,T(n))}))}},v=e=>{const t=l[e.clientIdentifier],n=t?t.subscription.serviceRequestId:void 0;if(t&&n&&(delete t.subscription.serviceRequestId,delete t.subscription.request,0===q(n).length)){const e=c.get(n);c.delete(n),delete f[n],e&&e.abort()}},g=(t,n,i,s)=>{e(void 0,void 0,void 0,(function*(){var e;const r=(new Date).getTime();Promise.race([fetch(m(t),{signal:null===(e=c.get(t.identifier))||void 0===e?void 0:e.signal,keepalive:!0}),y(t.identifier,t.timeout)]).then((e=>e.arrayBuffer().then((t=>[e,t])))).then((e=>{const s=e[1].byteLength>0?e[1]:void 0,o=n();0!==o.length&&(w("end",o,(new Date).toISOString(),t,s,e[0].headers.get("Content-Type"),(new Date).getTime()-r),i(o,e))})).catch((e=>{const t=n();0!==t.length&&s(t,e)}))}))},y=(e,t)=>new Promise(((n,i)=>{const s=setTimeout((()=>{c.delete(e),clearTimeout(s),i(new Error("Request timeout"))}),1e3*t)})),q=e=>Object.values(l).filter((t=>void 0!==t&&t.subscription.serviceRequestId===e)),I=(e,t)=>{delete f[t],e.forEach((e=>{delete e.subscription.request,delete e.subscription.serviceRequestId}))},m=e=>{let t;const n=e.queryParameters;let i=e.path;if(e.headers){t={};for(const[n,i]of Object.entries(e.headers))t[n]=i}return n&&0!==Object.keys(n).length&&(i=`${i}?${W(n)}`),new Request(`${e.origin}${i}`,{method:e.method,headers:t,redirect:"follow"})},j=e=>{var t,n,i,s;const r=l[e.clientIdentifier],u=R(r.subscription.previousTimetoken,e),c=o.createUUID(),a=Object.assign({},e.request);if(u.length>1){const s=F(u,e);if(s)return s;const o=(null!==(t=d[r.subscriptionKey])&&void 0!==t?t:{})[r.userId],l={},p=new Set(r.subscription.channelGroups),h=new Set(r.subscription.channels);o&&r.subscription.objectsWithState.length&&r.subscription.objectsWithState.forEach((e=>{const t=o[e];t&&(l[e]=t)}));for(const e of u){const{subscription:t}=e;t.serviceRequestId||(t.channelGroups.forEach(p.add,p),t.channels.forEach(h.add,h),t.serviceRequestId=c,o&&t.objectsWithState.forEach((e=>{const t=o[e];t&&!l[e]&&(l[e]=t)})))}const b=null!==(n=f[c])&&void 0!==n?n:f[c]={requestId:c,timetoken:null!==(i=a.queryParameters.tt)&&void 0!==i?i:"0",channelGroups:[],channels:[]};if(h.size){b.channels=Array.from(h).sort();const e=a.path.split("/");e[4]=b.channels.join(","),a.path=e.join("/")}p.size&&(b.channelGroups=Array.from(p).sort(),a.queryParameters["channel-group"]=b.channelGroups.join(",")),Object.keys(l).length&&(a.queryParameters.state=JSON.stringify(l))}else f[c]={requestId:c,timetoken:null!==(s=a.queryParameters.tt)&&void 0!==s?s:"0",channelGroups:r.subscription.channelGroups,channels:r.subscription.channels};return r.subscription.serviceRequestId=c,a.identifier=c,a},O=e=>{const t=l[e.clientIdentifier],n=$(e);let i=P(e.request),s=G(e.request);const r=Object.assign({},e.request);if(t){const{subscription:e}=t;s.length&&(e.channels=e.channels.filter((e=>!s.includes(e)))),i.length&&(e.channelGroups=e.channelGroups.filter((e=>!i.includes(e))))}for(const t of n)t.clientIdentifier!==e.clientIdentifier&&(s.length&&(s=s.filter((e=>!t.subscription.channels.includes(e)))),i.length&&(i=i.filter((e=>!t.subscription.channelGroups.includes(e)))));if(0!==s.length||0!==i.length){if(s.length){const e=r.path.split("/");e[4]=s.join(","),r.path=e.join("/")}return i.length&&(r.queryParameters["channel-group"]=i.join(",")),r}},A=(e,t)=>self.clients.get(e).then((e=>!!e&&(e.postMessage(t),!0))),w=(e,t,n,i,s,r,o)=>{var c;if(0===t.length)return;const l=null!==(c=p[t[0].subscriptionKey])&&void 0!==c?c:{};let a;if("start"===e)a={type:"request-progress-start",clientIdentifier:"",url:"",timestamp:n};else{let e;s&&r&&(-1!==r.indexOf("text/javascript")||-1!==r.indexOf("application/json")||-1!==r.indexOf("text/plain")||-1!==r.indexOf("text/html"))&&(e=u.decode(s)),a={type:"request-progress-end",clientIdentifier:"",url:"",response:e,timestamp:n,duration:o}}t.forEach((e=>{const t=l[e.clientIdentifier],{request:n}=e.subscription,s=null!=n?n:i;e.logVerbosity&&t&&s&&A(t,Object.assign(Object.assign({},a),{clientIdentifier:e.clientIdentifier,url:`${s.origin}${s.path}`,query:s.queryParameters})).then((t=>{t&&x(e.subscriptionKey,e.clientIdentifier,e.userId)}))}))},E=(e,t,n,i)=>{var s;if(0===e.length)return;if(!i&&!t)return;const r=null!==(s=p[e[0].subscriptionKey])&&void 0!==s?s:{};!i&&t&&(i=t[0].status>=400?T(void 0,t):S(t)),e.forEach((e=>{const t=r[e.clientIdentifier],{request:s}=e.subscription,o=null!=s?s:n;t&&o&&A(t,Object.assign(Object.assign({},i),{clientIdentifier:e.clientIdentifier,identifier:o.identifier,url:`${o.origin}${o.path}`})).then((t=>{t&&x(e.subscriptionKey,e.clientIdentifier,e.userId)}))}))},S=e=>{var t;const[n,i]=e,s=i.byteLength>0?i:void 0,r=parseInt(null!==(t=n.headers.get("Content-Length"))&&void 0!==t?t:"0",10),o=n.headers.get("Content-Type"),u={};return n.headers.forEach(((e,t)=>u[t]=e.toLowerCase())),{type:"request-process-success",clientIdentifier:"",identifier:"",url:"",response:{contentLength:r,contentType:o,headers:u,status:n.status,body:s}}},T=(e,t)=>{if(t)return Object.assign(Object.assign({},S(t)),{type:"request-process-error"});let n="NETWORK_ISSUE",i="Unknown error",s="Error";return e&&e instanceof Error&&(i=e.message,s=e.name),"AbortError"===s?(i="Request aborted",n="ABORTED"):"Request timeout"===i&&(n="TIMEOUT"),{type:"request-process-error",clientIdentifier:"",identifier:"",url:"",error:{name:s,type:n,message:i}}},k=e=>{var t,n,i,s,r,o,u,c,f,h,b,v,g,y,q,I,m,j,O,A,w,E,S,T,k,x,K,F,R,$;const U=e.data,{clientIdentifier:W}=U,C=U.request.queryParameters;let D=l[W];if(D){const e=null!==(b=C["channel-group"])&&void 0!==b?b:"",t=null!==(v=C.state)&&void 0!==v?v:"";if(D.subscription.filterExpression=null!==(g=C["filter-expr"])&&void 0!==g?g:"",D.subscription.previousTimetoken=D.subscription.timetoken,D.subscription.timetoken=null!==(y=C.tt)&&void 0!==y?y:"0",D.subscription.request=U.request,D.authKey=null!==(q=C.auth)&&void 0!==q?q:"",D.userId=C.uuid,D.subscription.path!==U.request.path&&(D.subscription.path=U.request.path,D.subscription.channels=G(U.request)),D.subscription.channelGroupQuery!==e&&(D.subscription.channelGroupQuery=e,D.subscription.channelGroups=P(U.request)),t.length>0){const e=JSON.parse(t),n=null!==(m=(x=null!==(I=d[k=D.subscriptionKey])&&void 0!==I?I:d[k]={})[K=D.userId])&&void 0!==m?m:x[K]={};Object.entries(e).forEach((([e,t])=>n[e]=t));for(const t of D.subscription.objectsWithState)e[t]||delete n[t];D.subscription.objectsWithState=Object.keys(e)}else if(D.subscription.objectsWithState.length){const e=null!==(O=(R=null!==(j=d[F=D.subscriptionKey])&&void 0!==j?j:d[F]={})[$=D.userId])&&void 0!==O?O:R[$]={};for(const t of D.subscription.objectsWithState)delete e[t];D.subscription.objectsWithState=[]}}else{const b=!U.request.path.startsWith("/v2/subscribe"),v=b?"":null!==(t=C["channel-group"])&&void 0!==t?t:"",g=b?"":null!==(n=C.state)&&void 0!==n?n:"";if(D=l[W]={clientIdentifier:W,subscriptionKey:U.subscriptionKey,userId:C.uuid,authKey:null!==(i=C.auth)&&void 0!==i?i:"",logVerbosity:U.logVerbosity,subscription:{path:b?"":U.request.path,channelGroupQuery:b?"":v,channels:b?[]:G(U.request),channelGroups:b?[]:P(U.request),previousTimetoken:b?"0":null!==(s=C.tt)&&void 0!==s?s:"0",timetoken:b?"0":null!==(r=C.tt)&&void 0!==r?r:"0",request:b?void 0:U.request,objectsWithState:[],filterExpression:b?void 0:null!==(o=C["filter-expr"])&&void 0!==o?o:""}},!b&&g.length>0){const e=JSON.parse(g),t=null!==(c=(w=null!==(u=d[A=D.subscriptionKey])&&void 0!==u?u:d[A]={})[E=D.userId])&&void 0!==c?c:w[E]={};Object.entries(e).forEach((([e,n])=>t[e]=n)),D.subscription.objectsWithState=Object.keys(e)}const y=null!==(f=a[S=U.subscriptionKey])&&void 0!==f?f:a[S]=[];y.every((e=>e.clientIdentifier!==W))&&y.push(D),(null!==(h=p[T=U.subscriptionKey])&&void 0!==h?h:p[T]={})[W]=e.source.id}},x=(e,t,n)=>{delete l[t];let i=a[e];if(i)if(i=i.filter((e=>e.clientIdentifier!==t)),i.length>0?a[e]=i:delete a[e],0===i.length&&delete d[e],i.length>0){const n=p[e];n&&(delete n[t],0===Object.keys(n).length&&delete p[e])}else delete p[e]},K=e=>{if(!(e.source&&e.source instanceof Client))return!1;const t=e.data,{clientIdentifier:n,subscriptionKey:i,logVerbosity:s}=t;return void 0!==s&&"boolean"==typeof s&&(!(!n||"string"!=typeof n)&&!(!i||"string"!=typeof i))},F=(e,t)=>{var n;const i=null!==(n=t.request.queryParameters["channel-group"])&&void 0!==n?n:"",s=t.request.path;let r,o;for(const n of e){const{subscription:e}=n;if(e.serviceRequestId){if(e.path===s&&e.channelGroupQuery===i)return e.serviceRequestId;{const n=f[e.serviceRequestId];if(r||(r=P(t.request)),o||(o=G(t.request)),o.length&&!U(n.channels,o))continue;if(r.length&&!U(n.channelGroups,r))continue;return e.serviceRequestId}}}},R=(e,t)=>{var n,i,s;const r=t.request.queryParameters,o=null!==(n=r["filter-expr"])&&void 0!==n?n:"",u=null!==(i=r.auth)&&void 0!==i?i:"",c=r.uuid;return(null!==(s=a[t.subscriptionKey])&&void 0!==s?s:[]).filter((t=>t.userId===c&&t.authKey===u&&t.subscription.filterExpression===o&&("0"===e||"0"===t.subscription.previousTimetoken||t.subscription.previousTimetoken===e)))},$=e=>{var t,n;const i=e.request.queryParameters,s=null!==(t=i.auth)&&void 0!==t?t:"",r=i.uuid;return(null!==(n=a[e.subscriptionKey])&&void 0!==n?n:[]).filter((e=>e.userId===r&&e.authKey===s))},G=e=>{const t=e.path.split("/")[e.path.startsWith("/v2/subscribe/")?4:6];return","===t?[]:t.split(",").filter((e=>e.length>0))},P=e=>{var t;const n=null!==(t=e.queryParameters["channel-group"])&&void 0!==t?t:"";return 0===n.length?[]:n.split(",").filter((e=>e.length>0))},U=(e,t)=>{const n=new Set(e);return t.every(n.has,n)},W=e=>Object.keys(e).map((t=>{const n=e[t];return Array.isArray(n)?n.map((e=>`${t}=${C(e)}`)).join("&"):`${t}=${C(n)}`})).join("&"),C=e=>encodeURIComponent(e).replace(/[!~*'()]/g,(e=>`%${e.charCodeAt(0).toString(16).toUpperCase()}`))})); diff --git a/karma/web.config.js b/karma/web.config.cjs similarity index 100% rename from karma/web.config.js rename to karma/web.config.cjs diff --git a/lib/cbor/common.js b/lib/cbor/common.js index 0a97069c6..29a9f2a2c 100644 --- a/lib/cbor/common.js +++ b/lib/cbor/common.js @@ -1,25 +1,19 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var default_1 = /** @class */ (function () { - function default_1(decode, base64ToBinary) { - this._base64ToBinary = base64ToBinary; - this._decode = decode; +class Cbor { + constructor(decode, base64ToBinary) { + this.decode = decode; + this.base64ToBinary = base64ToBinary; } - default_1.prototype.decodeToken = function (tokenString) { - var padding = ''; - if (tokenString.length % 4 === 3) { + decodeToken(tokenString) { + let padding = ''; + if (tokenString.length % 4 === 3) padding = '='; - } - else if (tokenString.length % 4 === 2) { + else if (tokenString.length % 4 === 2) padding = '=='; - } - var cleaned = tokenString.replace(/-/gi, '+').replace(/_/gi, '/') + padding; - var result = this._decode(this._base64ToBinary(cleaned)); - if (typeof result === 'object') { - return result; - } - return undefined; - }; - return default_1; -}()); -exports.default = default_1; + const cleaned = tokenString.replace(/-/gi, '+').replace(/_/gi, '/') + padding; + const result = this.decode(this.base64ToBinary(cleaned)); + return typeof result === 'object' ? result : undefined; + } +} +exports.default = Cbor; diff --git a/lib/core/components/abort_signal.js b/lib/core/components/abort_signal.js index acee414dd..6d51ec546 100644 --- a/lib/core/components/abort_signal.js +++ b/lib/core/components/abort_signal.js @@ -1,57 +1,31 @@ "use strict"; -var __extends = (this && this.__extends) || (function () { - 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); - }; - return function (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 __()); - }; -})(); Object.defineProperty(exports, "__esModule", { value: true }); exports.AbortSignal = exports.AbortError = void 0; -var subject_1 = require("./subject"); -var AbortError = /** @class */ (function (_super) { - __extends(AbortError, _super); - function AbortError() { - var _newTarget = this.constructor; - var _this = _super.call(this, 'The operation was aborted.') || this; - _this.name = 'AbortError'; - Object.setPrototypeOf(_this, _newTarget.prototype); - return _this; +const subject_1 = require("./subject"); +class AbortError extends Error { + constructor() { + super('The operation was aborted.'); + this.name = 'AbortError'; + Object.setPrototypeOf(this, new.target.prototype); } - return AbortError; -}(Error)); +} exports.AbortError = AbortError; -var AbortSignal = /** @class */ (function (_super) { - __extends(AbortSignal, _super); - function AbortSignal() { - var _this = _super !== null && _super.apply(this, arguments) || this; - _this._aborted = false; - return _this; +class AbortSignal extends subject_1.Subject { + constructor() { + super(...arguments); + this._aborted = false; } - Object.defineProperty(AbortSignal.prototype, "aborted", { - get: function () { - return this._aborted; - }, - enumerable: false, - configurable: true - }); - AbortSignal.prototype.throwIfAborted = function () { + get aborted() { + return this._aborted; + } + throwIfAborted() { if (this._aborted) { throw new AbortError(); } - }; - AbortSignal.prototype.abort = function () { + } + abort() { this._aborted = true; this.notify(new AbortError()); - }; - return AbortSignal; -}(subject_1.Subject)); + } +} exports.AbortSignal = AbortSignal; diff --git a/lib/core/components/base64_codec.js b/lib/core/components/base64_codec.js index 157dd3b04..4bac838e0 100644 --- a/lib/core/components/base64_codec.js +++ b/lib/core/components/base64_codec.js @@ -1,45 +1,30 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.encode = exports.decode = void 0; -var BASE64_CHARMAP = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; -/** - * Decode a Base64 encoded string. - * - * @param paddedInput Base64 string with padding - * @returns ArrayBuffer with decoded data - */ +const BASE64_CHARMAP = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; function decode(paddedInput) { - // Remove up to last two equal signs. - var input = paddedInput.replace(/==?$/, ''); - var outputLength = Math.floor((input.length / 4) * 3); - // Prepare output buffer. - var data = new ArrayBuffer(outputLength); - var view = new Uint8Array(data); - var cursor = 0; - /** - * Returns the next integer representation of a sixtet of bytes from the input - * @returns sixtet of bytes - */ + const input = paddedInput.replace(/==?$/, ''); + const outputLength = Math.floor((input.length / 4) * 3); + const data = new ArrayBuffer(outputLength); + const view = new Uint8Array(data); + let cursor = 0; function nextSixtet() { - var char = input.charAt(cursor++); - var index = BASE64_CHARMAP.indexOf(char); + const char = input.charAt(cursor++); + const index = BASE64_CHARMAP.indexOf(char); if (index === -1) { - throw new Error("Illegal character at ".concat(cursor, ": ").concat(input.charAt(cursor - 1))); + throw new Error(`Illegal character at ${cursor}: ${input.charAt(cursor - 1)}`); } return index; } - for (var i = 0; i < outputLength; i += 3) { - // Obtain four sixtets - var sx1 = nextSixtet(); - var sx2 = nextSixtet(); - var sx3 = nextSixtet(); - var sx4 = nextSixtet(); - // Encode them as three octets - var oc1 = ((sx1 & 63) << 2) | (sx2 >> 4); - var oc2 = ((sx2 & 15) << 4) | (sx3 >> 2); - var oc3 = ((sx3 & 3) << 6) | (sx4 >> 0); + for (let i = 0; i < outputLength; i += 3) { + const sx1 = nextSixtet(); + const sx2 = nextSixtet(); + const sx3 = nextSixtet(); + const sx4 = nextSixtet(); + const oc1 = ((sx1 & 0b00111111) << 2) | (sx2 >> 4); + const oc2 = ((sx2 & 0b00001111) << 4) | (sx3 >> 2); + const oc3 = ((sx3 & 0b00000011) << 6) | (sx4 >> 0); view[i] = oc1; - // Skip padding bytes. if (sx3 != 64) view[i + 1] = oc2; if (sx4 != 64) @@ -49,40 +34,33 @@ function decode(paddedInput) { } exports.decode = decode; function encode(input) { - var base64 = ''; - var encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; - var bytes = new Uint8Array(input); - var byteLength = bytes.byteLength; - var byteRemainder = byteLength % 3; - var mainLength = byteLength - byteRemainder; - var a, b, c, d; - var chunk; - // Main loop deals with bytes in chunks of 3 - for (var i = 0; i < mainLength; i = i + 3) { - // Combine the three bytes into a single integer + let base64 = ''; + const encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + const bytes = new Uint8Array(input); + const byteLength = bytes.byteLength; + const byteRemainder = byteLength % 3; + const mainLength = byteLength - byteRemainder; + let a, b, c, d; + let chunk; + for (let i = 0; i < mainLength; i = i + 3) { chunk = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2]; - // Use bitmasks to extract 6-bit segments from the triplet - a = (chunk & 16515072) >> 18; // 16515072 = (2^6 - 1) << 18 - b = (chunk & 258048) >> 12; // 258048 = (2^6 - 1) << 12 - c = (chunk & 4032) >> 6; // 4032 = (2^6 - 1) << 6 - d = chunk & 63; // 63 = 2^6 - 1 - // Convert the raw binary segments to the appropriate ASCII encoding + a = (chunk & 16515072) >> 18; + b = (chunk & 258048) >> 12; + c = (chunk & 4032) >> 6; + d = chunk & 63; base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d]; } - // Deal with the remaining bytes and padding if (byteRemainder == 1) { chunk = bytes[mainLength]; - a = (chunk & 252) >> 2; // 252 = (2^6 - 1) << 2 - // Set the 4 least significant bits to zero - b = (chunk & 3) << 4; // 3 = 2^2 - 1 + a = (chunk & 252) >> 2; + b = (chunk & 3) << 4; base64 += encodings[a] + encodings[b] + '=='; } else if (byteRemainder == 2) { chunk = (bytes[mainLength] << 8) | bytes[mainLength + 1]; - a = (chunk & 64512) >> 10; // 64512 = (2^6 - 1) << 10 - b = (chunk & 1008) >> 4; // 1008 = (2^6 - 1) << 4 - // Set the 2 least significant bits to zero - c = (chunk & 15) << 2; // 15 = 2^4 - 1 + a = (chunk & 64512) >> 10; + b = (chunk & 1008) >> 4; + c = (chunk & 15) << 2; base64 += encodings[a] + encodings[b] + encodings[c] + '='; } return base64; diff --git a/lib/core/components/config.js b/lib/core/components/config.js deleted file mode 100644 index 0b4c6b105..000000000 --- a/lib/core/components/config.js +++ /dev/null @@ -1,209 +0,0 @@ -"use strict"; -/* */ -/* global location */ -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var uuid_1 = __importDefault(require("./uuid")); -var PRESENCE_TIMEOUT_MINIMUM = 20; -var PRESENCE_TIMEOUT_DEFAULT = 300; -var makeDefaultOrigins = function () { return Array.from({ length: 20 }, function (_, i) { return "ps".concat(i + 1, ".pndsn.com"); }); }; -var default_1 = /** @class */ (function () { - function default_1(_a) { - var setup = _a.setup; - var _b, _c, _d, _e; - this._PNSDKSuffix = {}; - this.instanceId = "pn-".concat(uuid_1.default.createUUID()); - this.secretKey = setup.secretKey || setup.secret_key; - this.subscribeKey = setup.subscribeKey || setup.subscribe_key; - this.publishKey = setup.publishKey || setup.publish_key; - this.sdkName = setup.sdkName; - this.sdkFamily = setup.sdkFamily; - this.partnerId = setup.partnerId; - this.setAuthKey(setup.authKey); - this.cryptoModule = setup.cryptoModule; - this.setFilterExpression(setup.filterExpression); - if (typeof setup.origin !== 'string' && !Array.isArray(setup.origin) && setup.origin !== undefined) { - throw new Error('Origin must be either undefined, a string or a list of strings.'); - } - this.origin = setup.origin || makeDefaultOrigins(); - this.secure = setup.ssl || false; - this.restore = setup.restore || false; - this.proxy = setup.proxy; - this.keepAlive = setup.keepAlive; - this.keepAliveSettings = setup.keepAliveSettings; - this.autoNetworkDetection = setup.autoNetworkDetection || false; - this.dedupeOnSubscribe = setup.dedupeOnSubscribe || false; - this.maximumCacheSize = setup.maximumCacheSize || 100; - this.customEncrypt = setup.customEncrypt; - this.customDecrypt = setup.customDecrypt; - this.fileUploadPublishRetryLimit = (_b = setup.fileUploadPublishRetryLimit) !== null && _b !== void 0 ? _b : 5; - this.useRandomIVs = (_c = setup.useRandomIVs) !== null && _c !== void 0 ? _c : true; - this.enableEventEngine = (_d = setup.enableEventEngine) !== null && _d !== void 0 ? _d : false; - this.maintainPresenceState = (_e = setup.maintainPresenceState) !== null && _e !== void 0 ? _e : true; - // if location config exist and we are in https, force secure to true. - if (typeof location !== 'undefined' && location.protocol === 'https:') { - this.secure = true; - } - this.logVerbosity = setup.logVerbosity || false; - this.suppressLeaveEvents = setup.suppressLeaveEvents || false; - this.announceFailedHeartbeats = setup.announceFailedHeartbeats || true; - this.announceSuccessfulHeartbeats = setup.announceSuccessfulHeartbeats || false; - this.useInstanceId = setup.useInstanceId || false; - this.useRequestId = setup.useRequestId || false; - this.requestMessageCountThreshold = setup.requestMessageCountThreshold; - if (setup.retryConfiguration) { - this._setRetryConfiguration(setup.retryConfiguration); - } - // set timeout to how long a transaction request will wait for the server (default 15 seconds) - this.setTransactionTimeout(setup.transactionalRequestTimeout || 15 * 1000); - // set timeout to how long a subscribe event loop will run (default 310 seconds) - this.setSubscribeTimeout(setup.subscribeRequestTimeout || 310 * 1000); - // set config on beacon (https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon) usage - this.setSendBeaconConfig(setup.useSendBeacon || true); - // how long the SDK will report the client to be alive before issuing a timeout - if (setup.presenceTimeout) { - this.setPresenceTimeout(setup.presenceTimeout); - } - else { - this._presenceTimeout = PRESENCE_TIMEOUT_DEFAULT; - } - if (setup.heartbeatInterval != null) { - this.setHeartbeatInterval(setup.heartbeatInterval); - } - if (typeof setup.userId === 'string') { - if (typeof setup.uuid === 'string') { - throw new Error('Only one of the following configuration options has to be provided: `uuid` or `userId`'); - } - this.setUserId(setup.userId); - } - else { - if (typeof setup.uuid !== 'string') { - throw new Error('One of the following configuration options has to be provided: `uuid` or `userId`'); - } - this.setUUID(setup.uuid); - } - this.setCipherKey(setup.cipherKey, setup); - } - // exposed setters - default_1.prototype.getAuthKey = function () { - return this.authKey; - }; - default_1.prototype.setAuthKey = function (val) { - this.authKey = val; - return this; - }; - default_1.prototype.setCipherKey = function (val, setup, modules) { - var _a; - this.cipherKey = val; - if (this.cipherKey) { - this.cryptoModule = - (_a = setup.cryptoModule) !== null && _a !== void 0 ? _a : setup.initCryptoModule({ cipherKey: this.cipherKey, useRandomIVs: this.useRandomIVs }); - if (modules) - modules.cryptoModule = this.cryptoModule; - } - return this; - }; - default_1.prototype.getUUID = function () { - return this.UUID; - }; - default_1.prototype.setUUID = function (val) { - if (!val || typeof val !== 'string' || val.trim().length === 0) { - throw new Error('Missing uuid parameter. Provide a valid string uuid'); - } - this.UUID = val; - return this; - }; - default_1.prototype.getUserId = function () { - return this.UUID; - }; - default_1.prototype.setUserId = function (value) { - if (!value || typeof value !== 'string' || value.trim().length === 0) { - throw new Error('Missing or invalid userId parameter. Provide a valid string userId'); - } - this.UUID = value; - return this; - }; - default_1.prototype.getFilterExpression = function () { - return this.filterExpression; - }; - default_1.prototype.setFilterExpression = function (val) { - this.filterExpression = val; - return this; - }; - default_1.prototype.getPresenceTimeout = function () { - return this._presenceTimeout; - }; - default_1.prototype.setPresenceTimeout = function (val) { - if (val >= PRESENCE_TIMEOUT_MINIMUM) { - this._presenceTimeout = val; - } - else { - this._presenceTimeout = PRESENCE_TIMEOUT_MINIMUM; - // eslint-disable-next-line no-console - console.log('WARNING: Presence timeout is less than the minimum. Using minimum value: ', this._presenceTimeout); - } - this.setHeartbeatInterval(this._presenceTimeout / 2 - 1); - return this; - }; - default_1.prototype.setProxy = function (proxy) { - this.proxy = proxy; - }; - default_1.prototype.getHeartbeatInterval = function () { - return this._heartbeatInterval; - }; - default_1.prototype.setHeartbeatInterval = function (val) { - this._heartbeatInterval = val; - return this; - }; - // deprecated setters. - default_1.prototype.getSubscribeTimeout = function () { - return this._subscribeRequestTimeout; - }; - default_1.prototype.setSubscribeTimeout = function (val) { - this._subscribeRequestTimeout = val; - return this; - }; - default_1.prototype.getTransactionTimeout = function () { - return this._transactionalRequestTimeout; - }; - default_1.prototype.setTransactionTimeout = function (val) { - this._transactionalRequestTimeout = val; - return this; - }; - default_1.prototype.isSendBeaconEnabled = function () { - return this._useSendBeacon; - }; - default_1.prototype.setSendBeaconConfig = function (val) { - this._useSendBeacon = val; - return this; - }; - default_1.prototype.getVersion = function () { - return '7.6.3'; - }; - default_1.prototype._setRetryConfiguration = function (configuration) { - if (configuration.minimumdelay < 2) { - throw new Error('Minimum delay can not be set less than 2 seconds for retry'); - } - if (configuration.maximumDelay > 150) { - throw new Error('Maximum delay can not be set more than 150 seconds for retry'); - } - if (configuration.maximumDelay && maximumRetry > 6) { - throw new Error('Maximum retry for exponential retry policy can not be more than 6'); - } - else if (configuration.maximumRetry > 10) { - throw new Error('Maximum retry for linear retry policy can not be more than 10'); - } - this.retryConfiguration = configuration; - }; - default_1.prototype._addPnsdkSuffix = function (name, suffix) { - this._PNSDKSuffix[name] = suffix; - }; - default_1.prototype._getPnsdkSuffix = function (separator) { - var _this = this; - return Object.keys(this._PNSDKSuffix).reduce(function (result, key) { return result + separator + _this._PNSDKSuffix[key]; }, ''); - }; - return default_1; -}()); -exports.default = default_1; diff --git a/lib/core/components/configuration.js b/lib/core/components/configuration.js new file mode 100644 index 000000000..1b564c93b --- /dev/null +++ b/lib/core/components/configuration.js @@ -0,0 +1,125 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.makeConfiguration = void 0; +const uuid_1 = __importDefault(require("./uuid")); +const USE_RANDOM_INITIALIZATION_VECTOR = true; +const makeConfiguration = (base, setupCryptoModule) => { + var _a, _b, _c; + (_a = base.retryConfiguration) === null || _a === void 0 ? void 0 : _a.validate(); + (_b = base.useRandomIVs) !== null && _b !== void 0 ? _b : (base.useRandomIVs = USE_RANDOM_INITIALIZATION_VECTOR); + base.origin = standardOrigin((_c = base.ssl) !== null && _c !== void 0 ? _c : false, base.origin); + const cryptoModule = base.cryptoModule; + if (cryptoModule) + delete base.cryptoModule; + const clientConfiguration = Object.assign(Object.assign({}, base), { _pnsdkSuffix: {}, _instanceId: `pn-${uuid_1.default.createUUID()}`, _cryptoModule: undefined, _cipherKey: undefined, _setupCryptoModule: setupCryptoModule, get instanceId() { + if (this.useInstanceId) + return this._instanceId; + return undefined; + }, + getUserId() { + return this.userId; + }, + setUserId(value) { + if (!value || typeof value !== 'string' || value.trim().length === 0) + throw new Error('Missing or invalid userId parameter. Provide a valid string userId'); + this.userId = value; + }, + getAuthKey() { + return this.authKey; + }, + setAuthKey(authKey) { + this.authKey = authKey; + }, + getFilterExpression() { + return this.filterExpression; + }, + setFilterExpression(expression) { + this.filterExpression = expression; + }, + getCipherKey() { + return this._cipherKey; + }, + setCipherKey(key) { + this._cipherKey = key; + if (!key && this._cryptoModule) { + this._cryptoModule = undefined; + return; + } + else if (!key || !this._setupCryptoModule) + return; + this._cryptoModule = this._setupCryptoModule({ + cipherKey: key, + useRandomIVs: base.useRandomIVs, + customEncrypt: this.getCustomEncrypt(), + customDecrypt: this.getCustomDecrypt(), + }); + }, + getCryptoModule() { + return this._cryptoModule; + }, + getUseRandomIVs() { + return base.useRandomIVs; + }, + setPresenceTimeout(value) { + this.heartbeatInterval = value / 2 - 1; + this.presenceTimeout = value; + }, + getPresenceTimeout() { + return this.presenceTimeout; + }, + getHeartbeatInterval() { + return this.heartbeatInterval; + }, + setHeartbeatInterval(interval) { + this.heartbeatInterval = interval; + }, + getTransactionTimeout() { + return this.transactionalRequestTimeout; + }, + getSubscribeTimeout() { + return this.subscribeRequestTimeout; + }, + get PubNubFile() { + return base.PubNubFile; + }, + get version() { + return '7.6.3'; + }, + getVersion() { + return this.version; + }, + _addPnsdkSuffix(name, suffix) { + this._pnsdkSuffix[name] = `${suffix}`; + }, + _getPnsdkSuffix(separator) { + const sdk = Object.values(this._pnsdkSuffix).join(separator); + return sdk.length > 0 ? separator + sdk : ''; + }, + getUUID() { + return this.getUserId(); + }, + setUUID(value) { + this.setUserId(value); + }, + getCustomEncrypt() { + return base.customEncrypt; + }, + getCustomDecrypt() { + return base.customDecrypt; + } }); + if (base.cipherKey) + clientConfiguration.setCipherKey(base.cipherKey); + else if (cryptoModule) + clientConfiguration._cryptoModule = cryptoModule; + return clientConfiguration; +}; +exports.makeConfiguration = makeConfiguration; +const standardOrigin = (secure, origin) => { + const protocol = secure ? 'https://' : 'http://'; + if (typeof origin === 'string') + return `${protocol}${origin}`; + return `${protocol}${origin[Math.floor(Math.random() * origin.length)]}`; +}; diff --git a/lib/core/components/cryptography/hmac-sha256.js b/lib/core/components/cryptography/hmac-sha256.js index 4b8616de3..7f5e5716a 100644 --- a/lib/core/components/cryptography/hmac-sha256.js +++ b/lib/core/components/cryptography/hmac-sha256.js @@ -1,11 +1,4 @@ "use strict"; -/*eslint-disable */ -/* - CryptoJS v3.1.2 - code.google.com/p/crypto-js - (c) 2009-2013 by Jeff Mott. All rights reserved. - code.google.com/p/crypto-js/wiki/License - */ var CryptoJS = CryptoJS || (function (h, s) { var f = {}, g = (f.lib = {}), q = function () { }, m = (g.Base = { @@ -177,7 +170,6 @@ var CryptoJS = CryptoJS || var t = (f.algo = {}); return f; })(Math); -// SHA256 (function (h) { for (var s = CryptoJS, f = s.lib, g = f.WordArray, q = f.Hasher, f = s.algo, m = [], r = [], l = function (a) { return (4294967296 * (a - (a | 0))) | 0; @@ -256,7 +248,6 @@ var CryptoJS = CryptoJS || s.SHA256 = q._createHelper(f); s.HmacSHA256 = q._createHmacHelper(f); })(Math); -// HMAC SHA256 (function () { var h = CryptoJS, s = h.enc.Utf8; h.algo.HMAC = h.lib.Base.extend({ @@ -288,7 +279,6 @@ var CryptoJS = CryptoJS || }, }); })(); -// Base64 (function () { var u = CryptoJS, p = u.lib.WordArray; u.enc.Base64 = { @@ -320,7 +310,6 @@ var CryptoJS = CryptoJS || _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=', }; })(); -// BlockCipher (function (u) { function p(b, n, a, c, e, j, k) { b = b + ((n & a) | (~n & c)) + e + k; @@ -401,7 +390,6 @@ var CryptoJS = CryptoJS || return s.create(p).compute(d, l); }; })(); -// Cipher CryptoJS.lib.Cipher || (function (u) { var p = CryptoJS, d = p.lib, l = d.Base, s = d.WordArray, t = d.BufferedBlockAlgorithm, r = p.enc.Base64, w = p.algo.EvpKDF, v = (d.Cipher = t.extend({ @@ -598,7 +586,6 @@ CryptoJS.lib.Cipher || }, })); })(); -// AES (function () { for (var u = CryptoJS, p = u.lib.BlockCipher, d = u.algo, l = [], s = [], t = [], r = [], w = [], v = [], b = [], x = [], q = [], n = [], a = [], c = 0; 256 > c; c++) a[c] = 128 > c ? c << 1 : (c << 1) ^ 283; @@ -669,7 +656,6 @@ CryptoJS.lib.Cipher || })); u.AES = p._createHelper(d); })(); -// Mode ECB CryptoJS.mode.ECB = (function () { var ECB = CryptoJS.lib.BlockCipherMode.extend(); ECB.Encryptor = ECB.extend({ diff --git a/lib/core/components/cryptography/index.js b/lib/core/components/cryptography/index.js index 19c58e51e..434020616 100644 --- a/lib/core/components/cryptography/index.js +++ b/lib/core/components/cryptography/index.js @@ -3,149 +3,136 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -var base64_codec_1 = require("../base64_codec"); -var hmac_sha256_1 = __importDefault(require("./hmac-sha256")); +const base64_codec_1 = require("../base64_codec"); +const hmac_sha256_1 = __importDefault(require("./hmac-sha256")); function bufferToWordArray(b) { - var wa = []; - var i; + const wa = []; + let i; for (i = 0; i < b.length; i += 1) { wa[(i / 4) | 0] |= b[i] << (24 - 8 * i); } return hmac_sha256_1.default.lib.WordArray.create(wa, b.length); } -var default_1 = /** @class */ (function () { - function default_1(_a) { - var config = _a.config; - this._config = config; - this._iv = '0123456789012345'; - this._allowedKeyEncodings = ['hex', 'utf8', 'base64', 'binary']; - this._allowedKeyLengths = [128, 256]; - this._allowedModes = ['ecb', 'cbc']; - this._defaultOptions = { +class default_1 { + constructor(configuration) { + this.configuration = configuration; + this.iv = '0123456789012345'; + this.allowedKeyEncodings = ['hex', 'utf8', 'base64', 'binary']; + this.allowedKeyLengths = [128, 256]; + this.allowedModes = ['ecb', 'cbc']; + this.defaultOptions = { encryptKey: true, keyEncoding: 'utf8', keyLength: 256, mode: 'cbc', }; } - default_1.prototype.HMACSHA256 = function (data) { - var hash = hmac_sha256_1.default.HmacSHA256(data, this._config.secretKey); + HMACSHA256(data) { + const hash = hmac_sha256_1.default.HmacSHA256(data, this.configuration.secretKey); return hash.toString(hmac_sha256_1.default.enc.Base64); - }; - default_1.prototype.SHA256 = function (s) { - return hmac_sha256_1.default.SHA256(s).toString(hmac_sha256_1.default.enc.Hex); - }; - default_1.prototype._parseOptions = function (incomingOptions) { - // Defaults - var options = incomingOptions || {}; - if (!options.hasOwnProperty('encryptKey')) - options.encryptKey = this._defaultOptions.encryptKey; - if (!options.hasOwnProperty('keyEncoding')) - options.keyEncoding = this._defaultOptions.keyEncoding; - if (!options.hasOwnProperty('keyLength')) - options.keyLength = this._defaultOptions.keyLength; - if (!options.hasOwnProperty('mode')) - options.mode = this._defaultOptions.mode; - // Validation - if (this._allowedKeyEncodings.indexOf(options.keyEncoding.toLowerCase()) === -1) { - options.keyEncoding = this._defaultOptions.keyEncoding; - } - if (this._allowedKeyLengths.indexOf(parseInt(options.keyLength, 10)) === -1) { - options.keyLength = this._defaultOptions.keyLength; - } - if (this._allowedModes.indexOf(options.mode.toLowerCase()) === -1) { - options.mode = this._defaultOptions.mode; - } - return options; - }; - default_1.prototype._decodeKey = function (key, options) { - if (options.keyEncoding === 'base64') { - return hmac_sha256_1.default.enc.Base64.parse(key); - } - if (options.keyEncoding === 'hex') { - return hmac_sha256_1.default.enc.Hex.parse(key); - } - return key; - }; - default_1.prototype._getPaddedKey = function (key, options) { - key = this._decodeKey(key, options); - if (options.encryptKey) { - return hmac_sha256_1.default.enc.Utf8.parse(this.SHA256(key).slice(0, 32)); - } - return key; - }; - default_1.prototype._getMode = function (options) { - if (options.mode === 'ecb') { - return hmac_sha256_1.default.mode.ECB; - } - return hmac_sha256_1.default.mode.CBC; - }; - default_1.prototype._getIV = function (options) { - return options.mode === 'cbc' ? hmac_sha256_1.default.enc.Utf8.parse(this._iv) : null; - }; - default_1.prototype._getRandomIV = function () { - return hmac_sha256_1.default.lib.WordArray.random(16); - }; - default_1.prototype.encrypt = function (data, customCipherKey, options) { - if (this._config.customEncrypt) { - return this._config.customEncrypt(data); - } + } + SHA256(data) { + return hmac_sha256_1.default.SHA256(data).toString(hmac_sha256_1.default.enc.Hex); + } + encrypt(data, customCipherKey, options) { + if (this.configuration.customEncrypt) + return this.configuration.customEncrypt(data); return this.pnEncrypt(data, customCipherKey, options); - }; - default_1.prototype.decrypt = function (data, customCipherKey, options) { - if (this._config.customDecrypt) { - return this._config.customDecrypt(data); - } + } + decrypt(data, customCipherKey, options) { + if (this.configuration.customDecrypt) + return this.configuration.customDecrypt(data); return this.pnDecrypt(data, customCipherKey, options); - }; - default_1.prototype.pnEncrypt = function (data, customCipherKey, options) { - if (!customCipherKey && !this._config.cipherKey) + } + pnEncrypt(data, customCipherKey, options) { + const decidedCipherKey = customCipherKey !== null && customCipherKey !== void 0 ? customCipherKey : this.configuration.cipherKey; + if (!decidedCipherKey) return data; - options = this._parseOptions(options); - var mode = this._getMode(options); - var cipherKey = this._getPaddedKey(customCipherKey || this._config.cipherKey, options); - if (this._config.useRandomIVs) { - var waIv = this._getRandomIV(); - var waPayload = hmac_sha256_1.default.AES.encrypt(data, cipherKey, { iv: waIv, mode: mode }).ciphertext; + options = this.parseOptions(options); + const mode = this.getMode(options); + const cipherKey = this.getPaddedKey(decidedCipherKey, options); + if (this.configuration.useRandomIVs) { + const waIv = this.getRandomIV(); + const waPayload = hmac_sha256_1.default.AES.encrypt(data, cipherKey, { iv: waIv, mode }).ciphertext; return waIv.clone().concat(waPayload.clone()).toString(hmac_sha256_1.default.enc.Base64); } - var iv = this._getIV(options); - var encryptedHexArray = hmac_sha256_1.default.AES.encrypt(data, cipherKey, { iv: iv, mode: mode }).ciphertext; - var base64Encrypted = encryptedHexArray.toString(hmac_sha256_1.default.enc.Base64); + const iv = this.getIV(options); + const encryptedHexArray = hmac_sha256_1.default.AES.encrypt(data, cipherKey, { iv, mode }).ciphertext; + const base64Encrypted = encryptedHexArray.toString(hmac_sha256_1.default.enc.Base64); return base64Encrypted || data; - }; - default_1.prototype.pnDecrypt = function (data, customCipherKey, options) { - if (!customCipherKey && !this._config.cipherKey) + } + pnDecrypt(data, customCipherKey, options) { + const decidedCipherKey = customCipherKey !== null && customCipherKey !== void 0 ? customCipherKey : this.configuration.cipherKey; + if (!decidedCipherKey) return data; - options = this._parseOptions(options); - var mode = this._getMode(options); - var cipherKey = this._getPaddedKey(customCipherKey || this._config.cipherKey, options); - if (this._config.useRandomIVs) { - var ciphertext = new Uint8ClampedArray((0, base64_codec_1.decode)(data)); - var iv = bufferToWordArray(ciphertext.slice(0, 16)); - var payload = bufferToWordArray(ciphertext.slice(16)); + options = this.parseOptions(options); + const mode = this.getMode(options); + const cipherKey = this.getPaddedKey(decidedCipherKey, options); + if (this.configuration.useRandomIVs) { + const ciphertext = new Uint8ClampedArray((0, base64_codec_1.decode)(data)); + const iv = bufferToWordArray(ciphertext.slice(0, 16)); + const payload = bufferToWordArray(ciphertext.slice(16)); try { - var plainJSON = hmac_sha256_1.default.AES.decrypt({ ciphertext: payload }, cipherKey, { iv: iv, mode: mode }).toString(hmac_sha256_1.default.enc.Utf8); - var plaintext = JSON.parse(plainJSON); - return plaintext; + const plainJSON = hmac_sha256_1.default.AES.decrypt({ ciphertext: payload }, cipherKey, { iv, mode }).toString(hmac_sha256_1.default.enc.Utf8); + return JSON.parse(plainJSON); } catch (e) { return null; } } else { - var iv = this._getIV(options); + const iv = this.getIV(options); try { - var ciphertext = hmac_sha256_1.default.enc.Base64.parse(data); - var plainJSON = hmac_sha256_1.default.AES.decrypt({ ciphertext: ciphertext }, cipherKey, { iv: iv, mode: mode }).toString(hmac_sha256_1.default.enc.Utf8); - var plaintext = JSON.parse(plainJSON); - return plaintext; + const ciphertext = hmac_sha256_1.default.enc.Base64.parse(data); + const plainJSON = hmac_sha256_1.default.AES.decrypt({ ciphertext }, cipherKey, { iv, mode }).toString(hmac_sha256_1.default.enc.Utf8); + return JSON.parse(plainJSON); } catch (e) { return null; } } - }; - return default_1; -}()); + } + parseOptions(incomingOptions) { + var _a, _b, _c, _d; + if (!incomingOptions) + return this.defaultOptions; + const options = { + encryptKey: (_a = incomingOptions.encryptKey) !== null && _a !== void 0 ? _a : this.defaultOptions.encryptKey, + keyEncoding: (_b = incomingOptions.keyEncoding) !== null && _b !== void 0 ? _b : this.defaultOptions.keyEncoding, + keyLength: (_c = incomingOptions.keyLength) !== null && _c !== void 0 ? _c : this.defaultOptions.keyLength, + mode: (_d = incomingOptions.mode) !== null && _d !== void 0 ? _d : this.defaultOptions.mode, + }; + if (this.allowedKeyEncodings.indexOf(options.keyEncoding.toLowerCase()) === -1) + options.keyEncoding = this.defaultOptions.keyEncoding; + if (this.allowedKeyLengths.indexOf(options.keyLength) === -1) + options.keyLength = this.defaultOptions.keyLength; + if (this.allowedModes.indexOf(options.mode.toLowerCase()) === -1) + options.mode = this.defaultOptions.mode; + return options; + } + decodeKey(key, options) { + if (options.keyEncoding === 'base64') + return hmac_sha256_1.default.enc.Base64.parse(key); + if (options.keyEncoding === 'hex') + return hmac_sha256_1.default.enc.Hex.parse(key); + return key; + } + getPaddedKey(key, options) { + key = this.decodeKey(key, options); + if (options.encryptKey) + return hmac_sha256_1.default.enc.Utf8.parse(this.SHA256(key).slice(0, 32)); + return key; + } + getMode(options) { + if (options.mode === 'ecb') + return hmac_sha256_1.default.mode.ECB; + return hmac_sha256_1.default.mode.CBC; + } + getIV(options) { + return options.mode === 'cbc' ? hmac_sha256_1.default.enc.Utf8.parse(this.iv) : null; + } + getRandomIV() { + return hmac_sha256_1.default.lib.WordArray.random(16); + } +} exports.default = default_1; diff --git a/lib/core/components/deduping_manager.js b/lib/core/components/deduping_manager.js index 6ae413ad0..0f30833c4 100644 --- a/lib/core/components/deduping_manager.js +++ b/lib/core/components/deduping_manager.js @@ -1,40 +1,37 @@ "use strict"; -/* */ Object.defineProperty(exports, "__esModule", { value: true }); -var hashCode = function (payload) { - var hash = 0; +const hashCode = (payload) => { + let hash = 0; if (payload.length === 0) return hash; - for (var i = 0; i < payload.length; i += 1) { - var character = payload.charCodeAt(i); - hash = (hash << 5) - hash + character; // eslint-disable-line - hash = hash & hash; // eslint-disable-line + for (let i = 0; i < payload.length; i += 1) { + const character = payload.charCodeAt(i); + hash = (hash << 5) - hash + character; + hash = hash & hash; } return hash; }; -var default_1 = /** @class */ (function () { - function default_1(_a) { - var config = _a.config; +class default_1 { + constructor({ config }) { this.hashHistory = []; this._config = config; } - default_1.prototype.getKey = function (message) { - var hashedPayload = hashCode(JSON.stringify(message.payload)).toString(); - var timetoken = message.publishMetaData.publishTimetoken; - return "".concat(timetoken, "-").concat(hashedPayload); - }; - default_1.prototype.isDuplicate = function (message) { + getKey(message) { + const hashedPayload = hashCode(JSON.stringify(message.message)).toString(); + const timetoken = message.timetoken; + return `${timetoken}-${hashedPayload}`; + } + isDuplicate(message) { return this.hashHistory.includes(this.getKey(message)); - }; - default_1.prototype.addEntry = function (message) { + } + addEntry(message) { if (this.hashHistory.length >= this._config.maximumCacheSize) { this.hashHistory.shift(); } this.hashHistory.push(this.getKey(message)); - }; - default_1.prototype.clearHistory = function () { + } + clearHistory() { this.hashHistory = []; - }; - return default_1; -}()); + } +} exports.default = default_1; diff --git a/lib/core/components/endpoint.js b/lib/core/components/endpoint.js deleted file mode 100644 index 6c837275f..000000000 --- a/lib/core/components/endpoint.js +++ /dev/null @@ -1,282 +0,0 @@ -"use strict"; -var __extends = (this && this.__extends) || (function () { - 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); - }; - return function (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 = (this && this.__assign) || function () { - __assign = Object.assign || function(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); -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.signRequest = exports.generatePNSDK = exports.createValidationError = exports.PubNubError = void 0; -var uuid_1 = __importDefault(require("./uuid")); -var utils_1 = __importDefault(require("../utils")); -var operations_1 = __importDefault(require("../constants/operations")); -var categories_1 = __importDefault(require("../constants/categories")); -var PubNubError = /** @class */ (function (_super) { - __extends(PubNubError, _super); - function PubNubError(message, status) { - var _newTarget = this.constructor; - var _this = _super.call(this, message) || this; - _this.name = _this.constructor.name; - _this.status = status; - _this.message = message; - Object.setPrototypeOf(_this, _newTarget.prototype); - return _this; - } - return PubNubError; -}(Error)); -exports.PubNubError = PubNubError; -function createError(errorPayload, type) { - errorPayload.type = type; - errorPayload.error = true; - return errorPayload; -} -function createValidationError(message) { - return createError({ message: message }, 'validationError'); -} -exports.createValidationError = createValidationError; -function decideURL(endpoint, modules, incomingParams) { - if (endpoint.usePost && endpoint.usePost(modules, incomingParams)) { - return endpoint.postURL(modules, incomingParams); - } - if (endpoint.usePatch && endpoint.usePatch(modules, incomingParams)) { - return endpoint.patchURL(modules, incomingParams); - } - if (endpoint.useGetFile && endpoint.useGetFile(modules, incomingParams)) { - return endpoint.getFileURL(modules, incomingParams); - } - return endpoint.getURL(modules, incomingParams); -} -function generatePNSDK(config) { - if (config.sdkName) { - return config.sdkName; - } - var base = "PubNub-JS-".concat(config.sdkFamily); - if (config.partnerId) { - base += "-".concat(config.partnerId); - } - base += "/".concat(config.getVersion()); - var pnsdkSuffix = config._getPnsdkSuffix(' '); - if (pnsdkSuffix.length > 0) { - base += pnsdkSuffix; - } - return base; -} -exports.generatePNSDK = generatePNSDK; -function getHttpMethod(modules, endpoint, incomingParams) { - if (endpoint.usePost && endpoint.usePost(modules, incomingParams)) { - return 'POST'; - } - if (endpoint.usePatch && endpoint.usePatch(modules, incomingParams)) { - return 'PATCH'; - } - if (endpoint.useDelete && endpoint.useDelete(modules, incomingParams)) { - return 'DELETE'; - } - if (endpoint.useGetFile && endpoint.useGetFile(modules, incomingParams)) { - return 'GETFILE'; - } - return 'GET'; -} -function signRequest(modules, url, outgoingParams, incomingParams, endpoint) { - var config = modules.config, crypto = modules.crypto; - var httpMethod = getHttpMethod(modules, endpoint, incomingParams); - outgoingParams.timestamp = Math.floor(new Date().getTime() / 1000); - // This is because of a server-side bug, old publish using post should be deprecated - if (endpoint.getOperation() === 'PNPublishOperation' && - endpoint.usePost && - endpoint.usePost(modules, incomingParams)) { - httpMethod = 'GET'; - } - if (httpMethod === 'GETFILE') { - httpMethod = 'GET'; - } - var signInput = "".concat(httpMethod, "\n").concat(config.publishKey, "\n").concat(url, "\n").concat(utils_1.default.signPamFromParams(outgoingParams), "\n"); - if (httpMethod === 'POST') { - var payload = endpoint.postPayload(modules, incomingParams); - if (typeof payload === 'string') { - signInput += payload; - } - else { - signInput += JSON.stringify(payload); - } - } - else if (httpMethod === 'PATCH') { - var payload = endpoint.patchPayload(modules, incomingParams); - if (typeof payload === 'string') { - signInput += payload; - } - else { - signInput += JSON.stringify(payload); - } - } - var signature = "v2.".concat(crypto.HMACSHA256(signInput)); - signature = signature.replace(/\+/g, '-'); - signature = signature.replace(/\//g, '_'); - signature = signature.replace(/=+$/, ''); - outgoingParams.signature = signature; -} -exports.signRequest = signRequest; -function default_1(modules, endpoint) { - var args = []; - for (var _i = 2; _i < arguments.length; _i++) { - args[_i - 2] = arguments[_i]; - } - var networking = modules.networking, config = modules.config, telemetryManager = modules.telemetryManager, tokenManager = modules.tokenManager; - var requestId = uuid_1.default.createUUID(); - var callback = null; - var promiseComponent = null; - var incomingParams = {}; - if (endpoint.getOperation() === operations_1.default.PNTimeOperation || - endpoint.getOperation() === operations_1.default.PNChannelGroupsOperation) { - callback = args[0]; - } - else { - incomingParams = args[0]; - callback = args[1]; - } - // bridge in Promise support. - if (typeof Promise !== 'undefined' && !callback) { - promiseComponent = utils_1.default.createPromise(); - } - var validationResult = endpoint.validateParams(modules, incomingParams); - if (validationResult) { - if (callback) { - return callback(createValidationError(validationResult)); - } - if (promiseComponent) { - promiseComponent.reject(new PubNubError('Validation failed, check status for details', createValidationError(validationResult))); - return promiseComponent.promise; - } - return; - } - var outgoingParams = endpoint.prepareParams(modules, incomingParams); - var url = decideURL(endpoint, modules, incomingParams); - var callInstance; - var networkingParams = { - url: url, - operation: endpoint.getOperation(), - timeout: endpoint.getRequestTimeout(modules), - headers: endpoint.getRequestHeaders ? endpoint.getRequestHeaders() : {}, - ignoreBody: typeof endpoint.ignoreBody === 'function' ? endpoint.ignoreBody(modules) : false, - forceBuffered: typeof endpoint.forceBuffered === 'function' ? endpoint.forceBuffered(modules, incomingParams) : null, - abortSignal: typeof endpoint.getAbortSignal === 'function' ? endpoint.getAbortSignal(modules, incomingParams) : null, - }; - outgoingParams.uuid = config.UUID; - outgoingParams.pnsdk = generatePNSDK(config); - // Add telemetry information (if there is any available). - var telemetryLatencies = telemetryManager.operationsLatencyForRequest(); - if (Object.keys(telemetryLatencies).length) { - outgoingParams = __assign(__assign({}, outgoingParams), telemetryLatencies); - } - if (config.useInstanceId) { - outgoingParams.instanceid = config.instanceId; - } - if (config.useRequestId) { - outgoingParams.requestid = requestId; - } - if (endpoint.isAuthSupported()) { - var tokenOrKey = tokenManager.getToken() || config.getAuthKey(); - if (tokenOrKey) { - outgoingParams.auth = tokenOrKey; - } - } - if (config.secretKey) { - signRequest(modules, url, outgoingParams, incomingParams, endpoint); - } - var onResponse = function (status, payload) { - if (status.error) { - if (endpoint.handleError) { - endpoint.handleError(modules, incomingParams, status); - } - if (callback) { - callback(status); - } - else if (promiseComponent) { - promiseComponent.reject(new PubNubError('PubNub call failed, check status for details', status)); - } - return; - } - // Stop endpoint latency tracking. - telemetryManager.stopLatencyMeasure(endpoint.getOperation(), requestId); - var responseP = endpoint.handleResponse(modules, payload, incomingParams); - if (typeof (responseP === null || responseP === void 0 ? void 0 : responseP.then) !== 'function') { - responseP = Promise.resolve(responseP); - } - responseP - .then(function (result) { - if (callback) { - callback(status, result); - } - else if (promiseComponent) { - promiseComponent.fulfill(result); - } - }) - .catch(function (e) { - if (callback) { - var errorData = e; - if (endpoint.getOperation() === operations_1.default.PNSubscribeOperation) { - errorData = { - statusCode: 400, - error: true, - operation: endpoint.getOperation(), - errorData: e, - category: categories_1.default.PNUnknownCategory, - }; - } - callback(errorData, null); - } - else if (promiseComponent) { - promiseComponent.reject(new PubNubError('PubNub call failed, check status for details', e)); - } - }); - }; - // Start endpoint latency tracking. - telemetryManager.startLatencyMeasure(endpoint.getOperation(), requestId); - if (getHttpMethod(modules, endpoint, incomingParams) === 'POST') { - var payload = endpoint.postPayload(modules, incomingParams); - callInstance = networking.POST(outgoingParams, payload, networkingParams, onResponse); - } - else if (getHttpMethod(modules, endpoint, incomingParams) === 'PATCH') { - var payload = endpoint.patchPayload(modules, incomingParams); - callInstance = networking.PATCH(outgoingParams, payload, networkingParams, onResponse); - } - else if (getHttpMethod(modules, endpoint, incomingParams) === 'DELETE') { - callInstance = networking.DELETE(outgoingParams, networkingParams, onResponse); - } - else if (getHttpMethod(modules, endpoint, incomingParams) === 'GETFILE') { - callInstance = networking.GETFILE(outgoingParams, networkingParams, onResponse); - } - else { - callInstance = networking.GET(outgoingParams, networkingParams, onResponse); - } - if (endpoint.getOperation() === operations_1.default.PNSubscribeOperation) { - return callInstance; - } - if (promiseComponent) { - return promiseComponent.promise; - } -} -exports.default = default_1; diff --git a/lib/core/components/eventEmitter.js b/lib/core/components/eventEmitter.js index c75d9c60d..f843210ca 100644 --- a/lib/core/components/eventEmitter.js +++ b/lib/core/components/eventEmitter.js @@ -1,15 +1,4 @@ "use strict"; -var __assign = (this && this.__assign) || function () { - __assign = Object.assign || function(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); -}; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) @@ -22,263 +11,123 @@ var __rest = (this && this.__rest) || function (s, e) { return t; }; Object.defineProperty(exports, "__esModule", { value: true }); -var EventEmitter = /** @class */ (function () { - function EventEmitter(_a) { - var modules = _a.modules, listenerManager = _a.listenerManager, getFileUrl = _a.getFileUrl; - this.modules = modules; +const subscribe_1 = require("../endpoints/subscribe"); +class EventEmitter { + constructor(listenerManager) { this.listenerManager = listenerManager; - this.getFileUrl = getFileUrl; - this._channelListenerMap = new Map(); - this._groupListenerMap = new Map(); - if (modules.cryptoModule) - this._decoder = new TextDecoder(); + this.channelListenerMap = new Map(); + this.groupListenerMap = new Map(); } - EventEmitter.prototype.emitEvent = function (e) { - var channel = e.channel, publishMetaData = e.publishMetaData; - var subscriptionMatch = e.subscriptionMatch; - if (channel === subscriptionMatch) { - subscriptionMatch = null; + emitEvent(event) { + if (event.type === subscribe_1.PubNubEventType.Message) { + this.listenerManager.announceMessage(event.data); + this.announce('message', event.data, event.data.channel, event.data.subscription); } - if (e.channel.endsWith('-pnpres')) { - var announce = {}; - announce.channel = null; - announce.subscription = null; - if (channel) { - announce.channel = channel.substring(0, channel.lastIndexOf('-pnpres')); - } - if (subscriptionMatch) { - announce.subscription = subscriptionMatch.substring(0, subscriptionMatch.lastIndexOf('-pnpres')); - } - announce.action = e.payload.action; - announce.state = e.payload.data; - announce.timetoken = publishMetaData.timetoken; - announce.occupancy = e.payload.occupancy; - announce.uuid = e.payload.uuid; - announce.timestamp = e.payload.timestamp; - if (e.payload.join) { - announce.join = e.payload.join; - } - if (e.payload.leave) { - announce.leave = e.payload.leave; - } - if (e.payload.timeout) { - announce.timeout = e.payload.timeout; - } - // deprecated --> - announce.actualChannel = subscriptionMatch != null ? channel : null; - announce.subscribedChannel = subscriptionMatch != null ? subscriptionMatch : channel; - // <-- deprecated - this.listenerManager.announcePresence(announce); - this._announce('presence', announce, announce.channel, announce.subscription); + else if (event.type === subscribe_1.PubNubEventType.Signal) { + this.listenerManager.announceSignal(event.data); + this.announce('signal', event.data, event.data.channel, event.data.subscription); } - else if (e.messageType === 1) { - var announce = {}; - announce.channel = null; - announce.subscription = null; - announce.channel = channel; - announce.subscription = subscriptionMatch; - announce.timetoken = publishMetaData.timetoken; - announce.publisher = e.issuingClientId; - if (e.userMetadata) { - announce.userMetadata = e.userMetadata; - } - announce.message = e.payload; - this.listenerManager.announceSignal(announce); - this._announce('signal', announce, announce.channel, announce.subscription); + else if (event.type === subscribe_1.PubNubEventType.Presence) { + this.listenerManager.announcePresence(event.data); + this.announce('presence', event.data, event.data.channel, event.data.subscription); } - else if (e.messageType === 2) { - var announce = {}; - announce.channel = null; - announce.subscription = null; - announce.channel = channel; - announce.subscription = subscriptionMatch; - announce.timetoken = publishMetaData.timetoken; - announce.publisher = e.issuingClientId; - if (e.userMetadata) { - announce.userMetadata = e.userMetadata; - } - announce.message = { - event: e.payload.event, - type: e.payload.type, - data: e.payload.data, - }; - this.listenerManager.announceObjects(announce); - this._announce('objects', announce, announce.channel, announce.subscription); - if (e.payload.type === 'uuid') { - var eventData = this._renameChannelField(announce); - var userEvent = __assign(__assign({}, eventData), { message: __assign(__assign({}, eventData.message), { event: this._renameEvent(eventData.message.event), type: 'user' }) }); + else if (event.type === subscribe_1.PubNubEventType.AppContext) { + const { data: objectEvent } = event; + const { message: object } = objectEvent; + this.listenerManager.announceObjects(objectEvent); + this.announce('objects', objectEvent, objectEvent.channel, objectEvent.subscription); + if (object.type === 'uuid') { + const { message, channel } = objectEvent, restEvent = __rest(objectEvent, ["message", "channel"]); + const { event, type } = object, restObject = __rest(object, ["event", "type"]); + const userEvent = Object.assign(Object.assign({}, restEvent), { spaceId: channel, message: Object.assign(Object.assign({}, restObject), { event: event === 'set' ? 'updated' : 'removed', type: 'user' }) }); this.listenerManager.announceUser(userEvent); - this._announce('user', userEvent, announce.channel, announce.subscription); + this.announce('user', userEvent, userEvent.spaceId, userEvent.subscription); } - else if (e.payload.type === 'channel') { - var eventData = this._renameChannelField(announce); - var spaceEvent = __assign(__assign({}, eventData), { message: __assign(__assign({}, eventData.message), { event: this._renameEvent(eventData.message.event), type: 'space' }) }); + else if (object.type === 'channel') { + const { message, channel } = objectEvent, restEvent = __rest(objectEvent, ["message", "channel"]); + const { event, type } = object, restObject = __rest(object, ["event", "type"]); + const spaceEvent = Object.assign(Object.assign({}, restEvent), { spaceId: channel, message: Object.assign(Object.assign({}, restObject), { event: event === 'set' ? 'updated' : 'removed', type: 'space' }) }); this.listenerManager.announceSpace(spaceEvent); - this._announce('space', spaceEvent, announce.channel, announce.subscription); + this.announce('space', spaceEvent, spaceEvent.spaceId, spaceEvent.subscription); } - else if (e.payload.type === 'membership') { - var eventData = this._renameChannelField(announce); - var _a = eventData.message.data, user = _a.uuid, space = _a.channel, membershipData = __rest(_a, ["uuid", "channel"]); - membershipData.user = user; - membershipData.space = space; - var membershipEvent = __assign(__assign({}, eventData), { message: __assign(__assign({}, eventData.message), { event: this._renameEvent(eventData.message.event), data: membershipData }) }); + else if (object.type === 'membership') { + const { message, channel } = objectEvent, restEvent = __rest(objectEvent, ["message", "channel"]); + const { event, data } = object, restObject = __rest(object, ["event", "data"]); + const { uuid, channel: channelMeta } = data, restData = __rest(data, ["uuid", "channel"]); + const membershipEvent = Object.assign(Object.assign({}, restEvent), { spaceId: channel, message: Object.assign(Object.assign({}, restObject), { event: event === 'set' ? 'updated' : 'removed', data: Object.assign(Object.assign({}, restData), { user: uuid, space: channelMeta }) }) }); this.listenerManager.announceMembership(membershipEvent); - this._announce('membership', membershipEvent, announce.channel, announce.subscription); + this.announce('membership', membershipEvent, membershipEvent.spaceId, membershipEvent.subscription); } } - else if (e.messageType === 3) { - var announce = {}; - announce.channel = channel; - announce.subscription = subscriptionMatch; - announce.timetoken = publishMetaData.timetoken; - announce.publisher = e.issuingClientId; - announce.data = { - messageTimetoken: e.payload.data.messageTimetoken, - actionTimetoken: e.payload.data.actionTimetoken, - type: e.payload.data.type, - uuid: e.issuingClientId, - value: e.payload.data.value, - }; - announce.event = e.payload.event; - this.listenerManager.announceMessageAction(announce); - this._announce('messageAction', announce, announce.channel, announce.subscription); + else if (event.type === subscribe_1.PubNubEventType.MessageAction) { + this.listenerManager.announceMessageAction(event.data); + this.announce('messageAction', event.data, event.data.channel, event.data.subscription); } - else if (e.messageType === 4) { - var announce = {}; - announce.channel = channel; - announce.subscription = subscriptionMatch; - announce.timetoken = publishMetaData.timetoken; - announce.publisher = e.issuingClientId; - var msgPayload = e.payload; - if (this.modules.cryptoModule) { - var decryptedPayload = void 0; - try { - var decryptedData = this.modules.cryptoModule.decrypt(e.payload); - decryptedPayload = - decryptedData instanceof ArrayBuffer ? JSON.parse(this._decoder.decode(decryptedData)) : decryptedData; - } - catch (e) { - decryptedPayload = null; - announce.error = "Error while decrypting message content: ".concat(e.message); - } - if (decryptedPayload !== null) { - msgPayload = decryptedPayload; - } - } - if (e.userMetadata) { - announce.userMetadata = e.userMetadata; - } - announce.message = msgPayload.message; - announce.file = { - id: msgPayload.file.id, - name: msgPayload.file.name, - url: this.getFileUrl({ - id: msgPayload.file.id, - name: msgPayload.file.name, - channel: channel, - }), - }; - this.listenerManager.announceFile(announce); - this._announce('file', announce, announce.channel, announce.subscription); - } - else { - var announce = {}; - announce.channel = null; - announce.subscription = null; - announce.channel = channel; - announce.subscription = subscriptionMatch; - announce.timetoken = publishMetaData.timetoken; - announce.publisher = e.issuingClientId; - if (e.userMetadata) { - announce.userMetadata = e.userMetadata; - } - if (this.modules.cryptoModule) { - var decryptedPayload = void 0; - try { - var decryptedData = this.modules.cryptoModule.decrypt(e.payload); - decryptedPayload = - decryptedData instanceof ArrayBuffer ? JSON.parse(this._decoder.decode(decryptedData)) : decryptedData; - } - catch (e) { - decryptedPayload = null; - announce.error = "Error while decrypting message content: ".concat(e.message); - } - if (decryptedPayload != null) { - announce.message = decryptedPayload; - } - else { - announce.message = e.payload; - } - } - else { - announce.message = e.payload; - } - // deprecated --> - announce.actualChannel = subscriptionMatch != null ? channel : null; - announce.subscribedChannel = subscriptionMatch != null ? subscriptionMatch : channel; - // <-- deprecated - this.listenerManager.announceMessage(announce); - this._announce('message', announce, announce.channel, announce.subscription); + else if (event.type === subscribe_1.PubNubEventType.Files) { + this.listenerManager.announceFile(event.data); + this.announce('file', event.data, event.data.channel, event.data.subscription); } - }; - EventEmitter.prototype.addListener = function (l, channels, groups) { - var _this = this; + } + addListener(listener, channels, groups) { if (!(channels && groups)) { - this.listenerManager.addListener(l); + this.listenerManager.addListener(listener); } else { - channels === null || channels === void 0 ? void 0 : channels.forEach(function (c) { - if (_this._channelListenerMap[c]) { - if (!_this._channelListenerMap[c].includes(l)) - _this._channelListenerMap[c].push(l); - } - else { - _this._channelListenerMap[c] = [l]; + channels === null || channels === void 0 ? void 0 : channels.forEach((channel) => { + if (this.channelListenerMap.has(channel)) { + const channelListeners = this.channelListenerMap.get(channel); + if (!channelListeners.includes(listener)) + channelListeners.push(listener); } + else + this.channelListenerMap.set(channel, [listener]); }); - groups === null || groups === void 0 ? void 0 : groups.forEach(function (g) { - if (_this._groupListenerMap[g]) { - if (!_this._groupListenerMap[g].includes(l)) - _this._groupListenerMap[g].push(l); - } - else { - _this._groupListenerMap[g] = [l]; + groups === null || groups === void 0 ? void 0 : groups.forEach((group) => { + if (this.groupListenerMap.has(group)) { + const groupListeners = this.groupListenerMap.get(group); + if (!groupListeners.includes(listener)) + groupListeners.push(listener); } + else + this.groupListenerMap.set(group, [listener]); }); } - }; - EventEmitter.prototype.removeListener = function (listener, channels, groups) { - var _this = this; + } + removeListener(listener, channels, groups) { if (!(channels && groups)) { this.listenerManager.removeListener(listener); } else { - channels === null || channels === void 0 ? void 0 : channels.forEach(function (c) { - var _a; - _this._channelListenerMap[c] = (_a = _this._channelListenerMap[c]) === null || _a === void 0 ? void 0 : _a.filter(function (l) { return l !== listener; }); + channels === null || channels === void 0 ? void 0 : channels.forEach((channel) => { + if (this.channelListenerMap.has(channel)) { + this.channelListenerMap.set(channel, this.channelListenerMap.get(channel).filter((channelListener) => channelListener !== listener)); + } }); - groups === null || groups === void 0 ? void 0 : groups.forEach(function (g) { - var _a; - _this._groupListenerMap[g] = (_a = _this._groupListenerMap[g]) === null || _a === void 0 ? void 0 : _a.filter(function (l) { return l !== listener; }); + groups === null || groups === void 0 ? void 0 : groups.forEach((group) => { + if (this.groupListenerMap.has(group)) { + this.groupListenerMap.set(group, this.groupListenerMap.get(group).filter((groupListener) => groupListener !== listener)); + } }); } - }; - EventEmitter.prototype.removeAllListeners = function () { + } + removeAllListeners() { this.listenerManager.removeAllListeners(); - }; - EventEmitter.prototype._renameEvent = function (e) { - return e === 'set' ? 'updated' : 'removed'; - }; - EventEmitter.prototype._renameChannelField = function (announce) { - var channel = announce.channel, eventData = __rest(announce, ["channel"]); - eventData.spaceId = channel; - return eventData; - }; - EventEmitter.prototype._announce = function (type, event, channel, group) { - var _a, _b; - (_a = this._channelListenerMap[channel]) === null || _a === void 0 ? void 0 : _a.forEach(function (l) { return l[type] && l[type](event); }); - (_b = this._groupListenerMap[group]) === null || _b === void 0 ? void 0 : _b.forEach(function (l) { return l[type] && l[type](event); }); - }; - return EventEmitter; -}()); + this.channelListenerMap.clear(); + this.groupListenerMap.clear(); + } + announce(type, event, channel, group) { + if (event && this.channelListenerMap.has(channel)) + this.channelListenerMap.get(channel).forEach((listener) => { + const typedListener = listener[type]; + if (typedListener) + typedListener(event); + }); + if (group && this.groupListenerMap.has(group)) + this.groupListenerMap.get(group).forEach((listener) => { + const typedListener = listener[type]; + if (typedListener) + typedListener(event); + }); + } +} exports.default = EventEmitter; diff --git a/lib/core/components/listener_manager.js b/lib/core/components/listener_manager.js index 9518fb550..37778be75 100644 --- a/lib/core/components/listener_manager.js +++ b/lib/core/components/listener_manager.js @@ -3,98 +3,100 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -var categories_1 = __importDefault(require("../constants/categories")); -var default_1 = /** @class */ (function () { - function default_1() { - this._listeners = []; +exports.ListenerManager = void 0; +const categories_1 = __importDefault(require("../constants/categories")); +class ListenerManager { + constructor() { + this.listeners = []; } - default_1.prototype.addListener = function (newListener) { - if (this._listeners.includes(newListener)) { + addListener(listener) { + if (this.listeners.includes(listener)) return; - } - this._listeners.push(newListener); - }; - default_1.prototype.removeListener = function (deprecatedListener) { - var newListeners = []; - this._listeners.forEach(function (listener) { - if (listener !== deprecatedListener) - newListeners.push(listener); + this.listeners.push(listener); + } + removeListener(listener) { + this.listeners = this.listeners.filter((storedListener) => storedListener !== listener); + } + removeAllListeners() { + this.listeners = []; + } + announceStatus(status) { + this.listeners.forEach((listener) => { + if (listener.status) + listener.status(status); }); - this._listeners = newListeners; - }; - default_1.prototype.removeAllListeners = function () { - this._listeners = []; - }; - default_1.prototype.announcePresence = function (announce) { - this._listeners.forEach(function (listener) { + } + announcePresence(presence) { + this.listeners.forEach((listener) => { if (listener.presence) - listener.presence(announce); + listener.presence(presence); }); - }; - default_1.prototype.announceStatus = function (announce) { - this._listeners.forEach(function (listener) { - if (listener.status) - listener.status(announce); - }); - }; - default_1.prototype.announceMessage = function (announce) { - this._listeners.forEach(function (listener) { + } + announceMessage(message) { + this.listeners.forEach((listener) => { if (listener.message) - listener.message(announce); + listener.message(message); }); - }; - default_1.prototype.announceSignal = function (announce) { - this._listeners.forEach(function (listener) { + } + announceSignal(signal) { + this.listeners.forEach((listener) => { if (listener.signal) - listener.signal(announce); + listener.signal(signal); }); - }; - default_1.prototype.announceMessageAction = function (announce) { - this._listeners.forEach(function (listener) { + } + announceMessageAction(messageAction) { + this.listeners.forEach((listener) => { if (listener.messageAction) - listener.messageAction(announce); + listener.messageAction(messageAction); }); - }; - default_1.prototype.announceFile = function (announce) { - this._listeners.forEach(function (listener) { + } + announceFile(file) { + this.listeners.forEach((listener) => { if (listener.file) - listener.file(announce); + listener.file(file); }); - }; - default_1.prototype.announceObjects = function (announce) { - this._listeners.forEach(function (listener) { + } + announceObjects(object) { + this.listeners.forEach((listener) => { if (listener.objects) - listener.objects(announce); + listener.objects(object); + }); + } + announceNetworkUp() { + this.listeners.forEach((listener) => { + if (listener.status) { + listener.status({ + category: categories_1.default.PNNetworkUpCategory, + }); + } + }); + } + announceNetworkDown() { + this.listeners.forEach((listener) => { + if (listener.status) { + listener.status({ + category: categories_1.default.PNNetworkDownCategory, + }); + } }); - }; - default_1.prototype.announceUser = function (announce) { - this._listeners.forEach(function (listener) { + } + announceUser(user) { + this.listeners.forEach((listener) => { if (listener.user) - listener.user(announce); + listener.user(user); }); - }; - default_1.prototype.announceSpace = function (announce) { - this._listeners.forEach(function (listener) { + } + announceSpace(space) { + this.listeners.forEach((listener) => { if (listener.space) - listener.space(announce); + listener.space(space); }); - }; - default_1.prototype.announceMembership = function (announce) { - this._listeners.forEach(function (listener) { + } + announceMembership(membership) { + this.listeners.forEach((listener) => { if (listener.membership) - listener.membership(announce); + listener.membership(membership); }); - }; - default_1.prototype.announceNetworkUp = function () { - var networkStatus = {}; - networkStatus.category = categories_1.default.PNNetworkUpCategory; - this.announceStatus(networkStatus); - }; - default_1.prototype.announceNetworkDown = function () { - var networkStatus = {}; - networkStatus.category = categories_1.default.PNNetworkDownCategory; - this.announceStatus(networkStatus); - }; - return default_1; -}()); -exports.default = default_1; + } +} +exports.ListenerManager = ListenerManager; diff --git a/lib/core/components/push_payload.js b/lib/core/components/push_payload.js index a35eb6aeb..e2196cd9b 100644 --- a/lib/core/components/push_payload.js +++ b/lib/core/components/push_payload.js @@ -1,32 +1,4 @@ "use strict"; -/* */ -/* eslint max-classes-per-file: ["error", 5] */ -var __extends = (this && this.__extends) || (function () { - 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); - }; - return function (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 = (this && this.__assign) || function () { - __assign = Object.assign || function(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); -}; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) @@ -39,560 +11,296 @@ var __rest = (this && this.__rest) || function (s, e) { return t; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.FCMNotificationPayload = exports.MPNSNotificationPayload = exports.APNSNotificationPayload = void 0; -var BaseNotificationPayload = /** @class */ (function () { - function BaseNotificationPayload(payload, title, body) { +exports.FCMNotificationPayload = exports.APNSNotificationPayload = void 0; +class BaseNotificationPayload { + constructor(payload, title, body) { this._payload = payload; - this._setDefaultPayloadStructure(); + this.setDefaultPayloadStructure(); this.title = title; this.body = body; } - Object.defineProperty(BaseNotificationPayload.prototype, "payload", { - get: function () { - return this._payload; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(BaseNotificationPayload.prototype, "title", { - set: function (value) { - this._title = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(BaseNotificationPayload.prototype, "subtitle", { - set: function (value) { - this._subtitle = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(BaseNotificationPayload.prototype, "body", { - set: function (value) { - this._body = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(BaseNotificationPayload.prototype, "badge", { - set: function (value) { - this._badge = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(BaseNotificationPayload.prototype, "sound", { - set: function (value) { - this._sound = value; - }, - enumerable: false, - configurable: true - }); - BaseNotificationPayload.prototype._setDefaultPayloadStructure = function () { - // Empty. - }; - BaseNotificationPayload.prototype.toObject = function () { + get payload() { + return this._payload; + } + set title(value) { + this._title = value; + } + set subtitle(value) { + this._subtitle = value; + } + set body(value) { + this._body = value; + } + set badge(value) { + this._badge = value; + } + set sound(value) { + this._sound = value; + } + setDefaultPayloadStructure() { } + toObject() { return {}; - }; - return BaseNotificationPayload; -}()); -var APNSNotificationPayload = /** @class */ (function (_super) { - __extends(APNSNotificationPayload, _super); - function APNSNotificationPayload() { - return _super !== null && _super.apply(this, arguments) || this; - } - Object.defineProperty(APNSNotificationPayload.prototype, "configurations", { - set: function (value) { - if (!value || !value.length) - return; - this._configurations = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(APNSNotificationPayload.prototype, "notification", { - get: function () { - return this._payload.aps; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(APNSNotificationPayload.prototype, "title", { - get: function () { - return this._title; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.aps.alert.title = value; - this._title = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(APNSNotificationPayload.prototype, "subtitle", { - get: function () { - return this._subtitle; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.aps.alert.subtitle = value; - this._subtitle = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(APNSNotificationPayload.prototype, "body", { - get: function () { - return this._body; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.aps.alert.body = value; - this._body = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(APNSNotificationPayload.prototype, "badge", { - get: function () { - return this._badge; - }, - set: function (value) { - if (value === undefined || value === null) - return; - this._payload.aps.badge = value; - this._badge = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(APNSNotificationPayload.prototype, "sound", { - get: function () { - return this._sound; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.aps.sound = value; - this._sound = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(APNSNotificationPayload.prototype, "silent", { - set: function (value) { - this._isSilent = value; - }, - enumerable: false, - configurable: true - }); - APNSNotificationPayload.prototype._setDefaultPayloadStructure = function () { - this._payload.aps = { alert: {} }; - }; - APNSNotificationPayload.prototype.toObject = function () { - var _this = this; - var payload = __assign({}, this._payload); - /** @type {{alert: Object, badge: number, sound: string}} */ - var aps = payload.aps; - var alert = aps.alert; - if (this._isSilent) { + } +} +class APNSNotificationPayload extends BaseNotificationPayload { + constructor() { + super(...arguments); + this._apnsPushType = 'apns'; + this._isSilent = false; + } + get payload() { + return this._payload; + } + set configurations(value) { + if (!value || !value.length) + return; + this._configurations = value; + } + get notification() { + return this.payload.aps; + } + get title() { + return this._title; + } + set title(value) { + if (!value || !value.length) + return; + this.payload.aps.alert.title = value; + this._title = value; + } + get subtitle() { + return this._subtitle; + } + set subtitle(value) { + if (!value || !value.length) + return; + this.payload.aps.alert.subtitle = value; + this._subtitle = value; + } + get body() { + return this._body; + } + set body(value) { + if (!value || !value.length) + return; + this.payload.aps.alert.body = value; + this._body = value; + } + get badge() { + return this._badge; + } + set badge(value) { + if (value === undefined || value === null) + return; + this.payload.aps.badge = value; + this._badge = value; + } + get sound() { + return this._sound; + } + set sound(value) { + if (!value || !value.length) + return; + this.payload.aps.sound = value; + this._sound = value; + } + set silent(value) { + this._isSilent = value; + } + setDefaultPayloadStructure() { + this.payload.aps = { alert: {} }; + } + toObject() { + const payload = Object.assign({}, this.payload); + const { aps } = payload; + let { alert } = aps; + if (this._isSilent) aps['content-available'] = 1; - } if (this._apnsPushType === 'apns2') { - if (!this._configurations || !this._configurations.length) { + if (!this._configurations || !this._configurations.length) throw new ReferenceError('APNS2 configuration is missing'); - } - var configurations_1 = []; - this._configurations.forEach(function (configuration) { - configurations_1.push(_this._objectFromAPNS2Configuration(configuration)); + const configurations = []; + this._configurations.forEach((configuration) => { + configurations.push(this.objectFromAPNS2Configuration(configuration)); }); - if (configurations_1.length) { - payload.pn_push = configurations_1; - } + if (configurations.length) + payload.pn_push = configurations; } - if (!alert || !Object.keys(alert).length) { + if (!alert || !Object.keys(alert).length) delete aps.alert; - } if (this._isSilent) { delete aps.alert; delete aps.badge; delete aps.sound; alert = {}; } - return this._isSilent || Object.keys(alert).length ? payload : null; - }; - APNSNotificationPayload.prototype._objectFromAPNS2Configuration = function (configuration) { - var _this = this; - if (!configuration.targets || !configuration.targets.length) { + return this._isSilent || (alert && Object.keys(alert).length) ? payload : null; + } + objectFromAPNS2Configuration(configuration) { + if (!configuration.targets || !configuration.targets.length) throw new ReferenceError('At least one APNS2 target should be provided'); - } - var targets = []; - configuration.targets.forEach(function (target) { - targets.push(_this._objectFromAPNSTarget(target)); - }); - var collapseId = configuration.collapseId, expirationDate = configuration.expirationDate; - var objectifiedConfiguration = { auth_method: 'token', targets: targets, version: 'v2' }; - if (collapseId && collapseId.length) { + const { collapseId, expirationDate } = configuration; + const objectifiedConfiguration = { + auth_method: 'token', + targets: configuration.targets.map((target) => this.objectFromAPNSTarget(target)), + version: 'v2', + }; + if (collapseId && collapseId.length) objectifiedConfiguration.collapse_id = collapseId; - } - if (expirationDate) { + if (expirationDate) objectifiedConfiguration.expiration = expirationDate.toISOString(); - } return objectifiedConfiguration; - }; - APNSNotificationPayload.prototype._objectFromAPNSTarget = function (target) { - if (!target.topic || !target.topic.length) { + } + objectFromAPNSTarget(target) { + if (!target.topic || !target.topic.length) throw new TypeError("Target 'topic' undefined."); - } - var topic = target.topic, _a = target.environment, environment = _a === void 0 ? 'development' : _a, _b = target.excludedDevices, excludedDevices = _b === void 0 ? [] : _b; - var objectifiedTarget = { topic: topic, environment: environment }; - if (excludedDevices.length) { + const { topic, environment = 'development', excludedDevices = [] } = target; + const objectifiedTarget = { topic, environment }; + if (excludedDevices.length) objectifiedTarget.excluded_devices = excludedDevices; - } return objectifiedTarget; - }; - return APNSNotificationPayload; -}(BaseNotificationPayload)); + } +} exports.APNSNotificationPayload = APNSNotificationPayload; -var MPNSNotificationPayload = /** @class */ (function (_super) { - __extends(MPNSNotificationPayload, _super); - function MPNSNotificationPayload() { - return _super !== null && _super.apply(this, arguments) || this; - } - Object.defineProperty(MPNSNotificationPayload.prototype, "backContent", { - get: function () { - return this._backContent; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.back_content = value; - this._backContent = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(MPNSNotificationPayload.prototype, "backTitle", { - get: function () { - return this._backTitle; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.back_title = value; - this._backTitle = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(MPNSNotificationPayload.prototype, "count", { - get: function () { - return this._count; - }, - set: function (value) { - if (value === undefined || value === null) - return; - this._payload.count = value; - this._count = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(MPNSNotificationPayload.prototype, "title", { - get: function () { - return this._title; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.title = value; - this._title = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(MPNSNotificationPayload.prototype, "type", { - get: function () { - return this._type; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.type = value; - this._type = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(MPNSNotificationPayload.prototype, "subtitle", { - get: function () { - return this.backTitle; - }, - set: function (value) { - this.backTitle = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(MPNSNotificationPayload.prototype, "body", { - get: function () { - return this.backContent; - }, - set: function (value) { - this.backContent = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(MPNSNotificationPayload.prototype, "badge", { - get: function () { - return this.count; - }, - set: function (value) { - this.count = value; - }, - enumerable: false, - configurable: true - }); - MPNSNotificationPayload.prototype.toObject = function () { - return Object.keys(this._payload).length ? __assign({}, this._payload) : null; - }; - return MPNSNotificationPayload; -}(BaseNotificationPayload)); -exports.MPNSNotificationPayload = MPNSNotificationPayload; -var FCMNotificationPayload = /** @class */ (function (_super) { - __extends(FCMNotificationPayload, _super); - function FCMNotificationPayload() { - return _super !== null && _super.apply(this, arguments) || this; - } - Object.defineProperty(FCMNotificationPayload.prototype, "notification", { - get: function () { - return this._payload.notification; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(FCMNotificationPayload.prototype, "data", { - get: function () { - return this._payload.data; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(FCMNotificationPayload.prototype, "title", { - get: function () { - return this._title; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.notification.title = value; - this._title = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(FCMNotificationPayload.prototype, "body", { - get: function () { - return this._body; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.notification.body = value; - this._body = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(FCMNotificationPayload.prototype, "sound", { - get: function () { - return this._sound; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.notification.sound = value; - this._sound = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(FCMNotificationPayload.prototype, "icon", { - get: function () { - return this._icon; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.notification.icon = value; - this._icon = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(FCMNotificationPayload.prototype, "tag", { - get: function () { - return this._tag; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.notification.tag = value; - this._tag = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(FCMNotificationPayload.prototype, "silent", { - set: function (value) { - this._isSilent = value; - }, - enumerable: false, - configurable: true - }); - FCMNotificationPayload.prototype._setDefaultPayloadStructure = function () { - this._payload.notification = {}; - this._payload.data = {}; - }; - FCMNotificationPayload.prototype.toObject = function () { - var data = __assign({}, this._payload.data); - var notification = null; - var payload = {}; - /** - * Check whether additional data has been passed outside of 'data' object - * and put it into it if required. - */ - if (Object.keys(this._payload).length > 2) { - var _a = this._payload, initialNotification = _a.notification, initialData = _a.data, additionalData = __rest(_a, ["notification", "data"]); - data = __assign(__assign({}, data), additionalData); - } - if (this._isSilent) { - data.notification = this._payload.notification; - } - else { - notification = this._payload.notification; +class FCMNotificationPayload extends BaseNotificationPayload { + get payload() { + return this._payload; + } + get notification() { + return this.payload.notification; + } + get data() { + return this.payload.data; + } + get title() { + return this._title; + } + set title(value) { + if (!value || !value.length) + return; + this.payload.notification.title = value; + this._title = value; + } + get body() { + return this._body; + } + set body(value) { + if (!value || !value.length) + return; + this.payload.notification.body = value; + this._body = value; + } + get sound() { + return this._sound; + } + set sound(value) { + if (!value || !value.length) + return; + this.payload.notification.sound = value; + this._sound = value; + } + get icon() { + return this._icon; + } + set icon(value) { + if (!value || !value.length) + return; + this.payload.notification.icon = value; + this._icon = value; + } + get tag() { + return this._tag; + } + set tag(value) { + if (!value || !value.length) + return; + this.payload.notification.tag = value; + this._tag = value; + } + set silent(value) { + this._isSilent = value; + } + setDefaultPayloadStructure() { + this.payload.notification = {}; + this.payload.data = {}; + } + toObject() { + let data = Object.assign({}, this.payload.data); + let notification = null; + const payload = {}; + if (Object.keys(this.payload).length > 2) { + const _a = this.payload, { notification: initialNotification, data: initialData } = _a, additionalData = __rest(_a, ["notification", "data"]); + data = Object.assign(Object.assign({}, data), additionalData); } - if (Object.keys(data).length) { + if (this._isSilent) + data.notification = this.payload.notification; + else + notification = this.payload.notification; + if (Object.keys(data).length) payload.data = data; - } - if (notification && Object.keys(notification).length) { + if (notification && Object.keys(notification).length) payload.notification = notification; - } return Object.keys(payload).length ? payload : null; - }; - return FCMNotificationPayload; -}(BaseNotificationPayload)); + } +} exports.FCMNotificationPayload = FCMNotificationPayload; -var NotificationsPayload = /** @class */ (function () { - function NotificationsPayload(title, body) { - this._payload = { apns: {}, mpns: {}, fcm: {} }; +class NotificationsPayload { + constructor(title, body) { + this._payload = { apns: {}, fcm: {} }; this._title = title; this._body = body; this.apns = new APNSNotificationPayload(this._payload.apns, title, body); - this.mpns = new MPNSNotificationPayload(this._payload.mpns, title, body); this.fcm = new FCMNotificationPayload(this._payload.fcm, title, body); } - Object.defineProperty(NotificationsPayload.prototype, "debugging", { - set: function (value) { - this._debugging = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(NotificationsPayload.prototype, "title", { - get: function () { - return this._title; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(NotificationsPayload.prototype, "body", { - get: function () { - return this._body; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(NotificationsPayload.prototype, "subtitle", { - get: function () { - return this._subtitle; - }, - set: function (value) { - this._subtitle = value; - this.apns.subtitle = value; - this.mpns.subtitle = value; - this.fcm.subtitle = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(NotificationsPayload.prototype, "badge", { - get: function () { - return this._badge; - }, - set: function (value) { - this._badge = value; - this.apns.badge = value; - this.mpns.badge = value; - this.fcm.badge = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(NotificationsPayload.prototype, "sound", { - get: function () { - return this._sound; - }, - set: function (value) { - this._sound = value; - this.apns.sound = value; - this.mpns.sound = value; - this.fcm.sound = value; - }, - enumerable: false, - configurable: true - }); - /** - * Build notifications platform for requested platforms. - * - * @param {Array} platforms - List of platforms for which payload - * should be added to final dictionary. Supported values: gcm, apns, apns2, - * mpns. - * - * @returns {Object} Object with data, which can be sent with publish method - * call and trigger remote notifications for specified platforms. - */ - NotificationsPayload.prototype.buildPayload = function (platforms) { - var payload = {}; + set debugging(value) { + this._debugging = value; + } + get title() { + return this._title; + } + get subtitle() { + return this._subtitle; + } + set subtitle(value) { + this._subtitle = value; + this.apns.subtitle = value; + this.fcm.subtitle = value; + } + get body() { + return this._body; + } + get badge() { + return this._badge; + } + set badge(value) { + this._badge = value; + this.apns.badge = value; + this.fcm.badge = value; + } + get sound() { + return this._sound; + } + set sound(value) { + this._sound = value; + this.apns.sound = value; + this.fcm.sound = value; + } + buildPayload(platforms) { + const payload = {}; if (platforms.includes('apns') || platforms.includes('apns2')) { this.apns._apnsPushType = platforms.includes('apns') ? 'apns' : 'apns2'; - var apnsPayload = this.apns.toObject(); - if (apnsPayload && Object.keys(apnsPayload).length) { + const apnsPayload = this.apns.toObject(); + if (apnsPayload && Object.keys(apnsPayload).length) payload.pn_apns = apnsPayload; - } - } - if (platforms.includes('mpns')) { - var mpnsPayload = this.mpns.toObject(); - if (mpnsPayload && Object.keys(mpnsPayload).length) { - payload.pn_mpns = mpnsPayload; - } } if (platforms.includes('fcm')) { - var fcmPayload = this.fcm.toObject(); - if (fcmPayload && Object.keys(fcmPayload).length) { + const fcmPayload = this.fcm.toObject(); + if (fcmPayload && Object.keys(fcmPayload).length) payload.pn_gcm = fcmPayload; - } } - if (Object.keys(payload).length && this._debugging) { + if (Object.keys(payload).length && this._debugging) payload.pn_debug = true; - } return payload; - }; - return NotificationsPayload; -}()); + } +} exports.default = NotificationsPayload; diff --git a/lib/core/components/reconnection_manager.js b/lib/core/components/reconnection_manager.js index 26d293dc0..bc3065231 100644 --- a/lib/core/components/reconnection_manager.js +++ b/lib/core/components/reconnection_manager.js @@ -1,28 +1,29 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var default_1 = /** @class */ (function () { - function default_1(_a) { - var timeEndpoint = _a.timeEndpoint; - this._timeEndpoint = timeEndpoint; +exports.ReconnectionManager = void 0; +class ReconnectionManager { + constructor(time) { + this.time = time; } - default_1.prototype.onReconnection = function (reconnectionCallback) { - this._reconnectionCallback = reconnectionCallback; - }; - default_1.prototype.startPolling = function () { - this._timeTimer = setInterval(this._performTimeLoop.bind(this), 3000); - }; - default_1.prototype.stopPolling = function () { - clearInterval(this._timeTimer); - }; - default_1.prototype._performTimeLoop = function () { - var _this = this; - this._timeEndpoint(function (status) { + onReconnect(callback) { + this.callback = callback; + } + startPolling() { + this.timeTimer = setInterval(() => this.callTime(), 3000); + } + stopPolling() { + if (this.timeTimer) + clearInterval(this.timeTimer); + this.timeTimer = null; + } + callTime() { + this.time((status) => { if (!status.error) { - clearInterval(_this._timeTimer); - _this._reconnectionCallback(); + this.stopPolling(); + if (this.callback) + this.callback(); } }); - }; - return default_1; -}()); -exports.default = default_1; + } +} +exports.ReconnectionManager = ReconnectionManager; diff --git a/lib/core/components/request.js b/lib/core/components/request.js new file mode 100644 index 000000000..9da7e686b --- /dev/null +++ b/lib/core/components/request.js @@ -0,0 +1,98 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.AbstractRequest = void 0; +const transport_request_1 = require("../types/transport-request"); +const uuid_1 = __importDefault(require("./uuid")); +class AbstractRequest { + constructor(params) { + this.params = params; + this.requestIdentifier = uuid_1.default.createUUID(); + this._cancellationController = null; + } + get cancellationController() { + return this._cancellationController; + } + set cancellationController(controller) { + this._cancellationController = controller; + } + abort() { + if (this && this.cancellationController) + this.cancellationController.abort(); + } + operation() { + throw Error('Should be implemented by subclass.'); + } + validate() { + return undefined; + } + parse(_response) { + return __awaiter(this, void 0, void 0, function* () { + throw Error('Should be implemented by subclass.'); + }); + } + request() { + var _a, _b, _c, _d; + const request = { + method: (_b = (_a = this.params) === null || _a === void 0 ? void 0 : _a.method) !== null && _b !== void 0 ? _b : transport_request_1.TransportMethod.GET, + path: this.path, + queryParameters: this.queryParameters, + cancellable: (_d = (_c = this.params) === null || _c === void 0 ? void 0 : _c.cancellable) !== null && _d !== void 0 ? _d : false, + timeout: 10000, + identifier: this.requestIdentifier, + }; + const headers = this.headers; + if (headers) + request.headers = headers; + if (request.method === transport_request_1.TransportMethod.POST || request.method === transport_request_1.TransportMethod.PATCH) { + const [body, formData] = [this.body, this.formData]; + if (formData) + request.formData = formData; + if (body) + request.body = body; + } + return request; + } + get headers() { + return undefined; + } + get path() { + throw Error('`path` getter should be implemented by subclass.'); + } + get queryParameters() { + return {}; + } + get formData() { + return undefined; + } + get body() { + return undefined; + } + deserializeResponse(response) { + const contentType = response.headers['content-type']; + if (!contentType || (contentType.indexOf('javascript') === -1 && contentType.indexOf('json') === -1)) + return undefined; + const json = AbstractRequest.decoder.decode(response.body); + try { + const parsedJson = JSON.parse(json); + return parsedJson; + } + catch (error) { + console.error('Error parsing JSON response:', error); + return undefined; + } + } +} +exports.AbstractRequest = AbstractRequest; +AbstractRequest.decoder = new TextDecoder(); diff --git a/lib/core/components/stringify_buffer_keys.js b/lib/core/components/stringify_buffer_keys.js index 8e982e01b..1a0b1692b 100644 --- a/lib/core/components/stringify_buffer_keys.js +++ b/lib/core/components/stringify_buffer_keys.js @@ -2,26 +2,24 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.stringifyBufferKeys = void 0; function stringifyBufferKeys(obj) { - var isObject = function (value) { return value && typeof value === 'object' && value.constructor === Object; }; - var isString = function (value) { return typeof value === 'string' || value instanceof String; }; - var isNumber = function (value) { return typeof value === 'number' && isFinite(value); }; - if (!isObject(obj)) { + const isObject = (value) => typeof value === 'object' && value !== null && value.constructor === Object; + const isString = (value) => typeof value === 'string' || value instanceof String; + const isNumber = (value) => typeof value === 'number' && isFinite(value); + if (!isObject(obj)) return obj; - } - var normalizedObject = {}; - Object.keys(obj).forEach(function (key) { - var keyIsString = isString(key); - var stringifiedKey = key; - var value = obj[key]; - if (Array.isArray(key) || (keyIsString && key.indexOf(',') >= 0)) { - var bytes = keyIsString ? key.split(',') : key; - stringifiedKey = bytes.reduce(function (string, byte) { - string += String.fromCharCode(byte); - return string; + const normalizedObject = {}; + Object.keys(obj).forEach((key) => { + const keyIsString = isString(key); + let stringifiedKey = key; + const value = obj[key]; + if (keyIsString && key.indexOf(',') >= 0) { + const bytes = key.split(',').map(Number); + stringifiedKey = bytes.reduce((string, byte) => { + return string + String.fromCharCode(byte); }, ''); } - else if (isNumber(key) || (keyIsString && !isNaN(key))) { - stringifiedKey = String.fromCharCode(keyIsString ? parseInt(key, 10) : 10); + else if (isNumber(key) || (keyIsString && !isNaN(Number(key)))) { + stringifiedKey = String.fromCharCode(isNumber(key) ? key : parseInt(key, 10)); } normalizedObject[stringifiedKey] = isObject(value) ? stringifyBufferKeys(value) : value; }); diff --git a/lib/core/components/subject.js b/lib/core/components/subject.js index 0a8252ed6..fed3f3ade 100644 --- a/lib/core/components/subject.js +++ b/lib/core/components/subject.js @@ -1,23 +1,20 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Subject = void 0; -var Subject = /** @class */ (function () { - function Subject(sync) { - if (sync === void 0) { sync = false; } +class Subject { + constructor(sync = false) { this.sync = sync; this.listeners = new Set(); } - Subject.prototype.subscribe = function (listener) { - var _this = this; + subscribe(listener) { this.listeners.add(listener); - return function () { - _this.listeners.delete(listener); + return () => { + this.listeners.delete(listener); }; - }; - Subject.prototype.notify = function (event) { - var _this = this; - var wrapper = function () { - _this.listeners.forEach(function (listener) { + } + notify(event) { + const wrapper = () => { + this.listeners.forEach((listener) => { listener(event); }); }; @@ -27,7 +24,6 @@ var Subject = /** @class */ (function () { else { setTimeout(wrapper, 0); } - }; - return Subject; -}()); + } +} exports.Subject = Subject; diff --git a/lib/core/components/subscription-manager.js b/lib/core/components/subscription-manager.js new file mode 100644 index 000000000..fa7d37902 --- /dev/null +++ b/lib/core/components/subscription-manager.js @@ -0,0 +1,354 @@ +"use strict"; +var __rest = (this && this.__rest) || function (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; +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.SubscriptionManager = void 0; +const reconnection_manager_1 = require("./reconnection_manager"); +const categories_1 = __importDefault(require("../constants/categories")); +const categories_2 = __importDefault(require("../constants/categories")); +const deduping_manager_1 = __importDefault(require("./deduping_manager")); +class SubscriptionManager { + constructor(configuration, listenerManager, eventEmitter, subscribeCall, heartbeatCall, leaveCall, time) { + this.configuration = configuration; + this.listenerManager = listenerManager; + this.eventEmitter = eventEmitter; + this.subscribeCall = subscribeCall; + this.heartbeatCall = heartbeatCall; + this.leaveCall = leaveCall; + this.reconnectionManager = new reconnection_manager_1.ReconnectionManager(time); + this.dedupingManager = new deduping_manager_1.default({ config: this.configuration }); + this.heartbeatChannelGroups = {}; + this.heartbeatChannels = {}; + this.presenceChannelGroups = {}; + this.presenceChannels = {}; + this.heartbeatTimer = null; + this.presenceState = {}; + this.pendingChannelGroupSubscriptions = new Set(); + this.pendingChannelSubscriptions = new Set(); + this.channelGroups = {}; + this.channels = {}; + this.currentTimetoken = '0'; + this.lastTimetoken = '0'; + this.storedTimetoken = null; + this.subscriptionStatusAnnounced = false; + this.isOnline = true; + } + get subscribedChannels() { + return Object.keys(this.channels); + } + get subscribedChannelGroups() { + return Object.keys(this.channelGroups); + } + get abort() { + return this._subscribeAbort; + } + set abort(call) { + this._subscribeAbort = call; + } + disconnect() { + this.stopSubscribeLoop(); + this.stopHeartbeatTimer(); + this.reconnectionManager.stopPolling(); + } + reconnect() { + this.startSubscribeLoop(); + this.startHeartbeatTimer(); + } + subscribe(parameters) { + const { channels, channelGroups, timetoken, withPresence = false, withHeartbeats = false } = parameters; + if (timetoken) { + this.lastTimetoken = this.currentTimetoken; + this.currentTimetoken = timetoken; + } + if (this.currentTimetoken !== '0' && this.currentTimetoken !== 0) { + this.storedTimetoken = this.currentTimetoken; + this.currentTimetoken = 0; + } + channels === null || channels === void 0 ? void 0 : channels.forEach((channel) => { + this.pendingChannelSubscriptions.add(channel); + this.channels[channel] = {}; + if (withPresence) + this.presenceChannels[channel] = {}; + if (withHeartbeats || this.configuration.getHeartbeatInterval()) + this.heartbeatChannels[channel] = {}; + }); + channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.forEach((group) => { + this.pendingChannelGroupSubscriptions.add(group); + this.channelGroups[group] = {}; + if (withPresence) + this.presenceChannelGroups[group] = {}; + if (withHeartbeats || this.configuration.getHeartbeatInterval()) + this.heartbeatChannelGroups[group] = {}; + }); + this.subscriptionStatusAnnounced = false; + this.reconnect(); + } + unsubscribe(parameters, isOffline) { + let { channels, channelGroups } = parameters; + const actualChannelGroups = new Set(); + const actualChannels = new Set(); + channels === null || channels === void 0 ? void 0 : channels.forEach((channel) => { + if (channel in this.channels) { + delete this.channels[channel]; + actualChannels.add(channel); + if (channel in this.heartbeatChannels) + delete this.heartbeatChannels[channel]; + } + if (channel in this.presenceState) + delete this.presenceState[channel]; + if (channel in this.presenceChannels) { + delete this.presenceChannels[channel]; + actualChannels.add(channel); + } + }); + channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.forEach((group) => { + if (group in this.channelGroups) { + delete this.channelGroups[group]; + actualChannelGroups.add(group); + if (group in this.heartbeatChannelGroups) + delete this.heartbeatChannelGroups[group]; + } + if (group in this.presenceState) + delete this.presenceState[group]; + if (group in this.presenceChannelGroups) { + delete this.presenceChannelGroups[group]; + actualChannelGroups.add(group); + } + }); + if (actualChannels.size === 0 && actualChannelGroups.size === 0) + return; + if (this.configuration.suppressLeaveEvents === false && !isOffline) { + channelGroups = Array.from(actualChannelGroups); + channels = Array.from(actualChannels); + this.leaveCall({ channels, channelGroups }, (status) => { + const { error } = status, restOfStatus = __rest(status, ["error"]); + let errorMessage; + if (error) { + if (status.errorData && + typeof status.errorData === 'object' && + 'message' in status.errorData && + typeof status.errorData.message === 'string') + errorMessage = status.errorData.message; + else if ('message' in status && typeof status.message === 'string') + errorMessage = status.message; + } + this.listenerManager.announceStatus(Object.assign(Object.assign({}, restOfStatus), { error: errorMessage !== null && errorMessage !== void 0 ? errorMessage : false, affectedChannels: channels, affectedChannelGroups: channelGroups, currentTimetoken: this.currentTimetoken, lastTimetoken: this.lastTimetoken })); + }); + } + if (Object.keys(this.channels).length === 0 && + Object.keys(this.presenceChannels).length === 0 && + Object.keys(this.channelGroups).length === 0 && + Object.keys(this.presenceChannelGroups).length === 0) { + this.lastTimetoken = 0; + this.currentTimetoken = 0; + this.storedTimetoken = null; + this.region = null; + this.reconnectionManager.stopPolling(); + } + this.reconnect(); + } + unsubscribeAll(isOffline) { + this.unsubscribe({ + channels: this.subscribedChannels, + channelGroups: this.subscribedChannelGroups, + }, isOffline); + } + startSubscribeLoop() { + this.stopSubscribeLoop(); + const channelGroups = [...Object.keys(this.channelGroups)]; + const channels = [...Object.keys(this.channels)]; + Object.keys(this.presenceChannelGroups).forEach((group) => channelGroups.push(`${group}-pnpres`)); + Object.keys(this.presenceChannels).forEach((channel) => channels.push(`${channel}-pnpres`)); + if (channels.length === 0 && channelGroups.length === 0) + return; + this.subscribeCall({ + channels, + channelGroups, + state: this.presenceState, + heartbeat: this.configuration.getPresenceTimeout(), + timetoken: this.currentTimetoken, + region: this.region !== null ? this.region : undefined, + filterExpression: this.configuration.filterExpression, + }, (status, result) => { + this.processSubscribeResponse(status, result); + }); + } + stopSubscribeLoop() { + if (this._subscribeAbort) { + this._subscribeAbort(); + this._subscribeAbort = null; + } + } + processSubscribeResponse(status, result) { + if (status.error) { + if ((typeof status.errorData === 'object' && + 'name' in status.errorData && + status.errorData.name === 'AbortError') || + status.category === categories_1.default.PNCancelledCategory) + return; + if (status.category === categories_2.default.PNTimeoutCategory) { + this.startSubscribeLoop(); + } + else if (status.category === categories_2.default.PNNetworkIssuesCategory) { + this.disconnect(); + if (status.error && this.configuration.autoNetworkDetection && this.isOnline) { + this.isOnline = false; + this.listenerManager.announceNetworkDown(); + } + this.reconnectionManager.onReconnect(() => { + if (this.configuration.autoNetworkDetection && !this.isOnline) { + this.isOnline = true; + this.listenerManager.announceNetworkUp(); + } + this.reconnect(); + this.subscriptionStatusAnnounced = true; + const reconnectedAnnounce = { + category: categories_2.default.PNReconnectedCategory, + operation: status.operation, + lastTimetoken: this.lastTimetoken, + currentTimetoken: this.currentTimetoken, + }; + this.listenerManager.announceStatus(reconnectedAnnounce); + }); + this.reconnectionManager.startPolling(); + this.listenerManager.announceStatus(status); + } + else if (status.category === categories_2.default.PNBadRequestCategory) { + this.stopHeartbeatTimer(); + this.listenerManager.announceStatus(status); + } + else { + this.listenerManager.announceStatus(status); + } + return; + } + if (this.storedTimetoken) { + this.currentTimetoken = this.storedTimetoken; + this.storedTimetoken = null; + } + else { + this.lastTimetoken = this.currentTimetoken; + this.currentTimetoken = result.cursor.timetoken; + } + if (!this.subscriptionStatusAnnounced) { + const connected = { + category: categories_1.default.PNConnectedCategory, + operation: status.operation, + affectedChannels: Array.from(this.pendingChannelSubscriptions), + subscribedChannels: this.subscribedChannels, + affectedChannelGroups: Array.from(this.pendingChannelGroupSubscriptions), + lastTimetoken: this.lastTimetoken, + currentTimetoken: this.currentTimetoken, + }; + this.subscriptionStatusAnnounced = true; + this.listenerManager.announceStatus(connected); + this.pendingChannelGroupSubscriptions.clear(); + this.pendingChannelSubscriptions.clear(); + } + const { messages } = result; + const { requestMessageCountThreshold, dedupeOnSubscribe } = this.configuration; + if (requestMessageCountThreshold && messages.length >= requestMessageCountThreshold) { + this.listenerManager.announceStatus({ + category: categories_1.default.PNRequestMessageCountExceededCategory, + operation: status.operation, + }); + } + try { + messages.forEach((message) => { + if (dedupeOnSubscribe) { + if (this.dedupingManager.isDuplicate(message.data)) + return; + this.dedupingManager.addEntry(message.data); + } + this.eventEmitter.emitEvent(message); + }); + } + catch (e) { + const errorStatus = { + error: true, + category: categories_1.default.PNUnknownCategory, + errorData: e, + statusCode: 0, + }; + this.listenerManager.announceStatus(errorStatus); + } + this.region = result.cursor.region; + this.startSubscribeLoop(); + } + setState(parameters) { + const { state, channels, channelGroups } = parameters; + channels === null || channels === void 0 ? void 0 : channels.forEach((channel) => channel in this.channels && (this.presenceState[channel] = state)); + channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.forEach((group) => group in this.channelGroups && (this.presenceState[group] = state)); + } + changePresence(parameters) { + const { connected, channels, channelGroups } = parameters; + if (connected) { + channels === null || channels === void 0 ? void 0 : channels.forEach((channel) => (this.heartbeatChannels[channel] = {})); + channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.forEach((group) => (this.heartbeatChannelGroups[group] = {})); + } + else { + channels === null || channels === void 0 ? void 0 : channels.forEach((channel) => { + if (channel in this.heartbeatChannels) + delete this.heartbeatChannels[channel]; + }); + channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.forEach((group) => { + if (group in this.heartbeatChannelGroups) + delete this.heartbeatChannelGroups[group]; + }); + if (this.configuration.suppressLeaveEvents === false) { + this.leaveCall({ channels, channelGroups }, (status) => this.listenerManager.announceStatus(status)); + } + } + this.reconnect(); + } + startHeartbeatTimer() { + this.stopHeartbeatTimer(); + const heartbeatInterval = this.configuration.getHeartbeatInterval(); + if (!heartbeatInterval || heartbeatInterval === 0) + return; + this.sendHeartbeat(); + this.heartbeatTimer = setInterval(() => this.sendHeartbeat(), heartbeatInterval * 1000); + } + stopHeartbeatTimer() { + if (!this.heartbeatTimer) + return; + clearInterval(this.heartbeatTimer); + this.heartbeatTimer = null; + } + sendHeartbeat() { + const heartbeatChannelGroups = Object.keys(this.heartbeatChannelGroups); + const heartbeatChannels = Object.keys(this.heartbeatChannels); + if (heartbeatChannels.length === 0 && heartbeatChannelGroups.length === 0) + return; + this.heartbeatCall({ + channels: heartbeatChannels, + channelGroups: heartbeatChannelGroups, + heartbeat: this.configuration.getPresenceTimeout(), + state: this.presenceState, + }, (status) => { + if (status.error && this.configuration.announceFailedHeartbeats) + this.listenerManager.announceStatus(status); + if (status.error && this.configuration.autoNetworkDetection && this.isOnline) { + this.isOnline = false; + this.disconnect(); + this.listenerManager.announceNetworkDown(); + this.reconnect(); + } + if (!status.error && this.configuration.announceSuccessfulHeartbeats) + this.listenerManager.announceStatus(status); + }); + } +} +exports.SubscriptionManager = SubscriptionManager; diff --git a/lib/core/components/subscription_manager.js b/lib/core/components/subscription_manager.js deleted file mode 100644 index 077bb4a1b..000000000 --- a/lib/core/components/subscription_manager.js +++ /dev/null @@ -1,434 +0,0 @@ -"use strict"; -var __rest = (this && this.__rest) || function (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; -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var reconnection_manager_1 = __importDefault(require("./reconnection_manager")); -var deduping_manager_1 = __importDefault(require("./deduping_manager")); -var categories_1 = __importDefault(require("../constants/categories")); -var default_1 = /** @class */ (function () { - function default_1(_a) { - var subscribeEndpoint = _a.subscribeEndpoint, leaveEndpoint = _a.leaveEndpoint, heartbeatEndpoint = _a.heartbeatEndpoint, setStateEndpoint = _a.setStateEndpoint, timeEndpoint = _a.timeEndpoint, getFileUrl = _a.getFileUrl, config = _a.config, crypto = _a.crypto, listenerManager = _a.listenerManager, cryptoModule = _a.cryptoModule, eventEmitter = _a.eventEmitter; - this._listenerManager = listenerManager; - this._config = config; - this._leaveEndpoint = leaveEndpoint; - this._heartbeatEndpoint = heartbeatEndpoint; - this._setStateEndpoint = setStateEndpoint; - this._subscribeEndpoint = subscribeEndpoint; - this._getFileUrl = getFileUrl; - this._crypto = crypto; - this._cryptoModule = cryptoModule; - this._channels = {}; - this._presenceChannels = {}; - this._heartbeatChannels = {}; - this._heartbeatChannelGroups = {}; - this._channelGroups = {}; - this._presenceChannelGroups = {}; - this._pendingChannelSubscriptions = []; - this._pendingChannelGroupSubscriptions = []; - this._currentTimetoken = 0; - this._lastTimetoken = 0; - this._storedTimetoken = null; - this._subscriptionStatusAnnounced = false; - this._isOnline = true; - this._reconnectionManager = new reconnection_manager_1.default({ timeEndpoint: timeEndpoint }); - this._dedupingManager = new deduping_manager_1.default({ config: config }); - if (this._cryptoModule) - this._decoder = new TextDecoder(); - this._eventEmitter = eventEmitter; - } - default_1.prototype.adaptStateChange = function (args, callback) { - var _this = this; - var state = args.state, _a = args.channels, channels = _a === void 0 ? [] : _a, _b = args.channelGroups, channelGroups = _b === void 0 ? [] : _b, _c = args.withHeartbeat, withHeartbeat = _c === void 0 ? false : _c; - channels.forEach(function (channel) { - if (channel in _this._channels) - _this._channels[channel].state = state; - }); - channelGroups.forEach(function (channelGroup) { - if (channelGroup in _this._channelGroups) { - _this._channelGroups[channelGroup].state = state; - } - }); - if (withHeartbeat) { - var presenceState_1 = {}; - channels.forEach(function (channel) { return (presenceState_1[channel] = state); }); - channelGroups.forEach(function (group) { return (presenceState_1[group] = state); }); - return this._heartbeatEndpoint({ channels: channels, channelGroups: channelGroups, state: presenceState_1 }, callback); - } - return this._setStateEndpoint({ state: state, channels: channels, channelGroups: channelGroups }, callback); - }; - default_1.prototype.adaptPresenceChange = function (args) { - var _this = this; - var connected = args.connected, _a = args.channels, channels = _a === void 0 ? [] : _a, _b = args.channelGroups, channelGroups = _b === void 0 ? [] : _b; - if (connected) { - channels.forEach(function (channel) { - _this._heartbeatChannels[channel] = { state: {} }; - }); - channelGroups.forEach(function (channelGroup) { - _this._heartbeatChannelGroups[channelGroup] = { state: {} }; - }); - } - else { - channels.forEach(function (channel) { - if (channel in _this._heartbeatChannels) { - delete _this._heartbeatChannels[channel]; - } - }); - channelGroups.forEach(function (channelGroup) { - if (channelGroup in _this._heartbeatChannelGroups) { - delete _this._heartbeatChannelGroups[channelGroup]; - } - }); - if (this._config.suppressLeaveEvents === false) { - this._leaveEndpoint({ channels: channels, channelGroups: channelGroups }, function (status) { - _this._listenerManager.announceStatus(status); - }); - } - } - this.reconnect(); - }; - default_1.prototype.adaptSubscribeChange = function (args) { - var _this = this; - var timetoken = args.timetoken, _a = args.channels, channels = _a === void 0 ? [] : _a, _b = args.channelGroups, channelGroups = _b === void 0 ? [] : _b, _c = args.withPresence, withPresence = _c === void 0 ? false : _c, _d = args.withHeartbeats, withHeartbeats = _d === void 0 ? false : _d; - if (!this._config.subscribeKey || this._config.subscribeKey === '') { - // eslint-disable-next-line - if (console && console.log) { - console.log('subscribe key missing; aborting subscribe'); //eslint-disable-line - } - return; - } - if (timetoken) { - this._lastTimetoken = this._currentTimetoken; - this._currentTimetoken = timetoken; - } - // reset the current timetoken to get a connect event. - // $FlowFixMe - if (this._currentTimetoken !== '0' && this._currentTimetoken !== 0) { - this._storedTimetoken = this._currentTimetoken; - this._currentTimetoken = 0; - } - channels.forEach(function (channel) { - _this._channels[channel] = { state: {} }; - if (withPresence) - _this._presenceChannels[channel] = {}; - if (withHeartbeats || _this._config.getHeartbeatInterval()) - _this._heartbeatChannels[channel] = {}; - _this._pendingChannelSubscriptions.push(channel); - }); - channelGroups.forEach(function (channelGroup) { - _this._channelGroups[channelGroup] = { state: {} }; - if (withPresence) - _this._presenceChannelGroups[channelGroup] = {}; - if (withHeartbeats || _this._config.getHeartbeatInterval()) - _this._heartbeatChannelGroups[channelGroup] = {}; - _this._pendingChannelGroupSubscriptions.push(channelGroup); - }); - this._subscriptionStatusAnnounced = false; - this.reconnect(); - }; - default_1.prototype.adaptUnsubscribeChange = function (args, isOffline) { - var _this = this; - var _a = args.channels, channels = _a === void 0 ? [] : _a, _b = args.channelGroups, channelGroups = _b === void 0 ? [] : _b; - // keep track of which channels and channel groups - // we are going to unsubscribe from. - var actualChannels = []; - var actualChannelGroups = []; - // - channels.forEach(function (channel) { - if (channel in _this._channels) { - delete _this._channels[channel]; - actualChannels.push(channel); - if (channel in _this._heartbeatChannels) { - delete _this._heartbeatChannels[channel]; - } - } - if (channel in _this._presenceChannels) { - delete _this._presenceChannels[channel]; - actualChannels.push(channel); - } - }); - channelGroups.forEach(function (channelGroup) { - if (channelGroup in _this._channelGroups) { - delete _this._channelGroups[channelGroup]; - actualChannelGroups.push(channelGroup); - if (channelGroup in _this._heartbeatChannelGroups) { - delete _this._heartbeatChannelGroups[channelGroup]; - } - } - if (channelGroup in _this._presenceChannelGroups) { - delete _this._presenceChannelGroups[channelGroup]; - actualChannelGroups.push(channelGroup); - } - }); - // no-op if there are no channels and cg's to unsubscribe from. - if (actualChannels.length === 0 && actualChannelGroups.length === 0) { - return; - } - if (this._config.suppressLeaveEvents === false && !isOffline) { - this._leaveEndpoint({ channels: actualChannels, channelGroups: actualChannelGroups }, function (status) { - status.affectedChannels = actualChannels; - status.affectedChannelGroups = actualChannelGroups; - status.currentTimetoken = _this._currentTimetoken; - status.lastTimetoken = _this._lastTimetoken; - _this._listenerManager.announceStatus(status); - }); - } - // if we have nothing to subscribe to, reset the timetoken. - if (Object.keys(this._channels).length === 0 && - Object.keys(this._presenceChannels).length === 0 && - Object.keys(this._channelGroups).length === 0 && - Object.keys(this._presenceChannelGroups).length === 0) { - this._lastTimetoken = 0; - this._currentTimetoken = 0; - this._storedTimetoken = null; - this._region = null; - this._reconnectionManager.stopPolling(); - } - this.reconnect(); - }; - default_1.prototype.unsubscribeAll = function (isOffline) { - this.adaptUnsubscribeChange({ - channels: this.getSubscribedChannels(), - channelGroups: this.getSubscribedChannelGroups(), - }, isOffline); - }; - default_1.prototype.getHeartbeatChannels = function () { - return Object.keys(this._heartbeatChannels); - }; - default_1.prototype.getHeartbeatChannelGroups = function () { - return Object.keys(this._heartbeatChannelGroups); - }; - default_1.prototype.getSubscribedChannels = function () { - return Object.keys(this._channels); - }; - default_1.prototype.getSubscribedChannelGroups = function () { - return Object.keys(this._channelGroups); - }; - default_1.prototype.reconnect = function () { - this._startSubscribeLoop(); - this._registerHeartbeatTimer(); - }; - default_1.prototype.disconnect = function () { - this._stopSubscribeLoop(); - this._stopHeartbeatTimer(); - this._reconnectionManager.stopPolling(); - }; - default_1.prototype._registerHeartbeatTimer = function () { - this._stopHeartbeatTimer(); - // if the interval is 0 or undefined, do not queue up heartbeating - if (this._config.getHeartbeatInterval() === 0 || this._config.getHeartbeatInterval() === undefined) { - return; - } - this._performHeartbeatLoop(); - // $FlowFixMe - this._heartbeatTimer = setInterval(this._performHeartbeatLoop.bind(this), this._config.getHeartbeatInterval() * 1000); - }; - default_1.prototype._stopHeartbeatTimer = function () { - if (this._heartbeatTimer) { - // $FlowFixMe - clearInterval(this._heartbeatTimer); - this._heartbeatTimer = null; - } - }; - default_1.prototype._performHeartbeatLoop = function () { - var _this = this; - var heartbeatChannels = this.getHeartbeatChannels(); - var heartbeatChannelGroups = this.getHeartbeatChannelGroups(); - var presenceState = {}; - if (heartbeatChannels.length === 0 && heartbeatChannelGroups.length === 0) { - return; - } - this.getSubscribedChannels().forEach(function (channel) { - var channelState = _this._channels[channel].state; - if (Object.keys(channelState).length) { - presenceState[channel] = channelState; - } - }); - this.getSubscribedChannelGroups().forEach(function (channelGroup) { - var channelGroupState = _this._channelGroups[channelGroup].state; - if (Object.keys(channelGroupState).length) { - presenceState[channelGroup] = channelGroupState; - } - }); - var onHeartbeat = function (status) { - if (status.error && _this._config.announceFailedHeartbeats) { - _this._listenerManager.announceStatus(status); - } - if (status.error && _this._config.autoNetworkDetection && _this._isOnline) { - _this._isOnline = false; - _this.disconnect(); - _this._listenerManager.announceNetworkDown(); - _this.reconnect(); - } - if (!status.error && _this._config.announceSuccessfulHeartbeats) { - _this._listenerManager.announceStatus(status); - } - }; - this._heartbeatEndpoint({ - channels: heartbeatChannels, - channelGroups: heartbeatChannelGroups, - state: presenceState, - }, onHeartbeat.bind(this)); - }; - default_1.prototype._startSubscribeLoop = function () { - var _this = this; - this._stopSubscribeLoop(); - var presenceState = {}; - var channels = []; - var channelGroups = []; - Object.keys(this._channels).forEach(function (channel) { - var channelState = _this._channels[channel].state; - if (Object.keys(channelState).length) { - presenceState[channel] = channelState; - } - channels.push(channel); - }); - Object.keys(this._presenceChannels).forEach(function (channel) { - channels.push("".concat(channel, "-pnpres")); - }); - Object.keys(this._channelGroups).forEach(function (channelGroup) { - var channelGroupState = _this._channelGroups[channelGroup].state; - if (Object.keys(channelGroupState).length) { - presenceState[channelGroup] = channelGroupState; - } - channelGroups.push(channelGroup); - }); - Object.keys(this._presenceChannelGroups).forEach(function (channelGroup) { - channelGroups.push("".concat(channelGroup, "-pnpres")); - }); - if (channels.length === 0 && channelGroups.length === 0) { - return; - } - var subscribeArgs = { - channels: channels, - channelGroups: channelGroups, - state: presenceState, - timetoken: this._currentTimetoken, - filterExpression: this._config.filterExpression, - region: this._region, - }; - this._subscribeCall = this._subscribeEndpoint(subscribeArgs, this._processSubscribeResponse.bind(this)); - }; - default_1.prototype._processSubscribeResponse = function (status, payload) { - var _this = this; - if (status.error) { - // if error comes from request abort, ignore - if (status.errorData && status.errorData.message === 'Aborted') { - return; - } - // if we timeout from server, restart the loop. - if (status.category === categories_1.default.PNTimeoutCategory) { - this._startSubscribeLoop(); - } - else if (status.category === categories_1.default.PNNetworkIssuesCategory) { - // we lost internet connection, alert the reconnection manager and terminate all loops - this.disconnect(); - if (status.error && this._config.autoNetworkDetection && this._isOnline) { - this._isOnline = false; - this._listenerManager.announceNetworkDown(); - } - this._reconnectionManager.onReconnection(function () { - if (_this._config.autoNetworkDetection && !_this._isOnline) { - _this._isOnline = true; - _this._listenerManager.announceNetworkUp(); - } - _this.reconnect(); - _this._subscriptionStatusAnnounced = true; - var reconnectedAnnounce = { - category: categories_1.default.PNReconnectedCategory, - operation: status.operation, - lastTimetoken: _this._lastTimetoken, - currentTimetoken: _this._currentTimetoken, - }; - _this._listenerManager.announceStatus(reconnectedAnnounce); - }); - this._reconnectionManager.startPolling(); - this._listenerManager.announceStatus(status); - } - else if (status.category === categories_1.default.PNBadRequestCategory) { - this._stopHeartbeatTimer(); - this._listenerManager.announceStatus(status); - } - else { - this._listenerManager.announceStatus(status); - } - return; - } - if (this._storedTimetoken) { - this._currentTimetoken = this._storedTimetoken; - this._storedTimetoken = null; - } - else { - this._lastTimetoken = this._currentTimetoken; - this._currentTimetoken = payload.metadata.timetoken; - } - if (!this._subscriptionStatusAnnounced) { - var connectedAnnounce = {}; - connectedAnnounce.category = categories_1.default.PNConnectedCategory; - connectedAnnounce.operation = status.operation; - connectedAnnounce.affectedChannels = this._pendingChannelSubscriptions; - connectedAnnounce.subscribedChannels = this.getSubscribedChannels(); - connectedAnnounce.affectedChannelGroups = this._pendingChannelGroupSubscriptions; - connectedAnnounce.lastTimetoken = this._lastTimetoken; - connectedAnnounce.currentTimetoken = this._currentTimetoken; - this._subscriptionStatusAnnounced = true; - this._listenerManager.announceStatus(connectedAnnounce); - // clear the pending connections list - this._pendingChannelSubscriptions = []; - this._pendingChannelGroupSubscriptions = []; - } - var messages = payload.messages || []; - var _a = this._config, requestMessageCountThreshold = _a.requestMessageCountThreshold, dedupeOnSubscribe = _a.dedupeOnSubscribe; - if (requestMessageCountThreshold && messages.length >= requestMessageCountThreshold) { - var countAnnouncement = {}; - countAnnouncement.category = categories_1.default.PNRequestMessageCountExceededCategory; - countAnnouncement.operation = status.operation; - this._listenerManager.announceStatus(countAnnouncement); - } - messages.forEach(function (message) { - var channel = message.channel; - var subscriptionMatch = message.subscriptionMatch; - if (channel === subscriptionMatch) { - subscriptionMatch = null; - } - if (dedupeOnSubscribe) { - if (_this._dedupingManager.isDuplicate(message)) { - return; - } - _this._dedupingManager.addEntry(message); - } - _this._eventEmitter.emitEvent(message); - }); - this._region = payload.metadata.region; - this._startSubscribeLoop(); - }; - default_1.prototype._stopSubscribeLoop = function () { - if (this._subscribeCall) { - if (typeof this._subscribeCall.abort === 'function') { - this._subscribeCall.abort(); - } - this._subscribeCall = null; - } - }; - default_1.prototype._renameEvent = function (e) { - return e === 'set' ? 'updated' : 'removed'; - }; - default_1.prototype._renameChannelField = function (announce) { - var channel = announce.channel, eventData = __rest(announce, ["channel"]); - eventData.spaceId = channel; - return eventData; - }; - return default_1; -}()); -exports.default = default_1; diff --git a/lib/core/components/telemetry_manager.js b/lib/core/components/telemetry_manager.js deleted file mode 100644 index f63405121..000000000 --- a/lib/core/components/telemetry_manager.js +++ /dev/null @@ -1,137 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -/* */ -var operations_1 = __importDefault(require("../constants/operations")); -var default_1 = /** @class */ (function () { - function default_1(configuration) { - this._maximumSamplesCount = 100; - this._trackedLatencies = {}; - this._latencies = {}; - this._telemetryExcludeOperations = [ - operations_1.default.PNSubscribeOperation, - operations_1.default.PNReceiveMessagesOperation, - operations_1.default.PNHandshakeOperation, - ]; - this._maximumSamplesCount = configuration.maximumSamplesCount || this._maximumSamplesCount; - } - /** - * Compose object with latency information of recently used API endpoints. - * - * @return {Object} Object with request query key/value pairs. - */ - default_1.prototype.operationsLatencyForRequest = function () { - var _this = this; - var latencies = {}; - Object.keys(this._latencies).forEach(function (endpointName) { - var operationLatencies = _this._latencies[endpointName]; - var averageLatency = _this._averageLatency(operationLatencies); - if (averageLatency > 0) { - latencies["l_".concat(endpointName)] = averageLatency; - } - }); - return latencies; - }; - default_1.prototype.startLatencyMeasure = function (operationType, identifier) { - if (this._telemetryExcludeOperations.includes(operationType) || !identifier) { - return; - } - this._trackedLatencies[identifier] = Date.now(); - }; - default_1.prototype.stopLatencyMeasure = function (operationType, identifier) { - if (this._telemetryExcludeOperations.includes(operationType) || !identifier) { - return; - } - var endpointName = this._endpointName(operationType); - /** @type Array */ - var endpointLatencies = this._latencies[endpointName]; - var startDate = this._trackedLatencies[identifier]; - if (!endpointLatencies) { - this._latencies[endpointName] = []; - endpointLatencies = this._latencies[endpointName]; - } - endpointLatencies.push(Date.now() - startDate); - // Truncate samples count if there is more then configured. - if (endpointLatencies.length > this._maximumSamplesCount) { - endpointLatencies.splice(0, endpointLatencies.length - this._maximumSamplesCount); - } - delete this._trackedLatencies[identifier]; - }; - default_1.prototype._averageLatency = function (latencies) { - var arrayReduce = function (accumulatedLatency, latency) { return accumulatedLatency + latency; }; - return Math.floor(latencies.reduce(arrayReduce, 0) / latencies.length); - }; - default_1.prototype._endpointName = function (operationType) { - var operation = null; - switch (operationType) { - case operations_1.default.PNPublishOperation: - operation = 'pub'; - break; - case operations_1.default.PNSignalOperation: - operation = 'sig'; - break; - case operations_1.default.PNHistoryOperation: - case operations_1.default.PNFetchMessagesOperation: - case operations_1.default.PNDeleteMessagesOperation: - case operations_1.default.PNMessageCounts: - operation = 'hist'; - break; - case operations_1.default.PNUnsubscribeOperation: - case operations_1.default.PNWhereNowOperation: - case operations_1.default.PNHereNowOperation: - case operations_1.default.PNHeartbeatOperation: - case operations_1.default.PNSetStateOperation: - case operations_1.default.PNGetStateOperation: - operation = 'pres'; - break; - case operations_1.default.PNAddChannelsToGroupOperation: - case operations_1.default.PNRemoveChannelsFromGroupOperation: - case operations_1.default.PNChannelGroupsOperation: - case operations_1.default.PNRemoveGroupOperation: - case operations_1.default.PNChannelsForGroupOperation: - operation = 'cg'; - break; - case operations_1.default.PNPushNotificationEnabledChannelsOperation: - case operations_1.default.PNRemoveAllPushNotificationsOperation: - operation = 'push'; - break; - case operations_1.default.PNCreateUserOperation: - case operations_1.default.PNUpdateUserOperation: - case operations_1.default.PNDeleteUserOperation: - case operations_1.default.PNGetUserOperation: - case operations_1.default.PNGetUsersOperation: - case operations_1.default.PNCreateSpaceOperation: - case operations_1.default.PNUpdateSpaceOperation: - case operations_1.default.PNDeleteSpaceOperation: - case operations_1.default.PNGetSpaceOperation: - case operations_1.default.PNGetSpacesOperation: - case operations_1.default.PNGetMembersOperation: - case operations_1.default.PNUpdateMembersOperation: - case operations_1.default.PNGetMembershipsOperation: - case operations_1.default.PNUpdateMembershipsOperation: - operation = 'obj'; - break; - case operations_1.default.PNAddMessageActionOperation: - case operations_1.default.PNRemoveMessageActionOperation: - case operations_1.default.PNGetMessageActionsOperation: - operation = 'msga'; - break; - case operations_1.default.PNAccessManagerGrant: - case operations_1.default.PNAccessManagerAudit: - operation = 'pam'; - break; - case operations_1.default.PNAccessManagerGrantToken: - case operations_1.default.PNAccessManagerRevokeToken: - operation = 'pamv3'; - break; - default: - operation = 'time'; - break; - } - return operation; - }; - return default_1; -}()); -exports.default = default_1; diff --git a/lib/core/components/token_manager.js b/lib/core/components/token_manager.js index e41ef77a1..9ada86a34 100644 --- a/lib/core/components/token_manager.js +++ b/lib/core/components/token_manager.js @@ -1,128 +1,102 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var default_1 = /** @class */ (function () { - function default_1(config, cbor) { - this._config = config; - this._cbor = cbor; +exports.TokenManager = void 0; +class TokenManager { + constructor(cbor) { + this.cbor = cbor; } - default_1.prototype.setToken = function (token) { - if (token && token.length > 0) { - this._token = token; - } - else { - this._token = undefined; - } - }; - default_1.prototype.getToken = function () { - return this._token; - }; - default_1.prototype.extractPermissions = function (permissions) { - var permissionsResult = { - read: false, - write: false, - manage: false, - delete: false, - get: false, - update: false, - join: false, - }; - /* eslint-disable */ - if ((permissions & 128) === 128) { - permissionsResult.join = true; - } - if ((permissions & 64) === 64) { - permissionsResult.update = true; - } - if ((permissions & 32) === 32) { - permissionsResult.get = true; - } - if ((permissions & 8) === 8) { - permissionsResult.delete = true; - } - if ((permissions & 4) === 4) { - permissionsResult.manage = true; - } - if ((permissions & 2) === 2) { - permissionsResult.write = true; - } - if ((permissions & 1) === 1) { - permissionsResult.read = true; - } - /* eslint-enable */ - return permissionsResult; - }; - default_1.prototype.parseToken = function (tokenString) { - var _this = this; - var parsed = this._cbor.decodeToken(tokenString); + setToken(token) { + if (token && token.length > 0) + this.token = token; + else + this.token = undefined; + } + getToken() { + return this.token; + } + parseToken(tokenString) { + const parsed = this.cbor.decodeToken(tokenString); if (parsed !== undefined) { - var uuidResourcePermissions = parsed.res.uuid ? Object.keys(parsed.res.uuid) : []; - var channelResourcePermissions = Object.keys(parsed.res.chan); - var groupResourcePermissions = Object.keys(parsed.res.grp); - var uuidPatternPermissions = parsed.pat.uuid ? Object.keys(parsed.pat.uuid) : []; - var channelPatternPermissions = Object.keys(parsed.pat.chan); - var groupPatternPermissions = Object.keys(parsed.pat.grp); - var result_1 = { + const uuidResourcePermissions = parsed.res.uuid ? Object.keys(parsed.res.uuid) : []; + const channelResourcePermissions = Object.keys(parsed.res.chan); + const groupResourcePermissions = Object.keys(parsed.res.grp); + const uuidPatternPermissions = parsed.pat.uuid ? Object.keys(parsed.pat.uuid) : []; + const channelPatternPermissions = Object.keys(parsed.pat.chan); + const groupPatternPermissions = Object.keys(parsed.pat.grp); + const result = { version: parsed.v, timestamp: parsed.t, ttl: parsed.ttl, authorized_uuid: parsed.uuid, + signature: parsed.sig, }; - var uuidResources = uuidResourcePermissions.length > 0; - var channelResources = channelResourcePermissions.length > 0; - var groupResources = groupResourcePermissions.length > 0; + const uuidResources = uuidResourcePermissions.length > 0; + const channelResources = channelResourcePermissions.length > 0; + const groupResources = groupResourcePermissions.length > 0; if (uuidResources || channelResources || groupResources) { - result_1.resources = {}; + result.resources = {}; if (uuidResources) { - result_1.resources.uuids = {}; - uuidResourcePermissions.forEach(function (id) { - result_1.resources.uuids[id] = _this.extractPermissions(parsed.res.uuid[id]); - }); + const uuids = (result.resources.uuids = {}); + uuidResourcePermissions.forEach((id) => (uuids[id] = this.extractPermissions(parsed.res.uuid[id]))); } if (channelResources) { - result_1.resources.channels = {}; - channelResourcePermissions.forEach(function (id) { - result_1.resources.channels[id] = _this.extractPermissions(parsed.res.chan[id]); - }); + const channels = (result.resources.channels = {}); + channelResourcePermissions.forEach((id) => (channels[id] = this.extractPermissions(parsed.res.chan[id]))); } if (groupResources) { - result_1.resources.groups = {}; - groupResourcePermissions.forEach(function (id) { - result_1.resources.groups[id] = _this.extractPermissions(parsed.res.grp[id]); - }); + const groups = (result.resources.groups = {}); + groupResourcePermissions.forEach((id) => (groups[id] = this.extractPermissions(parsed.res.grp[id]))); } } - var uuidPatterns = uuidPatternPermissions.length > 0; - var channelPatterns = channelPatternPermissions.length > 0; - var groupPatterns = groupPatternPermissions.length > 0; + const uuidPatterns = uuidPatternPermissions.length > 0; + const channelPatterns = channelPatternPermissions.length > 0; + const groupPatterns = groupPatternPermissions.length > 0; if (uuidPatterns || channelPatterns || groupPatterns) { - result_1.patterns = {}; + result.patterns = {}; if (uuidPatterns) { - result_1.patterns.uuids = {}; - uuidPatternPermissions.forEach(function (id) { - result_1.patterns.uuids[id] = _this.extractPermissions(parsed.pat.uuid[id]); - }); + const uuids = (result.patterns.uuids = {}); + uuidPatternPermissions.forEach((id) => (uuids[id] = this.extractPermissions(parsed.pat.uuid[id]))); } if (channelPatterns) { - result_1.patterns.channels = {}; - channelPatternPermissions.forEach(function (id) { - result_1.patterns.channels[id] = _this.extractPermissions(parsed.pat.chan[id]); - }); + const channels = (result.patterns.channels = {}); + channelPatternPermissions.forEach((id) => (channels[id] = this.extractPermissions(parsed.pat.chan[id]))); } if (groupPatterns) { - result_1.patterns.groups = {}; - groupPatternPermissions.forEach(function (id) { - result_1.patterns.groups[id] = _this.extractPermissions(parsed.pat.grp[id]); - }); + const groups = (result.patterns.groups = {}); + groupPatternPermissions.forEach((id) => (groups[id] = this.extractPermissions(parsed.pat.grp[id]))); } } - if (Object.keys(parsed.meta).length > 0) { - result_1.meta = parsed.meta; - } - result_1.signature = parsed.sig; - return result_1; + if (parsed.meta && Object.keys(parsed.meta).length > 0) + result.meta = parsed.meta; + return result; } return undefined; - }; - return default_1; -}()); -exports.default = default_1; + } + extractPermissions(permissions) { + const permissionsResult = { + read: false, + write: false, + manage: false, + delete: false, + get: false, + update: false, + join: false, + }; + if ((permissions & 128) === 128) + permissionsResult.join = true; + if ((permissions & 64) === 64) + permissionsResult.update = true; + if ((permissions & 32) === 32) + permissionsResult.get = true; + if ((permissions & 8) === 8) + permissionsResult.delete = true; + if ((permissions & 4) === 4) + permissionsResult.manage = true; + if ((permissions & 2) === 2) + permissionsResult.write = true; + if ((permissions & 1) === 1) + permissionsResult.read = true; + return permissionsResult; + } +} +exports.TokenManager = TokenManager; diff --git a/lib/core/components/uuid.js b/lib/core/components/uuid.js index 18cbb6fd3..deb3c187f 100644 --- a/lib/core/components/uuid.js +++ b/lib/core/components/uuid.js @@ -3,9 +3,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -var lil_uuid_1 = __importDefault(require("lil-uuid")); +const lil_uuid_1 = __importDefault(require("lil-uuid")); exports.default = { - createUUID: function () { + createUUID() { if (lil_uuid_1.default.uuid) { return lil_uuid_1.default.uuid(); } diff --git a/lib/core/constants/categories.js b/lib/core/constants/categories.js index c976cd42a..de7657670 100644 --- a/lib/core/constants/categories.js +++ b/lib/core/constants/categories.js @@ -1,26 +1,22 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -/* */ -exports.default = { - // SDK will announce when the network appears to be connected again. - PNNetworkUpCategory: 'PNNetworkUpCategory', - // SDK will announce when the network appears to down. - PNNetworkDownCategory: 'PNNetworkDownCategory', - // call failed when network was unable to complete the call. - PNNetworkIssuesCategory: 'PNNetworkIssuesCategory', - // network call timed out - PNTimeoutCategory: 'PNTimeoutCategory', - // server responded with bad response - PNBadRequestCategory: 'PNBadRequestCategory', - // server responded with access denied - PNAccessDeniedCategory: 'PNAccessDeniedCategory', - // something strange happened; please check the logs. - PNUnknownCategory: 'PNUnknownCategory', - // on reconnection - PNReconnectedCategory: 'PNReconnectedCategory', - PNConnectedCategory: 'PNConnectedCategory', - PNRequestMessageCountExceededCategory: 'PNRequestMessageCountExceededCategory', - PNDisconnectedCategory: 'PNDisconnectedCategory', - PNConnectionErrorCategory: 'PNConnectionErrorCategory', - PNDisconnectedUnexpectedlyCategory: 'PNDisconnectedUnexpectedlyCategory', -}; +var StatusCategory; +(function (StatusCategory) { + StatusCategory["PNNetworkIssuesCategory"] = "PNNetworkIssuesCategory"; + StatusCategory["PNTimeoutCategory"] = "PNTimeoutCategory"; + StatusCategory["PNCancelledCategory"] = "PNCancelledCategory"; + StatusCategory["PNBadRequestCategory"] = "PNBadRequestCategory"; + StatusCategory["PNAccessDeniedCategory"] = "PNAccessDeniedCategory"; + StatusCategory["PNValidationErrorCategory"] = "PNValidationErrorCategory"; + StatusCategory["PNAcknowledgmentCategory"] = "PNAcknowledgmentCategory"; + StatusCategory["PNUnknownCategory"] = "PNUnknownCategory"; + StatusCategory["PNNetworkUpCategory"] = "PNNetworkUpCategory"; + StatusCategory["PNNetworkDownCategory"] = "PNNetworkDownCategory"; + StatusCategory["PNReconnectedCategory"] = "PNReconnectedCategory"; + StatusCategory["PNConnectedCategory"] = "PNConnectedCategory"; + StatusCategory["PNRequestMessageCountExceededCategory"] = "PNRequestMessageCountExceededCategory"; + StatusCategory["PNDisconnectedCategory"] = "PNDisconnectedCategory"; + StatusCategory["PNConnectionErrorCategory"] = "PNConnectionErrorCategory"; + StatusCategory["PNDisconnectedUnexpectedlyCategory"] = "PNDisconnectedUnexpectedlyCategory"; +})(StatusCategory || (StatusCategory = {})); +exports.default = StatusCategory; diff --git a/lib/core/constants/operations.js b/lib/core/constants/operations.js index 5a934e464..c30b7e919 100644 --- a/lib/core/constants/operations.js +++ b/lib/core/constants/operations.js @@ -1,83 +1,58 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -/* */ -exports.default = { - PNTimeOperation: 'PNTimeOperation', - PNHistoryOperation: 'PNHistoryOperation', - PNDeleteMessagesOperation: 'PNDeleteMessagesOperation', - PNFetchMessagesOperation: 'PNFetchMessagesOperation', - PNMessageCounts: 'PNMessageCountsOperation', - // pubsub - PNSubscribeOperation: 'PNSubscribeOperation', - PNUnsubscribeOperation: 'PNUnsubscribeOperation', - PNPublishOperation: 'PNPublishOperation', - PNSignalOperation: 'PNSignalOperation', - // Actions API - PNAddMessageActionOperation: 'PNAddActionOperation', - PNRemoveMessageActionOperation: 'PNRemoveMessageActionOperation', - PNGetMessageActionsOperation: 'PNGetMessageActionsOperation', - // Objects API - PNCreateUserOperation: 'PNCreateUserOperation', - PNUpdateUserOperation: 'PNUpdateUserOperation', - PNDeleteUserOperation: 'PNDeleteUserOperation', - PNGetUserOperation: 'PNGetUsersOperation', - PNGetUsersOperation: 'PNGetUsersOperation', - PNCreateSpaceOperation: 'PNCreateSpaceOperation', - PNUpdateSpaceOperation: 'PNUpdateSpaceOperation', - PNDeleteSpaceOperation: 'PNDeleteSpaceOperation', - PNGetSpaceOperation: 'PNGetSpacesOperation', - PNGetSpacesOperation: 'PNGetSpacesOperation', - PNGetMembersOperation: 'PNGetMembersOperation', - PNUpdateMembersOperation: 'PNUpdateMembersOperation', - PNGetMembershipsOperation: 'PNGetMembershipsOperation', - PNUpdateMembershipsOperation: 'PNUpdateMembershipsOperation', - // File Upload API v1 - PNListFilesOperation: 'PNListFilesOperation', - PNGenerateUploadUrlOperation: 'PNGenerateUploadUrlOperation', - PNPublishFileOperation: 'PNPublishFileOperation', - PNGetFileUrlOperation: 'PNGetFileUrlOperation', - PNDownloadFileOperation: 'PNDownloadFileOperation', - // Objects API v2 - // UUID - PNGetAllUUIDMetadataOperation: 'PNGetAllUUIDMetadataOperation', - PNGetUUIDMetadataOperation: 'PNGetUUIDMetadataOperation', - PNSetUUIDMetadataOperation: 'PNSetUUIDMetadataOperation', - PNRemoveUUIDMetadataOperation: 'PNRemoveUUIDMetadataOperation', - // channel - PNGetAllChannelMetadataOperation: 'PNGetAllChannelMetadataOperation', - PNGetChannelMetadataOperation: 'PNGetChannelMetadataOperation', - PNSetChannelMetadataOperation: 'PNSetChannelMetadataOperation', - PNRemoveChannelMetadataOperation: 'PNRemoveChannelMetadataOperation', - // member - // PNGetMembersOperation: 'PNGetMembersOperation', - PNSetMembersOperation: 'PNSetMembersOperation', - // PNGetMembershipsOperation: 'PNGetMembersOperation', - PNSetMembershipsOperation: 'PNSetMembershipsOperation', - // push - PNPushNotificationEnabledChannelsOperation: 'PNPushNotificationEnabledChannelsOperation', - PNRemoveAllPushNotificationsOperation: 'PNRemoveAllPushNotificationsOperation', - // - // presence - PNWhereNowOperation: 'PNWhereNowOperation', - PNSetStateOperation: 'PNSetStateOperation', - PNHereNowOperation: 'PNHereNowOperation', - PNGetStateOperation: 'PNGetStateOperation', - PNHeartbeatOperation: 'PNHeartbeatOperation', - // - // channel group - PNChannelGroupsOperation: 'PNChannelGroupsOperation', - PNRemoveGroupOperation: 'PNRemoveGroupOperation', - PNChannelsForGroupOperation: 'PNChannelsForGroupOperation', - PNAddChannelsToGroupOperation: 'PNAddChannelsToGroupOperation', - PNRemoveChannelsFromGroupOperation: 'PNRemoveChannelsFromGroupOperation', - // - // PAM - PNAccessManagerGrant: 'PNAccessManagerGrant', - PNAccessManagerGrantToken: 'PNAccessManagerGrantToken', - PNAccessManagerAudit: 'PNAccessManagerAudit', - PNAccessManagerRevokeToken: 'PNAccessManagerRevokeToken', - // - // subscription utilities - PNHandshakeOperation: 'PNHandshakeOperation', - PNReceiveMessagesOperation: 'PNReceiveMessagesOperation', -}; +var RequestOperation; +(function (RequestOperation) { + RequestOperation["PNPublishOperation"] = "PNPublishOperation"; + RequestOperation["PNSignalOperation"] = "PNSignalOperation"; + RequestOperation["PNSubscribeOperation"] = "PNSubscribeOperation"; + RequestOperation["PNUnsubscribeOperation"] = "PNUnsubscribeOperation"; + RequestOperation["PNWhereNowOperation"] = "PNWhereNowOperation"; + RequestOperation["PNHereNowOperation"] = "PNHereNowOperation"; + RequestOperation["PNGlobalHereNowOperation"] = "PNGlobalHereNowOperation"; + RequestOperation["PNSetStateOperation"] = "PNSetStateOperation"; + RequestOperation["PNGetStateOperation"] = "PNGetStateOperation"; + RequestOperation["PNHeartbeatOperation"] = "PNHeartbeatOperation"; + RequestOperation["PNAddMessageActionOperation"] = "PNAddActionOperation"; + RequestOperation["PNRemoveMessageActionOperation"] = "PNRemoveMessageActionOperation"; + RequestOperation["PNGetMessageActionsOperation"] = "PNGetMessageActionsOperation"; + RequestOperation["PNTimeOperation"] = "PNTimeOperation"; + RequestOperation["PNHistoryOperation"] = "PNHistoryOperation"; + RequestOperation["PNDeleteMessagesOperation"] = "PNDeleteMessagesOperation"; + RequestOperation["PNFetchMessagesOperation"] = "PNFetchMessagesOperation"; + RequestOperation["PNMessageCounts"] = "PNMessageCountsOperation"; + RequestOperation["PNGetAllUUIDMetadataOperation"] = "PNGetAllUUIDMetadataOperation"; + RequestOperation["PNGetUUIDMetadataOperation"] = "PNGetUUIDMetadataOperation"; + RequestOperation["PNSetUUIDMetadataOperation"] = "PNSetUUIDMetadataOperation"; + RequestOperation["PNRemoveUUIDMetadataOperation"] = "PNRemoveUUIDMetadataOperation"; + RequestOperation["PNGetAllChannelMetadataOperation"] = "PNGetAllChannelMetadataOperation"; + RequestOperation["PNGetChannelMetadataOperation"] = "PNGetChannelMetadataOperation"; + RequestOperation["PNSetChannelMetadataOperation"] = "PNSetChannelMetadataOperation"; + RequestOperation["PNRemoveChannelMetadataOperation"] = "PNRemoveChannelMetadataOperation"; + RequestOperation["PNGetMembersOperation"] = "PNGetMembersOperation"; + RequestOperation["PNSetMembersOperation"] = "PNSetMembersOperation"; + RequestOperation["PNGetMembershipsOperation"] = "PNGetMembershipsOperation"; + RequestOperation["PNSetMembershipsOperation"] = "PNSetMembershipsOperation"; + RequestOperation["PNListFilesOperation"] = "PNListFilesOperation"; + RequestOperation["PNGenerateUploadUrlOperation"] = "PNGenerateUploadUrlOperation"; + RequestOperation["PNPublishFileOperation"] = "PNPublishFileOperation"; + RequestOperation["PNPublishFileMessageOperation"] = "PNPublishFileMessageOperation"; + RequestOperation["PNGetFileUrlOperation"] = "PNGetFileUrlOperation"; + RequestOperation["PNDownloadFileOperation"] = "PNDownloadFileOperation"; + RequestOperation["PNDeleteFileOperation"] = "PNDeleteFileOperation"; + RequestOperation["PNAddPushNotificationEnabledChannelsOperation"] = "PNAddPushNotificationEnabledChannelsOperation"; + RequestOperation["PNRemovePushNotificationEnabledChannelsOperation"] = "PNRemovePushNotificationEnabledChannelsOperation"; + RequestOperation["PNPushNotificationEnabledChannelsOperation"] = "PNPushNotificationEnabledChannelsOperation"; + RequestOperation["PNRemoveAllPushNotificationsOperation"] = "PNRemoveAllPushNotificationsOperation"; + RequestOperation["PNChannelGroupsOperation"] = "PNChannelGroupsOperation"; + RequestOperation["PNRemoveGroupOperation"] = "PNRemoveGroupOperation"; + RequestOperation["PNChannelsForGroupOperation"] = "PNChannelsForGroupOperation"; + RequestOperation["PNAddChannelsToGroupOperation"] = "PNAddChannelsToGroupOperation"; + RequestOperation["PNRemoveChannelsFromGroupOperation"] = "PNRemoveChannelsFromGroupOperation"; + RequestOperation["PNAccessManagerGrant"] = "PNAccessManagerGrant"; + RequestOperation["PNAccessManagerGrantToken"] = "PNAccessManagerGrantToken"; + RequestOperation["PNAccessManagerAudit"] = "PNAccessManagerAudit"; + RequestOperation["PNAccessManagerRevokeToken"] = "PNAccessManagerRevokeToken"; + RequestOperation["PNHandshakeOperation"] = "PNHandshakeOperation"; + RequestOperation["PNReceiveMessagesOperation"] = "PNReceiveMessagesOperation"; +})(RequestOperation || (RequestOperation = {})); +exports.default = RequestOperation; diff --git a/lib/core/endpoints/access_manager/audit.js b/lib/core/endpoints/access_manager/audit.js index 2cdd17c8e..e39aeb6d0 100644 --- a/lib/core/endpoints/access_manager/audit.js +++ b/lib/core/endpoints/access_manager/audit.js @@ -1,51 +1,55 @@ "use strict"; -/* */ +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; -var operations_1 = __importDefault(require("../../constants/operations")); -function getOperation() { - return operations_1.default.PNAccessManagerAudit; -} -exports.getOperation = getOperation; -function validateParams(modules) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules) { - var config = modules.config; - return "/v2/auth/audit/sub-key/".concat(config.subscribeKey); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return false; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(modules, incomingParams) { - var channel = incomingParams.channel, channelGroup = incomingParams.channelGroup, _a = incomingParams.authKeys, authKeys = _a === void 0 ? [] : _a; - var params = {}; - if (channel) { - params.channel = channel; +exports.AuditRequest = void 0; +const pubnub_error_1 = require("../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../errors/pubnub-api-error"); +const request_1 = require("../../components/request"); +const operations_1 = __importDefault(require("../../constants/operations")); +const AUTH_KEYS = []; +class AuditRequest extends request_1.AbstractRequest { + constructor(parameters) { + var _a; + var _b; + super(); + this.parameters = parameters; + (_a = (_b = this.parameters).authKeys) !== null && _a !== void 0 ? _a : (_b.authKeys = AUTH_KEYS); } - if (channelGroup) { - params['channel-group'] = channelGroup; + operation() { + return operations_1.default.PNAccessManagerAudit; } - if (authKeys.length > 0) { - params.auth = authKeys.join(','); + validate() { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + return serviceResponse.payload; + }); + } + get path() { + return `/v2/auth/audit/sub-key/${this.parameters.keySet.subscribeKey}`; + } + get queryParameters() { + const { channel, channelGroup, authKeys } = this.parameters; + return Object.assign(Object.assign(Object.assign({}, (channel ? { channel } : {})), (channelGroup ? { 'channel-group': channelGroup } : {})), (authKeys && authKeys.length ? { auth: authKeys.join(',') } : {})); } - return params; -} -exports.prepareParams = prepareParams; -function handleResponse(modules, serverResponse) { - return serverResponse.payload; } -exports.handleResponse = handleResponse; +exports.AuditRequest = AuditRequest; diff --git a/lib/core/endpoints/access_manager/grant.js b/lib/core/endpoints/access_manager/grant.js index e65a390b5..dfb15e873 100644 --- a/lib/core/endpoints/access_manager/grant.js +++ b/lib/core/endpoints/access_manager/grant.js @@ -1,75 +1,79 @@ "use strict"; +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; -/* */ -var operations_1 = __importDefault(require("../../constants/operations")); -function getOperation() { - return operations_1.default.PNAccessManagerGrant; -} -exports.getOperation = getOperation; -function validateParams(modules, incomingParams) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - if (!config.publishKey) - return 'Missing Publish Key'; - if (!config.secretKey) - return 'Missing Secret Key'; - if (incomingParams.uuids != null && !incomingParams.authKeys) { - return 'authKeys are required for grant request on uuids'; +exports.GrantRequest = void 0; +const pubnub_error_1 = require("../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../errors/pubnub-api-error"); +const request_1 = require("../../components/request"); +const operations_1 = __importDefault(require("../../constants/operations")); +const READ_PERMISSION = false; +const WRITE_PERMISSION = false; +const DELETE_PERMISSION = false; +const GET_PERMISSION = false; +const UPDATE_PERMISSION = false; +const MANAGE_PERMISSION = false; +const JOIN_PERMISSION = false; +class GrantRequest extends request_1.AbstractRequest { + constructor(parameters) { + var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k; + var _l, _m, _o, _p, _q, _r, _s, _t, _u, _v; + super(); + this.parameters = parameters; + (_a = (_l = this.parameters).channels) !== null && _a !== void 0 ? _a : (_l.channels = []); + (_b = (_m = this.parameters).channelGroups) !== null && _b !== void 0 ? _b : (_m.channelGroups = []); + (_c = (_o = this.parameters).uuids) !== null && _c !== void 0 ? _c : (_o.uuids = []); + (_d = (_p = this.parameters).read) !== null && _d !== void 0 ? _d : (_p.read = READ_PERMISSION); + (_e = (_q = this.parameters).write) !== null && _e !== void 0 ? _e : (_q.write = WRITE_PERMISSION); + (_f = (_r = this.parameters).delete) !== null && _f !== void 0 ? _f : (_r.delete = DELETE_PERMISSION); + (_g = (_s = this.parameters).get) !== null && _g !== void 0 ? _g : (_s.get = GET_PERMISSION); + (_h = (_t = this.parameters).update) !== null && _h !== void 0 ? _h : (_t.update = UPDATE_PERMISSION); + (_j = (_u = this.parameters).manage) !== null && _j !== void 0 ? _j : (_u.manage = MANAGE_PERMISSION); + (_k = (_v = this.parameters).join) !== null && _k !== void 0 ? _k : (_v.join = JOIN_PERMISSION); } - if (incomingParams.uuids != null && (incomingParams.channels != null || incomingParams.channelGroups != null)) { - return 'Both channel/channelgroup and uuid cannot be used in the same request'; - } -} -exports.validateParams = validateParams; -function getURL(modules) { - var config = modules.config; - return "/v2/auth/grant/sub-key/".concat(config.subscribeKey); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return false; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(modules, incomingParams) { - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a, _b = incomingParams.channelGroups, channelGroups = _b === void 0 ? [] : _b, _c = incomingParams.uuids, uuids = _c === void 0 ? [] : _c, ttl = incomingParams.ttl, _d = incomingParams.read, read = _d === void 0 ? false : _d, _e = incomingParams.write, write = _e === void 0 ? false : _e, _f = incomingParams.manage, manage = _f === void 0 ? false : _f, _g = incomingParams.get, get = _g === void 0 ? false : _g, _h = incomingParams.join, join = _h === void 0 ? false : _h, _j = incomingParams.update, update = _j === void 0 ? false : _j, _k = incomingParams.authKeys, authKeys = _k === void 0 ? [] : _k; - var deleteParam = incomingParams.delete; - var params = {}; - params.r = read ? '1' : '0'; - params.w = write ? '1' : '0'; - params.m = manage ? '1' : '0'; - params.d = deleteParam ? '1' : '0'; - params.g = get ? '1' : '0'; - params.j = join ? '1' : '0'; - params.u = update ? '1' : '0'; - if (channels.length > 0) { - params.channel = channels.join(','); + operation() { + return operations_1.default.PNAccessManagerGrant; } - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); + validate() { + const { keySet: { subscribeKey, publishKey, secretKey }, uuids = [], channels = [], channelGroups = [], authKeys = [], } = this.parameters; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!publishKey) + return 'Missing Publish Key'; + if (!secretKey) + return 'Missing Secret Key'; + if (uuids.length !== 0 && authKeys.length === 0) + return 'authKeys are required for grant request on uuids'; + if (uuids.length && (channels.length !== 0 || channelGroups.length !== 0)) + return 'Both channel/channel group and uuid cannot be used in the same request'; } - if (authKeys.length > 0) { - params.auth = authKeys.join(','); + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + return serviceResponse.payload; + }); } - if (uuids.length > 0) { - params['target-uuid'] = uuids.join(','); + get path() { + return `/v2/auth/grant/sub-key/${this.parameters.keySet.subscribeKey}`; } - if (ttl || ttl === 0) { - params.ttl = ttl; + get queryParameters() { + const { channels, channelGroups, authKeys, uuids, read, write, manage, delete: del, get, join, update, ttl, } = this.parameters; + return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (channels && (channels === null || channels === void 0 ? void 0 : channels.length) > 0 ? { channel: channels.join(',') } : {})), (channelGroups && (channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.length) > 0 ? { 'channel-group': channelGroups.join(',') } : {})), (authKeys && (authKeys === null || authKeys === void 0 ? void 0 : authKeys.length) > 0 ? { auth: authKeys.join(',') } : {})), (uuids && (uuids === null || uuids === void 0 ? void 0 : uuids.length) > 0 ? { 'target-uuid': uuids.join(',') } : {})), { r: read ? '1' : '0', w: write ? '1' : '0', m: manage ? '1' : '0', d: del ? '1' : '0', g: get ? '1' : '0', j: join ? '1' : '0', u: update ? '1' : '0' }), (ttl || ttl === 0 ? { ttl } : {})); } - return params; -} -exports.prepareParams = prepareParams; -function handleResponse() { - return {}; } -exports.handleResponse = handleResponse; +exports.GrantRequest = GrantRequest; diff --git a/lib/core/endpoints/access_manager/grant_token.js b/lib/core/endpoints/access_manager/grant_token.js index 8c9f0b974..2c420331f 100644 --- a/lib/core/endpoints/access_manager/grant_token.js +++ b/lib/core/endpoints/access_manager/grant_token.js @@ -1,263 +1,160 @@ "use strict"; +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.postPayload = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.usePost = exports.postURL = exports.validateParams = exports.extractPermissions = exports.getOperation = void 0; -var operations_1 = __importDefault(require("../../constants/operations")); -function getOperation() { - return operations_1.default.PNAccessManagerGrantToken; -} -exports.getOperation = getOperation; -function hasVspTerms(incomingParams) { - var _a, _b, _c, _d; - var hasAuthorizedUserId = (incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.authorizedUserId) !== undefined; - var hasUserResources = ((_a = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.resources) === null || _a === void 0 ? void 0 : _a.users) !== undefined; - var hasSpaceResources = ((_b = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.resources) === null || _b === void 0 ? void 0 : _b.spaces) !== undefined; - var hasUserPatterns = ((_c = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.patterns) === null || _c === void 0 ? void 0 : _c.users) !== undefined; - var hasSpacePatterns = ((_d = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.patterns) === null || _d === void 0 ? void 0 : _d.spaces) !== undefined; - return hasUserPatterns || hasUserResources || hasSpacePatterns || hasSpaceResources || hasAuthorizedUserId; -} -function extractPermissions(permissions) { - var permissionsResult = 0; - if (permissions.join) { - permissionsResult |= 128; - } - if (permissions.update) { - permissionsResult |= 64; - } - if (permissions.get) { - permissionsResult |= 32; - } - if (permissions.delete) { - permissionsResult |= 8; - } - if (permissions.manage) { - permissionsResult |= 4; - } - if (permissions.write) { - permissionsResult |= 2; - } - if (permissions.read) { - permissionsResult |= 1; - } - return permissionsResult; -} -exports.extractPermissions = extractPermissions; -function prepareMessagePayloadVsp(_modules, _a) { - var ttl = _a.ttl, resources = _a.resources, patterns = _a.patterns, meta = _a.meta, authorizedUserId = _a.authorizedUserId; - var params = { - ttl: 0, - permissions: { - resources: { - channels: {}, - groups: {}, - uuids: {}, - users: {}, - spaces: {}, // not used, needed for api backward compatibility - }, - patterns: { - channels: {}, - groups: {}, - uuids: {}, - users: {}, - spaces: {}, // not used, needed for api backward compatibility - }, - meta: {}, - }, - }; - if (resources) { - var users_1 = resources.users, spaces_1 = resources.spaces, groups_1 = resources.groups; - if (users_1) { - Object.keys(users_1).forEach(function (userID) { - params.permissions.resources.uuids[userID] = extractPermissions(users_1[userID]); +exports.GrantTokenRequest = void 0; +const pubnub_error_1 = require("../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../errors/pubnub-api-error"); +const transport_request_1 = require("../../types/transport-request"); +const request_1 = require("../../components/request"); +const operations_1 = __importDefault(require("../../constants/operations")); +class GrantTokenRequest extends request_1.AbstractRequest { + constructor(parameters) { + var _a, _b; + var _c, _d; + super({ method: transport_request_1.TransportMethod.POST }); + this.parameters = parameters; + (_a = (_c = this.parameters).resources) !== null && _a !== void 0 ? _a : (_c.resources = {}); + (_b = (_d = this.parameters).patterns) !== null && _b !== void 0 ? _b : (_d.patterns = {}); + } + operation() { + return operations_1.default.PNAccessManagerGrantToken; + } + validate() { + var _a, _b, _c, _d, _e, _f; + const { keySet: { subscribeKey, publishKey, secretKey }, resources, patterns, } = this.parameters; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!publishKey) + return 'Missing Publish Key'; + if (!secretKey) + return 'Missing Secret Key'; + if (!resources && !patterns) + return 'Missing either Resources or Patterns'; + if (this.isVspPermissions(this.parameters) && + ('channels' in ((_a = this.parameters.resources) !== null && _a !== void 0 ? _a : {}) || + 'uuids' in ((_b = this.parameters.resources) !== null && _b !== void 0 ? _b : {}) || + 'groups' in ((_c = this.parameters.resources) !== null && _c !== void 0 ? _c : {}) || + 'channels' in ((_d = this.parameters.patterns) !== null && _d !== void 0 ? _d : {}) || + 'uuids' in ((_e = this.parameters.patterns) !== null && _e !== void 0 ? _e : {}) || + 'groups' in ((_f = this.parameters.patterns) !== null && _f !== void 0 ? _f : {}))) + return ('Cannot mix `users`, `spaces` and `authorizedUserId` with `uuids`, `channels`,' + + ' `groups` and `authorized_uuid`'); + let permissionsEmpty = true; + [this.parameters.resources, this.parameters.patterns].forEach((refPerm) => { + Object.keys(refPerm !== null && refPerm !== void 0 ? refPerm : {}).forEach((scope) => { + var _a; + if (refPerm && permissionsEmpty && Object.keys((_a = refPerm[scope]) !== null && _a !== void 0 ? _a : {}).length > 0) { + permissionsEmpty = false; + } }); - } - if (spaces_1) { - Object.keys(spaces_1).forEach(function (spaceId) { - params.permissions.resources.channels[spaceId] = extractPermissions(spaces_1[spaceId]); - }); - } - if (groups_1) { - Object.keys(groups_1).forEach(function (group) { - params.permissions.resources.groups[group] = extractPermissions(groups_1[group]); - }); - } - } - if (patterns) { - var users_2 = patterns.users, spaces_2 = patterns.spaces, groups_2 = patterns.groups; - if (users_2) { - Object.keys(users_2).forEach(function (userId) { - params.permissions.patterns.uuids[userId] = extractPermissions(users_2[userId]); - }); - } - if (spaces_2) { - Object.keys(spaces_2).forEach(function (spaceId) { - params.permissions.patterns.channels[spaceId] = extractPermissions(spaces_2[spaceId]); - }); - } - if (groups_2) { - Object.keys(groups_2).forEach(function (group) { - params.permissions.patterns.groups[group] = extractPermissions(groups_2[group]); - }); - } - } - if (ttl || ttl === 0) { - params.ttl = ttl; - } - if (meta) { - params.permissions.meta = meta; - } - if (authorizedUserId) { - params.permissions.uuid = "".concat(authorizedUserId); // ensure this is a string - } - return params; -} -function prepareMessagePayload(_modules, incomingParams) { - if (hasVspTerms(incomingParams)) { - return prepareMessagePayloadVsp(_modules, incomingParams); + }); + if (permissionsEmpty) + return 'Missing values for either Resources or Patterns'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + return serviceResponse.data.token; + }); + } + get path() { + return `/v3/pam/${this.parameters.keySet.subscribeKey}/grant`; + } + get body() { + const { ttl, meta } = this.parameters; + const body = Object.assign({}, (ttl || ttl === 0 ? { ttl } : {})); + const uuid = this.isVspPermissions(this.parameters) + ? this.parameters.authorizedUserId + : this.parameters.authorized_uuid; + const permissions = {}; + const resourcePermissions = {}; + const patternPermissions = {}; + const mapPermissions = (name, permissionBit, type, permissions) => { + if (!permissions[type]) + permissions[type] = {}; + permissions[type][name] = permissionBit; + }; + const { resources, patterns } = this.parameters; + [resources, patterns].forEach((refPerm, idx) => { + var _a, _b, _c, _d, _e; + const target = idx === 0 ? resourcePermissions : patternPermissions; + let channelsPermissions = {}; + let channelGroupsPermissions = {}; + let uuidsPermissions = {}; + if (!target.channels) + target.channels = {}; + if (!target.groups) + target.groups = {}; + if (!target.uuids) + target.uuids = {}; + if (!target.users) + target.users = {}; + if (!target.spaces) + target.spaces = {}; + if (refPerm) { + if ('spaces' in refPerm || 'users' in refPerm) { + channelsPermissions = (_a = refPerm.spaces) !== null && _a !== void 0 ? _a : {}; + uuidsPermissions = (_b = refPerm.users) !== null && _b !== void 0 ? _b : {}; + } + else if ('channels' in refPerm || 'uuids' in refPerm || 'groups' in refPerm) { + channelsPermissions = (_c = refPerm.channels) !== null && _c !== void 0 ? _c : {}; + channelGroupsPermissions = (_d = refPerm.groups) !== null && _d !== void 0 ? _d : {}; + uuidsPermissions = (_e = refPerm.uuids) !== null && _e !== void 0 ? _e : {}; + } + } + Object.keys(channelsPermissions).forEach((channel) => mapPermissions(channel, this.extractPermissions(channelsPermissions[channel]), 'channels', target)); + Object.keys(channelGroupsPermissions).forEach((groups) => mapPermissions(groups, this.extractPermissions(channelGroupsPermissions[groups]), 'groups', target)); + Object.keys(uuidsPermissions).forEach((uuids) => mapPermissions(uuids, this.extractPermissions(uuidsPermissions[uuids]), 'uuids', target)); + }); + if (uuid) + permissions.uuid = `${uuid}`; + permissions.resources = resourcePermissions; + permissions.patterns = patternPermissions; + permissions.meta = meta !== null && meta !== void 0 ? meta : {}; + body.permissions = permissions; + return JSON.stringify(body); + } + extractPermissions(permissions) { + let permissionsResult = 0; + if ('join' in permissions && permissions.join) + permissionsResult |= 128; + if ('update' in permissions && permissions.update) + permissionsResult |= 64; + if ('get' in permissions && permissions.get) + permissionsResult |= 32; + if ('delete' in permissions && permissions.delete) + permissionsResult |= 8; + if ('manage' in permissions && permissions.manage) + permissionsResult |= 4; + if ('write' in permissions && permissions.write) + permissionsResult |= 2; + if ('read' in permissions && permissions.read) + permissionsResult |= 1; + return permissionsResult; + } + isVspPermissions(parameters) { + var _a, _b, _c, _d; + return ('authorizedUserId' in parameters || + 'spaces' in ((_a = parameters.resources) !== null && _a !== void 0 ? _a : {}) || + 'users' in ((_b = parameters.resources) !== null && _b !== void 0 ? _b : {}) || + 'spaces' in ((_c = parameters.patterns) !== null && _c !== void 0 ? _c : {}) || + 'users' in ((_d = parameters.patterns) !== null && _d !== void 0 ? _d : {})); } - var ttl = incomingParams.ttl, resources = incomingParams.resources, patterns = incomingParams.patterns, meta = incomingParams.meta, authorized_uuid = incomingParams.authorized_uuid; - var params = { - ttl: 0, - permissions: { - resources: { - channels: {}, - groups: {}, - uuids: {}, - users: {}, - spaces: {}, // not used, needed for api backward compatibility - }, - patterns: { - channels: {}, - groups: {}, - uuids: {}, - users: {}, - spaces: {}, // not used, needed for api backward compatibility - }, - meta: {}, - }, - }; - if (resources) { - var uuids_1 = resources.uuids, channels_1 = resources.channels, groups_3 = resources.groups; - if (uuids_1) { - Object.keys(uuids_1).forEach(function (uuid) { - params.permissions.resources.uuids[uuid] = extractPermissions(uuids_1[uuid]); - }); - } - if (channels_1) { - Object.keys(channels_1).forEach(function (channel) { - params.permissions.resources.channels[channel] = extractPermissions(channels_1[channel]); - }); - } - if (groups_3) { - Object.keys(groups_3).forEach(function (group) { - params.permissions.resources.groups[group] = extractPermissions(groups_3[group]); - }); - } - } - if (patterns) { - var uuids_2 = patterns.uuids, channels_2 = patterns.channels, groups_4 = patterns.groups; - if (uuids_2) { - Object.keys(uuids_2).forEach(function (uuid) { - params.permissions.patterns.uuids[uuid] = extractPermissions(uuids_2[uuid]); - }); - } - if (channels_2) { - Object.keys(channels_2).forEach(function (channel) { - params.permissions.patterns.channels[channel] = extractPermissions(channels_2[channel]); - }); - } - if (groups_4) { - Object.keys(groups_4).forEach(function (group) { - params.permissions.patterns.groups[group] = extractPermissions(groups_4[group]); - }); - } - } - if (ttl || ttl === 0) { - params.ttl = ttl; - } - if (meta) { - params.permissions.meta = meta; - } - if (authorized_uuid) { - params.permissions.uuid = "".concat(authorized_uuid); // ensure this is a string - } - return params; -} -function validateParams(modules, incomingParams) { - var _a, _b, _c, _d, _e, _f; - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - if (!config.publishKey) - return 'Missing Publish Key'; - if (!config.secretKey) - return 'Missing Secret Key'; - if (!incomingParams.resources && !incomingParams.patterns) - return 'Missing either Resources or Patterns.'; - var hasAuthorizedUuid = (incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.authorized_uuid) !== undefined; - var hasUuidResources = ((_a = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.resources) === null || _a === void 0 ? void 0 : _a.uuids) !== undefined; - var hasChannelResources = ((_b = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.resources) === null || _b === void 0 ? void 0 : _b.channels) !== undefined; - var hasGroupResources = ((_c = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.resources) === null || _c === void 0 ? void 0 : _c.groups) !== undefined; - var hasUuidPatterns = ((_d = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.patterns) === null || _d === void 0 ? void 0 : _d.uuids) !== undefined; - var hasChannelPatterns = ((_e = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.patterns) === null || _e === void 0 ? void 0 : _e.channels) !== undefined; - var hasGroupPatterns = ((_f = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.patterns) === null || _f === void 0 ? void 0 : _f.groups) !== undefined; - var hasLegacyTerms = hasAuthorizedUuid || - hasUuidResources || - hasUuidPatterns || - hasChannelResources || - hasChannelPatterns || - hasGroupResources || - hasGroupPatterns; - if (hasVspTerms(incomingParams) && hasLegacyTerms) { - return ('Cannot mix `users`, `spaces` and `authorizedUserId` ' + - 'with `uuids`, `channels`, `groups` and `authorized_uuid`'); - } - if ((incomingParams.resources && - (!incomingParams.resources.uuids || Object.keys(incomingParams.resources.uuids).length === 0) && - (!incomingParams.resources.channels || Object.keys(incomingParams.resources.channels).length === 0) && - (!incomingParams.resources.groups || Object.keys(incomingParams.resources.groups).length === 0) && - (!incomingParams.resources.users || Object.keys(incomingParams.resources.users).length === 0) && - (!incomingParams.resources.spaces || Object.keys(incomingParams.resources.spaces).length === 0)) || - (incomingParams.patterns && - (!incomingParams.patterns.uuids || Object.keys(incomingParams.patterns.uuids).length === 0) && - (!incomingParams.patterns.channels || Object.keys(incomingParams.patterns.channels).length === 0) && - (!incomingParams.patterns.groups || Object.keys(incomingParams.patterns.groups).length === 0) && - (!incomingParams.patterns.users || Object.keys(incomingParams.patterns.users).length === 0) && - (!incomingParams.patterns.spaces || Object.keys(incomingParams.patterns.spaces).length === 0))) { - return 'Missing values for either Resources or Patterns.'; - } -} -exports.validateParams = validateParams; -function postURL(modules) { - var config = modules.config; - return "/v3/pam/".concat(config.subscribeKey, "/grant"); -} -exports.postURL = postURL; -function usePost() { - return true; -} -exports.usePost = usePost; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return false; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams() { - return {}; -} -exports.prepareParams = prepareParams; -function postPayload(modules, incomingParams) { - return prepareMessagePayload(modules, incomingParams); -} -exports.postPayload = postPayload; -function handleResponse(modules, response) { - var token = response.data.token; - return token; } -exports.handleResponse = handleResponse; +exports.GrantTokenRequest = GrantTokenRequest; diff --git a/lib/core/endpoints/access_manager/revoke_token.js b/lib/core/endpoints/access_manager/revoke_token.js index 81f04e9e5..648136fcc 100644 --- a/lib/core/endpoints/access_manager/revoke_token.js +++ b/lib/core/endpoints/access_manager/revoke_token.js @@ -1,41 +1,52 @@ "use strict"; -/** */ +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNAccessManagerRevokeToken; }, - validateParams: function (modules, token) { - var secretKey = modules.config.secretKey; - if (!secretKey) { +exports.RevokeTokenRequest = void 0; +const pubnub_error_1 = require("../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../errors/pubnub-api-error"); +const transport_request_1 = require("../../types/transport-request"); +const request_1 = require("../../components/request"); +const operations_1 = __importDefault(require("../../constants/operations")); +const utils_1 = require("../../utils"); +class RevokeTokenRequest extends request_1.AbstractRequest { + constructor(parameters) { + super({ method: transport_request_1.TransportMethod.DELETE }); + this.parameters = parameters; + } + operation() { + return operations_1.default.PNAccessManagerRevokeToken; + } + validate() { + if (!this.parameters.keySet.secretKey) return 'Missing Secret Key'; - } - if (!token) { + if (!this.parameters.token) return "token can't be empty"; - } - }, - getURL: function (_a, token) { - var config = _a.config; - return "/v3/pam/".concat(config.subscribeKey, "/grant/").concat(utils_1.default.encodeString(token)); - }, - useDelete: function () { return true; }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return false; }, - prepareParams: function (_a) { - var config = _a.config; - return ({ - uuid: config.getUUID(), + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + return {}; }); - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - }); }, -}; -exports.default = endpoint; + } + get path() { + const { keySet: { subscribeKey }, token, } = this.parameters; + return `/v3/pam/${subscribeKey}/grant/${(0, utils_1.encodeString)(token)}`; + } +} +exports.RevokeTokenRequest = RevokeTokenRequest; diff --git a/lib/core/endpoints/actions/add_message_action.js b/lib/core/endpoints/actions/add_message_action.js index fef7705ba..6f82bd0d5 100644 --- a/lib/core/endpoints/actions/add_message_action.js +++ b/lib/core/endpoints/actions/add_message_action.js @@ -1,67 +1,69 @@ "use strict"; -/* */ +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.postPayload = exports.prepareParams = exports.isAuthSupported = exports.getRequestHeaders = exports.getRequestTimeout = exports.postURL = exports.usePost = exports.validateParams = exports.getOperation = void 0; -var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -function getOperation() { - return operations_1.default.PNAddMessageActionOperation; -} -exports.getOperation = getOperation; -function validateParams(_a, incomingParams) { - var config = _a.config; - var action = incomingParams.action, channel = incomingParams.channel, messageTimetoken = incomingParams.messageTimetoken; - if (!messageTimetoken) - return 'Missing message timetoken'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - if (!channel) - return 'Missing message channel'; - if (!action) - return 'Missing Action'; - if (!action.value) - return 'Missing Action.value'; - if (!action.type) - return 'Missing Action.type'; - if (action.type.length > 15) - return 'Action.type value exceed maximum length of 15'; -} -exports.validateParams = validateParams; -function usePost() { - return true; -} -exports.usePost = usePost; -function postURL(_a, incomingParams) { - var config = _a.config; - var channel = incomingParams.channel, messageTimetoken = incomingParams.messageTimetoken; - return "/v1/message-actions/".concat(config.subscribeKey, "/channel/").concat(utils_1.default.encodeString(channel), "/message/").concat(messageTimetoken); -} -exports.postURL = postURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function getRequestHeaders() { - return { 'Content-Type': 'application/json' }; -} -exports.getRequestHeaders = getRequestHeaders; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams() { - return {}; -} -exports.prepareParams = prepareParams; -function postPayload(modules, incomingParams) { - return incomingParams.action; -} -exports.postPayload = postPayload; -function handleResponse(modules, addMessageActionResponse) { - return { data: addMessageActionResponse.data }; +exports.AddMessageActionRequest = void 0; +const pubnub_error_1 = require("../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../errors/pubnub-api-error"); +const transport_request_1 = require("../../types/transport-request"); +const request_1 = require("../../components/request"); +const operations_1 = __importDefault(require("../../constants/operations")); +const utils_1 = require("../../utils"); +class AddMessageActionRequest extends request_1.AbstractRequest { + constructor(parameters) { + super({ method: transport_request_1.TransportMethod.POST }); + this.parameters = parameters; + } + operation() { + return operations_1.default.PNAddMessageActionOperation; + } + validate() { + const { keySet: { subscribeKey }, action, channel, messageTimetoken, } = this.parameters; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!channel) + return 'Missing message channel'; + if (!messageTimetoken) + return 'Missing message timetoken'; + if (!action) + return 'Missing Action'; + if (!action.value) + return 'Missing Action.value'; + if (!action.type) + return 'Missing Action.type'; + if (action.type.length > 15) + return 'Action.type value exceed maximum length of 15'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + return { data: serviceResponse.data }; + }); + } + get headers() { + return { 'Content-Type': 'application/json' }; + } + get path() { + const { keySet: { subscribeKey }, channel, messageTimetoken, } = this.parameters; + return `/v1/message-actions/${subscribeKey}/channel/${(0, utils_1.encodeString)(channel)}/message/${messageTimetoken}`; + } + get body() { + return JSON.stringify(this.parameters.action); + } } -exports.handleResponse = handleResponse; +exports.AddMessageActionRequest = AddMessageActionRequest; diff --git a/lib/core/endpoints/actions/get_message_actions.js b/lib/core/endpoints/actions/get_message_actions.js index 669face9a..3a0ffcd86 100644 --- a/lib/core/endpoints/actions/get_message_actions.js +++ b/lib/core/endpoints/actions/get_message_actions.js @@ -1,59 +1,66 @@ "use strict"; +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; -/* */ -var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -function getOperation() { - return operations_1.default.PNGetMessageActionsOperation; -} -exports.getOperation = getOperation; -function validateParams(_a, incomingParams) { - var config = _a.config; - var channel = incomingParams.channel; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - if (!channel) - return 'Missing message channel'; -} -exports.validateParams = validateParams; -function getURL(_a, incomingParams) { - var config = _a.config; - var channel = incomingParams.channel; - return "/v1/message-actions/".concat(config.subscribeKey, "/channel/").concat(utils_1.default.encodeString(channel)); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(modules, incomingParams) { - var limit = incomingParams.limit, start = incomingParams.start, end = incomingParams.end; - var outgoingParams = {}; - if (limit) - outgoingParams.limit = limit; - if (start) - outgoingParams.start = start; - if (end) - outgoingParams.end = end; - return outgoingParams; -} -exports.prepareParams = prepareParams; -function handleResponse(modules, getMessageActionsResponse) { - /** @type GetMessageActionsResponse */ - var response = { data: getMessageActionsResponse.data, start: null, end: null }; - if (response.data.length) { - response.end = response.data[response.data.length - 1].actionTimetoken; - response.start = response.data[0].actionTimetoken; +exports.GetMessageActionsRequest = void 0; +const pubnub_error_1 = require("../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../errors/pubnub-api-error"); +const request_1 = require("../../components/request"); +const operations_1 = __importDefault(require("../../constants/operations")); +const utils_1 = require("../../utils"); +class GetMessageActionsRequest extends request_1.AbstractRequest { + constructor(parameters) { + super(); + this.parameters = parameters; + } + operation() { + return operations_1.default.PNGetMessageActionsOperation; + } + validate() { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + if (!this.parameters.channel) + return 'Missing message channel'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + let start = null; + let end = null; + if (serviceResponse.data.length > 0) { + start = serviceResponse.data[0].actionTimetoken; + end = serviceResponse.data[serviceResponse.data.length - 1].actionTimetoken; + } + return { + data: serviceResponse.data, + more: serviceResponse.more, + start, + end, + }; + }); + } + get path() { + const { keySet: { subscribeKey }, channel, } = this.parameters; + return `/v1/message-actions/${subscribeKey}/channel/${(0, utils_1.encodeString)(channel)}`; + } + get queryParameters() { + const { limit, start, end } = this.parameters; + return Object.assign(Object.assign(Object.assign({}, (start ? { start } : {})), (end ? { end } : {})), (limit ? { limit } : {})); } - return response; } -exports.handleResponse = handleResponse; +exports.GetMessageActionsRequest = GetMessageActionsRequest; diff --git a/lib/core/endpoints/actions/remove_message_action.js b/lib/core/endpoints/actions/remove_message_action.js index b70bc0a18..95d0a1969 100644 --- a/lib/core/endpoints/actions/remove_message_action.js +++ b/lib/core/endpoints/actions/remove_message_action.js @@ -1,53 +1,57 @@ "use strict"; -/* */ +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.useDelete = exports.validateParams = exports.getOperation = void 0; -var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -function getOperation() { - return operations_1.default.PNRemoveMessageActionOperation; -} -exports.getOperation = getOperation; -function validateParams(_a, incomingParams) { - var config = _a.config; - var channel = incomingParams.channel, actionTimetoken = incomingParams.actionTimetoken, messageTimetoken = incomingParams.messageTimetoken; - if (!messageTimetoken) - return 'Missing message timetoken'; - if (!actionTimetoken) - return 'Missing action timetoken'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - if (!channel) - return 'Missing message channel'; -} -exports.validateParams = validateParams; -function useDelete() { - return true; -} -exports.useDelete = useDelete; -function getURL(_a, incomingParams) { - var config = _a.config; - var channel = incomingParams.channel, actionTimetoken = incomingParams.actionTimetoken, messageTimetoken = incomingParams.messageTimetoken; - return "/v1/message-actions/".concat(config.subscribeKey, "/channel/").concat(utils_1.default.encodeString(channel), "/message/").concat(messageTimetoken, "/action/").concat(actionTimetoken); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams() { - return {}; -} -exports.prepareParams = prepareParams; -function handleResponse(modules, removeMessageActionResponse) { - return { data: removeMessageActionResponse.data }; -} -exports.handleResponse = handleResponse; +exports.RemoveMessageAction = void 0; +const pubnub_error_1 = require("../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../errors/pubnub-api-error"); +const transport_request_1 = require("../../types/transport-request"); +const request_1 = require("../../components/request"); +const operations_1 = __importDefault(require("../../constants/operations")); +const utils_1 = require("../../utils"); +class RemoveMessageAction extends request_1.AbstractRequest { + constructor(parameters) { + super({ method: transport_request_1.TransportMethod.DELETE }); + this.parameters = parameters; + } + operation() { + return operations_1.default.PNRemoveMessageActionOperation; + } + validate() { + const { keySet: { subscribeKey }, channel, messageTimetoken, actionTimetoken, } = this.parameters; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!channel) + return 'Missing message action channel'; + if (!messageTimetoken) + return 'Missing message timetoken'; + if (!actionTimetoken) + return 'Missing action timetoken'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + return { data: serviceResponse.data }; + }); + } + get path() { + const { keySet: { subscribeKey }, channel, actionTimetoken, messageTimetoken, } = this.parameters; + return `/v1/message-actions/${subscribeKey}/channel/${(0, utils_1.encodeString)(channel)}/message/${messageTimetoken}/action/${actionTimetoken}`; + } +} +exports.RemoveMessageAction = RemoveMessageAction; diff --git a/lib/core/endpoints/channel_groups/add_channels.js b/lib/core/endpoints/channel_groups/add_channels.js index 7c7426e5b..aa4720f56 100644 --- a/lib/core/endpoints/channel_groups/add_channels.js +++ b/lib/core/endpoints/channel_groups/add_channels.js @@ -1,50 +1,57 @@ "use strict"; +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; -/* */ -var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -function getOperation() { - return operations_1.default.PNAddChannelsToGroupOperation; -} -exports.getOperation = getOperation; -function validateParams(modules, incomingParams) { - var channels = incomingParams.channels, channelGroup = incomingParams.channelGroup; - var config = modules.config; - if (!channelGroup) - return 'Missing Channel Group'; - if (!channels || channels.length === 0) - return 'Missing Channels'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var channelGroup = incomingParams.channelGroup; - var config = modules.config; - return "/v1/channel-registration/sub-key/".concat(config.subscribeKey, "/channel-group/").concat(utils_1.default.encodeString(channelGroup)); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(modules, incomingParams) { - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a; - return { - add: channels.join(','), - }; -} -exports.prepareParams = prepareParams; -function handleResponse() { - return {}; +exports.AddChannelGroupChannelsRequest = void 0; +const pubnub_error_1 = require("../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../errors/pubnub-api-error"); +const request_1 = require("../../components/request"); +const operations_1 = __importDefault(require("../../constants/operations")); +const utils_1 = require("../../utils"); +class AddChannelGroupChannelsRequest extends request_1.AbstractRequest { + constructor(parameters) { + super(); + this.parameters = parameters; + } + operation() { + return operations_1.default.PNAddChannelsToGroupOperation; + } + validate() { + const { keySet: { subscribeKey }, channels, channelGroup, } = this.parameters; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!channelGroup) + return 'Missing Channel Group'; + if (!channels) + return 'Missing channels'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + return {}; + }); + } + get path() { + const { keySet: { subscribeKey }, channelGroup, } = this.parameters; + return `/v1/channel-registration/sub-key/${subscribeKey}/channel-group/${(0, utils_1.encodeString)(channelGroup)}`; + } + get queryParameters() { + return { add: this.parameters.channels.join(',') }; + } } -exports.handleResponse = handleResponse; +exports.AddChannelGroupChannelsRequest = AddChannelGroupChannelsRequest; diff --git a/lib/core/endpoints/channel_groups/delete_group.js b/lib/core/endpoints/channel_groups/delete_group.js index 4ee651809..e1def77fa 100644 --- a/lib/core/endpoints/channel_groups/delete_group.js +++ b/lib/core/endpoints/channel_groups/delete_group.js @@ -1,45 +1,51 @@ "use strict"; -/* */ +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.getRequestTimeout = exports.isAuthSupported = exports.getURL = exports.validateParams = exports.getOperation = void 0; -var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -function getOperation() { - return operations_1.default.PNRemoveGroupOperation; -} -exports.getOperation = getOperation; -function validateParams(modules, incomingParams) { - var channelGroup = incomingParams.channelGroup; - var config = modules.config; - if (!channelGroup) - return 'Missing Channel Group'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var channelGroup = incomingParams.channelGroup; - var config = modules.config; - return "/v1/channel-registration/sub-key/".concat(config.subscribeKey, "/channel-group/").concat(utils_1.default.encodeString(channelGroup), "/remove"); -} -exports.getURL = getURL; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function prepareParams() { - return {}; -} -exports.prepareParams = prepareParams; -function handleResponse() { - return {}; +exports.DeleteChannelGroupRequest = void 0; +const pubnub_error_1 = require("../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../errors/pubnub-api-error"); +const request_1 = require("../../components/request"); +const operations_1 = __importDefault(require("../../constants/operations")); +const utils_1 = require("../../utils"); +class DeleteChannelGroupRequest extends request_1.AbstractRequest { + constructor(parameters) { + super(); + this.parameters = parameters; + } + operation() { + return operations_1.default.PNRemoveGroupOperation; + } + validate() { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + if (!this.parameters.channelGroup) + return 'Missing Channel Group'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + return {}; + }); + } + get path() { + const { keySet: { subscribeKey }, channelGroup, } = this.parameters; + return `/v1/channel-registration/sub-key/${subscribeKey}/channel-group/${(0, utils_1.encodeString)(channelGroup)}/remove`; + } } -exports.handleResponse = handleResponse; +exports.DeleteChannelGroupRequest = DeleteChannelGroupRequest; diff --git a/lib/core/endpoints/channel_groups/list_channels.js b/lib/core/endpoints/channel_groups/list_channels.js index 6e385eec4..247359860 100644 --- a/lib/core/endpoints/channel_groups/list_channels.js +++ b/lib/core/endpoints/channel_groups/list_channels.js @@ -1,47 +1,51 @@ "use strict"; +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; -/* */ -var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -function getOperation() { - return operations_1.default.PNChannelsForGroupOperation; -} -exports.getOperation = getOperation; -function validateParams(modules, incomingParams) { - var channelGroup = incomingParams.channelGroup; - var config = modules.config; - if (!channelGroup) - return 'Missing Channel Group'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var channelGroup = incomingParams.channelGroup; - var config = modules.config; - return "/v1/channel-registration/sub-key/".concat(config.subscribeKey, "/channel-group/").concat(utils_1.default.encodeString(channelGroup)); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams() { - return {}; -} -exports.prepareParams = prepareParams; -function handleResponse(modules, serverResponse) { - return { - channels: serverResponse.payload.channels, - }; +exports.ListChannelGroupChannels = void 0; +const pubnub_error_1 = require("../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../errors/pubnub-api-error"); +const request_1 = require("../../components/request"); +const operations_1 = __importDefault(require("../../constants/operations")); +const utils_1 = require("../../utils"); +class ListChannelGroupChannels extends request_1.AbstractRequest { + constructor(parameters) { + super(); + this.parameters = parameters; + } + operation() { + return operations_1.default.PNChannelsForGroupOperation; + } + validate() { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + if (!this.parameters.channelGroup) + return 'Missing Channel Group'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + return { channels: serviceResponse.payload.channels }; + }); + } + get path() { + const { keySet: { subscribeKey }, channelGroup, } = this.parameters; + return `/v1/channel-registration/sub-key/${subscribeKey}/channel-group/${(0, utils_1.encodeString)(channelGroup)}`; + } } -exports.handleResponse = handleResponse; +exports.ListChannelGroupChannels = ListChannelGroupChannels; diff --git a/lib/core/endpoints/channel_groups/list_groups.js b/lib/core/endpoints/channel_groups/list_groups.js index e97da0540..6e8b8b6b1 100644 --- a/lib/core/endpoints/channel_groups/list_groups.js +++ b/lib/core/endpoints/channel_groups/list_groups.js @@ -1,42 +1,47 @@ "use strict"; -/* */ +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; -var operations_1 = __importDefault(require("../../constants/operations")); -function getOperation() { - return operations_1.default.PNChannelGroupsOperation; -} -exports.getOperation = getOperation; -function validateParams(modules) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules) { - var config = modules.config; - return "/v1/channel-registration/sub-key/".concat(config.subscribeKey, "/channel-group"); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams() { - return {}; -} -exports.prepareParams = prepareParams; -function handleResponse(modules, serverResponse) { - return { - groups: serverResponse.payload.groups, - }; +exports.ListChannelGroupsRequest = void 0; +const pubnub_error_1 = require("../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../errors/pubnub-api-error"); +const request_1 = require("../../components/request"); +const operations_1 = __importDefault(require("../../constants/operations")); +class ListChannelGroupsRequest extends request_1.AbstractRequest { + constructor(parameters) { + super(); + this.parameters = parameters; + } + operation() { + return operations_1.default.PNChannelGroupsOperation; + } + validate() { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + return { groups: serviceResponse.payload.groups }; + }); + } + get path() { + return `/v1/channel-registration/sub-key/${this.parameters.keySet.subscribeKey}/channel-group`; + } } -exports.handleResponse = handleResponse; +exports.ListChannelGroupsRequest = ListChannelGroupsRequest; diff --git a/lib/core/endpoints/channel_groups/remove_channels.js b/lib/core/endpoints/channel_groups/remove_channels.js index 74aa55bcf..cca35a99f 100644 --- a/lib/core/endpoints/channel_groups/remove_channels.js +++ b/lib/core/endpoints/channel_groups/remove_channels.js @@ -1,50 +1,57 @@ "use strict"; +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; -/* */ -var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -function getOperation() { - return operations_1.default.PNRemoveChannelsFromGroupOperation; -} -exports.getOperation = getOperation; -function validateParams(modules, incomingParams) { - var channels = incomingParams.channels, channelGroup = incomingParams.channelGroup; - var config = modules.config; - if (!channelGroup) - return 'Missing Channel Group'; - if (!channels || channels.length === 0) - return 'Missing Channels'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var channelGroup = incomingParams.channelGroup; - var config = modules.config; - return "/v1/channel-registration/sub-key/".concat(config.subscribeKey, "/channel-group/").concat(utils_1.default.encodeString(channelGroup)); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(modules, incomingParams) { - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a; - return { - remove: channels.join(','), - }; -} -exports.prepareParams = prepareParams; -function handleResponse() { - return {}; +exports.RemoveChannelGroupChannelsRequest = void 0; +const pubnub_error_1 = require("../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../errors/pubnub-api-error"); +const request_1 = require("../../components/request"); +const operations_1 = __importDefault(require("../../constants/operations")); +const utils_1 = require("../../utils"); +class RemoveChannelGroupChannelsRequest extends request_1.AbstractRequest { + constructor(parameters) { + super(); + this.parameters = parameters; + } + operation() { + return operations_1.default.PNRemoveChannelsFromGroupOperation; + } + validate() { + const { keySet: { subscribeKey }, channels, channelGroup, } = this.parameters; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!channelGroup) + return 'Missing Channel Group'; + if (!channels) + return 'Missing channels'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + return {}; + }); + } + get path() { + const { keySet: { subscribeKey }, channelGroup, } = this.parameters; + return `/v1/channel-registration/sub-key/${subscribeKey}/channel-group/${(0, utils_1.encodeString)(channelGroup)}`; + } + get queryParameters() { + return { remove: this.parameters.channels.join(',') }; + } } -exports.handleResponse = handleResponse; +exports.RemoveChannelGroupChannelsRequest = RemoveChannelGroupChannelsRequest; diff --git a/lib/core/endpoints/endpoint.js b/lib/core/endpoints/endpoint.js deleted file mode 100644 index 9fa8a127e..000000000 --- a/lib/core/endpoints/endpoint.js +++ /dev/null @@ -1,3 +0,0 @@ -"use strict"; -/** */ -// endpoint definition structure diff --git a/lib/core/endpoints/fetch_messages.js b/lib/core/endpoints/fetch_messages.js index ba1c5e7ec..f3935c84e 100644 --- a/lib/core/endpoints/fetch_messages.js +++ b/lib/core/endpoints/fetch_messages.js @@ -1,120 +1,173 @@ "use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; -/* */ -var operations_1 = __importDefault(require("../constants/operations")); -var utils_1 = __importDefault(require("../utils")); -function __processMessage(modules, message) { - var result = {}; - if (!modules.cryptoModule) { - result.payload = message; - return result; +exports.FetchMessagesRequest = void 0; +const pubnub_error_1 = require("../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../errors/pubnub-api-error"); +const request_1 = require("../components/request"); +const operations_1 = __importDefault(require("../constants/operations")); +const History = __importStar(require("../types/api/history")); +const utils_1 = require("../utils"); +const LOG_VERBOSITY = false; +const INCLUDE_MESSAGE_TYPE = true; +const STRINGIFY_TIMETOKENS = false; +const INCLUDE_UUID = true; +const SINGLE_CHANNEL_MESSAGES_COUNT = 100; +const MULTIPLE_CHANNELS_MESSAGES_COUNT = 25; +class FetchMessagesRequest extends request_1.AbstractRequest { + constructor(parameters) { + var _a, _b, _c, _d, _e; + super(); + this.parameters = parameters; + const includeMessageActions = (_a = parameters.includeMessageActions) !== null && _a !== void 0 ? _a : false; + const defaultCount = parameters.channels.length > 1 || includeMessageActions + ? MULTIPLE_CHANNELS_MESSAGES_COUNT + : SINGLE_CHANNEL_MESSAGES_COUNT; + if (!parameters.count) + parameters.count = defaultCount; + else + parameters.count = Math.min(parameters.count, defaultCount); + if (parameters.includeUuid) + parameters.includeUUID = parameters.includeUuid; + else + (_b = parameters.includeUUID) !== null && _b !== void 0 ? _b : (parameters.includeUUID = INCLUDE_UUID); + (_c = parameters.stringifiedTimeToken) !== null && _c !== void 0 ? _c : (parameters.stringifiedTimeToken = STRINGIFY_TIMETOKENS); + (_d = parameters.includeMessageType) !== null && _d !== void 0 ? _d : (parameters.includeMessageType = INCLUDE_MESSAGE_TYPE); + (_e = parameters.logVerbosity) !== null && _e !== void 0 ? _e : (parameters.logVerbosity = LOG_VERBOSITY); } - try { - var decryptedData = modules.cryptoModule.decrypt(message); - var decryptedPayload = decryptedData instanceof ArrayBuffer ? JSON.parse(new TextDecoder().decode(decryptedData)) : decryptedData; - result.payload = decryptedPayload; - return result; + operation() { + return operations_1.default.PNFetchMessagesOperation; } - catch (e) { - if (modules.config.logVerbosity && console && console.log) - console.log('decryption error', e.message); - result.payload = message; - result.error = "Error while decrypting message content: ".concat(e.message); + validate() { + const { keySet: { subscribeKey }, channels, includeMessageActions, } = this.parameters; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!channels) + return 'Missing channels'; + if (includeMessageActions !== undefined && includeMessageActions && channels.length > 1) + return ('History can return actions data for a single channel only. Either pass a single channel ' + + 'or disable the includeMessageActions flag.'); } - return result; -} -function getOperation() { - return operations_1.default.PNFetchMessagesOperation; -} -exports.getOperation = getOperation; -function validateParams(modules, incomingParams) { - var channels = incomingParams.channels, _a = incomingParams.includeMessageActions, includeMessageActions = _a === void 0 ? false : _a; - var config = modules.config; - if (!channels || channels.length === 0) - return 'Missing channels'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - if (includeMessageActions && channels.length > 1) { - throw new TypeError('History can return actions data for a single channel only. ' + - 'Either pass a single channel or disable the includeMessageActions flag.'); + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + var _a; + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + const responseChannels = (_a = serviceResponse.channels) !== null && _a !== void 0 ? _a : {}; + const channels = {}; + Object.keys(responseChannels).forEach((channel) => { + channels[channel] = responseChannels[channel].map((payload) => { + if (payload.message_type === null) + payload.message_type = History.PubNubMessageType.Message; + const processedPayload = this.processPayload(channel, payload); + const item = { + channel, + timetoken: payload.timetoken, + message: processedPayload.payload, + messageType: payload.message_type, + uuid: payload.uuid, + }; + if (payload.actions) { + const itemWithActions = item; + itemWithActions.actions = payload.actions; + itemWithActions.data = payload.actions; + } + if (payload.meta) + item.meta = payload.meta; + if (processedPayload.error) + item.error = processedPayload.error; + return item; + }); + }); + if (serviceResponse.more) + return { channels, more: serviceResponse.more }; + return { channels }; + }); } -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a, _b = incomingParams.includeMessageActions, includeMessageActions = _b === void 0 ? false : _b; - var config = modules.config; - var endpoint = !includeMessageActions ? 'history' : 'history-with-actions'; - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return "/v3/".concat(endpoint, "/sub-key/").concat(config.subscribeKey, "/channel/").concat(utils_1.default.encodeString(stringifiedChannels)); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(modules, incomingParams) { - var channels = incomingParams.channels, start = incomingParams.start, end = incomingParams.end, includeMessageActions = incomingParams.includeMessageActions, count = incomingParams.count, _a = incomingParams.stringifiedTimeToken, stringifiedTimeToken = _a === void 0 ? false : _a, _b = incomingParams.includeMeta, includeMeta = _b === void 0 ? false : _b, includeUuid = incomingParams.includeUuid, _c = incomingParams.includeUUID, includeUUID = _c === void 0 ? true : _c, _d = incomingParams.includeMessageType, includeMessageType = _d === void 0 ? true : _d; - var outgoingParams = {}; - if (count) { - outgoingParams.max = count; + get path() { + const { keySet: { subscribeKey }, channels, includeMessageActions, } = this.parameters; + const endpoint = !includeMessageActions ? 'history' : 'history-with-actions'; + return `/v3/${endpoint}/sub-key/${subscribeKey}/channel/${(0, utils_1.encodeNames)(channels)}`; } - else { - outgoingParams.max = channels.length > 1 || includeMessageActions === true ? 25 : 100; + get queryParameters() { + const { start, end, count, includeMessageType, includeMeta, includeUUID, stringifiedTimeToken } = this.parameters; + return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ max: count }, (start ? { start } : {})), (end ? { end } : {})), (stringifiedTimeToken ? { string_message_token: 'true' } : {})), (includeMeta !== undefined && includeMeta ? { include_meta: 'true' } : {})), (includeUUID ? { include_uuid: 'true' } : {})), (includeMessageType ? { include_message_type: 'true' } : {})); } - if (start) - outgoingParams.start = start; - if (end) - outgoingParams.end = end; - if (stringifiedTimeToken) - outgoingParams.string_message_token = 'true'; - if (includeMeta) - outgoingParams.include_meta = 'true'; - if (includeUUID && includeUuid !== false) - outgoingParams.include_uuid = 'true'; - if (includeMessageType) - outgoingParams.include_message_type = 'true'; - return outgoingParams; -} -exports.prepareParams = prepareParams; -function handleResponse(modules, serverResponse) { - var response = { - channels: {}, - }; - Object.keys(serverResponse.channels || {}).forEach(function (channelName) { - response.channels[channelName] = []; - (serverResponse.channels[channelName] || []).forEach(function (messageEnvelope) { - var announce = {}; - var processedMessgeResult = __processMessage(modules, messageEnvelope.message); - announce.channel = channelName; - announce.timetoken = messageEnvelope.timetoken; - announce.message = processedMessgeResult.payload; - announce.messageType = messageEnvelope.message_type; - announce.uuid = messageEnvelope.uuid; - if (messageEnvelope.actions) { - announce.actions = messageEnvelope.actions; - // This should be kept for few updates for existing clients consistency. - announce.data = messageEnvelope.actions; - } - if (messageEnvelope.meta) { - announce.meta = messageEnvelope.meta; - } - if (processedMessgeResult.error) - announce.error = processedMessgeResult.error; - response.channels[channelName].push(announce); - }); - }); - if (serverResponse.more) { - response.more = serverResponse.more; + processPayload(channel, payload) { + const { crypto, logVerbosity } = this.parameters; + if (!crypto || typeof payload.message !== 'string') + return { payload: payload.message }; + let decryptedPayload; + let error; + try { + const decryptedData = crypto.decrypt(payload.message); + decryptedPayload = + decryptedData instanceof ArrayBuffer + ? JSON.parse(FetchMessagesRequest.decoder.decode(decryptedData)) + : decryptedData; + } + catch (err) { + if (logVerbosity) + console.log(`decryption error`, err.message); + decryptedPayload = payload.message; + error = `Error while decrypting message content: ${err.message}`; + } + if (!error && + decryptedPayload && + payload.message_type == History.PubNubMessageType.Files && + typeof decryptedPayload === 'object' && + this.isFileMessage(decryptedPayload)) { + const fileMessage = decryptedPayload; + return { + payload: { + message: fileMessage.message, + file: Object.assign(Object.assign({}, fileMessage.file), { url: this.parameters.getFileUrl({ channel, id: fileMessage.file.id, name: fileMessage.file.name }) }), + }, + error, + }; + } + return { payload: decryptedPayload, error }; + } + isFileMessage(payload) { + return payload.file !== undefined; } - return response; } -exports.handleResponse = handleResponse; +exports.FetchMessagesRequest = FetchMessagesRequest; diff --git a/lib/core/endpoints/file_upload/delete_file.js b/lib/core/endpoints/file_upload/delete_file.js index 1e9529932..00f0a40b5 100644 --- a/lib/core/endpoints/file_upload/delete_file.js +++ b/lib/core/endpoints/file_upload/delete_file.js @@ -1,37 +1,55 @@ "use strict"; -/** */ +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNListFilesOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { +exports.DeleteFileRequest = void 0; +const pubnub_error_1 = require("../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../errors/pubnub-api-error"); +const transport_request_1 = require("../../types/transport-request"); +const request_1 = require("../../components/request"); +const operations_1 = __importDefault(require("../../constants/operations")); +const utils_1 = require("../../utils"); +class DeleteFileRequest extends request_1.AbstractRequest { + constructor(parameters) { + super({ method: transport_request_1.TransportMethod.DELETE }); + this.parameters = parameters; + } + operation() { + return operations_1.default.PNDeleteFileOperation; + } + validate() { + const { channel, id, name } = this.parameters; + if (!channel) return "channel can't be empty"; - } - if (!(params === null || params === void 0 ? void 0 : params.id)) { + if (!id) return "file id can't be empty"; - } - if (!(params === null || params === void 0 ? void 0 : params.name)) { + if (!name) return "file name can't be empty"; - } - }, - useDelete: function () { return true; }, - getURL: function (_a, params) { - var config = _a.config; - return "/v1/files/".concat(config.subscribeKey, "/channels/").concat(utils_1.default.encodeString(params.channel), "/files/").concat(params.id, "/").concat(params.name); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function () { return ({}); }, - handleResponse: function (_, response) { return ({ - status: response.status, - }); }, -}; -exports.default = endpoint; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + return serviceResponse; + }); + } + get path() { + const { keySet: { subscribeKey }, id, channel, name, } = this.parameters; + return `/v1/files/${subscribeKey}/channels/${(0, utils_1.encodeString)(channel)}/files/${id}/${name}`; + } +} +exports.DeleteFileRequest = DeleteFileRequest; diff --git a/lib/core/endpoints/file_upload/download_file.js b/lib/core/endpoints/file_upload/download_file.js index 65d4c6ee4..a5d6fae93 100644 --- a/lib/core/endpoints/file_upload/download_file.js +++ b/lib/core/endpoints/file_upload/download_file.js @@ -1,5 +1,4 @@ "use strict"; -// Download_file.js var __awaiter = (this && this.__awaiter) || function (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) { @@ -9,96 +8,55 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "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 (_) 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 }; - } -}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -/** */ -var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNDownloadFileOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { +exports.DownloadFileRequest = void 0; +const request_1 = require("../../components/request"); +const operations_1 = __importDefault(require("../../constants/operations")); +const utils_1 = require("../../utils"); +class DownloadFileRequest extends request_1.AbstractRequest { + constructor(parameters) { + super(); + this.parameters = parameters; + } + operation() { + return operations_1.default.PNDownloadFileOperation; + } + validate() { + const { channel, id, name } = this.parameters; + if (!channel) return "channel can't be empty"; - } - if (!(params === null || params === void 0 ? void 0 : params.name)) { - return "name can't be empty"; - } - if (!(params === null || params === void 0 ? void 0 : params.id)) { - return "id can't be empty"; - } - }, - useGetFile: function () { return true; }, - getFileURL: function (_a, params) { - var config = _a.config; - return "/v1/files/".concat(config.subscribeKey, "/channels/").concat(utils_1.default.encodeString(params.channel), "/files/").concat(params.id, "/").concat(params.name); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - ignoreBody: function () { return true; }, - forceBuffered: function () { return true; }, - prepareParams: function () { return ({}); }, - handleResponse: function (_a, res, params) { - var PubNubFile = _a.PubNubFile, config = _a.config, cryptography = _a.cryptography, cryptoModule = _a.cryptoModule; - return __awaiter(void 0, void 0, void 0, function () { - var body, _b; - var _c, _d; - return __generator(this, function (_e) { - switch (_e.label) { - case 0: - body = res.response.body; - if (!(PubNubFile.supportsEncryptFile && (params.cipherKey || cryptoModule))) return [3 /*break*/, 5]; - if (!(params.cipherKey == null)) return [3 /*break*/, 2]; - return [4 /*yield*/, cryptoModule.decryptFile(PubNubFile.create({ data: body, name: params.name }), PubNubFile)]; - case 1: - _b = (_e.sent()).data; - return [3 /*break*/, 4]; - case 2: return [4 /*yield*/, cryptography.decrypt((_c = params.cipherKey) !== null && _c !== void 0 ? _c : config.cipherKey, body)]; - case 3: - _b = _e.sent(); - _e.label = 4; - case 4: - body = _b; - _e.label = 5; - case 5: return [2 /*return*/, PubNubFile.create({ - data: body, - name: (_d = res.response.name) !== null && _d !== void 0 ? _d : params.name, - mimeType: res.response.type, - })]; - } - }); + if (!id) + return "file id can't be empty"; + if (!name) + return "file name can't be empty"; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const { cipherKey, crypto, cryptography, name, PubNubFile } = this.parameters; + const mimeType = response.headers['content-type']; + let decryptedFile; + let body = response.body; + if (PubNubFile.supportsEncryptFile && (cipherKey || crypto)) { + if (cipherKey && cryptography) + body = yield cryptography.decrypt(cipherKey, body); + else if (!cipherKey && crypto) + decryptedFile = yield crypto.decryptFile(PubNubFile.create({ data: body, name: name, mimeType }), PubNubFile); + } + return (decryptedFile + ? decryptedFile + : PubNubFile.create({ + data: body, + name, + mimeType, + })); }); - }, -}; -exports.default = endpoint; + } + get path() { + const { keySet: { subscribeKey }, channel, id, name, } = this.parameters; + return `/v1/files/${subscribeKey}/channels/${(0, utils_1.encodeString)(channel)}/files/${id}/${name}`; + } +} +exports.DownloadFileRequest = DownloadFileRequest; diff --git a/lib/core/endpoints/file_upload/generate_upload_url.js b/lib/core/endpoints/file_upload/generate_upload_url.js index c35b508b4..4f89bc5c5 100644 --- a/lib/core/endpoints/file_upload/generate_upload_url.js +++ b/lib/core/endpoints/file_upload/generate_upload_url.js @@ -1,39 +1,60 @@ "use strict"; -/** */ +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNGenerateUploadUrlOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { +exports.GenerateFileUploadUrlRequest = void 0; +const pubnub_error_1 = require("../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../errors/pubnub-api-error"); +const transport_request_1 = require("../../types/transport-request"); +const request_1 = require("../../components/request"); +const operations_1 = __importDefault(require("../../constants/operations")); +const utils_1 = require("../../utils"); +class GenerateFileUploadUrlRequest extends request_1.AbstractRequest { + constructor(parameters) { + super({ method: transport_request_1.TransportMethod.POST }); + this.parameters = parameters; + } + operation() { + return operations_1.default.PNGenerateUploadUrlOperation; + } + validate() { + if (!this.parameters.channel) return "channel can't be empty"; - } - if (!(params === null || params === void 0 ? void 0 : params.name)) { - return "name can't be empty"; - } - }, - usePost: function () { return true; }, - postURL: function (_a, params) { - var config = _a.config; - return "/v1/files/".concat(config.subscribeKey, "/channels/").concat(utils_1.default.encodeString(params.channel), "/generate-upload-url"); - }, - postPayload: function (_, params) { return ({ - name: params.name, - }); }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function () { return ({}); }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - file_upload_request: response.file_upload_request, - }); }, -}; -exports.default = endpoint; + if (!this.parameters.name) + return "'name' can't be empty"; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + return { + id: serviceResponse.data.id, + name: serviceResponse.data.name, + url: serviceResponse.file_upload_request.url, + formFields: serviceResponse.file_upload_request.form_fields, + }; + }); + } + get path() { + const { keySet: { subscribeKey }, channel, } = this.parameters; + return `/v1/files/${subscribeKey}/channels/${(0, utils_1.encodeString)(channel)}/generate-upload-url`; + } + get body() { + return JSON.stringify({ name: this.parameters.name }); + } +} +exports.GenerateFileUploadUrlRequest = GenerateFileUploadUrlRequest; diff --git a/lib/core/endpoints/file_upload/get_file_url.js b/lib/core/endpoints/file_upload/get_file_url.js index e7cb0e33e..91879738f 100644 --- a/lib/core/endpoints/file_upload/get_file_url.js +++ b/lib/core/endpoints/file_upload/get_file_url.js @@ -1,41 +1,47 @@ "use strict"; -/** */ +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -var endpoint_1 = require("../../components/endpoint"); -var utils_1 = __importDefault(require("../../utils")); -exports.default = (function (modules, _a) { - var channel = _a.channel, id = _a.id, name = _a.name; - var config = modules.config, networking = modules.networking, tokenManager = modules.tokenManager; - if (!channel) { - throw new endpoint_1.PubNubError('Validation failed, check status for details', (0, endpoint_1.createValidationError)("channel can't be empty")); - } - if (!id) { - throw new endpoint_1.PubNubError('Validation failed, check status for details', (0, endpoint_1.createValidationError)("file id can't be empty")); +exports.GetFileDownloadUrlRequest = void 0; +const transport_request_1 = require("../../types/transport-request"); +const request_1 = require("../../components/request"); +const operations_1 = __importDefault(require("../../constants/operations")); +const utils_1 = require("../../utils"); +class GetFileDownloadUrlRequest extends request_1.AbstractRequest { + constructor(parameters) { + super({ method: transport_request_1.TransportMethod.LOCAL }); + this.parameters = parameters; } - if (!name) { - throw new endpoint_1.PubNubError('Validation failed, check status for details', (0, endpoint_1.createValidationError)("file name can't be empty")); + operation() { + return operations_1.default.PNGetFileUrlOperation; } - var url = "/v1/files/".concat(config.subscribeKey, "/channels/").concat(utils_1.default.encodeString(channel), "/files/").concat(id, "/").concat(name); - var params = {}; - params.uuid = config.getUUID(); - params.pnsdk = (0, endpoint_1.generatePNSDK)(config); - var tokenOrKey = tokenManager.getToken() || config.getAuthKey(); - if (tokenOrKey) { - params.auth = tokenOrKey; + validate() { + const { channel, id, name } = this.parameters; + if (!channel) + return "channel can't be empty"; + if (!id) + return "file id can't be empty"; + if (!name) + return "file name can't be empty"; } - if (config.secretKey) { - (0, endpoint_1.signRequest)(modules, url, params, {}, { - getOperation: function () { return 'PubNubGetFileUrlOperation'; }, + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + return response.url; }); } - var queryParams = Object.keys(params) - .map(function (key) { return "".concat(encodeURIComponent(key), "=").concat(encodeURIComponent(params[key])); }) - .join('&'); - if (queryParams !== '') { - return "".concat(networking.getStandardOrigin()).concat(url, "?").concat(queryParams); + get path() { + const { channel, id, name, keySet: { subscribeKey }, } = this.parameters; + return `/v1/files/${subscribeKey}/channels/${(0, utils_1.encodeString)(channel)}/files/${id}/${name}`; } - return "".concat(networking.getStandardOrigin()).concat(url); -}); +} +exports.GetFileDownloadUrlRequest = GetFileDownloadUrlRequest; diff --git a/lib/core/endpoints/file_upload/list_files.js b/lib/core/endpoints/file_upload/list_files.js index 64b8f28f0..f258331b8 100644 --- a/lib/core/endpoints/file_upload/list_files.js +++ b/lib/core/endpoints/file_upload/list_files.js @@ -1,42 +1,57 @@ "use strict"; -/** */ +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNListFilesOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { +exports.FilesListRequest = void 0; +const pubnub_error_1 = require("../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../errors/pubnub-api-error"); +const request_1 = require("../../components/request"); +const operations_1 = __importDefault(require("../../constants/operations")); +const utils_1 = require("../../utils"); +const LIMIT = 100; +class FilesListRequest extends request_1.AbstractRequest { + constructor(parameters) { + var _a; + var _b; + super(); + this.parameters = parameters; + (_a = (_b = this.parameters).limit) !== null && _a !== void 0 ? _a : (_b.limit = LIMIT); + } + operation() { + return operations_1.default.PNListFilesOperation; + } + validate() { + if (!this.parameters.channel) return "channel can't be empty"; - } - }, - getURL: function (_a, params) { - var config = _a.config; - return "/v1/files/".concat(config.subscribeKey, "/channels/").concat(utils_1.default.encodeString(params.channel), "/files"); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_, params) { - var outParams = {}; - if (params.limit) { - outParams.limit = params.limit; - } - if (params.next) { - outParams.next = params.next; - } - return outParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - next: response.next, - count: response.count, - }); }, -}; -exports.default = endpoint; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + return serviceResponse; + }); + } + get path() { + const { keySet: { subscribeKey }, channel, } = this.parameters; + return `/v1/files/${subscribeKey}/channels/${(0, utils_1.encodeString)(channel)}/files`; + } + get queryParameters() { + const { limit, next } = this.parameters; + return Object.assign({ limit: limit }, (next ? { next } : {})); + } +} +exports.FilesListRequest = FilesListRequest; diff --git a/lib/core/endpoints/file_upload/publish_file.js b/lib/core/endpoints/file_upload/publish_file.js index 9a0a5584a..f69228964 100644 --- a/lib/core/endpoints/file_upload/publish_file.js +++ b/lib/core/endpoints/file_upload/publish_file.js @@ -1,66 +1,70 @@ "use strict"; -/** */ +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -var base64_codec_1 = require("../../components/base64_codec"); -var preparePayload = function (modules, payload) { - var stringifiedPayload = JSON.stringify(payload); - if (modules.cryptoModule) { - var encrypted = modules.cryptoModule.encrypt(stringifiedPayload); - stringifiedPayload = typeof encrypted === 'string' ? encrypted : (0, base64_codec_1.encode)(encrypted); - stringifiedPayload = JSON.stringify(stringifiedPayload); +exports.PublishFileMessageRequest = void 0; +const pubnub_error_1 = require("../../../errors/pubnub-error"); +const request_1 = require("../../components/request"); +const operations_1 = __importDefault(require("../../constants/operations")); +const base64_codec_1 = require("../../components/base64_codec"); +const utils_1 = require("../../utils"); +const STORE_IN_HISTORY = true; +class PublishFileMessageRequest extends request_1.AbstractRequest { + constructor(parameters) { + var _a; + var _b; + super(); + this.parameters = parameters; + (_a = (_b = this.parameters).storeInHistory) !== null && _a !== void 0 ? _a : (_b.storeInHistory = STORE_IN_HISTORY); } - return stringifiedPayload || ''; -}; -var endpoint = { - getOperation: function () { return operations_1.default.PNPublishFileOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { + operation() { + return operations_1.default.PNPublishFileMessageOperation; + } + validate() { + const { channel, fileId, fileName } = this.parameters; + if (!channel) return "channel can't be empty"; - } - if (!(params === null || params === void 0 ? void 0 : params.fileId)) { + if (!fileId) return "file id can't be empty"; - } - if (!(params === null || params === void 0 ? void 0 : params.fileName)) { + if (!fileName) return "file name can't be empty"; - } - }, - getURL: function (modules, params) { - var _a = modules.config, publishKey = _a.publishKey, subscribeKey = _a.subscribeKey; - var message = { - message: params.message, - file: { - name: params.fileName, - id: params.fileId, - }, - }; - var payload = preparePayload(modules, message); - return "/v1/files/publish-file/".concat(publishKey, "/").concat(subscribeKey, "/0/").concat(utils_1.default.encodeString(params.channel), "/0/").concat(utils_1.default.encodeString(payload)); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_, params) { - var outParams = {}; - if (params.ttl) { - outParams.ttl = params.ttl; - } - if (params.storeInHistory !== undefined) { - outParams.store = params.storeInHistory ? '1' : '0'; - } - if (params.meta && typeof params.meta === 'object') { - outParams.meta = JSON.stringify(params.meta); - } - return outParams; - }, - handleResponse: function (_, response) { return ({ - timetoken: response['2'], - }); }, -}; -exports.default = endpoint; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + return { timetoken: serviceResponse[2] }; + }); + } + get path() { + const { message, channel, keySet: { publishKey, subscribeKey }, fileId, fileName, } = this.parameters; + const fileMessage = Object.assign({ file: { + name: fileName, + id: fileId, + } }, (message ? { message } : {})); + return `/v1/files/publish-file/${publishKey}/${subscribeKey}/0/${(0, utils_1.encodeString)(channel)}/0/${(0, utils_1.encodeString)(this.prepareMessagePayload(fileMessage))}`; + } + get queryParameters() { + const { storeInHistory, ttl, meta } = this.parameters; + return Object.assign(Object.assign({ store: storeInHistory ? '1' : '0' }, (ttl ? { ttl } : {})), (meta && typeof meta === 'object' ? { meta: JSON.stringify(meta) } : {})); + } + prepareMessagePayload(payload) { + const { crypto } = this.parameters; + if (!crypto) + return JSON.stringify(payload) || ''; + const encrypted = crypto.encrypt(JSON.stringify(payload)); + return JSON.stringify(typeof encrypted === 'string' ? encrypted : (0, base64_codec_1.encode)(encrypted)); + } +} +exports.PublishFileMessageRequest = PublishFileMessageRequest; diff --git a/lib/core/endpoints/file_upload/send_file.js b/lib/core/endpoints/file_upload/send_file.js index 34aba2be1..ca036ee19 100644 --- a/lib/core/endpoints/file_upload/send_file.js +++ b/lib/core/endpoints/file_upload/send_file.js @@ -8,188 +8,111 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "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 (_) 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 }; - } +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -var endpoint_1 = require("../../components/endpoint"); -var sendFile = function (_a) { - var _this = this; - var generateUploadUrl = _a.generateUploadUrl, publishFile = _a.publishFile, _b = _a.modules, PubNubFile = _b.PubNubFile, config = _b.config, cryptography = _b.cryptography, cryptoModule = _b.cryptoModule, networking = _b.networking; - return function (_a) { - var channel = _a.channel, input = _a.file, message = _a.message, cipherKey = _a.cipherKey, meta = _a.meta, ttl = _a.ttl, storeInHistory = _a.storeInHistory; - return __awaiter(_this, void 0, void 0, function () { - var file, _b, _c, url, formFields, _d, id, name, _e, formFieldsWithMimeType, result, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, e_1, errorBody, reason, retries, wasSuccessful, publishResult, e_2; - return __generator(this, function (_t) { - switch (_t.label) { - case 0: - if (!channel) { - throw new endpoint_1.PubNubError('Validation failed, check status for details', (0, endpoint_1.createValidationError)("channel can't be empty")); - } - if (!input) { - throw new endpoint_1.PubNubError('Validation failed, check status for details', (0, endpoint_1.createValidationError)("file can't be empty")); - } - file = PubNubFile.create(input); - return [4 /*yield*/, generateUploadUrl({ channel: channel, name: file.name })]; - case 1: - _b = _t.sent(), _c = _b.file_upload_request, url = _c.url, formFields = _c.form_fields, _d = _b.data, id = _d.id, name = _d.name; - if (!(PubNubFile.supportsEncryptFile && (cipherKey || cryptoModule))) return [3 /*break*/, 6]; - if (!(cipherKey == null)) return [3 /*break*/, 3]; - return [4 /*yield*/, cryptoModule.encryptFile(file, PubNubFile)]; - case 2: - _e = _t.sent(); - return [3 /*break*/, 5]; - case 3: return [4 /*yield*/, cryptography.encryptFile(cipherKey, file, PubNubFile)]; - case 4: - _e = _t.sent(); - _t.label = 5; - case 5: - file = _e; - _t.label = 6; - case 6: - formFieldsWithMimeType = formFields; - if (file.mimeType) { - formFieldsWithMimeType = formFields.map(function (entry) { - if (entry.key === 'Content-Type') - return { key: entry.key, value: file.mimeType }; - return entry; - }); - } - _t.label = 7; - case 7: - _t.trys.push([7, 21, , 22]); - if (!(PubNubFile.supportsFileUri && input.uri)) return [3 /*break*/, 10]; - _g = (_f = networking).POSTFILE; - _h = [url, formFieldsWithMimeType]; - return [4 /*yield*/, file.toFileUri()]; - case 8: return [4 /*yield*/, _g.apply(_f, _h.concat([_t.sent()]))]; - case 9: - result = _t.sent(); - return [3 /*break*/, 20]; - case 10: - if (!PubNubFile.supportsFile) return [3 /*break*/, 13]; - _k = (_j = networking).POSTFILE; - _l = [url, formFieldsWithMimeType]; - return [4 /*yield*/, file.toFile()]; - case 11: return [4 /*yield*/, _k.apply(_j, _l.concat([_t.sent()]))]; - case 12: - result = _t.sent(); - return [3 /*break*/, 20]; - case 13: - if (!PubNubFile.supportsBuffer) return [3 /*break*/, 16]; - _o = (_m = networking).POSTFILE; - _p = [url, formFieldsWithMimeType]; - return [4 /*yield*/, file.toBuffer()]; - case 14: return [4 /*yield*/, _o.apply(_m, _p.concat([_t.sent()]))]; - case 15: - result = _t.sent(); - return [3 /*break*/, 20]; - case 16: - if (!PubNubFile.supportsBlob) return [3 /*break*/, 19]; - _r = (_q = networking).POSTFILE; - _s = [url, formFieldsWithMimeType]; - return [4 /*yield*/, file.toBlob()]; - case 17: return [4 /*yield*/, _r.apply(_q, _s.concat([_t.sent()]))]; - case 18: - result = _t.sent(); - return [3 /*break*/, 20]; - case 19: throw new Error('Unsupported environment'); - case 20: return [3 /*break*/, 22]; - case 21: - e_1 = _t.sent(); - if (e_1.response && typeof e_1.response.text === 'string') { - errorBody = e_1.response.text; - reason = /(.*)<\/Message>/gi.exec(errorBody); - throw new endpoint_1.PubNubError(reason ? "Upload to bucket failed: ".concat(reason[1]) : 'Upload to bucket failed.', e_1); - } - else { - throw new endpoint_1.PubNubError('Upload to bucket failed.', e_1); - } - return [3 /*break*/, 22]; - case 22: - if (result.status !== 204) { - throw new endpoint_1.PubNubError('Upload to bucket was unsuccessful', result); - } - retries = config.fileUploadPublishRetryLimit; - wasSuccessful = false; - publishResult = { timetoken: '0' }; - _t.label = 23; - case 23: - _t.trys.push([23, 25, , 26]); - return [4 /*yield*/, publishFile({ - channel: channel, - message: message, - fileId: id, - fileName: name, - meta: meta, - storeInHistory: storeInHistory, - ttl: ttl, - })]; - case 24: - /* eslint-disable-next-line no-await-in-loop */ - publishResult = _t.sent(); - wasSuccessful = true; - return [3 /*break*/, 26]; - case 25: - e_2 = _t.sent(); - retries -= 1; - return [3 /*break*/, 26]; - case 26: - if (!wasSuccessful && retries > 0) return [3 /*break*/, 23]; - _t.label = 27; - case 27: - if (!wasSuccessful) { - throw new endpoint_1.PubNubError('Publish failed. You may want to execute that operation manually using pubnub.publishFile', { - channel: channel, - id: id, - name: name, - }); - } - else { - return [2 /*return*/, { - timetoken: publishResult.timetoken, - id: id, - name: name, - }]; - } - return [2 /*return*/]; +exports.SendFileRequest = void 0; +const generate_upload_url_1 = require("./generate_upload_url"); +const pubnub_error_1 = require("../../../errors/pubnub-error"); +const operations_1 = __importDefault(require("../../constants/operations")); +const upload_file_1 = require("./upload-file"); +const pubnub_api_error_1 = require("../../../errors/pubnub-api-error"); +const categories_1 = __importDefault(require("../../constants/categories")); +class SendFileRequest { + constructor(parameters) { + var _a; + this.parameters = parameters; + this.file = (_a = this.parameters.PubNubFile) === null || _a === void 0 ? void 0 : _a.create(parameters.file); + if (!this.file) + throw new Error('File upload error: unable to create File object.'); + } + process() { + return __awaiter(this, void 0, void 0, function* () { + let fileName; + let fileId; + return this.generateFileUploadUrl() + .then((result) => { + fileName = result.name; + fileId = result.id; + return this.uploadFile(result); + }) + .then((result) => { + if (result.status !== 204) { + throw new pubnub_error_1.PubNubError('Upload to bucket was unsuccessful', { + error: true, + statusCode: result.status, + category: categories_1.default.PNUnknownCategory, + operation: operations_1.default.PNPublishFileOperation, + errorData: { message: result.message }, + }); } + }) + .then(() => this.publishFileMessage(fileId, fileName)) + .catch((error) => { + if (error instanceof pubnub_error_1.PubNubError) + throw error; + const apiError = !(error instanceof pubnub_api_error_1.PubNubAPIError) ? pubnub_api_error_1.PubNubAPIError.create(error) : error; + throw new pubnub_error_1.PubNubError('File upload error.', apiError.toStatus(operations_1.default.PNPublishFileOperation)); }); }); - }; -}; -exports.default = (function (deps) { - var f = sendFile(deps); - return function (params, cb) { - var resultP = f(params); - if (typeof cb === 'function') { - resultP.then(function (result) { return cb(null, result); }).catch(function (error) { return cb(error, null); }); - return resultP; - } - return resultP; - }; -}); + } + generateFileUploadUrl() { + return __awaiter(this, void 0, void 0, function* () { + const request = new generate_upload_url_1.GenerateFileUploadUrlRequest(Object.assign(Object.assign({}, this.parameters), { name: this.file.name, keySet: this.parameters.keySet })); + return this.parameters.sendRequest(request); + }); + } + uploadFile(uploadParameters) { + return __awaiter(this, void 0, void 0, function* () { + const { cipherKey, PubNubFile, crypto, cryptography } = this.parameters; + const { id, name, url, formFields } = uploadParameters; + if (this.parameters.PubNubFile.supportsEncryptFile) { + if (!cipherKey && crypto) + this.file = (yield crypto.encryptFile(this.file, PubNubFile)); + else if (cipherKey && cryptography) + this.file = (yield cryptography.encryptFile(cipherKey, this.file, PubNubFile)); + } + return this.parameters.sendRequest(new upload_file_1.UploadFileRequest({ + fileId: id, + fileName: name, + file: this.file, + uploadUrl: url, + formFields, + })); + }); + } + publishFileMessage(fileId, fileName) { + return __awaiter(this, void 0, void 0, function* () { + var _a, _b, _c, _d; + let result = { timetoken: '0' }; + let retries = this.parameters.fileUploadPublishRetryLimit; + let publishError; + let wasSuccessful = false; + do { + try { + result = yield this.parameters.publishFile(Object.assign(Object.assign({}, this.parameters), { fileId, fileName })); + wasSuccessful = true; + } + catch (error) { + if (error instanceof pubnub_error_1.PubNubError) + publishError = error; + retries -= 1; + } + } while (!wasSuccessful && retries > 0); + if (!wasSuccessful) { + throw new pubnub_error_1.PubNubError('Publish failed. You may want to execute that operation manually using pubnub.publishFile', { + error: true, + category: (_b = (_a = publishError.status) === null || _a === void 0 ? void 0 : _a.category) !== null && _b !== void 0 ? _b : categories_1.default.PNUnknownCategory, + statusCode: (_d = (_c = publishError.status) === null || _c === void 0 ? void 0 : _c.statusCode) !== null && _d !== void 0 ? _d : 0, + channel: this.parameters.channel, + id: fileId, + name: fileName, + }); + } + else + return { status: 200, timetoken: result.timetoken, id: fileId, name: fileName }; + }); + } +} +exports.SendFileRequest = SendFileRequest; diff --git a/lib/core/endpoints/file_upload/types.js b/lib/core/endpoints/file_upload/types.js deleted file mode 100644 index 1e44d895d..000000000 --- a/lib/core/endpoints/file_upload/types.js +++ /dev/null @@ -1,2 +0,0 @@ -"use strict"; -/** */ diff --git a/lib/core/endpoints/file_upload/upload-file.js b/lib/core/endpoints/file_upload/upload-file.js new file mode 100644 index 000000000..fefdb0f2b --- /dev/null +++ b/lib/core/endpoints/file_upload/upload-file.js @@ -0,0 +1,68 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.UploadFileRequest = void 0; +const transport_request_1 = require("../../types/transport-request"); +const request_1 = require("../../components/request"); +const operations_1 = __importDefault(require("../../constants/operations")); +class UploadFileRequest extends request_1.AbstractRequest { + constructor(parameters) { + super({ method: transport_request_1.TransportMethod.POST }); + this.parameters = parameters; + const mimeType = parameters.file.mimeType; + if (mimeType) { + parameters.formFields = parameters.formFields.map((entry) => { + if (entry.name === 'Content-Type') + return { name: entry.name, value: mimeType }; + return entry; + }); + } + } + operation() { + return operations_1.default.PNPublishFileOperation; + } + validate() { + const { fileId, fileName, file, uploadUrl } = this.parameters; + if (!fileId) + return "Validation failed: file 'id' can't be empty"; + if (!fileName) + return "Validation failed: file 'name' can't be empty"; + if (!file) + return "Validation failed: 'file' can't be empty"; + if (!uploadUrl) + return "Validation failed: file upload 'url' can't be empty"; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + return { + status: response.status, + message: response.body ? UploadFileRequest.decoder.decode(response.body) : 'OK', + }; + }); + } + request() { + return Object.assign(Object.assign({}, super.request()), { origin: new URL(this.parameters.uploadUrl).origin, timeout: 300 }); + } + get path() { + const { pathname, search } = new URL(this.parameters.uploadUrl); + return `${pathname}${search}`; + } + get body() { + return this.parameters.file; + } + get formData() { + return this.parameters.formFields; + } +} +exports.UploadFileRequest = UploadFileRequest; diff --git a/lib/core/endpoints/history/delete_messages.js b/lib/core/endpoints/history/delete_messages.js index 7a0e4df4a..6556ff638 100644 --- a/lib/core/endpoints/history/delete_messages.js +++ b/lib/core/endpoints/history/delete_messages.js @@ -1,55 +1,56 @@ "use strict"; -/* */ +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.useDelete = exports.validateParams = exports.getOperation = void 0; -var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -function getOperation() { - return operations_1.default.PNDeleteMessagesOperation; -} -exports.getOperation = getOperation; -function validateParams(modules, incomingParams) { - var channel = incomingParams.channel; - var config = modules.config; - if (!channel) - return 'Missing channel'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function useDelete() { - return true; -} -exports.useDelete = useDelete; -function getURL(modules, incomingParams) { - var channel = incomingParams.channel; - var config = modules.config; - return "/v3/history/sub-key/".concat(config.subscribeKey, "/channel/").concat(utils_1.default.encodeString(channel)); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(modules, incomingParams) { - var start = incomingParams.start, end = incomingParams.end; - var outgoingParams = {}; - if (start) - outgoingParams.start = start; - if (end) - outgoingParams.end = end; - return outgoingParams; -} -exports.prepareParams = prepareParams; -function handleResponse(modules, serverResponse) { - return serverResponse.payload; -} -exports.handleResponse = handleResponse; +exports.DeleteMessageRequest = void 0; +const pubnub_error_1 = require("../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../errors/pubnub-api-error"); +const transport_request_1 = require("../../types/transport-request"); +const request_1 = require("../../components/request"); +const operations_1 = __importDefault(require("../../constants/operations")); +const utils_1 = require("../../utils"); +class DeleteMessageRequest extends request_1.AbstractRequest { + constructor(parameters) { + super({ method: transport_request_1.TransportMethod.DELETE }); + this.parameters = parameters; + } + operation() { + return operations_1.default.PNDeleteMessagesOperation; + } + validate() { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + if (!this.parameters.channel) + return 'Missing channel'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + return {}; + }); + } + get path() { + const { keySet: { subscribeKey }, channel, } = this.parameters; + return `/v3/history/sub-key/${subscribeKey}/channel/${(0, utils_1.encodeString)(channel)}`; + } + get queryParameters() { + const { start, end } = this.parameters; + return Object.assign(Object.assign({}, (start ? { start } : {})), (end ? { end } : {})); + } +} +exports.DeleteMessageRequest = DeleteMessageRequest; diff --git a/lib/core/endpoints/history/get_history.js b/lib/core/endpoints/history/get_history.js index 5cbc72ad3..02691675a 100644 --- a/lib/core/endpoints/history/get_history.js +++ b/lib/core/endpoints/history/get_history.js @@ -1,100 +1,107 @@ "use strict"; +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; -/* */ -var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -function __processMessage(modules, message) { - var result = {}; - if (!modules.cryptoModule) { - result.payload = message; - return result; +exports.GetHistoryRequest = void 0; +const pubnub_error_1 = require("../../../errors/pubnub-error"); +const request_1 = require("../../components/request"); +const operations_1 = __importDefault(require("../../constants/operations")); +const utils_1 = require("../../utils"); +const LOG_VERBOSITY = false; +const INCLUDE_METADATA = false; +const STRINGIFY_TIMETOKENS = false; +const MESSAGES_COUNT = 100; +class GetHistoryRequest extends request_1.AbstractRequest { + constructor(parameters) { + var _a, _b, _c; + super(); + this.parameters = parameters; + if (parameters.count) + parameters.count = Math.min(parameters.count, MESSAGES_COUNT); + else + parameters.count = MESSAGES_COUNT; + (_a = parameters.stringifiedTimeToken) !== null && _a !== void 0 ? _a : (parameters.stringifiedTimeToken = STRINGIFY_TIMETOKENS); + (_b = parameters.includeMeta) !== null && _b !== void 0 ? _b : (parameters.includeMeta = INCLUDE_METADATA); + (_c = parameters.logVerbosity) !== null && _c !== void 0 ? _c : (parameters.logVerbosity = LOG_VERBOSITY); } - try { - var decryptedData = modules.cryptoModule.decrypt(message); - var decryptedPayload = decryptedData instanceof ArrayBuffer ? JSON.parse(new TextDecoder().decode(decryptedData)) : decryptedData; - result.payload = decryptedPayload; - return result; + operation() { + return operations_1.default.PNHistoryOperation; } - catch (e) { - if (modules.config.logVerbosity && console && console.log) - console.log('decryption error', e.message); - result.payload = message; - result.error = "Error while decrypting message content: ".concat(e.message); + validate() { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + if (!this.parameters.channel) + return 'Missing channel'; } - return result; -} -function getOperation() { - return operations_1.default.PNHistoryOperation; -} -exports.getOperation = getOperation; -function validateParams(modules, incomingParams) { - var channel = incomingParams.channel; - var config = modules.config; - if (!channel) - return 'Missing channel'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var channel = incomingParams.channel; - var config = modules.config; - return "/v2/history/sub-key/".concat(config.subscribeKey, "/channel/").concat(utils_1.default.encodeString(channel)); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(modules, incomingParams) { - var start = incomingParams.start, end = incomingParams.end, reverse = incomingParams.reverse, _a = incomingParams.count, count = _a === void 0 ? 100 : _a, _b = incomingParams.stringifiedTimeToken, stringifiedTimeToken = _b === void 0 ? false : _b, _c = incomingParams.includeMeta, includeMeta = _c === void 0 ? false : _c; - var outgoingParams = { - include_token: 'true', - }; - outgoingParams.count = count; - if (start) - outgoingParams.start = start; - if (end) - outgoingParams.end = end; - if (stringifiedTimeToken) - outgoingParams.string_message_token = 'true'; - if (reverse != null) - outgoingParams.reverse = reverse.toString(); - if (includeMeta) - outgoingParams.include_meta = 'true'; - return outgoingParams; -} -exports.prepareParams = prepareParams; -function handleResponse(modules, serverResponse) { - var response = { - messages: [], - startTimeToken: serverResponse[1], - endTimeToken: serverResponse[2], - }; - if (Array.isArray(serverResponse[0])) { - serverResponse[0].forEach(function (serverHistoryItem) { - var processedMessgeResult = __processMessage(modules, serverHistoryItem.message); - var item = { - timetoken: serverHistoryItem.timetoken, - entry: processedMessgeResult.payload, + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + const messages = serviceResponse[0]; + const startTimeToken = serviceResponse[1]; + const endTimeToken = serviceResponse[2]; + if (!Array.isArray(messages)) + return { messages: [], startTimeToken, endTimeToken }; + return { + messages: messages.map((payload) => { + const processedPayload = this.processPayload(payload.message); + const item = { + entry: processedPayload.payload, + timetoken: payload.timetoken, + }; + if (processedPayload.error) + item.error = processedPayload.error; + if (payload.meta) + item.meta = payload.meta; + return item; + }), + startTimeToken, + endTimeToken, }; - if (serverHistoryItem.meta) { - item.meta = serverHistoryItem.meta; - } - if (processedMessgeResult.error) - item.error = processedMessgeResult.error; - response.messages.push(item); }); } - return response; + get path() { + const { keySet: { subscribeKey }, channel, } = this.parameters; + return `/v2/history/sub-key/${subscribeKey}/channel/${(0, utils_1.encodeString)(channel)}`; + } + get queryParameters() { + const { start, end, reverse, count, stringifiedTimeToken, includeMeta } = this.parameters; + return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ count: count, include_token: 'true' }, (start ? { start } : {})), (end ? { end } : {})), (stringifiedTimeToken ? { string_message_token: 'true' } : {})), (reverse !== undefined && reverse !== null ? { reverse: reverse.toString() } : {})), (includeMeta ? { include_meta: 'true' } : {})); + } + processPayload(payload) { + const { crypto, logVerbosity } = this.parameters; + if (!crypto || typeof payload !== 'string') + return { payload }; + let decryptedPayload; + let error; + try { + const decryptedData = crypto.decrypt(payload); + decryptedPayload = + decryptedData instanceof ArrayBuffer + ? JSON.parse(GetHistoryRequest.decoder.decode(decryptedData)) + : decryptedData; + } + catch (err) { + if (logVerbosity) + console.log(`decryption error`, err.message); + decryptedPayload = payload; + error = `Error while decrypting message content: ${err.message}`; + } + return { + payload: decryptedPayload, + error, + }; + } } -exports.handleResponse = handleResponse; +exports.GetHistoryRequest = GetHistoryRequest; diff --git a/lib/core/endpoints/history/message_counts.js b/lib/core/endpoints/history/message_counts.js index 7beb84974..66fb9ec0c 100644 --- a/lib/core/endpoints/history/message_counts.js +++ b/lib/core/endpoints/history/message_counts.js @@ -1,78 +1,63 @@ "use strict"; -var __read = (this && this.__read) || function (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; +var __awaiter = (this && this.__awaiter) || function (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()); + }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; -var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -function getOperation() { - return operations_1.default.PNMessageCounts; -} -exports.getOperation = getOperation; -function validateParams(modules, incomingParams) { - var channels = incomingParams.channels, timetoken = incomingParams.timetoken, channelTimetokens = incomingParams.channelTimetokens; - var config = modules.config; - if (!channels) - return 'Missing channel'; - if (timetoken && channelTimetokens) - return 'timetoken and channelTimetokens are incompatible together'; - if (channelTimetokens && channelTimetokens.length > 1 && channels.length !== channelTimetokens.length) { - return 'Length of channelTimetokens and channels do not match'; +exports.MessageCountRequest = void 0; +const pubnub_error_1 = require("../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../errors/pubnub-api-error"); +const request_1 = require("../../components/request"); +const operations_1 = __importDefault(require("../../constants/operations")); +const utils_1 = require("../../utils"); +class MessageCountRequest extends request_1.AbstractRequest { + constructor(parameters) { + super(); + this.parameters = parameters; } - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var channels = incomingParams.channels; - var config = modules.config; - var stringifiedChannels = channels.join(','); - return "/v3/history/sub-key/".concat(config.subscribeKey, "/message-counts/").concat(utils_1.default.encodeString(stringifiedChannels)); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(modules, incomingParams) { - var timetoken = incomingParams.timetoken, channelTimetokens = incomingParams.channelTimetokens; - var outgoingParams = {}; - if (channelTimetokens && channelTimetokens.length === 1) { - var _a = __read(channelTimetokens, 1), tt = _a[0]; - outgoingParams.timetoken = tt; + operation() { + return operations_1.default.PNMessageCounts; } - else if (channelTimetokens) { - outgoingParams.channelsTimetoken = channelTimetokens.join(','); + validate() { + const { keySet: { subscribeKey }, channels, timetoken, channelTimetokens, } = this.parameters; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!channels) + return 'Missing channels'; + if (timetoken && channelTimetokens) + return '`timetoken` and `channelTimetokens` are incompatible together'; + if (!timetoken && !channelTimetokens) + return '`timetoken` or `channelTimetokens` need to be set'; + if (channelTimetokens && channelTimetokens.length > 1 && channelTimetokens.length !== channels.length) + return 'Length of `channelTimetokens` and `channels` do not match'; } - else if (timetoken) { - outgoingParams.timetoken = timetoken; + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + return { channels: serviceResponse.channels }; + }); + } + get path() { + return `/v3/history/sub-key/${this.parameters.keySet.subscribeKey}/message-counts/${(0, utils_1.encodeNames)(this.parameters.channels)}`; + } + get queryParameters() { + let { channelTimetokens } = this.parameters; + if (this.parameters.timetoken) + channelTimetokens = [this.parameters.timetoken]; + return Object.assign(Object.assign({}, (channelTimetokens.length === 1 ? { timetoken: channelTimetokens[0] } : {})), (channelTimetokens.length > 1 ? { channelsTimetoken: channelTimetokens.join(',') } : {})); } - return outgoingParams; -} -exports.prepareParams = prepareParams; -function handleResponse(modules, serverResponse) { - return { channels: serverResponse.channels }; } -exports.handleResponse = handleResponse; +exports.MessageCountRequest = MessageCountRequest; diff --git a/lib/core/endpoints/objects/channel/get.js b/lib/core/endpoints/objects/channel/get.js index b482749af..d7c3b86ed 100644 --- a/lib/core/endpoints/objects/channel/get.js +++ b/lib/core/endpoints/objects/channel/get.js @@ -1,41 +1,59 @@ "use strict"; +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -var operations_1 = __importDefault(require("../../../constants/operations")); -var utils_1 = __importDefault(require("../../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNGetChannelMetadataOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { +exports.GetChannelMetadataRequest = void 0; +const pubnub_error_1 = require("../../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../../errors/pubnub-api-error"); +const request_1 = require("../../../components/request"); +const operations_1 = __importDefault(require("../../../constants/operations")); +const utils_1 = require("../../../utils"); +const INCLUDE_CUSTOM_FIELDS = true; +class GetChannelMetadataRequest extends request_1.AbstractRequest { + constructor(parameters) { + var _a, _b; + var _c; + super(); + this.parameters = parameters; + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_c = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_c.customFields = INCLUDE_CUSTOM_FIELDS); + } + operation() { + return operations_1.default.PNGetChannelMetadataOperation; + } + validate() { + if (!this.parameters.channel) return 'Channel cannot be empty'; - } - }, - getURL: function (_a, params) { - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/channels/").concat(utils_1.default.encodeString(params.channel)); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_, params) { - var _a; - var queryParams = {}; - queryParams.include = ['status', 'type', 'custom']; - if (params === null || params === void 0 ? void 0 : params.include) { - if (((_a = params.include) === null || _a === void 0 ? void 0 : _a.customFields) === false) { - queryParams.include.pop(); + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); } - } - queryParams.include = queryParams.include.join(','); - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - }); }, -}; -exports.default = endpoint; + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + return serviceResponse; + }); + } + get path() { + const { keySet: { subscribeKey }, channel, } = this.parameters; + return `/v2/objects/${subscribeKey}/channels/${(0, utils_1.encodeString)(channel)}`; + } + get queryParameters() { + return { + include: ['status', 'type', ...(this.parameters.include.customFields ? ['custom'] : [])].join(','), + }; + } +} +exports.GetChannelMetadataRequest = GetChannelMetadataRequest; diff --git a/lib/core/endpoints/objects/channel/get_all.js b/lib/core/endpoints/objects/channel/get_all.js index a4e35acd2..228568d77 100644 --- a/lib/core/endpoints/objects/channel/get_all.js +++ b/lib/core/endpoints/objects/channel/get_all.js @@ -1,79 +1,57 @@ "use strict"; -var __read = (this && this.__read) || function (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; +var __awaiter = (this && this.__awaiter) || function (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()); + }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -var operations_1 = __importDefault(require("../../../constants/operations")); -var endpoint = { - getOperation: function () { return operations_1.default.PNGetAllChannelMetadataOperation; }, - validateParams: function () { - // No required parameters. - }, - getURL: function (_a) { - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/channels"); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_modules, params) { - var _a, _b, _c, _d, _e, _f, _g, _h, _j; - var queryParams = {}; - queryParams.include = ['status', 'type']; - if (params === null || params === void 0 ? void 0 : params.include) { - if ((_a = params.include) === null || _a === void 0 ? void 0 : _a.customFields) { - queryParams.include.push('custom'); +exports.GetAllChannelsMetadataRequest = void 0; +const pubnub_error_1 = require("../../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../../errors/pubnub-api-error"); +const request_1 = require("../../../components/request"); +const operations_1 = __importDefault(require("../../../constants/operations")); +const INCLUDE_CUSTOM_FIELDS = false; +const INCLUDE_TOTAL_COUNT = false; +const LIMIT = 100; +class GetAllChannelsMetadataRequest extends request_1.AbstractRequest { + constructor(parameters) { + var _a, _b, _c, _d; + var _e, _f; + super(); + this.parameters = parameters; + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_e = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_e.customFields = INCLUDE_CUSTOM_FIELDS); + (_c = (_f = parameters.include).totalCount) !== null && _c !== void 0 ? _c : (_f.totalCount = INCLUDE_TOTAL_COUNT); + (_d = parameters.limit) !== null && _d !== void 0 ? _d : (parameters.limit = LIMIT); + } + operation() { + return operations_1.default.PNGetAllChannelMetadataOperation; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); } - } - queryParams.include = queryParams.include.join(','); - if ((_b = params === null || params === void 0 ? void 0 : params.include) === null || _b === void 0 ? void 0 : _b.totalCount) { - queryParams.count = (_c = params.include) === null || _c === void 0 ? void 0 : _c.totalCount; - } - if ((_d = params === null || params === void 0 ? void 0 : params.page) === null || _d === void 0 ? void 0 : _d.next) { - queryParams.start = (_e = params.page) === null || _e === void 0 ? void 0 : _e.next; - } - if ((_f = params === null || params === void 0 ? void 0 : params.page) === null || _f === void 0 ? void 0 : _f.prev) { - queryParams.end = (_g = params.page) === null || _g === void 0 ? void 0 : _g.prev; - } - if (params === null || params === void 0 ? void 0 : params.filter) { - queryParams.filter = params.filter; - } - queryParams.limit = (_h = params === null || params === void 0 ? void 0 : params.limit) !== null && _h !== void 0 ? _h : 100; - if (params === null || params === void 0 ? void 0 : params.sort) { - queryParams.sort = Object.entries((_j = params.sort) !== null && _j !== void 0 ? _j : {}).map(function (_a) { - var _b = __read(_a, 2), key = _b[0], value = _b[1]; - if (value === 'asc' || value === 'desc') { - return "".concat(key, ":").concat(value); - } - return key; - }); - } - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - prev: response.prev, - next: response.next, - }); }, -}; -exports.default = endpoint; + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + return serviceResponse; + }); + } + get path() { + return `/v2/objects/${this.parameters.keySet.subscribeKey}/channels`; + } + get queryParameters() { + const { include, page, filter, sort, limit } = this.parameters; + const sorting = Object.entries(sort !== null && sort !== void 0 ? sort : {}).map(([option, order]) => order !== null ? `${option}:${order}` : option); + return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ include: ['status', 'type', ...(include.customFields ? ['custom'] : [])].join(','), count: `${include.totalCount}` }, (filter ? { filter } : {})), ((page === null || page === void 0 ? void 0 : page.next) ? { start: page.next } : {})), ((page === null || page === void 0 ? void 0 : page.prev) ? { end: page.prev } : {})), (limit ? { limit } : {})), (sorting.length ? { sort: sorting } : {})); + } +} +exports.GetAllChannelsMetadataRequest = GetAllChannelsMetadataRequest; diff --git a/lib/core/endpoints/objects/channel/remove.js b/lib/core/endpoints/objects/channel/remove.js index 9942abc80..725b652ad 100644 --- a/lib/core/endpoints/objects/channel/remove.js +++ b/lib/core/endpoints/objects/channel/remove.js @@ -1,32 +1,50 @@ "use strict"; -/** */ +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -var operations_1 = __importDefault(require("../../../constants/operations")); -var utils_1 = __importDefault(require("../../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNRemoveChannelMetadataOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { +exports.RemoveChannelMetadataRequest = void 0; +const pubnub_error_1 = require("../../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../../errors/pubnub-api-error"); +const transport_request_1 = require("../../../types/transport-request"); +const request_1 = require("../../../components/request"); +const operations_1 = __importDefault(require("../../../constants/operations")); +const utils_1 = require("../../../utils"); +class RemoveChannelMetadataRequest extends request_1.AbstractRequest { + constructor(parameters) { + super({ method: transport_request_1.TransportMethod.DELETE }); + this.parameters = parameters; + } + operation() { + return operations_1.default.PNRemoveChannelMetadataOperation; + } + validate() { + if (!this.parameters.channel) return 'Channel cannot be empty'; - } - }, - getURL: function (_a, params) { - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/channels/").concat(utils_1.default.encodeString(params.channel)); - }, - useDelete: function () { return true; }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function () { return ({}); }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - }); }, -}; -exports.default = endpoint; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + return serviceResponse; + }); + } + get path() { + const { keySet: { subscribeKey }, channel, } = this.parameters; + return `/v2/objects/${subscribeKey}/channels/${(0, utils_1.encodeString)(channel)}`; + } +} +exports.RemoveChannelMetadataRequest = RemoveChannelMetadataRequest; diff --git a/lib/core/endpoints/objects/channel/set.js b/lib/core/endpoints/objects/channel/set.js index 881bf48d1..6d903debb 100644 --- a/lib/core/endpoints/objects/channel/set.js +++ b/lib/core/endpoints/objects/channel/set.js @@ -1,47 +1,65 @@ "use strict"; -/** */ +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -var operations_1 = __importDefault(require("../../../constants/operations")); -var utils_1 = __importDefault(require("../../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNSetChannelMetadataOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { +exports.SetChannelMetadataRequest = void 0; +const pubnub_error_1 = require("../../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../../errors/pubnub-api-error"); +const transport_request_1 = require("../../../types/transport-request"); +const request_1 = require("../../../components/request"); +const operations_1 = __importDefault(require("../../../constants/operations")); +const utils_1 = require("../../../utils"); +const INCLUDE_CUSTOM_FIELDS = true; +class SetChannelMetadataRequest extends request_1.AbstractRequest { + constructor(parameters) { + var _a, _b; + var _c; + super({ method: transport_request_1.TransportMethod.PATCH }); + this.parameters = parameters; + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_c = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_c.customFields = INCLUDE_CUSTOM_FIELDS); + } + operation() { + return operations_1.default.PNSetChannelMetadataOperation; + } + validate() { + if (!this.parameters.channel) return 'Channel cannot be empty'; - } - if (!(params === null || params === void 0 ? void 0 : params.data)) { + if (!this.parameters.data) return 'Data cannot be empty'; - } - }, - usePatch: function () { return true; }, - patchURL: function (_a, params) { - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/channels/").concat(utils_1.default.encodeString(params.channel)); - }, - patchPayload: function (_, params) { return params.data; }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_, params) { - var _a; - var queryParams = {}; - queryParams.include = ['status', 'type', 'custom']; - if (params === null || params === void 0 ? void 0 : params.include) { - if (((_a = params.include) === null || _a === void 0 ? void 0 : _a.customFields) === false) { - queryParams.include.pop(); + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); } - } - queryParams.include = queryParams.include.join(','); - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - }); }, -}; -exports.default = endpoint; + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + return serviceResponse; + }); + } + get path() { + const { keySet: { subscribeKey }, channel, } = this.parameters; + return `/v2/objects/${subscribeKey}/channels/${(0, utils_1.encodeString)(channel)}`; + } + get queryParameters() { + return { + include: ['status', 'type', ...(this.parameters.include.customFields ? ['custom'] : [])].join(','), + }; + } + get body() { + return JSON.stringify(this.parameters.data); + } +} +exports.SetChannelMetadataRequest = SetChannelMetadataRequest; diff --git a/lib/core/endpoints/objects/member/get.js b/lib/core/endpoints/objects/member/get.js index e24405856..4329df0fc 100644 --- a/lib/core/endpoints/objects/member/get.js +++ b/lib/core/endpoints/objects/member/get.js @@ -1,98 +1,86 @@ "use strict"; -/** */ -var __read = (this && this.__read) || function (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; +var __awaiter = (this && this.__awaiter) || function (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()); + }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -var operations_1 = __importDefault(require("../../../constants/operations")); -var utils_1 = __importDefault(require("../../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNGetMembersOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { - return 'channel cannot be empty'; - } - }, - getURL: function (_a, params) { - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/channels/").concat(utils_1.default.encodeString(params.channel), "/uuids"); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_modules, params) { - var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p; - var queryParams = {}; - queryParams.include = []; - if (params === null || params === void 0 ? void 0 : params.include) { - if ((_a = params.include) === null || _a === void 0 ? void 0 : _a.statusField) { - queryParams.include.push('status'); - } - if ((_b = params.include) === null || _b === void 0 ? void 0 : _b.customFields) { - queryParams.include.push('custom'); - } - if ((_c = params.include) === null || _c === void 0 ? void 0 : _c.UUIDFields) { - queryParams.include.push('uuid'); - } - if ((_d = params.include) === null || _d === void 0 ? void 0 : _d.customUUIDFields) { - queryParams.include.push('uuid.custom'); - } - if ((_e = params.include) === null || _e === void 0 ? void 0 : _e.UUIDStatusField) { - queryParams.include.push('uuid.status'); - } - if ((_f = params.include) === null || _f === void 0 ? void 0 : _f.UUIDTypeField) { - queryParams.include.push('uuid.type'); +exports.GetChannelMembersRequest = void 0; +const pubnub_error_1 = require("../../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../../errors/pubnub-api-error"); +const request_1 = require("../../../components/request"); +const operations_1 = __importDefault(require("../../../constants/operations")); +const utils_1 = require("../../../utils"); +const INCLUDE_CUSTOM_FIELDS = false; +const INCLUDE_STATUS = false; +const INCLUDE_TOTAL_COUNT = false; +const INCLUDE_UUID_FIELDS = false; +const INCLUDE_UUID_STATUS_FIELD = false; +const INCLUDE_UUID_TYPE_FIELD = false; +const INCLUDE_UUID_CUSTOM_FIELDS = false; +const LIMIT = 100; +class GetChannelMembersRequest extends request_1.AbstractRequest { + constructor(parameters) { + var _a, _b, _c, _d, _e, _f, _g, _h, _j; + var _k, _l, _m, _o, _p, _q, _r; + super(); + this.parameters = parameters; + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_k = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_k.customFields = INCLUDE_CUSTOM_FIELDS); + (_c = (_l = parameters.include).totalCount) !== null && _c !== void 0 ? _c : (_l.totalCount = INCLUDE_TOTAL_COUNT); + (_d = (_m = parameters.include).statusField) !== null && _d !== void 0 ? _d : (_m.statusField = INCLUDE_STATUS); + (_e = (_o = parameters.include).UUIDFields) !== null && _e !== void 0 ? _e : (_o.UUIDFields = INCLUDE_UUID_FIELDS); + (_f = (_p = parameters.include).customUUIDFields) !== null && _f !== void 0 ? _f : (_p.customUUIDFields = INCLUDE_UUID_CUSTOM_FIELDS); + (_g = (_q = parameters.include).UUIDStatusField) !== null && _g !== void 0 ? _g : (_q.UUIDStatusField = INCLUDE_UUID_STATUS_FIELD); + (_h = (_r = parameters.include).UUIDTypeField) !== null && _h !== void 0 ? _h : (_r.UUIDTypeField = INCLUDE_UUID_TYPE_FIELD); + (_j = parameters.limit) !== null && _j !== void 0 ? _j : (parameters.limit = LIMIT); + } + operation() { + return operations_1.default.PNSetMembersOperation; + } + validate() { + if (!this.parameters.channel) + return 'Channel cannot be empty'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); } - } - queryParams.include = queryParams.include.join(','); - if ((_g = params === null || params === void 0 ? void 0 : params.include) === null || _g === void 0 ? void 0 : _g.totalCount) { - queryParams.count = (_h = params.include) === null || _h === void 0 ? void 0 : _h.totalCount; - } - if ((_j = params === null || params === void 0 ? void 0 : params.page) === null || _j === void 0 ? void 0 : _j.next) { - queryParams.start = (_k = params.page) === null || _k === void 0 ? void 0 : _k.next; - } - if ((_l = params === null || params === void 0 ? void 0 : params.page) === null || _l === void 0 ? void 0 : _l.prev) { - queryParams.end = (_m = params.page) === null || _m === void 0 ? void 0 : _m.prev; - } - if (params === null || params === void 0 ? void 0 : params.filter) { - queryParams.filter = params.filter; - } - queryParams.limit = (_o = params === null || params === void 0 ? void 0 : params.limit) !== null && _o !== void 0 ? _o : 100; - if (params === null || params === void 0 ? void 0 : params.sort) { - queryParams.sort = Object.entries((_p = params.sort) !== null && _p !== void 0 ? _p : {}).map(function (_a) { - var _b = __read(_a, 2), key = _b[0], value = _b[1]; - if (value === 'asc' || value === 'desc') { - return "".concat(key, ":").concat(value); - } - return key; - }); - } - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - prev: response.prev, - next: response.next, - }); }, -}; -exports.default = endpoint; + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + return serviceResponse; + }); + } + get path() { + const { keySet: { subscribeKey }, channel, } = this.parameters; + return `/v2/objects/${subscribeKey}/channels/${(0, utils_1.encodeString)(channel)}/uuids`; + } + get queryParameters() { + const { include, page, filter, sort, limit } = this.parameters; + const sorting = Object.entries(sort !== null && sort !== void 0 ? sort : {}).map(([option, order]) => order !== null ? `${option}:${order}` : option); + const includeFlags = []; + if (include.statusField) + includeFlags.push('status'); + if (include.customFields) + includeFlags.push('custom'); + if (include.UUIDFields) + includeFlags.push('uuid'); + if (include.UUIDStatusField) + includeFlags.push('uuid.status'); + if (include.UUIDTypeField) + includeFlags.push('uuid.type'); + if (include.customUUIDFields) + includeFlags.push('uuid.custom'); + return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ count: `${include.totalCount}` }, (includeFlags.length > 0 ? { include: includeFlags.join(',') } : {})), (filter ? { filter } : {})), ((page === null || page === void 0 ? void 0 : page.next) ? { start: page.next } : {})), ((page === null || page === void 0 ? void 0 : page.prev) ? { end: page.prev } : {})), (limit ? { limit } : {})), (sorting.length ? { sort: sorting } : {})); + } +} +exports.GetChannelMembersRequest = GetChannelMembersRequest; diff --git a/lib/core/endpoints/objects/member/set.js b/lib/core/endpoints/objects/member/set.js index 2aa211f29..6d6ba7cb5 100644 --- a/lib/core/endpoints/objects/member/set.js +++ b/lib/core/endpoints/objects/member/set.js @@ -1,116 +1,91 @@ "use strict"; -var __read = (this && this.__read) || function (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; +var __awaiter = (this && this.__awaiter) || function (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()); + }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -var operations_1 = __importDefault(require("../../../constants/operations")); -var utils_1 = __importDefault(require("../../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNSetMembersOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { +exports.SetChannelMembersRequest = void 0; +const pubnub_error_1 = require("../../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../../errors/pubnub-api-error"); +const transport_request_1 = require("../../../types/transport-request"); +const request_1 = require("../../../components/request"); +const operations_1 = __importDefault(require("../../../constants/operations")); +const utils_1 = require("../../../utils"); +const INCLUDE_CUSTOM_FIELDS = false; +const INCLUDE_TOTAL_COUNT = false; +const INCLUDE_UUID_FIELDS = false; +const INCLUDE_UUID_CUSTOM_FIELDS = false; +const LIMIT = 100; +class SetChannelMembersRequest extends request_1.AbstractRequest { + constructor(parameters) { + var _a, _b, _c, _d, _e, _f; + var _g, _h, _j, _k; + super({ method: transport_request_1.TransportMethod.PATCH }); + this.parameters = parameters; + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_g = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_g.customFields = INCLUDE_CUSTOM_FIELDS); + (_c = (_h = parameters.include).totalCount) !== null && _c !== void 0 ? _c : (_h.totalCount = INCLUDE_TOTAL_COUNT); + (_d = (_j = parameters.include).UUIDFields) !== null && _d !== void 0 ? _d : (_j.UUIDFields = INCLUDE_UUID_FIELDS); + (_e = (_k = parameters.include).customUUIDFields) !== null && _e !== void 0 ? _e : (_k.customUUIDFields = INCLUDE_UUID_CUSTOM_FIELDS); + (_f = parameters.limit) !== null && _f !== void 0 ? _f : (parameters.limit = LIMIT); + } + operation() { + return operations_1.default.PNSetMembersOperation; + } + validate() { + const { channel, uuids } = this.parameters; + if (!channel) return 'Channel cannot be empty'; - } - if (!(params === null || params === void 0 ? void 0 : params.uuids) || (params === null || params === void 0 ? void 0 : params.uuids.length) === 0) { + if (!uuids || uuids.length === 0) return 'UUIDs cannot be empty'; - } - }, - usePatch: function () { return true; }, - patchURL: function (_a, params) { - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/channels/").concat(utils_1.default.encodeString(params.channel), "/uuids"); - }, - patchPayload: function (_, params) { - var _a; - return (_a = { - set: [], - delete: [] - }, - _a[params.type] = params.uuids.map(function (uuid) { + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + return serviceResponse; + }); + } + get path() { + const { keySet: { subscribeKey }, channel, } = this.parameters; + return `/v2/objects/${subscribeKey}/channels/${(0, utils_1.encodeString)(channel)}/uuids`; + } + get queryParameters() { + const { include, page, filter, sort, limit } = this.parameters; + const sorting = Object.entries(sort !== null && sort !== void 0 ? sort : {}).map(([option, order]) => order !== null ? `${option}:${order}` : option); + const includeFlags = ['uuid.status', 'uuid.type', 'type']; + if (include.customFields) + includeFlags.push('custom'); + if (include.UUIDFields) + includeFlags.push('uuid'); + if (include.customUUIDFields) + includeFlags.push('uuid.custom'); + return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ count: `${include.totalCount}` }, (includeFlags.length > 0 ? { include: includeFlags.join(',') } : {})), (filter ? { filter } : {})), ((page === null || page === void 0 ? void 0 : page.next) ? { start: page.next } : {})), ((page === null || page === void 0 ? void 0 : page.prev) ? { end: page.prev } : {})), (limit ? { limit } : {})), (sorting.length ? { sort: sorting } : {})); + } + get body() { + const { uuids, type } = this.parameters; + return JSON.stringify({ + [`${type}`]: uuids.map((uuid) => { if (typeof uuid === 'string') { - return { - uuid: { - id: uuid, - }, - }; + return { uuid: { id: uuid } }; } - return { - uuid: { id: uuid.id }, - custom: uuid.custom, - status: uuid.status, - }; - }), - _a); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_modules, params) { - var _a, _b, _c, _d, _e, _f, _g, _h, _j; - var queryParams = {}; - queryParams.include = ['uuid.status', 'uuid.type', 'type']; - if (params === null || params === void 0 ? void 0 : params.include) { - if ((_a = params.include) === null || _a === void 0 ? void 0 : _a.customFields) { - queryParams.include.push('custom'); - } - if ((_b = params.include) === null || _b === void 0 ? void 0 : _b.customUUIDFields) { - queryParams.include.push('uuid.custom'); - } - if ((_c = params.include) === null || _c === void 0 ? void 0 : _c.UUIDFields) { - queryParams.include.push('uuid'); - } - } - queryParams.include = queryParams.include.join(','); - if ((_d = params === null || params === void 0 ? void 0 : params.include) === null || _d === void 0 ? void 0 : _d.totalCount) { - queryParams.count = true; - } - if ((_e = params === null || params === void 0 ? void 0 : params.page) === null || _e === void 0 ? void 0 : _e.next) { - queryParams.start = (_f = params.page) === null || _f === void 0 ? void 0 : _f.next; - } - if ((_g = params === null || params === void 0 ? void 0 : params.page) === null || _g === void 0 ? void 0 : _g.prev) { - queryParams.end = (_h = params.page) === null || _h === void 0 ? void 0 : _h.prev; - } - if (params === null || params === void 0 ? void 0 : params.filter) { - queryParams.filter = params.filter; - } - if (params.limit != null) { - queryParams.limit = params.limit; - } - if (params === null || params === void 0 ? void 0 : params.sort) { - queryParams.sort = Object.entries((_j = params.sort) !== null && _j !== void 0 ? _j : {}).map(function (_a) { - var _b = __read(_a, 2), key = _b[0], value = _b[1]; - if (value === 'asc' || value === 'desc') { - return "".concat(key, ":").concat(value); + else { + return { uuid: { id: uuid.id }, status: uuid.status, custom: uuid.custom }; } - return key; - }); - } - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - prev: response.prev, - next: response.next, - }); }, -}; -exports.default = endpoint; + }), + }); + } +} +exports.SetChannelMembersRequest = SetChannelMembersRequest; diff --git a/lib/core/endpoints/objects/membership/get.js b/lib/core/endpoints/objects/membership/get.js index 0e674260f..bc588f76c 100644 --- a/lib/core/endpoints/objects/membership/get.js +++ b/lib/core/endpoints/objects/membership/get.js @@ -1,96 +1,88 @@ "use strict"; -var __read = (this && this.__read) || function (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; +var __awaiter = (this && this.__awaiter) || function (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()); + }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -var operations_1 = __importDefault(require("../../../constants/operations")); -var utils_1 = __importDefault(require("../../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNGetMembershipsOperation; }, - validateParams: function () { - // No required parameters. - }, - getURL: function (_a, params) { - var _b; - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/uuids/").concat(utils_1.default.encodeString((_b = params === null || params === void 0 ? void 0 : params.uuid) !== null && _b !== void 0 ? _b : config.getUUID()), "/channels"); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_modules, params) { - var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p; - var queryParams = {}; - queryParams.include = []; - if (params === null || params === void 0 ? void 0 : params.include) { - if ((_a = params.include) === null || _a === void 0 ? void 0 : _a.statusField) { - queryParams.include.push('status'); - } - if ((_b = params.include) === null || _b === void 0 ? void 0 : _b.customFields) { - queryParams.include.push('custom'); - } - if ((_c = params.include) === null || _c === void 0 ? void 0 : _c.channelFields) { - queryParams.include.push('channel'); - } - if ((_d = params.include) === null || _d === void 0 ? void 0 : _d.customChannelFields) { - queryParams.include.push('channel.custom'); - } - if ((_e = params.include) === null || _e === void 0 ? void 0 : _e.channelStatusField) { - queryParams.include.push('channel.status'); - } - if ((_f = params.include) === null || _f === void 0 ? void 0 : _f.channelTypeField) { - queryParams.include.push('channel.type'); +exports.GetUUIDMembershipsRequest = void 0; +const pubnub_error_1 = require("../../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../../errors/pubnub-api-error"); +const request_1 = require("../../../components/request"); +const operations_1 = __importDefault(require("../../../constants/operations")); +const utils_1 = require("../../../utils"); +const INCLUDE_CUSTOM_FIELDS = false; +const INCLUDE_STATUS = false; +const INCLUDE_TOTAL_COUNT = false; +const INCLUDE_CHANNEL_FIELDS = false; +const INCLUDE_CHANNEL_STATUS_FIELD = false; +const INCLUDE_CHANNEL_TYPE_FIELD = false; +const INCLUDE_CHANNEL_CUSTOM_FIELDS = false; +const LIMIT = 100; +class GetUUIDMembershipsRequest extends request_1.AbstractRequest { + constructor(parameters) { + var _a, _b, _c, _d, _e, _f, _g, _h, _j; + var _k, _l, _m, _o, _p, _q, _r; + super(); + this.parameters = parameters; + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_k = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_k.customFields = INCLUDE_CUSTOM_FIELDS); + (_c = (_l = parameters.include).totalCount) !== null && _c !== void 0 ? _c : (_l.totalCount = INCLUDE_TOTAL_COUNT); + (_d = (_m = parameters.include).statusField) !== null && _d !== void 0 ? _d : (_m.statusField = INCLUDE_STATUS); + (_e = (_o = parameters.include).channelFields) !== null && _e !== void 0 ? _e : (_o.channelFields = INCLUDE_CHANNEL_FIELDS); + (_f = (_p = parameters.include).customChannelFields) !== null && _f !== void 0 ? _f : (_p.customChannelFields = INCLUDE_CHANNEL_CUSTOM_FIELDS); + (_g = (_q = parameters.include).channelStatusField) !== null && _g !== void 0 ? _g : (_q.channelStatusField = INCLUDE_CHANNEL_STATUS_FIELD); + (_h = (_r = parameters.include).channelTypeField) !== null && _h !== void 0 ? _h : (_r.channelTypeField = INCLUDE_CHANNEL_TYPE_FIELD); + (_j = parameters.limit) !== null && _j !== void 0 ? _j : (parameters.limit = LIMIT); + if (this.parameters.userId) + this.parameters.uuid = this.parameters.userId; + } + operation() { + return operations_1.default.PNGetMembershipsOperation; + } + validate() { + if (!this.parameters.uuid) + return "'uuid' cannot be empty"; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); } - } - queryParams.include = queryParams.include.join(','); - if ((_g = params === null || params === void 0 ? void 0 : params.include) === null || _g === void 0 ? void 0 : _g.totalCount) { - queryParams.count = (_h = params.include) === null || _h === void 0 ? void 0 : _h.totalCount; - } - if ((_j = params === null || params === void 0 ? void 0 : params.page) === null || _j === void 0 ? void 0 : _j.next) { - queryParams.start = (_k = params.page) === null || _k === void 0 ? void 0 : _k.next; - } - if ((_l = params === null || params === void 0 ? void 0 : params.page) === null || _l === void 0 ? void 0 : _l.prev) { - queryParams.end = (_m = params.page) === null || _m === void 0 ? void 0 : _m.prev; - } - if (params === null || params === void 0 ? void 0 : params.filter) { - queryParams.filter = params.filter; - } - queryParams.limit = (_o = params === null || params === void 0 ? void 0 : params.limit) !== null && _o !== void 0 ? _o : 100; - if (params === null || params === void 0 ? void 0 : params.sort) { - queryParams.sort = Object.entries((_p = params.sort) !== null && _p !== void 0 ? _p : {}).map(function (_a) { - var _b = __read(_a, 2), key = _b[0], value = _b[1]; - if (value === 'asc' || value === 'desc') { - return "".concat(key, ":").concat(value); - } - return key; - }); - } - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - prev: response.prev, - next: response.next, - }); }, -}; -exports.default = endpoint; + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + return serviceResponse; + }); + } + get path() { + const { keySet: { subscribeKey }, uuid, } = this.parameters; + return `/v2/objects/${subscribeKey}/uuids/${(0, utils_1.encodeString)(uuid)}/channels`; + } + get queryParameters() { + const { include, page, filter, sort, limit } = this.parameters; + const sorting = Object.entries(sort !== null && sort !== void 0 ? sort : {}).map(([option, order]) => order !== null ? `${option}:${order}` : option); + const includeFlags = []; + if (include.statusField) + includeFlags.push('status'); + if (include.customFields) + includeFlags.push('custom'); + if (include.channelFields) + includeFlags.push('channel'); + if (include.channelStatusField) + includeFlags.push('channel.status'); + if (include.channelTypeField) + includeFlags.push('channel.type'); + if (include.customChannelFields) + includeFlags.push('channel.custom'); + return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ count: `${include.totalCount}` }, (includeFlags.length > 0 ? { include: includeFlags.join(',') } : {})), (filter ? { filter } : {})), ((page === null || page === void 0 ? void 0 : page.next) ? { start: page.next } : {})), ((page === null || page === void 0 ? void 0 : page.prev) ? { end: page.prev } : {})), (limit ? { limit } : {})), (sorting.length ? { sort: sorting } : {})); + } +} +exports.GetUUIDMembershipsRequest = GetUUIDMembershipsRequest; diff --git a/lib/core/endpoints/objects/membership/set.js b/lib/core/endpoints/objects/membership/set.js index 13ea36ef5..10aaa32e3 100644 --- a/lib/core/endpoints/objects/membership/set.js +++ b/lib/core/endpoints/objects/membership/set.js @@ -1,115 +1,93 @@ "use strict"; -/** */ -var __read = (this && this.__read) || function (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; +var __awaiter = (this && this.__awaiter) || function (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()); + }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -var operations_1 = __importDefault(require("../../../constants/operations")); -var utils_1 = __importDefault(require("../../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNSetMembershipsOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channels) || (params === null || params === void 0 ? void 0 : params.channels.length) === 0) { +exports.SetUUIDMembershipsRequest = void 0; +const pubnub_error_1 = require("../../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../../errors/pubnub-api-error"); +const transport_request_1 = require("../../../types/transport-request"); +const request_1 = require("../../../components/request"); +const operations_1 = __importDefault(require("../../../constants/operations")); +const utils_1 = require("../../../utils"); +const INCLUDE_CUSTOM_FIELDS = false; +const INCLUDE_TOTAL_COUNT = false; +const INCLUDE_CHANNEL_FIELDS = false; +const INCLUDE_CHANNEL_CUSTOM_FIELDS = false; +const LIMIT = 100; +class SetUUIDMembershipsRequest extends request_1.AbstractRequest { + constructor(parameters) { + var _a, _b, _c, _d, _e, _f; + var _g, _h, _j, _k; + super({ method: transport_request_1.TransportMethod.PATCH }); + this.parameters = parameters; + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_g = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_g.customFields = INCLUDE_CUSTOM_FIELDS); + (_c = (_h = parameters.include).totalCount) !== null && _c !== void 0 ? _c : (_h.totalCount = INCLUDE_TOTAL_COUNT); + (_d = (_j = parameters.include).channelFields) !== null && _d !== void 0 ? _d : (_j.channelFields = INCLUDE_CHANNEL_FIELDS); + (_e = (_k = parameters.include).customChannelFields) !== null && _e !== void 0 ? _e : (_k.customChannelFields = INCLUDE_CHANNEL_CUSTOM_FIELDS); + (_f = parameters.limit) !== null && _f !== void 0 ? _f : (parameters.limit = LIMIT); + if (this.parameters.userId) + this.parameters.uuid = this.parameters.userId; + } + operation() { + return operations_1.default.PNSetMembershipsOperation; + } + validate() { + const { uuid, channels } = this.parameters; + if (!uuid) + return "'uuid' cannot be empty"; + if (!channels || channels.length === 0) return 'Channels cannot be empty'; - } - }, - usePatch: function () { return true; }, - patchURL: function (_a, params) { - var _b; - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/uuids/").concat(utils_1.default.encodeString((_b = params.uuid) !== null && _b !== void 0 ? _b : config.getUUID()), "/channels"); - }, - patchPayload: function (_, params) { - var _a; - return (_a = { - set: [], - delete: [] - }, - _a[params.type] = params.channels.map(function (channel) { + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + return serviceResponse; + }); + } + get path() { + const { keySet: { subscribeKey }, uuid, } = this.parameters; + return `/v2/objects/${subscribeKey}/uuids/${(0, utils_1.encodeString)(uuid)}/channels`; + } + get queryParameters() { + const { include, page, filter, sort, limit } = this.parameters; + const sorting = Object.entries(sort !== null && sort !== void 0 ? sort : {}).map(([option, order]) => order !== null ? `${option}:${order}` : option); + const includeFlags = ['channel.status', 'channel.type', 'status']; + if (include.customFields) + includeFlags.push('custom'); + if (include.channelFields) + includeFlags.push('channel'); + if (include.customChannelFields) + includeFlags.push('channel.custom'); + return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ count: `${include.totalCount}` }, (includeFlags.length > 0 ? { include: includeFlags.join(',') } : {})), (filter ? { filter } : {})), ((page === null || page === void 0 ? void 0 : page.next) ? { start: page.next } : {})), ((page === null || page === void 0 ? void 0 : page.prev) ? { end: page.prev } : {})), (limit ? { limit } : {})), (sorting.length ? { sort: sorting } : {})); + } + get body() { + const { channels, type } = this.parameters; + return JSON.stringify({ + [`${type}`]: channels.map((channel) => { if (typeof channel === 'string') { - return { - channel: { - id: channel, - }, - }; + return { channel: { id: channel } }; } - return { - channel: { id: channel.id }, - custom: channel.custom, - status: channel.status, - }; - }), - _a); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_modules, params) { - var _a, _b, _c, _d, _e, _f, _g, _h, _j; - var queryParams = {}; - queryParams.include = ['channel.status', 'channel.type', 'status']; - if (params === null || params === void 0 ? void 0 : params.include) { - if ((_a = params.include) === null || _a === void 0 ? void 0 : _a.customFields) { - queryParams.include.push('custom'); - } - if ((_b = params.include) === null || _b === void 0 ? void 0 : _b.customChannelFields) { - queryParams.include.push('channel.custom'); - } - if ((_c = params.include) === null || _c === void 0 ? void 0 : _c.channelFields) { - queryParams.include.push('channel'); - } - } - queryParams.include = queryParams.include.join(','); - if ((_d = params === null || params === void 0 ? void 0 : params.include) === null || _d === void 0 ? void 0 : _d.totalCount) { - queryParams.count = true; - } - if ((_e = params === null || params === void 0 ? void 0 : params.page) === null || _e === void 0 ? void 0 : _e.next) { - queryParams.start = (_f = params.page) === null || _f === void 0 ? void 0 : _f.next; - } - if ((_g = params === null || params === void 0 ? void 0 : params.page) === null || _g === void 0 ? void 0 : _g.prev) { - queryParams.end = (_h = params.page) === null || _h === void 0 ? void 0 : _h.prev; - } - if (params === null || params === void 0 ? void 0 : params.filter) { - queryParams.filter = params.filter; - } - if (params.limit != null) { - queryParams.limit = params.limit; - } - if (params === null || params === void 0 ? void 0 : params.sort) { - queryParams.sort = Object.entries((_j = params.sort) !== null && _j !== void 0 ? _j : {}).map(function (_a) { - var _b = __read(_a, 2), key = _b[0], value = _b[1]; - if (value === 'asc' || value === 'desc') { - return "".concat(key, ":").concat(value); + else { + return { channel: { id: channel.id }, status: channel.status, custom: channel.custom }; } - return key; - }); - } - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - prev: response.prev, - next: response.next, - }); }, -}; -exports.default = endpoint; + }), + }); + } +} +exports.SetUUIDMembershipsRequest = SetUUIDMembershipsRequest; diff --git a/lib/core/endpoints/objects/uuid/get.js b/lib/core/endpoints/objects/uuid/get.js index 36e1293d6..56383f4dd 100644 --- a/lib/core/endpoints/objects/uuid/get.js +++ b/lib/core/endpoints/objects/uuid/get.js @@ -1,43 +1,60 @@ "use strict"; -/** */ +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -var operations_1 = __importDefault(require("../../../constants/operations")); -var utils_1 = __importDefault(require("../../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNGetUUIDMetadataOperation; }, - validateParams: function () { - // No required parameters. - }, - getURL: function (_a, params) { - var _b; - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/uuids/").concat(utils_1.default.encodeString((_b = params === null || params === void 0 ? void 0 : params.uuid) !== null && _b !== void 0 ? _b : config.getUUID())); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_a, params) { - var _b, _c; - var config = _a.config; - var queryParams = {}; - queryParams.uuid = (_b = params === null || params === void 0 ? void 0 : params.uuid) !== null && _b !== void 0 ? _b : config.getUUID(); - queryParams.include = ['status', 'type', 'custom']; - if (params === null || params === void 0 ? void 0 : params.include) { - if (((_c = params.include) === null || _c === void 0 ? void 0 : _c.customFields) === false) { - queryParams.include.pop(); +exports.GetUUIDMetadataRequest = void 0; +const pubnub_error_1 = require("../../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../../errors/pubnub-api-error"); +const request_1 = require("../../../components/request"); +const operations_1 = __importDefault(require("../../../constants/operations")); +const utils_1 = require("../../../utils"); +const INCLUDE_CUSTOM_FIELDS = true; +class GetUUIDMetadataRequest extends request_1.AbstractRequest { + constructor(parameters) { + var _a, _b; + var _c; + super(); + this.parameters = parameters; + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_c = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_c.customFields = INCLUDE_CUSTOM_FIELDS); + if (this.parameters.userId) + this.parameters.uuid = this.parameters.userId; + } + operation() { + return operations_1.default.PNGetUUIDMetadataOperation; + } + validate() { + if (!this.parameters.uuid) + return "'uuid' cannot be empty"; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); } - } - queryParams.include = queryParams.include.join(','); - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - }); }, -}; -exports.default = endpoint; + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + return serviceResponse; + }); + } + get path() { + const { keySet: { subscribeKey }, uuid, } = this.parameters; + return `/v2/objects/${subscribeKey}/uuids/${(0, utils_1.encodeString)(uuid)}`; + } + get queryParameters() { + const { include } = this.parameters; + return { include: ['status', 'type', ...(include.customFields ? ['custom'] : [])].join(',') }; + } +} +exports.GetUUIDMetadataRequest = GetUUIDMetadataRequest; diff --git a/lib/core/endpoints/objects/uuid/get_all.js b/lib/core/endpoints/objects/uuid/get_all.js index f82c8e893..eae9bce3b 100644 --- a/lib/core/endpoints/objects/uuid/get_all.js +++ b/lib/core/endpoints/objects/uuid/get_all.js @@ -1,79 +1,55 @@ "use strict"; -var __read = (this && this.__read) || function (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; +var __awaiter = (this && this.__awaiter) || function (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()); + }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -var operations_1 = __importDefault(require("../../../constants/operations")); -var endpoint = { - getOperation: function () { return operations_1.default.PNGetAllUUIDMetadataOperation; }, - validateParams: function () { - // No required parameters. - }, - getURL: function (_a) { - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/uuids"); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_modules, params) { - var _a, _b, _c, _d, _e, _f, _g, _h, _j; - var queryParams = {}; - queryParams.include = ['status', 'type']; - if (params === null || params === void 0 ? void 0 : params.include) { - if ((_a = params.include) === null || _a === void 0 ? void 0 : _a.customFields) { - queryParams.include.push('custom'); +exports.GetAllUUIDMetadataRequest = void 0; +const pubnub_error_1 = require("../../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../../errors/pubnub-api-error"); +const request_1 = require("../../../components/request"); +const operations_1 = __importDefault(require("../../../constants/operations")); +const INCLUDE_CUSTOM_FIELDS = false; +const LIMIT = 100; +class GetAllUUIDMetadataRequest extends request_1.AbstractRequest { + constructor(parameters) { + var _a, _b, _c; + var _d; + super(); + this.parameters = parameters; + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_d = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_d.customFields = INCLUDE_CUSTOM_FIELDS); + (_c = parameters.limit) !== null && _c !== void 0 ? _c : (parameters.limit = LIMIT); + } + operation() { + return operations_1.default.PNGetAllUUIDMetadataOperation; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); } - } - queryParams.include = queryParams.include.join(','); - if ((_b = params === null || params === void 0 ? void 0 : params.include) === null || _b === void 0 ? void 0 : _b.totalCount) { - queryParams.count = (_c = params.include) === null || _c === void 0 ? void 0 : _c.totalCount; - } - if ((_d = params === null || params === void 0 ? void 0 : params.page) === null || _d === void 0 ? void 0 : _d.next) { - queryParams.start = (_e = params.page) === null || _e === void 0 ? void 0 : _e.next; - } - if ((_f = params === null || params === void 0 ? void 0 : params.page) === null || _f === void 0 ? void 0 : _f.prev) { - queryParams.end = (_g = params.page) === null || _g === void 0 ? void 0 : _g.prev; - } - if (params === null || params === void 0 ? void 0 : params.filter) { - queryParams.filter = params.filter; - } - queryParams.limit = (_h = params === null || params === void 0 ? void 0 : params.limit) !== null && _h !== void 0 ? _h : 100; - if (params === null || params === void 0 ? void 0 : params.sort) { - queryParams.sort = Object.entries((_j = params.sort) !== null && _j !== void 0 ? _j : {}).map(function (_a) { - var _b = __read(_a, 2), key = _b[0], value = _b[1]; - if (value === 'asc' || value === 'desc') { - return "".concat(key, ":").concat(value); - } - return key; - }); - } - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - next: response.next, - prev: response.prev, - }); }, -}; -exports.default = endpoint; + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + return serviceResponse; + }); + } + get path() { + return `/v2/objects/${this.parameters.keySet.subscribeKey}/uuids`; + } + get queryParameters() { + const { include, page, filter, sort, limit } = this.parameters; + const sorting = Object.entries(sort !== null && sort !== void 0 ? sort : {}).map(([option, order]) => order !== null ? `${option}:${order}` : option); + return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ include: ['status', 'type', ...(include.customFields ? ['custom'] : [])].join(',') }, (include.totalCount !== undefined ? { count: `${include.totalCount}` } : {})), (filter ? { filter } : {})), ((page === null || page === void 0 ? void 0 : page.next) ? { start: page.next } : {})), ((page === null || page === void 0 ? void 0 : page.prev) ? { end: page.prev } : {})), (limit ? { limit } : {})), (sorting.length ? { sort: sorting } : {})); + } +} +exports.GetAllUUIDMetadataRequest = GetAllUUIDMetadataRequest; diff --git a/lib/core/endpoints/objects/uuid/remove.js b/lib/core/endpoints/objects/uuid/remove.js index 5ad9a0599..9268a7792 100644 --- a/lib/core/endpoints/objects/uuid/remove.js +++ b/lib/core/endpoints/objects/uuid/remove.js @@ -1,37 +1,52 @@ "use strict"; -/** */ +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -var operations_1 = __importDefault(require("../../../constants/operations")); -var utils_1 = __importDefault(require("../../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNRemoveUUIDMetadataOperation; }, - validateParams: function () { - // No required parameters. - }, - getURL: function (_a, params) { - var _b; - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/uuids/").concat(utils_1.default.encodeString((_b = params === null || params === void 0 ? void 0 : params.uuid) !== null && _b !== void 0 ? _b : config.getUUID())); - }, - useDelete: function () { return true; }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_a, params) { - var _b; - var config = _a.config; - return ({ - uuid: (_b = params === null || params === void 0 ? void 0 : params.uuid) !== null && _b !== void 0 ? _b : config.getUUID(), +exports.RemoveUUIDMetadataRequest = void 0; +const pubnub_error_1 = require("../../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../../errors/pubnub-api-error"); +const transport_request_1 = require("../../../types/transport-request"); +const request_1 = require("../../../components/request"); +const operations_1 = __importDefault(require("../../../constants/operations")); +const utils_1 = require("../../../utils"); +class RemoveUUIDMetadataRequest extends request_1.AbstractRequest { + constructor(parameters) { + super({ method: transport_request_1.TransportMethod.DELETE }); + this.parameters = parameters; + if (this.parameters.userId) + this.parameters.uuid = this.parameters.userId; + } + operation() { + return operations_1.default.PNRemoveUUIDMetadataOperation; + } + validate() { + if (!this.parameters.uuid) + return "'uuid' cannot be empty"; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + return serviceResponse; }); - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - }); }, -}; -exports.default = endpoint; + } + get path() { + const { keySet: { subscribeKey }, uuid, } = this.parameters; + return `/v2/objects/${subscribeKey}/uuids/${(0, utils_1.encodeString)(uuid)}`; + } +} +exports.RemoveUUIDMetadataRequest = RemoveUUIDMetadataRequest; diff --git a/lib/core/endpoints/objects/uuid/set.js b/lib/core/endpoints/objects/uuid/set.js index 0f6f4e6e8..075c97b74 100644 --- a/lib/core/endpoints/objects/uuid/set.js +++ b/lib/core/endpoints/objects/uuid/set.js @@ -1,47 +1,67 @@ "use strict"; -/** */ +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -var operations_1 = __importDefault(require("../../../constants/operations")); -var utils_1 = __importDefault(require("../../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNSetUUIDMetadataOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.data)) { +exports.SetUUIDMetadataRequest = void 0; +const pubnub_error_1 = require("../../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../../errors/pubnub-api-error"); +const transport_request_1 = require("../../../types/transport-request"); +const request_1 = require("../../../components/request"); +const operations_1 = __importDefault(require("../../../constants/operations")); +const utils_1 = require("../../../utils"); +const INCLUDE_CUSTOM_FIELDS = true; +class SetUUIDMetadataRequest extends request_1.AbstractRequest { + constructor(parameters) { + var _a, _b; + var _c; + super({ method: transport_request_1.TransportMethod.PATCH }); + this.parameters = parameters; + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_c = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_c.customFields = INCLUDE_CUSTOM_FIELDS); + if (this.parameters.userId) + this.parameters.uuid = this.parameters.userId; + } + operation() { + return operations_1.default.PNSetUUIDMetadataOperation; + } + validate() { + if (!this.parameters.uuid) + return "'uuid' cannot be empty"; + if (!this.parameters.data) return 'Data cannot be empty'; - } - }, - usePatch: function () { return true; }, - patchURL: function (_a, params) { - var _b; - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/uuids/").concat(utils_1.default.encodeString((_b = params.uuid) !== null && _b !== void 0 ? _b : config.getUUID())); - }, - patchPayload: function (_, params) { return params.data; }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_a, params) { - var _b, _c; - var config = _a.config; - var queryParams = {}; - queryParams.uuid = (_b = params === null || params === void 0 ? void 0 : params.uuid) !== null && _b !== void 0 ? _b : config.getUUID(); - queryParams.include = ['status', 'type', 'custom']; - if (params === null || params === void 0 ? void 0 : params.include) { - if (((_c = params.include) === null || _c === void 0 ? void 0 : _c.customFields) === false) { - queryParams.include.pop(); + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); } - } - queryParams.include = queryParams.include.join(','); - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - }); }, -}; -exports.default = endpoint; + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + return serviceResponse; + }); + } + get path() { + const { keySet: { subscribeKey }, uuid, } = this.parameters; + return `/v2/objects/${subscribeKey}/uuids/${(0, utils_1.encodeString)(uuid)}`; + } + get queryParameters() { + return { + include: ['status', 'type', ...(this.parameters.include.customFields ? ['custom'] : [])].join(','), + }; + } + get body() { + return JSON.stringify(this.parameters.data); + } +} +exports.SetUUIDMetadataRequest = SetUUIDMetadataRequest; diff --git a/lib/core/endpoints/presence/get_state.js b/lib/core/endpoints/presence/get_state.js index 030ad9f8d..8373628e2 100644 --- a/lib/core/endpoints/presence/get_state.js +++ b/lib/core/endpoints/presence/get_state.js @@ -1,56 +1,66 @@ "use strict"; -/* */ +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; -var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -function getOperation() { - return operations_1.default.PNGetStateOperation; -} -exports.getOperation = getOperation; -function validateParams(modules) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var config = modules.config; - var _a = incomingParams.uuid, uuid = _a === void 0 ? config.UUID : _a, _b = incomingParams.channels, channels = _b === void 0 ? [] : _b; - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return "/v2/presence/sub-key/".concat(config.subscribeKey, "/channel/").concat(utils_1.default.encodeString(stringifiedChannels), "/uuid/").concat(uuid); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(modules, incomingParams) { - var _a = incomingParams.channelGroups, channelGroups = _a === void 0 ? [] : _a; - var params = {}; - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); +exports.GetPresenceStateRequest = void 0; +const pubnub_error_1 = require("../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../errors/pubnub-api-error"); +const request_1 = require("../../components/request"); +const operations_1 = __importDefault(require("../../constants/operations")); +const utils_1 = require("../../utils"); +class GetPresenceStateRequest extends request_1.AbstractRequest { + constructor(parameters) { + var _a, _b; + var _c, _d; + super(); + this.parameters = parameters; + (_a = (_c = this.parameters).channels) !== null && _a !== void 0 ? _a : (_c.channels = []); + (_b = (_d = this.parameters).channelGroups) !== null && _b !== void 0 ? _b : (_d.channelGroups = []); } - return params; -} -exports.prepareParams = prepareParams; -function handleResponse(modules, serverResponse, incomingParams) { - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a, _b = incomingParams.channelGroups, channelGroups = _b === void 0 ? [] : _b; - var channelsResponse = {}; - if (channels.length === 1 && channelGroups.length === 0) { - channelsResponse[channels[0]] = serverResponse.payload; + operation() { + return operations_1.default.PNGetStateOperation; + } + validate() { + const { keySet: { subscribeKey }, channels, channelGroups, } = this.parameters; + if (!subscribeKey) + return 'Missing Subscribe Key'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + const { channels = [], channelGroups = [] } = this.parameters; + const state = { channels: {} }; + if (channels.length === 1 && channelGroups.length === 0) + state.channels[channels[0]] = serviceResponse.payload; + else + state.channels = serviceResponse.payload; + return state; + }); + } + get path() { + const { keySet: { subscribeKey }, uuid, channels, } = this.parameters; + return `/v2/presence/sub-key/${subscribeKey}/channel/${(0, utils_1.encodeNames)(channels !== null && channels !== void 0 ? channels : [], ',')}/uuid/${uuid}`; } - else { - channelsResponse = serverResponse.payload; + get queryParameters() { + const { channelGroups } = this.parameters; + if (!channelGroups || channelGroups.length === 0) + return {}; + return { 'channel-group': channelGroups.join(',') }; } - return { channels: channelsResponse }; } -exports.handleResponse = handleResponse; +exports.GetPresenceStateRequest = GetPresenceStateRequest; diff --git a/lib/core/endpoints/presence/heartbeat.js b/lib/core/endpoints/presence/heartbeat.js index 137bfad1a..52de83f8e 100644 --- a/lib/core/endpoints/presence/heartbeat.js +++ b/lib/core/endpoints/presence/heartbeat.js @@ -1,53 +1,61 @@ "use strict"; -/* */ +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.getRequestTimeout = exports.isAuthSupported = exports.getURL = exports.validateParams = exports.getOperation = void 0; -var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -function getOperation() { - return operations_1.default.PNHeartbeatOperation; -} -exports.getOperation = getOperation; -function validateParams(modules) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var config = modules.config; - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a; - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return "/v2/presence/sub-key/".concat(config.subscribeKey, "/channel/").concat(utils_1.default.encodeString(stringifiedChannels), "/heartbeat"); -} -exports.getURL = getURL; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function prepareParams(modules, incomingParams) { - var _a = incomingParams.channelGroups, channelGroups = _a === void 0 ? [] : _a, state = incomingParams.state; - var config = modules.config; - var params = {}; - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); +exports.HeartbeatRequest = void 0; +const pubnub_error_1 = require("../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../errors/pubnub-api-error"); +const request_1 = require("../../components/request"); +const operations_1 = __importDefault(require("../../constants/operations")); +const utils_1 = require("../../utils"); +class HeartbeatRequest extends request_1.AbstractRequest { + constructor(parameters) { + super(); + this.parameters = parameters; } - if (state) { - params.state = JSON.stringify(state); + operation() { + return operations_1.default.PNHeartbeatOperation; + } + validate() { + const { keySet: { subscribeKey }, channels = [], channelGroups = [], } = this.parameters; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (channels.length === 0 && channelGroups.length === 0) + return 'Please provide a list of channels and/or channel-groups'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + return {}; + }); + } + get path() { + const { keySet: { subscribeKey }, channels, } = this.parameters; + return `/v2/presence/sub-key/${subscribeKey}/channel/${(0, utils_1.encodeNames)(channels !== null && channels !== void 0 ? channels : [], ',')}/heartbeat`; + } + get queryParameters() { + const { channelGroups, state, heartbeat } = this.parameters; + const query = { heartbeat: `${heartbeat}` }; + if (channelGroups && channelGroups.length !== 0) + query['channel-group'] = channelGroups.join(','); + if (state) + query.state = JSON.stringify(state); + return query; } - params.heartbeat = config.getPresenceTimeout(); - return params; -} -exports.prepareParams = prepareParams; -function handleResponse() { - return {}; } -exports.handleResponse = handleResponse; +exports.HeartbeatRequest = HeartbeatRequest; diff --git a/lib/core/endpoints/presence/here_now.js b/lib/core/endpoints/presence/here_now.js index 87cbd46e4..6900d5929 100644 --- a/lib/core/endpoints/presence/here_now.js +++ b/lib/core/endpoints/presence/here_now.js @@ -1,140 +1,95 @@ "use strict"; -var __assign = (this && this.__assign) || function () { - __assign = Object.assign || function(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); +var __awaiter = (this && this.__awaiter) || function (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()); + }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleError = exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; -/* */ -var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -function getOperation() { - return operations_1.default.PNHereNowOperation; -} -exports.getOperation = getOperation; -function validateParams(modules) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var config = modules.config; - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a, _b = incomingParams.channelGroups, channelGroups = _b === void 0 ? [] : _b; - var baseURL = "/v2/presence/sub-key/".concat(config.subscribeKey); - if (channels.length > 0 || channelGroups.length > 0) { - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - baseURL += "/channel/".concat(utils_1.default.encodeString(stringifiedChannels)); +exports.HereNowRequest = void 0; +const pubnub_error_1 = require("../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../errors/pubnub-api-error"); +const request_1 = require("../../components/request"); +const operations_1 = __importDefault(require("../../constants/operations")); +const utils_1 = require("../../utils"); +const INCLUDE_UUID = true; +const INCLUDE_STATE = false; +class HereNowRequest extends request_1.AbstractRequest { + constructor(parameters) { + var _a, _b, _c; + var _d, _e, _f; + super(); + this.parameters = parameters; + (_a = (_d = this.parameters).queryParameters) !== null && _a !== void 0 ? _a : (_d.queryParameters = {}); + (_b = (_e = this.parameters).includeUUIDs) !== null && _b !== void 0 ? _b : (_e.includeUUIDs = INCLUDE_UUID); + (_c = (_f = this.parameters).includeState) !== null && _c !== void 0 ? _c : (_f.includeState = INCLUDE_STATE); } - return baseURL; -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(modules, incomingParams) { - var _a = incomingParams.channelGroups, channelGroups = _a === void 0 ? [] : _a, _b = incomingParams.includeUUIDs, includeUUIDs = _b === void 0 ? true : _b, _c = incomingParams.includeState, includeState = _c === void 0 ? false : _c, _d = incomingParams.queryParameters, queryParameters = _d === void 0 ? {} : _d; - var params = {}; - if (!includeUUIDs) - params.disable_uuids = 1; - if (includeState) - params.state = 1; - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); + operation() { + const { channels = [], channelGroups = [] } = this.parameters; + return channels.length === 0 && channelGroups.length === 0 + ? operations_1.default.PNGlobalHereNowOperation + : operations_1.default.PNHereNowOperation; } - params = __assign(__assign({}, params), queryParameters); - return params; -} -exports.prepareParams = prepareParams; -function handleResponse(modules, serverResponse, incomingParams) { - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a, _b = incomingParams.channelGroups, channelGroups = _b === void 0 ? [] : _b, _c = incomingParams.includeUUIDs, includeUUIDs = _c === void 0 ? true : _c, _d = incomingParams.includeState, includeState = _d === void 0 ? false : _d; - var prepareSingularChannel = function () { - var response = {}; - var occupantsList = []; - response.totalChannels = 1; - response.totalOccupancy = serverResponse.occupancy; - response.channels = {}; - response.channels[channels[0]] = { - occupants: occupantsList, - name: channels[0], - occupancy: serverResponse.occupancy, - }; - // We have had issues in the past with server returning responses - // that contain no uuids array - if (includeUUIDs && serverResponse.uuids) { - serverResponse.uuids.forEach(function (uuidEntry) { - if (includeState) { - occupantsList.push({ state: uuidEntry.state, uuid: uuidEntry.uuid }); - } - else { - occupantsList.push({ state: null, uuid: uuidEntry }); - } + validate() { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + var _a, _b; + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + const totalChannels = 'occupancy' in serviceResponse ? 1 : serviceResponse.payload.total_channels; + const totalOccupancy = 'occupancy' in serviceResponse ? serviceResponse.occupancy : serviceResponse.payload.total_channels; + const channelsPresence = {}; + let channels = {}; + if ('occupancy' in serviceResponse) { + const channel = this.parameters.channels[0]; + channels[channel] = { uuids: (_a = serviceResponse.uuids) !== null && _a !== void 0 ? _a : [], occupancy: totalOccupancy }; + } + else + channels = (_b = serviceResponse.payload.channels) !== null && _b !== void 0 ? _b : {}; + Object.keys(channels).forEach((channel) => { + const channelEntry = channels[channel]; + channelsPresence[channel] = { + occupants: this.parameters.includeUUIDs + ? channelEntry.uuids.map((uuid) => { + if (typeof uuid === 'string') + return { uuid, state: null }; + return uuid; + }) + : [], + name: channel, + occupancy: channelEntry.occupancy, + }; }); - } - return response; - }; - var prepareMultipleChannel = function () { - var response = {}; - response.totalChannels = serverResponse.payload.total_channels; - response.totalOccupancy = serverResponse.payload.total_occupancy; - response.channels = {}; - Object.keys(serverResponse.payload.channels).forEach(function (channelName) { - var channelEntry = serverResponse.payload.channels[channelName]; - var occupantsList = []; - response.channels[channelName] = { - occupants: occupantsList, - name: channelName, - occupancy: channelEntry.occupancy, + return { + totalChannels, + totalOccupancy, + channels: channelsPresence, }; - if (includeUUIDs) { - channelEntry.uuids.forEach(function (uuidEntry) { - if (includeState) { - occupantsList.push({ - state: uuidEntry.state, - uuid: uuidEntry.uuid, - }); - } - else { - occupantsList.push({ state: null, uuid: uuidEntry }); - } - }); - } - return response; }); - return response; - }; - var response; - if (channels.length > 1 || channelGroups.length > 0 || (channelGroups.length === 0 && channels.length === 0)) { - response = prepareMultipleChannel(); } - else { - response = prepareSingularChannel(); + get path() { + const { keySet: { subscribeKey }, channels, channelGroups, } = this.parameters; + let path = `/v2/presence/sub-key/${subscribeKey}`; + if ((channels && channels.length > 0) || (channelGroups && channelGroups.length > 0)) + path += `/channel/${(0, utils_1.encodeNames)(channels !== null && channels !== void 0 ? channels : [], ',')}`; + return path; } - return response; -} -exports.handleResponse = handleResponse; -function handleError(modules, params, status) { - if (status.statusCode === 402 && !this.getURL(modules, params).includes('channel')) { - status.errorData.message = - 'You have tried to perform a Global Here Now operation, ' + - 'your keyset configuration does not support that. Please provide a channel, ' + - 'or enable the Global Here Now feature from the Portal.'; + get queryParameters() { + const { channelGroups, includeUUIDs, includeState, queryParameters } = this.parameters; + return Object.assign(Object.assign(Object.assign(Object.assign({}, (!includeUUIDs ? { disable_uuids: '1' } : {})), ((includeState !== null && includeState !== void 0 ? includeState : false) ? { state: '1' } : {})), (channelGroups && channelGroups.length > 0 ? { 'channel-group': channelGroups.join(',') } : {})), queryParameters); } } -exports.handleError = handleError; +exports.HereNowRequest = HereNowRequest; diff --git a/lib/core/endpoints/presence/leave.js b/lib/core/endpoints/presence/leave.js index be63c00dd..ec29564ba 100644 --- a/lib/core/endpoints/presence/leave.js +++ b/lib/core/endpoints/presence/leave.js @@ -1,48 +1,63 @@ "use strict"; -/* */ +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; -var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -function getOperation() { - return operations_1.default.PNUnsubscribeOperation; -} -exports.getOperation = getOperation; -function validateParams(modules) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var config = modules.config; - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a; - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return "/v2/presence/sub-key/".concat(config.subscribeKey, "/channel/").concat(utils_1.default.encodeString(stringifiedChannels), "/leave"); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(modules, incomingParams) { - var _a = incomingParams.channelGroups, channelGroups = _a === void 0 ? [] : _a; - var params = {}; - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); +exports.PresenceLeaveRequest = void 0; +const pubnub_error_1 = require("../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../errors/pubnub-api-error"); +const request_1 = require("../../components/request"); +const operations_1 = __importDefault(require("../../constants/operations")); +const utils_1 = require("../../utils"); +class PresenceLeaveRequest extends request_1.AbstractRequest { + constructor(parameters) { + super(); + this.parameters = parameters; + if (this.parameters.channelGroups) + this.parameters.channelGroups = Array.from(new Set(this.parameters.channelGroups)); + if (this.parameters.channels) + this.parameters.channels = Array.from(new Set(this.parameters.channels)); + } + operation() { + return operations_1.default.PNUnsubscribeOperation; + } + validate() { + const { keySet: { subscribeKey }, channels = [], channelGroups = [], } = this.parameters; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (channels.length === 0 && channelGroups.length === 0) + return 'At least one `channel` or `channel group` should be provided.'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + return {}; + }); + } + get path() { + var _a; + const { keySet: { subscribeKey }, channels, } = this.parameters; + return `/v2/presence/sub-key/${subscribeKey}/channel/${(0, utils_1.encodeNames)((_a = channels === null || channels === void 0 ? void 0 : channels.sort()) !== null && _a !== void 0 ? _a : [], ',')}/leave`; + } + get queryParameters() { + const { channelGroups } = this.parameters; + if (!channelGroups || channelGroups.length === 0) + return {}; + return { 'channel-group': channelGroups.sort().join(',') }; } - return params; -} -exports.prepareParams = prepareParams; -function handleResponse() { - return {}; } -exports.handleResponse = handleResponse; +exports.PresenceLeaveRequest = PresenceLeaveRequest; diff --git a/lib/core/endpoints/presence/set_state.js b/lib/core/endpoints/presence/set_state.js index daf813524..8ecfd935d 100644 --- a/lib/core/endpoints/presence/set_state.js +++ b/lib/core/endpoints/presence/set_state.js @@ -1,54 +1,61 @@ "use strict"; +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; -var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -function getOperation() { - return operations_1.default.PNSetStateOperation; -} -exports.getOperation = getOperation; -function validateParams(modules, incomingParams) { - var config = modules.config; - var state = incomingParams.state, _a = incomingParams.channels, channels = _a === void 0 ? [] : _a, _b = incomingParams.channelGroups, channelGroups = _b === void 0 ? [] : _b; - if (!state) - return 'Missing State'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - if (channels.length === 0 && channelGroups.length === 0) { - return 'Please provide a list of channels and/or channel-groups'; +exports.SetPresenceStateRequest = void 0; +const pubnub_error_1 = require("../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../errors/pubnub-api-error"); +const request_1 = require("../../components/request"); +const operations_1 = __importDefault(require("../../constants/operations")); +const utils_1 = require("../../utils"); +class SetPresenceStateRequest extends request_1.AbstractRequest { + constructor(parameters) { + super(); + this.parameters = parameters; } -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var config = modules.config; - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a; - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return "/v2/presence/sub-key/".concat(config.subscribeKey, "/channel/").concat(utils_1.default.encodeString(stringifiedChannels), "/uuid/").concat(utils_1.default.encodeString(config.UUID), "/data"); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(modules, incomingParams) { - var state = incomingParams.state, _a = incomingParams.channelGroups, channelGroups = _a === void 0 ? [] : _a; - var params = {}; - params.state = JSON.stringify(state); - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); + operation() { + return operations_1.default.PNSetStateOperation; + } + validate() { + const { keySet: { subscribeKey }, state, channels = [], channelGroups = [], } = this.parameters; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!state) + return 'Missing State'; + if ((channels === null || channels === void 0 ? void 0 : channels.length) === 0 && (channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.length) === 0) + return 'Please provide a list of channels and/or channel-groups'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + return { state: serviceResponse.payload }; + }); + } + get path() { + const { keySet: { subscribeKey }, uuid, channels, } = this.parameters; + return `/v2/presence/sub-key/${subscribeKey}/channel/${(0, utils_1.encodeNames)(channels !== null && channels !== void 0 ? channels : [], ',')}/uuid/${(0, utils_1.encodeString)(uuid)}/data`; + } + get queryParameters() { + const { channelGroups, state } = this.parameters; + const query = { state: JSON.stringify(state) }; + if (channelGroups && channelGroups.length !== 0) + query['channel-group'] = channelGroups.join(','); + return query; } - return params; -} -exports.prepareParams = prepareParams; -function handleResponse(modules, serverResponse) { - return { state: serverResponse.payload }; } -exports.handleResponse = handleResponse; +exports.SetPresenceStateRequest = SetPresenceStateRequest; diff --git a/lib/core/endpoints/presence/where_now.js b/lib/core/endpoints/presence/where_now.js index 05c069125..a536e143b 100644 --- a/lib/core/endpoints/presence/where_now.js +++ b/lib/core/endpoints/presence/where_now.js @@ -1,47 +1,51 @@ "use strict"; +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; -/* */ -var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -function getOperation() { - return operations_1.default.PNWhereNowOperation; -} -exports.getOperation = getOperation; -function validateParams(modules) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var config = modules.config; - var _a = incomingParams.uuid, uuid = _a === void 0 ? config.UUID : _a; - return "/v2/presence/sub-key/".concat(config.subscribeKey, "/uuid/").concat(utils_1.default.encodeString(uuid)); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams() { - return {}; -} -exports.prepareParams = prepareParams; -function handleResponse(modules, serverResponse) { - // This is a quick fix for when the server does not include a payload - // in where now responses - if (!serverResponse.payload) { - return { channels: [] }; +exports.WhereNowRequest = void 0; +const pubnub_error_1 = require("../../../errors/pubnub-error"); +const pubnub_api_error_1 = require("../../../errors/pubnub-api-error"); +const request_1 = require("../../components/request"); +const operations_1 = __importDefault(require("../../constants/operations")); +const utils_1 = require("../../utils"); +class WhereNowRequest extends request_1.AbstractRequest { + constructor(parameters) { + super(); + this.parameters = parameters; + } + operation() { + return operations_1.default.PNWhereNowOperation; + } + validate() { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + } + else if (serviceResponse.status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(response); + if (!serviceResponse.payload) + return { channels: [] }; + return { channels: serviceResponse.payload.channels }; + }); + } + get path() { + const { keySet: { subscribeKey }, uuid, } = this.parameters; + return `/v2/presence/sub-key/${subscribeKey}/uuid/${(0, utils_1.encodeString)(uuid)}`; } - return { channels: serverResponse.payload.channels }; } -exports.handleResponse = handleResponse; +exports.WhereNowRequest = WhereNowRequest; diff --git a/lib/core/endpoints/publish.js b/lib/core/endpoints/publish.js index f4d3dbafc..cd5d55ffb 100644 --- a/lib/core/endpoints/publish.js +++ b/lib/core/endpoints/publish.js @@ -1,93 +1,83 @@ "use strict"; +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.postPayload = exports.isAuthSupported = exports.getRequestTimeout = exports.postURL = exports.getURL = exports.usePost = exports.validateParams = exports.getOperation = void 0; -/* */ -var operations_1 = __importDefault(require("../constants/operations")); -var utils_1 = __importDefault(require("../utils")); -var base64_codec_1 = require("../components/base64_codec"); -function prepareMessagePayload(modules, messagePayload) { - var stringifiedPayload = JSON.stringify(messagePayload); - if (modules.cryptoModule) { - var encrypted = modules.cryptoModule.encrypt(stringifiedPayload); - stringifiedPayload = typeof encrypted === 'string' ? encrypted : (0, base64_codec_1.encode)(encrypted); - stringifiedPayload = JSON.stringify(stringifiedPayload); +exports.PublishRequest = void 0; +const pubnub_error_1 = require("../../errors/pubnub-error"); +const transport_request_1 = require("../types/transport-request"); +const request_1 = require("../components/request"); +const operations_1 = __importDefault(require("../constants/operations")); +const base64_codec_1 = require("../components/base64_codec"); +const utils_1 = require("../utils"); +const SEND_BY_POST = false; +class PublishRequest extends request_1.AbstractRequest { + constructor(parameters) { + var _a; + var _b; + super({ method: parameters.sendByPost ? transport_request_1.TransportMethod.POST : transport_request_1.TransportMethod.GET }); + this.parameters = parameters; + (_a = (_b = this.parameters).sendByPost) !== null && _a !== void 0 ? _a : (_b.sendByPost = SEND_BY_POST); } - return stringifiedPayload || ''; -} -function getOperation() { - return operations_1.default.PNPublishOperation; -} -exports.getOperation = getOperation; -function validateParams(_a, incomingParams) { - var config = _a.config; - var message = incomingParams.message, channel = incomingParams.channel; - if (!channel) - return 'Missing Channel'; - if (!message) - return 'Missing Message'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function usePost(modules, incomingParams) { - var _a = incomingParams.sendByPost, sendByPost = _a === void 0 ? false : _a; - return sendByPost; -} -exports.usePost = usePost; -function getURL(modules, incomingParams) { - var config = modules.config; - var channel = incomingParams.channel, message = incomingParams.message; - var stringifiedPayload = prepareMessagePayload(modules, message); - return "/publish/".concat(config.publishKey, "/").concat(config.subscribeKey, "/0/").concat(utils_1.default.encodeString(channel), "/0/").concat(utils_1.default.encodeString(stringifiedPayload)); -} -exports.getURL = getURL; -function postURL(modules, incomingParams) { - var config = modules.config; - var channel = incomingParams.channel; - return "/publish/".concat(config.publishKey, "/").concat(config.subscribeKey, "/0/").concat(utils_1.default.encodeString(channel), "/0"); -} -exports.postURL = postURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function postPayload(modules, incomingParams) { - var message = incomingParams.message; - return prepareMessagePayload(modules, message); -} -exports.postPayload = postPayload; -function prepareParams(modules, incomingParams) { - var meta = incomingParams.meta, _a = incomingParams.replicate, replicate = _a === void 0 ? true : _a, storeInHistory = incomingParams.storeInHistory, ttl = incomingParams.ttl; - var params = {}; - if (storeInHistory != null) { - if (storeInHistory) { - params.store = '1'; - } - else { - params.store = '0'; - } + operation() { + return operations_1.default.PNPublishOperation; } - if (ttl) { - params.ttl = ttl; + validate() { + const { message, channel, keySet: { publishKey }, } = this.parameters; + if (!channel) + return "Missing 'channel'"; + if (!message) + return "Missing 'message'"; + if (!publishKey) + return "Missing 'publishKey'"; } - if (replicate === false) { - params.norep = 'true'; + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + return { timetoken: serviceResponse[2] }; + }); } - if (meta && typeof meta === 'object') { - params.meta = JSON.stringify(meta); + get path() { + const { message, channel, keySet } = this.parameters; + const stringifiedPayload = this.prepareMessagePayload(message); + return `/publish/${keySet.publishKey}/${keySet.subscribeKey}/0/${(0, utils_1.encodeString)(channel)}/0${!this.parameters.sendByPost ? `/${(0, utils_1.encodeString)(stringifiedPayload)}` : ''}`; + } + get queryParameters() { + const { meta, replicate, storeInHistory, ttl } = this.parameters; + const query = {}; + if (storeInHistory !== undefined) + query.store = storeInHistory ? '1' : '0'; + if (ttl !== undefined) + query.ttl = ttl; + if (replicate !== undefined && !replicate) + query.norep = 'true'; + if (meta && typeof meta === 'object') + query.meta = JSON.stringify(meta); + return query; + } + get headers() { + return { 'Content-Type': 'application/json' }; + } + get body() { + return this.prepareMessagePayload(this.parameters.message); + } + prepareMessagePayload(payload) { + const { crypto } = this.parameters; + if (!crypto) + return JSON.stringify(payload) || ''; + const encrypted = crypto.encrypt(JSON.stringify(payload)); + return JSON.stringify(typeof encrypted === 'string' ? encrypted : (0, base64_codec_1.encode)(encrypted)); } - return params; -} -exports.prepareParams = prepareParams; -function handleResponse(modules, serverResponse) { - return { timetoken: serverResponse[2] }; } -exports.handleResponse = handleResponse; +exports.PublishRequest = PublishRequest; diff --git a/lib/core/endpoints/push/add_push_channels.js b/lib/core/endpoints/push/add_push_channels.js index 8912132ba..7e6ca21d2 100644 --- a/lib/core/endpoints/push/add_push_channels.js +++ b/lib/core/endpoints/push/add_push_channels.js @@ -1,70 +1,35 @@ "use strict"; -/* */ -var __assign = (this && this.__assign) || function () { - __assign = Object.assign || function(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); +var __awaiter = (this && this.__awaiter) || function (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()); + }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; -var operations_1 = __importDefault(require("../../constants/operations")); -function getOperation() { - return operations_1.default.PNPushNotificationEnabledChannelsOperation; -} -exports.getOperation = getOperation; -function validateParams(modules, incomingParams) { - var device = incomingParams.device, pushGateway = incomingParams.pushGateway, channels = incomingParams.channels, topic = incomingParams.topic; - var config = modules.config; - if (!device) - return 'Missing Device ID (device)'; - if (!pushGateway) - return 'Missing GW Type (pushGateway: gcm, apns or apns2)'; - if (pushGateway === 'apns2' && !topic) - return 'Missing APNS2 topic'; - if (!channels || channels.length === 0) - return 'Missing Channels'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var device = incomingParams.device, pushGateway = incomingParams.pushGateway; - var config = modules.config; - if (pushGateway === 'apns2') { - return "/v2/push/sub-key/".concat(config.subscribeKey, "/devices-apns2/").concat(device); +exports.AddDevicePushNotificationChannelsRequest = void 0; +const pubnub_error_1 = require("../../../errors/pubnub-error"); +const push_1 = require("./push"); +const operations_1 = __importDefault(require("../../constants/operations")); +class AddDevicePushNotificationChannelsRequest extends push_1.BasePushNotificationChannelsRequest { + constructor(parameters) { + super(Object.assign(Object.assign({}, parameters), { action: 'add' })); } - return "/v1/push/sub-key/".concat(config.subscribeKey, "/devices/").concat(device); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(modules, incomingParams) { - var pushGateway = incomingParams.pushGateway, _a = incomingParams.channels, channels = _a === void 0 ? [] : _a, _b = incomingParams.environment, environment = _b === void 0 ? 'development' : _b, topic = incomingParams.topic; - var parameters = { type: pushGateway, add: channels.join(',') }; - if (pushGateway === 'apns2') { - parameters = __assign(__assign({}, parameters), { environment: environment, topic: topic }); - delete parameters.type; + operation() { + return operations_1.default.PNAddPushNotificationEnabledChannelsOperation; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + return {}; + }); } - return parameters; -} -exports.prepareParams = prepareParams; -function handleResponse() { - return {}; } -exports.handleResponse = handleResponse; +exports.AddDevicePushNotificationChannelsRequest = AddDevicePushNotificationChannelsRequest; diff --git a/lib/core/endpoints/push/list_push_channels.js b/lib/core/endpoints/push/list_push_channels.js index 1acd572ab..355026b81 100644 --- a/lib/core/endpoints/push/list_push_channels.js +++ b/lib/core/endpoints/push/list_push_channels.js @@ -1,72 +1,35 @@ "use strict"; -var __assign = (this && this.__assign) || function () { - __assign = Object.assign || function(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); +var __awaiter = (this && this.__awaiter) || function (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()); + }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; -/* */ -var operations_1 = __importDefault(require("../../constants/operations")); -function getOperation() { - return operations_1.default.PNPushNotificationEnabledChannelsOperation; -} -exports.getOperation = getOperation; -function validateParams(modules, incomingParams) { - var device = incomingParams.device, pushGateway = incomingParams.pushGateway, topic = incomingParams.topic; - var config = modules.config; - if (!device) - return 'Missing Device ID (device)'; - if (!pushGateway) - return 'Missing GW Type (pushGateway: gcm, apns or apns2)'; - if (pushGateway === 'apns2' && !topic) - return 'Missing APNS2 topic'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var device = incomingParams.device, pushGateway = incomingParams.pushGateway; - var config = modules.config; - if (pushGateway === 'apns2') { - return "/v2/push/sub-key/".concat(config.subscribeKey, "/devices-apns2/").concat(device); +exports.ListDevicePushNotificationChannelsRequest = void 0; +const pubnub_error_1 = require("../../../errors/pubnub-error"); +const push_1 = require("./push"); +const operations_1 = __importDefault(require("../../constants/operations")); +class ListDevicePushNotificationChannelsRequest extends push_1.BasePushNotificationChannelsRequest { + constructor(parameters) { + super(Object.assign(Object.assign({}, parameters), { action: 'list' })); } - return "/v1/push/sub-key/".concat(config.subscribeKey, "/devices/").concat(device); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(modules, incomingParams) { - var pushGateway = incomingParams.pushGateway, _a = incomingParams.environment, environment = _a === void 0 ? 'development' : _a, topic = incomingParams.topic, start = incomingParams.start, count = incomingParams.count; - var parameters = { type: pushGateway }; - if (pushGateway === 'apns2') { - parameters = __assign(__assign({}, parameters), { environment: environment, topic: topic }); - delete parameters.type; + operation() { + return operations_1.default.PNPushNotificationEnabledChannelsOperation; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + return { channels: serviceResponse }; + }); } - if (start) - parameters.start = start; - if (count && count > 0) - parameters.count = count; - return parameters; -} -exports.prepareParams = prepareParams; -function handleResponse(modules, serverResponse) { - return { channels: serverResponse }; } -exports.handleResponse = handleResponse; +exports.ListDevicePushNotificationChannelsRequest = ListDevicePushNotificationChannelsRequest; diff --git a/lib/core/endpoints/push/push.js b/lib/core/endpoints/push/push.js new file mode 100644 index 000000000..82c63aab4 --- /dev/null +++ b/lib/core/endpoints/push/push.js @@ -0,0 +1,70 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.BasePushNotificationChannelsRequest = void 0; +const request_1 = require("../../components/request"); +const ENVIRONMENT = 'development'; +const MAX_COUNT = 1000; +class BasePushNotificationChannelsRequest extends request_1.AbstractRequest { + constructor(parameters) { + var _a; + var _b; + super(); + this.parameters = parameters; + if (this.parameters.pushGateway === 'apns2') + (_a = (_b = this.parameters).environment) !== null && _a !== void 0 ? _a : (_b.environment = ENVIRONMENT); + if (this.parameters.count && this.parameters.count > MAX_COUNT) + this.parameters.count = MAX_COUNT; + } + operation() { + throw Error('Should be implemented in subclass.'); + } + validate() { + const { keySet: { subscribeKey }, action, device, pushGateway, } = this.parameters; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!device) + return 'Missing Device ID (device)'; + if ((action === 'add' || action === 'remove') && + (!('channels' in this.parameters) || this.parameters.channels.length === 0)) + return 'Missing Channels'; + if (!pushGateway) + return 'Missing GW Type (pushGateway: gcm or apns2)'; + if (this.parameters.pushGateway === 'apns2' && !this.parameters.topic) + return 'Missing APNS2 topic'; + } + parse(_response) { + return __awaiter(this, void 0, void 0, function* () { + throw Error('Should be implemented in subclass.'); + }); + } + get path() { + const { keySet: { subscribeKey }, action, device, pushGateway, } = this.parameters; + let path = pushGateway === 'apns2' + ? `/v2/push/sub-key/${subscribeKey}/devices-apns2/${device}` + : `/v1/push/sub-key/${subscribeKey}/devices/${device}`; + if (action === 'remove-device') + path = `${path}/remove`; + return path; + } + get queryParameters() { + const { start, count } = this.parameters; + let query = Object.assign(Object.assign({ type: this.parameters.pushGateway }, (start ? { start } : {})), (count && count > 0 ? { count } : {})); + if ('channels' in this.parameters) + query[this.parameters.action] = this.parameters.channels.join(','); + if (this.parameters.pushGateway === 'apns2') { + const { environment, topic } = this.parameters; + query = Object.assign(Object.assign({}, query), { environment: environment, topic }); + } + return query; + } +} +exports.BasePushNotificationChannelsRequest = BasePushNotificationChannelsRequest; diff --git a/lib/core/endpoints/push/remove_device.js b/lib/core/endpoints/push/remove_device.js index 80abf1028..4e71bc5ce 100644 --- a/lib/core/endpoints/push/remove_device.js +++ b/lib/core/endpoints/push/remove_device.js @@ -1,68 +1,35 @@ "use strict"; -/* */ -var __assign = (this && this.__assign) || function () { - __assign = Object.assign || function(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); +var __awaiter = (this && this.__awaiter) || function (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()); + }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; -var operations_1 = __importDefault(require("../../constants/operations")); -function getOperation() { - return operations_1.default.PNRemoveAllPushNotificationsOperation; -} -exports.getOperation = getOperation; -function validateParams(modules, incomingParams) { - var device = incomingParams.device, pushGateway = incomingParams.pushGateway, topic = incomingParams.topic; - var config = modules.config; - if (!device) - return 'Missing Device ID (device)'; - if (!pushGateway) - return 'Missing GW Type (pushGateway: gcm, apns or apns2)'; - if (pushGateway === 'apns2' && !topic) - return 'Missing APNS2 topic'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var device = incomingParams.device, pushGateway = incomingParams.pushGateway; - var config = modules.config; - if (pushGateway === 'apns2') { - return "/v2/push/sub-key/".concat(config.subscribeKey, "/devices-apns2/").concat(device, "/remove"); +exports.RemoveDevicePushNotificationRequest = void 0; +const pubnub_error_1 = require("../../../errors/pubnub-error"); +const push_1 = require("./push"); +const operations_1 = __importDefault(require("../../constants/operations")); +class RemoveDevicePushNotificationRequest extends push_1.BasePushNotificationChannelsRequest { + constructor(parameters) { + super(Object.assign(Object.assign({}, parameters), { action: 'remove-device' })); } - return "/v1/push/sub-key/".concat(config.subscribeKey, "/devices/").concat(device, "/remove"); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(modules, incomingParams) { - var pushGateway = incomingParams.pushGateway, _a = incomingParams.environment, environment = _a === void 0 ? 'development' : _a, topic = incomingParams.topic; - var parameters = { type: pushGateway }; - if (pushGateway === 'apns2') { - parameters = __assign(__assign({}, parameters), { environment: environment, topic: topic }); - delete parameters.type; + operation() { + return operations_1.default.PNRemoveAllPushNotificationsOperation; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + return {}; + }); } - return parameters; -} -exports.prepareParams = prepareParams; -function handleResponse() { - return {}; } -exports.handleResponse = handleResponse; +exports.RemoveDevicePushNotificationRequest = RemoveDevicePushNotificationRequest; diff --git a/lib/core/endpoints/push/remove_push_channels.js b/lib/core/endpoints/push/remove_push_channels.js index a6256a9f3..96d179ae7 100644 --- a/lib/core/endpoints/push/remove_push_channels.js +++ b/lib/core/endpoints/push/remove_push_channels.js @@ -1,70 +1,35 @@ "use strict"; -/* */ -var __assign = (this && this.__assign) || function () { - __assign = Object.assign || function(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); +var __awaiter = (this && this.__awaiter) || function (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()); + }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; -var operations_1 = __importDefault(require("../../constants/operations")); -function getOperation() { - return operations_1.default.PNPushNotificationEnabledChannelsOperation; -} -exports.getOperation = getOperation; -function validateParams(modules, incomingParams) { - var device = incomingParams.device, pushGateway = incomingParams.pushGateway, channels = incomingParams.channels, topic = incomingParams.topic; - var config = modules.config; - if (!device) - return 'Missing Device ID (device)'; - if (!pushGateway) - return 'Missing GW Type (pushGateway: gcm, apns or apns2)'; - if (pushGateway === 'apns2' && !topic) - return 'Missing APNS2 topic'; - if (!channels || channels.length === 0) - return 'Missing Channels'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var device = incomingParams.device, pushGateway = incomingParams.pushGateway; - var config = modules.config; - if (pushGateway === 'apns2') { - return "/v2/push/sub-key/".concat(config.subscribeKey, "/devices-apns2/").concat(device); +exports.RemoveDevicePushNotificationChannelsRequest = void 0; +const pubnub_error_1 = require("../../../errors/pubnub-error"); +const push_1 = require("./push"); +const operations_1 = __importDefault(require("../../constants/operations")); +class RemoveDevicePushNotificationChannelsRequest extends push_1.BasePushNotificationChannelsRequest { + constructor(parameters) { + super(Object.assign(Object.assign({}, parameters), { action: 'remove' })); } - return "/v1/push/sub-key/".concat(config.subscribeKey, "/devices/").concat(device); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(modules, incomingParams) { - var pushGateway = incomingParams.pushGateway, _a = incomingParams.channels, channels = _a === void 0 ? [] : _a, _b = incomingParams.environment, environment = _b === void 0 ? 'development' : _b, topic = incomingParams.topic; - var parameters = { type: pushGateway, remove: channels.join(',') }; - if (pushGateway === 'apns2') { - parameters = __assign(__assign({}, parameters), { environment: environment, topic: topic }); - delete parameters.type; + operation() { + return operations_1.default.PNRemovePushNotificationEnabledChannelsOperation; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + return {}; + }); } - return parameters; -} -exports.prepareParams = prepareParams; -function handleResponse() { - return {}; } -exports.handleResponse = handleResponse; +exports.RemoveDevicePushNotificationChannelsRequest = RemoveDevicePushNotificationChannelsRequest; diff --git a/lib/core/endpoints/signal.js b/lib/core/endpoints/signal.js index e72ff68e8..ad60cb35e 100644 --- a/lib/core/endpoints/signal.js +++ b/lib/core/endpoints/signal.js @@ -1,53 +1,51 @@ "use strict"; -/* */ +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; -var operations_1 = __importDefault(require("../constants/operations")); -var utils_1 = __importDefault(require("../utils")); -function prepareMessagePayload(modules, messagePayload) { - var stringifiedPayload = JSON.stringify(messagePayload); - return stringifiedPayload; -} -function getOperation() { - return operations_1.default.PNSignalOperation; -} -exports.getOperation = getOperation; -function validateParams(_a, incomingParams) { - var config = _a.config; - var message = incomingParams.message, channel = incomingParams.channel; - if (!channel) - return 'Missing Channel'; - if (!message) - return 'Missing Message'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var config = modules.config; - var channel = incomingParams.channel, message = incomingParams.message; - var stringifiedPayload = prepareMessagePayload(modules, message); - return "/signal/".concat(config.publishKey, "/").concat(config.subscribeKey, "/0/").concat(utils_1.default.encodeString(channel), "/0/").concat(utils_1.default.encodeString(stringifiedPayload)); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams() { - var params = {}; - return params; -} -exports.prepareParams = prepareParams; -function handleResponse(modules, serverResponse) { - return { timetoken: serverResponse[2] }; -} -exports.handleResponse = handleResponse; +exports.SignalRequest = void 0; +const pubnub_error_1 = require("../../errors/pubnub-error"); +const request_1 = require("../components/request"); +const operations_1 = __importDefault(require("../constants/operations")); +const utils_1 = require("../utils"); +class SignalRequest extends request_1.AbstractRequest { + constructor(parameters) { + super(); + this.parameters = parameters; + } + operation() { + return operations_1.default.PNSignalOperation; + } + validate() { + const { message, channel, keySet: { publishKey }, } = this.parameters; + if (!channel) + return "Missing 'channel'"; + if (!message) + return "Missing 'message'"; + if (!publishKey) + return "Missing 'publishKey'"; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + return { timetoken: serviceResponse[2] }; + }); + } + get path() { + const { keySet: { publishKey, subscribeKey }, channel, message, } = this.parameters; + const stringifiedPayload = JSON.stringify(message); + return `/signal/${publishKey}/${subscribeKey}/0/${(0, utils_1.encodeString)(channel)}/0/${(0, utils_1.encodeString)(stringifiedPayload)}`; + } +} +exports.SignalRequest = SignalRequest; diff --git a/lib/core/endpoints/subscribe.js b/lib/core/endpoints/subscribe.js index 4e05c306c..2588611e4 100644 --- a/lib/core/endpoints/subscribe.js +++ b/lib/core/endpoints/subscribe.js @@ -1,88 +1,273 @@ "use strict"; +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; -/* */ -var operations_1 = __importDefault(require("../constants/operations")); -var utils_1 = __importDefault(require("../utils")); -function getOperation() { - return operations_1.default.PNSubscribeOperation; -} -exports.getOperation = getOperation; -function validateParams(modules) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var config = modules.config; - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a; - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return "/v2/subscribe/".concat(config.subscribeKey, "/").concat(utils_1.default.encodeString(stringifiedChannels), "/0"); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getSubscribeTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(_a, incomingParams) { - var config = _a.config; - var state = incomingParams.state, _b = incomingParams.channelGroups, channelGroups = _b === void 0 ? [] : _b, timetoken = incomingParams.timetoken, filterExpression = incomingParams.filterExpression, region = incomingParams.region; - var params = { - heartbeat: config.getPresenceTimeout(), - }; - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); +exports.SubscribeRequest = exports.BaseSubscribeRequest = exports.PubNubEventType = void 0; +const pubnub_error_1 = require("../../errors/pubnub-error"); +const request_1 = require("../components/request"); +const operations_1 = __importDefault(require("../constants/operations")); +const utils_1 = require("../utils"); +const WITH_PRESENCE = false; +var PubNubEventType; +(function (PubNubEventType) { + PubNubEventType[PubNubEventType["Presence"] = -2] = "Presence"; + PubNubEventType[PubNubEventType["Message"] = -1] = "Message"; + PubNubEventType[PubNubEventType["Signal"] = 1] = "Signal"; + PubNubEventType[PubNubEventType["AppContext"] = 2] = "AppContext"; + PubNubEventType[PubNubEventType["MessageAction"] = 3] = "MessageAction"; + PubNubEventType[PubNubEventType["Files"] = 4] = "Files"; +})(PubNubEventType || (exports.PubNubEventType = PubNubEventType = {})); +class BaseSubscribeRequest extends request_1.AbstractRequest { + constructor(parameters) { + var _a, _b, _c; + var _d, _e, _f; + super({ cancellable: true }); + this.parameters = parameters; + (_a = (_d = this.parameters).withPresence) !== null && _a !== void 0 ? _a : (_d.withPresence = WITH_PRESENCE); + (_b = (_e = this.parameters).channelGroups) !== null && _b !== void 0 ? _b : (_e.channelGroups = []); + (_c = (_f = this.parameters).channels) !== null && _c !== void 0 ? _c : (_f.channels = []); } - if (filterExpression && filterExpression.length > 0) { - params['filter-expr'] = filterExpression; + operation() { + return operations_1.default.PNSubscribeOperation; } - if (Object.keys(state).length) { - params.state = JSON.stringify(state); + validate() { + const { keySet: { subscribeKey }, channels, channelGroups, } = this.parameters; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!channels && !channelGroups) + return '`channels` and `channelGroups` both should not be empty'; } - if (timetoken) { - params.tt = timetoken; + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + let serviceResponse; + try { + const json = request_1.AbstractRequest.decoder.decode(response.body); + const parsedJson = JSON.parse(json); + serviceResponse = parsedJson; + } + catch (error) { + console.error('Error parsing JSON response:', error); + } + if (!serviceResponse) { + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + } + const events = serviceResponse.m.map((envelope) => { + let { e: eventType } = envelope; + eventType !== null && eventType !== void 0 ? eventType : (eventType = envelope.c.endsWith('-pnpres') ? PubNubEventType.Presence : PubNubEventType.Message); + if (typeof envelope.d === 'string') { + if (eventType == PubNubEventType.Message) { + return { + type: PubNubEventType.Message, + data: this.messageFromEnvelope(envelope), + }; + } + return { + type: PubNubEventType.Files, + data: this.fileFromEnvelope(envelope), + }; + } + else if (eventType == PubNubEventType.Message) { + return { + type: PubNubEventType.Message, + data: this.messageFromEnvelope(envelope), + }; + } + else if (eventType === PubNubEventType.Presence) { + return { + type: PubNubEventType.Presence, + data: this.presenceEventFromEnvelope(envelope), + }; + } + else if (eventType == PubNubEventType.Signal) { + return { + type: PubNubEventType.Signal, + data: this.signalFromEnvelope(envelope), + }; + } + else if (eventType === PubNubEventType.AppContext) { + return { + type: PubNubEventType.AppContext, + data: this.appContextFromEnvelope(envelope), + }; + } + else if (eventType === PubNubEventType.MessageAction) { + return { + type: PubNubEventType.MessageAction, + data: this.messageActionFromEnvelope(envelope), + }; + } + return { + type: PubNubEventType.Files, + data: this.fileFromEnvelope(envelope), + }; + }); + return { + cursor: { timetoken: serviceResponse.t.t, region: serviceResponse.t.r }, + messages: events, + }; + }); } - if (region) { - params.tr = region; + get headers() { + return { accept: 'text/javascript' }; } - return params; -} -exports.prepareParams = prepareParams; -function handleResponse(modules, serverResponse) { - var messages = []; - serverResponse.m.forEach(function (rawMessage) { - var publishMetaData = { - timetoken: rawMessage.p.t, - region: rawMessage.p.r, + presenceEventFromEnvelope(envelope) { + const { d: payload } = envelope; + const [channel, subscription] = this.subscriptionChannelFromEnvelope(envelope); + const trimmedChannel = channel.replace('-pnpres', ''); + const actualChannel = subscription !== null ? trimmedChannel : null; + const subscribedChannel = subscription !== null ? subscription : trimmedChannel; + if (typeof payload !== 'string' && 'data' in payload) { + payload['state'] = payload.data; + delete payload.data; + } + return Object.assign({ channel: trimmedChannel, subscription, + actualChannel, + subscribedChannel, timetoken: envelope.p.t }, payload); + } + messageFromEnvelope(envelope) { + const [channel, subscription] = this.subscriptionChannelFromEnvelope(envelope); + const [message, decryptionError] = this.decryptedData(envelope.d); + const actualChannel = subscription !== null ? channel : null; + const subscribedChannel = subscription !== null ? subscription : channel; + const event = { + channel, + subscription, + actualChannel, + subscribedChannel, + timetoken: envelope.p.t, + publisher: envelope.i, + message, }; - var parsedMessage = { - shard: parseInt(rawMessage.a, 10), - subscriptionMatch: rawMessage.b, - channel: rawMessage.c, - messageType: rawMessage.e, - payload: rawMessage.d, - flags: rawMessage.f, - issuingClientId: rawMessage.i, - subscribeKey: rawMessage.k, - originationTimetoken: rawMessage.o, - userMetadata: rawMessage.u, - publishMetaData: publishMetaData, + if (envelope.u) + event.userMetadata = envelope.u; + if (decryptionError) + event.error = decryptionError; + return event; + } + signalFromEnvelope(envelope) { + const [channel, subscription] = this.subscriptionChannelFromEnvelope(envelope); + const event = { + channel, + subscription, + timetoken: envelope.p.t, + publisher: envelope.i, + message: envelope.d, }; - messages.push(parsedMessage); - }); - var metadata = { - timetoken: serverResponse.t.t, - region: serverResponse.t.r, - }; - return { messages: messages, metadata: metadata }; + if (envelope.u) + event.userMetadata = envelope.u; + return event; + } + messageActionFromEnvelope(envelope) { + const [channel, subscription] = this.subscriptionChannelFromEnvelope(envelope); + const action = envelope.d; + return { + channel, + subscription, + timetoken: envelope.p.t, + publisher: envelope.i, + event: action.event, + data: Object.assign(Object.assign({}, action.data), { uuid: envelope.i }), + }; + } + appContextFromEnvelope(envelope) { + const [channel, subscription] = this.subscriptionChannelFromEnvelope(envelope); + const object = envelope.d; + return { + channel, + subscription, + timetoken: envelope.p.t, + message: object, + }; + } + fileFromEnvelope(envelope) { + const [channel, subscription] = this.subscriptionChannelFromEnvelope(envelope); + const [file, decryptionError] = this.decryptedData(envelope.d); + let errorMessage = decryptionError; + const event = { + channel, + subscription, + timetoken: envelope.p.t, + publisher: envelope.i, + }; + if (envelope.u) + event.userMetadata = envelope.u; + if (!file) + errorMessage !== null && errorMessage !== void 0 ? errorMessage : (errorMessage = `File information payload is missing.`); + else if (typeof file === 'string') + errorMessage !== null && errorMessage !== void 0 ? errorMessage : (errorMessage = `Unexpected file information payload data type.`); + else { + event.message = file.message; + if (file.file) { + event.file = { + id: file.file.id, + name: file.file.name, + url: this.parameters.getFileUrl({ id: file.file.id, name: file.file.name, channel }), + }; + } + } + if (errorMessage) + event.error = errorMessage; + return event; + } + subscriptionChannelFromEnvelope(envelope) { + return [envelope.c, envelope.b === undefined ? envelope.c : envelope.b]; + } + decryptedData(data) { + if (!this.parameters.crypto || typeof data !== 'string') + return [data, undefined]; + let payload; + let error; + try { + const decryptedData = this.parameters.crypto.decrypt(data); + payload = + decryptedData instanceof ArrayBuffer + ? JSON.parse(SubscribeRequest.decoder.decode(decryptedData)) + : decryptedData; + } + catch (err) { + payload = null; + error = `Error while decrypting message content: ${err.message}`; + } + return [(payload !== null && payload !== void 0 ? payload : data), error]; + } +} +exports.BaseSubscribeRequest = BaseSubscribeRequest; +class SubscribeRequest extends BaseSubscribeRequest { + get path() { + var _a; + const { keySet: { subscribeKey }, channels, } = this.parameters; + return `/v2/subscribe/${subscribeKey}/${(0, utils_1.encodeNames)((_a = channels === null || channels === void 0 ? void 0 : channels.sort()) !== null && _a !== void 0 ? _a : [], ',')}/0`; + } + get queryParameters() { + const { channelGroups, filterExpression, heartbeat, state, timetoken, region } = this.parameters; + const query = {}; + if (channelGroups && channelGroups.length > 0) + query['channel-group'] = channelGroups.sort().join(','); + if (filterExpression && filterExpression.length > 0) + query['filter-expr'] = filterExpression; + if (heartbeat) + query.heartbeat = heartbeat; + if (state && Object.keys(state).length > 0) + query['state'] = JSON.stringify(state); + if (timetoken !== undefined && typeof timetoken === 'string') { + if (timetoken.length > 0 && timetoken !== '0') + query['tt'] = timetoken; + } + else if (timetoken !== undefined && timetoken > 0) + query['tt'] = timetoken; + if (region) + query['tr'] = region; + return query; + } } -exports.handleResponse = handleResponse; +exports.SubscribeRequest = SubscribeRequest; diff --git a/lib/core/endpoints/subscriptionUtils/handshake.js b/lib/core/endpoints/subscriptionUtils/handshake.js index c30834e5b..36e175b4d 100644 --- a/lib/core/endpoints/subscriptionUtils/handshake.js +++ b/lib/core/endpoints/subscriptionUtils/handshake.js @@ -3,44 +3,28 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNHandshakeOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channels) && !(params === null || params === void 0 ? void 0 : params.channelGroups)) { - return 'channels and channleGroups both should not be empty'; - } - }, - getURL: function (_a, params) { - var config = _a.config; - var _b = params.channels, channels = _b === void 0 ? [] : _b; - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return "/v2/subscribe/".concat(config.subscribeKey, "/").concat(utils_1.default.encodeString(stringifiedChannels), "/0"); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getSubscribeTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_, params) { - var outParams = {}; - if (params.channelGroups && params.channelGroups.length > 0) { - outParams['channel-group'] = params.channelGroups.join(','); - } - outParams.tt = 0; - if (params.state) { - outParams.state = JSON.stringify(params.state); - } - if (params.filterExpression && params.filterExpression.length > 0) { - outParams['filter-expr'] = params.filterExpression; - } - outParams.ee = ''; - return outParams; - }, - handleResponse: function (_, response) { return ({ - region: response.t.r, - timetoken: response.t.t, - }); }, -}; -exports.default = endpoint; +exports.HandshakeSubscribeRequest = void 0; +const operations_1 = __importDefault(require("../../constants/operations")); +const subscribe_1 = require("../subscribe"); +const utils_1 = require("../../utils"); +class HandshakeSubscribeRequest extends subscribe_1.BaseSubscribeRequest { + operation() { + return operations_1.default.PNHandshakeOperation; + } + get path() { + const { keySet: { subscribeKey }, channels = [], } = this.parameters; + return `/v2/subscribe/${subscribeKey}/${(0, utils_1.encodeNames)(channels.sort(), ',')}/0`; + } + get queryParameters() { + const { channelGroups, filterExpression, state } = this.parameters; + const query = { tt: 0, ee: '' }; + if (channelGroups && channelGroups.length > 0) + query['channel-group'] = channelGroups.sort().join(','); + if (filterExpression && filterExpression.length > 0) + query['filter-expr'] = filterExpression; + if (state && Object.keys(state).length > 0) + query['state'] = JSON.stringify(state); + return query; + } +} +exports.HandshakeSubscribeRequest = HandshakeSubscribeRequest; diff --git a/lib/core/endpoints/subscriptionUtils/receiveMessages.js b/lib/core/endpoints/subscriptionUtils/receiveMessages.js index 278049190..c78a73f84 100644 --- a/lib/core/endpoints/subscriptionUtils/receiveMessages.js +++ b/lib/core/endpoints/subscriptionUtils/receiveMessages.js @@ -3,74 +3,43 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNReceiveMessagesOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channels) && !(params === null || params === void 0 ? void 0 : params.channelGroups)) { - return 'channels and channleGroups both should not be empty'; - } - if (!(params === null || params === void 0 ? void 0 : params.timetoken)) { +exports.ReceiveMessagesSubscribeRequest = void 0; +const operations_1 = __importDefault(require("../../constants/operations")); +const subscribe_1 = require("../subscribe"); +const utils_1 = require("../../utils"); +class ReceiveMessagesSubscribeRequest extends subscribe_1.BaseSubscribeRequest { + operation() { + return operations_1.default.PNReceiveMessagesOperation; + } + validate() { + const validationResult = super.validate(); + if (validationResult) + return validationResult; + if (!this.parameters.timetoken) return 'timetoken can not be empty'; - } - if (!(params === null || params === void 0 ? void 0 : params.region)) { + if (!this.parameters.region) return 'region can not be empty'; + } + get path() { + const { keySet: { subscribeKey }, channels = [], } = this.parameters; + return `/v2/subscribe/${subscribeKey}/${(0, utils_1.encodeNames)(channels.sort(), ',')}/0`; + } + get queryParameters() { + const { channelGroups, filterExpression, timetoken, region } = this.parameters; + const query = { ee: '' }; + if (channelGroups && channelGroups.length > 0) + query['channel-group'] = channelGroups.sort().join(','); + if (filterExpression && filterExpression.length > 0) + query['filter-expr'] = filterExpression; + if (typeof timetoken === 'string') { + if (timetoken && timetoken.length > 0) + query['tt'] = timetoken; } - }, - getURL: function (_a, params) { - var config = _a.config; - var _b = params.channels, channels = _b === void 0 ? [] : _b; - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return "/v2/subscribe/".concat(config.subscribeKey, "/").concat(utils_1.default.encodeString(stringifiedChannels), "/0"); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getSubscribeTimeout(); - }, - isAuthSupported: function () { return true; }, - getAbortSignal: function (_, params) { return params.abortSignal; }, - prepareParams: function (_, params) { - var outParams = {}; - if (params.channelGroups && params.channelGroups.length > 0) { - outParams['channel-group'] = params.channelGroups.join(','); - } - if (params.filterExpression && params.filterExpression.length > 0) { - outParams['filter-expr'] = params.filterExpression; - } - outParams.tt = params.timetoken; - outParams.tr = params.region; - outParams.ee = ''; - return outParams; - }, - handleResponse: function (_, response) { - var parsedMessages = []; - response.m.forEach(function (envelope) { - var parsedMessage = { - shard: parseInt(envelope.a, 10), - subscriptionMatch: envelope.b, - channel: envelope.c, - messageType: envelope.e, - payload: envelope.d, - flags: envelope.f, - issuingClientId: envelope.i, - subscribeKey: envelope.k, - originationTimetoken: envelope.o, - userMetadata: envelope.u, - publishMetaData: { - timetoken: envelope.p.t, - region: envelope.p.r, - }, - }; - parsedMessages.push(parsedMessage); - }); - return { - messages: parsedMessages, - metadata: { - region: response.t.r, - timetoken: response.t.t, - }, - }; - }, -}; -exports.default = endpoint; + else if (timetoken && timetoken > 0) + query['tt'] = timetoken; + if (region) + query['tr'] = region; + return query; + } +} +exports.ReceiveMessagesSubscribeRequest = ReceiveMessagesSubscribeRequest; diff --git a/lib/core/endpoints/time.js b/lib/core/endpoints/time.js index 8673d0a95..a09d61681 100644 --- a/lib/core/endpoints/time.js +++ b/lib/core/endpoints/time.js @@ -1,39 +1,38 @@ "use strict"; +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.validateParams = exports.handleResponse = exports.isAuthSupported = exports.prepareParams = exports.getRequestTimeout = exports.getURL = exports.getOperation = void 0; -/* */ -var operations_1 = __importDefault(require("../constants/operations")); -function getOperation() { - return operations_1.default.PNTimeOperation; -} -exports.getOperation = getOperation; -function getURL() { - return '/time/0'; -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function prepareParams() { - return {}; -} -exports.prepareParams = prepareParams; -function isAuthSupported() { - return false; -} -exports.isAuthSupported = isAuthSupported; -function handleResponse(modules, serverResponse) { - return { - timetoken: serverResponse[0], - }; -} -exports.handleResponse = handleResponse; -function validateParams() { - // pass +exports.TimeRequest = void 0; +const pubnub_error_1 = require("../../errors/pubnub-error"); +const request_1 = require("../components/request"); +const operations_1 = __importDefault(require("../constants/operations")); +class TimeRequest extends request_1.AbstractRequest { + constructor() { + super(); + } + operation() { + return operations_1.default.PNTimeOperation; + } + parse(response) { + return __awaiter(this, void 0, void 0, function* () { + const serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new pubnub_error_1.PubNubError('Service response error, check status for details', (0, pubnub_error_1.createValidationError)('Unable to deserialize service response')); + return { timetoken: serviceResponse[0] }; + }); + } + get path() { + return '/time/0'; + } } -exports.validateParams = validateParams; +exports.TimeRequest = TimeRequest; diff --git a/lib/core/endpoints/user/create.js b/lib/core/endpoints/user/create.js deleted file mode 100644 index e9526855c..000000000 --- a/lib/core/endpoints/user/create.js +++ /dev/null @@ -1,40 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNCreateUserOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.data)) { - return 'Data cannot be empty'; - } - }, - usePost: function () { return true; }, - postURL: function (_a, params) { - var _b; - var config = _a.config; - return "/v3/objects/".concat(config.subscribeKey, "/users/").concat(utils_1.default.encodeString((_b = params.userId) !== null && _b !== void 0 ? _b : config.getUserId())); - }, - postPayload: function (_, params) { return params.data; }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_a, params) { - var _b; - var config = _a.config; - var queryParams = { - uuid: (_b = params === null || params === void 0 ? void 0 : params.userId) !== null && _b !== void 0 ? _b : config.getUserId(), - }; - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - }); }, -}; -exports.default = endpoint; diff --git a/lib/core/endpoints/user/fetch.js b/lib/core/endpoints/user/fetch.js deleted file mode 100644 index 473da58c5..000000000 --- a/lib/core/endpoints/user/fetch.js +++ /dev/null @@ -1,34 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNFetchUserOperation; }, - validateParams: function () { - // No required parameters. - }, - getURL: function (_a, params) { - var _b; - var config = _a.config; - return "/v3/objects/".concat(config.subscribeKey, "/users/").concat(utils_1.default.encodeString((_b = params === null || params === void 0 ? void 0 : params.userId) !== null && _b !== void 0 ? _b : config.getUserId())); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_a, params) { - var _b; - var config = _a.config; - var queryParams = { uuid: (_b = params === null || params === void 0 ? void 0 : params.userId) !== null && _b !== void 0 ? _b : config.getUserId() }; - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - }); }, -}; -exports.default = endpoint; diff --git a/lib/core/interfaces/configuration.js b/lib/core/interfaces/configuration.js new file mode 100644 index 000000000..bd776878e --- /dev/null +++ b/lib/core/interfaces/configuration.js @@ -0,0 +1,90 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.setDefaults = void 0; +const pubnub_error_1 = require("../../errors/pubnub-error"); +const USE_SSL = true; +const RESTORE = false; +const AUTO_NETWORK_DETECTION = false; +const DEDUPE_ON_SUBSCRIBE = false; +const DEDUPE_CACHE_SIZE = 100; +const FILE_PUBLISH_RETRY_LIMIT = 5; +const ENABLE_EVENT_ENGINE = false; +const MAINTAIN_PRESENCE_STATE = true; +const KEEP_ALIVE = false; +const USE_VERBOSE_LOGGING = false; +const SUPPRESS_LEAVE_EVENTS = false; +const ANNOUNCE_HEARTBEAT_FAILURE = true; +const ANNOUNCE_HEARTBEAT_SUCCESS = false; +const USE_INSTANCE_ID = false; +const USE_REQUEST_ID = true; +const TRANSACTIONAL_REQUEST_TIMEOUT = 15; +const SUBSCRIBE_REQUEST_TIMEOUT = 310; +const PRESENCE_TIMEOUT = 300; +const PRESENCE_TIMEOUT_MINIMUM = 20; +const setDefaults = (configuration) => { + var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q; + const configurationCopy = Object.assign({}, configuration); + (_a = configurationCopy.logVerbosity) !== null && _a !== void 0 ? _a : (configurationCopy.logVerbosity = USE_VERBOSE_LOGGING); + (_b = configurationCopy.ssl) !== null && _b !== void 0 ? _b : (configurationCopy.ssl = USE_SSL); + (_c = configurationCopy.transactionalRequestTimeout) !== null && _c !== void 0 ? _c : (configurationCopy.transactionalRequestTimeout = TRANSACTIONAL_REQUEST_TIMEOUT); + (_d = configurationCopy.subscribeRequestTimeout) !== null && _d !== void 0 ? _d : (configurationCopy.subscribeRequestTimeout = SUBSCRIBE_REQUEST_TIMEOUT); + (_e = configurationCopy.restore) !== null && _e !== void 0 ? _e : (configurationCopy.restore = RESTORE); + (_f = configurationCopy.useInstanceId) !== null && _f !== void 0 ? _f : (configurationCopy.useInstanceId = USE_INSTANCE_ID); + (_g = configurationCopy.suppressLeaveEvents) !== null && _g !== void 0 ? _g : (configurationCopy.suppressLeaveEvents = SUPPRESS_LEAVE_EVENTS); + (_h = configurationCopy.requestMessageCountThreshold) !== null && _h !== void 0 ? _h : (configurationCopy.requestMessageCountThreshold = DEDUPE_CACHE_SIZE); + (_j = configurationCopy.autoNetworkDetection) !== null && _j !== void 0 ? _j : (configurationCopy.autoNetworkDetection = AUTO_NETWORK_DETECTION); + (_k = configurationCopy.enableEventEngine) !== null && _k !== void 0 ? _k : (configurationCopy.enableEventEngine = ENABLE_EVENT_ENGINE); + (_l = configurationCopy.maintainPresenceState) !== null && _l !== void 0 ? _l : (configurationCopy.maintainPresenceState = MAINTAIN_PRESENCE_STATE); + (_m = configurationCopy.keepAlive) !== null && _m !== void 0 ? _m : (configurationCopy.keepAlive = KEEP_ALIVE); + if (configurationCopy.userId && configurationCopy.uuid) + throw new pubnub_error_1.PubNubError("PubNub client configuration error: use only 'userId'"); + (_o = configurationCopy.userId) !== null && _o !== void 0 ? _o : (configurationCopy.userId = configurationCopy.uuid); + if (!configurationCopy.userId) + throw new pubnub_error_1.PubNubError("PubNub client configuration error: 'userId' not set"); + else if (((_p = configurationCopy.userId) === null || _p === void 0 ? void 0 : _p.trim().length) === 0) + throw new pubnub_error_1.PubNubError("PubNub client configuration error: 'userId' is empty"); + if (!configurationCopy.origin) + configurationCopy.origin = Array.from({ length: 20 }, (_, i) => `ps${i + 1}.pndsn.com`); + const keySet = { + subscribeKey: configurationCopy.subscribeKey, + publishKey: configurationCopy.publishKey, + secretKey: configurationCopy.secretKey, + }; + if (configurationCopy.presenceTimeout !== undefined && configurationCopy.presenceTimeout < PRESENCE_TIMEOUT_MINIMUM) { + configurationCopy.presenceTimeout = PRESENCE_TIMEOUT_MINIMUM; + console.log('WARNING: Presence timeout is less than the minimum. Using minimum value: ', PRESENCE_TIMEOUT_MINIMUM); + } + (_q = configurationCopy.presenceTimeout) !== null && _q !== void 0 ? _q : (configurationCopy.presenceTimeout = PRESENCE_TIMEOUT); + let announceSuccessfulHeartbeats = ANNOUNCE_HEARTBEAT_SUCCESS; + let announceFailedHeartbeats = ANNOUNCE_HEARTBEAT_FAILURE; + let fileUploadPublishRetryLimit = FILE_PUBLISH_RETRY_LIMIT; + let dedupeOnSubscribe = DEDUPE_ON_SUBSCRIBE; + const maximumCacheSize = DEDUPE_CACHE_SIZE; + let useRequestId = USE_REQUEST_ID; + if (configurationCopy.dedupeOnSubscribe !== undefined && typeof configurationCopy.dedupeOnSubscribe === 'boolean') { + dedupeOnSubscribe = configurationCopy.dedupeOnSubscribe; + } + if (configurationCopy.useRequestId !== undefined && typeof configurationCopy.useRequestId === 'boolean') { + useRequestId = configurationCopy.useRequestId; + } + if (configurationCopy.announceSuccessfulHeartbeats !== undefined && + typeof configurationCopy.announceSuccessfulHeartbeats === 'boolean') { + announceSuccessfulHeartbeats = configurationCopy.announceSuccessfulHeartbeats; + } + if (configurationCopy.announceFailedHeartbeats !== undefined && + typeof configurationCopy.announceFailedHeartbeats === 'boolean') { + announceFailedHeartbeats = configurationCopy.announceFailedHeartbeats; + } + if (configurationCopy.fileUploadPublishRetryLimit !== undefined && + typeof configurationCopy.fileUploadPublishRetryLimit === 'number') { + fileUploadPublishRetryLimit = configurationCopy.fileUploadPublishRetryLimit; + } + return Object.assign(Object.assign({}, configurationCopy), { keySet, + dedupeOnSubscribe, + maximumCacheSize, + useRequestId, + announceSuccessfulHeartbeats, + announceFailedHeartbeats, + fileUploadPublishRetryLimit }); +}; +exports.setDefaults = setDefaults; diff --git a/lib/core/interfaces/crypto-module.js b/lib/core/interfaces/crypto-module.js new file mode 100644 index 000000000..72ba0823b --- /dev/null +++ b/lib/core/interfaces/crypto-module.js @@ -0,0 +1,22 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.AbstractCryptoModule = void 0; +class AbstractCryptoModule { + static legacyCryptoModule(config) { + throw new Error('Should be implemented by concrete crypto module implementation.'); + } + static aesCbcCryptoModule(config) { + throw new Error('Should be implemented by concrete crypto module implementation.'); + } + constructor(configuration) { + var _a; + this.defaultCryptor = configuration.default; + this.cryptors = (_a = configuration.cryptors) !== null && _a !== void 0 ? _a : []; + } + getAllCryptors() { + return [this.defaultCryptor, ...this.cryptors]; + } +} +exports.AbstractCryptoModule = AbstractCryptoModule; +AbstractCryptoModule.encoder = new TextEncoder(); +AbstractCryptoModule.decoder = new TextDecoder(); diff --git a/lib/core/components/_endpoint.js b/lib/core/interfaces/cryptography.js similarity index 100% rename from lib/core/components/_endpoint.js rename to lib/core/interfaces/cryptography.js diff --git a/lib/crypto/modules/WebCryptoModule/ICryptor.js b/lib/core/interfaces/request.js similarity index 100% rename from lib/crypto/modules/WebCryptoModule/ICryptor.js rename to lib/core/interfaces/request.js diff --git a/lib/crypto/modules/WebCryptoModule/ILegacyCryptor.js b/lib/core/interfaces/transport.js similarity index 100% rename from lib/crypto/modules/WebCryptoModule/ILegacyCryptor.js rename to lib/core/interfaces/transport.js diff --git a/lib/core/pubnub-channel-groups.js b/lib/core/pubnub-channel-groups.js new file mode 100644 index 000000000..fbab5c9b9 --- /dev/null +++ b/lib/core/pubnub-channel-groups.js @@ -0,0 +1,63 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const remove_channels_1 = require("./endpoints/channel_groups/remove_channels"); +const add_channels_1 = require("./endpoints/channel_groups/add_channels"); +const list_channels_1 = require("./endpoints/channel_groups/list_channels"); +const delete_group_1 = require("./endpoints/channel_groups/delete_group"); +const list_groups_1 = require("./endpoints/channel_groups/list_groups"); +class PubnubChannelGroups { + constructor(keySet, sendRequest) { + this.keySet = keySet; + this.sendRequest = sendRequest; + } + listChannels(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new list_channels_1.ListChannelGroupChannels(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + listGroups(callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new list_groups_1.ListChannelGroupsRequest({ keySet: this.keySet }); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + addChannels(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new add_channels_1.AddChannelGroupChannelsRequest(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + removeChannels(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new remove_channels_1.RemoveChannelGroupChannelsRequest(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + deleteGroup(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new delete_group_1.DeleteChannelGroupRequest(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } +} +exports.default = PubnubChannelGroups; diff --git a/lib/core/pubnub-common.js b/lib/core/pubnub-common.js index 9a145cdc7..e0eed71e2 100644 --- a/lib/core/pubnub-common.js +++ b/lib/core/pubnub-common.js @@ -1,15 +1,4 @@ "use strict"; -var __assign = (this && this.__assign) || function () { - __assign = Object.assign || function(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); -}; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); @@ -33,641 +22,845 @@ var __importStar = (this && this.__importStar) || function (mod) { __setModuleDefault(result, mod); return result; }; -var __values = (this && this.__values) || function(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."); -}; -var __read = (this && this.__read) || function (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; -}; -var __spreadArray = (this && this.__spreadArray) || function (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)); +var __awaiter = (this && this.__awaiter) || function (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()); + }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -var config_1 = __importDefault(require("./components/config")); -var index_1 = __importDefault(require("./components/cryptography/index")); -var base64_codec_1 = require("./components/base64_codec"); -var subscription_manager_1 = __importDefault(require("./components/subscription_manager")); -var telemetry_manager_1 = __importDefault(require("./components/telemetry_manager")); -var push_payload_1 = __importDefault(require("./components/push_payload")); -var listener_manager_1 = __importDefault(require("./components/listener_manager")); -var token_manager_1 = __importDefault(require("./components/token_manager")); -var endpoint_1 = __importDefault(require("./components/endpoint")); -var addChannelsChannelGroupConfig = __importStar(require("./endpoints/channel_groups/add_channels")); -var removeChannelsChannelGroupConfig = __importStar(require("./endpoints/channel_groups/remove_channels")); -var deleteChannelGroupConfig = __importStar(require("./endpoints/channel_groups/delete_group")); -var listChannelGroupsConfig = __importStar(require("./endpoints/channel_groups/list_groups")); -var listChannelsInChannelGroupConfig = __importStar(require("./endpoints/channel_groups/list_channels")); -var addPushChannelsConfig = __importStar(require("./endpoints/push/add_push_channels")); -var removePushChannelsConfig = __importStar(require("./endpoints/push/remove_push_channels")); -var listPushChannelsConfig = __importStar(require("./endpoints/push/list_push_channels")); -var removeDevicePushConfig = __importStar(require("./endpoints/push/remove_device")); -var presenceLeaveEndpointConfig = __importStar(require("./endpoints/presence/leave")); -var presenceWhereNowEndpointConfig = __importStar(require("./endpoints/presence/where_now")); -var presenceHeartbeatEndpointConfig = __importStar(require("./endpoints/presence/heartbeat")); -var presenceGetStateConfig = __importStar(require("./endpoints/presence/get_state")); -var presenceSetStateConfig = __importStar(require("./endpoints/presence/set_state")); -var presenceHereNowConfig = __importStar(require("./endpoints/presence/here_now")); -// Actions API -var addMessageActionEndpointConfig = __importStar(require("./endpoints/actions/add_message_action")); -var removeMessageActionEndpointConfig = __importStar(require("./endpoints/actions/remove_message_action")); -var getMessageActionEndpointConfig = __importStar(require("./endpoints/actions/get_message_actions")); -// File Upload API v1 -var list_files_1 = __importDefault(require("./endpoints/file_upload/list_files")); -var generate_upload_url_1 = __importDefault(require("./endpoints/file_upload/generate_upload_url")); -var publish_file_1 = __importDefault(require("./endpoints/file_upload/publish_file")); -var send_file_1 = __importDefault(require("./endpoints/file_upload/send_file")); -var get_file_url_1 = __importDefault(require("./endpoints/file_upload/get_file_url")); -var download_file_1 = __importDefault(require("./endpoints/file_upload/download_file")); -var delete_file_1 = __importDefault(require("./endpoints/file_upload/delete_file")); -// Object API v2 -var get_all_1 = __importDefault(require("./endpoints/objects/uuid/get_all")); -var get_1 = __importDefault(require("./endpoints/objects/uuid/get")); -var set_1 = __importDefault(require("./endpoints/objects/uuid/set")); -var remove_1 = __importDefault(require("./endpoints/objects/uuid/remove")); -var get_all_2 = __importDefault(require("./endpoints/objects/channel/get_all")); -var get_2 = __importDefault(require("./endpoints/objects/channel/get")); -var set_2 = __importDefault(require("./endpoints/objects/channel/set")); -var remove_2 = __importDefault(require("./endpoints/objects/channel/remove")); -var get_3 = __importDefault(require("./endpoints/objects/member/get")); -var set_3 = __importDefault(require("./endpoints/objects/member/set")); -var get_4 = __importDefault(require("./endpoints/objects/membership/get")); -var set_4 = __importDefault(require("./endpoints/objects/membership/set")); -var auditEndpointConfig = __importStar(require("./endpoints/access_manager/audit")); -var grantEndpointConfig = __importStar(require("./endpoints/access_manager/grant")); -var grantTokenEndpointConfig = __importStar(require("./endpoints/access_manager/grant_token")); -var revoke_token_1 = __importDefault(require("./endpoints/access_manager/revoke_token")); -var publishEndpointConfig = __importStar(require("./endpoints/publish")); -var signalEndpointConfig = __importStar(require("./endpoints/signal")); -var historyEndpointConfig = __importStar(require("./endpoints/history/get_history")); -var deleteMessagesEndpointConfig = __importStar(require("./endpoints/history/delete_messages")); -var messageCountsEndpointConfig = __importStar(require("./endpoints/history/message_counts")); -var fetchMessagesEndpointConfig = __importStar(require("./endpoints/fetch_messages")); -var timeEndpointConfig = __importStar(require("./endpoints/time")); -var subscribeEndpointConfig = __importStar(require("./endpoints/subscribe")); -// subscription utilities -var handshake_1 = __importDefault(require("./endpoints/subscriptionUtils/handshake")); -var receiveMessages_1 = __importDefault(require("./endpoints/subscriptionUtils/receiveMessages")); -var operations_1 = __importDefault(require("./constants/operations")); -var categories_1 = __importDefault(require("./constants/categories")); -var uuid_1 = __importDefault(require("./components/uuid")); -var event_engine_1 = require("../event-engine"); -var presence_1 = require("../event-engine/presence/presence"); -var retryPolicy_1 = require("../event-engine/core/retryPolicy"); -var eventEmitter_1 = __importDefault(require("./components/eventEmitter")); -var Channel_1 = require("../entities/Channel"); -var ChannelGroup_1 = require("../entities/ChannelGroup"); -var ChannelMetadata_1 = require("../entities/ChannelMetadata"); -var UserMetadata_1 = require("../entities/UserMetadata"); -var SubscriptionSet_1 = require("../entities/SubscriptionSet"); -var default_1 = /** @class */ (function () { - function default_1(setup) { - var _this = this; - var networking = setup.networking, cbor = setup.cbor; - var config = new config_1.default({ setup: setup }); - this._config = config; - var crypto = new index_1.default({ config: config }); // LEGACY - var cryptography = setup.cryptography; - networking.init(config); - var tokenManager = new token_manager_1.default(config, cbor); - this._tokenManager = tokenManager; - var telemetryManager = new telemetry_manager_1.default({ - maximumSamplesCount: 60000, - }); - this._telemetryManager = telemetryManager; - var cryptoModule = this._config.cryptoModule; - var modules = { - config: config, - networking: networking, - crypto: crypto, - cryptography: cryptography, - tokenManager: tokenManager, - telemetryManager: telemetryManager, - PubNubFile: setup.PubNubFile, - cryptoModule: cryptoModule, - }; - this.File = setup.PubNubFile; - this.encryptFile = function (key, file) { - if (arguments.length == 1 && typeof key != 'string' && modules.cryptoModule) { - file = key; - return modules.cryptoModule.encryptFile(file, this.File); - } - return cryptography.encryptFile(key, file, this.File); - }; - this.decryptFile = function (key, file) { - if (arguments.length == 1 && typeof key != 'string' && modules.cryptoModule) { - file = key; - return modules.cryptoModule.decryptFile(file, this.File); - } - return cryptography.decryptFile(key, file, this.File); - }; - var timeEndpoint = endpoint_1.default.bind(this, modules, timeEndpointConfig); - var leaveEndpoint = endpoint_1.default.bind(this, modules, presenceLeaveEndpointConfig); - var heartbeatEndpoint = endpoint_1.default.bind(this, modules, presenceHeartbeatEndpointConfig); - var setStateEndpoint = endpoint_1.default.bind(this, modules, presenceSetStateConfig); - var subscribeEndpoint = endpoint_1.default.bind(this, modules, subscribeEndpointConfig); - // managers - var listenerManager = new listener_manager_1.default(); - this._listenerManager = listenerManager; - this.iAmHere = endpoint_1.default.bind(this, modules, presenceHeartbeatEndpointConfig); - this.iAmAway = endpoint_1.default.bind(this, modules, presenceLeaveEndpointConfig); - this.setPresenceState = endpoint_1.default.bind(this, modules, presenceSetStateConfig); - this.handshake = endpoint_1.default.bind(this, modules, handshake_1.default); - this.receiveMessages = endpoint_1.default.bind(this, modules, receiveMessages_1.default); - this._eventEmitter = new eventEmitter_1.default({ - modules: modules, - listenerManager: this._listenerManager, - getFileUrl: function (params) { return (0, get_file_url_1.default)(modules, params); }, - }); - if (config.enableEventEngine === true) { - if (config.maintainPresenceState) { - this.presenceState = {}; - this.setState = function (args) { - var _a, _b; - (_a = args.channels) === null || _a === void 0 ? void 0 : _a.forEach(function (channel) { return (_this.presenceState[channel] = args.state); }); - (_b = args.channelGroups) === null || _b === void 0 ? void 0 : _b.forEach(function (group) { return (_this.presenceState[group] = args.state); }); - return _this.setPresenceState({ - channels: args.channels, - channelGroups: args.channelGroups, - state: _this.presenceState, - }); - }; - } - if (config.getHeartbeatInterval()) { - var presenceEventEngine = new presence_1.PresenceEventEngine({ - heartbeat: this.iAmHere, - leave: this.iAmAway, - heartbeatDelay: function () { - return new Promise(function (resolve) { return setTimeout(resolve, modules.config.getHeartbeatInterval() * 1000); }); - }, - retryDelay: function (amount) { return new Promise(function (resolve) { return setTimeout(resolve, amount); }); }, - config: modules.config, +exports.PubNubCore = void 0; +const listener_manager_1 = require("./components/listener_manager"); +const subscription_manager_1 = require("./components/subscription-manager"); +const push_payload_1 = __importDefault(require("./components/push_payload")); +const eventEmitter_1 = __importDefault(require("./components/eventEmitter")); +const base64_codec_1 = require("./components/base64_codec"); +const uuid_1 = __importDefault(require("./components/uuid")); +const operations_1 = __importDefault(require("./constants/operations")); +const categories_1 = __importDefault(require("./constants/categories")); +const pubnub_error_1 = require("../errors/pubnub-error"); +const pubnub_api_error_1 = require("../errors/pubnub-api-error"); +const presence_1 = require("../event-engine/presence/presence"); +const retryPolicy_1 = require("../event-engine/core/retryPolicy"); +const event_engine_1 = require("../event-engine"); +const Publish = __importStar(require("./endpoints/publish")); +const Signal = __importStar(require("./endpoints/signal")); +const subscribe_1 = require("./endpoints/subscribe"); +const receiveMessages_1 = require("./endpoints/subscriptionUtils/receiveMessages"); +const handshake_1 = require("./endpoints/subscriptionUtils/handshake"); +const get_state_1 = require("./endpoints/presence/get_state"); +const set_state_1 = require("./endpoints/presence/set_state"); +const heartbeat_1 = require("./endpoints/presence/heartbeat"); +const leave_1 = require("./endpoints/presence/leave"); +const where_now_1 = require("./endpoints/presence/where_now"); +const here_now_1 = require("./endpoints/presence/here_now"); +const delete_messages_1 = require("./endpoints/history/delete_messages"); +const message_counts_1 = require("./endpoints/history/message_counts"); +const get_history_1 = require("./endpoints/history/get_history"); +const fetch_messages_1 = require("./endpoints/fetch_messages"); +const get_message_actions_1 = require("./endpoints/actions/get_message_actions"); +const add_message_action_1 = require("./endpoints/actions/add_message_action"); +const remove_message_action_1 = require("./endpoints/actions/remove_message_action"); +const publish_file_1 = require("./endpoints/file_upload/publish_file"); +const get_file_url_1 = require("./endpoints/file_upload/get_file_url"); +const delete_file_1 = require("./endpoints/file_upload/delete_file"); +const list_files_1 = require("./endpoints/file_upload/list_files"); +const send_file_1 = require("./endpoints/file_upload/send_file"); +const revoke_token_1 = require("./endpoints/access_manager/revoke_token"); +const grant_token_1 = require("./endpoints/access_manager/grant_token"); +const grant_1 = require("./endpoints/access_manager/grant"); +const audit_1 = require("./endpoints/access_manager/audit"); +const ChannelMetadata_1 = require("../entities/ChannelMetadata"); +const SubscriptionSet_1 = require("../entities/SubscriptionSet"); +const ChannelGroup_1 = require("../entities/ChannelGroup"); +const UserMetadata_1 = require("../entities/UserMetadata"); +const Channel_1 = require("../entities/Channel"); +const pubnub_channel_groups_1 = __importDefault(require("./pubnub-channel-groups")); +const pubnub_push_1 = __importDefault(require("./pubnub-push")); +const pubnub_objects_1 = __importDefault(require("./pubnub-objects")); +const Time = __importStar(require("./endpoints/time")); +const utils_1 = require("./utils"); +const download_file_1 = require("./endpoints/file_upload/download_file"); +class PubNubCore { + static notificationPayload(title, body) { + return new push_payload_1.default(title, body); + } + static generateUUID() { + return uuid_1.default.createUUID(); + } + constructor(configuration) { + this._configuration = configuration.configuration; + this.cryptography = configuration.cryptography; + this.tokenManager = configuration.tokenManager; + this.transport = configuration.transport; + this.crypto = configuration.crypto; + this._objects = new pubnub_objects_1.default(this._configuration, this.sendRequest.bind(this)); + this._channelGroups = new pubnub_channel_groups_1.default(this._configuration.keySet, this.sendRequest.bind(this)); + this._push = new pubnub_push_1.default(this._configuration.keySet, this.sendRequest.bind(this)); + this.listenerManager = new listener_manager_1.ListenerManager(); + this.eventEmitter = new eventEmitter_1.default(this.listenerManager); + if (this._configuration.enableEventEngine) { + let heartbeatInterval = this._configuration.getHeartbeatInterval(); + this.presenceState = {}; + if (heartbeatInterval) { + this.presenceEventEngine = new presence_1.PresenceEventEngine({ + heartbeat: this.heartbeat.bind(this), + leave: (parameters) => this.makeUnsubscribe(parameters, () => { }), + heartbeatDelay: () => new Promise((resolve, reject) => { + heartbeatInterval = this._configuration.getHeartbeatInterval(); + if (!heartbeatInterval) + reject(new pubnub_error_1.PubNubError('Heartbeat interval has been reset.')); + else + setTimeout(resolve, heartbeatInterval * 1000); + }), + retryDelay: (amount) => new Promise((resolve) => setTimeout(resolve, amount)), + emitStatus: (status) => this.listenerManager.announceStatus(status), + config: this._configuration, presenceState: this.presenceState, - emitStatus: function (status) { - listenerManager.announceStatus(status); - }, }); - this.presenceEventEngine = presenceEventEngine; - this.join = this.presenceEventEngine.join.bind(presenceEventEngine); - this.leave = this.presenceEventEngine.leave.bind(presenceEventEngine); - this.leaveAll = this.presenceEventEngine.leaveAll.bind(presenceEventEngine); } - var eventEngine = new event_engine_1.EventEngine({ - handshake: this.handshake, - receiveMessages: this.receiveMessages, - delay: function (amount) { return new Promise(function (resolve) { return setTimeout(resolve, amount); }); }, - join: this.join, - leave: this.leave, - leaveAll: this.leaveAll, + this.eventEngine = new event_engine_1.EventEngine({ + handshake: this.subscribeHandshake.bind(this), + receiveMessages: this.subscribeReceiveMessages.bind(this), + delay: (amount) => new Promise((resolve) => setTimeout(resolve, amount)), + join: this.join.bind(this), + leave: this.leave.bind(this), + leaveAll: this.leaveAll.bind(this), presenceState: this.presenceState, - config: modules.config, - emitMessages: function (events) { - var e_1, _a; + config: this._configuration, + emitMessages: (events) => { try { - for (var events_1 = __values(events), events_1_1 = events_1.next(); !events_1_1.done; events_1_1 = events_1.next()) { - var event_1 = events_1_1.value; - _this._eventEmitter.emitEvent(event_1); - } + events.forEach((event) => this.eventEmitter.emitEvent(event)); } - catch (e_1_1) { e_1 = { error: e_1_1 }; } - finally { - try { - if (events_1_1 && !events_1_1.done && (_a = events_1.return)) _a.call(events_1); - } - finally { if (e_1) throw e_1.error; } + catch (e) { + const errorStatus = { + error: true, + category: categories_1.default.PNUnknownCategory, + errorData: e, + statusCode: 0, + }; + this.listenerManager.announceStatus(errorStatus); } }, - emitStatus: function (status) { - listenerManager.announceStatus(status); - }, + emitStatus: (status) => this.listenerManager.announceStatus(status), }); - this.subscribe = eventEngine.subscribe.bind(eventEngine); - this.unsubscribe = eventEngine.unsubscribe.bind(eventEngine); - this.unsubscribeAll = eventEngine.unsubscribeAll.bind(eventEngine); - this.reconnect = eventEngine.reconnect.bind(eventEngine); - this.disconnect = eventEngine.disconnect.bind(eventEngine); - this.destroy = eventEngine.dispose.bind(eventEngine); - this.getSubscribedChannels = eventEngine.getSubscribedChannels.bind(eventEngine); - this.getSubscribedChannelGroups = eventEngine.getSubscribedChannelGroups.bind(eventEngine); - this.eventEngine = eventEngine; } else { - var subscriptionManager_1 = new subscription_manager_1.default({ - timeEndpoint: timeEndpoint, - leaveEndpoint: leaveEndpoint, - heartbeatEndpoint: heartbeatEndpoint, - setStateEndpoint: setStateEndpoint, - subscribeEndpoint: subscribeEndpoint, - crypto: modules.crypto, - config: modules.config, - listenerManager: listenerManager, - getFileUrl: function (params) { return (0, get_file_url_1.default)(modules, params); }, - cryptoModule: modules.cryptoModule, - eventEmitter: this._eventEmitter, - }); - this.subscribe = subscriptionManager_1.adaptSubscribeChange.bind(subscriptionManager_1); - this.unsubscribe = subscriptionManager_1.adaptUnsubscribeChange.bind(subscriptionManager_1); - this.disconnect = subscriptionManager_1.disconnect.bind(subscriptionManager_1); - this.reconnect = subscriptionManager_1.reconnect.bind(subscriptionManager_1); - this.unsubscribeAll = subscriptionManager_1.unsubscribeAll.bind(subscriptionManager_1); - this.getSubscribedChannels = subscriptionManager_1.getSubscribedChannels.bind(subscriptionManager_1); - this.getSubscribedChannelGroups = subscriptionManager_1.getSubscribedChannelGroups.bind(subscriptionManager_1); - this.setState = subscriptionManager_1.adaptStateChange.bind(subscriptionManager_1); - this.presence = subscriptionManager_1.adaptPresenceChange.bind(subscriptionManager_1); - this.destroy = function (isOffline) { - subscriptionManager_1.unsubscribeAll(isOffline); - subscriptionManager_1.disconnect(); - }; + this.subscriptionManager = new subscription_manager_1.SubscriptionManager(this._configuration, this.listenerManager, this.eventEmitter, this.makeSubscribe.bind(this), this.heartbeat.bind(this), this.makeUnsubscribe.bind(this), this.time.bind(this)); } - this.addListener = this._eventEmitter.addListener.bind(this._eventEmitter); - this.removeListener = this._eventEmitter.removeListener.bind(this._eventEmitter); - this.removeAllListeners = this._eventEmitter.removeAllListeners.bind(this._eventEmitter); - this.parseToken = tokenManager.parseToken.bind(tokenManager); - this.setToken = tokenManager.setToken.bind(tokenManager); - this.getToken = tokenManager.getToken.bind(tokenManager); - /* channel groups */ - this.channelGroups = { - listGroups: endpoint_1.default.bind(this, modules, listChannelGroupsConfig), - listChannels: endpoint_1.default.bind(this, modules, listChannelsInChannelGroupConfig), - addChannels: endpoint_1.default.bind(this, modules, addChannelsChannelGroupConfig), - removeChannels: endpoint_1.default.bind(this, modules, removeChannelsChannelGroupConfig), - deleteGroup: endpoint_1.default.bind(this, modules, deleteChannelGroupConfig), - }; - /* push */ - this.push = { - addChannels: endpoint_1.default.bind(this, modules, addPushChannelsConfig), - removeChannels: endpoint_1.default.bind(this, modules, removePushChannelsConfig), - deleteDevice: endpoint_1.default.bind(this, modules, removeDevicePushConfig), - listChannels: endpoint_1.default.bind(this, modules, listPushChannelsConfig), - }; - /* presence */ - this.hereNow = endpoint_1.default.bind(this, modules, presenceHereNowConfig); - this.whereNow = endpoint_1.default.bind(this, modules, presenceWhereNowEndpointConfig); - this.getState = endpoint_1.default.bind(this, modules, presenceGetStateConfig); - /* PAM */ - this.grant = endpoint_1.default.bind(this, modules, grantEndpointConfig); - this.grantToken = endpoint_1.default.bind(this, modules, grantTokenEndpointConfig); - this.audit = endpoint_1.default.bind(this, modules, auditEndpointConfig); - this.revokeToken = endpoint_1.default.bind(this, modules, revoke_token_1.default); - this.publish = endpoint_1.default.bind(this, modules, publishEndpointConfig); - this.fire = function (args, callback) { - args.replicate = false; - args.storeInHistory = false; - return _this.publish(args, callback); - }; - this.signal = endpoint_1.default.bind(this, modules, signalEndpointConfig); - this.history = endpoint_1.default.bind(this, modules, historyEndpointConfig); - this.deleteMessages = endpoint_1.default.bind(this, modules, deleteMessagesEndpointConfig); - this.messageCounts = endpoint_1.default.bind(this, modules, messageCountsEndpointConfig); - this.fetchMessages = endpoint_1.default.bind(this, modules, fetchMessagesEndpointConfig); - // Actions API - this.addMessageAction = endpoint_1.default.bind(this, modules, addMessageActionEndpointConfig); - this.removeMessageAction = endpoint_1.default.bind(this, modules, removeMessageActionEndpointConfig); - this.getMessageActions = endpoint_1.default.bind(this, modules, getMessageActionEndpointConfig); - // File Upload API v1 - this.listFiles = endpoint_1.default.bind(this, modules, list_files_1.default); - var generateUploadUrl = endpoint_1.default.bind(this, modules, generate_upload_url_1.default); - this.publishFile = endpoint_1.default.bind(this, modules, publish_file_1.default); - this.sendFile = (0, send_file_1.default)({ - generateUploadUrl: generateUploadUrl, - publishFile: this.publishFile, - modules: modules, - }); - this.getFileUrl = function (params) { return (0, get_file_url_1.default)(modules, params); }; - this.downloadFile = endpoint_1.default.bind(this, modules, download_file_1.default); - this.deleteFile = endpoint_1.default.bind(this, modules, delete_file_1.default); - // entities - this.channel = function (name) { return new Channel_1.Channel(name, _this._eventEmitter, _this); }; - this.channelGroup = function (name) { return new ChannelGroup_1.ChannelGroup(name, _this._eventEmitter, _this); }; - this.channelMetadata = function (id) { return new ChannelMetadata_1.ChannelMetadata(id, _this._eventEmitter, _this); }; - this.userMetadata = function (id) { return new UserMetadata_1.UserMetadata(id, _this._eventEmitter, _this); }; - this.subscriptionSet = function (args) { - return new SubscriptionSet_1.SubscriptionSet({ - channels: args.channels, - channelGroups: args.channelGroups, - subscriptionOptions: args.subscriptionOptions, - eventEmitter: _this._eventEmitter, - pubnub: _this, - }); - }; - // Objects API v2 - this.objects = { - getAllUUIDMetadata: endpoint_1.default.bind(this, modules, get_all_1.default), - getUUIDMetadata: endpoint_1.default.bind(this, modules, get_1.default), - setUUIDMetadata: endpoint_1.default.bind(this, modules, set_1.default), - removeUUIDMetadata: endpoint_1.default.bind(this, modules, remove_1.default), - getAllChannelMetadata: endpoint_1.default.bind(this, modules, get_all_2.default), - getChannelMetadata: endpoint_1.default.bind(this, modules, get_2.default), - setChannelMetadata: endpoint_1.default.bind(this, modules, set_2.default), - removeChannelMetadata: endpoint_1.default.bind(this, modules, remove_2.default), - getChannelMembers: endpoint_1.default.bind(this, modules, get_3.default), - setChannelMembers: function (parameters) { - var rest = []; - for (var _i = 1; _i < arguments.length; _i++) { - rest[_i - 1] = arguments[_i]; - } - return endpoint_1.default.call.apply(endpoint_1.default, __spreadArray([_this, - modules, - set_3.default, __assign({ type: 'set' }, parameters)], __read(rest), false)); - }, - removeChannelMembers: function (parameters) { - var rest = []; - for (var _i = 1; _i < arguments.length; _i++) { - rest[_i - 1] = arguments[_i]; - } - return endpoint_1.default.call.apply(endpoint_1.default, __spreadArray([_this, - modules, - set_3.default, __assign({ type: 'delete' }, parameters)], __read(rest), false)); - }, - getMemberships: endpoint_1.default.bind(this, modules, get_4.default), - setMemberships: function (parameters) { - var rest = []; - for (var _i = 1; _i < arguments.length; _i++) { - rest[_i - 1] = arguments[_i]; - } - return endpoint_1.default.call.apply(endpoint_1.default, __spreadArray([_this, - modules, - set_4.default, __assign({ type: 'set' }, parameters)], __read(rest), false)); - }, - removeMemberships: function (parameters) { - var rest = []; - for (var _i = 1; _i < arguments.length; _i++) { - rest[_i - 1] = arguments[_i]; + } + get configuration() { + return this._configuration; + } + get _config() { + return this.configuration; + } + get authKey() { + var _a; + return (_a = this._configuration.authKey) !== null && _a !== void 0 ? _a : undefined; + } + getAuthKey() { + return this.authKey; + } + setAuthKey(authKey) { + this._configuration.setAuthKey(authKey); + } + get userId() { + return this._configuration.userId; + } + set userId(value) { + if (!value || typeof value !== 'string' || value.trim().length === 0) + throw new Error('Missing or invalid userId parameter. Provide a valid string userId'); + this._configuration.userId = value; + } + getUserId() { + return this._configuration.userId; + } + setUserId(value) { + if (!value || typeof value !== 'string' || value.trim().length === 0) + throw new Error('Missing or invalid userId parameter. Provide a valid string userId'); + this._configuration.userId = value; + } + get filterExpression() { + var _a; + return (_a = this._configuration.getFilterExpression()) !== null && _a !== void 0 ? _a : undefined; + } + getFilterExpression() { + return this.filterExpression; + } + set filterExpression(expression) { + this._configuration.setFilterExpression(expression); + } + setFilterExpression(expression) { + this.filterExpression = expression; + } + get cipherKey() { + return this._configuration.getCipherKey(); + } + set cipherKey(key) { + this._configuration.setCipherKey(key); + } + setCipherKey(key) { + this.cipherKey = key; + } + set heartbeatInterval(interval) { + this._configuration.setHeartbeatInterval(interval); + } + setHeartbeatInterval(interval) { + this.heartbeatInterval = interval; + } + getVersion() { + return this._configuration.getVersion(); + } + _addPnsdkSuffix(name, suffix) { + this._configuration._addPnsdkSuffix(name, suffix); + } + getUUID() { + return this.userId; + } + setUUID(value) { + this.userId = value; + } + get customEncrypt() { + return this._configuration.getCustomEncrypt(); + } + get customDecrypt() { + return this._configuration.getCustomDecrypt(); + } + channel(name) { + return new Channel_1.Channel(name, this.eventEmitter, this); + } + channelGroup(name) { + return new ChannelGroup_1.ChannelGroup(name, this.eventEmitter, this); + } + channelMetadata(id) { + return new ChannelMetadata_1.ChannelMetadata(id, this.eventEmitter, this); + } + userMetadata(id) { + return new UserMetadata_1.UserMetadata(id, this.eventEmitter, this); + } + subscriptionSet(parameters) { + return new SubscriptionSet_1.SubscriptionSet(Object.assign(Object.assign({}, parameters), { eventEmitter: this.eventEmitter, pubnub: this })); + } + sendRequest(request, callback) { + return __awaiter(this, void 0, void 0, function* () { + const validationResult = request.validate(); + if (validationResult) { + if (callback) + return callback((0, pubnub_error_1.createValidationError)(validationResult), null); + throw new pubnub_error_1.PubNubError('Validation failed, check status for details', (0, pubnub_error_1.createValidationError)(validationResult)); + } + const transportRequest = request.request(); + if (transportRequest.formData && transportRequest.formData.length > 0) { + transportRequest.timeout = 300; + } + else { + if (request.operation() === operations_1.default.PNSubscribeOperation) + transportRequest.timeout = this._configuration.getSubscribeTimeout(); + else + transportRequest.timeout = this._configuration.getTransactionTimeout(); + } + const status = { + error: false, + operation: request.operation(), + category: categories_1.default.PNAcknowledgmentCategory, + statusCode: 0, + }; + const [sendableRequest, cancellationController] = this.transport.makeSendable(transportRequest); + request.cancellationController = cancellationController ? cancellationController : null; + return sendableRequest + .then((response) => { + status.statusCode = response.status; + if (response.status !== 200 && response.status !== 204) { + const contentType = response.headers['content-type']; + if (contentType || contentType.indexOf('javascript') !== -1 || contentType.indexOf('json') !== -1) { + const json = JSON.parse(PubNubCore.decoder.decode(response.body)); + if (typeof json === 'object' && 'error' in json && json.error && typeof json.error === 'object') + status.errorData = json.error; + } } - return endpoint_1.default.call.apply(endpoint_1.default, __spreadArray([_this, - modules, - set_4.default, __assign({ type: 'delete' }, parameters)], __read(rest), false)); - }, - }; - // User Apis - this.createUser = function (args) { - return _this.objects.setUUIDMetadata({ - uuid: args.userId, - data: args.data, - include: args.include, + return request.parse(response); + }) + .then((parsed) => { + if (callback) + return callback(status, parsed); + return parsed; + }) + .catch((error) => { + const apiError = !(error instanceof pubnub_api_error_1.PubNubAPIError) ? pubnub_api_error_1.PubNubAPIError.create(error) : error; + if (callback) + return callback(apiError.toStatus(request.operation()), null); + throw apiError.toPubNubError(request.operation(), 'REST API request processing error, check status for details'); }); - }; - this.updateUser = this.createUser; - this.removeUser = function (args) { - return _this.objects.removeUUIDMetadata({ - uuid: args === null || args === void 0 ? void 0 : args.userId, + }); + } + destroy(isOffline) { + if (this.subscriptionManager) { + this.subscriptionManager.unsubscribeAll(isOffline); + this.subscriptionManager.disconnect(); + } + else if (this.eventEngine) + this.eventEngine.dispose(); + } + stop() { + this.destroy(); + } + addListener(listener) { + this.listenerManager.addListener(listener); + } + removeListener(listener) { + this.listenerManager.removeListener(listener); + } + removeAllListeners() { + this.listenerManager.removeAllListeners(); + } + publish(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new Publish.PublishRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet, crypto: this._configuration.getCryptoModule() })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + signal(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new Signal.SignalRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + fire(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + callback !== null && callback !== void 0 ? callback : (callback = () => { }); + return this.publish(Object.assign(Object.assign({}, parameters), { replicate: false, storeInHistory: false }), callback); + }); + } + getSubscribedChannels() { + if (this.subscriptionManager) + return this.subscriptionManager.subscribedChannels; + else if (this.eventEngine) + return this.eventEngine.getSubscribedChannels(); + return []; + } + getSubscribedChannelGroups() { + if (this.subscriptionManager) + return this.subscriptionManager.subscribedChannelGroups; + else if (this.eventEngine) + return this.eventEngine.getSubscribedChannelGroups(); + return []; + } + subscribe(parameters) { + if (this.subscriptionManager) + this.subscriptionManager.subscribe(parameters); + else if (this.eventEngine) + this.eventEngine.subscribe(parameters); + } + makeSubscribe(parameters, callback) { + const request = new subscribe_1.SubscribeRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet, crypto: this._configuration.getCryptoModule(), getFileUrl: this.getFileUrl.bind(this) })); + this.sendRequest(request, (status, result) => { + var _a; + if (this.subscriptionManager && ((_a = this.subscriptionManager.abort) === null || _a === void 0 ? void 0 : _a.identifier) === request.requestIdentifier) + this.subscriptionManager.abort = null; + callback(status, result); + }); + if (this.subscriptionManager) { + const callableAbort = () => request.abort(); + callableAbort.identifier = request.requestIdentifier; + this.subscriptionManager.abort = callableAbort; + } + } + unsubscribe(parameters) { + if (this.subscriptionManager) + this.subscriptionManager.unsubscribe(parameters); + else if (this.eventEngine) + this.eventEngine.unsubscribe(parameters); + } + makeUnsubscribe(parameters, callback) { + this.sendRequest(new leave_1.PresenceLeaveRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet })), callback); + } + unsubscribeAll() { + if (this.subscriptionManager) + this.subscriptionManager.unsubscribeAll(); + else if (this.eventEngine) + this.eventEngine.unsubscribeAll(); + } + disconnect() { + if (this.subscriptionManager) + this.subscriptionManager.disconnect(); + else if (this.eventEngine) + this.eventEngine.disconnect(); + } + reconnect(parameters) { + if (this.subscriptionManager) + this.subscriptionManager.reconnect(); + else if (this.eventEngine) + this.eventEngine.reconnect(parameters !== null && parameters !== void 0 ? parameters : {}); + } + subscribeHandshake(parameters) { + return __awaiter(this, void 0, void 0, function* () { + const request = new handshake_1.HandshakeSubscribeRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet, crypto: this._configuration.getCryptoModule(), getFileUrl: this.getFileUrl.bind(this) })); + const abortUnsubscribe = parameters.abortSignal.subscribe((err) => { + request.abort(); }); - }; - this.fetchUser = function (args) { - return _this.objects.getUUIDMetadata({ - uuid: args === null || args === void 0 ? void 0 : args.userId, - include: args === null || args === void 0 ? void 0 : args.include, + const handshakeResponse = this.sendRequest(request); + return handshakeResponse.then((response) => { + abortUnsubscribe(); + return response.cursor; }); - }; - this.fetchUsers = this.objects.getAllUUIDMetadata; - // Space apis - this.createSpace = function (args) { - return _this.objects.setChannelMetadata({ - channel: args.spaceId, - data: args.data, - include: args.include, + }); + } + subscribeReceiveMessages(parameters) { + return __awaiter(this, void 0, void 0, function* () { + const request = new receiveMessages_1.ReceiveMessagesSubscribeRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet, crypto: this._configuration.getCryptoModule(), getFileUrl: this.getFileUrl.bind(this) })); + const abortUnsubscribe = parameters.abortSignal.subscribe((err) => { + request.abort(); }); - }; - this.updateSpace = this.createSpace; - this.removeSpace = function (args) { - return _this.objects.removeChannelMetadata({ - channel: args.spaceId, + const handshakeResponse = this.sendRequest(request); + return handshakeResponse.then((response) => { + abortUnsubscribe(); + return response; }); - }; - this.fetchSpace = function (args) { - return _this.objects.getChannelMetadata({ - channel: args.spaceId, - include: args.include, + }); + } + getMessageActions(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new get_message_actions_1.GetMessageActionsRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + addMessageAction(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new add_message_action_1.AddMessageActionRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + removeMessageAction(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new remove_message_action_1.RemoveMessageAction(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + fetchMessages(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new fetch_messages_1.FetchMessagesRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet, crypto: this._configuration.getCryptoModule(), getFileUrl: this.getFileUrl.bind(this) })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + deleteMessages(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new delete_messages_1.DeleteMessageRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + messageCounts(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new message_counts_1.MessageCountRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + history(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new get_history_1.GetHistoryRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet, crypto: this._configuration.getCryptoModule() })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + hereNow(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new here_now_1.HereNowRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + whereNow(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + var _a; + const request = new where_now_1.WhereNowRequest({ + uuid: (_a = parameters.uuid) !== null && _a !== void 0 ? _a : this._configuration.userId, + keySet: this._configuration.keySet, }); - }; - this.fetchSpaces = this.objects.getAllChannelMetadata; - // Membership apis - this.addMemberships = function (parameters) { + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + getState(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + var _a; + const request = new get_state_1.GetPresenceStateRequest(Object.assign(Object.assign({}, parameters), { uuid: (_a = parameters.uuid) !== null && _a !== void 0 ? _a : this._configuration.userId, keySet: this._configuration.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + setState(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { var _a, _b; - if (typeof parameters.spaceId === 'string') { - return _this.objects.setChannelMembers({ - channel: parameters.spaceId, - uuids: (_a = parameters.users) === null || _a === void 0 ? void 0 : _a.map(function (user) { - if (typeof user === 'string') { - return user; - } - return { - id: user.userId, - custom: user.custom, - status: user.status, - }; - }), - limit: 0, - }); - } - else { - return _this.objects.setMemberships({ - uuid: parameters.userId, - channels: (_b = parameters.spaces) === null || _b === void 0 ? void 0 : _b.map(function (space) { - if (typeof space === 'string') { - return space; - } - return { - id: space.spaceId, - custom: space.custom, - status: space.status, - }; - }), - limit: 0, - }); - } - }; - this.updateMemberships = this.addMemberships; - this.removeMemberships = function (parameters) { - if (typeof parameters.spaceId === 'string') { - return _this.objects.removeChannelMembers({ - channel: parameters.spaceId, - uuids: parameters.userIds, - limit: 0, - }); - } - else { - return _this.objects.removeMemberships({ - uuid: parameters.userId, - channels: parameters.spaceIds, - limit: 0, - }); - } - }; - this.fetchMemberships = function (params) { - if (typeof params.spaceId === 'string') { - return _this.objects - .getChannelMembers({ - channel: params.spaceId, - filter: params.filter, - limit: params.limit, - page: params.page, - include: { - customFields: params.include.customFields, - UUIDFields: params.include.userFields, - customUUIDFields: params.include.customUserFields, - statusField: params.include.statusField, - UUIDStatusField: params.include.userStatusField, - UUIDTypeField: params.include.userTypeField, - totalCount: params.include.totalCount, - }, - sort: params.sort != null - ? Object.fromEntries(Object.entries(params.sort).map(function (_a) { - var _b = __read(_a, 2), k = _b[0], v = _b[1]; - return [k.replace('user', 'uuid'), v]; - })) - : null, - }) - .then(function (res) { - var _a; - res.data = (_a = res.data) === null || _a === void 0 ? void 0 : _a.map(function (m) { - return { - user: m.uuid, - custom: m.custom, - updated: m.updated, - eTag: m.eTag, - }; - }); - return res; - }); - } - else { - return _this.objects - .getMemberships({ - uuid: params.userId, - filter: params.filter, - limit: params.limit, - page: params.page, - include: { - customFields: params.include.customFields, - channelFields: params.include.spaceFields, - customChannelFields: params.include.customSpaceFields, - statusField: params.include.statusField, - channelStatusField: params.include.spaceStatusField, - channelTypeField: params.include.spaceTypeField, - totalCount: params.include.totalCount, - }, - sort: params.sort != null - ? Object.fromEntries(Object.entries(params.sort).map(function (_a) { - var _b = __read(_a, 2), k = _b[0], v = _b[1]; - return [k.replace('space', 'channel'), v]; - })) - : null, - }) - .then(function (res) { - var _a; - res.data = (_a = res.data) === null || _a === void 0 ? void 0 : _a.map(function (m) { - return { - space: m.channel, - custom: m.custom, - updated: m.updated, - eTag: m.eTag, - }; - }); - return res; - }); + const { keySet, userId: userId } = this._configuration; + const heartbeat = this._configuration.getPresenceTimeout(); + let request; + if (this._configuration.enableEventEngine && this.presenceState) { + const presenceState = this.presenceState; + (_a = parameters.channels) === null || _a === void 0 ? void 0 : _a.forEach((channel) => (presenceState[channel] = parameters.state)); + if ('channelGroups' in parameters) { + (_b = parameters.channelGroups) === null || _b === void 0 ? void 0 : _b.forEach((group) => (presenceState[group] = parameters.state)); + } } - }; - this.time = timeEndpoint; - // --- deprecated ------------------ - this.stop = this.destroy; // -------- - // --- deprecated ------------------ - // mount crypto - this.encrypt = function (data, key) { - if (typeof key === 'undefined' && modules.cryptoModule) { - var encrypted = modules.cryptoModule.encrypt(data); - return typeof encrypted === 'string' ? encrypted : (0, base64_codec_1.encode)(encrypted); + if ('withHeartbeat' in parameters) { + request = new heartbeat_1.HeartbeatRequest(Object.assign(Object.assign({}, parameters), { keySet, heartbeat })); } else { - return crypto.encrypt(data, key); - } - }; - this.decrypt = function (data, key) { - if (typeof key === 'undefined' && cryptoModule) { - var decrypted = modules.cryptoModule.decrypt(data); - return decrypted instanceof ArrayBuffer ? JSON.parse(new TextDecoder().decode(decrypted)) : decrypted; + request = new set_state_1.SetPresenceStateRequest(Object.assign(Object.assign({}, parameters), { keySet, uuid: userId })); } - else { - return crypto.decrypt(data, key); + if (this.subscriptionManager) + this.subscriptionManager.setState(parameters); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + presence(parameters) { + var _a; + (_a = this.subscriptionManager) === null || _a === void 0 ? void 0 : _a.changePresence(parameters); + } + heartbeat(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new heartbeat_1.HeartbeatRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + join(parameters) { + var _a; + (_a = this.presenceEventEngine) === null || _a === void 0 ? void 0 : _a.join(parameters); + } + leave(parameters) { + var _a; + (_a = this.presenceEventEngine) === null || _a === void 0 ? void 0 : _a.leave(parameters); + } + leaveAll() { + var _a; + (_a = this.presenceEventEngine) === null || _a === void 0 ? void 0 : _a.leaveAll(); + } + grantToken(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new grant_token_1.GrantTokenRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + revokeToken(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new revoke_token_1.RevokeTokenRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + get token() { + return this.tokenManager.getToken(); + } + getToken() { + return this.token; + } + set token(token) { + this.tokenManager.setToken(token); + } + setToken(token) { + this.token = token; + } + parseToken(token) { + return this.tokenManager.parseToken(token); + } + grant(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new grant_1.GrantRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + audit(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new audit_1.AuditRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + get objects() { + return this._objects; + } + fetchUsers(parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this.objects._getAllUUIDMetadata(parametersOrCallback, callback); + }); + } + fetchUser(parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this.objects._getUUIDMetadata(parametersOrCallback, callback); + }); + } + createUser(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this.objects._setUUIDMetadata(parameters, callback); + }); + } + updateUser(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this.objects._setUUIDMetadata(parameters, callback); + }); + } + removeUser(parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this.objects._removeUUIDMetadata(parametersOrCallback, callback); + }); + } + fetchSpaces(parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this.objects._getAllChannelMetadata(parametersOrCallback, callback); + }); + } + fetchSpace(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this.objects._getChannelMetadata(parameters, callback); + }); + } + createSpace(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this.objects._setChannelMetadata(parameters, callback); + }); + } + updateSpace(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this.objects._setChannelMetadata(parameters, callback); + }); + } + removeSpace(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this.objects._removeChannelMetadata(parameters, callback); + }); + } + fetchMemberships(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this.objects.fetchMemberships(parameters, callback); + }); + } + addMemberships(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this.objects.addMemberships(parameters, callback); + }); + } + updateMemberships(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this.objects.addMemberships(parameters, callback); + }); + } + removeMemberships(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + var _a, _b, _c; + if ('spaceId' in parameters) { + const spaceParameters = parameters; + const requestParameters = { + channel: (_a = spaceParameters.spaceId) !== null && _a !== void 0 ? _a : spaceParameters.channel, + uuids: (_b = spaceParameters.userIds) !== null && _b !== void 0 ? _b : spaceParameters.uuids, + limit: 0, + }; + if (callback) + return this.objects.removeChannelMembers(requestParameters, callback); + return this.objects.removeChannelMembers(requestParameters); } - }; - /* config */ - this.getAuthKey = modules.config.getAuthKey.bind(modules.config); - this.setAuthKey = modules.config.setAuthKey.bind(modules.config); - this.getUUID = modules.config.getUUID.bind(modules.config); - this.setUUID = modules.config.setUUID.bind(modules.config); - this.getUserId = modules.config.getUserId.bind(modules.config); - this.setUserId = modules.config.setUserId.bind(modules.config); - this.getFilterExpression = modules.config.getFilterExpression.bind(modules.config); - this.setFilterExpression = modules.config.setFilterExpression.bind(modules.config); - this.setCipherKey = function (key) { return modules.config.setCipherKey(key, setup, modules); }; - this.setHeartbeatInterval = modules.config.setHeartbeatInterval.bind(modules.config); - if (networking.hasModule('proxy')) { - this.setProxy = function (proxy) { - modules.config.setProxy(proxy); - _this.reconnect(); + const userParameters = parameters; + const requestParameters = { + uuid: userParameters.userId, + channels: (_c = userParameters.spaceIds) !== null && _c !== void 0 ? _c : userParameters.channels, + limit: 0, }; - } + if (callback) + return this.objects.removeMemberships(requestParameters, callback); + return this.objects.removeMemberships(requestParameters); + }); + } + get channelGroups() { + return this._channelGroups; } - default_1.prototype.getVersion = function () { - return this._config.getVersion(); - }; - default_1.prototype._addPnsdkSuffix = function (name, suffix) { - this._config._addPnsdkSuffix(name, suffix); - }; - // network hooks to indicate network changes - default_1.prototype.networkDownDetected = function () { - this._listenerManager.announceNetworkDown(); - if (this._config.restore) { - this.disconnect(); + get push() { + return this._push; + } + sendFile(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + if (!this._configuration.PubNubFile) + throw new Error("Validation failed: 'PubNubFile' not configured or file upload not supported by the platform."); + const sendFileRequest = new send_file_1.SendFileRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet, PubNubFile: this._configuration.PubNubFile, fileUploadPublishRetryLimit: this._configuration.fileUploadPublishRetryLimit, file: parameters.file, sendRequest: this.sendRequest.bind(this), publishFile: this.publishFile.bind(this), crypto: this._configuration.getCryptoModule(), cryptography: this.cryptography ? this.cryptography : undefined })); + const status = { + error: false, + operation: operations_1.default.PNPublishFileOperation, + category: categories_1.default.PNAcknowledgmentCategory, + statusCode: 0, + }; + return sendFileRequest + .process() + .then((response) => { + status.statusCode = response.status; + if (callback) + return callback(status, response); + return response; + }) + .catch((error) => { + let errorStatus; + if (error instanceof pubnub_error_1.PubNubError) + errorStatus = error.status; + else if (error instanceof pubnub_api_error_1.PubNubAPIError) + errorStatus = error.toStatus(status.operation); + if (callback && errorStatus) + callback(errorStatus, null); + throw new pubnub_error_1.PubNubError('REST API request processing error, check status for details', errorStatus); + }); + }); + } + publishFile(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + if (!this._configuration.PubNubFile) + throw new Error("Validation failed: 'PubNubFile' not configured or file upload not supported by the platform."); + const request = new publish_file_1.PublishFileMessageRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet, crypto: this._configuration.getCryptoModule() })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + listFiles(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new list_files_1.FilesListRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + getFileUrl(parameters) { + var _a; + const request = this.transport.request(new get_file_url_1.GetFileDownloadUrlRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet })).request()); + const query = (_a = request.queryParameters) !== null && _a !== void 0 ? _a : {}; + const queryString = Object.keys(query) + .map((key) => { + const queryValue = query[key]; + if (!Array.isArray(queryValue)) + return `${key}=${(0, utils_1.encodeString)(queryValue)}`; + return queryValue.map((value) => `${key}=${(0, utils_1.encodeString)(value)}`).join('&'); + }) + .join('&'); + return `${request.origin}${request.path}?${queryString}`; + } + downloadFile(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + if (!this._configuration.PubNubFile) + throw new Error("Validation failed: 'PubNubFile' not configured or file upload not supported by the platform."); + const request = new download_file_1.DownloadFileRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet, PubNubFile: this._configuration.PubNubFile, cryptography: this.cryptography ? this.cryptography : undefined, crypto: this._configuration.getCryptoModule() })); + if (callback) + return this.sendRequest(request, callback); + return (yield this.sendRequest(request)); + }); + } + deleteFile(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new delete_file_1.DeleteFileRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + time(callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new Time.TimeRequest(); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + encrypt(data, customCipherKey) { + const cryptoModule = this._configuration.getCryptoModule(); + if (!customCipherKey && cryptoModule && typeof data === 'string') { + const encrypted = cryptoModule.encrypt(data); + return typeof encrypted === 'string' ? encrypted : (0, base64_codec_1.encode)(encrypted); } - else { - this.destroy(true); + if (!this.crypto) + throw new Error('Encryption error: cypher key not set'); + return this.crypto.encrypt(data, customCipherKey); + } + decrypt(data, customCipherKey) { + const cryptoModule = this._configuration.getCryptoModule(); + if (!customCipherKey && cryptoModule) { + const decrypted = cryptoModule.decrypt(data); + return decrypted instanceof ArrayBuffer ? JSON.parse(new TextDecoder().decode(decrypted)) : decrypted; } - }; - default_1.prototype.networkUpDetected = function () { - this._listenerManager.announceNetworkUp(); - this.reconnect(); - }; - default_1.notificationPayload = function (title, body) { - return new push_payload_1.default(title, body); - }; - default_1.generateUUID = function () { - return uuid_1.default.createUUID(); - }; - default_1.OPERATIONS = operations_1.default; - default_1.CATEGORIES = categories_1.default; - default_1.LinearRetryPolicy = retryPolicy_1.RetryPolicy.LinearRetryPolicy; - default_1.ExponentialRetryPolicy = retryPolicy_1.RetryPolicy.ExponentialRetryPolicy; - return default_1; -}()); -exports.default = default_1; + if (!this.crypto) + throw new Error('Decryption error: cypher key not set'); + return this.crypto.decrypt(data, customCipherKey); + } + encryptFile(keyOrFile, file) { + return __awaiter(this, void 0, void 0, function* () { + var _a; + if (typeof keyOrFile !== 'string') + file = keyOrFile; + if (!file) + throw new Error('File encryption error. Source file is missing.'); + if (!this._configuration.PubNubFile) + throw new Error('File encryption error. File constructor not configured.'); + if (typeof keyOrFile !== 'string' && !this._configuration.getCryptoModule()) + throw new Error('File encryption error. Crypto module not configured.'); + if (typeof keyOrFile === 'string') { + if (!this.cryptography) + throw new Error('File encryption error. File encryption not available'); + return this.cryptography.encryptFile(keyOrFile, file, this._configuration.PubNubFile); + } + return (_a = this._configuration.getCryptoModule()) === null || _a === void 0 ? void 0 : _a.encryptFile(file, this._configuration.PubNubFile); + }); + } + decryptFile(keyOrFile, file) { + return __awaiter(this, void 0, void 0, function* () { + var _a; + if (typeof keyOrFile !== 'string') + file = keyOrFile; + if (!file) + throw new Error('File encryption error. Source file is missing.'); + if (!this._configuration.PubNubFile) + throw new Error('File decryption error. File constructor' + ' not configured.'); + if (typeof keyOrFile === 'string' && !this._configuration.getCryptoModule()) + throw new Error('File decryption error. Crypto module not configured.'); + if (typeof keyOrFile === 'string') { + if (!this.cryptography) + throw new Error('File decryption error. File decryption not available'); + return this.cryptography.decryptFile(keyOrFile, file, this._configuration.PubNubFile); + } + return (_a = this._configuration.getCryptoModule()) === null || _a === void 0 ? void 0 : _a.decryptFile(file, this._configuration.PubNubFile); + }); + } +} +exports.PubNubCore = PubNubCore; +PubNubCore.decoder = new TextDecoder(); +PubNubCore.OPERATIONS = operations_1.default; +PubNubCore.CATEGORIES = categories_1.default; +PubNubCore.ExponentialRetryPolicy = retryPolicy_1.RetryPolicy.ExponentialRetryPolicy; +PubNubCore.LinearRetryPolicy = retryPolicy_1.RetryPolicy.LinearRetryPolicy; diff --git a/lib/core/pubnub-objects.js b/lib/core/pubnub-objects.js new file mode 100644 index 000000000..79b1e885b --- /dev/null +++ b/lib/core/pubnub-objects.js @@ -0,0 +1,317 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const get_all_1 = require("./endpoints/objects/channel/get_all"); +const remove_1 = require("./endpoints/objects/channel/remove"); +const get_1 = require("./endpoints/objects/membership/get"); +const set_1 = require("./endpoints/objects/membership/set"); +const get_all_2 = require("./endpoints/objects/uuid/get_all"); +const get_2 = require("./endpoints/objects/channel/get"); +const set_2 = require("./endpoints/objects/channel/set"); +const remove_2 = require("./endpoints/objects/uuid/remove"); +const get_3 = require("./endpoints/objects/member/get"); +const set_3 = require("./endpoints/objects/member/set"); +const get_4 = require("./endpoints/objects/uuid/get"); +const set_4 = require("./endpoints/objects/uuid/set"); +class PubNubObjects { + constructor(configuration, sendRequest) { + this.configuration = configuration; + this.sendRequest = sendRequest; + this.keySet = configuration.keySet; + } + getAllUUIDMetadata(parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this._getAllUUIDMetadata(parametersOrCallback, callback); + }); + } + _getAllUUIDMetadata(parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function* () { + const parameters = parametersOrCallback && typeof parametersOrCallback !== 'function' ? parametersOrCallback : {}; + callback !== null && callback !== void 0 ? callback : (callback = typeof parametersOrCallback === 'function' ? parametersOrCallback : undefined); + const request = new get_all_2.GetAllUUIDMetadataRequest(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + getUUIDMetadata(parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this._getUUIDMetadata(parametersOrCallback, callback); + }); + } + _getUUIDMetadata(parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function* () { + var _a; + const parameters = parametersOrCallback && typeof parametersOrCallback !== 'function' ? parametersOrCallback : {}; + callback !== null && callback !== void 0 ? callback : (callback = typeof parametersOrCallback === 'function' ? parametersOrCallback : undefined); + if (parameters.userId) + parameters.uuid = parameters.userId; + (_a = parameters.uuid) !== null && _a !== void 0 ? _a : (parameters.uuid = this.configuration.userId); + const request = new get_4.GetUUIDMetadataRequest(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + setUUIDMetadata(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this._setUUIDMetadata(parameters, callback); + }); + } + _setUUIDMetadata(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + var _a; + if (parameters.userId) + parameters.uuid = parameters.userId; + (_a = parameters.uuid) !== null && _a !== void 0 ? _a : (parameters.uuid = this.configuration.userId); + const request = new set_4.SetUUIDMetadataRequest(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + removeUUIDMetadata(parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this._removeUUIDMetadata(parametersOrCallback, callback); + }); + } + _removeUUIDMetadata(parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function* () { + var _a; + const parameters = parametersOrCallback && typeof parametersOrCallback !== 'function' ? parametersOrCallback : {}; + callback !== null && callback !== void 0 ? callback : (callback = typeof parametersOrCallback === 'function' ? parametersOrCallback : undefined); + if (parameters.userId) + parameters.uuid = parameters.userId; + (_a = parameters.uuid) !== null && _a !== void 0 ? _a : (parameters.uuid = this.configuration.userId); + const request = new remove_2.RemoveUUIDMetadataRequest(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + getAllChannelMetadata(parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this._getAllChannelMetadata(parametersOrCallback, callback); + }); + } + _getAllChannelMetadata(parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function* () { + const parameters = parametersOrCallback && typeof parametersOrCallback !== 'function' ? parametersOrCallback : {}; + callback !== null && callback !== void 0 ? callback : (callback = typeof parametersOrCallback === 'function' ? parametersOrCallback : undefined); + const request = new get_all_1.GetAllChannelsMetadataRequest(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + getChannelMetadata(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this._getChannelMetadata(parameters, callback); + }); + } + _getChannelMetadata(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new get_2.GetChannelMetadataRequest(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + setChannelMetadata(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this._setChannelMetadata(parameters, callback); + }); + } + _setChannelMetadata(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new set_2.SetChannelMetadataRequest(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + removeChannelMetadata(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + return this._removeChannelMetadata(parameters, callback); + }); + } + _removeChannelMetadata(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new remove_1.RemoveChannelMetadataRequest(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + getChannelMembers(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new get_3.GetChannelMembersRequest(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + setChannelMembers(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new set_3.SetChannelMembersRequest(Object.assign(Object.assign({}, parameters), { type: 'set', keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + removeChannelMembers(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new set_3.SetChannelMembersRequest(Object.assign(Object.assign({}, parameters), { type: 'delete', keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + getMemberships(parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function* () { + var _a; + const parameters = parametersOrCallback && typeof parametersOrCallback !== 'function' ? parametersOrCallback : {}; + callback !== null && callback !== void 0 ? callback : (callback = typeof parametersOrCallback === 'function' ? parametersOrCallback : undefined); + if (parameters.userId) + parameters.uuid = parameters.userId; + (_a = parameters.uuid) !== null && _a !== void 0 ? _a : (parameters.uuid = this.configuration.userId); + const request = new get_1.GetUUIDMembershipsRequest(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + setMemberships(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + var _a; + if (parameters.userId) + parameters.uuid = parameters.userId; + (_a = parameters.uuid) !== null && _a !== void 0 ? _a : (parameters.uuid = this.configuration.userId); + const request = new set_1.SetUUIDMembershipsRequest(Object.assign(Object.assign({}, parameters), { type: 'set', keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + removeMemberships(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + var _a; + if (parameters.userId) + parameters.uuid = parameters.userId; + (_a = parameters.uuid) !== null && _a !== void 0 ? _a : (parameters.uuid = this.configuration.userId); + const request = new set_1.SetUUIDMembershipsRequest(Object.assign(Object.assign({}, parameters), { type: 'delete', keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + fetchMemberships(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + var _a, _b; + if ('spaceId' in parameters) { + const spaceParameters = parameters; + const mappedParameters = { + channel: (_a = spaceParameters.spaceId) !== null && _a !== void 0 ? _a : spaceParameters.channel, + filter: spaceParameters.filter, + limit: spaceParameters.limit, + page: spaceParameters.page, + include: Object.assign({}, spaceParameters.include), + sort: spaceParameters.sort + ? Object.fromEntries(Object.entries(spaceParameters.sort).map(([key, value]) => [key.replace('user', 'uuid'), value])) + : undefined, + }; + const mapMembers = (response) => ({ + status: response.status, + data: response.data.map((members) => ({ + user: members.uuid, + custom: members.custom, + updated: members.updated, + eTag: members.eTag, + })), + totalCount: response.totalCount, + next: response.next, + prev: response.prev, + }); + if (callback) + return this.getChannelMembers(mappedParameters, (status, result) => { + callback(status, result ? mapMembers(result) : result); + }); + return this.getChannelMembers(mappedParameters).then(mapMembers); + } + const userParameters = parameters; + const mappedParameters = { + uuid: (_b = userParameters.userId) !== null && _b !== void 0 ? _b : userParameters.uuid, + filter: userParameters.filter, + limit: userParameters.limit, + page: userParameters.page, + include: Object.assign({}, userParameters.include), + sort: userParameters.sort + ? Object.fromEntries(Object.entries(userParameters.sort).map(([key, value]) => [key.replace('space', 'channel'), value])) + : undefined, + }; + const mapMemberships = (response) => ({ + status: response.status, + data: response.data.map((membership) => ({ + space: membership.channel, + custom: membership.custom, + updated: membership.updated, + eTag: membership.eTag, + })), + totalCount: response.totalCount, + next: response.next, + prev: response.prev, + }); + if (callback) + return this.getMemberships(mappedParameters, (status, result) => { + callback(status, result ? mapMemberships(result) : result); + }); + return this.getMemberships(mappedParameters).then(mapMemberships); + }); + } + addMemberships(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + var _a, _b, _c, _d, _e, _f; + if ('spaceId' in parameters) { + const spaceParameters = parameters; + const mappedParameters = { + channel: (_a = spaceParameters.spaceId) !== null && _a !== void 0 ? _a : spaceParameters.channel, + uuids: (_c = (_b = spaceParameters.users) === null || _b === void 0 ? void 0 : _b.map((user) => { + if (typeof user === 'string') + return user; + user.userId; + return { id: user.userId, custom: user.custom }; + })) !== null && _c !== void 0 ? _c : spaceParameters.uuids, + limit: 0, + }; + if (callback) + return this.setChannelMembers(mappedParameters, callback); + return this.setChannelMembers(mappedParameters); + } + const userParameters = parameters; + const mappedParameters = { + uuid: (_d = userParameters.userId) !== null && _d !== void 0 ? _d : userParameters.uuid, + channels: (_f = (_e = userParameters.spaces) === null || _e === void 0 ? void 0 : _e.map((space) => { + if (typeof space === 'string') + return space; + return { + id: space.spaceId, + custom: space.custom, + }; + })) !== null && _f !== void 0 ? _f : userParameters.channels, + limit: 0, + }; + if (callback) + return this.setMemberships(mappedParameters, callback); + return this.setMemberships(mappedParameters); + }); + } +} +exports.default = PubNubObjects; diff --git a/lib/core/pubnub-push.js b/lib/core/pubnub-push.js new file mode 100644 index 000000000..94f135a9c --- /dev/null +++ b/lib/core/pubnub-push.js @@ -0,0 +1,54 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const remove_push_channels_1 = require("./endpoints/push/remove_push_channels"); +const list_push_channels_1 = require("./endpoints/push/list_push_channels"); +const add_push_channels_1 = require("./endpoints/push/add_push_channels"); +const remove_device_1 = require("./endpoints/push/remove_device"); +class PubNubPushNotifications { + constructor(keySet, sendRequest) { + this.keySet = keySet; + this.sendRequest = sendRequest; + } + listChannels(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new list_push_channels_1.ListDevicePushNotificationChannelsRequest(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + addChannels(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new add_push_channels_1.AddDevicePushNotificationChannelsRequest(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + removeChannels(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new remove_push_channels_1.RemoveDevicePushNotificationChannelsRequest(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } + deleteDevice(parameters, callback) { + return __awaiter(this, void 0, void 0, function* () { + const request = new remove_device_1.RemoveDevicePushNotificationRequest(Object.assign(Object.assign({}, parameters), { keySet: this.keySet })); + if (callback) + return this.sendRequest(request, callback); + return this.sendRequest(request); + }); + } +} +exports.default = PubNubPushNotifications; diff --git a/lib/entities/common.js b/lib/core/types/api/access-panager.js similarity index 100% rename from lib/entities/common.js rename to lib/core/types/api/access-panager.js diff --git a/lib/core/types/api/app-context.js b/lib/core/types/api/app-context.js new file mode 100644 index 000000000..c8ad2e549 --- /dev/null +++ b/lib/core/types/api/app-context.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/lib/core/types/api/channel-groups.js b/lib/core/types/api/channel-groups.js new file mode 100644 index 000000000..c8ad2e549 --- /dev/null +++ b/lib/core/types/api/channel-groups.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/lib/core/types/api/file-sharing.js b/lib/core/types/api/file-sharing.js new file mode 100644 index 000000000..c8ad2e549 --- /dev/null +++ b/lib/core/types/api/file-sharing.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/lib/core/types/api/history.js b/lib/core/types/api/history.js new file mode 100644 index 000000000..82e074734 --- /dev/null +++ b/lib/core/types/api/history.js @@ -0,0 +1,8 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.PubNubMessageType = void 0; +var PubNubMessageType; +(function (PubNubMessageType) { + PubNubMessageType[PubNubMessageType["Message"] = -1] = "Message"; + PubNubMessageType[PubNubMessageType["Files"] = 4] = "Files"; +})(PubNubMessageType || (exports.PubNubMessageType = PubNubMessageType = {})); diff --git a/lib/core/types/api/index.js b/lib/core/types/api/index.js new file mode 100644 index 000000000..c8ad2e549 --- /dev/null +++ b/lib/core/types/api/index.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/lib/core/types/api/message-action.js b/lib/core/types/api/message-action.js new file mode 100644 index 000000000..c8ad2e549 --- /dev/null +++ b/lib/core/types/api/message-action.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/lib/core/types/api/presence.js b/lib/core/types/api/presence.js new file mode 100644 index 000000000..c8ad2e549 --- /dev/null +++ b/lib/core/types/api/presence.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/lib/core/types/api/push-notifications.js b/lib/core/types/api/push-notifications.js new file mode 100644 index 000000000..c8ad2e549 --- /dev/null +++ b/lib/core/types/api/push-notifications.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/lib/core/types/api/push.js b/lib/core/types/api/push.js new file mode 100644 index 000000000..c8ad2e549 --- /dev/null +++ b/lib/core/types/api/push.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/lib/core/types/api/subscription.js b/lib/core/types/api/subscription.js new file mode 100644 index 000000000..c8ad2e549 --- /dev/null +++ b/lib/core/types/api/subscription.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/lib/core/types/file.js b/lib/core/types/file.js new file mode 100644 index 000000000..c8ad2e549 --- /dev/null +++ b/lib/core/types/file.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/lib/core/types/transport-request.js b/lib/core/types/transport-request.js new file mode 100644 index 000000000..d24afce7b --- /dev/null +++ b/lib/core/types/transport-request.js @@ -0,0 +1,11 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.TransportMethod = void 0; +var TransportMethod; +(function (TransportMethod) { + TransportMethod["GET"] = "GET"; + TransportMethod["POST"] = "POST"; + TransportMethod["PATCH"] = "PATCH"; + TransportMethod["DELETE"] = "DELETE"; + TransportMethod["LOCAL"] = "LOCAL"; +})(TransportMethod || (exports.TransportMethod = TransportMethod = {})); diff --git a/lib/core/types/transport-response.js b/lib/core/types/transport-response.js new file mode 100644 index 000000000..c8ad2e549 --- /dev/null +++ b/lib/core/types/transport-response.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/lib/core/utils.js b/lib/core/utils.js index 51f97541f..2bd14eee4 100644 --- a/lib/core/utils.js +++ b/lib/core/utils.js @@ -1,85 +1,38 @@ "use strict"; -var __read = (this && this.__read) || function (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; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.queryStringFromObject = exports.findUniqueCommonElements = exports.removeSingleOccurance = exports.encodeNames = exports.encodeString = void 0; +const encodeString = (input) => { + return encodeURIComponent(input).replace(/[!~*'()]/g, (x) => `%${x.charCodeAt(0).toString(16).toUpperCase()}`); }; -var __spreadArray = (this && this.__spreadArray) || function (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)); +exports.encodeString = encodeString; +const encodeNames = (names, defaultString) => { + const encodedNames = names.map((name) => (0, exports.encodeString)(name)); + return encodedNames.length ? encodedNames.join(',') : defaultString !== null && defaultString !== void 0 ? defaultString : ''; }; -function objectToList(o) { - var l = []; - Object.keys(o).forEach(function (key) { return l.push(key); }); - return l; -} -function encodeString(input) { - return encodeURIComponent(input).replace(/[!~*'()]/g, function (x) { return "%".concat(x.charCodeAt(0).toString(16).toUpperCase()); }); -} -function objectToListSorted(o) { - return objectToList(o).sort(); -} -function signPamFromParams(params) { - var l = objectToListSorted(params); - return l.map(function (paramKey) { return "".concat(paramKey, "=").concat(encodeString(params[paramKey])); }).join('&'); -} -function endsWith(searchString, suffix) { - return searchString.indexOf(suffix, this.length - suffix.length) !== -1; -} -function createPromise() { - var successResolve; - var failureResolve; - var promise = new Promise(function (fulfill, reject) { - successResolve = fulfill; - failureResolve = reject; - }); - return { promise: promise, reject: failureResolve, fulfill: successResolve }; -} -function stringToArrayBuffer(str) { - var buf = new ArrayBuffer(str.length * 2); - var bufView = new Uint16Array(buf); - for (var i = 0, strLen = str.length; i < strLen; i++) { - bufView[i] = str.charCodeAt(i); - } - return buf; -} -function removeSingleOccurance(source, elementsToRemove) { - var removed = Object.fromEntries(elementsToRemove.map(function (prop) { return [prop, false]; })); - return source.filter(function (e) { +exports.encodeNames = encodeNames; +const removeSingleOccurance = (source, elementsToRemove) => { + const removed = Object.fromEntries(elementsToRemove.map((prop) => [prop, false])); + return source.filter((e) => { if (elementsToRemove.includes(e) && !removed[e]) { removed[e] = true; return false; } return true; }); -} -function findUniqueCommonElements(a, b) { - return __spreadArray([], __read(a), false).filter(function (value) { - return b.includes(value) && a.indexOf(value) === a.lastIndexOf(value) && b.indexOf(value) === b.lastIndexOf(value); - }); -} -module.exports = { - signPamFromParams: signPamFromParams, - endsWith: endsWith, - createPromise: createPromise, - encodeString: encodeString, - stringToArrayBuffer: stringToArrayBuffer, - removeSingleOccurance: removeSingleOccurance, - findUniqueCommonElements: findUniqueCommonElements, }; +exports.removeSingleOccurance = removeSingleOccurance; +const findUniqueCommonElements = (a, b) => { + return [...a].filter((value) => b.includes(value) && a.indexOf(value) === a.lastIndexOf(value) && b.indexOf(value) === b.lastIndexOf(value)); +}; +exports.findUniqueCommonElements = findUniqueCommonElements; +const queryStringFromObject = (query) => { + return Object.keys(query) + .map((key) => { + const queryValue = query[key]; + if (!Array.isArray(queryValue)) + return `${key}=${(0, exports.encodeString)(queryValue)}`; + return queryValue.map((value) => `${key}=${(0, exports.encodeString)(value)}`).join('&'); + }) + .join('&'); +}; +exports.queryStringFromObject = queryStringFromObject; diff --git a/lib/crypto/index.js b/lib/crypto/index.js index 1e44d895d..3918c74e4 100644 --- a/lib/crypto/index.js +++ b/lib/crypto/index.js @@ -1,2 +1 @@ "use strict"; -/** */ diff --git a/lib/crypto/modules/NodeCryptoModule/aesCbcCryptor.js b/lib/crypto/modules/NodeCryptoModule/aesCbcCryptor.js index 613e8cfec..c03ba9b34 100644 --- a/lib/crypto/modules/NodeCryptoModule/aesCbcCryptor.js +++ b/lib/crypto/modules/NodeCryptoModule/aesCbcCryptor.js @@ -8,139 +8,97 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "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 (_) 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 }; - } -}; Object.defineProperty(exports, "__esModule", { value: true }); -var stream_1 = require("stream"); -var crypto_1 = require("crypto"); -var AesCbcCryptor = /** @class */ (function () { - function AesCbcCryptor(configuration) { - this.cipherKey = configuration.cipherKey; +const crypto_1 = require("crypto"); +const stream_1 = require("stream"); +class AesCbcCryptor { + constructor({ cipherKey }) { + this.cipherKey = cipherKey; } - Object.defineProperty(AesCbcCryptor.prototype, "algo", { - get: function () { - return 'aes-256-cbc'; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(AesCbcCryptor.prototype, "identifier", { - get: function () { - return 'ACRH'; - }, - enumerable: false, - configurable: true - }); - AesCbcCryptor.prototype.getIv = function () { - return (0, crypto_1.randomBytes)(AesCbcCryptor.BLOCK_SIZE); - }; - AesCbcCryptor.prototype.getKey = function () { - var sha = (0, crypto_1.createHash)('sha256'); - sha.update(Buffer.from(this.cipherKey, 'utf8')); - return Buffer.from(sha.digest()); - }; - AesCbcCryptor.prototype.encrypt = function (data) { - var iv = this.getIv(); - var key = this.getKey(); - var plainData = typeof data === 'string' ? new TextEncoder().encode(data) : data; - var bPlain = Buffer.from(plainData); + encrypt(data) { + const iv = this.getIv(); + const key = this.getKey(); + const plainData = typeof data === 'string' ? AesCbcCryptor.encoder.encode(data) : data; + const bPlain = Buffer.from(plainData); if (bPlain.byteLength === 0) - throw new Error('encryption error. empty content'); - var aes = (0, crypto_1.createCipheriv)(this.algo, key, iv); + throw new Error('Encryption error: empty content'); + const aes = (0, crypto_1.createCipheriv)(this.algo, key, iv); return { metadata: iv, data: Buffer.concat([aes.update(bPlain), aes.final()]), }; - }; - AesCbcCryptor.prototype.decrypt = function (encryptedData) { - var data = typeof encryptedData.data === 'string' ? new TextEncoder().encode(encryptedData.data) : encryptedData.data; - if (data.byteLength <= 0) - throw new Error('decryption error: empty content'); - var aes = (0, crypto_1.createDecipheriv)(this.algo, this.getKey(), encryptedData.metadata); - return Uint8Array.from(Buffer.concat([aes.update(data), aes.final()])).buffer; - }; - AesCbcCryptor.prototype.encryptStream = function (stream) { - return __awaiter(this, void 0, void 0, function () { - var output, bIv, aes; - return __generator(this, function (_a) { - output = new stream_1.PassThrough(); - bIv = this.getIv(); - if (stream.readable === false) - throw new Error('encryption error. empty stream'); - aes = (0, crypto_1.createCipheriv)(this.algo, this.getKey(), bIv); - stream.pipe(aes).pipe(output); - return [2 /*return*/, { - stream: output, - metadata: bIv, - metadataLength: AesCbcCryptor.BLOCK_SIZE, - }]; - }); + } + encryptStream(stream) { + return __awaiter(this, void 0, void 0, function* () { + if (!stream.readable) + throw new Error('Encryption error: empty stream'); + const output = new stream_1.PassThrough(); + const bIv = this.getIv(); + const aes = (0, crypto_1.createCipheriv)(this.algo, this.getKey(), bIv); + stream.pipe(aes).pipe(output); + return { + stream: output, + metadata: bIv, + metadataLength: AesCbcCryptor.BLOCK_SIZE, + }; }); - }; - AesCbcCryptor.prototype.decryptStream = function (encryptedStream) { - return __awaiter(this, void 0, void 0, function () { - var decryptedStream, bIv, aes, onReadable; - var _this = this; - return __generator(this, function (_a) { - decryptedStream = new stream_1.PassThrough(); - bIv = Buffer.alloc(0); - aes = null; - onReadable = function () { - var data = encryptedStream.stream.read(); - while (data !== null) { - if (data) { - var bChunk = Buffer.from(data); - var sliceLen = encryptedStream.metadataLength - bIv.byteLength; - if (bChunk.byteLength < sliceLen) { - bIv = Buffer.concat([bIv, bChunk]); - } - else { - bIv = Buffer.concat([bIv, bChunk.slice(0, sliceLen)]); - aes = (0, crypto_1.createDecipheriv)(_this.algo, _this.getKey(), bIv); - aes.pipe(decryptedStream); - aes.write(bChunk.slice(sliceLen)); - } + } + decrypt(input) { + const data = typeof input.data === 'string' ? new TextEncoder().encode(input.data) : input.data; + if (data.byteLength <= 0) + throw new Error('Decryption error: empty content'); + const aes = (0, crypto_1.createDecipheriv)(this.algo, this.getKey(), input.metadata); + const decryptedDataBuffer = Buffer.concat([aes.update(data), aes.final()]); + return decryptedDataBuffer.buffer.slice(decryptedDataBuffer.byteOffset, decryptedDataBuffer.byteOffset + decryptedDataBuffer.length); + } + decryptStream(stream) { + return __awaiter(this, void 0, void 0, function* () { + const decryptedStream = new stream_1.PassThrough(); + let bIv = Buffer.alloc(0); + let aes = null; + const onReadable = () => { + let data = stream.stream.read(); + while (data !== null) { + if (data) { + const bChunk = Buffer.from(data); + const sliceLen = stream.metadataLength - bIv.byteLength; + if (bChunk.byteLength < sliceLen) { + bIv = Buffer.concat([bIv, bChunk]); + } + else { + bIv = Buffer.concat([bIv, bChunk.slice(0, sliceLen)]); + aes = (0, crypto_1.createDecipheriv)(this.algo, this.getKey(), bIv); + aes.pipe(decryptedStream); + aes.write(bChunk.slice(sliceLen)); } - data = encryptedStream.stream.read(); - } - }; - encryptedStream.stream.on('readable', onReadable); - encryptedStream.stream.on('end', function () { - if (aes) { - aes.end(); } - decryptedStream.end(); - }); - return [2 /*return*/, decryptedStream]; + data = stream.stream.read(); + } + }; + stream.stream.on('readable', onReadable); + stream.stream.on('end', () => { + if (aes) + aes.end(); + decryptedStream.end(); }); + return decryptedStream; }); - }; - AesCbcCryptor.BLOCK_SIZE = 16; - return AesCbcCryptor; -}()); + } + get identifier() { + return 'ACRH'; + } + get algo() { + return 'aes-256-cbc'; + } + getIv() { + return (0, crypto_1.randomBytes)(AesCbcCryptor.BLOCK_SIZE); + } + getKey() { + const sha = (0, crypto_1.createHash)('sha256'); + sha.update(Buffer.from(this.cipherKey, 'utf8')); + return Buffer.from(sha.digest()); + } +} +AesCbcCryptor.BLOCK_SIZE = 16; +AesCbcCryptor.encoder = new TextEncoder(); exports.default = AesCbcCryptor; diff --git a/lib/crypto/modules/NodeCryptoModule/legacyCryptor.js b/lib/crypto/modules/NodeCryptoModule/legacyCryptor.js index 21273869f..e1c348040 100644 --- a/lib/crypto/modules/NodeCryptoModule/legacyCryptor.js +++ b/lib/crypto/modules/NodeCryptoModule/legacyCryptor.js @@ -8,79 +8,48 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "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 (_) 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 }; - } -}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -var index_1 = __importDefault(require("../../../core/components/cryptography/index")); -var base64_codec_1 = require("../../../core/components/base64_codec"); -var node_1 = __importDefault(require("../node")); -var LegacyCryptor = /** @class */ (function () { - function LegacyCryptor(config) { +const index_1 = __importDefault(require("../../../core/components/cryptography/index")); +const base64_codec_1 = require("../../../core/components/base64_codec"); +const pubnub_error_1 = require("../../../errors/pubnub-error"); +const node_1 = __importDefault(require("../node")); +class LegacyCryptor { + constructor(config) { this.config = config; - this.cryptor = new index_1.default({ config: config }); + this.cryptor = new index_1.default(Object.assign({}, config)); this.fileCryptor = new node_1.default(); } - Object.defineProperty(LegacyCryptor.prototype, "identifier", { - get: function () { - return ''; - }, - enumerable: false, - configurable: true - }); - LegacyCryptor.prototype.encrypt = function (data) { + encrypt(data) { if (data.length === 0) - throw new Error('encryption error. empty content'); + throw new Error('Encryption error: empty content'); return { data: this.cryptor.encrypt(data), metadata: null, }; - }; - LegacyCryptor.prototype.decrypt = function (encryptedData) { - var data = typeof encryptedData.data === 'string' ? encryptedData.data : (0, base64_codec_1.encode)(encryptedData.data); - return this.cryptor.decrypt(data); - }; - LegacyCryptor.prototype.encryptFile = function (file, File) { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - return [2 /*return*/, this.fileCryptor.encryptFile(this.config.cipherKey, file, File)]; - }); + } + encryptFile(file, File) { + return __awaiter(this, void 0, void 0, function* () { + if (!this.config.cipherKey) + throw new pubnub_error_1.PubNubError('File encryption error: cipher key not set.'); + return this.fileCryptor.encryptFile(this.config.cipherKey, file, File); }); - }; - LegacyCryptor.prototype.decryptFile = function (file, File) { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - return [2 /*return*/, this.fileCryptor.decryptFile(this.config.cipherKey, file, File)]; - }); + } + decrypt(encryptedData) { + const data = typeof encryptedData.data === 'string' ? encryptedData.data : (0, base64_codec_1.encode)(encryptedData.data); + return this.cryptor.decrypt(data); + } + decryptFile(file, File) { + return __awaiter(this, void 0, void 0, function* () { + if (!this.config.cipherKey) + throw new pubnub_error_1.PubNubError('File decryption error: cipher key not set.'); + return this.fileCryptor.decryptFile(this.config.cipherKey, file, File); }); - }; - return LegacyCryptor; -}()); + } + get identifier() { + return ''; + } +} exports.default = LegacyCryptor; diff --git a/lib/crypto/modules/NodeCryptoModule/nodeCryptoModule.js b/lib/crypto/modules/NodeCryptoModule/nodeCryptoModule.js index fdaef2d94..bebd0de80 100644 --- a/lib/crypto/modules/NodeCryptoModule/nodeCryptoModule.js +++ b/lib/crypto/modules/NodeCryptoModule/nodeCryptoModule.js @@ -8,439 +8,323 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "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 (_) 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 }; - } -}; -var __read = (this && this.__read) || function (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; -}; -var __spreadArray = (this && this.__spreadArray) || function (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)); -}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.CryptoModule = exports.AesCbcCryptor = exports.LegacyCryptor = void 0; -var stream_1 = require("stream"); -var base64_codec_1 = require("../../../core/components/base64_codec"); -var legacyCryptor_1 = __importDefault(require("./legacyCryptor")); -exports.LegacyCryptor = legacyCryptor_1.default; -var aesCbcCryptor_1 = __importDefault(require("./aesCbcCryptor")); +const stream_1 = require("stream"); +const buffer_1 = require("buffer"); +const crypto_module_1 = require("../../../core/interfaces/crypto-module"); +const base64_codec_1 = require("../../../core/components/base64_codec"); +const pubnub_error_1 = require("../../../errors/pubnub-error"); +const aesCbcCryptor_1 = __importDefault(require("./aesCbcCryptor")); exports.AesCbcCryptor = aesCbcCryptor_1.default; -var CryptoModule = /** @class */ (function () { - function CryptoModule(cryptoModuleConfiguration) { - var _a; - this.defaultCryptor = cryptoModuleConfiguration.default; - this.cryptors = (_a = cryptoModuleConfiguration.cryptors) !== null && _a !== void 0 ? _a : []; - } - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore: type detection issue with old Config type assignment - CryptoModule.legacyCryptoModule = function (config) { +const legacyCryptor_1 = __importDefault(require("./legacyCryptor")); +exports.LegacyCryptor = legacyCryptor_1.default; +class CryptoModule extends crypto_module_1.AbstractCryptoModule { + static legacyCryptoModule(config) { var _a; + if (!config.cipherKey) + throw new pubnub_error_1.PubNubError('Crypto module error: cipher key not set.'); return new this({ - default: new legacyCryptor_1.default({ - cipherKey: config.cipherKey, - useRandomIVs: (_a = config.useRandomIVs) !== null && _a !== void 0 ? _a : true, - }), + default: new legacyCryptor_1.default(Object.assign(Object.assign({}, config), { useRandomIVs: (_a = config.useRandomIVs) !== null && _a !== void 0 ? _a : true })), cryptors: [new aesCbcCryptor_1.default({ cipherKey: config.cipherKey })], }); - }; - CryptoModule.aesCbcCryptoModule = function (config) { + } + static aesCbcCryptoModule(config) { var _a; + if (!config.cipherKey) + throw new pubnub_error_1.PubNubError('Crypto module error: cipher key not set.'); return new this({ default: new aesCbcCryptor_1.default({ cipherKey: config.cipherKey }), cryptors: [ - new legacyCryptor_1.default({ - cipherKey: config.cipherKey, - useRandomIVs: (_a = config.useRandomIVs) !== null && _a !== void 0 ? _a : true, - }), + new legacyCryptor_1.default(Object.assign(Object.assign({}, config), { useRandomIVs: (_a = config.useRandomIVs) !== null && _a !== void 0 ? _a : true })), ], }); - }; - CryptoModule.withDefaultCryptor = function (defaultCryptor) { + } + static withDefaultCryptor(defaultCryptor) { return new this({ default: defaultCryptor }); - }; - CryptoModule.prototype.getAllCryptors = function () { - return __spreadArray([this.defaultCryptor], __read(this.cryptors), false); - }; - CryptoModule.prototype.getLegacyCryptor = function () { - return this.getAllCryptors().find(function (c) { return c.identifier === ''; }); - }; - CryptoModule.prototype.encrypt = function (data) { - var encrypted = this.defaultCryptor.encrypt(data); + } + encrypt(data) { + const encrypted = data instanceof ArrayBuffer && this.defaultCryptor.identifier === CryptoModule.LEGACY_IDENTIFIER + ? this.defaultCryptor.encrypt(CryptoModule.decoder.decode(data)) + : this.defaultCryptor.encrypt(data); if (!encrypted.metadata) return encrypted.data; - var header = CryptorHeader.from(this.defaultCryptor.identifier, encrypted.metadata); - var headerData = new Uint8Array(header.length); - var pos = 0; - headerData.set(header.data, pos); - pos = header.length - encrypted.metadata.length; - headerData.set(encrypted.metadata, pos); - return Buffer.concat([headerData, Buffer.from(encrypted.data)]); - }; - CryptoModule.prototype.decrypt = function (data) { - var encryptedData = Buffer.from(typeof data === 'string' ? (0, base64_codec_1.decode)(data) : data); - var header = CryptorHeader.tryParse(encryptedData); - var cryptor = this.getCryptor(header); - var metadata = header.length > 0 + const headerData = this.getHeaderData(encrypted); + const encryptedData = typeof encrypted.data === 'string' + ? CryptoModule.encoder.encode(encrypted.data).buffer + : encrypted.data.buffer.slice(encrypted.data.byteOffset, encrypted.data.byteOffset + encrypted.data.length); + return this.concatArrayBuffer(headerData, encryptedData); + } + encryptFile(file, File) { + return __awaiter(this, void 0, void 0, function* () { + if (this.defaultCryptor.identifier === CryptorHeader.LEGACY_IDENTIFIER) + return this.defaultCryptor.encryptFile(file, File); + if (file.data instanceof buffer_1.Buffer) { + const encryptedData = this.encrypt(file.data); + return File.create({ + name: file.name, + mimeType: 'application/octet-stream', + data: buffer_1.Buffer.from(typeof encryptedData === 'string' ? CryptoModule.encoder.encode(encryptedData) : encryptedData), + }); + } + if (file.data instanceof stream_1.Readable) { + if (!file.contentLength || file.contentLength === 0) + throw new Error('Encryption error: empty content'); + const encryptedStream = yield this.defaultCryptor.encryptStream(file.data); + const header = CryptorHeader.from(this.defaultCryptor.identifier, encryptedStream.metadata); + const payload = new Uint8Array(header.length); + let pos = 0; + payload.set(header.data, pos); + pos += header.length; + if (encryptedStream.metadata) { + const metadata = new Uint8Array(encryptedStream.metadata); + pos -= encryptedStream.metadata.byteLength; + payload.set(metadata, pos); + } + const output = new stream_1.PassThrough(); + output.write(payload); + encryptedStream.stream.pipe(output); + return File.create({ + name: file.name, + mimeType: 'application/octet-stream', + stream: output, + }); + } + }); + } + decrypt(data) { + const encryptedData = buffer_1.Buffer.from(typeof data === 'string' ? (0, base64_codec_1.decode)(data) : data); + const header = CryptorHeader.tryParse(encryptedData.buffer.slice(encryptedData.byteOffset, encryptedData.byteOffset + encryptedData.length)); + const cryptor = this.getCryptor(header); + const metadata = header.length > 0 ? encryptedData.slice(header.length - header.metadataLength, header.length) : null; if (encryptedData.slice(header.length).byteLength <= 0) - throw new Error('decryption error. empty content'); + throw new Error('Decryption error: empty content'); return cryptor.decrypt({ data: encryptedData.slice(header.length), metadata: metadata, }); - }; - CryptoModule.prototype.encryptFile = function (file, File) { - return __awaiter(this, void 0, void 0, function () { - var encryptedStream, header, payload, pos, output; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - /** - * Files handled differently in case of Legacy cryptor. - * (as long as we support legacy need to check on intsance type) - */ - if (this.defaultCryptor.identifier === CryptorHeader.LEGACY_IDENTIFIER) - return [2 /*return*/, this.defaultCryptor.encryptFile(file, File)]; - if (file.data instanceof Buffer) { - return [2 /*return*/, File.create({ - name: file.name, - mimeType: 'application/octet-stream', - data: Buffer.from(this.encrypt(file.data)), - })]; - } - if (!(file.data instanceof stream_1.Readable)) return [3 /*break*/, 2]; - if (file.contentLength === 0) - throw new Error('encryption error. empty content'); - return [4 /*yield*/, this.defaultCryptor.encryptStream(file.data)]; - case 1: - encryptedStream = _a.sent(); - header = CryptorHeader.from(this.defaultCryptor.identifier, encryptedStream.metadata); - payload = new Uint8Array(header.length); - pos = 0; - payload.set(header.data, pos); - pos += header.length; - if (encryptedStream.metadata) { - pos -= encryptedStream.metadata.length; - payload.set(encryptedStream.metadata, pos); - } - output = new stream_1.PassThrough(); - output.write(payload); - encryptedStream.stream.pipe(output); - return [2 /*return*/, File.create({ - name: file.name, - mimeType: 'application/octet-stream', - stream: output, - })]; - case 2: return [2 /*return*/]; - } - }); - }); - }; - CryptoModule.prototype.decryptFile = function (file, File) { - return __awaiter(this, void 0, void 0, function () { - var header, cryptor, stream_2; - var _this = this; - return __generator(this, function (_a) { - if ((file === null || file === void 0 ? void 0 : file.data) instanceof Buffer) { - header = CryptorHeader.tryParse(file.data); - cryptor = this.getCryptor(header); - /** - * If It's legacyone then redirect it. - * (as long as we support legacy need to check on instance type) - */ - if ((cryptor === null || cryptor === void 0 ? void 0 : cryptor.identifier) === CryptoModule.LEGACY_IDENTIFIER) - return [2 /*return*/, cryptor.decryptFile(file, File)]; - return [2 /*return*/, File.create({ - name: file.name, - data: Buffer.from(this.decrypt(file === null || file === void 0 ? void 0 : file.data)), - })]; - } - if (file.data instanceof stream_1.Readable) { - stream_2 = file.data; - return [2 /*return*/, new Promise(function (resolve) { - stream_2.on('readable', function () { return resolve(_this.onStreamReadable(stream_2, file, File)); }); - })]; - } - return [2 /*return*/]; - }); - }); - }; - CryptoModule.prototype.onStreamReadable = function (stream, file, File) { - return __awaiter(this, void 0, void 0, function () { - var magicBytes, versionByte, identifier, cryptor, headerSize, _a, _b; - var _c; - return __generator(this, function (_d) { - switch (_d.label) { - case 0: - stream.removeAllListeners('readable'); - magicBytes = stream.read(4); - if (!CryptorHeader.isSentinel(magicBytes)) { - if (magicBytes === null) - throw new Error('decryption error. empty content'); - stream.unshift(magicBytes); - return [2 /*return*/, this.decryptLegacyFileStream(stream, file, File)]; - } - versionByte = stream.read(1); - CryptorHeader.validateVersion(versionByte[0]); - identifier = stream.read(4); - cryptor = this.getCryptorFromId(CryptorHeader.tryGetIdentifier(identifier)); - headerSize = CryptorHeader.tryGetMetadataSizeFromStream(stream); - if (file.contentLength <= CryptorHeader.MIN_HEADER_LEGTH + headerSize) - throw new Error('decryption error. empty content'); - _b = (_a = File).create; - _c = { - name: file.name, - mimeType: 'application/octet-stream' - }; - return [4 /*yield*/, cryptor.decryptStream({ stream: stream, metadataLength: headerSize })]; - case 1: return [2 /*return*/, _b.apply(_a, [(_c.stream = _d.sent(), - _c)])]; - } - }); - }); - }; - CryptoModule.prototype.decryptLegacyFileStream = function (stream, file, File) { - return __awaiter(this, void 0, void 0, function () { - var cryptor; - return __generator(this, function (_a) { - if (file.contentLength <= 16) - throw new Error('decryption error: empty content'); - cryptor = this.getLegacyCryptor(); - if (cryptor) { - return [2 /*return*/, cryptor.decryptFile(File.create({ - name: file.name, - stream: stream, - }), File)]; - } - else { - throw new Error('unknown cryptor error'); - } - return [2 /*return*/]; - }); + } + decryptFile(file, File) { + return __awaiter(this, void 0, void 0, function* () { + if (file.data && file.data instanceof buffer_1.Buffer) { + const header = CryptorHeader.tryParse(file.data.buffer.slice(file.data.byteOffset, file.data.byteOffset + file.data.length)); + const cryptor = this.getCryptor(header); + if ((cryptor === null || cryptor === void 0 ? void 0 : cryptor.identifier) === CryptoModule.LEGACY_IDENTIFIER) + return cryptor.decryptFile(file, File); + return File.create({ + name: file.name, + data: buffer_1.Buffer.from(this.decrypt(file.data)), + }); + } + if (file.data && file.data instanceof stream_1.Readable) { + const stream = file.data; + return new Promise((resolve) => { + stream.on('readable', () => resolve(this.onStreamReadable(stream, file, File))); + }); + } }); - }; - CryptoModule.prototype.getCryptor = function (header) { - if (header === '') { - var cryptor = this.getAllCryptors().find(function (c) { return c.identifier === ''; }); + } + getLegacyCryptor() { + return this.getCryptorFromId(CryptoModule.LEGACY_IDENTIFIER); + } + getCryptorFromId(id) { + const cryptor = this.getAllCryptors().find((cryptor) => id === cryptor.identifier); + if (cryptor) + return cryptor; + throw new Error('Unknown cryptor error'); + } + getCryptor(header) { + if (typeof header === 'string') { + const cryptor = this.getAllCryptors().find((c) => c.identifier === header); if (cryptor) return cryptor; - throw new Error('unknown cryptor error'); + throw new Error('Unknown cryptor error'); } else if (header instanceof CryptorHeaderV1) { return this.getCryptorFromId(header.identifier); } - }; - CryptoModule.prototype.getCryptorFromId = function (id) { - var cryptor = this.getAllCryptors().find(function (c) { return id === c.identifier; }); - if (cryptor) { - return cryptor; - } - throw new Error('unknown cryptor error'); - }; - CryptoModule.LEGACY_IDENTIFIER = ''; - return CryptoModule; -}()); -exports.CryptoModule = CryptoModule; -// CryptorHeader Utility -var CryptorHeader = /** @class */ (function () { - function CryptorHeader() { } - CryptorHeader.from = function (id, metadata) { + getHeaderData(encrypted) { + if (!encrypted.metadata) + return; + const header = CryptorHeader.from(this.defaultCryptor.identifier, encrypted.metadata); + const headerData = new Uint8Array(header.length); + let pos = 0; + headerData.set(header.data, pos); + pos += header.length - encrypted.metadata.byteLength; + headerData.set(new Uint8Array(encrypted.metadata), pos); + return headerData.buffer; + } + concatArrayBuffer(ab1, ab2) { + const tmp = new Uint8Array(ab1.byteLength + ab2.byteLength); + tmp.set(new Uint8Array(ab1), 0); + tmp.set(new Uint8Array(ab2), ab1.byteLength); + return tmp.buffer; + } + onStreamReadable(stream, file, File) { + return __awaiter(this, void 0, void 0, function* () { + stream.removeAllListeners('readable'); + const magicBytes = stream.read(4); + if (!CryptorHeader.isSentinel(magicBytes)) { + if (magicBytes === null) + throw new Error('Decryption error: empty content'); + stream.unshift(magicBytes); + return this.decryptLegacyFileStream(stream, file, File); + } + const versionByte = stream.read(1); + CryptorHeader.validateVersion(versionByte[0]); + const identifier = stream.read(4); + const cryptor = this.getCryptorFromId(CryptorHeader.tryGetIdentifier(identifier)); + const headerSize = CryptorHeader.tryGetMetadataSizeFromStream(stream); + if (!file.contentLength || file.contentLength <= CryptorHeader.MIN_HEADER_LENGTH + headerSize) + throw new Error('Decryption error: empty content'); + return File.create({ + name: file.name, + mimeType: 'application/octet-stream', + stream: (yield cryptor.decryptStream({ + stream: stream, + metadataLength: headerSize, + })), + }); + }); + } + decryptLegacyFileStream(stream, file, File) { + return __awaiter(this, void 0, void 0, function* () { + if (!file.contentLength || file.contentLength <= 16) + throw new Error('Decryption error: empty content'); + const cryptor = this.getLegacyCryptor(); + if (cryptor) { + return cryptor.decryptFile(File.create({ + name: file.name, + stream: stream, + }), File); + } + else + throw new Error('unknown cryptor error'); + }); + } +} +exports.CryptoModule = CryptoModule; +CryptoModule.LEGACY_IDENTIFIER = ''; +class CryptorHeader { + static from(id, metadata) { if (id === CryptorHeader.LEGACY_IDENTIFIER) return; - return new CryptorHeaderV1(id, metadata.length); - }; - CryptorHeader.isSentinel = function (bytes) { - if (bytes && bytes.byteLength >= 4) { - if (bytes.toString('utf8') == CryptorHeader.SENTINEL) - return true; - } - }; - CryptorHeader.validateVersion = function (data) { + return new CryptorHeaderV1(id, metadata.byteLength); + } + static isSentinel(bytes) { + return bytes && bytes.byteLength >= 4 && CryptorHeader.decoder.decode(bytes) == CryptorHeader.SENTINEL; + } + static validateVersion(data) { if (data && data > CryptorHeader.MAX_VERSION) - throw new Error('decryption error. invalid header version'); + throw new Error('Decryption error: invalid header version'); return data; - }; - CryptorHeader.tryGetIdentifier = function (data) { - if (data.byteLength < 4) { - throw new Error('unknown cryptor error. decryption failed'); - } - else { - return data.toString('utf8'); - } - }; - CryptorHeader.tryGetMetadataSizeFromStream = function (stream) { - var sizeBuf = stream.read(1); - if (sizeBuf && sizeBuf[0] < 255) { + } + static tryGetIdentifier(data) { + if (data.byteLength < 4) + throw new Error('Decryption error: unknown cryptor error'); + else + return CryptorHeader.decoder.decode(data); + } + static tryGetMetadataSizeFromStream(stream) { + const sizeBuf = stream.read(1); + if (sizeBuf && sizeBuf[0] < 255) return sizeBuf[0]; - } if (sizeBuf[0] === 255) { - var nextBuf = stream.read(2); + const nextBuf = stream.read(2); if (nextBuf.length >= 2) { - return new Uint16Array([nextBuf[0], nextBuf[1]]).reduce(function (acc, val) { return (acc << 8) + val; }, 0); + return new Uint16Array([nextBuf[0], nextBuf[1]]).reduce((acc, val) => (acc << 8) + val, 0); } } - throw new Error('decryption error. Invalid metadata size'); - }; - CryptorHeader.tryParse = function (encryptedData) { - var sentinel = ''; - var version = null; - if (encryptedData.length >= 4) { + throw new Error('Decryption error: invalid metadata size'); + } + static tryParse(encryptedData) { + const encryptedDataView = new DataView(encryptedData); + let sentinel; + let version = null; + if (encryptedData.byteLength >= 4) { sentinel = encryptedData.slice(0, 4); - if (sentinel.toString('utf8') !== CryptorHeader.SENTINEL) - return ''; - } - if (encryptedData.length >= 5) { - version = encryptedData[4]; - } - else { - throw new Error('decryption error. invalid header version'); + if (!this.isSentinel(sentinel)) + return CryptoModule.LEGACY_IDENTIFIER; } + if (encryptedData.byteLength >= 5) + version = encryptedDataView.getInt8(4); + else + throw new Error('Decryption error: invalid header version'); if (version > CryptorHeader.MAX_VERSION) throw new Error('unknown cryptor error'); - var identifier; - var pos = 5 + CryptorHeader.IDENTIFIER_LENGTH; - if (encryptedData.length >= pos) { + let identifier; + let pos = 5 + CryptorHeader.IDENTIFIER_LENGTH; + if (encryptedData.byteLength >= pos) identifier = encryptedData.slice(5, pos); - } - else { - throw new Error('decryption error. invalid crypto identifier'); - } - var metadataLength = null; - if (encryptedData.length >= pos + 1) { - metadataLength = encryptedData[pos]; - } - else { - throw new Error('decryption error. invalid metadata length'); - } + else + throw new Error('Decryption error: invalid crypto identifier'); + let metadataLength = null; + if (encryptedData.byteLength >= pos + 1) + metadataLength = encryptedDataView.getInt8(pos); + else + throw new Error('Decryption error: invalid metadata length'); pos += 1; - if (metadataLength === 255 && encryptedData.length >= pos + 2) { - metadataLength = new Uint16Array(encryptedData.slice(pos, pos + 2)).reduce(function (acc, val) { return (acc << 8) + val; }, 0); - pos += 2; + if (metadataLength === 255 && encryptedData.byteLength >= pos + 2) { + metadataLength = new Uint16Array(encryptedData.slice(pos, pos + 2)).reduce((acc, val) => (acc << 8) + val, 0); } - return new CryptorHeaderV1(identifier.toString('utf8'), metadataLength); - }; - CryptorHeader.SENTINEL = 'PNED'; - CryptorHeader.LEGACY_IDENTIFIER = ''; - CryptorHeader.IDENTIFIER_LENGTH = 4; - CryptorHeader.VERSION = 1; - CryptorHeader.MAX_VERSION = 1; - CryptorHeader.MIN_HEADER_LEGTH = 10; - return CryptorHeader; -}()); -// v1 CryptorHeader -var CryptorHeaderV1 = /** @class */ (function () { - function CryptorHeaderV1(id, metadataLength) { + return new CryptorHeaderV1(CryptorHeader.decoder.decode(identifier), metadataLength); + } +} +CryptorHeader.decoder = new TextDecoder(); +CryptorHeader.SENTINEL = 'PNED'; +CryptorHeader.LEGACY_IDENTIFIER = ''; +CryptorHeader.IDENTIFIER_LENGTH = 4; +CryptorHeader.VERSION = 1; +CryptorHeader.MAX_VERSION = 1; +CryptorHeader.MIN_HEADER_LENGTH = 10; +class CryptorHeaderV1 { + constructor(id, metadataLength) { this._identifier = id; this._metadataLength = metadataLength; } - Object.defineProperty(CryptorHeaderV1.prototype, "identifier", { - get: function () { - return this._identifier; - }, - set: function (value) { - this._identifier = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(CryptorHeaderV1.prototype, "metadataLength", { - get: function () { - return this._metadataLength; - }, - set: function (value) { - this._metadataLength = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(CryptorHeaderV1.prototype, "version", { - get: function () { - return CryptorHeader.VERSION; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(CryptorHeaderV1.prototype, "length", { - get: function () { - return (CryptorHeader.SENTINEL.length + - 1 + - CryptorHeader.IDENTIFIER_LENGTH + - (this.metadataLength < 255 ? 1 : 3) + - this.metadataLength); - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(CryptorHeaderV1.prototype, "data", { - get: function () { - var pos = 0; - var header = new Uint8Array(this.length); - header.set(Buffer.from(CryptorHeader.SENTINEL)); - pos += CryptorHeader.SENTINEL.length; - header[pos] = this.version; - pos++; - if (this.identifier) - header.set(Buffer.from(this.identifier), pos); - pos += CryptorHeader.IDENTIFIER_LENGTH; - var metadataLength = this.metadataLength; - if (metadataLength < 255) { - header[pos] = metadataLength; - } - else { - header.set([255, metadataLength >> 8, metadataLength & 0xff], pos); - } - return header; - }, - enumerable: false, - configurable: true - }); - return CryptorHeaderV1; -}()); + get identifier() { + return this._identifier; + } + set identifier(value) { + this._identifier = value; + } + get metadataLength() { + return this._metadataLength; + } + set metadataLength(value) { + this._metadataLength = value; + } + get version() { + return CryptorHeader.VERSION; + } + get length() { + return (CryptorHeader.SENTINEL.length + + 1 + + CryptorHeader.IDENTIFIER_LENGTH + + (this.metadataLength < 255 ? 1 : 3) + + this.metadataLength); + } + get data() { + let pos = 0; + const header = new Uint8Array(this.length); + header.set(buffer_1.Buffer.from(CryptorHeader.SENTINEL)); + pos += CryptorHeader.SENTINEL.length; + header[pos] = this.version; + pos++; + if (this.identifier) + header.set(buffer_1.Buffer.from(this.identifier), pos); + const metadataLength = this.metadataLength; + pos += CryptorHeader.IDENTIFIER_LENGTH; + if (metadataLength < 255) + header[pos] = metadataLength; + else + header.set([255, metadataLength >> 8, metadataLength & 0xff], pos); + return header; + } +} diff --git a/lib/crypto/modules/WebCryptoModule/aesCbcCryptor.js b/lib/crypto/modules/WebCryptoModule/aesCbcCryptor.js deleted file mode 100644 index d80cbbb15..000000000 --- a/lib/crypto/modules/WebCryptoModule/aesCbcCryptor.js +++ /dev/null @@ -1,148 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (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()); - }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "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 (_) 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 }; - } -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var hmac_sha256_1 = __importDefault(require("../../../core/components/cryptography/hmac-sha256")); -var base64_codec_1 = require("../../../core/components/base64_codec"); -var AesCbcCryptor = /** @class */ (function () { - function AesCbcCryptor(configuration) { - this.cipherKey = configuration.cipherKey; - this.CryptoJS = hmac_sha256_1.default; - this.encryptedKey = this.CryptoJS.SHA256(this.cipherKey); - } - Object.defineProperty(AesCbcCryptor.prototype, "algo", { - get: function () { - return 'AES-CBC'; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(AesCbcCryptor.prototype, "identifier", { - get: function () { - return 'ACRH'; - }, - enumerable: false, - configurable: true - }); - AesCbcCryptor.prototype.getIv = function () { - return crypto.getRandomValues(new Uint8Array(AesCbcCryptor.BLOCK_SIZE)); - }; - AesCbcCryptor.prototype.getKey = function () { - return __awaiter(this, void 0, void 0, function () { - var bKey, abHash; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - bKey = AesCbcCryptor.encoder.encode(this.cipherKey); - return [4 /*yield*/, crypto.subtle.digest('SHA-256', bKey.buffer)]; - case 1: - abHash = _a.sent(); - return [2 /*return*/, crypto.subtle.importKey('raw', abHash, this.algo, true, ['encrypt', 'decrypt'])]; - } - }); - }); - }; - AesCbcCryptor.prototype.encrypt = function (data) { - var stringData = typeof data === 'string' ? data : AesCbcCryptor.decoder.decode(data); - if (stringData.length === 0) - throw new Error('encryption error. empty content'); - var abIv = this.getIv(); - return { - metadata: abIv, - data: (0, base64_codec_1.decode)(this.CryptoJS.AES.encrypt(data, this.encryptedKey, { - iv: this.bufferToWordArray(abIv), - mode: this.CryptoJS.mode.CBC, - }).ciphertext.toString(this.CryptoJS.enc.Base64)), - }; - }; - AesCbcCryptor.prototype.decrypt = function (encryptedData) { - var iv = this.bufferToWordArray(new Uint8ClampedArray(encryptedData.metadata)); - var data = this.bufferToWordArray(new Uint8ClampedArray(encryptedData.data)); - return AesCbcCryptor.encoder.encode(this.CryptoJS.AES.decrypt({ ciphertext: data }, this.encryptedKey, { - iv: iv, - mode: this.CryptoJS.mode.CBC, - }).toString(this.CryptoJS.enc.Utf8)).buffer; - }; - AesCbcCryptor.prototype.encryptFileData = function (data) { - return __awaiter(this, void 0, void 0, function () { - var key, iv; - var _a; - return __generator(this, function (_b) { - switch (_b.label) { - case 0: return [4 /*yield*/, this.getKey()]; - case 1: - key = _b.sent(); - iv = this.getIv(); - _a = {}; - return [4 /*yield*/, crypto.subtle.encrypt({ name: this.algo, iv: iv }, key, data)]; - case 2: return [2 /*return*/, (_a.data = _b.sent(), - _a.metadata = iv, - _a)]; - } - }); - }); - }; - AesCbcCryptor.prototype.decryptFileData = function (encryptedData) { - return __awaiter(this, void 0, void 0, function () { - var key; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: return [4 /*yield*/, this.getKey()]; - case 1: - key = _a.sent(); - return [2 /*return*/, crypto.subtle.decrypt({ name: this.algo, iv: encryptedData.metadata }, key, encryptedData.data)]; - } - }); - }); - }; - AesCbcCryptor.prototype.bufferToWordArray = function (b) { - var wa = []; - var i; - for (i = 0; i < b.length; i += 1) { - wa[(i / 4) | 0] |= b[i] << (24 - 8 * i); - } - return this.CryptoJS.lib.WordArray.create(wa, b.length); - }; - AesCbcCryptor.BLOCK_SIZE = 16; - AesCbcCryptor.encoder = new TextEncoder(); - AesCbcCryptor.decoder = new TextDecoder(); - return AesCbcCryptor; -}()); -exports.default = AesCbcCryptor; diff --git a/lib/crypto/modules/WebCryptoModule/legacyCryptor.js b/lib/crypto/modules/WebCryptoModule/legacyCryptor.js deleted file mode 100644 index 9b318e359..000000000 --- a/lib/crypto/modules/WebCryptoModule/legacyCryptor.js +++ /dev/null @@ -1,90 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (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()); - }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "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 (_) 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 }; - } -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var index_1 = __importDefault(require("../../../core/components/cryptography/index")); -var web_1 = __importDefault(require("../web")); -var base64_codec_1 = require("../../../core/components/base64_codec"); -var LegacyCryptor = /** @class */ (function () { - function LegacyCryptor(config) { - this.config = config; - this.cryptor = new index_1.default({ config: config }); - this.fileCryptor = new web_1.default(); - } - Object.defineProperty(LegacyCryptor.prototype, "identifier", { - get: function () { - return ''; - }, - enumerable: false, - configurable: true - }); - LegacyCryptor.prototype.encrypt = function (data) { - var stringData = typeof data === 'string' ? data : new TextDecoder().decode(data); - return { - data: this.cryptor.encrypt(stringData), - metadata: null, - }; - }; - LegacyCryptor.prototype.decrypt = function (encryptedData) { - var data = typeof encryptedData.data === 'string' ? encryptedData.data : (0, base64_codec_1.encode)(encryptedData.data); - return this.cryptor.decrypt(data); - }; - LegacyCryptor.prototype.encryptFile = function (file, File) { - var _a; - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_b) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - //@ts-ignore: can not detect cipherKey from old Config - return [2 /*return*/, this.fileCryptor.encryptFile((_a = this.config) === null || _a === void 0 ? void 0 : _a.cipherKey, file, File)]; - }); - }); - }; - LegacyCryptor.prototype.decryptFile = function (file, File) { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - //@ts-ignore: can not detect cipherKey from old Config - return [2 /*return*/, this.fileCryptor.decryptFile(this.config.cipherKey, file, File)]; - }); - }); - }; - return LegacyCryptor; -}()); -exports.default = LegacyCryptor; diff --git a/lib/crypto/modules/WebCryptoModule/webCryptoModule.js b/lib/crypto/modules/WebCryptoModule/webCryptoModule.js deleted file mode 100644 index f4c7ccabf..000000000 --- a/lib/crypto/modules/WebCryptoModule/webCryptoModule.js +++ /dev/null @@ -1,376 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (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()); - }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "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 (_) 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 }; - } -}; -var __read = (this && this.__read) || function (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; -}; -var __spreadArray = (this && this.__spreadArray) || function (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)); -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.CryptoModule = exports.AesCbcCryptor = exports.LegacyCryptor = void 0; -var legacyCryptor_1 = __importDefault(require("./legacyCryptor")); -exports.LegacyCryptor = legacyCryptor_1.default; -var aesCbcCryptor_1 = __importDefault(require("./aesCbcCryptor")); -exports.AesCbcCryptor = aesCbcCryptor_1.default; -var base64_codec_1 = require("../../../core/components/base64_codec"); -var CryptoModule = /** @class */ (function () { - function CryptoModule(cryptoModuleConfiguration) { - var _a; - this.defaultCryptor = cryptoModuleConfiguration.default; - this.cryptors = (_a = cryptoModuleConfiguration.cryptors) !== null && _a !== void 0 ? _a : []; - } - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - //@ts-ignore: type detection issue with old Config type assignment - CryptoModule.legacyCryptoModule = function (config) { - var _a; - return new this({ - default: new legacyCryptor_1.default({ - cipherKey: config.cipherKey, - useRandomIVs: (_a = config.useRandomIVs) !== null && _a !== void 0 ? _a : true, - }), - cryptors: [new aesCbcCryptor_1.default({ cipherKey: config.cipherKey })], - }); - }; - CryptoModule.aesCbcCryptoModule = function (config) { - var _a; - return new this({ - default: new aesCbcCryptor_1.default({ cipherKey: config.cipherKey }), - cryptors: [ - new legacyCryptor_1.default({ - cipherKey: config.cipherKey, - useRandomIVs: (_a = config.useRandomIVs) !== null && _a !== void 0 ? _a : true, - }), - ], - }); - }; - CryptoModule.withDefaultCryptor = function (defaultCryptor) { - return new this({ default: defaultCryptor }); - }; - CryptoModule.prototype.getAllCryptors = function () { - return __spreadArray([this.defaultCryptor], __read(this.cryptors), false); - }; - CryptoModule.prototype.encrypt = function (data) { - var encrypted = this.defaultCryptor.encrypt(data); - if (!encrypted.metadata) - return encrypted.data; - var headerData = this.getHeaderData(encrypted); - return this.concatArrayBuffer(headerData, encrypted.data); - }; - CryptoModule.prototype.decrypt = function (data) { - var encryptedData = typeof data === 'string' ? (0, base64_codec_1.decode)(data) : data; - var header = CryptorHeader.tryParse(encryptedData); - var cryptor = this.getCryptor(header); - var metadata = header.length > 0 - ? encryptedData.slice(header.length - header.metadataLength, header.length) - : null; - if (encryptedData.slice(header.length).byteLength <= 0) - throw new Error('decryption error. empty content'); - return cryptor.decrypt({ - data: encryptedData.slice(header.length), - metadata: metadata, - }); - }; - CryptoModule.prototype.encryptFile = function (file, File) { - return __awaiter(this, void 0, void 0, function () { - var fileData, encrypted; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - if (this.defaultCryptor.identifier === CryptorHeader.LEGACY_IDENTIFIER) - return [2 /*return*/, this.defaultCryptor.encryptFile(file, File)]; - return [4 /*yield*/, this.getFileData(file.data)]; - case 1: - fileData = _a.sent(); - return [4 /*yield*/, this.defaultCryptor.encryptFileData(fileData)]; - case 2: - encrypted = _a.sent(); - return [2 /*return*/, File.create({ - name: file.name, - mimeType: 'application/octet-stream', - data: this.concatArrayBuffer(this.getHeaderData(encrypted), encrypted.data), - })]; - } - }); - }); - }; - CryptoModule.prototype.decryptFile = function (file, File) { - return __awaiter(this, void 0, void 0, function () { - var data, header, cryptor, fileData, metadata, _a, _b; - var _c; - return __generator(this, function (_d) { - switch (_d.label) { - case 0: return [4 /*yield*/, file.data.arrayBuffer()]; - case 1: - data = _d.sent(); - header = CryptorHeader.tryParse(data); - cryptor = this.getCryptor(header); - if ((cryptor === null || cryptor === void 0 ? void 0 : cryptor.identifier) === CryptoModule.LEGACY_IDENTIFIER) { - return [2 /*return*/, cryptor.decryptFile(file, File)]; - } - return [4 /*yield*/, this.getFileData(data)]; - case 2: - fileData = _d.sent(); - metadata = fileData.slice(header.length - header.metadataLength, header.length); - _b = (_a = File).create; - _c = { - name: file.name - }; - return [4 /*yield*/, this.defaultCryptor.decryptFileData({ - data: data.slice(header.length), - metadata: metadata, - })]; - case 3: return [2 /*return*/, _b.apply(_a, [(_c.data = _d.sent(), - _c)])]; - } - }); - }); - }; - CryptoModule.prototype.getCryptor = function (header) { - if (header === '') { - var cryptor = this.getAllCryptors().find(function (c) { return c.identifier === ''; }); - if (cryptor) - return cryptor; - throw new Error('unknown cryptor error'); - } - else if (header instanceof CryptorHeaderV1) { - return this.getCryptorFromId(header.identifier); - } - }; - CryptoModule.prototype.getCryptorFromId = function (id) { - var cryptor = this.getAllCryptors().find(function (c) { return id === c.identifier; }); - if (cryptor) { - return cryptor; - } - throw Error('unknown cryptor error'); - }; - CryptoModule.prototype.concatArrayBuffer = function (ab1, ab2) { - var tmp = new Uint8Array(ab1.byteLength + ab2.byteLength); - tmp.set(new Uint8Array(ab1), 0); - tmp.set(new Uint8Array(ab2), ab1.byteLength); - return tmp.buffer; - }; - CryptoModule.prototype.getHeaderData = function (encrypted) { - if (!encrypted.metadata) - return; - var header = CryptorHeader.from(this.defaultCryptor.identifier, encrypted.metadata); - var headerData = new Uint8Array(header.length); - var pos = 0; - headerData.set(header.data, pos); - pos += header.length - encrypted.metadata.byteLength; - headerData.set(new Uint8Array(encrypted.metadata), pos); - return headerData.buffer; - }; - CryptoModule.prototype.getFileData = function (input) { - return __awaiter(this, void 0, void 0, function () { - var fileData; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - if (!(input instanceof Blob)) return [3 /*break*/, 2]; - return [4 /*yield*/, input.arrayBuffer()]; - case 1: - fileData = _a.sent(); - return [2 /*return*/, fileData]; - case 2: - if (input instanceof ArrayBuffer) { - return [2 /*return*/, input]; - } - if (typeof input === 'string') { - return [2 /*return*/, CryptoModule.encoder.encode(input)]; - } - throw new Error('Cannot decrypt/encrypt file. In browsers file encrypt/decrypt supported for string, ArrayBuffer or Blob'); - } - }); - }); - }; - CryptoModule.LEGACY_IDENTIFIER = ''; - CryptoModule.encoder = new TextEncoder(); - CryptoModule.decoder = new TextDecoder(); - return CryptoModule; -}()); -exports.CryptoModule = CryptoModule; -// CryptorHeader Utility -var CryptorHeader = /** @class */ (function () { - function CryptorHeader() { - } - CryptorHeader.from = function (id, metadata) { - if (id === CryptorHeader.LEGACY_IDENTIFIER) - return; - return new CryptorHeaderV1(id, metadata.byteLength); - }; - CryptorHeader.tryParse = function (data) { - var encryptedData = new Uint8Array(data); - var sentinel = ''; - var version = null; - if (encryptedData.byteLength >= 4) { - sentinel = encryptedData.slice(0, 4); - if (this.decoder.decode(sentinel) !== CryptorHeader.SENTINEL) - return ''; - } - if (encryptedData.byteLength >= 5) { - version = encryptedData[4]; - } - else { - throw new Error('decryption error. invalid header version'); - } - if (version > CryptorHeader.MAX_VERSION) - throw new Error('unknown cryptor error'); - var identifier = ''; - var pos = 5 + CryptorHeader.IDENTIFIER_LENGTH; - if (encryptedData.byteLength >= pos) { - identifier = encryptedData.slice(5, pos); - } - else { - throw new Error('decryption error. invalid crypto identifier'); - } - var metadataLength = null; - if (encryptedData.byteLength >= pos + 1) { - metadataLength = encryptedData[pos]; - } - else { - throw new Error('decryption error. invalid metadata length'); - } - pos += 1; - if (metadataLength === 255 && encryptedData.byteLength >= pos + 2) { - metadataLength = new Uint16Array(encryptedData.slice(pos, pos + 2)).reduce(function (acc, val) { return (acc << 8) + val; }, 0); - pos += 2; - } - return new CryptorHeaderV1(this.decoder.decode(identifier), metadataLength); - }; - CryptorHeader.SENTINEL = 'PNED'; - CryptorHeader.LEGACY_IDENTIFIER = ''; - CryptorHeader.IDENTIFIER_LENGTH = 4; - CryptorHeader.VERSION = 1; - CryptorHeader.MAX_VERSION = 1; - CryptorHeader.decoder = new TextDecoder(); - return CryptorHeader; -}()); -// v1 CryptorHeader -var CryptorHeaderV1 = /** @class */ (function () { - function CryptorHeaderV1(id, metadataLength) { - this._identifier = id; - this._metadataLength = metadataLength; - } - Object.defineProperty(CryptorHeaderV1.prototype, "identifier", { - get: function () { - return this._identifier; - }, - set: function (value) { - this._identifier = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(CryptorHeaderV1.prototype, "metadataLength", { - get: function () { - return this._metadataLength; - }, - set: function (value) { - this._metadataLength = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(CryptorHeaderV1.prototype, "version", { - get: function () { - return CryptorHeader.VERSION; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(CryptorHeaderV1.prototype, "length", { - get: function () { - return (CryptorHeader.SENTINEL.length + - 1 + - CryptorHeader.IDENTIFIER_LENGTH + - (this.metadataLength < 255 ? 1 : 3) + - this.metadataLength); - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(CryptorHeaderV1.prototype, "data", { - get: function () { - var pos = 0; - var header = new Uint8Array(this.length); - var encoder = new TextEncoder(); - header.set(encoder.encode(CryptorHeader.SENTINEL)); - pos += CryptorHeader.SENTINEL.length; - header[pos] = this.version; - pos++; - if (this.identifier) - header.set(encoder.encode(this.identifier), pos); - pos += CryptorHeader.IDENTIFIER_LENGTH; - var metadataLength = this.metadataLength; - if (metadataLength < 255) { - header[pos] = metadataLength; - } - else { - header.set([255, metadataLength >> 8, metadataLength & 0xff], pos); - } - return header; - }, - enumerable: false, - configurable: true - }); - CryptorHeaderV1.IDENTIFIER_LENGTH = 4; - CryptorHeaderV1.SENTINEL = 'PNED'; - return CryptorHeaderV1; -}()); diff --git a/lib/crypto/modules/node.js b/lib/crypto/modules/node.js index cb3968452..8e7d36a86 100644 --- a/lib/crypto/modules/node.js +++ b/lib/crypto/modules/node.js @@ -8,222 +8,115 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "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 (_) 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 }; - } -}; Object.defineProperty(exports, "__esModule", { value: true }); -/** */ -var stream_1 = require("stream"); -var crypto_1 = require("crypto"); -var NodeCryptography = /** @class */ (function () { - function NodeCryptography() { - } - Object.defineProperty(NodeCryptography.prototype, "algo", { - get: function () { - return 'aes-256-cbc'; - }, - enumerable: false, - configurable: true - }); - NodeCryptography.prototype.encrypt = function (key, input) { - return __awaiter(this, void 0, void 0, function () { - var bKey; - return __generator(this, function (_a) { - bKey = this.getKey(key); - if (input instanceof Buffer) { - return [2 /*return*/, this.encryptBuffer(bKey, input)]; - } - if (input instanceof stream_1.Readable) { - return [2 /*return*/, this.encryptStream(bKey, input)]; - } - if (typeof input === 'string') { - return [2 /*return*/, this.encryptString(bKey, input)]; - } - throw new Error('Unsupported input format'); - }); +const crypto_1 = require("crypto"); +const stream_1 = require("stream"); +const buffer_1 = require("buffer"); +class NodeCryptography { + encrypt(key, input) { + return __awaiter(this, void 0, void 0, function* () { + const bKey = this.getKey(key); + if (input instanceof buffer_1.Buffer) + return this.encryptBuffer(bKey, input); + if (input instanceof stream_1.Readable) + return this.encryptStream(bKey, input); + if (typeof input === 'string') + return this.encryptString(bKey, input); + throw new Error('Encryption error: unsupported input format'); }); - }; - NodeCryptography.prototype.decrypt = function (key, input) { - return __awaiter(this, void 0, void 0, function () { - var bKey; - return __generator(this, function (_a) { - bKey = this.getKey(key); - if (input instanceof Buffer) { - return [2 /*return*/, this.decryptBuffer(bKey, input)]; - } - if (input instanceof stream_1.Readable) { - return [2 /*return*/, this.decryptStream(bKey, input)]; - } - if (typeof input === 'string') { - return [2 /*return*/, this.decryptString(bKey, input)]; - } - throw new Error('Unsupported input format'); - }); + } + encryptBuffer(key, buffer) { + const bIv = this.getIv(); + const aes = (0, crypto_1.createCipheriv)(this.algo, key, bIv); + return buffer_1.Buffer.concat([bIv, aes.update(buffer), aes.final()]); + } + encryptStream(key, stream) { + return __awaiter(this, void 0, void 0, function* () { + const bIv = this.getIv(); + const aes = (0, crypto_1.createCipheriv)(this.algo, key, bIv).setAutoPadding(true); + let initiated = false; + return stream.pipe(aes).pipe(new stream_1.Transform({ + transform(chunk, _, cb) { + if (!initiated) { + initiated = true; + this.push(buffer_1.Buffer.concat([bIv, chunk])); + } + else + this.push(chunk); + cb(); + }, + })); }); - }; - NodeCryptography.prototype.encryptFile = function (key, file, File) { - return __awaiter(this, void 0, void 0, function () { - var bKey, _a, _b, _c, _d; - var _e, _f; - return __generator(this, function (_g) { - switch (_g.label) { - case 0: - bKey = this.getKey(key); - if (!(file.data instanceof Buffer)) return [3 /*break*/, 2]; - if (file.data.byteLength <= 0) - throw new Error('encryption error. empty content'); - _b = (_a = File).create; - _e = { - name: file.name, - mimeType: 'application/octet-stream' - }; - return [4 /*yield*/, this.encryptBuffer(bKey, file.data)]; - case 1: return [2 /*return*/, _b.apply(_a, [(_e.data = _g.sent(), - _e)])]; - case 2: - if (!(file.data instanceof stream_1.Readable)) return [3 /*break*/, 4]; - if (file.contentLength === 0) - throw new Error('encryption error. empty content'); - _d = (_c = File).create; - _f = { - name: file.name, - mimeType: 'application/octet-stream' - }; - return [4 /*yield*/, this.encryptStream(bKey, file.data)]; - case 3: return [2 /*return*/, _d.apply(_c, [(_f.stream = _g.sent(), - _f)])]; - case 4: throw new Error('Cannot encrypt this file. In Node.js file encryption supports only string, Buffer or Stream.'); - } - }); + } + encryptString(key, text) { + const bIv = this.getIv(); + const bPlaintext = buffer_1.Buffer.from(text); + const aes = (0, crypto_1.createCipheriv)(this.algo, key, bIv); + return buffer_1.Buffer.concat([bIv, aes.update(bPlaintext), aes.final()]).toString('utf8'); + } + encryptFile(key, file, File) { + return __awaiter(this, void 0, void 0, function* () { + const bKey = this.getKey(key); + if (file.data instanceof buffer_1.Buffer) { + if (file.data.byteLength <= 0) + throw new Error('Encryption error: empty content.'); + return File.create({ + name: file.name, + mimeType: file.mimeType, + data: this.encryptBuffer(bKey, file.data), + }); + } + if (file.data instanceof stream_1.Readable) { + if (!file.contentLength || file.contentLength === 0) + throw new Error('Encryption error: empty content.'); + return File.create({ + name: file.name, + mimeType: file.mimeType, + stream: yield this.encryptStream(bKey, file.data), + }); + } + throw new Error('Cannot encrypt this file. In Node.js file encryption supports only string, Buffer or Stream.'); }); - }; - NodeCryptography.prototype.decryptFile = function (key, file, File) { - return __awaiter(this, void 0, void 0, function () { - var bKey, _a, _b, _c, _d; - var _e, _f; - return __generator(this, function (_g) { - switch (_g.label) { - case 0: - bKey = this.getKey(key); - if (!(file.data instanceof Buffer)) return [3 /*break*/, 2]; - _b = (_a = File).create; - _e = { - name: file.name - }; - return [4 /*yield*/, this.decryptBuffer(bKey, file.data)]; - case 1: return [2 /*return*/, _b.apply(_a, [(_e.data = _g.sent(), - _e)])]; - case 2: - if (!(file.data instanceof stream_1.Readable)) return [3 /*break*/, 4]; - _d = (_c = File).create; - _f = { - name: file.name - }; - return [4 /*yield*/, this.decryptStream(bKey, file.data)]; - case 3: return [2 /*return*/, _d.apply(_c, [(_f.stream = _g.sent(), - _f)])]; - case 4: throw new Error('Cannot decrypt this file. In Node.js file decryption supports only string, Buffer or Stream.'); - } - }); + } + decrypt(key, input) { + return __awaiter(this, void 0, void 0, function* () { + const bKey = this.getKey(key); + if (input instanceof ArrayBuffer) { + const decryptedBuffer = this.decryptBuffer(bKey, buffer_1.Buffer.from(input)); + return decryptedBuffer.buffer.slice(decryptedBuffer.byteOffset, decryptedBuffer.byteOffset + decryptedBuffer.length); + } + if (input instanceof buffer_1.Buffer) + return this.decryptBuffer(bKey, input); + if (input instanceof stream_1.Readable) + return this.decryptStream(bKey, input); + if (typeof input === 'string') + return this.decryptString(bKey, input); + throw new Error('Decryption error: unsupported input format'); }); - }; - NodeCryptography.prototype.getKey = function (key) { - var sha = (0, crypto_1.createHash)('sha256'); - sha.update(Buffer.from(key, 'utf8')); - return Buffer.from(sha.digest('hex').slice(0, 32), 'utf8'); - }; - NodeCryptography.prototype.getIv = function () { - return (0, crypto_1.randomBytes)(NodeCryptography.IV_LENGTH); - }; - NodeCryptography.prototype.encryptString = function (key, plaintext) { - var bIv = this.getIv(); - var bPlaintext = Buffer.from(plaintext); - var aes = (0, crypto_1.createCipheriv)(this.algo, key, bIv); - return Buffer.concat([bIv, aes.update(bPlaintext), aes.final()]).toString('utf8'); - }; - NodeCryptography.prototype.decryptString = function (key, sCiphertext) { - var ciphertext = Buffer.from(sCiphertext); - var bIv = ciphertext.slice(0, NodeCryptography.IV_LENGTH); - var bCiphertext = ciphertext.slice(NodeCryptography.IV_LENGTH); - var aes = (0, crypto_1.createDecipheriv)(this.algo, key, bIv); - return Buffer.concat([aes.update(bCiphertext), aes.final()]).toString('utf8'); - }; - NodeCryptography.prototype.encryptBuffer = function (key, plaintext) { - var bIv = this.getIv(); - var aes = (0, crypto_1.createCipheriv)(this.algo, key, bIv); - return Buffer.concat([bIv, aes.update(plaintext), aes.final()]); - }; - NodeCryptography.prototype.decryptBuffer = function (key, ciphertext) { - var bIv = ciphertext.slice(0, NodeCryptography.IV_LENGTH); - var bCiphertext = ciphertext.slice(NodeCryptography.IV_LENGTH); + } + decryptBuffer(key, buffer) { + const bIv = buffer.slice(0, NodeCryptography.IV_LENGTH); + const bCiphertext = buffer.slice(NodeCryptography.IV_LENGTH); if (bCiphertext.byteLength <= 0) - throw new Error('decryption error: empty content'); - var aes = (0, crypto_1.createDecipheriv)(this.algo, key, bIv); - return Buffer.concat([aes.update(bCiphertext), aes.final()]); - }; - NodeCryptography.prototype.encryptStream = function (key, stream) { - return __awaiter(this, void 0, void 0, function () { - var bIv, aes, inited; - return __generator(this, function (_a) { - bIv = this.getIv(); - aes = (0, crypto_1.createCipheriv)('aes-256-cbc', key, bIv).setAutoPadding(true); - inited = false; - return [2 /*return*/, stream.pipe(aes).pipe(new stream_1.Transform({ - transform: function (chunk, _, cb) { - if (!inited) { - inited = true; - this.push(Buffer.concat([bIv, chunk])); - } - else { - this.push(chunk); - } - cb(); - }, - }))]; - }); - }); - }; - NodeCryptography.prototype.decryptStream = function (key, stream) { - var _this = this; - var output = new stream_1.PassThrough(); - var bIv = Buffer.alloc(0); - var aes = null; - var getIv = function () { - var data = stream.read(); + throw new Error('Decryption error: empty content'); + const aes = (0, crypto_1.createDecipheriv)(this.algo, key, bIv); + return buffer_1.Buffer.concat([aes.update(bCiphertext), aes.final()]); + } + decryptStream(key, stream) { + let aes = null; + const output = new stream_1.PassThrough(); + let bIv = buffer_1.Buffer.alloc(0); + const getIv = () => { + let data = stream.read(); while (data !== null) { if (data) { - var bChunk = Buffer.from(data); - var sliceLen = NodeCryptography.IV_LENGTH - bIv.byteLength; - if (bChunk.byteLength < sliceLen) { - bIv = Buffer.concat([bIv, bChunk]); - } + const bChunk = buffer_1.Buffer.from(data); + const sliceLen = NodeCryptography.IV_LENGTH - bIv.byteLength; + if (bChunk.byteLength < sliceLen) + bIv = buffer_1.Buffer.concat([bIv, bChunk]); else { - bIv = Buffer.concat([bIv, bChunk.slice(0, sliceLen)]); - aes = (0, crypto_1.createDecipheriv)(_this.algo, key, bIv); + bIv = buffer_1.Buffer.concat([bIv, bChunk.slice(0, sliceLen)]); + aes = (0, crypto_1.createDecipheriv)(this.algo, key, bIv); aes.pipe(output); aes.write(bChunk.slice(sliceLen)); } @@ -232,15 +125,51 @@ var NodeCryptography = /** @class */ (function () { } }; stream.on('readable', getIv); - stream.on('end', function () { - if (aes) { + stream.on('end', () => { + if (aes) aes.end(); - } output.end(); }); return output; - }; - NodeCryptography.IV_LENGTH = 16; - return NodeCryptography; -}()); + } + decryptString(key, text) { + const ciphertext = buffer_1.Buffer.from(text); + const bIv = ciphertext.slice(0, NodeCryptography.IV_LENGTH); + const bCiphertext = ciphertext.slice(NodeCryptography.IV_LENGTH); + const aes = (0, crypto_1.createDecipheriv)(this.algo, key, bIv); + return buffer_1.Buffer.concat([aes.update(bCiphertext), aes.final()]).toString('utf8'); + } + decryptFile(key, file, File) { + return __awaiter(this, void 0, void 0, function* () { + const bKey = this.getKey(key); + if (file.data instanceof buffer_1.Buffer) { + return File.create({ + name: file.name, + mimeType: file.mimeType, + data: this.decryptBuffer(bKey, file.data), + }); + } + if (file.data instanceof stream_1.Readable) { + return File.create({ + name: file.name, + mimeType: file.mimeType, + stream: this.decryptStream(bKey, file.data), + }); + } + throw new Error('Cannot decrypt this file. In Node.js file decryption supports only string, Buffer or Stream.'); + }); + } + get algo() { + return 'aes-256-cbc'; + } + getKey(key) { + const sha = (0, crypto_1.createHash)('sha256'); + sha.update(buffer_1.Buffer.from(key, 'utf8')); + return buffer_1.Buffer.from(sha.digest('hex').slice(0, 32), 'utf8'); + } + getIv() { + return (0, crypto_1.randomBytes)(NodeCryptography.IV_LENGTH); + } +} +NodeCryptography.IV_LENGTH = 16; exports.default = NodeCryptography; diff --git a/lib/crypto/modules/web.js b/lib/crypto/modules/web.js deleted file mode 100644 index b7bb887ea..000000000 --- a/lib/crypto/modules/web.js +++ /dev/null @@ -1,230 +0,0 @@ -"use strict"; -/* global crypto */ -var __awaiter = (this && this.__awaiter) || function (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()); - }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "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 (_) 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 }; - } -}; -Object.defineProperty(exports, "__esModule", { value: true }); -function concatArrayBuffer(ab1, ab2) { - var tmp = new Uint8Array(ab1.byteLength + ab2.byteLength); - tmp.set(new Uint8Array(ab1), 0); - tmp.set(new Uint8Array(ab2), ab1.byteLength); - return tmp.buffer; -} -var WebCryptography = /** @class */ (function () { - function WebCryptography() { - } - Object.defineProperty(WebCryptography.prototype, "algo", { - get: function () { - return 'aes-256-cbc'; - }, - enumerable: false, - configurable: true - }); - WebCryptography.prototype.encrypt = function (key, input) { - return __awaiter(this, void 0, void 0, function () { - var cKey; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: return [4 /*yield*/, this.getKey(key)]; - case 1: - cKey = _a.sent(); - if (input instanceof ArrayBuffer) { - return [2 /*return*/, this.encryptArrayBuffer(cKey, input)]; - } - if (typeof input === 'string') { - return [2 /*return*/, this.encryptString(cKey, input)]; - } - throw new Error('Cannot encrypt this file. In browsers file encryption supports only string or ArrayBuffer'); - } - }); - }); - }; - WebCryptography.prototype.decrypt = function (key, input) { - return __awaiter(this, void 0, void 0, function () { - var cKey; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: return [4 /*yield*/, this.getKey(key)]; - case 1: - cKey = _a.sent(); - if (input instanceof ArrayBuffer) { - return [2 /*return*/, this.decryptArrayBuffer(cKey, input)]; - } - if (typeof input === 'string') { - return [2 /*return*/, this.decryptString(cKey, input)]; - } - throw new Error('Cannot decrypt this file. In browsers file decryption supports only string or ArrayBuffer'); - } - }); - }); - }; - WebCryptography.prototype.encryptFile = function (key, file, File) { - return __awaiter(this, void 0, void 0, function () { - var bKey, abPlaindata, abCipherdata; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - if (file.data.byteLength <= 0) - throw new Error('encryption error. empty content'); - return [4 /*yield*/, this.getKey(key)]; - case 1: - bKey = _a.sent(); - return [4 /*yield*/, file.data.arrayBuffer()]; - case 2: - abPlaindata = _a.sent(); - return [4 /*yield*/, this.encryptArrayBuffer(bKey, abPlaindata)]; - case 3: - abCipherdata = _a.sent(); - return [2 /*return*/, File.create({ - name: file.name, - mimeType: 'application/octet-stream', - data: abCipherdata, - })]; - } - }); - }); - }; - WebCryptography.prototype.decryptFile = function (key, file, File) { - return __awaiter(this, void 0, void 0, function () { - var bKey, abCipherdata, abPlaindata; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: return [4 /*yield*/, this.getKey(key)]; - case 1: - bKey = _a.sent(); - return [4 /*yield*/, file.data.arrayBuffer()]; - case 2: - abCipherdata = _a.sent(); - return [4 /*yield*/, this.decryptArrayBuffer(bKey, abCipherdata)]; - case 3: - abPlaindata = _a.sent(); - return [2 /*return*/, File.create({ - name: file.name, - data: abPlaindata, - })]; - } - }); - }); - }; - WebCryptography.prototype.getKey = function (key) { - return __awaiter(this, void 0, void 0, function () { - var digest, hashHex, abKey; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: return [4 /*yield*/, crypto.subtle.digest('SHA-256', WebCryptography.encoder.encode(key))]; - case 1: - digest = _a.sent(); - hashHex = Array.from(new Uint8Array(digest)) - .map(function (b) { return b.toString(16).padStart(2, '0'); }) - .join(''); - abKey = WebCryptography.encoder.encode(hashHex.slice(0, 32)).buffer; - return [2 /*return*/, crypto.subtle.importKey('raw', abKey, 'AES-CBC', true, ['encrypt', 'decrypt'])]; - } - }); - }); - }; - WebCryptography.prototype.encryptArrayBuffer = function (key, plaintext) { - return __awaiter(this, void 0, void 0, function () { - var abIv, _a, _b; - return __generator(this, function (_c) { - switch (_c.label) { - case 0: - abIv = crypto.getRandomValues(new Uint8Array(16)); - _a = concatArrayBuffer; - _b = [abIv.buffer]; - return [4 /*yield*/, crypto.subtle.encrypt({ name: 'AES-CBC', iv: abIv }, key, plaintext)]; - case 1: return [2 /*return*/, _a.apply(void 0, _b.concat([_c.sent()]))]; - } - }); - }); - }; - WebCryptography.prototype.decryptArrayBuffer = function (key, ciphertext) { - return __awaiter(this, void 0, void 0, function () { - var abIv, data; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - abIv = ciphertext.slice(0, 16); - if (ciphertext.slice(WebCryptography.IV_LENGTH).byteLength <= 0) - throw new Error('decryption error: empty content'); - return [4 /*yield*/, crypto.subtle.decrypt({ name: 'AES-CBC', iv: abIv }, key, ciphertext.slice(WebCryptography.IV_LENGTH))]; - case 1: - data = _a.sent(); - return [2 /*return*/, data]; - } - }); - }); - }; - WebCryptography.prototype.encryptString = function (key, plaintext) { - return __awaiter(this, void 0, void 0, function () { - var abIv, abPlaintext, abPayload, ciphertext; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - abIv = crypto.getRandomValues(new Uint8Array(16)); - abPlaintext = WebCryptography.encoder.encode(plaintext).buffer; - return [4 /*yield*/, crypto.subtle.encrypt({ name: 'AES-CBC', iv: abIv }, key, abPlaintext)]; - case 1: - abPayload = _a.sent(); - ciphertext = concatArrayBuffer(abIv.buffer, abPayload); - return [2 /*return*/, WebCryptography.decoder.decode(ciphertext)]; - } - }); - }); - }; - WebCryptography.prototype.decryptString = function (key, ciphertext) { - return __awaiter(this, void 0, void 0, function () { - var abCiphertext, abIv, abPayload, abPlaintext; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - abCiphertext = WebCryptography.encoder.encode(ciphertext).buffer; - abIv = abCiphertext.slice(0, 16); - abPayload = abCiphertext.slice(16); - return [4 /*yield*/, crypto.subtle.decrypt({ name: 'AES-CBC', iv: abIv }, key, abPayload)]; - case 1: - abPlaintext = _a.sent(); - return [2 /*return*/, WebCryptography.decoder.decode(abPlaintext)]; - } - }); - }); - }; - WebCryptography.IV_LENGTH = 16; - WebCryptography.encoder = new TextEncoder(); - WebCryptography.decoder = new TextDecoder(); - return WebCryptography; -}()); -exports.default = WebCryptography; diff --git a/lib/entities/Channel.js b/lib/entities/Channel.js index 0043f20dc..2aa39e7cf 100644 --- a/lib/entities/Channel.js +++ b/lib/entities/Channel.js @@ -1,22 +1,21 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Channel = void 0; -var Subscription_1 = require("./Subscription"); -var Channel = /** @class */ (function () { - function Channel(channelName, eventEmitter, pubnub) { - this.name = channelName; +const Subscription_1 = require("./Subscription"); +class Channel { + constructor(channelName, eventEmitter, pubnub) { this.eventEmitter = eventEmitter; this.pubnub = pubnub; + this.name = channelName; } - Channel.prototype.subscription = function (subscriptionOptions) { + subscription(subscriptionOptions) { return new Subscription_1.Subscription({ - channels: (subscriptionOptions === null || subscriptionOptions === void 0 ? void 0 : subscriptionOptions.receivePresenceEvents) ? [this.name, "".concat(this.name, "-pnpres")] : [this.name], + channels: (subscriptionOptions === null || subscriptionOptions === void 0 ? void 0 : subscriptionOptions.receivePresenceEvents) ? [this.name, `${this.name}-pnpres`] : [this.name], channelGroups: [], subscriptionOptions: subscriptionOptions, eventEmitter: this.eventEmitter, pubnub: this.pubnub, }); - }; - return Channel; -}()); + } +} exports.Channel = Channel; diff --git a/lib/entities/ChannelGroup.js b/lib/entities/ChannelGroup.js index 07a0bea48..d4de51cac 100644 --- a/lib/entities/ChannelGroup.js +++ b/lib/entities/ChannelGroup.js @@ -1,22 +1,21 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ChannelGroup = void 0; -var Subscription_1 = require("./Subscription"); -var ChannelGroup = /** @class */ (function () { - function ChannelGroup(channelGroup, eventEmitter, pubnub) { - this.name = channelGroup; +const Subscription_1 = require("./Subscription"); +class ChannelGroup { + constructor(channelGroup, eventEmitter, pubnub) { this.eventEmitter = eventEmitter; this.pubnub = pubnub; + this.name = channelGroup; } - ChannelGroup.prototype.subscription = function (subscriptionOptions) { + subscription(subscriptionOptions) { return new Subscription_1.Subscription({ channels: [], - channelGroups: (subscriptionOptions === null || subscriptionOptions === void 0 ? void 0 : subscriptionOptions.receivePresenceEvents) ? [this.name, "".concat(this.name, "-pnpres")] : [this.name], + channelGroups: (subscriptionOptions === null || subscriptionOptions === void 0 ? void 0 : subscriptionOptions.receivePresenceEvents) ? [this.name, `${this.name}-pnpres`] : [this.name], subscriptionOptions: subscriptionOptions, eventEmitter: this.eventEmitter, pubnub: this.pubnub, }); - }; - return ChannelGroup; -}()); + } +} exports.ChannelGroup = ChannelGroup; diff --git a/lib/entities/ChannelMetadata.js b/lib/entities/ChannelMetadata.js index 5345f4ed8..c1d6fe93e 100644 --- a/lib/entities/ChannelMetadata.js +++ b/lib/entities/ChannelMetadata.js @@ -1,14 +1,14 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ChannelMetadata = void 0; -var Subscription_1 = require("./Subscription"); -var ChannelMetadata = /** @class */ (function () { - function ChannelMetadata(id, eventEmitter, pubnub) { +const Subscription_1 = require("./Subscription"); +class ChannelMetadata { + constructor(id, eventEmitter, pubnub) { this.id = id; this.eventEmitter = eventEmitter; this.pubnub = pubnub; } - ChannelMetadata.prototype.subscription = function (subscriptionOptions) { + subscription(subscriptionOptions) { return new Subscription_1.Subscription({ channels: [this.id], channelGroups: [], @@ -16,7 +16,6 @@ var ChannelMetadata = /** @class */ (function () { eventEmitter: this.eventEmitter, pubnub: this.pubnub, }); - }; - return ChannelMetadata; -}()); + } +} exports.ChannelMetadata = ChannelMetadata; diff --git a/lib/entities/SubscribeCapable.js b/lib/entities/SubscribeCapable.js index 554527544..3a037f788 100644 --- a/lib/entities/SubscribeCapable.js +++ b/lib/entities/SubscribeCapable.js @@ -1,92 +1,46 @@ "use strict"; -var __assign = (this && this.__assign) || function () { - __assign = Object.assign || function(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); -}; Object.defineProperty(exports, "__esModule", { value: true }); exports.SubscribeCapable = void 0; -var SubscribeCapable = /** @class */ (function () { - function SubscribeCapable() { - } - SubscribeCapable.prototype.subscribe = function () { +class SubscribeCapable { + subscribe() { var _a, _b; - this.pubnub.subscribe(__assign({ channels: this.channelNames, channelGroups: this.groupNames }, (((_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.cursor) === null || _b === void 0 ? void 0 : _b.timetoken) && { timetoken: this.options.cursor.timetoken }))); - }; - SubscribeCapable.prototype.unsubscribe = function () { + this.pubnub.subscribe(Object.assign({ channels: this.channelNames, channelGroups: this.groupNames }, (((_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.cursor) === null || _b === void 0 ? void 0 : _b.timetoken) && { timetoken: this.options.cursor.timetoken }))); + } + unsubscribe() { this.pubnub.unsubscribe({ - channels: this.channelNames.filter(function (c) { return !c.endsWith('-pnpres'); }), - channelGroups: this.groupNames.filter(function (cg) { return !cg.endsWith('-pnpres'); }), + channels: this.channelNames.filter((c) => !c.endsWith('-pnpres')), + channelGroups: this.groupNames.filter((cg) => !cg.endsWith('-pnpres')), }); - }; - Object.defineProperty(SubscribeCapable.prototype, "onMessage", { - set: function (onMessagelistener) { - this.listener.message = onMessagelistener; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(SubscribeCapable.prototype, "onPresence", { - set: function (onPresencelistener) { - this.listener.presence = onPresencelistener; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(SubscribeCapable.prototype, "onSignal", { - set: function (onSignalListener) { - this.listener.signal = onSignalListener; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(SubscribeCapable.prototype, "onObjects", { - set: function (onObjectsListener) { - this.listener.objects = onObjectsListener; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(SubscribeCapable.prototype, "onMessageAction", { - set: function (messageActionEventListener) { - this.listener.messageAction = messageActionEventListener; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(SubscribeCapable.prototype, "onFile", { - set: function (fileEventListener) { - this.listener.file = fileEventListener; - }, - enumerable: false, - configurable: true - }); - SubscribeCapable.prototype.addListener = function (listener) { - this.eventEmitter.addListener(listener, this.channelNames.filter(function (c) { return !c.endsWith('-pnpres'); }), this.groupNames.filter(function (cg) { return !cg.endsWith('-pnpres'); })); - }; - SubscribeCapable.prototype.removeListener = function (listener) { + } + set onMessage(onMessageListener) { + this.listener.message = onMessageListener; + } + set onPresence(onPresenceListener) { + this.listener.presence = onPresenceListener; + } + set onSignal(onSignalListener) { + this.listener.signal = onSignalListener; + } + set onObjects(onObjectsListener) { + this.listener.objects = onObjectsListener; + } + set onMessageAction(messageActionEventListener) { + this.listener.messageAction = messageActionEventListener; + } + set onFile(fileEventListener) { + this.listener.file = fileEventListener; + } + addListener(listener) { + this.eventEmitter.addListener(listener, this.channelNames.filter((c) => !c.endsWith('-pnpres')), this.groupNames.filter((cg) => !cg.endsWith('-pnpres'))); + } + removeListener(listener) { this.eventEmitter.removeListener(listener, this.channelNames, this.groupNames); - }; - Object.defineProperty(SubscribeCapable.prototype, "channels", { - get: function () { - return this.channelNames.slice(0); - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(SubscribeCapable.prototype, "channelGroups", { - get: function () { - return this.groupNames.slice(0); - }, - enumerable: false, - configurable: true - }); - return SubscribeCapable; -}()); + } + get channels() { + return this.channelNames.slice(0); + } + get channelGroups() { + return this.groupNames.slice(0); + } +} exports.SubscribeCapable = SubscribeCapable; diff --git a/lib/entities/Subscription.js b/lib/entities/Subscription.js index 586f8d3c3..e2aa6e8ba 100644 --- a/lib/entities/Subscription.js +++ b/lib/entities/Subscription.js @@ -1,84 +1,29 @@ "use strict"; -var __extends = (this && this.__extends) || (function () { - 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); - }; - return function (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 = (this && this.__assign) || function () { - __assign = Object.assign || function(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); -}; -var __read = (this && this.__read) || function (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; -}; -var __spreadArray = (this && this.__spreadArray) || function (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)); -}; Object.defineProperty(exports, "__esModule", { value: true }); exports.Subscription = void 0; -var SubscriptionSet_1 = require("./SubscriptionSet"); -var SubscribeCapable_1 = require("./SubscribeCapable"); -var Subscription = /** @class */ (function (_super) { - __extends(Subscription, _super); - function Subscription(_a) { - var channels = _a.channels, channelGroups = _a.channelGroups, subscriptionOptions = _a.subscriptionOptions, eventEmitter = _a.eventEmitter, pubnub = _a.pubnub; - var _this = _super.call(this) || this; - _this.channelNames = []; - _this.groupNames = []; - _this.channelNames = channels; - _this.groupNames = channelGroups; - _this.options = subscriptionOptions; - _this.pubnub = pubnub; - _this.eventEmitter = eventEmitter; - _this.listener = {}; - eventEmitter.addListener(_this.listener, _this.channelNames.filter(function (c) { return !c.endsWith('-pnpres'); }), _this.groupNames.filter(function (cg) { return !cg.endsWith('-pnpres'); })); - return _this; +const SubscribeCapable_1 = require("./SubscribeCapable"); +const SubscriptionSet_1 = require("./SubscriptionSet"); +class Subscription extends SubscribeCapable_1.SubscribeCapable { + constructor({ channels, channelGroups, subscriptionOptions, eventEmitter, pubnub, }) { + super(); + this.channelNames = []; + this.groupNames = []; + this.channelNames = channels; + this.groupNames = channelGroups; + this.options = subscriptionOptions; + this.pubnub = pubnub; + this.eventEmitter = eventEmitter; + this.listener = {}; + eventEmitter.addListener(this.listener, this.channelNames.filter((c) => !c.endsWith('-pnpres')), this.groupNames.filter((cg) => !cg.endsWith('-pnpres'))); } - Subscription.prototype.addSubscription = function (subscription) { + addSubscription(subscription) { return new SubscriptionSet_1.SubscriptionSet({ - channels: __spreadArray(__spreadArray([], __read(this.channelNames), false), __read(subscription.channels), false), - channelGroups: __spreadArray(__spreadArray([], __read(this.groupNames), false), __read(subscription.channelGroups), false), - subscriptionOptions: __assign(__assign({}, this.options), subscription === null || subscription === void 0 ? void 0 : subscription.options), + channels: [...this.channelNames, ...subscription.channels], + channelGroups: [...this.groupNames, ...subscription.channelGroups], + subscriptionOptions: Object.assign(Object.assign({}, this.options), subscription === null || subscription === void 0 ? void 0 : subscription.options), eventEmitter: this.eventEmitter, pubnub: this.pubnub, }); - }; - return Subscription; -}(SubscribeCapable_1.SubscribeCapable)); + } +} exports.Subscription = Subscription; diff --git a/lib/entities/SubscriptionSet.js b/lib/entities/SubscriptionSet.js index 590de45e0..46f048685 100644 --- a/lib/entities/SubscriptionSet.js +++ b/lib/entities/SubscriptionSet.js @@ -1,111 +1,63 @@ "use strict"; -var __extends = (this && this.__extends) || (function () { - 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); - }; - return function (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 __read = (this && this.__read) || function (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; -}; -var __spreadArray = (this && this.__spreadArray) || function (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)); -}; Object.defineProperty(exports, "__esModule", { value: true }); exports.SubscriptionSet = void 0; -var SubscribeCapable_1 = require("./SubscribeCapable"); -var SubscriptionSet = /** @class */ (function (_super) { - __extends(SubscriptionSet, _super); - function SubscriptionSet(_a) { - var _b = _a.channels, channels = _b === void 0 ? [] : _b, _c = _a.channelGroups, channelGroups = _c === void 0 ? [] : _c, subscriptionOptions = _a.subscriptionOptions, eventEmitter = _a.eventEmitter, pubnub = _a.pubnub; - var _this = _super.call(this) || this; - _this.channelNames = []; - _this.groupNames = []; - _this.subscriptionList = []; - _this.options = subscriptionOptions; - _this.eventEmitter = eventEmitter; - _this.pubnub = pubnub; +const SubscribeCapable_1 = require("./SubscribeCapable"); +class SubscriptionSet extends SubscribeCapable_1.SubscribeCapable { + constructor({ channels = [], channelGroups = [], subscriptionOptions, eventEmitter, pubnub, }) { + super(); + this.channelNames = []; + this.groupNames = []; + this.subscriptionList = []; + this.options = subscriptionOptions; + this.eventEmitter = eventEmitter; + this.pubnub = pubnub; channels - .filter(function (c) { return !c.endsWith('-pnpres'); }) - .forEach(function (c) { - var subscription = _this.pubnub.channel(c).subscription(_this.options); - _this.channelNames = __spreadArray(__spreadArray([], __read(_this.channelNames), false), __read(subscription.channels), false); - _this.subscriptionList.push(subscription); + .filter((c) => !c.endsWith('-pnpres')) + .forEach((c) => { + const subscription = this.pubnub.channel(c).subscription(this.options); + this.channelNames = [...this.channelNames, ...subscription.channels]; + this.subscriptionList.push(subscription); }); channelGroups - .filter(function (cg) { return !cg.endsWith('-pnpres'); }) - .forEach(function (cg) { - var subscription = _this.pubnub.channelGroup(cg).subscription(_this.options); - _this.groupNames = __spreadArray(__spreadArray([], __read(_this.groupNames), false), __read(subscription.channelGroups), false); - _this.subscriptionList.push(subscription); + .filter((cg) => !cg.endsWith('-pnpres')) + .forEach((cg) => { + const subscription = this.pubnub.channelGroup(cg).subscription(this.options); + this.groupNames = [...this.groupNames, ...subscription.channelGroups]; + this.subscriptionList.push(subscription); }); - _this.listener = {}; - eventEmitter.addListener(_this.listener, _this.channelNames.filter(function (c) { return !c.endsWith('-pnpres'); }), _this.groupNames.filter(function (cg) { return !cg.endsWith('-pnpres'); })); - return _this; + this.listener = {}; + eventEmitter.addListener(this.listener, this.channelNames.filter((c) => !c.endsWith('-pnpres')), this.groupNames.filter((cg) => !cg.endsWith('-pnpres'))); } - SubscriptionSet.prototype.addSubscription = function (subscription) { + addSubscription(subscription) { this.subscriptionList.push(subscription); - this.channelNames = __spreadArray(__spreadArray([], __read(this.channelNames), false), __read(subscription.channels), false); - this.groupNames = __spreadArray(__spreadArray([], __read(this.groupNames), false), __read(subscription.channelGroups), false); + this.channelNames = [...this.channelNames, ...subscription.channels]; + this.groupNames = [...this.groupNames, ...subscription.channelGroups]; this.eventEmitter.addListener(this.listener, subscription.channels, subscription.channelGroups); - }; - SubscriptionSet.prototype.removeSubscription = function (subscription) { - var channelsToRemove = subscription.channels; - var groupsToRemove = subscription.channelGroups; - this.channelNames = this.channelNames.filter(function (c) { return !channelsToRemove.includes(c); }); - this.groupNames = this.groupNames.filter(function (cg) { return !groupsToRemove.includes(cg); }); - this.subscriptionList = this.subscriptionList.filter(function (s) { return s !== subscription; }); + } + removeSubscription(subscription) { + const channelsToRemove = subscription.channels; + const groupsToRemove = subscription.channelGroups; + this.channelNames = this.channelNames.filter((c) => !channelsToRemove.includes(c)); + this.groupNames = this.groupNames.filter((cg) => !groupsToRemove.includes(cg)); + this.subscriptionList = this.subscriptionList.filter((s) => s !== subscription); this.eventEmitter.removeListener(this.listener, channelsToRemove, groupsToRemove); - }; - SubscriptionSet.prototype.addSubscriptionSet = function (subscriptionSet) { - this.subscriptionList = __spreadArray(__spreadArray([], __read(this.subscriptionList), false), __read(subscriptionSet.subscriptions), false); - this.channelNames = __spreadArray(__spreadArray([], __read(this.channelNames), false), __read(subscriptionSet.channels), false); - this.groupNames = __spreadArray(__spreadArray([], __read(this.groupNames), false), __read(subscriptionSet.channelGroups), false); + } + addSubscriptionSet(subscriptionSet) { + this.subscriptionList = [...this.subscriptionList, ...subscriptionSet.subscriptions]; + this.channelNames = [...this.channelNames, ...subscriptionSet.channels]; + this.groupNames = [...this.groupNames, ...subscriptionSet.channelGroups]; this.eventEmitter.addListener(this.listener, subscriptionSet.channels, subscriptionSet.channelGroups); - }; - SubscriptionSet.prototype.removeSubscriptionSet = function (subscriptionSet) { - var channelsToRemove = subscriptionSet.channels; - var groupsToRemove = subscriptionSet.channelGroups; - this.channelNames = this.channelNames.filter(function (c) { return !channelsToRemove.includes(c); }); - this.groupNames = this.groupNames.filter(function (cg) { return !groupsToRemove.includes(cg); }); - this.subscriptionList = this.subscriptionList.filter(function (s) { return !subscriptionSet.subscriptions.includes(s); }); + } + removeSubscriptionSet(subscriptionSet) { + const channelsToRemove = subscriptionSet.channels; + const groupsToRemove = subscriptionSet.channelGroups; + this.channelNames = this.channelNames.filter((c) => !channelsToRemove.includes(c)); + this.groupNames = this.groupNames.filter((cg) => !groupsToRemove.includes(cg)); + this.subscriptionList = this.subscriptionList.filter((s) => !subscriptionSet.subscriptions.includes(s)); this.eventEmitter.removeListener(this.listener, channelsToRemove, groupsToRemove); - }; - Object.defineProperty(SubscriptionSet.prototype, "subscriptions", { - get: function () { - return this.subscriptionList.slice(0); - }, - enumerable: false, - configurable: true - }); - return SubscriptionSet; -}(SubscribeCapable_1.SubscribeCapable)); + } + get subscriptions() { + return this.subscriptionList.slice(0); + } +} exports.SubscriptionSet = SubscriptionSet; diff --git a/lib/entities/UserMetadata.js b/lib/entities/UserMetadata.js index 8989b01f3..d7c03f5f1 100644 --- a/lib/entities/UserMetadata.js +++ b/lib/entities/UserMetadata.js @@ -1,14 +1,14 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.UserMetadata = void 0; -var Subscription_1 = require("./Subscription"); -var UserMetadata = /** @class */ (function () { - function UserMetadata(id, eventEmitter, pubnub) { +const Subscription_1 = require("./Subscription"); +class UserMetadata { + constructor(id, eventEmitter, pubnub) { this.id = id; this.eventEmitter = eventEmitter; this.pubnub = pubnub; } - UserMetadata.prototype.subscription = function (subscriptionOptions) { + subscription(subscriptionOptions) { return new Subscription_1.Subscription({ channels: [this.id], channelGroups: [], @@ -16,7 +16,6 @@ var UserMetadata = /** @class */ (function () { eventEmitter: this.eventEmitter, pubnub: this.pubnub, }); - }; - return UserMetadata; -}()); + } +} exports.UserMetadata = UserMetadata; diff --git a/lib/errors/pubnub-api-error.js b/lib/errors/pubnub-api-error.js new file mode 100644 index 000000000..193fd3562 --- /dev/null +++ b/lib/errors/pubnub-api-error.js @@ -0,0 +1,140 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.PubNubAPIError = void 0; +const categories_1 = __importDefault(require("../core/constants/categories")); +const pubnub_error_1 = require("./pubnub-error"); +class PubNubAPIError extends Error { + static create(errorOrResponse, data) { + if (errorOrResponse instanceof Error) + return PubNubAPIError.createFromError(errorOrResponse); + else + return PubNubAPIError.createFromServiceResponse(errorOrResponse, data); + } + static createFromError(error) { + let category = categories_1.default.PNUnknownCategory; + let message = 'Unknown error'; + let errorName = 'Error'; + if (!error) + return new PubNubAPIError(message, category, 0); + else if (error instanceof PubNubAPIError) + return error; + if (error instanceof Error) { + message = error.message; + errorName = error.name; + } + if (errorName === 'AbortError' || message.indexOf('Aborted') !== -1) { + category = categories_1.default.PNCancelledCategory; + message = 'Request cancelled'; + } + else if (message.indexOf('timeout') !== -1) { + category = categories_1.default.PNTimeoutCategory; + message = 'Request timeout'; + } + else if (message.indexOf('network') !== -1) { + category = categories_1.default.PNNetworkIssuesCategory; + message = 'Network issues'; + } + else if (errorName === 'TypeError') { + category = categories_1.default.PNBadRequestCategory; + } + else if (errorName === 'FetchError') { + const errorCode = error.code; + if (['ECONNREFUSED', 'ENETUNREACH', 'ENOTFOUND', 'ECONNRESET', 'EAI_AGAIN'].includes(errorCode)) + category = categories_1.default.PNNetworkIssuesCategory; + if (errorCode === 'ECONNREFUSED') + message = 'Connection refused'; + else if (errorCode === 'ENETUNREACH') + message = 'Network not reachable'; + else if (errorCode === 'ENOTFOUND') + message = 'Server not found'; + else if (errorCode === 'ECONNRESET') + message = 'Connection reset by peer'; + else if (errorCode === 'EAI_AGAIN') + message = 'Name resolution error'; + else if (errorCode === 'ETIMEDOUT') { + category = categories_1.default.PNTimeoutCategory; + message = 'Request timeout'; + } + else + message = `Unknown system error: ${error}`; + } + else if (message === 'Request timeout') + category = categories_1.default.PNTimeoutCategory; + return new PubNubAPIError(message, category, 0, error); + } + static createFromServiceResponse(response, data) { + let category = categories_1.default.PNUnknownCategory; + let errorData; + let message = 'Unknown error'; + let { status } = response; + data !== null && data !== void 0 ? data : (data = response.body); + if (status === 402) + message = 'Not available for used key set. Contact support@pubnub.com'; + else if (status === 400) { + category = categories_1.default.PNBadRequestCategory; + message = 'Bad request'; + } + else if (status === 403) { + category = categories_1.default.PNAccessDeniedCategory; + message = 'Access denied'; + } + if (data && data.byteLength > 0) { + const decoded = new TextDecoder().decode(data); + if (response.headers['content-type'].indexOf('text/javascript') !== -1 || + response.headers['content-type'].indexOf('application/json') !== -1) { + try { + const errorResponse = JSON.parse(decoded); + if (typeof errorResponse === 'object' && !Array.isArray(errorResponse)) { + if ('error' in errorResponse && + (errorResponse.error === 1 || errorResponse.error === true) && + 'status' in errorResponse && + typeof errorResponse.status === 'number' && + 'message' in errorResponse && + 'service' in errorResponse) { + errorData = errorResponse; + status = errorResponse.status; + } + else + errorData = errorResponse; + if ('error' in errorResponse && errorResponse.error instanceof Error) + errorData = errorResponse.error; + } + } + catch (_) { + errorData = decoded; + } + } + else if (response.headers['content-type'].indexOf('xml') !== -1) { + const reason = /(.*)<\/Message>/gi.exec(decoded); + message = reason ? `Upload to bucket failed: ${reason[1]}` : 'Upload to bucket failed.'; + } + else { + errorData = decoded; + } + } + return new PubNubAPIError(message, category, status, errorData); + } + constructor(message, category, statusCode, errorData) { + super(message); + this.category = category; + this.statusCode = statusCode; + this.errorData = errorData; + this.name = 'PubNubAPIError'; + } + toStatus(operation) { + return { + error: true, + category: this.category, + operation, + statusCode: this.statusCode, + errorData: this.errorData, + }; + } + toPubNubError(operation, message) { + return new pubnub_error_1.PubNubError(message !== null && message !== void 0 ? message : this.message, this.toStatus(operation)); + } +} +exports.PubNubAPIError = PubNubAPIError; diff --git a/lib/errors/pubnub-error.js b/lib/errors/pubnub-error.js new file mode 100644 index 000000000..40c24f8df --- /dev/null +++ b/lib/errors/pubnub-error.js @@ -0,0 +1,26 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.createValidationError = exports.PubNubError = void 0; +const categories_1 = __importDefault(require("../core/constants/categories")); +class PubNubError extends Error { + constructor(message, status) { + super(message); + this.status = status; + this.name = 'PubNubError'; + this.message = message; + Object.setPrototypeOf(this, new.target.prototype); + } +} +exports.PubNubError = PubNubError; +function createError(errorPayload) { + var _a; + (_a = errorPayload.statusCode) !== null && _a !== void 0 ? _a : (errorPayload.statusCode = 0); + return Object.assign(Object.assign({}, errorPayload), { statusCode: errorPayload.statusCode, category: categories_1.default.PNValidationErrorCategory, error: true }); +} +function createValidationError(message, statusCode) { + return createError(Object.assign({ message }, (statusCode !== undefined ? { statusCode } : {}))); +} +exports.createValidationError = createValidationError; diff --git a/lib/event-engine/core/change.js b/lib/event-engine/core/change.js index 2b5963b5c..c8ad2e549 100644 --- a/lib/event-engine/core/change.js +++ b/lib/event-engine/core/change.js @@ -1,3 +1,2 @@ "use strict"; -/* eslint-disable @typescript-eslint/no-explicit-any */ Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/lib/event-engine/core/dispatcher.js b/lib/event-engine/core/dispatcher.js index 056a97830..4cfc94966 100644 --- a/lib/event-engine/core/dispatcher.js +++ b/lib/event-engine/core/dispatcher.js @@ -1,79 +1,39 @@ "use strict"; -/* eslint-disable @typescript-eslint/no-explicit-any */ -var __values = (this && this.__values) || function(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."); -}; -var __read = (this && this.__read) || function (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; -}; Object.defineProperty(exports, "__esModule", { value: true }); exports.Dispatcher = void 0; -var Dispatcher = /** @class */ (function () { - function Dispatcher(dependencies) { +class Dispatcher { + constructor(dependencies) { this.dependencies = dependencies; this.instances = new Map(); this.handlers = new Map(); } - Dispatcher.prototype.on = function (type, handlerCreator) { + on(type, handlerCreator) { this.handlers.set(type, handlerCreator); - }; - Dispatcher.prototype.dispatch = function (invocation) { + } + dispatch(invocation) { if (invocation.type === 'CANCEL') { if (this.instances.has(invocation.payload)) { - var instance_1 = this.instances.get(invocation.payload); - instance_1 === null || instance_1 === void 0 ? void 0 : instance_1.cancel(); + const instance = this.instances.get(invocation.payload); + instance === null || instance === void 0 ? void 0 : instance.cancel(); this.instances.delete(invocation.payload); } return; } - var handlerCreator = this.handlers.get(invocation.type); + const handlerCreator = this.handlers.get(invocation.type); if (!handlerCreator) { - throw new Error("Unhandled invocation '".concat(invocation.type, "'")); + throw new Error(`Unhandled invocation '${invocation.type}'`); } - var instance = handlerCreator(invocation.payload, this.dependencies); + const instance = handlerCreator(invocation.payload, this.dependencies); if (invocation.managed) { this.instances.set(invocation.type, instance); } instance.start(); - }; - Dispatcher.prototype.dispose = function () { - var e_1, _a; - try { - for (var _b = __values(this.instances.entries()), _c = _b.next(); !_c.done; _c = _b.next()) { - var _d = __read(_c.value, 2), key = _d[0], instance = _d[1]; - instance.cancel(); - this.instances.delete(key); - } - } - catch (e_1_1) { e_1 = { error: e_1_1 }; } - finally { - try { - if (_c && !_c.done && (_a = _b.return)) _a.call(_b); - } - finally { if (e_1) throw e_1.error; } + } + dispose() { + for (const [key, instance] of this.instances.entries()) { + instance.cancel(); + this.instances.delete(key); } - }; - return Dispatcher; -}()); + } +} exports.Dispatcher = Dispatcher; diff --git a/lib/event-engine/core/engine.js b/lib/event-engine/core/engine.js index 2b0eb5519..351df033f 100644 --- a/lib/event-engine/core/engine.js +++ b/lib/event-engine/core/engine.js @@ -1,60 +1,13 @@ "use strict"; -/* eslint-disable @typescript-eslint/no-explicit-any */ -var __extends = (this && this.__extends) || (function () { - 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); - }; - return function (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 __read = (this && this.__read) || function (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; -}; -var __values = (this && this.__values) || function(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."); -}; Object.defineProperty(exports, "__esModule", { value: true }); exports.Engine = void 0; -var subject_1 = require("../../core/components/subject"); -var state_1 = require("./state"); -var Engine = /** @class */ (function (_super) { - __extends(Engine, _super); - function Engine() { - return _super !== null && _super.apply(this, arguments) || this; - } - Engine.prototype.describe = function (label) { +const subject_1 = require("../../core/components/subject"); +const state_1 = require("./state"); +class Engine extends subject_1.Subject { + describe(label) { return new state_1.State(label); - }; - Engine.prototype.start = function (initialState, initialContext) { + } + start(initialState, initialContext) { this.currentState = initialState; this.currentContext = initialContext; this.notify({ @@ -63,9 +16,8 @@ var Engine = /** @class */ (function (_super) { context: initialContext, }); return; - }; - Engine.prototype.transition = function (event) { - var e_1, _a, e_2, _b, e_3, _c; + } + transition(event) { if (!this.currentState) { throw new Error('Start the engine first'); } @@ -73,28 +25,18 @@ var Engine = /** @class */ (function (_super) { type: 'eventReceived', event: event, }); - var transition = this.currentState.transition(this.currentContext, event); + const transition = this.currentState.transition(this.currentContext, event); if (transition) { - var _d = __read(transition, 3), newState = _d[0], newContext = _d[1], effects = _d[2]; - try { - for (var _e = __values(this.currentState.exitEffects), _f = _e.next(); !_f.done; _f = _e.next()) { - var effect = _f.value; - this.notify({ - type: 'invocationDispatched', - invocation: effect(this.currentContext), - }); - } - } - catch (e_1_1) { e_1 = { error: e_1_1 }; } - finally { - try { - if (_f && !_f.done && (_a = _e.return)) _a.call(_e); - } - finally { if (e_1) throw e_1.error; } + const [newState, newContext, effects] = transition; + for (const effect of this.currentState.exitEffects) { + this.notify({ + type: 'invocationDispatched', + invocation: effect(this.currentContext), + }); } - var oldState = this.currentState; + const oldState = this.currentState; this.currentState = newState; - var oldContext = this.currentContext; + const oldContext = this.currentContext; this.currentContext = newContext; this.notify({ type: 'transitionDone', @@ -104,40 +46,19 @@ var Engine = /** @class */ (function (_super) { toContext: newContext, event: event, }); - try { - for (var effects_1 = __values(effects), effects_1_1 = effects_1.next(); !effects_1_1.done; effects_1_1 = effects_1.next()) { - var effect = effects_1_1.value; - this.notify({ - type: 'invocationDispatched', - invocation: effect, - }); - } - } - catch (e_2_1) { e_2 = { error: e_2_1 }; } - finally { - try { - if (effects_1_1 && !effects_1_1.done && (_b = effects_1.return)) _b.call(effects_1); - } - finally { if (e_2) throw e_2.error; } + for (const effect of effects) { + this.notify({ + type: 'invocationDispatched', + invocation: effect, + }); } - try { - for (var _g = __values(this.currentState.enterEffects), _h = _g.next(); !_h.done; _h = _g.next()) { - var effect = _h.value; - this.notify({ - type: 'invocationDispatched', - invocation: effect(this.currentContext), - }); - } - } - catch (e_3_1) { e_3 = { error: e_3_1 }; } - finally { - try { - if (_h && !_h.done && (_c = _g.return)) _c.call(_g); - } - finally { if (e_3) throw e_3.error; } + for (const effect of this.currentState.enterEffects) { + this.notify({ + type: 'invocationDispatched', + invocation: effect(this.currentContext), + }); } } - }; - return Engine; -}(subject_1.Subject)); + } +} exports.Engine = Engine; diff --git a/lib/event-engine/core/handler.js b/lib/event-engine/core/handler.js index f5446b05f..88bead570 100644 --- a/lib/event-engine/core/handler.js +++ b/lib/event-engine/core/handler.js @@ -1,52 +1,27 @@ "use strict"; -var __extends = (this && this.__extends) || (function () { - 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); - }; - return function (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 __()); - }; -})(); Object.defineProperty(exports, "__esModule", { value: true }); exports.asyncHandler = exports.Handler = void 0; -var abort_signal_1 = require("../../core/components/abort_signal"); -var Handler = /** @class */ (function () { - function Handler(payload, dependencies) { +const abort_signal_1 = require("../../core/components/abort_signal"); +class Handler { + constructor(payload, dependencies) { this.payload = payload; this.dependencies = dependencies; } - return Handler; -}()); +} exports.Handler = Handler; -var AsyncHandler = /** @class */ (function (_super) { - __extends(AsyncHandler, _super); - function AsyncHandler(payload, dependencies, asyncFunction) { - var _this = _super.call(this, payload, dependencies) || this; - _this.asyncFunction = asyncFunction; - _this.abortSignal = new abort_signal_1.AbortSignal(); - return _this; +class AsyncHandler extends Handler { + constructor(payload, dependencies, asyncFunction) { + super(payload, dependencies); + this.asyncFunction = asyncFunction; + this.abortSignal = new abort_signal_1.AbortSignal(); } - AsyncHandler.prototype.start = function () { - this.asyncFunction(this.payload, this.abortSignal, this.dependencies).catch(function (error) { - // console.log('Unhandled error:', error); - // swallow the error + start() { + this.asyncFunction(this.payload, this.abortSignal, this.dependencies).catch((error) => { }); - }; - AsyncHandler.prototype.cancel = function () { + } + cancel() { this.abortSignal.abort(); - }; - return AsyncHandler; -}(Handler)); -var asyncHandler = function (handlerFunction) { - return function (payload, dependencies) { - return new AsyncHandler(payload, dependencies, handlerFunction); - }; -}; + } +} +const asyncHandler = (handlerFunction) => (payload, dependencies) => new AsyncHandler(payload, dependencies, handlerFunction); exports.asyncHandler = asyncHandler; diff --git a/lib/event-engine/core/reconnectionDelay.js b/lib/event-engine/core/reconnectionDelay.js deleted file mode 100644 index e2078670a..000000000 --- a/lib/event-engine/core/reconnectionDelay.js +++ /dev/null @@ -1,27 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.ReconnectionDelay = void 0; -var ReconnectionDelay = /** @class */ (function () { - function ReconnectionDelay() { - } - ReconnectionDelay.getDelay = function (policy, attempts, backoff) { - var backoffValue = backoff !== null && backoff !== void 0 ? backoff : 5; - switch (policy.toUpperCase()) { - case 'LINEAR': - return attempts * backoffValue + 200; - case 'EXPONENTIAL': - return Math.trunc(Math.pow(2, attempts - 1)) * 1000 + Math.random() * 1000; - default: - throw new Error('invalid policy'); - } - }; - ReconnectionDelay.shouldRetry = function (maxRetries, attempts, policy) { - // maxRetries > attempts && policy && policy != 'None'; - if (policy && policy !== 'None') { - return maxRetries > attempts; - } - return false; - }; - return ReconnectionDelay; -}()); -exports.ReconnectionDelay = ReconnectionDelay; diff --git a/lib/event-engine/core/retryPolicy.js b/lib/event-engine/core/retryPolicy.js index dde639271..a038d25c3 100644 --- a/lib/event-engine/core/retryPolicy.js +++ b/lib/event-engine/core/retryPolicy.js @@ -1,26 +1,24 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RetryPolicy = void 0; -var RetryPolicy = /** @class */ (function () { - function RetryPolicy() { - } - RetryPolicy.LinearRetryPolicy = function (configuration) { +class RetryPolicy { + static LinearRetryPolicy(configuration) { return { delay: configuration.delay, maximumRetry: configuration.maximumRetry, - shouldRetry: function (error, attempt) { + shouldRetry(error, attempt) { var _a; if (((_a = error === null || error === void 0 ? void 0 : error.status) === null || _a === void 0 ? void 0 : _a.statusCode) === 403) { return false; } return this.maximumRetry > attempt; }, - getDelay: function (_, reason) { + getDelay(_, reason) { var _a; - var delay = (_a = reason.retryAfter) !== null && _a !== void 0 ? _a : this.delay; + const delay = (_a = reason.retryAfter) !== null && _a !== void 0 ? _a : this.delay; return (delay + Math.random()) * 1000; }, - getGiveupReason: function (error, attempt) { + getGiveupReason(error, attempt) { var _a; if (this.maximumRetry <= attempt) { return 'retry attempts exhaused.'; @@ -30,37 +28,48 @@ var RetryPolicy = /** @class */ (function () { } return 'unknown error'; }, + validate() { + if (this.maximumRetry > 10) + throw new Error('Maximum retry for linear retry policy can not be more than 10'); + }, }; - }; - RetryPolicy.ExponentialRetryPolicy = function (configuration) { + } + static ExponentialRetryPolicy(configuration) { return { minimumDelay: configuration.minimumDelay, maximumDelay: configuration.maximumDelay, maximumRetry: configuration.maximumRetry, - shouldRetry: function (error, attempt) { + shouldRetry(reason, attempt) { var _a; - if (((_a = error === null || error === void 0 ? void 0 : error.status) === null || _a === void 0 ? void 0 : _a.statusCode) === 403) { + if (((_a = reason === null || reason === void 0 ? void 0 : reason.status) === null || _a === void 0 ? void 0 : _a.statusCode) === 403) { return false; } return this.maximumRetry > attempt; }, - getDelay: function (attempt, reason) { + getDelay(attempt, reason) { var _a; - var delay = (_a = reason.retryAfter) !== null && _a !== void 0 ? _a : Math.min(Math.pow(2, attempt), this.maximumDelay); + const delay = (_a = reason.retryAfter) !== null && _a !== void 0 ? _a : Math.min(Math.pow(2, attempt), this.maximumDelay); return (delay + Math.random()) * 1000; }, - getGiveupReason: function (error, attempt) { + getGiveupReason(reason, attempt) { var _a; if (this.maximumRetry <= attempt) { - return 'retry attempts exhaused.'; + return 'retry attempts exhausted.'; } - if (((_a = error === null || error === void 0 ? void 0 : error.status) === null || _a === void 0 ? void 0 : _a.statusCode) === 403) { + if (((_a = reason === null || reason === void 0 ? void 0 : reason.status) === null || _a === void 0 ? void 0 : _a.statusCode) === 403) { return 'forbidden operation.'; } return 'unknown error'; }, + validate() { + if (this.minimumDelay < 2) + throw new Error('Minimum delay can not be set less than 2 seconds for retry'); + else if (this.maximumDelay) + throw new Error('Maximum delay can not be set more than 150 seconds for retry'); + else if (this.maximumRetry > 6) + throw new Error('Maximum retry for exponential retry policy can not be more than 6'); + }, }; - }; - return RetryPolicy; -}()); + } +} exports.RetryPolicy = RetryPolicy; diff --git a/lib/event-engine/core/state.js b/lib/event-engine/core/state.js index 0e722a6a3..88c83cf6a 100644 --- a/lib/event-engine/core/state.js +++ b/lib/event-engine/core/state.js @@ -1,36 +1,34 @@ "use strict"; -/* eslint-disable @typescript-eslint/no-explicit-any */ Object.defineProperty(exports, "__esModule", { value: true }); exports.State = void 0; -var State = /** @class */ (function () { - function State(label) { - this.label = label; - this.transitionMap = new Map(); - this.enterEffects = []; - this.exitEffects = []; - } - State.prototype.transition = function (context, event) { +class State { + transition(context, event) { var _a; if (this.transitionMap.has(event.type)) { return (_a = this.transitionMap.get(event.type)) === null || _a === void 0 ? void 0 : _a(context, event); } return undefined; - }; - State.prototype.on = function (eventType, transition) { + } + constructor(label) { + this.label = label; + this.transitionMap = new Map(); + this.enterEffects = []; + this.exitEffects = []; + } + on(eventType, transition) { this.transitionMap.set(eventType, transition); return this; - }; - State.prototype.with = function (context, effects) { + } + with(context, effects) { return [this, context, effects !== null && effects !== void 0 ? effects : []]; - }; - State.prototype.onEnter = function (effect) { + } + onEnter(effect) { this.enterEffects.push(effect); return this; - }; - State.prototype.onExit = function (effect) { + } + onExit(effect) { this.exitEffects.push(effect); return this; - }; - return State; -}()); + } +} exports.State = State; diff --git a/lib/event-engine/core/types.js b/lib/event-engine/core/types.js index d21b2facd..85dc4a919 100644 --- a/lib/event-engine/core/types.js +++ b/lib/event-engine/core/types.js @@ -1,41 +1,11 @@ "use strict"; -/* eslint-disable @typescript-eslint/no-explicit-any */ -var __read = (this && this.__read) || function (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; -}; -var __spreadArray = (this && this.__spreadArray) || function (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)); -}; Object.defineProperty(exports, "__esModule", { value: true }); exports.createManagedEffect = exports.createEffect = exports.createEvent = void 0; function createEvent(type, fn) { - var creator = function () { - var args = []; - for (var _i = 0; _i < arguments.length; _i++) { - args[_i] = arguments[_i]; - } + const creator = function (...args) { return { - type: type, - payload: fn === null || fn === void 0 ? void 0 : fn.apply(void 0, __spreadArray([], __read(args), false)), + type, + payload: fn === null || fn === void 0 ? void 0 : fn(...args), }; }; creator.type = type; @@ -43,24 +13,16 @@ function createEvent(type, fn) { } exports.createEvent = createEvent; function createEffect(type, fn) { - var creator = function () { - var args = []; - for (var _i = 0; _i < arguments.length; _i++) { - args[_i] = arguments[_i]; - } - return { type: type, payload: fn.apply(void 0, __spreadArray([], __read(args), false)), managed: false }; + const creator = (...args) => { + return { type, payload: fn(...args), managed: false }; }; creator.type = type; return creator; } exports.createEffect = createEffect; function createManagedEffect(type, fn) { - var creator = function () { - var args = []; - for (var _i = 0; _i < arguments.length; _i++) { - args[_i] = arguments[_i]; - } - return { type: type, payload: fn.apply(void 0, __spreadArray([], __read(args), false)), managed: true }; + const creator = (...args) => { + return { type, payload: fn(...args), managed: true }; }; creator.type = type; creator.cancel = { type: 'CANCEL', payload: type, managed: false }; diff --git a/lib/event-engine/dispatcher.js b/lib/event-engine/dispatcher.js index 27e5c02a9..c8e3c2ddb 100644 --- a/lib/event-engine/dispatcher.js +++ b/lib/event-engine/dispatcher.js @@ -1,30 +1,4 @@ "use strict"; -var __extends = (this && this.__extends) || (function () { - 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); - }; - return function (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 = (this && this.__assign) || function () { - __assign = Object.assign || function(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); -}; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); @@ -57,210 +31,116 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "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 (_) 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 }; - } +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.EventEngineDispatcher = void 0; -var endpoint_1 = require("../core/components/endpoint"); -var core_1 = require("./core"); -var effects = __importStar(require("./effects")); -var events = __importStar(require("./events")); -var EventEngineDispatcher = /** @class */ (function (_super) { - __extends(EventEngineDispatcher, _super); - function EventEngineDispatcher(engine, dependencies) { - var _this = _super.call(this, dependencies) || this; - _this.on(effects.handshake.type, (0, core_1.asyncHandler)(function (payload, abortSignal, _a) { - var handshake = _a.handshake, presenceState = _a.presenceState, config = _a.config; - return __awaiter(_this, void 0, void 0, function () { - var result, e_1; - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - abortSignal.throwIfAborted(); - _b.label = 1; - case 1: - _b.trys.push([1, 3, , 4]); - return [4 /*yield*/, handshake(__assign({ abortSignal: abortSignal, channels: payload.channels, channelGroups: payload.groups, filterExpression: config.filterExpression }, (config.maintainPresenceState && { state: presenceState })))]; - case 2: - result = _b.sent(); - return [2 /*return*/, engine.transition(events.handshakeSuccess(result))]; - case 3: - e_1 = _b.sent(); - if (e_1 instanceof Error && e_1.message === 'Aborted') { - return [2 /*return*/]; - } - if (e_1 instanceof endpoint_1.PubNubError) { - return [2 /*return*/, engine.transition(events.handshakeFailure(e_1))]; - } - return [3 /*break*/, 4]; - case 4: return [2 /*return*/]; - } - }); - }); - })); - _this.on(effects.receiveMessages.type, (0, core_1.asyncHandler)(function (payload, abortSignal, _a) { - var receiveMessages = _a.receiveMessages, config = _a.config; - return __awaiter(_this, void 0, void 0, function () { - var result, error_1; - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - abortSignal.throwIfAborted(); - _b.label = 1; - case 1: - _b.trys.push([1, 3, , 4]); - return [4 /*yield*/, receiveMessages({ - abortSignal: abortSignal, - channels: payload.channels, - channelGroups: payload.groups, - timetoken: payload.cursor.timetoken, - region: payload.cursor.region, - filterExpression: config.filterExpression, - })]; - case 2: - result = _b.sent(); - engine.transition(events.receiveSuccess(result.metadata, result.messages)); - return [3 /*break*/, 4]; - case 3: - error_1 = _b.sent(); - if (error_1 instanceof Error && error_1.message === 'Aborted') { - return [2 /*return*/]; - } - if (error_1 instanceof endpoint_1.PubNubError && !abortSignal.aborted) { - return [2 /*return*/, engine.transition(events.receiveFailure(error_1))]; - } - return [3 /*break*/, 4]; - case 4: return [2 /*return*/]; - } - }); - }); - })); - _this.on(effects.emitMessages.type, (0, core_1.asyncHandler)(function (payload, _, _a) { - var emitMessages = _a.emitMessages; - return __awaiter(_this, void 0, void 0, function () { - return __generator(this, function (_b) { - if (payload.length > 0) { - emitMessages(payload); - } - return [2 /*return*/]; - }); - }); - })); - _this.on(effects.emitStatus.type, (0, core_1.asyncHandler)(function (payload, _, _a) { - var emitStatus = _a.emitStatus; - return __awaiter(_this, void 0, void 0, function () { - return __generator(this, function (_b) { - emitStatus(payload); - return [2 /*return*/]; +const pubnub_error_1 = require("../errors/pubnub-error"); +const core_1 = require("./core"); +const effects = __importStar(require("./effects")); +const events = __importStar(require("./events")); +const categories_1 = __importDefault(require("../core/constants/categories")); +class EventEngineDispatcher extends core_1.Dispatcher { + constructor(engine, dependencies) { + super(dependencies); + this.on(effects.handshake.type, (0, core_1.asyncHandler)((payload_1, abortSignal_1, _a) => __awaiter(this, [payload_1, abortSignal_1, _a], void 0, function* (payload, abortSignal, { handshake, presenceState, config }) { + abortSignal.throwIfAborted(); + try { + const result = yield handshake(Object.assign({ abortSignal: abortSignal, channels: payload.channels, channelGroups: payload.groups, filterExpression: config.filterExpression }, (config.maintainPresenceState && { state: presenceState }))); + return engine.transition(events.handshakeSuccess(result)); + } + catch (e) { + if (e instanceof pubnub_error_1.PubNubError) { + if (e.status && e.status.category == categories_1.default.PNCancelledCategory) + return; + return engine.transition(events.handshakeFailure(e)); + } + } + }))); + this.on(effects.receiveMessages.type, (0, core_1.asyncHandler)((payload_2, abortSignal_2, _b) => __awaiter(this, [payload_2, abortSignal_2, _b], void 0, function* (payload, abortSignal, { receiveMessages, config }) { + abortSignal.throwIfAborted(); + try { + const result = yield receiveMessages({ + abortSignal: abortSignal, + channels: payload.channels, + channelGroups: payload.groups, + timetoken: payload.cursor.timetoken, + region: payload.cursor.region, + filterExpression: config.filterExpression, }); - }); - })); - _this.on(effects.receiveReconnect.type, (0, core_1.asyncHandler)(function (payload, abortSignal, _a) { - var receiveMessages = _a.receiveMessages, delay = _a.delay, config = _a.config; - return __awaiter(_this, void 0, void 0, function () { - var result, error_2; - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - if (!(config.retryConfiguration && config.retryConfiguration.shouldRetry(payload.reason, payload.attempts))) return [3 /*break*/, 6]; - abortSignal.throwIfAborted(); - return [4 /*yield*/, delay(config.retryConfiguration.getDelay(payload.attempts, payload.reason))]; - case 1: - _b.sent(); - abortSignal.throwIfAborted(); - _b.label = 2; - case 2: - _b.trys.push([2, 4, , 5]); - return [4 /*yield*/, receiveMessages({ - abortSignal: abortSignal, - channels: payload.channels, - channelGroups: payload.groups, - timetoken: payload.cursor.timetoken, - region: payload.cursor.region, - filterExpression: config.filterExpression, - })]; - case 3: - result = _b.sent(); - return [2 /*return*/, engine.transition(events.receiveReconnectSuccess(result.metadata, result.messages))]; - case 4: - error_2 = _b.sent(); - if (error_2 instanceof Error && error_2.message === 'Aborted') { - return [2 /*return*/]; - } - if (error_2 instanceof endpoint_1.PubNubError) { - return [2 /*return*/, engine.transition(events.receiveReconnectFailure(error_2))]; - } - return [3 /*break*/, 5]; - case 5: return [3 /*break*/, 7]; - case 6: return [2 /*return*/, engine.transition(events.receiveReconnectGiveup(new endpoint_1.PubNubError(config.retryConfiguration.getGiveupReason(payload.reason, payload.attempts))))]; - case 7: return [2 /*return*/]; + engine.transition(events.receiveSuccess(result.cursor, result.messages)); + } + catch (error) { + if (error instanceof pubnub_error_1.PubNubError) { + if (error.status && error.status.category == categories_1.default.PNCancelledCategory) + return; + if (!abortSignal.aborted) + return engine.transition(events.receiveFailure(error)); + } + } + }))); + this.on(effects.emitMessages.type, (0, core_1.asyncHandler)((payload_3, _1, _c) => __awaiter(this, [payload_3, _1, _c], void 0, function* (payload, _, { emitMessages }) { + if (payload.length > 0) { + emitMessages(payload); + } + }))); + this.on(effects.emitStatus.type, (0, core_1.asyncHandler)((payload_4, _2, _d) => __awaiter(this, [payload_4, _2, _d], void 0, function* (payload, _, { emitStatus }) { + emitStatus(payload); + }))); + this.on(effects.receiveReconnect.type, (0, core_1.asyncHandler)((payload_5, abortSignal_3, _e) => __awaiter(this, [payload_5, abortSignal_3, _e], void 0, function* (payload, abortSignal, { receiveMessages, delay, config }) { + if (config.retryConfiguration && config.retryConfiguration.shouldRetry(payload.reason, payload.attempts)) { + abortSignal.throwIfAborted(); + yield delay(config.retryConfiguration.getDelay(payload.attempts, payload.reason)); + abortSignal.throwIfAborted(); + try { + const result = yield receiveMessages({ + abortSignal: abortSignal, + channels: payload.channels, + channelGroups: payload.groups, + timetoken: payload.cursor.timetoken, + region: payload.cursor.region, + filterExpression: config.filterExpression, + }); + return engine.transition(events.receiveReconnectSuccess(result.cursor, result.messages)); + } + catch (error) { + if (error instanceof pubnub_error_1.PubNubError) { + if (error.status && error.status.category == categories_1.default.PNCancelledCategory) + return; + return engine.transition(events.receiveReconnectFailure(error)); } - }); - }); - })); - _this.on(effects.handshakeReconnect.type, (0, core_1.asyncHandler)(function (payload, abortSignal, _a) { - var handshake = _a.handshake, delay = _a.delay, presenceState = _a.presenceState, config = _a.config; - return __awaiter(_this, void 0, void 0, function () { - var result, error_3; - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - if (!(config.retryConfiguration && config.retryConfiguration.shouldRetry(payload.reason, payload.attempts))) return [3 /*break*/, 6]; - abortSignal.throwIfAborted(); - return [4 /*yield*/, delay(config.retryConfiguration.getDelay(payload.attempts, payload.reason))]; - case 1: - _b.sent(); - abortSignal.throwIfAborted(); - _b.label = 2; - case 2: - _b.trys.push([2, 4, , 5]); - return [4 /*yield*/, handshake(__assign({ abortSignal: abortSignal, channels: payload.channels, channelGroups: payload.groups, filterExpression: config.filterExpression }, (config.maintainPresenceState && { state: presenceState })))]; - case 3: - result = _b.sent(); - return [2 /*return*/, engine.transition(events.handshakeReconnectSuccess(result))]; - case 4: - error_3 = _b.sent(); - if (error_3 instanceof Error && error_3.message === 'Aborted') { - return [2 /*return*/]; - } - if (error_3 instanceof endpoint_1.PubNubError) { - return [2 /*return*/, engine.transition(events.handshakeReconnectFailure(error_3))]; - } - return [3 /*break*/, 5]; - case 5: return [3 /*break*/, 7]; - case 6: return [2 /*return*/, engine.transition(events.handshakeReconnectGiveup(new endpoint_1.PubNubError(config.retryConfiguration.getGiveupReason(payload.reason, payload.attempts))))]; - case 7: return [2 /*return*/]; + } + } + else { + return engine.transition(events.receiveReconnectGiveup(new pubnub_error_1.PubNubError(config.retryConfiguration + ? config.retryConfiguration.getGiveupReason(payload.reason, payload.attempts) + : 'Unable to complete subscribe messages receive.'))); + } + }))); + this.on(effects.handshakeReconnect.type, (0, core_1.asyncHandler)((payload_6, abortSignal_4, _f) => __awaiter(this, [payload_6, abortSignal_4, _f], void 0, function* (payload, abortSignal, { handshake, delay, presenceState, config }) { + if (config.retryConfiguration && config.retryConfiguration.shouldRetry(payload.reason, payload.attempts)) { + abortSignal.throwIfAborted(); + yield delay(config.retryConfiguration.getDelay(payload.attempts, payload.reason)); + abortSignal.throwIfAborted(); + try { + const result = yield handshake(Object.assign({ abortSignal: abortSignal, channels: payload.channels, channelGroups: payload.groups, filterExpression: config.filterExpression }, (config.maintainPresenceState && { state: presenceState }))); + return engine.transition(events.handshakeReconnectSuccess(result)); + } + catch (error) { + if (error instanceof pubnub_error_1.PubNubError) { + if (error.status && error.status.category == categories_1.default.PNCancelledCategory) + return; + return engine.transition(events.handshakeReconnectFailure(error)); } - }); - }); - })); - return _this; + } + } + else { + return engine.transition(events.handshakeReconnectGiveup(new pubnub_error_1.PubNubError(config.retryConfiguration + ? config.retryConfiguration.getGiveupReason(payload.reason, payload.attempts) + : 'Unable to complete subscribe handshake'))); + } + }))); } - return EventEngineDispatcher; -}(core_1.Dispatcher)); +} exports.EventEngineDispatcher = EventEngineDispatcher; diff --git a/lib/event-engine/effects.js b/lib/event-engine/effects.js index 2b5ead623..2c788f77c 100644 --- a/lib/event-engine/effects.js +++ b/lib/event-engine/effects.js @@ -1,13 +1,13 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.handshakeReconnect = exports.receiveReconnect = exports.emitStatus = exports.emitMessages = exports.receiveMessages = exports.handshake = void 0; -var core_1 = require("./core"); -exports.handshake = (0, core_1.createManagedEffect)('HANDSHAKE', function (channels, groups) { return ({ - channels: channels, - groups: groups, -}); }); -exports.receiveMessages = (0, core_1.createManagedEffect)('RECEIVE_MESSAGES', function (channels, groups, cursor) { return ({ channels: channels, groups: groups, cursor: cursor }); }); -exports.emitMessages = (0, core_1.createEffect)('EMIT_MESSAGES', function (events) { return events; }); -exports.emitStatus = (0, core_1.createEffect)('EMIT_STATUS', function (status) { return status; }); -exports.receiveReconnect = (0, core_1.createManagedEffect)('RECEIVE_RECONNECT', function (context) { return context; }); -exports.handshakeReconnect = (0, core_1.createManagedEffect)('HANDSHAKE_RECONNECT', function (context) { return context; }); +const core_1 = require("./core"); +exports.handshake = (0, core_1.createManagedEffect)('HANDSHAKE', (channels, groups) => ({ + channels, + groups, +})); +exports.receiveMessages = (0, core_1.createManagedEffect)('RECEIVE_MESSAGES', (channels, groups, cursor) => ({ channels, groups, cursor })); +exports.emitMessages = (0, core_1.createEffect)('EMIT_MESSAGES', (events) => events); +exports.emitStatus = (0, core_1.createEffect)('EMIT_STATUS', (status) => status); +exports.receiveReconnect = (0, core_1.createManagedEffect)('RECEIVE_RECONNECT', (context) => context); +exports.handshakeReconnect = (0, core_1.createManagedEffect)('HANDSHAKE_RECONNECT', (context) => context); diff --git a/lib/event-engine/events.js b/lib/event-engine/events.js index bcea70719..3725ca704 100644 --- a/lib/event-engine/events.js +++ b/lib/event-engine/events.js @@ -1,42 +1,42 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.unsubscribeAll = exports.reconnect = exports.disconnect = exports.receiveReconnectGiveup = exports.receiveReconnectFailure = exports.receiveReconnectSuccess = exports.receiveFailure = exports.receiveSuccess = exports.handshakeReconnectGiveup = exports.handshakeReconnectFailure = exports.handshakeReconnectSuccess = exports.handshakeFailure = exports.handshakeSuccess = exports.restore = exports.subscriptionChange = void 0; -var core_1 = require("./core"); -exports.subscriptionChange = (0, core_1.createEvent)('SUBSCRIPTION_CHANGED', function (channels, groups) { return ({ - channels: channels, - groups: groups, -}); }); -exports.restore = (0, core_1.createEvent)('SUBSCRIPTION_RESTORED', function (channels, groups, timetoken, region) { return ({ - channels: channels, - groups: groups, +const core_1 = require("./core"); +exports.subscriptionChange = (0, core_1.createEvent)('SUBSCRIPTION_CHANGED', (channels, groups) => ({ + channels, + groups, +})); +exports.restore = (0, core_1.createEvent)('SUBSCRIPTION_RESTORED', (channels, groups, timetoken, region) => ({ + channels, + groups, cursor: { timetoken: timetoken, region: region !== null && region !== void 0 ? region : 0, }, -}); }); -exports.handshakeSuccess = (0, core_1.createEvent)('HANDSHAKE_SUCCESS', function (cursor) { return cursor; }); -exports.handshakeFailure = (0, core_1.createEvent)('HANDSHAKE_FAILURE', function (error) { return error; }); -exports.handshakeReconnectSuccess = (0, core_1.createEvent)('HANDSHAKE_RECONNECT_SUCCESS', function (cursor) { return ({ - cursor: cursor, -}); }); -exports.handshakeReconnectFailure = (0, core_1.createEvent)('HANDSHAKE_RECONNECT_FAILURE', function (error) { return error; }); -exports.handshakeReconnectGiveup = (0, core_1.createEvent)('HANDSHAKE_RECONNECT_GIVEUP', function (error) { return error; }); -exports.receiveSuccess = (0, core_1.createEvent)('RECEIVE_SUCCESS', function (cursor, events) { return ({ - cursor: cursor, - events: events, -}); }); -exports.receiveFailure = (0, core_1.createEvent)('RECEIVE_FAILURE', function (error) { return error; }); -exports.receiveReconnectSuccess = (0, core_1.createEvent)('RECEIVE_RECONNECT_SUCCESS', function (cursor, events) { return ({ - cursor: cursor, - events: events, -}); }); -exports.receiveReconnectFailure = (0, core_1.createEvent)('RECEIVE_RECONNECT_FAILURE', function (error) { return error; }); -exports.receiveReconnectGiveup = (0, core_1.createEvent)('RECEIVING_RECONNECT_GIVEUP', function (error) { return error; }); -exports.disconnect = (0, core_1.createEvent)('DISCONNECT', function () { return ({}); }); -exports.reconnect = (0, core_1.createEvent)('RECONNECT', function (timetoken, region) { return ({ +})); +exports.handshakeSuccess = (0, core_1.createEvent)('HANDSHAKE_SUCCESS', (cursor) => cursor); +exports.handshakeFailure = (0, core_1.createEvent)('HANDSHAKE_FAILURE', (error) => error); +exports.handshakeReconnectSuccess = (0, core_1.createEvent)('HANDSHAKE_RECONNECT_SUCCESS', (cursor) => ({ + cursor, +})); +exports.handshakeReconnectFailure = (0, core_1.createEvent)('HANDSHAKE_RECONNECT_FAILURE', (error) => error); +exports.handshakeReconnectGiveup = (0, core_1.createEvent)('HANDSHAKE_RECONNECT_GIVEUP', (error) => error); +exports.receiveSuccess = (0, core_1.createEvent)('RECEIVE_SUCCESS', (cursor, events) => ({ + cursor, + events, +})); +exports.receiveFailure = (0, core_1.createEvent)('RECEIVE_FAILURE', (error) => error); +exports.receiveReconnectSuccess = (0, core_1.createEvent)('RECEIVE_RECONNECT_SUCCESS', (cursor, events) => ({ + cursor, + events, +})); +exports.receiveReconnectFailure = (0, core_1.createEvent)('RECEIVE_RECONNECT_FAILURE', (error) => error); +exports.receiveReconnectGiveup = (0, core_1.createEvent)('RECEIVING_RECONNECT_GIVEUP', (error) => error); +exports.disconnect = (0, core_1.createEvent)('DISCONNECT', () => ({})); +exports.reconnect = (0, core_1.createEvent)('RECONNECT', (timetoken, region) => ({ cursor: { timetoken: timetoken !== null && timetoken !== void 0 ? timetoken : '', region: region !== null && region !== void 0 ? region : 0, }, -}); }); -exports.unsubscribeAll = (0, core_1.createEvent)('UNSUBSCRIBE_ALL', function () { return ({}); }); +})); +exports.unsubscribeAll = (0, core_1.createEvent)('UNSUBSCRIBE_ALL', () => ({})); diff --git a/lib/event-engine/index.js b/lib/event-engine/index.js index 2dcdfa1bd..fd48c7427 100644 --- a/lib/event-engine/index.js +++ b/lib/event-engine/index.js @@ -22,94 +22,66 @@ var __importStar = (this && this.__importStar) || function (mod) { __setModuleDefault(result, mod); return result; }; -var __read = (this && this.__read) || function (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; -}; -var __spreadArray = (this && this.__spreadArray) || function (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)); -}; Object.defineProperty(exports, "__esModule", { value: true }); exports.EventEngine = void 0; -var core_1 = require("./core"); -var dispatcher_1 = require("./dispatcher"); -var events = __importStar(require("./events")); -var unsubscribed_1 = require("./states/unsubscribed"); -var utils = __importStar(require("../core/utils")); -var EventEngine = /** @class */ (function () { - function EventEngine(dependencies) { - var _this = this; +const core_1 = require("./core"); +const dispatcher_1 = require("./dispatcher"); +const events = __importStar(require("./events")); +const unsubscribed_1 = require("./states/unsubscribed"); +const utils = __importStar(require("../core/utils")); +class EventEngine { + get _engine() { + return this.engine; + } + constructor(dependencies) { this.engine = new core_1.Engine(); this.channels = []; this.groups = []; this.dependencies = dependencies; this.dispatcher = new dispatcher_1.EventEngineDispatcher(this.engine, dependencies); - this._unsubscribeEngine = this.engine.subscribe(function (change) { + this._unsubscribeEngine = this.engine.subscribe((change) => { if (change.type === 'invocationDispatched') { - _this.dispatcher.dispatch(change.invocation); + this.dispatcher.dispatch(change.invocation); } }); this.engine.start(unsubscribed_1.UnsubscribedState, undefined); } - Object.defineProperty(EventEngine.prototype, "_engine", { - get: function () { - return this.engine; - }, - enumerable: false, - configurable: true - }); - EventEngine.prototype.subscribe = function (_a) { - var _this = this; - var channels = _a.channels, channelGroups = _a.channelGroups, timetoken = _a.timetoken, withPresence = _a.withPresence; - this.channels = __spreadArray(__spreadArray([], __read(this.channels), false), __read((channels !== null && channels !== void 0 ? channels : [])), false); - this.groups = __spreadArray(__spreadArray([], __read(this.groups), false), __read((channelGroups !== null && channelGroups !== void 0 ? channelGroups : [])), false); + subscribe({ channels, channelGroups, timetoken, withPresence, }) { + this.channels = [...this.channels, ...(channels !== null && channels !== void 0 ? channels : [])]; + this.groups = [...this.groups, ...(channelGroups !== null && channelGroups !== void 0 ? channelGroups : [])]; if (withPresence) { - this.channels.map(function (c) { return _this.channels.push("".concat(c, "-pnpres")); }); - this.groups.map(function (g) { return _this.groups.push("".concat(g, "-pnpres")); }); + this.channels.map((c) => this.channels.push(`${c}-pnpres`)); + this.groups.map((g) => this.groups.push(`${g}-pnpres`)); } if (timetoken) { - this.engine.transition(events.restore(Array.from(new Set(__spreadArray(__spreadArray([], __read(this.channels), false), __read((channels !== null && channels !== void 0 ? channels : [])), false))), Array.from(new Set(__spreadArray(__spreadArray([], __read(this.groups), false), __read((channelGroups !== null && channelGroups !== void 0 ? channelGroups : [])), false))), timetoken)); + this.engine.transition(events.restore(Array.from(new Set([...this.channels, ...(channels !== null && channels !== void 0 ? channels : [])])), Array.from(new Set([...this.groups, ...(channelGroups !== null && channelGroups !== void 0 ? channelGroups : [])])), timetoken)); } else { - this.engine.transition(events.subscriptionChange(Array.from(new Set(__spreadArray(__spreadArray([], __read(this.channels), false), __read((channels !== null && channels !== void 0 ? channels : [])), false))), Array.from(new Set(__spreadArray(__spreadArray([], __read(this.groups), false), __read((channelGroups !== null && channelGroups !== void 0 ? channelGroups : [])), false))))); + this.engine.transition(events.subscriptionChange(Array.from(new Set([...this.channels, ...(channels !== null && channels !== void 0 ? channels : [])])), Array.from(new Set([...this.groups, ...(channelGroups !== null && channelGroups !== void 0 ? channelGroups : [])])))); } if (this.dependencies.join) { this.dependencies.join({ - channels: Array.from(new Set(this.channels.filter(function (c) { return !c.endsWith('-pnpres'); }))), - groups: Array.from(new Set(this.groups.filter(function (g) { return !g.endsWith('-pnpres'); }))), + channels: Array.from(new Set(this.channels.filter((c) => !c.endsWith('-pnpres')))), + groups: Array.from(new Set(this.groups.filter((g) => !g.endsWith('-pnpres')))), }); } - }; - EventEngine.prototype.unsubscribe = function (_a) { - var _this = this; - var _b = _a.channels, channels = _b === void 0 ? [] : _b, _c = _a.channelGroups, channelGroups = _c === void 0 ? [] : _c; - var filteredChannels = utils.removeSingleOccurance(this.channels, __spreadArray(__spreadArray([], __read(channels), false), __read(channels.map(function (c) { return "".concat(c, "-pnpres"); })), false)); - var filteredGroups = utils.removeSingleOccurance(this.groups, __spreadArray(__spreadArray([], __read(channelGroups), false), __read(channelGroups.map(function (c) { return "".concat(c, "-pnpres"); })), false)); + } + unsubscribe({ channels = [], channelGroups = [] }) { + const filteredChannels = utils.removeSingleOccurance(this.channels, [ + ...channels, + ...channels.map((c) => `${c}-pnpres`), + ]); + const filteredGroups = utils.removeSingleOccurance(this.groups, [ + ...channelGroups, + ...channelGroups.map((c) => `${c}-pnpres`), + ]); if (new Set(this.channels).size !== new Set(filteredChannels).size || new Set(this.groups).size !== new Set(filteredGroups).size) { - var channelsToLeave = utils.findUniqueCommonElements(this.channels, channels); - var groupstoLeave = utils.findUniqueCommonElements(this.groups, channelGroups); + const channelsToLeave = utils.findUniqueCommonElements(this.channels, channels); + const groupstoLeave = utils.findUniqueCommonElements(this.groups, channelGroups); if (this.dependencies.presenceState) { - channelsToLeave === null || channelsToLeave === void 0 ? void 0 : channelsToLeave.forEach(function (c) { return delete _this.dependencies.presenceState[c]; }); - groupstoLeave === null || groupstoLeave === void 0 ? void 0 : groupstoLeave.forEach(function (g) { return delete _this.dependencies.presenceState[g]; }); + channelsToLeave === null || channelsToLeave === void 0 ? void 0 : channelsToLeave.forEach((c) => delete this.dependencies.presenceState[c]); + groupstoLeave === null || groupstoLeave === void 0 ? void 0 : groupstoLeave.forEach((g) => delete this.dependencies.presenceState[g]); } this.channels = filteredChannels; this.groups = filteredGroups; @@ -121,39 +93,39 @@ var EventEngine = /** @class */ (function () { }); } } - }; - EventEngine.prototype.unsubscribeAll = function () { + } + unsubscribeAll() { this.channels = []; this.groups = []; if (this.dependencies.presenceState) { - this.dependencies.presenceState = {}; + Object.keys(this.dependencies.presenceState).forEach((objectName) => { + delete this.dependencies.presenceState[objectName]; + }); } this.engine.transition(events.subscriptionChange(this.channels.slice(0), this.groups.slice(0))); if (this.dependencies.leaveAll) { this.dependencies.leaveAll(); } - }; - EventEngine.prototype.reconnect = function (_a) { - var timetoken = _a.timetoken, region = _a.region; + } + reconnect({ timetoken, region }) { this.engine.transition(events.reconnect(timetoken, region)); - }; - EventEngine.prototype.disconnect = function () { + } + disconnect() { this.engine.transition(events.disconnect()); if (this.dependencies.leaveAll) { this.dependencies.leaveAll(); } - }; - EventEngine.prototype.getSubscribedChannels = function () { - return Array.from(new Set(this.channels)); - }; - EventEngine.prototype.getSubscribedChannelGroups = function () { - return Array.from(new Set(this.groups)); - }; - EventEngine.prototype.dispose = function () { + } + getSubscribedChannels() { + return Array.from(new Set(this.channels.slice(0))); + } + getSubscribedChannelGroups() { + return Array.from(new Set(this.groups.slice(0))); + } + dispose() { this.disconnect(); this._unsubscribeEngine(); this.dispatcher.dispose(); - }; - return EventEngine; -}()); + } +} exports.EventEngine = EventEngine; diff --git a/lib/event-engine/presence/dispatcher.js b/lib/event-engine/presence/dispatcher.js index 2b79f44eb..e38d0f967 100644 --- a/lib/event-engine/presence/dispatcher.js +++ b/lib/event-engine/presence/dispatcher.js @@ -1,30 +1,4 @@ "use strict"; -var __extends = (this && this.__extends) || (function () { - 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); - }; - return function (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 = (this && this.__assign) || function () { - __assign = Object.assign || function(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); -}; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); @@ -57,166 +31,80 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "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 (_) 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 }; - } -}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.PresenceEventEngineDispatcher = void 0; -var endpoint_1 = require("../../core/components/endpoint"); -var core_1 = require("../core"); -var operations_1 = __importDefault(require("../../core/constants/operations")); -var effects = __importStar(require("./effects")); -var events = __importStar(require("./events")); -var PresenceEventEngineDispatcher = /** @class */ (function (_super) { - __extends(PresenceEventEngineDispatcher, _super); - function PresenceEventEngineDispatcher(engine, dependencies) { - var _this = _super.call(this, dependencies) || this; - _this.on(effects.heartbeat.type, (0, core_1.asyncHandler)(function (payload, _, _a) { - var heartbeat = _a.heartbeat, presenceState = _a.presenceState, config = _a.config; - return __awaiter(_this, void 0, void 0, function () { - var result, e_1; - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - _b.trys.push([0, 2, , 3]); - return [4 /*yield*/, heartbeat(__assign({ channels: payload.channels, channelGroups: payload.groups }, (config.maintainPresenceState && { state: presenceState })))]; - case 1: - result = _b.sent(); - engine.transition(events.heartbeatSuccess(200)); - return [3 /*break*/, 3]; - case 2: - e_1 = _b.sent(); - if (e_1 instanceof endpoint_1.PubNubError) { - return [2 /*return*/, engine.transition(events.heartbeatFailure(e_1))]; - } - return [3 /*break*/, 3]; - case 3: return [2 /*return*/]; - } - }); - }); - })); - _this.on(effects.leave.type, (0, core_1.asyncHandler)(function (payload, _, _a) { - var leave = _a.leave, config = _a.config; - return __awaiter(_this, void 0, void 0, function () { - var result, e_2; - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - if (!!config.suppressLeaveEvents) return [3 /*break*/, 4]; - _b.label = 1; - case 1: - _b.trys.push([1, 3, , 4]); - return [4 /*yield*/, leave({ - channels: payload.channels, - channelGroups: payload.groups, - })]; - case 2: - result = _b.sent(); - return [3 /*break*/, 4]; - case 3: - e_2 = _b.sent(); - return [3 /*break*/, 4]; - case 4: return [2 /*return*/]; - } - }); - }); - })); - _this.on(effects.wait.type, (0, core_1.asyncHandler)(function (_, abortSignal, _a) { - var heartbeatDelay = _a.heartbeatDelay; - return __awaiter(_this, void 0, void 0, function () { - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - abortSignal.throwIfAborted(); - return [4 /*yield*/, heartbeatDelay()]; - case 1: - _b.sent(); - abortSignal.throwIfAborted(); - return [2 /*return*/, engine.transition(events.timesUp())]; - } - }); - }); - })); - _this.on(effects.delayedHeartbeat.type, (0, core_1.asyncHandler)(function (payload, abortSignal, _a) { - var heartbeat = _a.heartbeat, retryDelay = _a.retryDelay, presenceState = _a.presenceState, config = _a.config; - return __awaiter(_this, void 0, void 0, function () { - var result, e_3; - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - if (!(config.retryConfiguration && config.retryConfiguration.shouldRetry(payload.reason, payload.attempts))) return [3 /*break*/, 6]; - abortSignal.throwIfAborted(); - return [4 /*yield*/, retryDelay(config.retryConfiguration.getDelay(payload.attempts, payload.reason))]; - case 1: - _b.sent(); - abortSignal.throwIfAborted(); - _b.label = 2; - case 2: - _b.trys.push([2, 4, , 5]); - return [4 /*yield*/, heartbeat(__assign({ channels: payload.channels, channelGroups: payload.groups }, (config.maintainPresenceState && { state: presenceState })))]; - case 3: - result = _b.sent(); - return [2 /*return*/, engine.transition(events.heartbeatSuccess(200))]; - case 4: - e_3 = _b.sent(); - if (e_3 instanceof Error && e_3.message === 'Aborted') { - return [2 /*return*/]; - } - if (e_3 instanceof endpoint_1.PubNubError) { - return [2 /*return*/, engine.transition(events.heartbeatFailure(e_3))]; - } - return [3 /*break*/, 5]; - case 5: return [3 /*break*/, 7]; - case 6: return [2 /*return*/, engine.transition(events.heartbeatGiveup())]; - case 7: return [2 /*return*/]; - } - }); - }); - })); - _this.on(effects.emitStatus.type, (0, core_1.asyncHandler)(function (payload, _, _a) { - var emitStatus = _a.emitStatus, config = _a.config; - return __awaiter(_this, void 0, void 0, function () { - var _b; - return __generator(this, function (_c) { - if (config.announceFailedHeartbeats && ((_b = payload === null || payload === void 0 ? void 0 : payload.status) === null || _b === void 0 ? void 0 : _b.error) === true) { - emitStatus(payload.status); - } - else if (config.announceSuccessfulHeartbeats && payload.statusCode === 200) { - emitStatus(__assign(__assign({}, payload), { operation: operations_1.default.PNHeartbeatOperation, error: false })); +const core_1 = require("../core"); +const operations_1 = __importDefault(require("../../core/constants/operations")); +const pubnub_error_1 = require("../../errors/pubnub-error"); +const effects = __importStar(require("./effects")); +const events = __importStar(require("./events")); +const categories_1 = __importDefault(require("../../core/constants/categories")); +class PresenceEventEngineDispatcher extends core_1.Dispatcher { + constructor(engine, dependencies) { + super(dependencies); + this.on(effects.heartbeat.type, (0, core_1.asyncHandler)((payload_1, _1, _a) => __awaiter(this, [payload_1, _1, _a], void 0, function* (payload, _, { heartbeat, presenceState, config }) { + try { + const result = yield heartbeat(Object.assign(Object.assign({ channels: payload.channels, channelGroups: payload.groups }, (config.maintainPresenceState && { state: presenceState })), { heartbeat: config.presenceTimeout })); + engine.transition(events.heartbeatSuccess(200)); + } + catch (e) { + if (e instanceof pubnub_error_1.PubNubError) { + if (e.status && e.status.category == categories_1.default.PNCancelledCategory) + return; + return engine.transition(events.heartbeatFailure(e)); + } + } + }))); + this.on(effects.leave.type, (0, core_1.asyncHandler)((payload_2, _2, _b) => __awaiter(this, [payload_2, _2, _b], void 0, function* (payload, _, { leave, config }) { + if (!config.suppressLeaveEvents) { + try { + leave({ + channels: payload.channels, + channelGroups: payload.groups, + }); + } + catch (e) { } + } + }))); + this.on(effects.wait.type, (0, core_1.asyncHandler)((_3, abortSignal_1, _c) => __awaiter(this, [_3, abortSignal_1, _c], void 0, function* (_, abortSignal, { heartbeatDelay }) { + abortSignal.throwIfAborted(); + yield heartbeatDelay(); + abortSignal.throwIfAborted(); + return engine.transition(events.timesUp()); + }))); + this.on(effects.delayedHeartbeat.type, (0, core_1.asyncHandler)((payload_3, abortSignal_2, _d) => __awaiter(this, [payload_3, abortSignal_2, _d], void 0, function* (payload, abortSignal, { heartbeat, retryDelay, presenceState, config }) { + if (config.retryConfiguration && config.retryConfiguration.shouldRetry(payload.reason, payload.attempts)) { + abortSignal.throwIfAborted(); + yield retryDelay(config.retryConfiguration.getDelay(payload.attempts, payload.reason)); + abortSignal.throwIfAborted(); + try { + const result = yield heartbeat(Object.assign(Object.assign({ channels: payload.channels, channelGroups: payload.groups }, (config.maintainPresenceState && { state: presenceState })), { heartbeat: config.presenceTimeout })); + return engine.transition(events.heartbeatSuccess(200)); + } + catch (e) { + if (e instanceof pubnub_error_1.PubNubError) { + if (e.status && e.status.category == categories_1.default.PNCancelledCategory) + return; + return engine.transition(events.heartbeatFailure(e)); } - return [2 /*return*/]; - }); - }); - })); - return _this; + } + } + else { + return engine.transition(events.heartbeatGiveup()); + } + }))); + this.on(effects.emitStatus.type, (0, core_1.asyncHandler)((payload_4, _4, _e) => __awaiter(this, [payload_4, _4, _e], void 0, function* (payload, _, { emitStatus, config }) { + var _f; + if (config.announceFailedHeartbeats && ((_f = payload === null || payload === void 0 ? void 0 : payload.status) === null || _f === void 0 ? void 0 : _f.error) === true) { + emitStatus(payload.status); + } + else if (config.announceSuccessfulHeartbeats && payload.statusCode === 200) { + emitStatus(Object.assign(Object.assign({}, payload), { operation: operations_1.default.PNHeartbeatOperation, error: false })); + } + }))); } - return PresenceEventEngineDispatcher; -}(core_1.Dispatcher)); +} exports.PresenceEventEngineDispatcher = PresenceEventEngineDispatcher; diff --git a/lib/event-engine/presence/effects.js b/lib/event-engine/presence/effects.js index 3e6dd2887..beab7cbc6 100644 --- a/lib/event-engine/presence/effects.js +++ b/lib/event-engine/presence/effects.js @@ -1,15 +1,15 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.delayedHeartbeat = exports.wait = exports.emitStatus = exports.leave = exports.heartbeat = void 0; -var core_1 = require("../core"); -exports.heartbeat = (0, core_1.createEffect)('HEARTBEAT', function (channels, groups) { return ({ - channels: channels, - groups: groups, -}); }); -exports.leave = (0, core_1.createEffect)('LEAVE', function (channels, groups) { return ({ - channels: channels, - groups: groups, -}); }); -exports.emitStatus = (0, core_1.createEffect)('EMIT_STATUS', function (status) { return status; }); -exports.wait = (0, core_1.createManagedEffect)('WAIT', function () { return ({}); }); -exports.delayedHeartbeat = (0, core_1.createManagedEffect)('DELAYED_HEARTBEAT', function (context) { return context; }); +const core_1 = require("../core"); +exports.heartbeat = (0, core_1.createEffect)('HEARTBEAT', (channels, groups) => ({ + channels, + groups, +})); +exports.leave = (0, core_1.createEffect)('LEAVE', (channels, groups) => ({ + channels, + groups, +})); +exports.emitStatus = (0, core_1.createEffect)('EMIT_STATUS', (status) => status); +exports.wait = (0, core_1.createManagedEffect)('WAIT', () => ({})); +exports.delayedHeartbeat = (0, core_1.createManagedEffect)('DELAYED_HEARTBEAT', (context) => context); diff --git a/lib/event-engine/presence/events.js b/lib/event-engine/presence/events.js index cca3e9a06..58bdd3e8c 100644 --- a/lib/event-engine/presence/events.js +++ b/lib/event-engine/presence/events.js @@ -1,19 +1,19 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.timesUp = exports.heartbeatGiveup = exports.heartbeatFailure = exports.heartbeatSuccess = exports.leftAll = exports.left = exports.joined = exports.disconnect = exports.reconnect = void 0; -var core_1 = require("../core"); -exports.reconnect = (0, core_1.createEvent)('RECONNECT', function () { return ({}); }); -exports.disconnect = (0, core_1.createEvent)('DISCONNECT', function () { return ({}); }); -exports.joined = (0, core_1.createEvent)('JOINED', function (channels, groups) { return ({ - channels: channels, - groups: groups, -}); }); -exports.left = (0, core_1.createEvent)('LEFT', function (channels, groups) { return ({ - channels: channels, - groups: groups, -}); }); -exports.leftAll = (0, core_1.createEvent)('LEFT_ALL', function () { return ({}); }); -exports.heartbeatSuccess = (0, core_1.createEvent)('HEARTBEAT_SUCCESS', function (statusCode) { return ({ statusCode: statusCode }); }); -exports.heartbeatFailure = (0, core_1.createEvent)('HEARTBEAT_FAILURE', function (error) { return error; }); -exports.heartbeatGiveup = (0, core_1.createEvent)('HEARTBEAT_GIVEUP', function () { return ({}); }); -exports.timesUp = (0, core_1.createEvent)('TIMES_UP', function () { return ({}); }); +const core_1 = require("../core"); +exports.reconnect = (0, core_1.createEvent)('RECONNECT', () => ({})); +exports.disconnect = (0, core_1.createEvent)('DISCONNECT', () => ({})); +exports.joined = (0, core_1.createEvent)('JOINED', (channels, groups) => ({ + channels, + groups, +})); +exports.left = (0, core_1.createEvent)('LEFT', (channels, groups) => ({ + channels, + groups, +})); +exports.leftAll = (0, core_1.createEvent)('LEFT_ALL', () => ({})); +exports.heartbeatSuccess = (0, core_1.createEvent)('HEARTBEAT_SUCCESS', (statusCode) => ({ statusCode })); +exports.heartbeatFailure = (0, core_1.createEvent)('HEARTBEAT_FAILURE', (error) => error); +exports.heartbeatGiveup = (0, core_1.createEvent)('HEARTBEAT_GIVEUP', () => ({})); +exports.timesUp = (0, core_1.createEvent)('TIMES_UP', () => ({})); diff --git a/lib/event-engine/presence/presence.js b/lib/event-engine/presence/presence.js index 40c6c11f3..fbfa7c939 100644 --- a/lib/event-engine/presence/presence.js +++ b/lib/event-engine/presence/presence.js @@ -22,81 +22,47 @@ var __importStar = (this && this.__importStar) || function (mod) { __setModuleDefault(result, mod); return result; }; -var __read = (this && this.__read) || function (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; -}; -var __spreadArray = (this && this.__spreadArray) || function (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)); -}; Object.defineProperty(exports, "__esModule", { value: true }); exports.PresenceEventEngine = void 0; -var core_1 = require("../core"); -var events = __importStar(require("./events")); -var dispatcher_1 = require("./dispatcher"); -var heartbeat_inactive_1 = require("./states/heartbeat_inactive"); -var PresenceEventEngine = /** @class */ (function () { - function PresenceEventEngine(dependencies) { - var _this = this; +const core_1 = require("../core"); +const events = __importStar(require("./events")); +const dispatcher_1 = require("./dispatcher"); +const heartbeat_inactive_1 = require("./states/heartbeat_inactive"); +class PresenceEventEngine { + get _engine() { + return this.engine; + } + constructor(dependencies) { + this.dependencies = dependencies; this.engine = new core_1.Engine(); this.channels = []; this.groups = []; this.dispatcher = new dispatcher_1.PresenceEventEngineDispatcher(this.engine, dependencies); - this.dependencies = dependencies; - this._unsubscribeEngine = this.engine.subscribe(function (change) { + this._unsubscribeEngine = this.engine.subscribe((change) => { if (change.type === 'invocationDispatched') { - _this.dispatcher.dispatch(change.invocation); + this.dispatcher.dispatch(change.invocation); } }); this.engine.start(heartbeat_inactive_1.HeartbeatInactiveState, undefined); } - Object.defineProperty(PresenceEventEngine.prototype, "_engine", { - get: function () { - return this.engine; - }, - enumerable: false, - configurable: true - }); - PresenceEventEngine.prototype.join = function (_a) { - var channels = _a.channels, groups = _a.groups; - this.channels = __spreadArray(__spreadArray([], __read(this.channels), false), __read((channels !== null && channels !== void 0 ? channels : [])), false); - this.groups = __spreadArray(__spreadArray([], __read(this.groups), false), __read((groups !== null && groups !== void 0 ? groups : [])), false); + join({ channels, groups }) { + this.channels = [...this.channels, ...(channels !== null && channels !== void 0 ? channels : [])]; + this.groups = [...this.groups, ...(groups !== null && groups !== void 0 ? groups : [])]; this.engine.transition(events.joined(this.channels.slice(0), this.groups.slice(0))); - }; - PresenceEventEngine.prototype.leave = function (_a) { - var _this = this; - var channels = _a.channels, groups = _a.groups; + } + leave({ channels, groups }) { if (this.dependencies.presenceState) { - channels === null || channels === void 0 ? void 0 : channels.forEach(function (c) { return delete _this.dependencies.presenceState[c]; }); - groups === null || groups === void 0 ? void 0 : groups.forEach(function (g) { return delete _this.dependencies.presenceState[g]; }); + channels === null || channels === void 0 ? void 0 : channels.forEach((c) => delete this.dependencies.presenceState[c]); + groups === null || groups === void 0 ? void 0 : groups.forEach((g) => delete this.dependencies.presenceState[g]); } this.engine.transition(events.left(channels !== null && channels !== void 0 ? channels : [], groups !== null && groups !== void 0 ? groups : [])); - }; - PresenceEventEngine.prototype.leaveAll = function () { + } + leaveAll() { this.engine.transition(events.leftAll()); - }; - PresenceEventEngine.prototype.dispose = function () { + } + dispose() { this._unsubscribeEngine(); this.dispatcher.dispose(); - }; - return PresenceEventEngine; -}()); + } +} exports.PresenceEventEngine = PresenceEventEngine; diff --git a/lib/event-engine/presence/states/heartbeat_cooldown.js b/lib/event-engine/presence/states/heartbeat_cooldown.js index 0ee9ba6ef..5dd1a1b8d 100644 --- a/lib/event-engine/presence/states/heartbeat_cooldown.js +++ b/lib/event-engine/presence/states/heartbeat_cooldown.js @@ -1,64 +1,29 @@ "use strict"; -var __read = (this && this.__read) || function (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; -}; -var __spreadArray = (this && this.__spreadArray) || function (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)); -}; Object.defineProperty(exports, "__esModule", { value: true }); exports.HeartbeatCooldownState = void 0; -var state_1 = require("../../core/state"); -var events_1 = require("../events"); -var effects_1 = require("../effects"); -var heartbeating_1 = require("./heartbeating"); -var heartbeat_stopped_1 = require("./heartbeat_stopped"); -var heartbeat_inactive_1 = require("./heartbeat_inactive"); +const state_1 = require("../../core/state"); +const events_1 = require("../events"); +const effects_1 = require("../effects"); +const heartbeating_1 = require("./heartbeating"); +const heartbeat_stopped_1 = require("./heartbeat_stopped"); +const heartbeat_inactive_1 = require("./heartbeat_inactive"); exports.HeartbeatCooldownState = new state_1.State('HEARTBEAT_COOLDOWN'); -exports.HeartbeatCooldownState.onEnter(function () { return (0, effects_1.wait)(); }); -exports.HeartbeatCooldownState.onExit(function () { return effects_1.wait.cancel; }); -exports.HeartbeatCooldownState.on(events_1.timesUp.type, function (context, _) { - return heartbeating_1.HeartbeatingState.with({ - channels: context.channels, - groups: context.groups, - }); -}); -exports.HeartbeatCooldownState.on(events_1.joined.type, function (context, event) { - return heartbeating_1.HeartbeatingState.with({ - channels: __spreadArray(__spreadArray([], __read(context.channels), false), __read(event.payload.channels), false), - groups: __spreadArray(__spreadArray([], __read(context.groups), false), __read(event.payload.groups), false), - }); -}); -exports.HeartbeatCooldownState.on(events_1.left.type, function (context, event) { - return heartbeating_1.HeartbeatingState.with({ - channels: context.channels.filter(function (channel) { return !event.payload.channels.includes(channel); }), - groups: context.groups.filter(function (group) { return !event.payload.groups.includes(group); }), - }, [(0, effects_1.leave)(event.payload.channels, event.payload.groups)]); -}); -exports.HeartbeatCooldownState.on(events_1.disconnect.type, function (context) { - return heartbeat_stopped_1.HeartbeatStoppedState.with({ - channels: context.channels, - groups: context.groups, - }, [(0, effects_1.leave)(context.channels, context.groups)]); -}); -exports.HeartbeatCooldownState.on(events_1.leftAll.type, function (context, _) { - return heartbeat_inactive_1.HeartbeatInactiveState.with(undefined, [(0, effects_1.leave)(context.channels, context.groups)]); -}); +exports.HeartbeatCooldownState.onEnter(() => (0, effects_1.wait)()); +exports.HeartbeatCooldownState.onExit(() => effects_1.wait.cancel); +exports.HeartbeatCooldownState.on(events_1.timesUp.type, (context, _) => heartbeating_1.HeartbeatingState.with({ + channels: context.channels, + groups: context.groups, +})); +exports.HeartbeatCooldownState.on(events_1.joined.type, (context, event) => heartbeating_1.HeartbeatingState.with({ + channels: [...context.channels, ...event.payload.channels], + groups: [...context.groups, ...event.payload.groups], +})); +exports.HeartbeatCooldownState.on(events_1.left.type, (context, event) => heartbeating_1.HeartbeatingState.with({ + channels: context.channels.filter((channel) => !event.payload.channels.includes(channel)), + groups: context.groups.filter((group) => !event.payload.groups.includes(group)), +}, [(0, effects_1.leave)(event.payload.channels, event.payload.groups)])); +exports.HeartbeatCooldownState.on(events_1.disconnect.type, (context) => heartbeat_stopped_1.HeartbeatStoppedState.with({ + channels: context.channels, + groups: context.groups, +}, [(0, effects_1.leave)(context.channels, context.groups)])); +exports.HeartbeatCooldownState.on(events_1.leftAll.type, (context, _) => heartbeat_inactive_1.HeartbeatInactiveState.with(undefined, [(0, effects_1.leave)(context.channels, context.groups)])); diff --git a/lib/event-engine/presence/states/heartbeat_failed.js b/lib/event-engine/presence/states/heartbeat_failed.js index 349c75756..4ea95efa8 100644 --- a/lib/event-engine/presence/states/heartbeat_failed.js +++ b/lib/event-engine/presence/states/heartbeat_failed.js @@ -1,62 +1,27 @@ "use strict"; -var __read = (this && this.__read) || function (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; -}; -var __spreadArray = (this && this.__spreadArray) || function (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)); -}; Object.defineProperty(exports, "__esModule", { value: true }); exports.HeartbeatFailedState = void 0; -var state_1 = require("../../core/state"); -var events_1 = require("../events"); -var effects_1 = require("../effects"); -var heartbeating_1 = require("./heartbeating"); -var heartbeat_stopped_1 = require("./heartbeat_stopped"); -var heartbeat_inactive_1 = require("./heartbeat_inactive"); +const state_1 = require("../../core/state"); +const events_1 = require("../events"); +const effects_1 = require("../effects"); +const heartbeating_1 = require("./heartbeating"); +const heartbeat_stopped_1 = require("./heartbeat_stopped"); +const heartbeat_inactive_1 = require("./heartbeat_inactive"); exports.HeartbeatFailedState = new state_1.State('HEARTBEAT_FAILED'); -exports.HeartbeatFailedState.on(events_1.joined.type, function (context, event) { - return heartbeating_1.HeartbeatingState.with({ - channels: __spreadArray(__spreadArray([], __read(context.channels), false), __read(event.payload.channels), false), - groups: __spreadArray(__spreadArray([], __read(context.groups), false), __read(event.payload.groups), false), - }); -}); -exports.HeartbeatFailedState.on(events_1.left.type, function (context, event) { - return heartbeating_1.HeartbeatingState.with({ - channels: context.channels.filter(function (channel) { return !event.payload.channels.includes(channel); }), - groups: context.groups.filter(function (group) { return !event.payload.groups.includes(group); }), - }, [(0, effects_1.leave)(event.payload.channels, event.payload.groups)]); -}); -exports.HeartbeatFailedState.on(events_1.reconnect.type, function (context, _) { - return heartbeating_1.HeartbeatingState.with({ - channels: context.channels, - groups: context.groups, - }); -}); -exports.HeartbeatFailedState.on(events_1.disconnect.type, function (context, _) { - return heartbeat_stopped_1.HeartbeatStoppedState.with({ - channels: context.channels, - groups: context.groups, - }, [(0, effects_1.leave)(context.channels, context.groups)]); -}); -exports.HeartbeatFailedState.on(events_1.leftAll.type, function (context, _) { - return heartbeat_inactive_1.HeartbeatInactiveState.with(undefined, [(0, effects_1.leave)(context.channels, context.groups)]); -}); +exports.HeartbeatFailedState.on(events_1.joined.type, (context, event) => heartbeating_1.HeartbeatingState.with({ + channels: [...context.channels, ...event.payload.channels], + groups: [...context.groups, ...event.payload.groups], +})); +exports.HeartbeatFailedState.on(events_1.left.type, (context, event) => heartbeating_1.HeartbeatingState.with({ + channels: context.channels.filter((channel) => !event.payload.channels.includes(channel)), + groups: context.groups.filter((group) => !event.payload.groups.includes(group)), +}, [(0, effects_1.leave)(event.payload.channels, event.payload.groups)])); +exports.HeartbeatFailedState.on(events_1.reconnect.type, (context, _) => heartbeating_1.HeartbeatingState.with({ + channels: context.channels, + groups: context.groups, +})); +exports.HeartbeatFailedState.on(events_1.disconnect.type, (context, _) => heartbeat_stopped_1.HeartbeatStoppedState.with({ + channels: context.channels, + groups: context.groups, +}, [(0, effects_1.leave)(context.channels, context.groups)])); +exports.HeartbeatFailedState.on(events_1.leftAll.type, (context, _) => heartbeat_inactive_1.HeartbeatInactiveState.with(undefined, [(0, effects_1.leave)(context.channels, context.groups)])); diff --git a/lib/event-engine/presence/states/heartbeat_inactive.js b/lib/event-engine/presence/states/heartbeat_inactive.js index ec795611e..7bbb964c7 100644 --- a/lib/event-engine/presence/states/heartbeat_inactive.js +++ b/lib/event-engine/presence/states/heartbeat_inactive.js @@ -1,13 +1,11 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.HeartbeatInactiveState = void 0; -var state_1 = require("../../core/state"); -var events_1 = require("../events"); -var heartbeating_1 = require("./heartbeating"); +const state_1 = require("../../core/state"); +const events_1 = require("../events"); +const heartbeating_1 = require("./heartbeating"); exports.HeartbeatInactiveState = new state_1.State('HEARTBEAT_INACTIVE'); -exports.HeartbeatInactiveState.on(events_1.joined.type, function (_, event) { - return heartbeating_1.HeartbeatingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - }); -}); +exports.HeartbeatInactiveState.on(events_1.joined.type, (_, event) => heartbeating_1.HeartbeatingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, +})); diff --git a/lib/event-engine/presence/states/heartbeat_reconnecting.js b/lib/event-engine/presence/states/heartbeat_reconnecting.js index 1fb51af39..d26321ccc 100644 --- a/lib/event-engine/presence/states/heartbeat_reconnecting.js +++ b/lib/event-engine/presence/states/heartbeat_reconnecting.js @@ -1,86 +1,42 @@ "use strict"; -var __assign = (this && this.__assign) || function () { - __assign = Object.assign || function(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); -}; -var __read = (this && this.__read) || function (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; -}; -var __spreadArray = (this && this.__spreadArray) || function (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)); -}; Object.defineProperty(exports, "__esModule", { value: true }); exports.HearbeatReconnectingState = void 0; -var state_1 = require("../../core/state"); -var events_1 = require("../events"); -var effects_1 = require("../effects"); -var heartbeating_1 = require("./heartbeating"); -var heartbeat_stopped_1 = require("./heartbeat_stopped"); -var heartbeat_cooldown_1 = require("./heartbeat_cooldown"); -var heartbeat_inactive_1 = require("./heartbeat_inactive"); -var heartbeat_failed_1 = require("./heartbeat_failed"); +const state_1 = require("../../core/state"); +const events_1 = require("../events"); +const effects_1 = require("../effects"); +const heartbeating_1 = require("./heartbeating"); +const heartbeat_stopped_1 = require("./heartbeat_stopped"); +const heartbeat_cooldown_1 = require("./heartbeat_cooldown"); +const heartbeat_inactive_1 = require("./heartbeat_inactive"); +const heartbeat_failed_1 = require("./heartbeat_failed"); exports.HearbeatReconnectingState = new state_1.State('HEARBEAT_RECONNECTING'); -exports.HearbeatReconnectingState.onEnter(function (context) { return (0, effects_1.delayedHeartbeat)(context); }); -exports.HearbeatReconnectingState.onExit(function () { return effects_1.delayedHeartbeat.cancel; }); -exports.HearbeatReconnectingState.on(events_1.joined.type, function (context, event) { - return heartbeating_1.HeartbeatingState.with({ - channels: __spreadArray(__spreadArray([], __read(context.channels), false), __read(event.payload.channels), false), - groups: __spreadArray(__spreadArray([], __read(context.groups), false), __read(event.payload.groups), false), - }); -}); -exports.HearbeatReconnectingState.on(events_1.left.type, function (context, event) { - return heartbeating_1.HeartbeatingState.with({ - channels: context.channels.filter(function (channel) { return !event.payload.channels.includes(channel); }), - groups: context.groups.filter(function (group) { return !event.payload.groups.includes(group); }), - }, [(0, effects_1.leave)(event.payload.channels, event.payload.groups)]); -}); -exports.HearbeatReconnectingState.on(events_1.disconnect.type, function (context, _) { +exports.HearbeatReconnectingState.onEnter((context) => (0, effects_1.delayedHeartbeat)(context)); +exports.HearbeatReconnectingState.onExit(() => effects_1.delayedHeartbeat.cancel); +exports.HearbeatReconnectingState.on(events_1.joined.type, (context, event) => heartbeating_1.HeartbeatingState.with({ + channels: [...context.channels, ...event.payload.channels], + groups: [...context.groups, ...event.payload.groups], +})); +exports.HearbeatReconnectingState.on(events_1.left.type, (context, event) => heartbeating_1.HeartbeatingState.with({ + channels: context.channels.filter((channel) => !event.payload.channels.includes(channel)), + groups: context.groups.filter((group) => !event.payload.groups.includes(group)), +}, [(0, effects_1.leave)(event.payload.channels, event.payload.groups)])); +exports.HearbeatReconnectingState.on(events_1.disconnect.type, (context, _) => { heartbeat_stopped_1.HeartbeatStoppedState.with({ channels: context.channels, groups: context.groups, }, [(0, effects_1.leave)(context.channels, context.groups)]); }); -exports.HearbeatReconnectingState.on(events_1.heartbeatSuccess.type, function (context, event) { +exports.HearbeatReconnectingState.on(events_1.heartbeatSuccess.type, (context, event) => { return heartbeat_cooldown_1.HeartbeatCooldownState.with({ channels: context.channels, groups: context.groups, }); }); -exports.HearbeatReconnectingState.on(events_1.heartbeatFailure.type, function (context, event) { - return exports.HearbeatReconnectingState.with(__assign(__assign({}, context), { attempts: context.attempts + 1, reason: event.payload })); -}); -exports.HearbeatReconnectingState.on(events_1.heartbeatGiveup.type, function (context, event) { +exports.HearbeatReconnectingState.on(events_1.heartbeatFailure.type, (context, event) => exports.HearbeatReconnectingState.with(Object.assign(Object.assign({}, context), { attempts: context.attempts + 1, reason: event.payload }))); +exports.HearbeatReconnectingState.on(events_1.heartbeatGiveup.type, (context, event) => { return heartbeat_failed_1.HeartbeatFailedState.with({ channels: context.channels, groups: context.groups, }); }); -exports.HearbeatReconnectingState.on(events_1.leftAll.type, function (context, _) { - return heartbeat_inactive_1.HeartbeatInactiveState.with(undefined, [(0, effects_1.leave)(context.channels, context.groups)]); -}); +exports.HearbeatReconnectingState.on(events_1.leftAll.type, (context, _) => heartbeat_inactive_1.HeartbeatInactiveState.with(undefined, [(0, effects_1.leave)(context.channels, context.groups)])); diff --git a/lib/event-engine/presence/states/heartbeat_stopped.js b/lib/event-engine/presence/states/heartbeat_stopped.js index 6146a4266..6c162f433 100644 --- a/lib/event-engine/presence/states/heartbeat_stopped.js +++ b/lib/event-engine/presence/states/heartbeat_stopped.js @@ -1,52 +1,21 @@ "use strict"; -var __read = (this && this.__read) || function (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; -}; -var __spreadArray = (this && this.__spreadArray) || function (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)); -}; Object.defineProperty(exports, "__esModule", { value: true }); exports.HeartbeatStoppedState = void 0; -var state_1 = require("../../core/state"); -var events_1 = require("../events"); -var heartbeat_inactive_1 = require("./heartbeat_inactive"); -var heartbeating_1 = require("./heartbeating"); +const state_1 = require("../../core/state"); +const events_1 = require("../events"); +const heartbeat_inactive_1 = require("./heartbeat_inactive"); +const heartbeating_1 = require("./heartbeating"); exports.HeartbeatStoppedState = new state_1.State('HEARTBEAT_STOPPED'); -exports.HeartbeatStoppedState.on(events_1.joined.type, function (context, event) { - return exports.HeartbeatStoppedState.with({ - channels: __spreadArray(__spreadArray([], __read(context.channels), false), __read(event.payload.channels), false), - groups: __spreadArray(__spreadArray([], __read(context.groups), false), __read(event.payload.groups), false), - }); -}); -exports.HeartbeatStoppedState.on(events_1.left.type, function (context, event) { - return exports.HeartbeatStoppedState.with({ - channels: context.channels.filter(function (channel) { return !event.payload.channels.includes(channel); }), - groups: context.groups.filter(function (group) { return !event.payload.groups.includes(group); }), - }); -}); -exports.HeartbeatStoppedState.on(events_1.reconnect.type, function (context, _) { - return heartbeating_1.HeartbeatingState.with({ - channels: context.channels, - groups: context.groups, - }); -}); -exports.HeartbeatStoppedState.on(events_1.leftAll.type, function (context, _) { return heartbeat_inactive_1.HeartbeatInactiveState.with(undefined); }); +exports.HeartbeatStoppedState.on(events_1.joined.type, (context, event) => exports.HeartbeatStoppedState.with({ + channels: [...context.channels, ...event.payload.channels], + groups: [...context.groups, ...event.payload.groups], +})); +exports.HeartbeatStoppedState.on(events_1.left.type, (context, event) => exports.HeartbeatStoppedState.with({ + channels: context.channels.filter((channel) => !event.payload.channels.includes(channel)), + groups: context.groups.filter((group) => !event.payload.groups.includes(group)), +})); +exports.HeartbeatStoppedState.on(events_1.reconnect.type, (context, _) => heartbeating_1.HeartbeatingState.with({ + channels: context.channels, + groups: context.groups, +})); +exports.HeartbeatStoppedState.on(events_1.leftAll.type, (context, _) => heartbeat_inactive_1.HeartbeatInactiveState.with(undefined)); diff --git a/lib/event-engine/presence/states/heartbeating.js b/lib/event-engine/presence/states/heartbeating.js index 675f30d64..588b414ee 100644 --- a/lib/event-engine/presence/states/heartbeating.js +++ b/lib/event-engine/presence/states/heartbeating.js @@ -1,78 +1,36 @@ "use strict"; -var __assign = (this && this.__assign) || function () { - __assign = Object.assign || function(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); -}; -var __read = (this && this.__read) || function (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; -}; -var __spreadArray = (this && this.__spreadArray) || function (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)); -}; Object.defineProperty(exports, "__esModule", { value: true }); exports.HeartbeatingState = void 0; -var state_1 = require("../../core/state"); -var events_1 = require("../events"); -var effects_1 = require("../effects"); -var heartbeat_cooldown_1 = require("./heartbeat_cooldown"); -var heartbeat_reconnecting_1 = require("./heartbeat_reconnecting"); -var heartbeat_stopped_1 = require("./heartbeat_stopped"); -var heartbeat_inactive_1 = require("./heartbeat_inactive"); +const state_1 = require("../../core/state"); +const events_1 = require("../events"); +const effects_1 = require("../effects"); +const heartbeat_cooldown_1 = require("./heartbeat_cooldown"); +const heartbeat_reconnecting_1 = require("./heartbeat_reconnecting"); +const heartbeat_stopped_1 = require("./heartbeat_stopped"); +const heartbeat_inactive_1 = require("./heartbeat_inactive"); exports.HeartbeatingState = new state_1.State('HEARTBEATING'); -exports.HeartbeatingState.onEnter(function (context) { return (0, effects_1.heartbeat)(context.channels, context.groups); }); -exports.HeartbeatingState.on(events_1.heartbeatSuccess.type, function (context, event) { +exports.HeartbeatingState.onEnter((context) => (0, effects_1.heartbeat)(context.channels, context.groups)); +exports.HeartbeatingState.on(events_1.heartbeatSuccess.type, (context, event) => { return heartbeat_cooldown_1.HeartbeatCooldownState.with({ channels: context.channels, groups: context.groups, }); }); -exports.HeartbeatingState.on(events_1.joined.type, function (context, event) { +exports.HeartbeatingState.on(events_1.joined.type, (context, event) => exports.HeartbeatingState.with({ + channels: [...context.channels, ...event.payload.channels], + groups: [...context.groups, ...event.payload.groups], +})); +exports.HeartbeatingState.on(events_1.left.type, (context, event) => { return exports.HeartbeatingState.with({ - channels: __spreadArray(__spreadArray([], __read(context.channels), false), __read(event.payload.channels), false), - groups: __spreadArray(__spreadArray([], __read(context.groups), false), __read(event.payload.groups), false), - }); -}); -exports.HeartbeatingState.on(events_1.left.type, function (context, event) { - return exports.HeartbeatingState.with({ - channels: context.channels.filter(function (channel) { return !event.payload.channels.includes(channel); }), - groups: context.groups.filter(function (group) { return !event.payload.groups.includes(group); }), + channels: context.channels.filter((channel) => !event.payload.channels.includes(channel)), + groups: context.groups.filter((group) => !event.payload.groups.includes(group)), }, [(0, effects_1.leave)(event.payload.channels, event.payload.groups)]); }); -exports.HeartbeatingState.on(events_1.heartbeatFailure.type, function (context, event) { - return heartbeat_reconnecting_1.HearbeatReconnectingState.with(__assign(__assign({}, context), { attempts: 0, reason: event.payload })); -}); -exports.HeartbeatingState.on(events_1.disconnect.type, function (context) { - return heartbeat_stopped_1.HeartbeatStoppedState.with({ - channels: context.channels, - groups: context.groups, - }, [(0, effects_1.leave)(context.channels, context.groups)]); -}); -exports.HeartbeatingState.on(events_1.leftAll.type, function (context, _) { - return heartbeat_inactive_1.HeartbeatInactiveState.with(undefined, [(0, effects_1.leave)(context.channels, context.groups)]); +exports.HeartbeatingState.on(events_1.heartbeatFailure.type, (context, event) => { + return heartbeat_reconnecting_1.HearbeatReconnectingState.with(Object.assign(Object.assign({}, context), { attempts: 0, reason: event.payload })); }); +exports.HeartbeatingState.on(events_1.disconnect.type, (context) => heartbeat_stopped_1.HeartbeatStoppedState.with({ + channels: context.channels, + groups: context.groups, +}, [(0, effects_1.leave)(context.channels, context.groups)])); +exports.HeartbeatingState.on(events_1.leftAll.type, (context, _) => heartbeat_inactive_1.HeartbeatInactiveState.with(undefined, [(0, effects_1.leave)(context.channels, context.groups)])); diff --git a/lib/event-engine/states/handshake_failed.js b/lib/event-engine/states/handshake_failed.js index 658ff855d..ad658adb6 100644 --- a/lib/event-engine/states/handshake_failed.js +++ b/lib/event-engine/states/handshake_failed.js @@ -1,26 +1,22 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.HandshakeFailedState = void 0; -var state_1 = require("../core/state"); -var events_1 = require("../events"); -var handshaking_1 = require("./handshaking"); -var unsubscribed_1 = require("./unsubscribed"); +const state_1 = require("../core/state"); +const events_1 = require("../events"); +const handshaking_1 = require("./handshaking"); +const unsubscribed_1 = require("./unsubscribed"); exports.HandshakeFailedState = new state_1.State('HANDSHAKE_FAILED'); -exports.HandshakeFailedState.on(events_1.subscriptionChange.type, function (context, event) { - return handshaking_1.HandshakingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: context.cursor, - }); -}); -exports.HandshakeFailedState.on(events_1.reconnect.type, function (context, event) { - return handshaking_1.HandshakingState.with({ - channels: context.channels, - groups: context.groups, - cursor: event.payload.cursor || context.cursor, - }); -}); -exports.HandshakeFailedState.on(events_1.restore.type, function (context, event) { +exports.HandshakeFailedState.on(events_1.subscriptionChange.type, (context, event) => handshaking_1.HandshakingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: context.cursor, +})); +exports.HandshakeFailedState.on(events_1.reconnect.type, (context, event) => handshaking_1.HandshakingState.with({ + channels: context.channels, + groups: context.groups, + cursor: event.payload.cursor || context.cursor, +})); +exports.HandshakeFailedState.on(events_1.restore.type, (context, event) => { var _a, _b; return handshaking_1.HandshakingState.with({ channels: event.payload.channels, @@ -31,4 +27,4 @@ exports.HandshakeFailedState.on(events_1.restore.type, function (context, event) }, }); }); -exports.HandshakeFailedState.on(events_1.unsubscribeAll.type, function (_) { return unsubscribed_1.UnsubscribedState.with(); }); +exports.HandshakeFailedState.on(events_1.unsubscribeAll.type, (_) => unsubscribed_1.UnsubscribedState.with()); diff --git a/lib/event-engine/states/handshake_failure.js b/lib/event-engine/states/handshake_failure.js deleted file mode 100644 index 4f682098a..000000000 --- a/lib/event-engine/states/handshake_failure.js +++ /dev/null @@ -1,26 +0,0 @@ -"use strict"; -var __assign = (this && this.__assign) || function () { - __assign = Object.assign || function(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); -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.HandshakeFailureState = void 0; -var state_1 = require("../core/state"); -var events_1 = require("../events"); -var handshake_stopped_1 = require("./handshake_stopped"); -var handshaking_1 = require("./handshaking"); -exports.HandshakeFailureState = new state_1.State('HANDSHAKE_FAILURE'); -exports.HandshakeFailureState.on(events_1.disconnect.type, function (context) { - return handshake_stopped_1.HandshakeStoppedState.with({ - channels: context.channels, - groups: context.groups, - }); -}); -exports.HandshakeFailureState.on(events_1.reconnect.type, function (context) { return handshaking_1.HandshakingState.with(__assign({}, context)); }); diff --git a/lib/event-engine/states/handshake_reconnecting.js b/lib/event-engine/states/handshake_reconnecting.js index 9f5339e73..6c95593aa 100644 --- a/lib/event-engine/states/handshake_reconnecting.js +++ b/lib/event-engine/states/handshake_reconnecting.js @@ -1,35 +1,24 @@ "use strict"; -var __assign = (this && this.__assign) || function () { - __assign = Object.assign || function(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); -}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.HandshakeReconnectingState = void 0; -var state_1 = require("../core/state"); -var effects_1 = require("../effects"); -var events_1 = require("../events"); -var handshake_failed_1 = require("./handshake_failed"); -var handshake_stopped_1 = require("./handshake_stopped"); -var handshaking_1 = require("./handshaking"); -var receiving_1 = require("./receiving"); -var unsubscribed_1 = require("./unsubscribed"); -var categories_1 = __importDefault(require("../../core/constants/categories")); +const state_1 = require("../core/state"); +const effects_1 = require("../effects"); +const events_1 = require("../events"); +const handshake_failed_1 = require("./handshake_failed"); +const handshake_stopped_1 = require("./handshake_stopped"); +const handshaking_1 = require("./handshaking"); +const receiving_1 = require("./receiving"); +const unsubscribed_1 = require("./unsubscribed"); +const categories_1 = __importDefault(require("../../core/constants/categories")); exports.HandshakeReconnectingState = new state_1.State('HANDSHAKE_RECONNECTING'); -exports.HandshakeReconnectingState.onEnter(function (context) { return (0, effects_1.handshakeReconnect)(context); }); -exports.HandshakeReconnectingState.onExit(function () { return effects_1.handshakeReconnect.cancel; }); -exports.HandshakeReconnectingState.on(events_1.handshakeReconnectSuccess.type, function (context, event) { +exports.HandshakeReconnectingState.onEnter((context) => (0, effects_1.handshakeReconnect)(context)); +exports.HandshakeReconnectingState.onExit(() => effects_1.handshakeReconnect.cancel); +exports.HandshakeReconnectingState.on(events_1.handshakeReconnectSuccess.type, (context, event) => { var _a, _b; - var cursor = { + const cursor = { timetoken: !!((_a = context.cursor) === null || _a === void 0 ? void 0 : _a.timetoken) ? (_b = context.cursor) === null || _b === void 0 ? void 0 : _b.timetoken : event.payload.cursor.timetoken, region: event.payload.cursor.region, }; @@ -39,10 +28,8 @@ exports.HandshakeReconnectingState.on(events_1.handshakeReconnectSuccess.type, f cursor: cursor, }, [(0, effects_1.emitStatus)({ category: categories_1.default.PNConnectedCategory })]); }); -exports.HandshakeReconnectingState.on(events_1.handshakeReconnectFailure.type, function (context, event) { - return exports.HandshakeReconnectingState.with(__assign(__assign({}, context), { attempts: context.attempts + 1, reason: event.payload })); -}); -exports.HandshakeReconnectingState.on(events_1.handshakeReconnectGiveup.type, function (context, event) { +exports.HandshakeReconnectingState.on(events_1.handshakeReconnectFailure.type, (context, event) => exports.HandshakeReconnectingState.with(Object.assign(Object.assign({}, context), { attempts: context.attempts + 1, reason: event.payload }))); +exports.HandshakeReconnectingState.on(events_1.handshakeReconnectGiveup.type, (context, event) => { var _a; return handshake_failed_1.HandshakeFailedState.with({ groups: context.groups, @@ -51,21 +38,17 @@ exports.HandshakeReconnectingState.on(events_1.handshakeReconnectGiveup.type, fu reason: event.payload, }, [(0, effects_1.emitStatus)({ category: categories_1.default.PNConnectionErrorCategory, error: (_a = event.payload) === null || _a === void 0 ? void 0 : _a.message })]); }); -exports.HandshakeReconnectingState.on(events_1.disconnect.type, function (context) { - return handshake_stopped_1.HandshakeStoppedState.with({ - channels: context.channels, - groups: context.groups, - cursor: context.cursor, - }); -}); -exports.HandshakeReconnectingState.on(events_1.subscriptionChange.type, function (context, event) { - return handshaking_1.HandshakingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: context.cursor, - }); -}); -exports.HandshakeReconnectingState.on(events_1.restore.type, function (context, event) { +exports.HandshakeReconnectingState.on(events_1.disconnect.type, (context) => handshake_stopped_1.HandshakeStoppedState.with({ + channels: context.channels, + groups: context.groups, + cursor: context.cursor, +})); +exports.HandshakeReconnectingState.on(events_1.subscriptionChange.type, (context, event) => handshaking_1.HandshakingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: context.cursor, +})); +exports.HandshakeReconnectingState.on(events_1.restore.type, (context, event) => { var _a, _b; return handshaking_1.HandshakingState.with({ channels: event.payload.channels, @@ -76,4 +59,4 @@ exports.HandshakeReconnectingState.on(events_1.restore.type, function (context, }, }); }); -exports.HandshakeReconnectingState.on(events_1.unsubscribeAll.type, function (_) { return unsubscribed_1.UnsubscribedState.with(undefined); }); +exports.HandshakeReconnectingState.on(events_1.unsubscribeAll.type, (_) => unsubscribed_1.UnsubscribedState.with(undefined)); diff --git a/lib/event-engine/states/handshake_stopped.js b/lib/event-engine/states/handshake_stopped.js index 3e2838fb9..1cad18d75 100644 --- a/lib/event-engine/states/handshake_stopped.js +++ b/lib/event-engine/states/handshake_stopped.js @@ -1,33 +1,18 @@ "use strict"; -var __assign = (this && this.__assign) || function () { - __assign = Object.assign || function(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); -}; Object.defineProperty(exports, "__esModule", { value: true }); exports.HandshakeStoppedState = void 0; -var state_1 = require("../core/state"); -var events_1 = require("../events"); -var handshaking_1 = require("./handshaking"); -var unsubscribed_1 = require("./unsubscribed"); +const state_1 = require("../core/state"); +const events_1 = require("../events"); +const handshaking_1 = require("./handshaking"); +const unsubscribed_1 = require("./unsubscribed"); exports.HandshakeStoppedState = new state_1.State('HANDSHAKE_STOPPED'); -exports.HandshakeStoppedState.on(events_1.subscriptionChange.type, function (context, event) { - return exports.HandshakeStoppedState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: context.cursor, - }); -}); -exports.HandshakeStoppedState.on(events_1.reconnect.type, function (context, event) { - return handshaking_1.HandshakingState.with(__assign(__assign({}, context), { cursor: event.payload.cursor || context.cursor })); -}); -exports.HandshakeStoppedState.on(events_1.restore.type, function (context, event) { +exports.HandshakeStoppedState.on(events_1.subscriptionChange.type, (context, event) => exports.HandshakeStoppedState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: context.cursor, +})); +exports.HandshakeStoppedState.on(events_1.reconnect.type, (context, event) => handshaking_1.HandshakingState.with(Object.assign(Object.assign({}, context), { cursor: event.payload.cursor || context.cursor }))); +exports.HandshakeStoppedState.on(events_1.restore.type, (context, event) => { var _a; return exports.HandshakeStoppedState.with({ channels: event.payload.channels, @@ -38,4 +23,4 @@ exports.HandshakeStoppedState.on(events_1.restore.type, function (context, event }, }); }); -exports.HandshakeStoppedState.on(events_1.unsubscribeAll.type, function (_) { return unsubscribed_1.UnsubscribedState.with(); }); +exports.HandshakeStoppedState.on(events_1.unsubscribeAll.type, (_) => unsubscribed_1.UnsubscribedState.with()); diff --git a/lib/event-engine/states/handshaking.js b/lib/event-engine/states/handshaking.js index acb960681..13d3c1cca 100644 --- a/lib/event-engine/states/handshaking.js +++ b/lib/event-engine/states/handshaking.js @@ -4,18 +4,18 @@ var __importDefault = (this && this.__importDefault) || function (mod) { }; Object.defineProperty(exports, "__esModule", { value: true }); exports.HandshakingState = void 0; -var state_1 = require("../core/state"); -var effects_1 = require("../effects"); -var events_1 = require("../events"); -var handshake_reconnecting_1 = require("./handshake_reconnecting"); -var handshake_stopped_1 = require("./handshake_stopped"); -var receiving_1 = require("./receiving"); -var unsubscribed_1 = require("./unsubscribed"); -var categories_1 = __importDefault(require("../../core/constants/categories")); +const state_1 = require("../core/state"); +const effects_1 = require("../effects"); +const events_1 = require("../events"); +const handshake_reconnecting_1 = require("./handshake_reconnecting"); +const handshake_stopped_1 = require("./handshake_stopped"); +const receiving_1 = require("./receiving"); +const unsubscribed_1 = require("./unsubscribed"); +const categories_1 = __importDefault(require("../../core/constants/categories")); exports.HandshakingState = new state_1.State('HANDSHAKING'); -exports.HandshakingState.onEnter(function (context) { return (0, effects_1.handshake)(context.channels, context.groups); }); -exports.HandshakingState.onExit(function () { return effects_1.handshake.cancel; }); -exports.HandshakingState.on(events_1.subscriptionChange.type, function (context, event) { +exports.HandshakingState.onEnter((context) => (0, effects_1.handshake)(context.channels, context.groups)); +exports.HandshakingState.onExit(() => effects_1.handshake.cancel); +exports.HandshakingState.on(events_1.subscriptionChange.type, (context, event) => { if (event.payload.channels.length === 0 && event.payload.groups.length === 0) { return unsubscribed_1.UnsubscribedState.with(undefined); } @@ -25,7 +25,7 @@ exports.HandshakingState.on(events_1.subscriptionChange.type, function (context, cursor: context.cursor, }); }); -exports.HandshakingState.on(events_1.handshakeSuccess.type, function (context, event) { +exports.HandshakingState.on(events_1.handshakeSuccess.type, (context, event) => { var _a, _b; return receiving_1.ReceivingState.with({ channels: context.channels, @@ -40,7 +40,7 @@ exports.HandshakingState.on(events_1.handshakeSuccess.type, function (context, e }), ]); }); -exports.HandshakingState.on(events_1.handshakeFailure.type, function (context, event) { +exports.HandshakingState.on(events_1.handshakeFailure.type, (context, event) => { return handshake_reconnecting_1.HandshakeReconnectingState.with({ channels: context.channels, groups: context.groups, @@ -49,14 +49,12 @@ exports.HandshakingState.on(events_1.handshakeFailure.type, function (context, e reason: event.payload, }); }); -exports.HandshakingState.on(events_1.disconnect.type, function (context) { - return handshake_stopped_1.HandshakeStoppedState.with({ - channels: context.channels, - groups: context.groups, - cursor: context.cursor, - }); -}); -exports.HandshakingState.on(events_1.restore.type, function (context, event) { +exports.HandshakingState.on(events_1.disconnect.type, (context) => handshake_stopped_1.HandshakeStoppedState.with({ + channels: context.channels, + groups: context.groups, + cursor: context.cursor, +})); +exports.HandshakingState.on(events_1.restore.type, (context, event) => { var _a; return exports.HandshakingState.with({ channels: event.payload.channels, @@ -67,4 +65,4 @@ exports.HandshakingState.on(events_1.restore.type, function (context, event) { }, }); }); -exports.HandshakingState.on(events_1.unsubscribeAll.type, function (_) { return unsubscribed_1.UnsubscribedState.with(); }); +exports.HandshakingState.on(events_1.unsubscribeAll.type, (_) => unsubscribed_1.UnsubscribedState.with()); diff --git a/lib/event-engine/states/receive_failed.js b/lib/event-engine/states/receive_failed.js index 6a880df98..d6af9bfd3 100644 --- a/lib/event-engine/states/receive_failed.js +++ b/lib/event-engine/states/receive_failed.js @@ -1,12 +1,12 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ReceiveFailedState = void 0; -var state_1 = require("../core/state"); -var events_1 = require("../events"); -var handshaking_1 = require("./handshaking"); -var unsubscribed_1 = require("./unsubscribed"); +const state_1 = require("../core/state"); +const events_1 = require("../events"); +const handshaking_1 = require("./handshaking"); +const unsubscribed_1 = require("./unsubscribed"); exports.ReceiveFailedState = new state_1.State('RECEIVE_FAILED'); -exports.ReceiveFailedState.on(events_1.reconnect.type, function (context, event) { +exports.ReceiveFailedState.on(events_1.reconnect.type, (context, event) => { var _a; return handshaking_1.HandshakingState.with({ channels: context.channels, @@ -17,21 +17,17 @@ exports.ReceiveFailedState.on(events_1.reconnect.type, function (context, event) }, }); }); -exports.ReceiveFailedState.on(events_1.subscriptionChange.type, function (context, event) { - return handshaking_1.HandshakingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: context.cursor, - }); -}); -exports.ReceiveFailedState.on(events_1.restore.type, function (context, event) { - return handshaking_1.HandshakingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: { - timetoken: event.payload.cursor.timetoken, - region: event.payload.cursor.region || context.cursor.region, - }, - }); -}); -exports.ReceiveFailedState.on(events_1.unsubscribeAll.type, function (_) { return unsubscribed_1.UnsubscribedState.with(undefined); }); +exports.ReceiveFailedState.on(events_1.subscriptionChange.type, (context, event) => handshaking_1.HandshakingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: context.cursor, +})); +exports.ReceiveFailedState.on(events_1.restore.type, (context, event) => handshaking_1.HandshakingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: { + timetoken: event.payload.cursor.timetoken, + region: event.payload.cursor.region || context.cursor.region, + }, +})); +exports.ReceiveFailedState.on(events_1.unsubscribeAll.type, (_) => unsubscribed_1.UnsubscribedState.with(undefined)); diff --git a/lib/event-engine/states/receive_failure.js b/lib/event-engine/states/receive_failure.js deleted file mode 100644 index 4eb9e2b72..000000000 --- a/lib/event-engine/states/receive_failure.js +++ /dev/null @@ -1,38 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.ReceiveFailureState = void 0; -var state_1 = require("../core/state"); -var events_1 = require("../events"); -var handshaking_1 = require("./handshaking"); -var receive_stopped_1 = require("./receive_stopped"); -var unsubscribed_1 = require("./unsubscribed"); -exports.ReceiveFailureState = new state_1.State('RECEIVE_FAILED'); -exports.ReceiveFailureState.on(events_1.reconnectingRetry.type, function (context) { - return handshaking_1.HandshakingState.with({ - channels: context.channels, - groups: context.groups, - timetoken: context.cursor.timetoken, - }); -}); -exports.ReceiveFailureState.on(events_1.disconnect.type, function (context) { - return receive_stopped_1.ReceiveStoppedState.with({ - channels: context.channels, - groups: context.groups, - cursor: context.cursor, - }); -}); -exports.ReceiveFailureState.on(events_1.subscriptionChange.type, function (_, event) { - return handshaking_1.HandshakingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - timetoken: event.payload.timetoken, - }); -}); -exports.ReceiveFailureState.on(events_1.restore.type, function (_, event) { - return handshaking_1.HandshakingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - timetoken: event.payload.timetoken, - }); -}); -exports.ReceiveFailureState.on(events_1.unsubscribeAll.type, function (_) { return unsubscribed_1.UnsubscribedState.with(undefined); }); diff --git a/lib/event-engine/states/receive_reconnecting.js b/lib/event-engine/states/receive_reconnecting.js index 7f0559d5e..8f98426f1 100644 --- a/lib/event-engine/states/receive_reconnecting.js +++ b/lib/event-engine/states/receive_reconnecting.js @@ -1,42 +1,27 @@ "use strict"; -var __assign = (this && this.__assign) || function () { - __assign = Object.assign || function(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); -}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ReceiveReconnectingState = void 0; -var state_1 = require("../core/state"); -var effects_1 = require("../effects"); -var events_1 = require("../events"); -var receiving_1 = require("./receiving"); -var receive_failed_1 = require("./receive_failed"); -var receive_stopped_1 = require("./receive_stopped"); -var unsubscribed_1 = require("./unsubscribed"); -var categories_1 = __importDefault(require("../../core/constants/categories")); +const state_1 = require("../core/state"); +const effects_1 = require("../effects"); +const events_1 = require("../events"); +const receiving_1 = require("./receiving"); +const receive_failed_1 = require("./receive_failed"); +const receive_stopped_1 = require("./receive_stopped"); +const unsubscribed_1 = require("./unsubscribed"); +const categories_1 = __importDefault(require("../../core/constants/categories")); exports.ReceiveReconnectingState = new state_1.State('RECEIVE_RECONNECTING'); -exports.ReceiveReconnectingState.onEnter(function (context) { return (0, effects_1.receiveReconnect)(context); }); -exports.ReceiveReconnectingState.onExit(function () { return effects_1.receiveReconnect.cancel; }); -exports.ReceiveReconnectingState.on(events_1.receiveReconnectSuccess.type, function (context, event) { - return receiving_1.ReceivingState.with({ - channels: context.channels, - groups: context.groups, - cursor: event.payload.cursor, - }, [(0, effects_1.emitMessages)(event.payload.events)]); -}); -exports.ReceiveReconnectingState.on(events_1.receiveReconnectFailure.type, function (context, event) { - return exports.ReceiveReconnectingState.with(__assign(__assign({}, context), { attempts: context.attempts + 1, reason: event.payload })); -}); -exports.ReceiveReconnectingState.on(events_1.receiveReconnectGiveup.type, function (context, event) { +exports.ReceiveReconnectingState.onEnter((context) => (0, effects_1.receiveReconnect)(context)); +exports.ReceiveReconnectingState.onExit(() => effects_1.receiveReconnect.cancel); +exports.ReceiveReconnectingState.on(events_1.receiveReconnectSuccess.type, (context, event) => receiving_1.ReceivingState.with({ + channels: context.channels, + groups: context.groups, + cursor: event.payload.cursor, +}, [(0, effects_1.emitMessages)(event.payload.events)])); +exports.ReceiveReconnectingState.on(events_1.receiveReconnectFailure.type, (context, event) => exports.ReceiveReconnectingState.with(Object.assign(Object.assign({}, context), { attempts: context.attempts + 1, reason: event.payload }))); +exports.ReceiveReconnectingState.on(events_1.receiveReconnectGiveup.type, (context, event) => { var _a; return receive_failed_1.ReceiveFailedState.with({ groups: context.groups, @@ -45,30 +30,22 @@ exports.ReceiveReconnectingState.on(events_1.receiveReconnectGiveup.type, functi reason: event.payload, }, [(0, effects_1.emitStatus)({ category: categories_1.default.PNDisconnectedUnexpectedlyCategory, error: (_a = event.payload) === null || _a === void 0 ? void 0 : _a.message })]); }); -exports.ReceiveReconnectingState.on(events_1.disconnect.type, function (context) { - return receive_stopped_1.ReceiveStoppedState.with({ - channels: context.channels, - groups: context.groups, - cursor: context.cursor, - }, [(0, effects_1.emitStatus)({ category: categories_1.default.PNDisconnectedCategory })]); -}); -exports.ReceiveReconnectingState.on(events_1.restore.type, function (context, event) { - return receiving_1.ReceivingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: { - timetoken: event.payload.cursor.timetoken, - region: event.payload.cursor.region || context.cursor.region, - }, - }); -}); -exports.ReceiveReconnectingState.on(events_1.subscriptionChange.type, function (context, event) { - return receiving_1.ReceivingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: context.cursor, - }); -}); -exports.ReceiveReconnectingState.on(events_1.unsubscribeAll.type, function (_) { - return unsubscribed_1.UnsubscribedState.with(undefined, [(0, effects_1.emitStatus)({ category: categories_1.default.PNDisconnectedCategory })]); -}); +exports.ReceiveReconnectingState.on(events_1.disconnect.type, (context) => receive_stopped_1.ReceiveStoppedState.with({ + channels: context.channels, + groups: context.groups, + cursor: context.cursor, +}, [(0, effects_1.emitStatus)({ category: categories_1.default.PNDisconnectedCategory })])); +exports.ReceiveReconnectingState.on(events_1.restore.type, (context, event) => receiving_1.ReceivingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: { + timetoken: event.payload.cursor.timetoken, + region: event.payload.cursor.region || context.cursor.region, + }, +})); +exports.ReceiveReconnectingState.on(events_1.subscriptionChange.type, (context, event) => receiving_1.ReceivingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: context.cursor, +})); +exports.ReceiveReconnectingState.on(events_1.unsubscribeAll.type, (_) => unsubscribed_1.UnsubscribedState.with(undefined, [(0, effects_1.emitStatus)({ category: categories_1.default.PNDisconnectedCategory })])); diff --git a/lib/event-engine/states/receive_stopped.js b/lib/event-engine/states/receive_stopped.js index ea0eb5a13..1078a2e4b 100644 --- a/lib/event-engine/states/receive_stopped.js +++ b/lib/event-engine/states/receive_stopped.js @@ -1,29 +1,25 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ReceiveStoppedState = void 0; -var state_1 = require("../core/state"); -var events_1 = require("../events"); -var handshaking_1 = require("./handshaking"); -var unsubscribed_1 = require("./unsubscribed"); +const state_1 = require("../core/state"); +const events_1 = require("../events"); +const handshaking_1 = require("./handshaking"); +const unsubscribed_1 = require("./unsubscribed"); exports.ReceiveStoppedState = new state_1.State('RECEIVE_STOPPED'); -exports.ReceiveStoppedState.on(events_1.subscriptionChange.type, function (context, event) { - return exports.ReceiveStoppedState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: context.cursor, - }); -}); -exports.ReceiveStoppedState.on(events_1.restore.type, function (context, event) { - return exports.ReceiveStoppedState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: { - timetoken: event.payload.cursor.timetoken, - region: event.payload.cursor.region || context.cursor.region, - }, - }); -}); -exports.ReceiveStoppedState.on(events_1.reconnect.type, function (context, event) { +exports.ReceiveStoppedState.on(events_1.subscriptionChange.type, (context, event) => exports.ReceiveStoppedState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: context.cursor, +})); +exports.ReceiveStoppedState.on(events_1.restore.type, (context, event) => exports.ReceiveStoppedState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: { + timetoken: event.payload.cursor.timetoken, + region: event.payload.cursor.region || context.cursor.region, + }, +})); +exports.ReceiveStoppedState.on(events_1.reconnect.type, (context, event) => { var _a; return handshaking_1.HandshakingState.with({ channels: context.channels, @@ -34,4 +30,4 @@ exports.ReceiveStoppedState.on(events_1.reconnect.type, function (context, event }, }); }); -exports.ReceiveStoppedState.on(events_1.unsubscribeAll.type, function () { return unsubscribed_1.UnsubscribedState.with(undefined); }); +exports.ReceiveStoppedState.on(events_1.unsubscribeAll.type, () => unsubscribed_1.UnsubscribedState.with(undefined)); diff --git a/lib/event-engine/states/receiving.js b/lib/event-engine/states/receiving.js index 122018e8e..66f44e747 100644 --- a/lib/event-engine/states/receiving.js +++ b/lib/event-engine/states/receiving.js @@ -1,36 +1,25 @@ "use strict"; -var __assign = (this && this.__assign) || function () { - __assign = Object.assign || function(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); -}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ReceivingState = void 0; -var state_1 = require("../core/state"); -var effects_1 = require("../effects"); -var events_1 = require("../events"); -var unsubscribed_1 = require("./unsubscribed"); -var receive_reconnecting_1 = require("./receive_reconnecting"); -var receive_stopped_1 = require("./receive_stopped"); -var categories_1 = __importDefault(require("../../core/constants/categories")); +const state_1 = require("../core/state"); +const effects_1 = require("../effects"); +const events_1 = require("../events"); +const unsubscribed_1 = require("./unsubscribed"); +const receive_reconnecting_1 = require("./receive_reconnecting"); +const receive_stopped_1 = require("./receive_stopped"); +const categories_1 = __importDefault(require("../../core/constants/categories")); exports.ReceivingState = new state_1.State('RECEIVING'); -exports.ReceivingState.onEnter(function (context) { return (0, effects_1.receiveMessages)(context.channels, context.groups, context.cursor); }); -exports.ReceivingState.onExit(function () { return effects_1.receiveMessages.cancel; }); -exports.ReceivingState.on(events_1.receiveSuccess.type, function (context, event) { +exports.ReceivingState.onEnter((context) => (0, effects_1.receiveMessages)(context.channels, context.groups, context.cursor)); +exports.ReceivingState.onExit(() => effects_1.receiveMessages.cancel); +exports.ReceivingState.on(events_1.receiveSuccess.type, (context, event) => { return exports.ReceivingState.with({ channels: context.channels, groups: context.groups, cursor: event.payload.cursor }, [ (0, effects_1.emitMessages)(event.payload.events), ]); }); -exports.ReceivingState.on(events_1.subscriptionChange.type, function (context, event) { +exports.ReceivingState.on(events_1.subscriptionChange.type, (context, event) => { if (event.payload.channels.length === 0 && event.payload.groups.length === 0) { return unsubscribed_1.UnsubscribedState.with(undefined); } @@ -40,7 +29,7 @@ exports.ReceivingState.on(events_1.subscriptionChange.type, function (context, e groups: event.payload.groups, }); }); -exports.ReceivingState.on(events_1.restore.type, function (context, event) { +exports.ReceivingState.on(events_1.restore.type, (context, event) => { if (event.payload.channels.length === 0 && event.payload.groups.length === 0) { return unsubscribed_1.UnsubscribedState.with(undefined); } @@ -53,16 +42,14 @@ exports.ReceivingState.on(events_1.restore.type, function (context, event) { }, }); }); -exports.ReceivingState.on(events_1.receiveFailure.type, function (context, event) { - return receive_reconnecting_1.ReceiveReconnectingState.with(__assign(__assign({}, context), { attempts: 0, reason: event.payload })); +exports.ReceivingState.on(events_1.receiveFailure.type, (context, event) => { + return receive_reconnecting_1.ReceiveReconnectingState.with(Object.assign(Object.assign({}, context), { attempts: 0, reason: event.payload })); }); -exports.ReceivingState.on(events_1.disconnect.type, function (context) { +exports.ReceivingState.on(events_1.disconnect.type, (context) => { return receive_stopped_1.ReceiveStoppedState.with({ channels: context.channels, groups: context.groups, cursor: context.cursor, }, [(0, effects_1.emitStatus)({ category: categories_1.default.PNDisconnectedCategory })]); }); -exports.ReceivingState.on(events_1.unsubscribeAll.type, function (_) { - return unsubscribed_1.UnsubscribedState.with(undefined, [(0, effects_1.emitStatus)({ category: categories_1.default.PNDisconnectedCategory })]); -}); +exports.ReceivingState.on(events_1.unsubscribeAll.type, (_) => unsubscribed_1.UnsubscribedState.with(undefined, [(0, effects_1.emitStatus)({ category: categories_1.default.PNDisconnectedCategory })])); diff --git a/lib/event-engine/states/unsubscribed.js b/lib/event-engine/states/unsubscribed.js index e5076d50c..10f3b2bad 100644 --- a/lib/event-engine/states/unsubscribed.js +++ b/lib/event-engine/states/unsubscribed.js @@ -1,17 +1,15 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.UnsubscribedState = void 0; -var state_1 = require("../core/state"); -var events_1 = require("../events"); -var handshaking_1 = require("./handshaking"); +const state_1 = require("../core/state"); +const events_1 = require("../events"); +const handshaking_1 = require("./handshaking"); exports.UnsubscribedState = new state_1.State('UNSUBSCRIBED'); -exports.UnsubscribedState.on(events_1.subscriptionChange.type, function (_, event) { - return handshaking_1.HandshakingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - }); -}); -exports.UnsubscribedState.on(events_1.restore.type, function (_, event) { +exports.UnsubscribedState.on(events_1.subscriptionChange.type, (_, event) => handshaking_1.HandshakingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, +})); +exports.UnsubscribedState.on(events_1.restore.type, (_, event) => { return handshaking_1.HandshakingState.with({ channels: event.payload.channels, groups: event.payload.groups, diff --git a/lib/file/index.js b/lib/file/index.js deleted file mode 100644 index 1e44d895d..000000000 --- a/lib/file/index.js +++ /dev/null @@ -1,2 +0,0 @@ -"use strict"; -/** */ diff --git a/lib/file/modules/node.js b/lib/file/modules/node.js index bb0988238..5b0c17841 100644 --- a/lib/file/modules/node.js +++ b/lib/file/modules/node.js @@ -8,167 +8,125 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "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 (_) 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 }; - } -}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; -var _a; Object.defineProperty(exports, "__esModule", { value: true }); -var stream_1 = require("stream"); -var fs_1 = __importDefault(require("fs")); -var path_1 = require("path"); -var PubNubFile = (_a = /** @class */ (function () { - function PubNubFile(_a) { - var stream = _a.stream, data = _a.data, encoding = _a.encoding, name = _a.name, mimeType = _a.mimeType; - if (stream instanceof stream_1.Readable) { - this.data = stream; - if (stream instanceof fs_1.default.ReadStream) { - // $FlowFixMe: incomplete flow node definitions - this.name = (0, path_1.basename)(stream.path); - this.contentLength = fs_1.default.statSync(stream.path).size; - } - } - else if (data instanceof Buffer) { - this.data = Buffer.from(data); - } - else if (typeof data === 'string') { - // $FlowFixMe: incomplete flow node definitions - this.data = Buffer.from(data, encoding !== null && encoding !== void 0 ? encoding : 'utf8'); - } - if (name) { - this.name = (0, path_1.basename)(name); - } - if (mimeType) { - this.mimeType = mimeType; - } - if (this.data === undefined) { - throw new Error("Couldn't construct a file out of supplied options."); - } - if (this.name === undefined) { - throw new Error("Couldn't guess filename out of the options. Please provide one."); +const stream_1 = require("stream"); +const buffer_1 = require("buffer"); +const path_1 = require("path"); +const fs_1 = __importDefault(require("fs")); +class PubNubFile { + static create(file) { + return new PubNubFile(file); + } + constructor(file) { + const { stream, data, encoding, name, mimeType } = file; + let fileData; + let contentLength; + let fileMimeType; + let fileName; + if (stream && stream instanceof stream_1.Readable) { + fileData = stream; + if (stream instanceof fs_1.default.ReadStream) { + const streamFilePath = stream.path instanceof buffer_1.Buffer ? new TextDecoder().decode(stream.path) : stream.path; + fileName = (0, path_1.basename)(streamFilePath); + contentLength = fs_1.default.statSync(streamFilePath).size; } } - PubNubFile.create = function (config) { - return new this(config); - }; - PubNubFile.prototype.toBuffer = function () { - if (this.data instanceof Buffer) { - return Promise.resolve(Buffer.from(this.data)); - } - if (this.data instanceof stream_1.Readable) { - var stream_2 = this.data; - return new Promise(function (resolve, reject) { - var chunks = []; - stream_2.on('data', function (chunk) { return chunks.push(chunk); }); - stream_2.once('error', reject); - stream_2.once('end', function () { - resolve(Buffer.concat(chunks)); - }); - }); - } - if (typeof this.data === 'string') { - return Promise.resolve(Buffer.from(this.data)); - } - throw new Error("Can't cast to 'buffer'."); - }; - PubNubFile.prototype.toArrayBuffer = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - throw new Error('This feature is only supported in browser environments.'); - }); - }); - }; - PubNubFile.prototype.toString = function (encoding) { - if (encoding === void 0) { encoding = 'utf8'; } - return __awaiter(this, void 0, void 0, function () { - var buffer; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: return [4 /*yield*/, this.toBuffer()]; - case 1: - buffer = _a.sent(); - return [2 /*return*/, buffer.toString(encoding)]; - } - }); - }); - }; - PubNubFile.prototype.toStream = function () { - return __awaiter(this, void 0, void 0, function () { - var input_1, stream; - return __generator(this, function (_a) { - if (!(this.data instanceof stream_1.Readable)) { - input_1 = this.data; - return [2 /*return*/, new stream_1.Readable({ - read: function () { - this.push(Buffer.from(input_1)); - this.push(null); - }, - })]; - } - stream = new stream_1.PassThrough(); - if (this.data instanceof stream_1.Readable) { - this.data.pipe(stream); - } - return [2 /*return*/, stream]; - }); - }); - }; - PubNubFile.prototype.toFile = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - throw new Error('This feature is only supported in browser environments.'); - }); - }); - }; - PubNubFile.prototype.toFileUri = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - throw new Error('This feature is only supported in react native environments.'); + else if (data instanceof buffer_1.Buffer) { + contentLength = data.length; + fileData = buffer_1.Buffer.alloc(contentLength); + data.copy(fileData); + } + else if (data instanceof ArrayBuffer) { + contentLength = data.byteLength; + fileData = buffer_1.Buffer.from(data); + } + else if (typeof data === 'string') { + fileData = buffer_1.Buffer.from(data, encoding !== null && encoding !== void 0 ? encoding : 'utf8'); + contentLength = fileData.length; + } + if (contentLength) + this.contentLength = contentLength; + if (mimeType) + fileMimeType = mimeType; + else + fileMimeType = 'application/octet-stream'; + if (name) + fileName = (0, path_1.basename)(name); + if (fileData === undefined) + throw new Error("Couldn't construct a file out of supplied options."); + if (fileName === undefined) + throw new Error("Couldn't guess filename out of the options. Please provide one."); + this.mimeType = fileMimeType; + this.data = fileData; + this.name = fileName; + } + toBuffer() { + return __awaiter(this, void 0, void 0, function* () { + if (this.data instanceof buffer_1.Buffer) + return this.data; + const stream = this.data; + return new Promise((resolve, reject) => { + const chunks = []; + stream.on('data', (chunk) => { + chunks.push(chunk); }); - }); - }; - PubNubFile.prototype.toBlob = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - throw new Error('This feature is only supported in browser environments.'); + stream.on('end', () => { + resolve(buffer_1.Buffer.concat(chunks)); }); + stream.on('error', (error) => reject(error)); }); - }; - return PubNubFile; - }()), - _a.supportsBlob = false, - _a.supportsFile = false, - _a.supportsBuffer = typeof Buffer !== 'undefined', - _a.supportsStream = true, - _a.supportsString = true, - _a.supportsArrayBuffer = false, - _a.supportsEncryptFile = true, - _a.supportsFileUri = false, - _a); + }); + } + toArrayBuffer() { + return __awaiter(this, void 0, void 0, function* () { + return this.toBuffer().then((buffer) => buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.length)); + }); + } + toString() { + return __awaiter(this, arguments, void 0, function* (encoding = 'utf8') { + return this.toBuffer().then((buffer) => buffer.toString(encoding)); + }); + } + toStream() { + return __awaiter(this, void 0, void 0, function* () { + if (this.data instanceof stream_1.Readable) { + const stream = new stream_1.PassThrough(); + this.data.pipe(stream); + return stream; + } + return this.toBuffer().then((buffer) => new stream_1.Readable({ + read() { + this.push(buffer); + this.push(null); + }, + })); + }); + } + toFile() { + return __awaiter(this, void 0, void 0, function* () { + throw new Error('This feature is only supported in browser environments.'); + }); + } + toFileUri() { + return __awaiter(this, void 0, void 0, function* () { + throw new Error('This feature is only supported in React Native environments.'); + }); + } + toBlob() { + return __awaiter(this, void 0, void 0, function* () { + throw new Error('This feature is only supported in browser environments.'); + }); + } +} +PubNubFile.supportsBlob = false; +PubNubFile.supportsFile = false; +PubNubFile.supportsBuffer = true; +PubNubFile.supportsStream = true; +PubNubFile.supportsString = true; +PubNubFile.supportsArrayBuffer = true; +PubNubFile.supportsEncryptFile = true; +PubNubFile.supportsFileUri = false; exports.default = PubNubFile; diff --git a/lib/file/modules/react-native.js b/lib/file/modules/react-native.js index 6a83eca25..b66464e3a 100644 --- a/lib/file/modules/react-native.js +++ b/lib/file/modules/react-native.js @@ -1,5 +1,4 @@ "use strict"; -/* global File, FileReader */ var __awaiter = (this && this.__awaiter) || function (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) { @@ -9,207 +8,145 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "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 (_) 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 }; - } -}; -var _a; Object.defineProperty(exports, "__esModule", { value: true }); -var PubNubFile = (_a = /** @class */ (function () { - function PubNubFile(config) { - if (config instanceof File) { - this.data = config; - this.name = this.data.name; - this.mimeType = this.data.type; +exports.PubNubFile = void 0; +class PubNubFile { + static create(file) { + return new PubNubFile(file); + } + constructor(file) { + let fileData; + let contentLength; + let fileMimeType; + let fileName; + if (file instanceof File) { + fileData = file; + fileName = file.name; + fileMimeType = file.type; + contentLength = file.size; + } + else if ('data' in file) { + const contents = file.data; + fileMimeType = file.mimeType; + fileName = file.name; + fileData = new File([contents], fileName, { type: fileMimeType }); + contentLength = fileData.size; + } + else if ('uri' in file) { + fileMimeType = file.mimeType; + fileName = file.name; + fileData = { + uri: file.uri, + name: file.name, + type: file.mimeType, + }; + } + else + throw new Error("Couldn't construct a file out of supplied options. URI or file data required."); + if (fileData === undefined) + throw new Error("Couldn't construct a file out of supplied options."); + if (fileName === undefined) + throw new Error("Couldn't guess filename out of the options. Please provide one."); + if (contentLength) + this.contentLength = contentLength; + this.mimeType = fileMimeType; + this.data = fileData; + this.name = fileName; + } + toBuffer() { + return __awaiter(this, void 0, void 0, function* () { + throw new Error('This feature is only supported in Node.js environments.'); + }); + } + toArrayBuffer() { + return __awaiter(this, void 0, void 0, function* () { + if (this.data && this.data instanceof File) { + const data = this.data; + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.addEventListener('load', () => { + if (reader.result instanceof ArrayBuffer) + return resolve(reader.result); + }); + reader.addEventListener('error', () => reject(reader.error)); + reader.readAsArrayBuffer(data); + }); } - else if (config.uri) { - // uri upload for react native - this.data = { - uri: config.uri, - name: config.name, - type: config.mimeType, - }; - this.name = config.name; - if (config.mimeType) { - this.mimeType = config.mimeType; - } + else if (this.data && 'uri' in this.data) { + throw new Error('This file contains a file URI and does not contain the file contents.'); } - else if (config.data) { - this.data = config.data; - this.name = config.name; - if (config.mimeType) { - this.mimeType = config.mimeType; + else if (this.data) { + let result; + try { + result = yield this.data.arrayBuffer(); } + catch (error) { + throw new Error(`Unable to support toArrayBuffer in ReactNative environment: ${error}`); + } + return result; } - else { - throw new Error("Couldn't construct a file out of supplied options. URI or file data required."); - } - if (this.data === undefined) { - throw new Error("Couldn't construct a file out of supplied options."); - } - if (this.name === undefined) { - throw new Error("Couldn't guess filename out of the options. Please provide one."); - } - } - PubNubFile.create = function (config) { - return new this(config); - }; - PubNubFile.prototype.toBuffer = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - throw new Error('This feature is only supported in Node.js environments.'); - }); - }); - }; - PubNubFile.prototype.toStream = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - throw new Error('This feature is only supported in Node.js environments.'); - }); - }); - }; - PubNubFile.prototype.toBlob = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - if (this.data && this.data.uri) { - throw new Error('This file contains a file URI and does not contain the file contents.'); - } - else if (this.data instanceof File) { - return [2 /*return*/, this.data]; - } - else { - // data must be a fetch response - return [2 /*return*/, this.data.blob()]; - } - return [2 /*return*/]; - }); - }); - }; - PubNubFile.prototype.toArrayBuffer = function () { - return __awaiter(this, void 0, void 0, function () { - var result, e_1; - var _this = this; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - if (!(this.data && this.data.uri)) return [3 /*break*/, 1]; - throw new Error('This file contains a file URI and does not contain the file contents.'); - case 1: - if (!(this.data instanceof File)) return [3 /*break*/, 2]; - return [2 /*return*/, new Promise(function (resolve, reject) { - var reader = new FileReader(); - reader.addEventListener('load', function () { - if (reader.result instanceof ArrayBuffer) { - return resolve(reader.result); - } - }); - reader.addEventListener('error', function () { - reject(reader.error); - }); - reader.readAsArrayBuffer(_this.data); - })]; - case 2: - result = void 0; - _a.label = 3; - case 3: - _a.trys.push([3, 5, , 6]); - return [4 /*yield*/, this.data.arrayBuffer()]; - case 4: - result = _a.sent(); - return [3 /*break*/, 6]; - case 5: - e_1 = _a.sent(); - throw new Error("Unable to support toArrayBuffer in ReactNative environment: ".concat(e_1)); - case 6: return [2 /*return*/, result]; - } - }); - }); - }; - PubNubFile.prototype.toString = function () { - return __awaiter(this, void 0, void 0, function () { - var _this = this; - return __generator(this, function (_a) { - if (this.data && this.data.uri) { - return [2 /*return*/, JSON.stringify(this.data)]; - } - if (this.data instanceof File) { - return [2 /*return*/, new Promise(function (resolve, reject) { - var reader = new FileReader(); - reader.addEventListener('load', function () { - if (typeof reader.result === 'string') { - return resolve(reader.result); - } - }); - reader.addEventListener('error', function () { - reject(reader.error); - }); - reader.readAsBinaryString(_this.data); - })]; - } - // data must be a fetch response - return [2 /*return*/, this.data.text()]; - }); - }); - }; - PubNubFile.prototype.toFile = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - if (this.data.uri) { - throw new Error('This file contains a file URI and does not contain the file contents.'); - } - else if (this.data instanceof File) { - return [2 /*return*/, this.data]; - } - else { - // data must be a fetch response - return [2 /*return*/, this.data.blob()]; - } - return [2 /*return*/]; - }); - }); - }; - PubNubFile.prototype.toFileUri = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - if (this.data && this.data.uri) { - return [2 /*return*/, this.data]; - } - throw new Error('This file does not contain a file URI'); + throw new Error('Unable convert provided file content type to ArrayBuffer'); + }); + } + toString() { + return __awaiter(this, void 0, void 0, function* () { + if (this.data && 'uri' in this.data) + return JSON.stringify(this.data); + else if (this.data && this.data instanceof File) { + const data = this.data; + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.addEventListener('load', () => { + if (typeof reader.result === 'string') + return resolve(reader.result); + }); + reader.addEventListener('error', () => reject(reader.error)); + reader.readAsBinaryString(data); }); - }); - }; - return PubNubFile; - }()), - _a.supportsFile = typeof File !== 'undefined', - _a.supportsBlob = typeof Blob !== 'undefined', - _a.supportsArrayBuffer = typeof ArrayBuffer !== 'undefined', - _a.supportsBuffer = false, - _a.supportsStream = false, - _a.supportsString = true, - _a.supportsEncryptFile = false, - _a.supportsFileUri = true, - _a); + } + return this.data.text(); + }); + } + toStream() { + return __awaiter(this, void 0, void 0, function* () { + throw new Error('This feature is only supported in Node.js environments.'); + }); + } + toFile() { + return __awaiter(this, void 0, void 0, function* () { + if (this.data instanceof File) + return this.data; + else if ('uri' in this.data) + throw new Error('This file contains a file URI and does not contain the file contents.'); + else + return this.data.blob(); + }); + } + toFileUri() { + return __awaiter(this, void 0, void 0, function* () { + if (this.data && 'uri' in this.data) + return this.data; + throw new Error('This file does not contain a file URI'); + }); + } + toBlob() { + return __awaiter(this, void 0, void 0, function* () { + if (this.data instanceof File) + return this.data; + else if (this.data && 'uri' in this.data) + throw new Error('This file contains a file URI and does not contain the file contents.'); + else + return this.data.blob(); + }); + } +} +exports.PubNubFile = PubNubFile; +PubNubFile.supportsBlob = typeof Blob !== 'undefined'; +PubNubFile.supportsFile = typeof File !== 'undefined'; +PubNubFile.supportsBuffer = false; +PubNubFile.supportsStream = false; +PubNubFile.supportsString = true; +PubNubFile.supportsArrayBuffer = true; +PubNubFile.supportsEncryptFile = false; +PubNubFile.supportsFileUri = true; exports.default = PubNubFile; diff --git a/lib/file/modules/web.js b/lib/file/modules/web.js deleted file mode 100644 index 36be1d830..000000000 --- a/lib/file/modules/web.js +++ /dev/null @@ -1,150 +0,0 @@ -"use strict"; -/* global File, FileReader */ -var __awaiter = (this && this.__awaiter) || function (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()); - }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "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 (_) 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 }; - } -}; -var _a; -Object.defineProperty(exports, "__esModule", { value: true }); -var PubNubFile = (_a = /** @class */ (function () { - function PubNubFile(config) { - if (config instanceof File) { - this.data = config; - this.name = this.data.name; - this.mimeType = this.data.type; - } - else if (config.data) { - var contents = config.data; - this.data = new File([contents], config.name, { type: config.mimeType }); - this.name = config.name; - if (config.mimeType) { - this.mimeType = config.mimeType; - } - } - if (this.data === undefined) { - throw new Error("Couldn't construct a file out of supplied options."); - } - if (this.name === undefined) { - throw new Error("Couldn't guess filename out of the options. Please provide one."); - } - } - PubNubFile.create = function (config) { - return new this(config); - }; - PubNubFile.prototype.toBuffer = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - throw new Error('This feature is only supported in Node.js environments.'); - }); - }); - }; - PubNubFile.prototype.toStream = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - throw new Error('This feature is only supported in Node.js environments.'); - }); - }); - }; - PubNubFile.prototype.toFileUri = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - throw new Error('This feature is only supported in react native environments.'); - }); - }); - }; - PubNubFile.prototype.toBlob = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - return [2 /*return*/, this.data]; - }); - }); - }; - PubNubFile.prototype.toArrayBuffer = function () { - return __awaiter(this, void 0, void 0, function () { - var _this = this; - return __generator(this, function (_a) { - return [2 /*return*/, new Promise(function (resolve, reject) { - var reader = new FileReader(); - reader.addEventListener('load', function () { - if (reader.result instanceof ArrayBuffer) { - return resolve(reader.result); - } - }); - reader.addEventListener('error', function () { - reject(reader.error); - }); - reader.readAsArrayBuffer(_this.data); - })]; - }); - }); - }; - PubNubFile.prototype.toString = function () { - return __awaiter(this, void 0, void 0, function () { - var _this = this; - return __generator(this, function (_a) { - return [2 /*return*/, new Promise(function (resolve, reject) { - var reader = new FileReader(); - reader.addEventListener('load', function () { - if (typeof reader.result === 'string') { - return resolve(reader.result); - } - }); - reader.addEventListener('error', function () { - reject(reader.error); - }); - reader.readAsBinaryString(_this.data); - })]; - }); - }); - }; - PubNubFile.prototype.toFile = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - return [2 /*return*/, this.data]; - }); - }); - }; - return PubNubFile; - }()), - _a.supportsFile = typeof File !== 'undefined', - _a.supportsBlob = typeof Blob !== 'undefined', - _a.supportsArrayBuffer = typeof ArrayBuffer !== 'undefined', - _a.supportsBuffer = false, - _a.supportsStream = false, - _a.supportsString = true, - _a.supportsEncryptFile = true, - _a.supportsFileUri = false, - _a); -exports.default = PubNubFile; diff --git a/lib/nativescript/index.js b/lib/nativescript/index.js deleted file mode 100644 index 595f49acb..000000000 --- a/lib/nativescript/index.js +++ /dev/null @@ -1,41 +0,0 @@ -"use strict"; -/* */ -var __extends = (this && this.__extends) || (function () { - 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); - }; - return function (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 __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var pubnub_common_1 = __importDefault(require("../core/pubnub-common")); -var networking_1 = __importDefault(require("../networking")); -var common_1 = __importDefault(require("../db/common")); -var nativescript_1 = require("../networking/modules/nativescript"); -var default_1 = /** @class */ (function (_super) { - __extends(default_1, _super); - function default_1(setup) { - setup.db = new common_1.default(); - setup.networking = new networking_1.default({ - del: nativescript_1.del, - get: nativescript_1.get, - post: nativescript_1.post, - patch: nativescript_1.patch, - }); - setup.sdkFamily = 'NativeScript'; - return _super.call(this, setup) || this; - } - return default_1; -}(pubnub_common_1.default)); -exports.default = default_1; diff --git a/lib/networking/index.js b/lib/networking/index.js deleted file mode 100644 index 2b25c9249..000000000 --- a/lib/networking/index.js +++ /dev/null @@ -1,102 +0,0 @@ -"use strict"; -/* */ -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var categories_1 = __importDefault(require("../core/constants/categories")); -var default_1 = /** @class */ (function () { - function default_1(modules) { - var _this = this; - this._modules = {}; - Object.keys(modules).forEach(function (key) { - _this._modules[key] = modules[key].bind(_this); - }); - } - default_1.prototype.init = function (config) { - this._config = config; - if (Array.isArray(this._config.origin)) { - this._currentSubDomain = Math.floor(Math.random() * this._config.origin.length); - } - else { - this._currentSubDomain = 0; - } - this._coreParams = {}; - // create initial origins - this.shiftStandardOrigin(); - }; - default_1.prototype.nextOrigin = function () { - var protocol = this._config.secure ? 'https://' : 'http://'; - if (typeof this._config.origin === 'string') { - return "".concat(protocol).concat(this._config.origin); - } - this._currentSubDomain += 1; - if (this._currentSubDomain >= this._config.origin.length) { - this._currentSubDomain = 0; - } - var origin = this._config.origin[this._currentSubDomain]; - return "".concat(protocol).concat(origin); - }; - default_1.prototype.hasModule = function (name) { - return name in this._modules; - }; - // origin operations - default_1.prototype.shiftStandardOrigin = function () { - this._standardOrigin = this.nextOrigin(); - return this._standardOrigin; - }; - default_1.prototype.getStandardOrigin = function () { - return this._standardOrigin; - }; - default_1.prototype.POSTFILE = function (url, fields, file) { - return this._modules.postfile(url, fields, file); - }; - default_1.prototype.GETFILE = function (params, endpoint, callback) { - return this._modules.getfile(params, endpoint, callback); - }; - default_1.prototype.POST = function (params, body, endpoint, callback) { - return this._modules.post(params, body, endpoint, callback); - }; - default_1.prototype.PATCH = function (params, body, endpoint, callback) { - return this._modules.patch(params, body, endpoint, callback); - }; - default_1.prototype.GET = function (params, endpoint, callback) { - return this._modules.get(params, endpoint, callback); - }; - default_1.prototype.DELETE = function (params, endpoint, callback) { - return this._modules.del(params, endpoint, callback); - }; - default_1.prototype._detectErrorCategory = function (err) { - if (err.code === 'ENOTFOUND') { - return categories_1.default.PNNetworkIssuesCategory; - } - if (err.code === 'ECONNREFUSED') { - return categories_1.default.PNNetworkIssuesCategory; - } - if (err.code === 'ECONNRESET') { - return categories_1.default.PNNetworkIssuesCategory; - } - if (err.code === 'EAI_AGAIN') { - return categories_1.default.PNNetworkIssuesCategory; - } - if (err.status === 0 || (err.hasOwnProperty('status') && typeof err.status === 'undefined')) { - return categories_1.default.PNNetworkIssuesCategory; - } - if (err.timeout) - return categories_1.default.PNTimeoutCategory; - if (err.code === 'ETIMEDOUT') { - return categories_1.default.PNNetworkIssuesCategory; - } - if (err.response) { - if (err.response.badRequest) { - return categories_1.default.PNBadRequestCategory; - } - if (err.response.forbidden) { - return categories_1.default.PNAccessDeniedCategory; - } - } - return categories_1.default.PNUnknownCategory; - }; - return default_1; -}()); -exports.default = default_1; diff --git a/lib/networking/modules/nativescript.js b/lib/networking/modules/nativescript.js deleted file mode 100644 index 3f8c3c568..000000000 --- a/lib/networking/modules/nativescript.js +++ /dev/null @@ -1,78 +0,0 @@ -"use strict"; -/* */ -Object.defineProperty(exports, "__esModule", { value: true }); -exports.del = exports.patch = exports.post = exports.get = void 0; -var http_1 = require("http"); -var utils_1 = require("../utils"); -function log(url, qs, res) { - var _pickLogger = function () { - if (console && console.log) - return console; // eslint-disable-line no-console - return console; - }; - var start = new Date().getTime(); - var timestamp = new Date().toISOString(); - var logger = _pickLogger(); - logger.log('<<<<<'); // eslint-disable-line no-console - logger.log("[".concat(timestamp, "]"), '\n', url, '\n', qs); // eslint-disable-line no-console - logger.log('-----'); // eslint-disable-line no-console - var now = new Date().getTime(); - var elapsed = now - start; - var timestampDone = new Date().toISOString(); - logger.log('>>>>>>'); // eslint-disable-line no-console - logger.log("[".concat(timestampDone, " / ").concat(elapsed, "]"), '\n', url, '\n', qs, '\n', res); // eslint-disable-line no-console - logger.log('-----'); // eslint-disable-line no-console -} -function xdr(method, url, params, body, endpoint, callback) { - var _this = this; - var status = {}; - status.operation = endpoint.operation; - var httpConfig = { - method: method, - url: (0, utils_1.buildUrl)(url, params), - timeout: endpoint.timeout, - content: body, - }; - // $FlowFixMe - return (0, http_1.request)(httpConfig) - .then(function (response) { - status.error = false; - if (response.statusCode) { - status.statusCode = response.statusCode; - } - return response.content.toJSON(); - }) - .then(function (response) { - var resp = response; - if (_this._config.logVerbosity) { - log(url, params, resp); - } - callback(status, resp); - }) - .catch(function (e) { - status.error = true; - status.errorData = e; - status.category = _this._detectErrorCategory(e); - callback(status, null); - }); -} -function get(params, endpoint, callback) { - var url = this.getStandardOrigin() + endpoint.url; - return xdr.call(this, 'GET', url, params, '', endpoint, callback); -} -exports.get = get; -function post(params, body, endpoint, callback) { - var url = this.getStandardOrigin() + endpoint.url; - return xdr.call(this, 'POST', url, params, body, endpoint, callback); -} -exports.post = post; -function patch(params, body, endpoint, callback) { - var url = this.getStandardOrigin() + endpoint.url; - return xdr.call(this, 'PATCH', url, params, body, endpoint, callback); -} -exports.patch = patch; -function del(params, endpoint, callback) { - var url = this.getStandardOrigin() + endpoint.url; - return xdr.call(this, 'DELETE', url, params, '', endpoint, callback); -} -exports.del = del; diff --git a/lib/networking/modules/node.js b/lib/networking/modules/node.js deleted file mode 100644 index 08fecd318..000000000 --- a/lib/networking/modules/node.js +++ /dev/null @@ -1,31 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.keepAlive = exports.proxy = void 0; -var superagent_1 = __importDefault(require("superagent")); -var agentkeepalive_1 = __importDefault(require("agentkeepalive")); -var proxyAgent_1 = __importDefault(require("../proxyAgent")); -var keepAliveAgent = null; -var keepAliveSecureAgent = null; -(0, proxyAgent_1.default)(superagent_1.default); -function proxy(superagentConstruct) { - return superagentConstruct.proxy(this._config.proxy); -} -exports.proxy = proxy; -function keepAlive(superagentConstruct) { - var agent = this._config.secure ? keepAliveSecureAgent : keepAliveAgent; - if (agent === null) { - var AgentClass = this._config.secure ? agentkeepalive_1.default.HttpsAgent : agentkeepalive_1.default; - agent = new AgentClass(this._config.keepAliveSettings); - if (this._config.secure) { - keepAliveSecureAgent = agent; - } - else { - keepAliveAgent = agent; - } - } - return superagentConstruct.agent(agent); -} -exports.keepAlive = keepAlive; diff --git a/lib/networking/modules/react_native.js b/lib/networking/modules/react_native.js deleted file mode 100644 index 34b26ba0d..000000000 --- a/lib/networking/modules/react_native.js +++ /dev/null @@ -1,164 +0,0 @@ -"use strict"; -/* */ -/* global FormData */ -/* global fetch */ -var __awaiter = (this && this.__awaiter) || function (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()); - }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "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 (_) 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 }; - } -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.getfile = exports.postfile = void 0; -var web_node_1 = require("./web-node"); -function postfileuri(url, fields, fileInput) { - return __awaiter(this, void 0, void 0, function () { - var formData, result; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - formData = new FormData(); - fields.forEach(function (_a) { - var key = _a.key, value = _a.value; - formData.append(key, value); - }); - formData.append('file', fileInput); - return [4 /*yield*/, fetch(url, { - method: 'POST', - body: formData, - })]; - case 1: - result = _a.sent(); - return [2 /*return*/, result]; - } - }); - }); -} -function postfile(url, fields, fileInput) { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - if (!fileInput.uri) { - return [2 /*return*/, (0, web_node_1.postfile)(url, fields, fileInput)]; - } - return [2 /*return*/, postfileuri(url, fields, fileInput)]; - }); - }); -} -exports.postfile = postfile; -function getfile(params, endpoint, callback) { - var _this = this; - var url = this.getStandardOrigin() + endpoint.url; - if (params && Object.keys(params).length > 0) { - var searchParams = new URLSearchParams(params); - if (endpoint.url.indexOf('?') > -1) { - url += '&'; - } - else { - url += '?'; - } - url += searchParams.toString(); - } - var fetchResult = fetch(url, { method: 'GET', headers: endpoint.headers }); - fetchResult.then(function (resp) { return __awaiter(_this, void 0, void 0, function () { - var parsedResponse, status, _a, _b, e_1; - return __generator(this, function (_c) { - switch (_c.label) { - case 0: - status = {}; - status.error = false; - status.operation = endpoint.operation; - if (resp && resp.status) { - status.statusCode = resp.status; - } - if (!endpoint.ignoreBody) return [3 /*break*/, 1]; - parsedResponse = { - headers: resp.headers, - redirects: [], - response: resp, - }; - return [3 /*break*/, 4]; - case 1: - _c.trys.push([1, 3, , 4]); - _b = (_a = JSON).parse; - return [4 /*yield*/, resp.text()]; - case 2: - parsedResponse = _b.apply(_a, [_c.sent()]); - return [3 /*break*/, 4]; - case 3: - e_1 = _c.sent(); - status.errorData = resp; - status.error = true; - return [2 /*return*/, callback(status, null)]; - case 4: - if (parsedResponse.error && - parsedResponse.error === 1 && - parsedResponse.status && - parsedResponse.message && - parsedResponse.service) { - status.errorData = parsedResponse; - status.statusCode = parsedResponse.status; - status.error = true; - status.category = this._detectErrorCategory(status); - return [2 /*return*/, callback(status, null)]; - } - if (parsedResponse.error && parsedResponse.error.message) { - status.errorData = parsedResponse.error; - } - // returning the entire response in order to use response methods for - // reading the body in react native because the response.body - // is a ReadableStream which doesn't seem to be reliable on ios and android - return [2 /*return*/, callback(status, { response: { body: resp } })]; - } - }); - }); }); - fetchResult.catch(function (err) { - var status = {}; - status.error = true; - status.operation = endpoint.operation; - if (err.response && err.response.text && !_this._config.logVerbosity) { - try { - status.errorData = JSON.parse(err.response.text); - } - catch (e) { - status.errorData = err; - } - } - else { - status.errorData = err; - } - status.category = _this._detectErrorCategory(err); - return callback(status, null); - }); - return fetchResult; -} -exports.getfile = getfile; diff --git a/lib/networking/modules/titanium.js b/lib/networking/modules/titanium.js deleted file mode 100644 index 41975a4f0..000000000 --- a/lib/networking/modules/titanium.js +++ /dev/null @@ -1,86 +0,0 @@ -"use strict"; -/* */ -/* global XMLHttpRequest, Ti */ -Object.defineProperty(exports, "__esModule", { value: true }); -exports.del = exports.patch = exports.post = exports.get = void 0; -var utils_1 = require("../utils"); -function log(url, qs, res) { - var _pickLogger = function () { - if (Ti && Ti.API && Ti.API.log) - return Ti.API; - return console; - }; - var start = new Date().getTime(); - var timestamp = new Date().toISOString(); - var logger = _pickLogger(); - logger.log('<<<<<'); // eslint-disable-line no-console - logger.log("[".concat(timestamp, "]"), '\n', url, '\n', qs); // eslint-disable-line no-console - logger.log('-----'); // eslint-disable-line no-console - var now = new Date().getTime(); - var elapsed = now - start; - var timestampDone = new Date().toISOString(); - logger.log('>>>>>>'); // eslint-disable-line no-console - logger.log("[".concat(timestampDone, " / ").concat(elapsed, "]"), '\n', url, '\n', qs, '\n', res); // eslint-disable-line no-console - logger.log('-----'); -} -function getHttpClient() { - if (Ti.Platform.osname === 'mobileweb') { - return new XMLHttpRequest(); - } - return Ti.Network.createHTTPClient(); -} -function keepAlive(xhr) { - if (Ti.Platform.osname !== 'mobileweb' && this._config.keepAlive) { - xhr.enableKeepAlive = true; - } -} -function xdr(xhr, method, url, params, body, endpoint, callback) { - var _this = this; - var status = {}; - status.operation = endpoint.operation; - xhr.open(method, (0, utils_1.buildUrl)(url, params), true); - keepAlive.call(this, xhr); - xhr.onload = function () { - status.error = false; - if (xhr.status) { - status.statusCode = xhr.status; - } - var resp = JSON.parse(xhr.responseText); - if (_this._config.logVerbosity) { - log(url, params, xhr.responseText); - } - return callback(status, resp); - }; - xhr.onerror = function (e) { - status.error = true; - status.errorData = e.error; - status.category = _this._detectErrorCategory(e.error); - return callback(status, null); - }; - xhr.timeout = Ti.Platform.osname === 'android' ? 2147483647 : Infinity; - xhr.send(body); -} -function get(params, endpoint, callback) { - var xhr = getHttpClient(); - var url = this.getStandardOrigin() + endpoint.url; - return xdr.call(this, xhr, 'GET', url, params, {}, endpoint, callback); -} -exports.get = get; -function post(params, body, endpoint, callback) { - var xhr = getHttpClient(); - var url = this.getStandardOrigin() + endpoint.url; - return xdr.call(this, xhr, 'POST', url, params, JSON.parse(body), endpoint, callback); -} -exports.post = post; -function patch(params, body, endpoint, callback) { - var xhr = getHttpClient(); - var url = this.getStandardOrigin() + endpoint.url; - return xdr.call(this, xhr, 'PATCH', url, params, JSON.parse(body), endpoint, callback); -} -exports.patch = patch; -function del(params, endpoint, callback) { - var xhr = getHttpClient(); - var url = this.getStandardOrigin() + endpoint.url; - return xdr.call(this, xhr, 'DELETE', url, params, {}, endpoint, callback); -} -exports.del = del; diff --git a/lib/networking/modules/web-node.js b/lib/networking/modules/web-node.js deleted file mode 100644 index 55b14d860..000000000 --- a/lib/networking/modules/web-node.js +++ /dev/null @@ -1,228 +0,0 @@ -"use strict"; -/* */ -/* global window */ -var __awaiter = (this && this.__awaiter) || function (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()); - }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "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 (_) 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 }; - } -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.del = exports.patch = exports.post = exports.get = exports.getfile = exports.postfile = void 0; -var superagent_1 = __importDefault(require("superagent")); -var categories_1 = __importDefault(require("../../core/constants/categories")); -function log(req) { - var _pickLogger = function () { - if (console && console.log) - return console; // eslint-disable-line no-console - if (window && window.console && window.console.log) - return window.console; - return console; - }; - var start = new Date().getTime(); - var timestamp = new Date().toISOString(); - var logger = _pickLogger(); - logger.log('<<<<<'); - logger.log("[".concat(timestamp, "]"), '\n', req.url, '\n', req.qs); - logger.log('-----'); - req.on('response', function (res) { - var now = new Date().getTime(); - var elapsed = now - start; - var timestampDone = new Date().toISOString(); - logger.log('>>>>>>'); - logger.log("[".concat(timestampDone, " / ").concat(elapsed, "]"), '\n', req.url, '\n', req.qs, '\n', res.text); - logger.log('-----'); - }); -} -function xdr(superagentConstruct, endpoint, callback) { - var _this = this; - if (this._config.logVerbosity) { - superagentConstruct = superagentConstruct.use(log); - } - if (this._config.proxy && this._modules.proxy) { - superagentConstruct = this._modules.proxy.call(this, superagentConstruct); - } - if (this._config.keepAlive && this._modules.keepAlive) { - superagentConstruct = this._modules.keepAlive(superagentConstruct); - } - var sc = superagentConstruct; - if (endpoint.abortSignal) { - var unsubscribe_1 = endpoint.abortSignal.subscribe(function () { - sc.abort(); - unsubscribe_1(); - }); - } - if (endpoint.forceBuffered === true) { - if (typeof Blob === 'undefined') { - sc = sc.buffer().responseType('arraybuffer'); - } - else { - sc = sc.responseType('arraybuffer'); - } - } - else if (endpoint.forceBuffered === false) { - sc = sc.buffer(false); - } - sc = sc.timeout(endpoint.timeout); - sc.on('abort', function () { - return callback({ - category: categories_1.default.PNUnknownCategory, - error: true, - operation: endpoint.operation, - errorData: new Error('Aborted'), - }, null); - }); - sc.end(function (err, resp) { - var parsedResponse; - var status = {}; - status.error = err !== null; - status.operation = endpoint.operation; - if (resp && resp.status) { - status.statusCode = resp.status; - } - if (err) { - if (err.response && err.response.text && !_this._config.logVerbosity) { - try { - status.errorData = JSON.parse(err.response.text); - } - catch (e) { - status.errorData = err; - } - } - else { - status.errorData = err; - } - status.category = _this._detectErrorCategory(err); - return callback(status, null); - } - if (endpoint.ignoreBody) { - parsedResponse = { - headers: resp.headers, - redirects: resp.redirects, - response: resp, - }; - } - else { - try { - parsedResponse = JSON.parse(resp.text); - } - catch (e) { - status.errorData = resp; - status.error = true; - return callback(status, null); - } - } - if (parsedResponse.error && - parsedResponse.error === 1 && - parsedResponse.status && - parsedResponse.message && - parsedResponse.service) { - status.errorData = parsedResponse; - status.statusCode = parsedResponse.status; - status.error = true; - status.category = _this._detectErrorCategory(status); - return callback(status, null); - } - if (parsedResponse.error && parsedResponse.error.message) { - status.errorData = parsedResponse.error; - } - return callback(status, parsedResponse); - }); - return sc; -} -function postfile(url, fields, fileInput) { - return __awaiter(this, void 0, void 0, function () { - var agent, result; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - agent = superagent_1.default.post(url); - fields.forEach(function (_a) { - var key = _a.key, value = _a.value; - agent = agent.field(key, value); - }); - agent.attach('file', fileInput, { contentType: 'application/octet-stream' }); - return [4 /*yield*/, agent]; - case 1: - result = _a.sent(); - return [2 /*return*/, result]; - } - }); - }); -} -exports.postfile = postfile; -function getfile(params, endpoint, callback) { - var superagentConstruct = superagent_1.default - .get(this.getStandardOrigin() + endpoint.url) - .set(endpoint.headers) - .query(params); - return xdr.call(this, superagentConstruct, endpoint, callback); -} -exports.getfile = getfile; -function get(params, endpoint, callback) { - var superagentConstruct = superagent_1.default - .get(this.getStandardOrigin() + endpoint.url) - .set(endpoint.headers) - .query(params); - return xdr.call(this, superagentConstruct, endpoint, callback); -} -exports.get = get; -function post(params, body, endpoint, callback) { - var superagentConstruct = superagent_1.default - .post(this.getStandardOrigin() + endpoint.url) - .query(params) - .set(endpoint.headers) - .send(body); - return xdr.call(this, superagentConstruct, endpoint, callback); -} -exports.post = post; -function patch(params, body, endpoint, callback) { - var superagentConstruct = superagent_1.default - .patch(this.getStandardOrigin() + endpoint.url) - .query(params) - .set(endpoint.headers) - .send(body); - return xdr.call(this, superagentConstruct, endpoint, callback); -} -exports.patch = patch; -function del(params, endpoint, callback) { - var superagentConstruct = superagent_1.default - .delete(this.getStandardOrigin() + endpoint.url) - .set(endpoint.headers) - .query(params); - return xdr.call(this, superagentConstruct, endpoint, callback); -} -exports.del = del; diff --git a/lib/networking/proxyAgent.js b/lib/networking/proxyAgent.js deleted file mode 100644 index dd7feee08..000000000 --- a/lib/networking/proxyAgent.js +++ /dev/null @@ -1,15 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -var proxy_agent_1 = require("proxy-agent"); -function default_1(superagent) { - var Request = superagent.Request; - Request.prototype.proxy = proxy; - return superagent; -} -exports.default = default_1; -function proxy(proxyConfiguration) { - var agent = new proxy_agent_1.ProxyAgent(proxyConfiguration); - if (agent) - this.agent(agent); - return this; -} diff --git a/lib/networking/utils.js b/lib/networking/utils.js deleted file mode 100644 index a554841c8..000000000 --- a/lib/networking/utils.js +++ /dev/null @@ -1,33 +0,0 @@ -"use strict"; -/* */ -Object.defineProperty(exports, "__esModule", { value: true }); -exports.buildUrl = exports.encodedKeyValuePair = void 0; -function encodedKeyValuePair(pairs, key, value) { - if (value != null) { - if (Array.isArray(value)) { - value.forEach(function (item) { - encodedKeyValuePair(pairs, key, item); - }); - } - else if (typeof value === 'object') { - Object.keys(value).forEach(function (subkey) { - encodedKeyValuePair(pairs, "".concat(key, "[").concat(subkey, "]"), value[subkey]); - }); - } - else { - pairs.push("".concat(encodeURIComponent(key), "=").concat(encodeURIComponent(value))); - } - } - else if (value === null) { - pairs.push(encodeURIComponent("".concat(encodeURIComponent(key)))); - } -} -exports.encodedKeyValuePair = encodedKeyValuePair; -function buildUrl(url, params) { - var pairs = []; - Object.keys(params).forEach(function (key) { - encodedKeyValuePair(pairs, key, params[key]); - }); - return "".concat(url, "?").concat(pairs.join('&')); -} -exports.buildUrl = buildUrl; diff --git a/lib/node/configuration.js b/lib/node/configuration.js new file mode 100644 index 000000000..2bdbc0ccc --- /dev/null +++ b/lib/node/configuration.js @@ -0,0 +1,10 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.setDefaults = void 0; +const configuration_1 = require("../core/interfaces/configuration"); +const KEEP_ALIVE = false; +const setDefaults = (configuration) => { + var _a; + return Object.assign(Object.assign({}, (0, configuration_1.setDefaults)(configuration)), { keepAlive: (_a = configuration.keepAlive) !== null && _a !== void 0 ? _a : KEEP_ALIVE }); +}; +exports.setDefaults = setDefaults; diff --git a/lib/node/index.js b/lib/node/index.js index 7f463e5fa..5fd5e321e 100644 --- a/lib/node/index.js +++ b/lib/node/index.js @@ -1,65 +1,67 @@ "use strict"; -var __extends = (this && this.__extends) || (function () { - 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); - }; - return function (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 __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; var _a; -var cbor_sync_1 = __importDefault(require("cbor-sync")); -var pubnub_common_1 = __importDefault(require("../core/pubnub-common")); -var networking_1 = __importDefault(require("../networking")); -var common_1 = __importDefault(require("../cbor/common")); -var base64_codec_1 = require("../core/components/base64_codec"); -var web_node_1 = require("../networking/modules/web-node"); -var node_1 = require("../networking/modules/node"); -var node_2 = __importDefault(require("../crypto/modules/node")); -var node_3 = __importDefault(require("../file/modules/node")); -var nodeCryptoModule_1 = require("../crypto/modules/NodeCryptoModule/nodeCryptoModule"); -module.exports = (_a = /** @class */ (function (_super) { - __extends(class_1, _super); - function class_1(setup) { - setup.cbor = new common_1.default(function (buffer) { return cbor_sync_1.default.decode(Buffer.from(buffer)); }, base64_codec_1.decode); - setup.networking = new networking_1.default({ - keepAlive: node_1.keepAlive, - del: web_node_1.del, - get: web_node_1.get, - post: web_node_1.post, - patch: web_node_1.patch, - proxy: node_1.proxy, - getfile: web_node_1.getfile, - postfile: web_node_1.postfile, - }); - setup.sdkFamily = 'Nodejs'; - setup.PubNubFile = node_3.default; - setup.cryptography = new node_2.default(); - setup.initCryptoModule = function (cryptoConfiguration) { +const cbor_sync_1 = __importDefault(require("cbor-sync")); +const buffer_1 = require("buffer"); +const nodeCryptoModule_1 = require("../crypto/modules/NodeCryptoModule/nodeCryptoModule"); +const node_1 = __importDefault(require("../file/modules/node")); +const configuration_1 = require("../core/components/configuration"); +const configuration_2 = require("./configuration"); +const token_manager_1 = require("../core/components/token_manager"); +const node_transport_1 = require("../transport/node-transport"); +const middleware_1 = require("../transport/middleware"); +const base64_codec_1 = require("../core/components/base64_codec"); +const node_2 = __importDefault(require("../crypto/modules/node")); +const cryptography_1 = __importDefault(require("../core/components/cryptography")); +const pubnub_error_1 = require("../errors/pubnub-error"); +const pubnub_common_1 = require("../core/pubnub-common"); +const common_1 = __importDefault(require("../cbor/common")); +module.exports = (_a = class PubNub extends pubnub_common_1.PubNubCore { + constructor(configuration) { + const configurationCopy = (0, configuration_2.setDefaults)(configuration); + const platformConfiguration = Object.assign(Object.assign({}, configurationCopy), { sdkFamily: 'Nodejs', PubNubFile: node_1.default }); + const clientConfiguration = (0, configuration_1.makeConfiguration)(platformConfiguration, (cryptoConfiguration) => { + if (!cryptoConfiguration.cipherKey) + return undefined; return new nodeCryptoModule_1.CryptoModule({ - default: new nodeCryptoModule_1.LegacyCryptor({ - cipherKey: cryptoConfiguration.cipherKey, - useRandomIVs: cryptoConfiguration.useRandomIVs, - }), + default: new nodeCryptoModule_1.LegacyCryptor(Object.assign({}, cryptoConfiguration)), cryptors: [new nodeCryptoModule_1.AesCbcCryptor({ cipherKey: cryptoConfiguration.cipherKey })], }); - }; - if (!('ssl' in setup)) { - setup.ssl = true; - } - return _super.call(this, setup) || this; + }); + const tokenManager = new token_manager_1.TokenManager(new common_1.default((buffer) => cbor_sync_1.default.decode(buffer_1.Buffer.from(buffer)), base64_codec_1.decode)); + const crypto = new cryptography_1.default({ + secretKey: clientConfiguration.secretKey, + cipherKey: clientConfiguration.getCipherKey(), + useRandomIVs: clientConfiguration.getUseRandomIVs(), + customEncrypt: clientConfiguration.getCustomEncrypt(), + customDecrypt: clientConfiguration.getCustomDecrypt(), + }); + const transport = new node_transport_1.NodeTransport(configuration.keepAlive, configuration.keepAliveSettings); + const transportMiddleware = new middleware_1.PubNubMiddleware({ + clientConfiguration, + tokenManager, + transport, + shaHMAC: crypto === null || crypto === void 0 ? void 0 : crypto.HMACSHA256.bind(crypto), + }); + super({ + configuration: clientConfiguration, + transport: transportMiddleware, + cryptography: new node_2.default(), + tokenManager, + crypto, + }); + this.File = node_1.default; + this.nodeTransport = transport; + } + setProxy(configuration) { + var _b; + if (configuration && ((_b = this._configuration.keepAlive) !== null && _b !== void 0 ? _b : false)) + throw new pubnub_error_1.PubNubError("Can't set 'proxy' because already configured for 'keepAlive'"); + this.nodeTransport.setProxy(configuration); + this.reconnect(); } - return class_1; - }(pubnub_common_1.default)), + }, _a.CryptoModule = nodeCryptoModule_1.CryptoModule, _a); diff --git a/lib/react_native/configuration.js b/lib/react_native/configuration.js new file mode 100644 index 000000000..3d4e24615 --- /dev/null +++ b/lib/react_native/configuration.js @@ -0,0 +1,8 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.setDefaults = void 0; +const configuration_1 = require("../core/interfaces/configuration"); +const setDefaults = (configuration) => { + return (0, configuration_1.setDefaults)(configuration); +}; +exports.setDefaults = setDefaults; diff --git a/lib/react_native/index.js b/lib/react_native/index.js index 8c1e501cb..7345921f2 100644 --- a/lib/react_native/index.js +++ b/lib/react_native/index.js @@ -1,51 +1,53 @@ "use strict"; -var __extends = (this && this.__extends) || (function () { - 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); - }; - return function (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 __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -var cbor_js_1 = __importDefault(require("cbor-js")); -var buffer_1 = require("buffer"); -var pubnub_common_1 = __importDefault(require("../core/pubnub-common")); -var networking_1 = __importDefault(require("../networking")); -var base64_codec_1 = require("../core/components/base64_codec"); -var stringify_buffer_keys_1 = require("../core/components/stringify_buffer_keys"); -var common_1 = __importDefault(require("../cbor/common")); -var web_node_1 = require("../networking/modules/web-node"); -var react_native_1 = require("../networking/modules/react_native"); -var react_native_2 = __importDefault(require("../file/modules/react-native")); +const text_encoding_1 = require("text-encoding"); +require("react-native-url-polyfill/auto"); +const cbor_js_1 = __importDefault(require("cbor-js")); +const buffer_1 = require("buffer"); +const web_react_native_transport_1 = require("../transport/web-react-native-transport"); +const stringify_buffer_keys_1 = require("../core/components/stringify_buffer_keys"); +const configuration_1 = require("../core/components/configuration"); +const token_manager_1 = require("../core/components/token_manager"); +const middleware_1 = require("../transport/middleware"); +const base64_codec_1 = require("../core/components/base64_codec"); +const react_native_1 = __importDefault(require("../file/modules/react-native")); +const cryptography_1 = __importDefault(require("../core/components/cryptography")); +const pubnub_common_1 = require("../core/pubnub-common"); +const configuration_2 = require("./configuration"); +const common_1 = __importDefault(require("../cbor/common")); +global.TextEncoder = global.TextEncoder || text_encoding_1.TextEncoder; +global.TextDecoder = global.TextDecoder || text_encoding_1.TextDecoder; global.Buffer = global.Buffer || buffer_1.Buffer; -var default_1 = /** @class */ (function (_super) { - __extends(default_1, _super); - function default_1(setup) { - setup.cbor = new common_1.default(function (arrayBuffer) { return (0, stringify_buffer_keys_1.stringifyBufferKeys)(cbor_js_1.default.decode(arrayBuffer)); }, base64_codec_1.decode); - setup.PubNubFile = react_native_2.default; - setup.networking = new networking_1.default({ - del: web_node_1.del, - get: web_node_1.get, - post: web_node_1.post, - patch: web_node_1.patch, - getfile: react_native_1.getfile, - postfile: react_native_1.postfile, +class PubNub extends pubnub_common_1.PubNubCore { + constructor(configuration) { + const configurationCopy = (0, configuration_2.setDefaults)(configuration); + const platformConfiguration = Object.assign(Object.assign({}, configurationCopy), { sdkFamily: 'ReactNative', PubNubFile: react_native_1.default }); + const clientConfiguration = (0, configuration_1.makeConfiguration)(platformConfiguration); + const tokenManager = new token_manager_1.TokenManager(new common_1.default((arrayBuffer) => (0, stringify_buffer_keys_1.stringifyBufferKeys)(cbor_js_1.default.decode(arrayBuffer)), base64_codec_1.decode)); + let crypto; + if (clientConfiguration.getCipherKey() || clientConfiguration.secretKey) { + crypto = new cryptography_1.default({ + secretKey: clientConfiguration.secretKey, + cipherKey: clientConfiguration.getCipherKey(), + useRandomIVs: clientConfiguration.getUseRandomIVs(), + customEncrypt: clientConfiguration.getCustomEncrypt(), + customDecrypt: clientConfiguration.getCustomDecrypt(), + }); + } + const transportMiddleware = new middleware_1.PubNubMiddleware({ + clientConfiguration, + tokenManager, + transport: new web_react_native_transport_1.WebReactNativeTransport(clientConfiguration.keepAlive, clientConfiguration.logVerbosity), + }); + super({ + configuration: clientConfiguration, + transport: transportMiddleware, + tokenManager, + crypto, }); - setup.sdkFamily = 'ReactNative'; - setup.ssl = true; - return _super.call(this, setup) || this; } - return default_1; -}(pubnub_common_1.default)); -exports.default = default_1; +} +exports.default = PubNub; diff --git a/lib/titanium/index.js b/lib/titanium/index.js deleted file mode 100644 index f577196b7..000000000 --- a/lib/titanium/index.js +++ /dev/null @@ -1,42 +0,0 @@ -"use strict"; -var __extends = (this && this.__extends) || (function () { - 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); - }; - return function (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 __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = void 0; -var cbor_sync_1 = __importDefault(require("cbor-sync")); -var pubnub_common_1 = __importDefault(require("../core/pubnub-common")); -var networking_1 = __importDefault(require("../networking")); -var common_1 = __importDefault(require("../cbor/common")); -var titanium_1 = require("../networking/modules/titanium"); -var PubNub = /** @class */ (function (_super) { - __extends(PubNub, _super); - function PubNub(setup) { - setup.cbor = new common_1.default(cbor_sync_1.default.decode, function (base64String) { return Buffer.from(base64String, 'base64'); }); - setup.sdkFamily = 'TitaniumSDK'; - setup.networking = new networking_1.default({ - del: titanium_1.del, - get: titanium_1.get, - post: titanium_1.post, - patch: titanium_1.patch, - }); - return _super.call(this, setup) || this; - } - return PubNub; -}(pubnub_common_1.default)); -exports.default = PubNub; diff --git a/lib/transport/middleware.js b/lib/transport/middleware.js new file mode 100644 index 000000000..7433a00a1 --- /dev/null +++ b/lib/transport/middleware.js @@ -0,0 +1,106 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.PubNubMiddleware = exports.RequestSignature = void 0; +const transport_request_1 = require("../core/types/transport-request"); +const utils_1 = require("../core/utils"); +class RequestSignature { + constructor(publishKey, secretKey, hasher) { + this.publishKey = publishKey; + this.secretKey = secretKey; + this.hasher = hasher; + } + signature(req) { + const method = req.path.startsWith('/publish') ? transport_request_1.TransportMethod.GET : req.method; + let signatureInput = `${method}\n${this.publishKey}\n${req.path}\n${this.queryParameters(req.queryParameters)}\n`; + if (method === transport_request_1.TransportMethod.POST || method === transport_request_1.TransportMethod.PATCH) { + const body = req.body; + let payload; + if (body && body instanceof ArrayBuffer) { + payload = RequestSignature.textDecoder.decode(body); + } + else if (body && typeof body !== 'object') { + payload = body; + } + if (payload) + signatureInput += payload; + } + return `v2.${this.hasher(signatureInput, this.secretKey)}` + .replace(/\+/g, '-') + .replace(/\//g, '_') + .replace(/=+$/, ''); + } + queryParameters(query) { + return Object.keys(query) + .sort() + .map((key) => { + const queryValue = query[key]; + if (!Array.isArray(queryValue)) + return `${key}=${(0, utils_1.encodeString)(queryValue)}`; + return queryValue + .sort() + .map((value) => `${key}=${(0, utils_1.encodeString)(value)}`) + .join('&'); + }) + .join('&'); + } +} +exports.RequestSignature = RequestSignature; +RequestSignature.textDecoder = new TextDecoder('utf-8'); +class PubNubMiddleware { + constructor(configuration) { + this.configuration = configuration; + const { clientConfiguration: { keySet }, shaHMAC, } = configuration; + if (keySet.secretKey && shaHMAC) + this.signatureGenerator = new RequestSignature(keySet.publishKey, keySet.secretKey, shaHMAC); + } + makeSendable(req) { + return this.configuration.transport.makeSendable(this.request(req)); + } + request(req) { + var _a; + const { clientConfiguration } = this.configuration; + req = this.configuration.transport.request(req); + if (!req.queryParameters) + req.queryParameters = {}; + if (clientConfiguration.useInstanceId) + req.queryParameters['instanceid'] = clientConfiguration.instanceId; + if (!req.queryParameters['uuid']) + req.queryParameters['uuid'] = clientConfiguration.userId; + if (clientConfiguration.useRequestId) + req.queryParameters['requestid'] = req.identifier; + req.queryParameters['pnsdk'] = this.generatePNSDK(); + (_a = req.origin) !== null && _a !== void 0 ? _a : (req.origin = clientConfiguration.origin); + this.authenticateRequest(req); + this.signRequest(req); + return req; + } + authenticateRequest(req) { + var _a; + if (req.path.startsWith('/v2/auth/') || req.path.startsWith('/v3/pam/') || req.path.startsWith('/time')) + return; + const { clientConfiguration, tokenManager } = this.configuration; + const accessKey = (_a = tokenManager.getToken()) !== null && _a !== void 0 ? _a : clientConfiguration.authKey; + if (accessKey) + req.queryParameters['auth'] = accessKey; + } + signRequest(req) { + if (!this.signatureGenerator || req.path.startsWith('/time')) + return; + req.queryParameters['timestamp'] = String(Math.floor(new Date().getTime() / 1000)); + req.queryParameters['signature'] = this.signatureGenerator.signature(req); + } + generatePNSDK() { + const { clientConfiguration } = this.configuration; + if (clientConfiguration.sdkName) + return clientConfiguration.sdkName; + let base = `PubNub-JS-${clientConfiguration.sdkFamily}`; + if (clientConfiguration.partnerId) + base += `-${clientConfiguration.partnerId}`; + base += `/${clientConfiguration.getVersion()}`; + const pnsdkSuffix = clientConfiguration._getPnsdkSuffix(' '); + if (pnsdkSuffix.length > 0) + base += pnsdkSuffix; + return base; + } +} +exports.PubNubMiddleware = PubNubMiddleware; diff --git a/lib/transport/node-transport.js b/lib/transport/node-transport.js new file mode 100644 index 000000000..80418e7c2 --- /dev/null +++ b/lib/transport/node-transport.js @@ -0,0 +1,162 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.NodeTransport = void 0; +const node_fetch_1 = __importStar(require("node-fetch")); +const proxy_agent_1 = require("proxy-agent"); +const https_1 = require("https"); +const http_1 = require("http"); +const form_data_1 = __importDefault(require("form-data")); +const buffer_1 = require("buffer"); +const pubnub_api_error_1 = require("../errors/pubnub-api-error"); +const utils_1 = require("../core/utils"); +class NodeTransport { + constructor(keepAlive = false, keepAliveSettings = { timeout: 30000 }, logVerbosity = false) { + this.keepAlive = keepAlive; + this.keepAliveSettings = keepAliveSettings; + this.logVerbosity = logVerbosity; + } + setProxy(configuration) { + this.proxyConfiguration = configuration; + } + makeSendable(req) { + let controller = undefined; + let abortController; + if (req.cancellable) { + abortController = new AbortController(); + controller = { + abortController, + abort: () => abortController === null || abortController === void 0 ? void 0 : abortController.abort(), + }; + } + return [ + this.requestFromTransportRequest(req).then((request) => { + const start = new Date().getTime(); + this.logRequestProcessProgress(request); + return (0, node_fetch_1.default)(request, { + signal: abortController === null || abortController === void 0 ? void 0 : abortController.signal, + timeout: req.timeout * 1000, + }) + .then((response) => response.arrayBuffer().then((arrayBuffer) => [response, arrayBuffer])) + .then((response) => { + const responseBody = response[1].byteLength > 0 ? response[1] : undefined; + const { status, headers: requestHeaders } = response[0]; + const headers = {}; + requestHeaders.forEach((value, key) => (headers[key] = value.toLowerCase())); + const transportResponse = { + status, + url: request.url, + headers, + body: responseBody, + }; + if (status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(transportResponse); + this.logRequestProcessProgress(request, new Date().getTime() - start, responseBody); + return transportResponse; + }) + .catch((error) => { + throw pubnub_api_error_1.PubNubAPIError.create(error); + }); + }), + controller, + ]; + } + request(req) { + return req; + } + requestFromTransportRequest(req) { + return __awaiter(this, void 0, void 0, function* () { + let headers = req.headers; + let body; + let path = req.path; + if (req.formData && req.formData.length > 0) { + req.queryParameters = {}; + const file = req.body; + const fileData = yield file.toArrayBuffer(); + const formData = new form_data_1.default(); + for (const { key, value } of req.formData) + formData.append(key, value); + formData.append('file', buffer_1.Buffer.from(fileData), { contentType: 'application/octet-stream', filename: file.name }); + body = formData; + headers = formData.getHeaders(headers !== null && headers !== void 0 ? headers : {}); + } + else if (req.body && (typeof req.body === 'string' || req.body instanceof ArrayBuffer)) + body = req.body; + if (req.queryParameters && Object.keys(req.queryParameters).length !== 0) + path = `${path}?${(0, utils_1.queryStringFromObject)(req.queryParameters)}`; + return new node_fetch_1.Request(`${req.origin}${path}`, { + agent: this.agentForTransportRequest(req), + method: req.method, + headers, + redirect: 'follow', + body, + }); + }); + } + agentForTransportRequest(req) { + if (!this.keepAlive && !this.proxyConfiguration) + return undefined; + if (this.proxyConfiguration) + return this.proxyAgent ? this.proxyAgent : (this.proxyAgent = new proxy_agent_1.ProxyAgent(this.proxyConfiguration)); + const useSecureAgent = req.origin.startsWith('https:'); + if (useSecureAgent && this.httpsAgent === undefined) + this.httpsAgent = new https_1.Agent(Object.assign({ keepAlive: true }, this.keepAliveSettings)); + else if (!useSecureAgent && this.httpAgent === undefined) { + this.httpAgent = new http_1.Agent(Object.assign({ keepAlive: true }, this.keepAliveSettings)); + } + return useSecureAgent ? this.httpsAgent : this.httpAgent; + } + logRequestProcessProgress(request, elapsed, body) { + if (!this.logVerbosity) + return; + const { protocol, host, pathname, search } = new URL(request.url); + const timestamp = new Date().toISOString(); + if (!elapsed) { + console.log('<<<<<'); + console.log(`[${timestamp}]`, `\n${protocol}//${host}${pathname}`, `\n${search}`); + console.log('-----'); + } + else { + const stringifiedBody = body ? NodeTransport.decoder.decode(body) : undefined; + console.log('>>>>>>'); + console.log(`[${timestamp} / ${elapsed}]`, `\n${protocol}//${host}${pathname}`, `\n${search}`, `\n${stringifiedBody}`); + console.log('-----'); + } + } +} +exports.NodeTransport = NodeTransport; +NodeTransport.decoder = new TextDecoder(); diff --git a/lib/transport/web-react-native-transport.js b/lib/transport/web-react-native-transport.js new file mode 100644 index 000000000..bf09f69d2 --- /dev/null +++ b/lib/transport/web-react-native-transport.js @@ -0,0 +1,122 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (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()); + }); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.WebReactNativeTransport = void 0; +const pubnub_api_error_1 = require("../errors/pubnub-api-error"); +const utils_1 = require("../core/utils"); +class WebReactNativeTransport { + constructor(keepAlive = false, logVerbosity) { + this.keepAlive = keepAlive; + this.logVerbosity = logVerbosity; + } + makeSendable(req) { + let controller; + let abortController; + if (req.cancellable) { + abortController = new AbortController(); + controller = { + abortController, + abort: () => abortController === null || abortController === void 0 ? void 0 : abortController.abort(), + }; + } + return [ + this.requestFromTransportRequest(req).then((request) => { + const start = new Date().getTime(); + this.logRequestProcessProgress(request); + const requestTimeout = new Promise((_, reject) => { + const timeoutId = setTimeout(() => { + clearTimeout(timeoutId); + reject(new Error('Request timeout')); + }, req.timeout * 1000); + }); + return Promise.race([fetch(request, { signal: abortController === null || abortController === void 0 ? void 0 : abortController.signal }), requestTimeout]) + .then((response) => response.arrayBuffer().then((arrayBuffer) => [response, arrayBuffer])) + .then((response) => { + const responseBody = response[1].byteLength > 0 ? response[1] : undefined; + const { status, headers: requestHeaders } = response[0]; + const headers = {}; + requestHeaders.forEach((value, key) => (headers[key] = value.toLowerCase())); + const transportResponse = { + status, + url: request.url, + headers, + body: responseBody, + }; + if (status >= 400) + throw pubnub_api_error_1.PubNubAPIError.create(transportResponse); + this.logRequestProcessProgress(request, new Date().getTime() - start, responseBody); + return transportResponse; + }) + .catch((error) => { + throw pubnub_api_error_1.PubNubAPIError.create(error); + }); + }), + controller, + ]; + } + request(req) { + return req; + } + requestFromTransportRequest(req) { + return __awaiter(this, void 0, void 0, function* () { + let body; + let path = req.path; + if (req.formData && req.formData.length > 0) { + req.queryParameters = {}; + const file = req.body; + const formData = new FormData(); + for (const { key, value } of req.formData) + formData.append(key, value); + try { + const fileData = yield file.toArrayBuffer(); + formData.append('file', new Blob([fileData], { type: 'application/octet-stream' }), file.name); + } + catch (_) { + try { + const fileData = yield file.toFileUri(); + formData.append('file', fileData, file.name); + } + catch (_) { } + } + body = formData; + } + else if (req.body && (typeof req.body === 'string' || req.body instanceof ArrayBuffer)) + body = req.body; + if (req.queryParameters && Object.keys(req.queryParameters).length !== 0) + path = `${path}?${(0, utils_1.queryStringFromObject)(req.queryParameters)}`; + return new Request(`${req.origin}${path}`, { + method: req.method, + headers: req.headers, + redirect: 'follow', + body, + }); + }); + } + logRequestProcessProgress(request, elapsed, body) { + if (!this.logVerbosity) + return; + const { protocol, host, pathname, search } = new URL(request.url); + const timestamp = new Date().toISOString(); + if (!elapsed) { + console.log('<<<<<'); + console.log(`[${timestamp}]`, `\n${protocol}//${host}${pathname}`, `\n${search}`); + console.log('-----'); + } + else { + const stringifiedBody = body ? WebReactNativeTransport.decoder.decode(body) : undefined; + console.log('>>>>>>'); + console.log(`[${timestamp} / ${elapsed}]`, `\n${protocol}//${host}${pathname}`, `\n${search}`, `\n${stringifiedBody}`); + console.log('-----'); + } + } +} +exports.WebReactNativeTransport = WebReactNativeTransport; +WebReactNativeTransport.decoder = new TextDecoder(); diff --git a/lib/web/index.js b/lib/web/index.js deleted file mode 100644 index fcda537bb..000000000 --- a/lib/web/index.js +++ /dev/null @@ -1,84 +0,0 @@ -"use strict"; -/* eslint no-bitwise: ["error", { "allow": ["~", "&", ">>"] }] */ -/* global navigator, window */ -var __extends = (this && this.__extends) || (function () { - 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); - }; - return function (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 __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var cbor_js_1 = __importDefault(require("cbor-js")); -var pubnub_common_1 = __importDefault(require("../core/pubnub-common")); -var networking_1 = __importDefault(require("../networking")); -var base64_codec_1 = require("../core/components/base64_codec"); -var stringify_buffer_keys_1 = require("../core/components/stringify_buffer_keys"); -var common_1 = __importDefault(require("../cbor/common")); -var web_node_1 = require("../networking/modules/web-node"); -var web_1 = __importDefault(require("../crypto/modules/web")); -var web_2 = __importDefault(require("../file/modules/web")); -var webCryptoModule_1 = require("../crypto/modules/WebCryptoModule/webCryptoModule"); -function sendBeacon(url) { - if (navigator && navigator.sendBeacon) { - navigator.sendBeacon(url); - } - else { - return false; - } -} -var default_1 = /** @class */ (function (_super) { - __extends(default_1, _super); - function default_1(setup) { - var _this = this; - // extract config. - var _a = setup.listenToBrowserNetworkEvents, listenToBrowserNetworkEvents = _a === void 0 ? true : _a; - setup.sdkFamily = 'Web'; - setup.networking = new networking_1.default({ - del: web_node_1.del, - get: web_node_1.get, - post: web_node_1.post, - patch: web_node_1.patch, - sendBeacon: sendBeacon, - getfile: web_node_1.getfile, - postfile: web_node_1.postfile, - }); - setup.cbor = new common_1.default(function (arrayBuffer) { return (0, stringify_buffer_keys_1.stringifyBufferKeys)(cbor_js_1.default.decode(arrayBuffer)); }, base64_codec_1.decode); - setup.PubNubFile = web_2.default; - setup.cryptography = new web_1.default(); - setup.initCryptoModule = function (cryptoConfiguration) { - return new webCryptoModule_1.CryptoModule({ - default: new webCryptoModule_1.LegacyCryptor({ - cipherKey: cryptoConfiguration.cipherKey, - useRandomIVs: cryptoConfiguration.useRandomIVs, - }), - cryptors: [new webCryptoModule_1.AesCbcCryptor({ cipherKey: cryptoConfiguration.cipherKey })], - }); - }; - _this = _super.call(this, setup) || this; - if (listenToBrowserNetworkEvents) { - // mount network events. - window.addEventListener('offline', function () { - _this.networkDownDetected(); - }); - window.addEventListener('online', function () { - _this.networkUpDetected(); - }); - } - return _this; - } - default_1.CryptoModule = webCryptoModule_1.CryptoModule; - return default_1; -}(pubnub_common_1.default)); -exports.default = default_1; diff --git a/package-lock.json b/package-lock.json index 36efbc4cc..089766f5a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,49 +1,60 @@ { "name": "pubnub", - "version": "7.6.0", + "version": "7.6.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pubnub", - "version": "7.6.0", + "version": "7.6.3", "license": "SEE LICENSE IN LICENSE", "dependencies": { "agentkeepalive": "^3.5.2", "buffer": "^6.0.3", "cbor-js": "^0.1.0", "cbor-sync": "^1.0.4", + "form-data": "^4.0.0", "lil-uuid": "^0.1.1", + "node-fetch": "^2.7.0", "proxy-agent": "^6.3.0", - "superagent": "^8.1.2" + "react-native-url-polyfill": "^2.0.0", + "text-encoding": "^0.7.0" }, "devDependencies": { - "@cucumber/cucumber": "^7.3.1", + "@cucumber/cucumber": "^10.4.0", "@cucumber/pretty-formatter": "^1.0.0", - "@rollup/plugin-commonjs": "^21.0.2", - "@rollup/plugin-json": "^4.1.0", - "@rollup/plugin-node-resolve": "^13.1.3", - "@rollup/plugin-typescript": "^8.3.1", - "@types/chai": "^4.3.3", + "@rollup/plugin-commonjs": "^25.0.7", + "@rollup/plugin-json": "^6.1.0", + "@rollup/plugin-node-resolve": "^15.2.3", + "@rollup/plugin-replace": "^5.0.5", + "@rollup/plugin-terser": "^0.4.4", + "@rollup/plugin-typescript": "^11.1.6", + "@types/cbor-js": "^0.1.1", + "@types/chai": "^4.3.14", + "@types/chai-as-promised": "^7.1.8", "@types/cucumber": "^7.0.0", "@types/expect": "^24.3.0", + "@types/lil-uuid": "^0.1.3", "@types/mocha": "^9.1.0", "@types/nock": "^9.3.1", - "@types/node-fetch": "^2.6.3", + "@types/node-fetch": "^2.6.11", "@types/pubnub": "^7.2.0", - "@typescript-eslint/eslint-plugin": "^5.12.1", - "@typescript-eslint/parser": "^5.12.1", - "chai": "^4.3.4", + "@types/sinon": "^17.0.3", + "@types/text-encoding": "^0.0.39", + "@types/underscore": "^1.11.15", + "@typescript-eslint/eslint-plugin": "^7.4.0", + "@typescript-eslint/parser": "^7.4.0", + "chai": "^4.4.1", "chai-as-promised": "^7.1.1", "chai-nock": "^1.2.0", "cucumber-pretty": "^6.0.1", - "cucumber-tsflow": "^4.0.0-rc.11", - "es6-shim": "^0.35.6", - "eslint": "^8.9.0", - "eslint-plugin-mocha": "^10.0.3", - "eslint-plugin-prettier": "^4.0.0", + "cucumber-tsflow": "^4.4.4", + "es6-shim": "^0.35.8", + "eslint": "^8.57.0", + "eslint-plugin-mocha": "^10.4.1", + "eslint-plugin-prettier": "^5.1.3", "js-yaml": "^3.13.1", - "karma": "^5.0.3", + "karma": "6.4.3", "karma-chai": "^0.1.0", "karma-chrome-launcher": "^3.1.0", "karma-mocha": "^2.0.1", @@ -51,3677 +62,9745 @@ "karma-sinon-chai": "^2.0.2", "karma-sourcemap-loader": "^0.3.7", "karma-spec-reporter": "0.0.32", - "mocha": "^9.2.1", - "nock": "^9.6.1", - "node-fetch": "^2.6.9", + "mocha": "10.4.0", + "nock": "^14.0.0-beta.5", "phantomjs-prebuilt": "^2.1.16", - "prettier": "^2.5.1", + "prettier": "^3.2.5", "rimraf": "^3.0.2", - "rollup": "^2.68.0", - "rollup-plugin-gzip": "^3.0.1", - "rollup-plugin-terser": "^7.0.2", + "rollup": "^4.13.2", + "rollup-plugin-gzip": "^3.1.2", + "rollup-plugin-string": "^3.0.0", "sinon": "^7.5.0", "sinon-chai": "^3.3.0", "source-map-support": "^0.5.21", - "ts-mocha": "^9.0.2", - "ts-node": "^10.9.1", - "typescript": "^4.8.4", + "ts-mocha": "^10.0.0", + "ts-node": "^10.9.2", + "tsx": "^4.7.1", + "typescript": "^5.4.5", "underscore": "^1.9.2" } }, - "node_modules/@babel/code-frame": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", - "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "peer": true, "dependencies": { - "@babel/highlight": "^7.16.7" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { - "node": ">=6.9.0" + "node": ">=6.0.0" } }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", - "dev": true, + "node_modules/@babel/code-frame": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "dependencies": { + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" + }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/highlight": { - "version": "7.16.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", - "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, + "node_modules/@babel/compat-data": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz", + "integrity": "sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==", + "peer": true, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/runtime-corejs3": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.20.0.tgz", - "integrity": "sha512-v1JH7PeAAGBEyTQM9TqojVl+b20zXtesFKCJHu50xMxZKD1fX0TKaKHPsZfFkXfs7D1M9M6Eeqg1FkJ3a0x2dA==", - "dev": true, + "node_modules/@babel/core": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.4.tgz", + "integrity": "sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg==", "peer": true, "dependencies": { - "core-js-pure": "^3.25.1", - "regenerator-runtime": "^0.13.10" + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.4", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.24.4", + "@babel/parser": "^7.24.4", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" } }, - "node_modules/@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", - "dev": true, - "optional": true, + "node_modules/@babel/core/node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "peer": true, + "bin": { + "json5": "lib/cli.js" + }, "engines": { - "node": ">=0.1.90" + "node": ">=6" } }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "peer": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz", + "integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==", + "peer": true, "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" + "@babel/types": "^7.24.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" }, "engines": { - "node": ">=12" + "node": ">=6.9.0" } }, - "node_modules/@cucumber/create-meta": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@cucumber/create-meta/-/create-meta-5.0.0.tgz", - "integrity": "sha512-Z5kMZkUff00S3/KSnKzB/KOm2UIxMXY1xXmj2dQMlD49lV6v/W8EEvgDMNtQotQNSOQU5bDupmWQpk+o16tXIw==", - "dev": true, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "peer": true, "dependencies": { - "@cucumber/messages": "^16.0.0" + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@cucumber/create-meta/node_modules/@cucumber/messages": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@cucumber/messages/-/messages-16.0.1.tgz", - "integrity": "sha512-80JcaAfQragFqR1rMhRwiqWL9HcR6Z4LDD2mfF0Lxg/lFkCNvmWa9Jl10NUNfFXYD555NKPzP/8xFo55abw8TQ==", - "dev": true, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", + "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", + "peer": true, "dependencies": { - "@types/uuid": "8.3.0", - "class-transformer": "0.4.0", - "reflect-metadata": "0.1.13", - "uuid": "8.3.2" - } - }, - "node_modules/@cucumber/create-meta/node_modules/@types/uuid": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.0.tgz", - "integrity": "sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ==", - "dev": true - }, - "node_modules/@cucumber/create-meta/node_modules/class-transformer": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.4.0.tgz", - "integrity": "sha512-ETWD/H2TbWbKEi7m9N4Km5+cw1hNcqJSxlSYhsLsNjQzWWiZIYA1zafxpK9PwVfaZ6AqR5rrjPVUBGESm5tQUA==", - "dev": true - }, - "node_modules/@cucumber/create-meta/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/@cucumber/cucumber": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/@cucumber/cucumber/-/cucumber-7.3.2.tgz", - "integrity": "sha512-qqptM9w+UqXEYBAkrIGpIVPXDWv+zp0LrS89LiwHZwBp0cJg00su/iPMZ4j8TvCJiKfAwJXsAI1yjrd1POtU+w==", - "dev": true, - "dependencies": { - "@cucumber/create-meta": "^5.0.0", - "@cucumber/cucumber-expressions": "^12.1.1", - "@cucumber/gherkin": "^19.0.3", - "@cucumber/gherkin-streams": "^2.0.2", - "@cucumber/html-formatter": "^15.0.2", - "@cucumber/messages": "^16.0.1", - "@cucumber/tag-expressions": "^3.0.1", - "assertion-error-formatter": "^3.0.0", - "bluebird": "^3.7.2", - "capital-case": "^1.0.4", - "cli-table3": "0.6.1", - "colors": "1.4.0", - "commander": "^7.0.0", - "create-require": "^1.1.1", - "duration": "^0.2.2", - "durations": "^3.4.2", - "figures": "^3.2.0", - "glob": "^7.1.6", - "indent-string": "^4.0.0", - "is-generator": "^1.0.3", - "is-stream": "^2.0.0", - "knuth-shuffle-seeded": "^1.0.6", - "lodash": "^4.17.21", - "mz": "^2.7.0", - "progress": "^2.0.3", - "resolve": "^1.19.0", - "resolve-pkg": "^2.0.0", - "stack-chain": "^2.0.0", - "stacktrace-js": "^2.0.2", - "string-argv": "^0.3.1", - "tmp": "^0.2.1", - "util-arity": "^1.1.0", - "verror": "^1.10.0" - }, - "bin": { - "cucumber-js": "bin/cucumber-js" + "@babel/types": "^7.22.15" }, "engines": { - "node": ">=10" + "node": ">=6.9.0" } }, - "node_modules/@cucumber/cucumber-expressions": { - "version": "12.1.3", - "resolved": "https://registry.npmjs.org/@cucumber/cucumber-expressions/-/cucumber-expressions-12.1.3.tgz", - "integrity": "sha512-LB8MAzE4F/t2KIgsDEz4gZH0xSI4aG0/LmYUPyISPPjUS1pI/yGWWyeX2WsiUQxpSs765WcNIq5Bggt7gGGO3Q==", - "dev": true, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "peer": true, "dependencies": { - "regexp-match-indices": "1.0.2" + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@cucumber/cucumber/node_modules/@cucumber/messages": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@cucumber/messages/-/messages-16.0.1.tgz", - "integrity": "sha512-80JcaAfQragFqR1rMhRwiqWL9HcR6Z4LDD2mfF0Lxg/lFkCNvmWa9Jl10NUNfFXYD555NKPzP/8xFo55abw8TQ==", - "dev": true, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "peer": true, "dependencies": { - "@types/uuid": "8.3.0", - "class-transformer": "0.4.0", - "reflect-metadata": "0.1.13", - "uuid": "8.3.2" + "yallist": "^3.0.2" } }, - "node_modules/@cucumber/cucumber/node_modules/@types/uuid": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.0.tgz", - "integrity": "sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ==", - "dev": true + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "peer": true, + "bin": { + "semver": "bin/semver.js" + } }, - "node_modules/@cucumber/cucumber/node_modules/class-transformer": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.4.0.tgz", - "integrity": "sha512-ETWD/H2TbWbKEi7m9N4Km5+cw1hNcqJSxlSYhsLsNjQzWWiZIYA1zafxpK9PwVfaZ6AqR5rrjPVUBGESm5tQUA==", - "dev": true + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "peer": true }, - "node_modules/@cucumber/cucumber/node_modules/cli-table3": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.1.tgz", - "integrity": "sha512-w0q/enDHhPLq44ovMGdQeeDLvwxwavsJX7oQGYt/LrBlYsyaxyDnp6z3QzFut/6kLLKnlcUVJLrpB7KBfgG/RA==", - "dev": true, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.4.tgz", + "integrity": "sha512-lG75yeuUSVu0pIcbhiYMXBXANHrpUPaOfu7ryAzskCgKUHuAxRQI5ssrtmF0X9UXldPlvT0XM/A4F44OXRt6iQ==", + "peer": true, "dependencies": { - "string-width": "^4.2.0" + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-member-expression-to-functions": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.24.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "semver": "^6.3.1" }, "engines": { - "node": "10.* || >= 12.*" + "node": ">=6.9.0" }, - "optionalDependencies": { - "colors": "1.4.0" + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@cucumber/cucumber/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "peer": true, "bin": { - "uuid": "dist/bin/uuid" + "semver": "bin/semver.js" } }, - "node_modules/@cucumber/gherkin": { - "version": "19.0.3", - "resolved": "https://registry.npmjs.org/@cucumber/gherkin/-/gherkin-19.0.3.tgz", - "integrity": "sha512-gWdMm8mfRk3P+VugJWvNALaQV5QnT+5RkqWy3tO+4NsMSQZPo5p4V4vXwriQZ/sZR1Wni5TDRztuRsKLgZ3XHA==", - "dev": true, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", + "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", + "peer": true, "dependencies": { - "@cucumber/message-streams": "^2.0.0", - "@cucumber/messages": "^16.0.1" + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@cucumber/gherkin-streams": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@cucumber/gherkin-streams/-/gherkin-streams-2.0.2.tgz", - "integrity": "sha512-cKmXOBz4OwGlrHMBCc4qCC3KzLaqcEZ11nWWskIbv6jyfvlIRuM2OgEF6VLcNVewczifW1p6DrDj0OO+BeXocA==", - "dev": true, - "dependencies": { - "@cucumber/gherkin": "^19.0.1", - "@cucumber/message-streams": "^2.0.0", - "@cucumber/messages": "^16.0.0", - "commander": "7.2.0", - "source-map-support": "0.5.19" - }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "peer": true, "bin": { - "gherkin-javascript": "bin/gherkin" + "semver": "bin/semver.js" } }, - "node_modules/@cucumber/gherkin-streams/node_modules/@cucumber/messages": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@cucumber/messages/-/messages-16.0.1.tgz", - "integrity": "sha512-80JcaAfQragFqR1rMhRwiqWL9HcR6Z4LDD2mfF0Lxg/lFkCNvmWa9Jl10NUNfFXYD555NKPzP/8xFo55abw8TQ==", - "dev": true, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.1.tgz", + "integrity": "sha512-o7SDgTJuvx5vLKD6SFvkydkSMBvahDKGiNJzG22IZYXhiqoe9efY7zocICBgzHV4IRg5wdgl2nEL/tulKIEIbA==", + "peer": true, "dependencies": { - "@types/uuid": "8.3.0", - "class-transformer": "0.4.0", - "reflect-metadata": "0.1.13", - "uuid": "8.3.2" + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@cucumber/gherkin-streams/node_modules/@types/uuid": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.0.tgz", - "integrity": "sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ==", - "dev": true - }, - "node_modules/@cucumber/gherkin-streams/node_modules/class-transformer": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.4.0.tgz", - "integrity": "sha512-ETWD/H2TbWbKEi7m9N4Km5+cw1hNcqJSxlSYhsLsNjQzWWiZIYA1zafxpK9PwVfaZ6AqR5rrjPVUBGESm5tQUA==", - "dev": true + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "peer": true, + "engines": { + "node": ">=6.9.0" + } }, - "node_modules/@cucumber/gherkin-streams/node_modules/source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", - "dev": true, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "peer": true, "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@cucumber/gherkin-streams/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "bin": { - "uuid": "dist/bin/uuid" + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "peer": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@cucumber/gherkin/node_modules/@cucumber/messages": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@cucumber/messages/-/messages-16.0.1.tgz", - "integrity": "sha512-80JcaAfQragFqR1rMhRwiqWL9HcR6Z4LDD2mfF0Lxg/lFkCNvmWa9Jl10NUNfFXYD555NKPzP/8xFo55abw8TQ==", - "dev": true, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", + "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", + "peer": true, "dependencies": { - "@types/uuid": "8.3.0", - "class-transformer": "0.4.0", - "reflect-metadata": "0.1.13", - "uuid": "8.3.2" + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@cucumber/gherkin/node_modules/@types/uuid": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.0.tgz", - "integrity": "sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ==", - "dev": true - }, - "node_modules/@cucumber/gherkin/node_modules/class-transformer": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.4.0.tgz", - "integrity": "sha512-ETWD/H2TbWbKEi7m9N4Km5+cw1hNcqJSxlSYhsLsNjQzWWiZIYA1zafxpK9PwVfaZ6AqR5rrjPVUBGESm5tQUA==", - "dev": true - }, - "node_modules/@cucumber/gherkin/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "bin": { - "uuid": "dist/bin/uuid" + "node_modules/@babel/helper-module-imports": { + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz", + "integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==", + "peer": true, + "dependencies": { + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@cucumber/html-formatter": { - "version": "15.0.2", - "resolved": "https://registry.npmjs.org/@cucumber/html-formatter/-/html-formatter-15.0.2.tgz", - "integrity": "sha512-j+YGY4ytj78G/v1gZo53D+vuKXlTg/oxNwSCCGvRQo75+AqYDJSkm/vexXJQ5lY1rXAvlbZ9KI6jhg6LDs0YdQ==", - "dev": true, + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "peer": true, "dependencies": { - "@cucumber/messages": "^16.0.1", - "commander": "7.2.0", - "source-map-support": "0.5.19" + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" }, - "bin": { - "cucumber-html-formatter": "bin/cucumber-html-formatter.js" + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@cucumber/html-formatter/node_modules/@cucumber/messages": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@cucumber/messages/-/messages-16.0.1.tgz", - "integrity": "sha512-80JcaAfQragFqR1rMhRwiqWL9HcR6Z4LDD2mfF0Lxg/lFkCNvmWa9Jl10NUNfFXYD555NKPzP/8xFo55abw8TQ==", - "dev": true, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "peer": true, "dependencies": { - "@types/uuid": "8.3.0", - "class-transformer": "0.4.0", - "reflect-metadata": "0.1.13", - "uuid": "8.3.2" + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@cucumber/html-formatter/node_modules/@types/uuid": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.0.tgz", - "integrity": "sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ==", - "dev": true + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz", + "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==", + "peer": true, + "engines": { + "node": ">=6.9.0" + } }, - "node_modules/@cucumber/html-formatter/node_modules/class-transformer": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.4.0.tgz", - "integrity": "sha512-ETWD/H2TbWbKEi7m9N4Km5+cw1hNcqJSxlSYhsLsNjQzWWiZIYA1zafxpK9PwVfaZ6AqR5rrjPVUBGESm5tQUA==", - "dev": true + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", + "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", + "peer": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-wrap-function": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } }, - "node_modules/@cucumber/html-formatter/node_modules/source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", - "dev": true, + "node_modules/@babel/helper-replace-supers": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.1.tgz", + "integrity": "sha512-QCR1UqC9BzG5vZl8BMicmZ28RuUBnHhAMddD8yHFHDRH9lLTZ9uUPehX8ctVPT8l0TKblJidqcgUUKGVrePleQ==", + "peer": true, "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-member-expression-to-functions": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@cucumber/html-formatter/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "bin": { - "uuid": "dist/bin/uuid" + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "peer": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@cucumber/message-streams": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@cucumber/message-streams/-/message-streams-2.1.0.tgz", - "integrity": "sha512-Yh3mw3qv6QL9NI/ihkZF8V9MX2GbnR6oktv34kC3uAbrQy9d/b2SZ3HNjG3J9JQqpV4B7Om3SPElJYIeo66TrA==", - "dev": true, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", + "peer": true, "dependencies": { - "@cucumber/messages": "^16.0.1" + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@cucumber/message-streams/node_modules/@cucumber/messages": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@cucumber/messages/-/messages-16.0.1.tgz", - "integrity": "sha512-80JcaAfQragFqR1rMhRwiqWL9HcR6Z4LDD2mfF0Lxg/lFkCNvmWa9Jl10NUNfFXYD555NKPzP/8xFo55abw8TQ==", - "dev": true, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "peer": true, "dependencies": { - "@types/uuid": "8.3.0", - "class-transformer": "0.4.0", - "reflect-metadata": "0.1.13", - "uuid": "8.3.2" + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@cucumber/message-streams/node_modules/@types/uuid": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.0.tgz", - "integrity": "sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ==", - "dev": true - }, - "node_modules/@cucumber/message-streams/node_modules/class-transformer": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.4.0.tgz", - "integrity": "sha512-ETWD/H2TbWbKEi7m9N4Km5+cw1hNcqJSxlSYhsLsNjQzWWiZIYA1zafxpK9PwVfaZ6AqR5rrjPVUBGESm5tQUA==", - "dev": true + "node_modules/@babel/helper-string-parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", + "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==", + "peer": true, + "engines": { + "node": ">=6.9.0" + } }, - "node_modules/@cucumber/message-streams/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "bin": { - "uuid": "dist/bin/uuid" + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@cucumber/messages": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/@cucumber/messages/-/messages-21.0.1.tgz", - "integrity": "sha512-pGR7iURM4SF9Qp1IIpNiVQ77J9kfxMkPOEbyy+zRmGABnWWCsqMpJdfHeh9Mb3VskemVw85++e15JT0PYdcR3g==", - "dev": true, + "node_modules/@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", "peer": true, - "dependencies": { - "@types/uuid": "8.3.4", - "class-transformer": "0.5.1", - "reflect-metadata": "0.1.13", - "uuid": "9.0.0" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@cucumber/pretty-formatter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@cucumber/pretty-formatter/-/pretty-formatter-1.0.0.tgz", - "integrity": "sha512-wcnIMN94HyaHGsfq72dgCvr1d8q6VGH4Y6Gl5weJ2TNZw1qn2UY85Iki4c9VdaLUONYnyYH3+178YB+9RFe/Hw==", - "dev": true, + "node_modules/@babel/helper-wrap-function": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz", + "integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==", + "peer": true, "dependencies": { - "ansi-styles": "^5.0.0", - "cli-table3": "^0.6.0", - "figures": "^3.2.0", - "ts-dedent": "^2.0.0" + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.15", + "@babel/types": "^7.22.19" }, - "peerDependencies": { - "@cucumber/cucumber": ">=7.0.0", - "@cucumber/messages": "*" - } - }, - "node_modules/@cucumber/pretty-formatter/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=6.9.0" } }, - "node_modules/@cucumber/tag-expressions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@cucumber/tag-expressions/-/tag-expressions-3.0.1.tgz", - "integrity": "sha512-OGCXaJ1BQXmQ5b9pw+JYsBGumK2/LPZiLmbj1o1JFVeSNs2PY8WPQFSyXrskhrHz5Nd/6lYg7lvGMtFHOncC4w==", - "dev": true - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, + "node_modules/@babel/helpers": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.4.tgz", + "integrity": "sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw==", + "peer": true, "dependencies": { - "eslint-visitor-keys": "^3.3.0" + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + "node": ">=6.9.0" } }, - "node_modules/@eslint-community/regexpp": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.0.tgz", - "integrity": "sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==", - "dev": true, + "node_modules/@babel/highlight": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", + "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + "node": ">=6.9.0" } }, - "node_modules/@eslint/eslintrc": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", - "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", - "dev": true, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.5.1", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" + "color-convert": "^1.9.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=4" } }, - "node_modules/@eslint/eslintrc/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/@eslint/eslintrc/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dependencies": { - "argparse": "^2.0.1" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": ">=4" } }, - "node_modules/@eslint/js": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.37.0.tgz", - "integrity": "sha512-x5vzdtOOGgFVDCUs81QRB2+liax8rFg3+7hqM+QhBG0/G3F1ZsoYl97UrqgHgQ9KKT7G6c4V+aTUCgu/n22v1A==", - "dev": true, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=0.8.0" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", - "dev": true, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" + "has-flag": "^3.0.0" }, "engines": { - "node": ">=10.10.0" + "node": ">=4" } }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" + "node_modules/@babel/parser": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz", + "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==", + "peer": true, + "bin": { + "parser": "bin/babel-parser.js" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "engines": { + "node": ">=6.0.0" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.4.tgz", + "integrity": "sha512-qpl6vOOEEzTLLcsuqYYo8yDtrTocmu2xkGvgNebvPjT9DTtfFYGmgDqY+rBYXNlqL4s9qLDn6xkrJv4RxAPiTA==", + "peer": true, "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@jest/types/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.1.tgz", + "integrity": "sha512-y4HqEnkelJIOQGd+3g1bTeKsA5c6qM7eOn7VggGVbBc0y8MLSKHacwcIE2PplNlQSj0PqS9rrXL/nkPVK+kUNg==", + "peer": true, "dependencies": { - "color-convert": "^2.0.1" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { - "node": ">=8" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@jest/types/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.1.tgz", + "integrity": "sha512-Hj791Ii4ci8HqnaKHAlLNs+zaLXb0EzSDhiAWp5VNlyvCNymYfacs64pxTxbH1znW/NcArSmwpmG9IKE/TUVVQ==", + "peer": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.24.1" }, "engines": { - "node": ">=10" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "peerDependencies": { + "@babel/core": "^7.13.0" } }, - "node_modules/@jest/types/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.1.tgz", + "integrity": "sha512-m9m/fXsXLiHfwdgydIFnpk+7jlVbnvlK5B2EKiPdLUb6WX654ZaaEWJUjk8TftRbZpK0XibovlLWX4KIZhV6jw==", + "peer": true, "dependencies": { - "color-name": "~1.1.4" + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { - "node": ">=7.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@jest/types/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/types/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, + "node_modules/@babel/plugin-proposal-async-generator-functions": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz", + "integrity": "sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-async-generator-functions instead.", + "peer": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-remap-async-to-generator": "^7.18.9", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, "engines": { - "node": ">=8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@jest/types/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, + "node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.", + "peer": true, "dependencies": { - "has-flag": "^4.0.0" + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { - "node": ">=8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true, + "node_modules/@babel/plugin-proposal-export-default-from": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.24.1.tgz", + "integrity": "sha512-+0hrgGGV3xyYIjOrD/bUZk/iUwOIGuoANfRfVg1cPhYBxF+TIXSEcc42DqzBICmWsnAQ+SfKedY0bj8QD+LuMg==", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-export-default-from": "^7.24.1" + }, "engines": { - "node": ">=6.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, + "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead.", + "peer": true, "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, + "node_modules/@babel/plugin-proposal-numeric-separator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-numeric-separator instead.", + "peer": true, "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" }, "engines": { - "node": ">= 8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, + "node_modules/@babel/plugin-proposal-object-rest-spread": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz", + "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead.", + "peer": true, + "dependencies": { + "@babel/compat-data": "^7.20.5", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.20.7" + }, "engines": { - "node": ">= 8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, + "node_modules/@babel/plugin-proposal-optional-catch-binding": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", + "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-catch-binding instead.", + "peer": true, "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" }, "engines": { - "node": ">= 8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@rollup/plugin-commonjs": { - "version": "21.0.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-21.0.2.tgz", - "integrity": "sha512-d/OmjaLVO4j/aQX69bwpWPpbvI3TJkQuxoAk7BH8ew1PyoMBLTOuvJTjzG8oEoW7drIIqB0KCJtfFLu/2GClWg==", - "dev": true, + "node_modules/@babel/plugin-proposal-optional-chaining": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz", + "integrity": "sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead.", + "peer": true, "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "commondir": "^1.0.1", - "estree-walker": "^2.0.1", - "glob": "^7.1.6", - "is-reference": "^1.2.1", - "magic-string": "^0.25.7", - "resolve": "^1.17.0" + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" }, "engines": { - "node": ">= 8.0.0" + "node": ">=6.9.0" }, "peerDependencies": { - "rollup": "^2.38.3" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@rollup/plugin-json": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-4.1.0.tgz", - "integrity": "sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^3.0.8" + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "peer": true, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "rollup": "^1.20.0 || ^2.0.0" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "13.1.3", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.1.3.tgz", - "integrity": "sha512-BdxNk+LtmElRo5d06MGY4zoepyrXX1tkzX2hrnPEZ53k78GuOMWLqmJDGIIOPwVRIFZrLQOo+Yr6KtCuLIA0AQ==", - "dev": true, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "peer": true, "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "builtin-modules": "^3.1.0", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.19.0" + "@babel/helper-plugin-utils": "^7.8.0" }, - "engines": { - "node": ">= 10.0.0" + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" }, "peerDependencies": { - "rollup": "^2.42.0" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@rollup/plugin-typescript": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.3.1.tgz", - "integrity": "sha512-84rExe3ICUBXzqNX48WZV2Jp3OddjTMX97O2Py6D1KJaGSwWp0mDHXj+bCGNJqWHIEKDIT2U0sDjhP4czKi6cA==", - "dev": true, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "peer": true, "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "resolve": "^1.17.0" + "@babel/helper-plugin-utils": "^7.14.5" }, "engines": { - "node": ">=8.0.0" + "node": ">=6.9.0" }, "peerDependencies": { - "rollup": "^2.14.0", - "tslib": "*", - "typescript": ">=3.7.0" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", - "dev": true, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-default-from": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.24.1.tgz", + "integrity": "sha512-cNXSxv9eTkGUtd0PsNMK8Yx5xeScxfpWOUAxE+ZPAXXEcAMOC3fk7LRdXq5fvpra2pLx2p1YtkAhpUbB2SwaRA==", + "peer": true, "dependencies": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { - "node": ">= 8.0.0" + "node": ">=6.9.0" }, "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@rollup/pluginutils/node_modules/estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", - "dev": true - }, - "node_modules/@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", - "dev": true, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "peer": true, "dependencies": { - "type-detect": "4.0.8" + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@sinonjs/formatio": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.2.tgz", - "integrity": "sha512-B8SEsgd8gArBLMD6zpRw3juQ2FVSsmdd7qlevyDqzS9WTCtvF55/gAL+h6gue8ZvPYcdiPdvueM/qm//9XzyTQ==", - "dev": true, + "node_modules/@babel/plugin-syntax-flow": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.24.1.tgz", + "integrity": "sha512-sxi2kLTI5DeW5vDtMUsk4mTPwvlUDbjOnoWayhynCwrw4QXRld4QEYwqzY8JmQXaJUtgUuCIurtSRH5sn4c7mA==", + "peer": true, "dependencies": { - "@sinonjs/commons": "^1", - "@sinonjs/samsam": "^3.1.0" + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@sinonjs/samsam": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.3.tgz", - "integrity": "sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ==", - "dev": true, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.1.tgz", + "integrity": "sha512-IuwnI5XnuF189t91XbxmXeCDz3qs6iDRO7GJ++wcfgeXNs/8FmIlKcpDSXNVyuLQxlwvskmI3Ct73wUODkJBlQ==", + "peer": true, "dependencies": { - "@sinonjs/commons": "^1.3.0", - "array-from": "^2.1.1", - "lodash": "^4.17.15" + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@sinonjs/text-encoding": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", - "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", - "dev": true - }, - "node_modules/@tootallnate/quickjs-emscripten": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", - "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==" - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", - "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", - "dev": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", - "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", - "dev": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", - "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", - "dev": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", - "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", - "dev": true - }, - "node_modules/@types/chai": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.3.tgz", - "integrity": "sha512-hC7OMnszpxhZPduX+m+nrx+uFoLkWOMiR4oa/AZF3MuSETYTZmFfJAHqZEM8MVlvfG7BEUcgvtwoCTxBp6hm3g==", - "dev": true - }, - "node_modules/@types/cucumber": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@types/cucumber/-/cucumber-7.0.0.tgz", - "integrity": "sha512-cr5NN8/jmbw3vDKTQfGW0cSzDtkvxixu9bUD6po9U6OEF04XLuukTDldFG34ccDscLkA8bYnZ7VjxP79cIC7tg==", - "deprecated": "This is a stub types definition. @cucumber/cucumber provides its own type definitions, so you do not need this installed.", - "dev": true, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.1.tgz", + "integrity": "sha512-zhQTMH0X2nVLnb04tz+s7AMuasX8U0FnpE+nHTOhSOINjWMnopoZTxtIKsd45n4GQ/HIZLyfIpoul8e2m0DnRA==", + "peer": true, "dependencies": { - "@cucumber/cucumber": "*" + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", - "dev": true - }, - "node_modules/@types/expect": { - "version": "24.3.0", - "resolved": "https://registry.npmjs.org/@types/expect/-/expect-24.3.0.tgz", - "integrity": "sha512-aq5Z+YFBz5o2b6Sp1jigx5nsmoZMK5Ceurjwy6PZmRv7dEi1jLtkARfvB1ME+OXJUG+7TZUDcv3WoCr/aor6dQ==", - "deprecated": "This is a stub types definition. expect provides its own type definitions, so you do not need this installed.", - "dev": true, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "peer": true, "dependencies": { - "expect": "*" + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "peer": true, "dependencies": { - "@types/istanbul-lib-coverage": "*" + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz", + "integrity": "sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==", + "peer": true, "dependencies": { - "@types/istanbul-lib-report": "*" + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", - "dev": true - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", - "dev": true, - "optional": true - }, - "node_modules/@types/mocha": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.0.tgz", - "integrity": "sha512-QCWHkbMv4Y5U9oW10Uxbr45qMMSzl4OzijsozynUAgx3kEHUdXB00udx2dWDQ7f2TU2a2uuiFaRZjCe3unPpeg==", - "dev": true - }, - "node_modules/@types/nock": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/@types/nock/-/nock-9.3.1.tgz", - "integrity": "sha512-eOVHXS5RnWOjTVhu3deCM/ruy9E6JCgeix2g7wpFiekQh3AaEAK1cz43tZDukKmtSmQnwvSySq7ubijCA32I7Q==", - "dev": true, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "peer": true, "dependencies": { - "@types/node": "*" + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@types/node": { - "version": "17.0.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", - "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==", - "dev": true - }, - "node_modules/@types/node-fetch": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.3.tgz", - "integrity": "sha512-ETTL1mOEdq/sxUtgtOhKjyB2Irra4cjxksvcMUR5Zr4n+PxVhsCD9WS46oPbHL3et9Zde7CNRr+WUNlcHvsX+w==", - "dev": true, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "peer": true, "dependencies": { - "@types/node": "*", - "form-data": "^3.0.0" + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@types/node-fetch/node_modules/form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "dev": true, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "peer": true, "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "@babel/helper-plugin-utils": "^7.10.4" }, - "engines": { - "node": ">= 6" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@types/pubnub": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@types/pubnub/-/pubnub-7.2.0.tgz", - "integrity": "sha512-Ui58Xsn8/4Ty1hFW0t91ED6FKezzipjO+GEJviOdJdqp817+I5/WMfo5zBsDfjbZQWMqcdrktMauKpUqiIF1wA==", - "dev": true - }, - "node_modules/@types/resolve": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", - "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", - "dev": true, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "peer": true, "dependencies": { - "@types/node": "*" + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, - "node_modules/@types/uuid": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", - "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", - "dev": true, - "peer": true - }, - "node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "peer": true, "dependencies": { - "@types/yargs-parser": "*" + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@types/yargs-parser": { - "version": "20.2.1", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", - "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", - "dev": true + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.12.1.tgz", - "integrity": "sha512-M499lqa8rnNK7mUv74lSFFttuUsubIRdAbHcVaP93oFcKkEmHmLqy2n7jM9C8DVmFMYK61ExrZU6dLYhQZmUpw==", - "dev": true, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "peer": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.12.1", - "@typescript-eslint/type-utils": "5.12.1", - "@typescript-eslint/utils": "5.12.1", - "debug": "^4.3.2", - "functional-red-black-tree": "^1.0.1", - "ignore": "^5.1.8", - "regexpp": "^3.2.0", - "semver": "^7.3.5", - "tsutils": "^3.21.0" + "@babel/helper-plugin-utils": "^7.14.5" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=6.9.0" }, "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "@babel/core": "^7.0.0-0" } }, - "node_modules/@typescript-eslint/parser": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.12.1.tgz", - "integrity": "sha512-6LuVUbe7oSdHxUWoX/m40Ni8gsZMKCi31rlawBHt7VtW15iHzjbpj2WLiToG2758KjtCCiLRKZqfrOdl3cNKuw==", - "dev": true, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "peer": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.12.1", - "@typescript-eslint/types": "5.12.1", - "@typescript-eslint/typescript-estree": "5.12.1", - "debug": "^4.3.2" + "@babel/helper-plugin-utils": "^7.14.5" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=6.9.0" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "@babel/core": "^7.0.0-0" } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.12.1.tgz", - "integrity": "sha512-J0Wrh5xS6XNkd4TkOosxdpObzlYfXjAFIm9QxYLCPOcHVv1FyyFCPom66uIh8uBr0sZCrtS+n19tzufhwab8ZQ==", - "dev": true, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz", + "integrity": "sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==", + "peer": true, "dependencies": { - "@typescript-eslint/types": "5.12.1", - "@typescript-eslint/visitor-keys": "5.12.1" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=6.9.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.12.1.tgz", - "integrity": "sha512-Gh8feEhsNLeCz6aYqynh61Vsdy+tiNNkQtc+bN3IvQvRqHkXGUhYkUi+ePKzP0Mb42se7FDb+y2SypTbpbR/Sg==", - "dev": true, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "peer": true, "dependencies": { - "@typescript-eslint/utils": "5.12.1", - "debug": "^4.3.2", - "tsutils": "^3.21.0" + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=6.9.0" }, "peerDependencies": { - "eslint": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "@babel/core": "^7.0.0" } }, - "node_modules/@typescript-eslint/types": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.12.1.tgz", - "integrity": "sha512-hfcbq4qVOHV1YRdhkDldhV9NpmmAu2vp6wuFODL71Y0Ixak+FLeEU4rnPxgmZMnGreGEghlEucs9UZn5KOfHJA==", - "dev": true, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.1.tgz", + "integrity": "sha512-ngT/3NkRhsaep9ck9uj2Xhv9+xB1zShY3tM3g6om4xxCELwCDN4g4Aq5dRn48+0hasAql7s2hdBOysCfNpr4fw==", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=6.9.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.12.1.tgz", - "integrity": "sha512-ahOdkIY9Mgbza7L9sIi205Pe1inCkZWAHE1TV1bpxlU4RZNPtXaDZfiiFWcL9jdxvW1hDYZJXrFm+vlMkXRbBw==", - "dev": true, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.3.tgz", + "integrity": "sha512-Qe26CMYVjpQxJ8zxM1340JFNjZaF+ISWpr1Kt/jGo+ZTUzKkfw/pphEWbRCb+lmSM6k/TOgfYLvmbHkUQ0asIg==", + "peer": true, "dependencies": { - "@typescript-eslint/types": "5.12.1", - "@typescript-eslint/visitor-keys": "5.12.1", - "debug": "^4.3.2", - "globby": "^11.0.4", - "is-glob": "^4.0.3", - "semver": "^7.3.5", - "tsutils": "^3.21.0" + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-remap-async-to-generator": "^7.22.20", + "@babel/plugin-syntax-async-generators": "^7.8.4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=6.9.0" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@typescript-eslint/utils": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.12.1.tgz", - "integrity": "sha512-Qq9FIuU0EVEsi8fS6pG+uurbhNTtoYr4fq8tKjBupsK5Bgbk2I32UGm0Sh+WOyjOPgo/5URbxxSNV6HYsxV4MQ==", - "dev": true, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.1.tgz", + "integrity": "sha512-AawPptitRXp1y0n4ilKcGbRYWfbbzFWz2NqNu7dacYDtFtz0CMjG64b3LQsb3KIgnf4/obcUL78hfaOS7iCUfw==", + "peer": true, "dependencies": { - "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.12.1", - "@typescript-eslint/types": "5.12.1", - "@typescript-eslint/typescript-estree": "5.12.1", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" + "@babel/helper-module-imports": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-remap-async-to-generator": "^7.22.20" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=6.9.0" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@typescript-eslint/utils/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.1.tgz", + "integrity": "sha512-TWWC18OShZutrv9C6mye1xwtam+uNi2bnTOCBUd5sZxyHOiWbU6ztSROofIMrK84uweEZC219POICK/sTYwfgg==", + "peer": true, "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { - "node": ">=8.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@typescript-eslint/utils/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.4.tgz", + "integrity": "sha512-nIFUZIpGKDf9O9ttyRXpHFpKC+X3Y5mtshZONuEUYBomAKoM4y029Jr+uB1bHGPhNmK8YXHevDtKDOLmtRrp6g==", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, "engines": { - "node": ">=4.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.12.1.tgz", - "integrity": "sha512-l1KSLfupuwrXx6wc0AuOmC7Ko5g14ZOQ86wJJqRbdLbXLK02pK/DPiDDqCc7BqqiiA04/eAA6ayL0bgOrAkH7A==", - "dev": true, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.1.tgz", + "integrity": "sha512-OMLCXi0NqvJfORTaPQBwqLXHhb93wkBKZ4aNwMl6WtehO7ar+cmp+89iPEQPqxAnxsOKTaMcs3POz3rKayJ72g==", + "peer": true, "dependencies": { - "@typescript-eslint/types": "5.12.1", - "eslint-visitor-keys": "^3.0.0" + "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=6.9.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", - "dev": true - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dev": true, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.4.tgz", + "integrity": "sha512-B8q7Pz870Hz/q9UgP8InNpY01CSLDSCyqX7zcRuv3FcPl87A2G17lASroHWaCtbdIcbYzOZ7kWmXFKbijMSmFg==", + "peer": true, "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" + "@babel/helper-create-class-features-plugin": "^7.24.4", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-class-static-block": "^7.14.5" }, "engines": { - "node": ">= 0.6" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" } }, - "node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "dev": true, - "bin": { - "acorn": "bin/acorn" + "node_modules/@babel/plugin-transform-classes": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.1.tgz", + "integrity": "sha512-ZTIe3W7UejJd3/3R4p7ScyyOoafetUShSf4kCqV0O7F/RiHxVj/wRaRnQlrGwflvcehNA8M42HkAiEDYZu2F1Q==", + "peer": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-replace-supers": "^7.24.1", + "@babel/helper-split-export-declaration": "^7.22.6", + "globals": "^11.1.0" }, "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, + "node": ">=6.9.0" + }, "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + "@babel/core": "^7.0.0-0" } }, - "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true, + "node_modules/@babel/plugin-transform-classes/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "peer": true, "engines": { - "node": ">=0.4.0" + "node": ">=4" } }, - "node_modules/after": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", - "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=", - "dev": true - }, - "node_modules/agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.1.tgz", + "integrity": "sha512-5pJGVIUfJpOS+pAqBQd+QMaTD2vCL/HcePooON6pDpHgRp4gNRmzyHTPIkXntwKsq3ayUFVfJaIKPw2pOkOcTw==", + "peer": true, "dependencies": { - "debug": "^4.3.4" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/template": "^7.24.0" }, "engines": { - "node": ">= 14" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/agent-base/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.1.tgz", + "integrity": "sha512-ow8jciWqNxR3RYbSNVuF4U2Jx130nwnBnhRw6N6h1bOejNkABmcI5X5oz29K4alWX7vf1C+o6gtKXikzRKkVdw==", + "peer": true, "dependencies": { - "ms": "2.1.2" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { - "node": ">=6.0" + "node": ">=6.9.0" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/agentkeepalive": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.2.tgz", - "integrity": "sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ==", + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.1.tgz", + "integrity": "sha512-p7uUxgSoZwZ2lPNMzUkqCts3xlp8n+o05ikjy7gbtFJSt9gdU88jAmtfmOxHM14noQXBxfgzf2yRWECiNVhTCw==", + "peer": true, "dependencies": { - "humanize-ms": "^1.2.1" + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { - "node": ">= 4.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.1.tgz", + "integrity": "sha512-msyzuUnvsjsaSaocV6L7ErfNsa5nDWL1XKNnDePLgmz+WdU4w/J8+AxBMrWfi9m4IxfL5sZQKUPQKDQeeAT6lA==", + "peer": true, "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "@babel/helper-plugin-utils": "^7.24.0" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.1.tgz", + "integrity": "sha512-av2gdSTyXcJVdI+8aFZsCAtR29xJt0S5tas+Ef8NvBNmD1a+N/3ecMLeMBgfcK+xzsjdLDT6oHt+DFPyeqUbDA==", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, "engines": { - "node": ">=6" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.1.tgz", + "integrity": "sha512-U1yX13dVBSwS23DEAqU+Z/PkwE9/m7QQy8Y9/+Tdb8UWYaGNDYwTLi19wqIAiROr8sXVum9A/rtiH5H0boUcTw==", + "peer": true, + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + }, "engines": { - "node": ">=8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.1.tgz", + "integrity": "sha512-Ft38m/KFOyzKw2UaJFkWG9QnHPG/Q/2SkOrRk4pNBPg5IPZ+dOxcmkK5IyuBcxiNPyyYowPGUReyBvrvZs7IlQ==", + "peer": true, "dependencies": { - "color-convert": "^1.9.0" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" }, "engines": { - "node": ">=4" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=", - "dev": true + "node_modules/@babel/plugin-transform-flow-strip-types": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.24.1.tgz", + "integrity": "sha512-iIYPIWt3dUmUKKE10s3W+jsQ3icFkw0JyRVyY1B7G4yK/nngAOHLVx8xlhA6b/Jzl/Y0nis8gjqhqKtRDQqHWQ==", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-flow": "^7.24.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.1.tgz", + "integrity": "sha512-OxBdcnF04bpdQdR3i4giHZNZQn7cm8RQKcSwA17wAAqEELo1ZOwp5FFgeptWUQXFyT9kwHo10aqqauYkRZPCAg==", + "peer": true, "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" }, "engines": { - "node": ">= 8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/arg": { - "version": "4.1.3", + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.1.tgz", + "integrity": "sha512-BXmDZpPlh7jwicKArQASrj8n22/w6iymRnvHYYd2zO30DbE277JO20/7yXJT3QxDPtiQiOxQBbZH4TpivNXIxA==", + "peer": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.1.tgz", + "integrity": "sha512-U7RMFmRvoasscrIFy5xA4gIp8iWnWubnKkKuUGJjsuOH7GfbMkB+XZzeslx2kLdEGdOJDamEmCqOks6e8nv8DQ==", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.1.tgz", + "integrity": "sha512-zn9pwz8U7nCqOYIiBaOxoQOtYmMODXTJnkxG4AtX8fPmnCRYWBOHD0qcpwS9e2VDSp1zNJYpdnFMIKb8jmwu6g==", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.1.tgz", + "integrity": "sha512-OhN6J4Bpz+hIBqItTeWJujDOfNP+unqv/NJgyhlpSqgBTPm37KkMmZV6SYcOj+pnDbdcl1qRGV/ZiIjX9Iy34w==", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.1.tgz", + "integrity": "sha512-4ojai0KysTWXzHseJKa1XPNXKRbuUrhkOPY4rEGeR+7ChlJVKxFa3H3Bz+7tWaGKgJAXUWKOGmltN+u9B3+CVg==", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.1.tgz", + "integrity": "sha512-lAxNHi4HVtjnHd5Rxg3D5t99Xm6H7b04hUS7EHIXcUl2EV4yl1gWdqZrNzXnSrHveL9qMdbODlLF55mvgjAfaQ==", + "peer": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.1.tgz", + "integrity": "sha512-szog8fFTUxBfw0b98gEWPaEqF42ZUD/T3bkynW/wtgx2p/XCP55WEsb+VosKceRSd6njipdZvNogqdtI4Q0chw==", + "peer": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-simple-access": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.1.tgz", + "integrity": "sha512-mqQ3Zh9vFO1Tpmlt8QPnbwGHzNz3lpNEMxQb1kAemn/erstyqw1r9KeOlOfo3y6xAnFEcOv2tSyrXfmMk+/YZA==", + "peer": true, + "dependencies": { + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.1.tgz", + "integrity": "sha512-tuA3lpPj+5ITfcCluy6nWonSL7RvaG0AOTeAuvXqEKS34lnLzXpDb0dcP6K8jD0zWZFNDVly90AGFJPnm4fOYg==", + "peer": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", + "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", + "peer": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.1.tgz", + "integrity": "sha512-/rurytBM34hYy0HKZQyA0nHbQgQNFm4Q/BOc9Hflxi2X3twRof7NaE5W46j4kQitm7SvACVRXsa6N/tSZxvPug==", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.1.tgz", + "integrity": "sha512-iQ+caew8wRrhCikO5DrUYx0mrmdhkaELgFa+7baMcVuhxIkN7oxt06CZ51D65ugIb1UWRQ8oQe+HXAVM6qHFjw==", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.1.tgz", + "integrity": "sha512-7GAsGlK4cNL2OExJH1DzmDeKnRv/LXq0eLUSvudrehVA5Rgg4bIrqEUW29FbKMBRT0ztSqisv7kjP+XIC4ZMNw==", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.1.tgz", + "integrity": "sha512-XjD5f0YqOtebto4HGISLNfiNMTTs6tbkFf2TOqJlYKYmbo+mN9Dnpl4SRoofiziuOWMIyq3sZEUqLo3hLITFEA==", + "peer": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.24.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.1.tgz", + "integrity": "sha512-oKJqR3TeI5hSLRxudMjFQ9re9fBVUU0GICqM3J1mi8MqlhVr6hC/ZN4ttAyMuQR6EZZIY6h/exe5swqGNNIkWQ==", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-replace-supers": "^7.24.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.1.tgz", + "integrity": "sha512-oBTH7oURV4Y+3EUrf6cWn1OHio3qG/PVwO5J03iSJmBg6m2EhKjkAu/xuaXaYwWW9miYtvbWv4LNf0AmR43LUA==", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.1.tgz", + "integrity": "sha512-n03wmDt+987qXwAgcBlnUUivrZBPZ8z1plL0YvgQalLm+ZE5BMhGm94jhxXtA1wzv1Cu2aaOv1BM9vbVttrzSg==", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.1.tgz", + "integrity": "sha512-8Jl6V24g+Uw5OGPeWNKrKqXPDw2YDjLc53ojwfMcKwlEoETKU9rU0mHUtcg9JntWI/QYzGAXNWEcVHZ+fR+XXg==", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.1.tgz", + "integrity": "sha512-tGvisebwBO5em4PaYNqt4fkw56K2VALsAbAakY0FjTYqJp7gfdrgr7YX76Or8/cpik0W6+tj3rZ0uHU9Oil4tw==", + "peer": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.1.tgz", + "integrity": "sha512-pTHxDVa0BpUbvAgX3Gat+7cSciXqUcY9j2VZKTbSB6+VQGpNgNO9ailxTGHSXlqOnX1Hcx1Enme2+yv7VqP9bg==", + "peer": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.1.tgz", + "integrity": "sha512-LetvD7CrHmEx0G442gOomRr66d7q8HzzGGr4PMHGr+5YIm6++Yke+jxj246rpvsbyhJwCLxcTn6zW1P1BSenqA==", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.24.1.tgz", + "integrity": "sha512-mvoQg2f9p2qlpDQRBC7M3c3XTr0k7cp/0+kFKKO/7Gtu0LSw16eKB+Fabe2bDT/UpsyasTBBkAnbdsLrkD5XMw==", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.23.4.tgz", + "integrity": "sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA==", + "peer": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-jsx": "^7.23.3", + "@babel/types": "^7.23.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.24.1.tgz", + "integrity": "sha512-kDJgnPujTmAZ/9q2CN4m2/lRsUUPDvsG3+tSHWUJIzMGTt5U/b/fwWd3RO3n+5mjLrsBrVa5eKFRVSQbi3dF1w==", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.24.1.tgz", + "integrity": "sha512-1v202n7aUq4uXAieRTKcwPzNyphlCuqHHDcdSNc+vdhoTEZcFMh+L5yZuCmGaIO7bs1nJUNfHB89TZyoL48xNA==", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.1.tgz", + "integrity": "sha512-sJwZBCzIBE4t+5Q4IGLaaun5ExVMRY0lYwos/jNecjMrVCygCdph3IKv0tkP5Fc87e/1+bebAmEAGBfnRD+cnw==", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.1.tgz", + "integrity": "sha512-JAclqStUfIwKN15HrsQADFgeZt+wexNQ0uLhuqvqAUFoqPMjEcFCYZBhq0LUdz6dZK/mD+rErhW71fbx8RYElg==", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.24.3.tgz", + "integrity": "sha512-J0BuRPNlNqlMTRJ72eVptpt9VcInbxO6iP3jaxr+1NPhC0UkKL+6oeX6VXMEYdADnuqmMmsBspt4d5w8Y/TCbQ==", + "peer": true, + "dependencies": { + "@babel/helper-module-imports": "^7.24.3", + "@babel/helper-plugin-utils": "^7.24.0", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.1", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "peer": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.1.tgz", + "integrity": "sha512-LyjVB1nsJ6gTTUKRjRWx9C1s9hE7dLfP/knKdrfeH9UPtAGjYGgxIbFfx7xyLIEWs7Xe1Gnf8EWiUqfjLhInZA==", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.1.tgz", + "integrity": "sha512-KjmcIM+fxgY+KxPVbjelJC6hrH1CgtPmTvdXAfn3/a9CnWGSTY7nH4zm5+cjmWJybdcPSsD0++QssDsjcpe47g==", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.1.tgz", + "integrity": "sha512-9v0f1bRXgPVcPrngOQvLXeGNNVLc8UjMVfebo9ka0WF3/7+aVUHmaJVT3sa0XCzEFioPfPHZiOcYG9qOsH63cw==", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.1.tgz", + "integrity": "sha512-WRkhROsNzriarqECASCNu/nojeXCDTE/F2HmRgOzi7NGvyfYGq1NEjKBK3ckLfRgGc6/lPAqP0vDOSw3YtG34g==", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.1.tgz", + "integrity": "sha512-CBfU4l/A+KruSUoW+vTQthwcAdwuqbpRNB8HQKlZABwHRhsdHZ9fezp4Sn18PeAlYxTNiLMlx4xUBV3AWfg1BA==", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.4.tgz", + "integrity": "sha512-79t3CQ8+oBGk/80SQ8MN3Bs3obf83zJ0YZjDmDaEZN8MqhMI760apl5z6a20kFeMXBwJX99VpKT8CKxEBp5H1g==", + "peer": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.24.4", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-typescript": "^7.24.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.1.tgz", + "integrity": "sha512-RlkVIcWT4TLI96zM660S877E7beKlQw7Ig+wqkKBiWfj0zH5Q4h50q6er4wzZKRNSYpfo6ILJ+hrJAGSX2qcNw==", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.1.tgz", + "integrity": "sha512-Ss4VvlfYV5huWApFsF8/Sq0oXnGO+jB+rijFEFugTd3cwSObUSnUi88djgR5528Csl0uKlrI331kRqe56Ov2Ng==", + "peer": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.1.tgz", + "integrity": "sha512-2A/94wgZgxfTsiLaQ2E36XAOdcZmGAaEEgVmxQWwZXWkGhvoHbaqXcKnU8zny4ycpu3vNqg0L/PcCiYtHtA13g==", + "peer": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.1.tgz", + "integrity": "sha512-fqj4WuzzS+ukpgerpAoOnMfQXwUHFxXUZUE84oL2Kao2N8uSlvcpnAidKASgsNgzZHBsHWvcm8s9FPWUhAb8fA==", + "peer": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.4.tgz", + "integrity": "sha512-7Kl6cSmYkak0FK/FXjSEnLJ1N9T/WA2RkMhu17gZ/dsxKJUuTYNIylahPTzqpLyJN4WhDif8X0XK1R8Wsguo/A==", + "peer": true, + "dependencies": { + "@babel/compat-data": "^7.24.4", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.4", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.1", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.1", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.1", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.24.1", + "@babel/plugin-syntax-import-attributes": "^7.24.1", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.24.1", + "@babel/plugin-transform-async-generator-functions": "^7.24.3", + "@babel/plugin-transform-async-to-generator": "^7.24.1", + "@babel/plugin-transform-block-scoped-functions": "^7.24.1", + "@babel/plugin-transform-block-scoping": "^7.24.4", + "@babel/plugin-transform-class-properties": "^7.24.1", + "@babel/plugin-transform-class-static-block": "^7.24.4", + "@babel/plugin-transform-classes": "^7.24.1", + "@babel/plugin-transform-computed-properties": "^7.24.1", + "@babel/plugin-transform-destructuring": "^7.24.1", + "@babel/plugin-transform-dotall-regex": "^7.24.1", + "@babel/plugin-transform-duplicate-keys": "^7.24.1", + "@babel/plugin-transform-dynamic-import": "^7.24.1", + "@babel/plugin-transform-exponentiation-operator": "^7.24.1", + "@babel/plugin-transform-export-namespace-from": "^7.24.1", + "@babel/plugin-transform-for-of": "^7.24.1", + "@babel/plugin-transform-function-name": "^7.24.1", + "@babel/plugin-transform-json-strings": "^7.24.1", + "@babel/plugin-transform-literals": "^7.24.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.24.1", + "@babel/plugin-transform-member-expression-literals": "^7.24.1", + "@babel/plugin-transform-modules-amd": "^7.24.1", + "@babel/plugin-transform-modules-commonjs": "^7.24.1", + "@babel/plugin-transform-modules-systemjs": "^7.24.1", + "@babel/plugin-transform-modules-umd": "^7.24.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", + "@babel/plugin-transform-new-target": "^7.24.1", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.1", + "@babel/plugin-transform-numeric-separator": "^7.24.1", + "@babel/plugin-transform-object-rest-spread": "^7.24.1", + "@babel/plugin-transform-object-super": "^7.24.1", + "@babel/plugin-transform-optional-catch-binding": "^7.24.1", + "@babel/plugin-transform-optional-chaining": "^7.24.1", + "@babel/plugin-transform-parameters": "^7.24.1", + "@babel/plugin-transform-private-methods": "^7.24.1", + "@babel/plugin-transform-private-property-in-object": "^7.24.1", + "@babel/plugin-transform-property-literals": "^7.24.1", + "@babel/plugin-transform-regenerator": "^7.24.1", + "@babel/plugin-transform-reserved-words": "^7.24.1", + "@babel/plugin-transform-shorthand-properties": "^7.24.1", + "@babel/plugin-transform-spread": "^7.24.1", + "@babel/plugin-transform-sticky-regex": "^7.24.1", + "@babel/plugin-transform-template-literals": "^7.24.1", + "@babel/plugin-transform-typeof-symbol": "^7.24.1", + "@babel/plugin-transform-unicode-escapes": "^7.24.1", + "@babel/plugin-transform-unicode-property-regex": "^7.24.1", + "@babel/plugin-transform-unicode-regex": "^7.24.1", + "@babel/plugin-transform-unicode-sets-regex": "^7.24.1", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.4", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "peer": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-flow": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.24.1.tgz", + "integrity": "sha512-sWCV2G9pcqZf+JHyv/RyqEIpFypxdCSxWIxQjpdaQxenNog7cN1pr76hg8u0Fz8Qgg0H4ETkGcJnXL8d4j0PPA==", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-transform-flow-strip-types": "^7.24.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.24.1.tgz", + "integrity": "sha512-1DBaMmRDpuYQBPWD8Pf/WEwCrtgRHxsZnP4mIy9G/X+hFfbI47Q2G4t1Paakld84+qsk2fSsUPMKg71jkoOOaQ==", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-syntax-jsx": "^7.24.1", + "@babel/plugin-transform-modules-commonjs": "^7.24.1", + "@babel/plugin-transform-typescript": "^7.24.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/register": { + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.23.7.tgz", + "integrity": "sha512-EjJeB6+kvpk+Y5DAkEAmbOBEFkh9OASx0huoEkqYTFxAZHzOAX2Oh5uwAUuL2rUddqfM0SA+KPXV2TbzoZ2kvQ==", + "peer": true, + "dependencies": { + "clone-deep": "^4.0.1", + "find-cache-dir": "^2.0.0", + "make-dir": "^2.1.0", + "pirates": "^4.0.6", + "source-map-support": "^0.5.16" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", + "peer": true + }, + "node_modules/@babel/runtime": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz", + "integrity": "sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==", + "peer": true, + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime-corejs3": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.24.4.tgz", + "integrity": "sha512-VOQOexSilscN24VEY810G/PqtpFvx/z6UqDIjIWbDe2368HhDLkYN5TYwaEz/+eRCUkhJ2WaNLLmQAlxzfWj4w==", + "dev": true, + "peer": true, + "dependencies": { + "core-js-pure": "^3.30.2", + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", + "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", + "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.24.1", + "@babel/generator": "^7.24.1", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.24.1", + "@babel/types": "^7.24.0", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", + "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "peer": true, + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@cucumber/ci-environment": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@cucumber/ci-environment/-/ci-environment-10.0.1.tgz", + "integrity": "sha512-/+ooDMPtKSmvcPMDYnMZt4LuoipfFfHaYspStI4shqw8FyKcfQAmekz6G+QKWjQQrvM+7Hkljwx58MEwPCwwzg==", + "dev": true + }, + "node_modules/@cucumber/cucumber": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/@cucumber/cucumber/-/cucumber-10.4.0.tgz", + "integrity": "sha512-pFPu4tCzHJUm1S4GfWUlhJYYqfbVPCmYCADehuhNU+MR29mvy49DQE6WS6aVdwABPawzpBs0H8EuQYA8Vh9Yqw==", + "dev": true, + "dependencies": { + "@cucumber/ci-environment": "10.0.1", + "@cucumber/cucumber-expressions": "17.1.0", + "@cucumber/gherkin": "28.0.0", + "@cucumber/gherkin-streams": "5.0.1", + "@cucumber/gherkin-utils": "9.0.0", + "@cucumber/html-formatter": "21.3.1", + "@cucumber/message-streams": "4.0.1", + "@cucumber/messages": "24.1.0", + "@cucumber/tag-expressions": "6.1.0", + "assertion-error-formatter": "^3.0.0", + "capital-case": "^1.0.4", + "chalk": "^4.1.2", + "cli-table3": "0.6.3", + "commander": "^10.0.0", + "debug": "^4.3.4", + "error-stack-parser": "^2.1.4", + "figures": "^3.2.0", + "glob": "^10.3.10", + "has-ansi": "^4.0.1", + "indent-string": "^4.0.0", + "is-installed-globally": "^0.4.0", + "is-stream": "^2.0.0", + "knuth-shuffle-seeded": "^1.0.6", + "lodash.merge": "^4.6.2", + "lodash.mergewith": "^4.6.2", + "luxon": "3.2.1", + "mkdirp": "^2.1.5", + "mz": "^2.7.0", + "progress": "^2.0.3", + "read-pkg-up": "^7.0.1", + "resolve-pkg": "^2.0.0", + "semver": "7.5.3", + "string-argv": "0.3.1", + "strip-ansi": "6.0.1", + "supports-color": "^8.1.1", + "tmp": "0.2.3", + "type-fest": "^4.8.3", + "util-arity": "^1.1.0", + "xmlbuilder": "^15.1.1", + "yaml": "^2.2.2", + "yup": "1.2.0" + }, + "bin": { + "cucumber-js": "bin/cucumber.js" + }, + "engines": { + "node": "18 || >=20" + }, + "funding": { + "url": "https://opencollective.com/cucumber" + } + }, + "node_modules/@cucumber/cucumber-expressions": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/@cucumber/cucumber-expressions/-/cucumber-expressions-17.1.0.tgz", + "integrity": "sha512-PCv/ppsPynniKPWJr5v566daCVe+pbxQpHGrIu/Ev57cCH9Rv+X0F6lio4Id3Z64TaG7btCRLUGewIgLwmrwOA==", + "dev": true, + "dependencies": { + "regexp-match-indices": "1.0.2" + } + }, + "node_modules/@cucumber/gherkin": { + "version": "28.0.0", + "resolved": "https://registry.npmjs.org/@cucumber/gherkin/-/gherkin-28.0.0.tgz", + "integrity": "sha512-Ee6zJQq0OmIUPdW0mSnsCsrWA2PZAELNDPICD2pLfs0Oz7RAPgj80UsD2UCtqyAhw2qAR62aqlktKUlai5zl/A==", + "dev": true, + "dependencies": { + "@cucumber/messages": ">=19.1.4 <=24" + } + }, + "node_modules/@cucumber/gherkin-streams": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@cucumber/gherkin-streams/-/gherkin-streams-5.0.1.tgz", + "integrity": "sha512-/7VkIE/ASxIP/jd4Crlp4JHXqdNFxPGQokqWqsaCCiqBiu5qHoKMxcWNlp9njVL/n9yN4S08OmY3ZR8uC5x74Q==", + "dev": true, + "dependencies": { + "commander": "9.1.0", + "source-map-support": "0.5.21" + }, + "bin": { + "gherkin-javascript": "bin/gherkin" + }, + "peerDependencies": { + "@cucumber/gherkin": ">=22.0.0", + "@cucumber/message-streams": ">=4.0.0", + "@cucumber/messages": ">=17.1.1" + } + }, + "node_modules/@cucumber/gherkin-streams/node_modules/commander": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.1.0.tgz", + "integrity": "sha512-i0/MaqBtdbnJ4XQs4Pmyb+oFQl+q0lsAmokVUH92SlSw4fkeAcG3bVon+Qt7hmtF+u3Het6o4VgrcY3qAoEB6w==", + "dev": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/@cucumber/gherkin-utils": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@cucumber/gherkin-utils/-/gherkin-utils-9.0.0.tgz", + "integrity": "sha512-clk4q39uj7pztZuZtyI54V8lRsCUz0Y/p8XRjIeHh7ExeEztpWkp4ca9q1FjUOPfQQ8E7OgqFbqoQQXZ1Bx7fw==", + "dev": true, + "dependencies": { + "@cucumber/gherkin": "^28.0.0", + "@cucumber/messages": "^24.0.0", + "@teppeis/multimaps": "3.0.0", + "commander": "12.0.0", + "source-map-support": "^0.5.21" + }, + "bin": { + "gherkin-utils": "bin/gherkin-utils" + } + }, + "node_modules/@cucumber/gherkin-utils/node_modules/commander": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.0.0.tgz", + "integrity": "sha512-MwVNWlYjDTtOjX5PiD7o5pK0UrFU/OYgcJfjjK4RaHZETNtjJqrZa9Y9ds88+A+f+d5lv+561eZ+yCKoS3gbAA==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@cucumber/html-formatter": { + "version": "21.3.1", + "resolved": "https://registry.npmjs.org/@cucumber/html-formatter/-/html-formatter-21.3.1.tgz", + "integrity": "sha512-M1zbre7e8MsecXheqNv62BKY5J06YJSv1LmsD7sJ3mu5t1jirLjj2It1HqPsX5CQAfg9n69xFRugPgLMSte9TA==", + "dev": true, + "peerDependencies": { + "@cucumber/messages": ">=18" + } + }, + "node_modules/@cucumber/message-streams": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@cucumber/message-streams/-/message-streams-4.0.1.tgz", + "integrity": "sha512-Kxap9uP5jD8tHUZVjTWgzxemi/0uOsbGjd4LBOSxcJoOCRbESFwemUzilJuzNTB8pcTQUh8D5oudUyxfkJOKmA==", + "dev": true, + "peerDependencies": { + "@cucumber/messages": ">=17.1.1" + } + }, + "node_modules/@cucumber/messages": { + "version": "24.1.0", + "resolved": "https://registry.npmjs.org/@cucumber/messages/-/messages-24.1.0.tgz", + "integrity": "sha512-hxVHiBurORcobhVk80I9+JkaKaNXkW6YwGOEFIh/2aO+apAN+5XJgUUWjng9NwqaQrW1sCFuawLB1AuzmBaNdQ==", + "dev": true, + "dependencies": { + "@types/uuid": "9.0.8", + "class-transformer": "0.5.1", + "reflect-metadata": "0.2.1", + "uuid": "9.0.1" + } + }, + "node_modules/@cucumber/pretty-formatter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@cucumber/pretty-formatter/-/pretty-formatter-1.0.1.tgz", + "integrity": "sha512-A1lU4VVP0aUWdOTmpdzvXOyEYuPtBDI0xYwYJnmoMDplzxMdhcHk86lyyvYDoMoPzzq6OkOE3isuosvUU4X7IQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^5.0.0", + "cli-table3": "^0.6.0", + "figures": "^3.2.0", + "ts-dedent": "^2.0.0" + }, + "peerDependencies": { + "@cucumber/cucumber": ">=7.0.0", + "@cucumber/messages": "*" + } + }, + "node_modules/@cucumber/tag-expressions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@cucumber/tag-expressions/-/tag-expressions-6.1.0.tgz", + "integrity": "sha512-+3DwRumrCJG27AtzCIL37A/X+A/gSfxOPLg8pZaruh5SLumsTmpvilwroVWBT2fPzmno/tGXypeK5a7NHU4RzA==", + "dev": true + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", + "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", + "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", + "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", + "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", + "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", + "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", + "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", + "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", + "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", + "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", + "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", + "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", + "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", + "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", + "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", + "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", + "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", + "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", + "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", + "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", + "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", + "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", + "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "peer": true + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "peer": true, + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "dev": true + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/ttlcache": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@isaacs/ttlcache/-/ttlcache-1.4.1.tgz", + "integrity": "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==", + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jest/create-cache-key-function": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-29.7.0.tgz", + "integrity": "sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==", + "peer": true, + "dependencies": { + "@jest/types": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "peer": true, + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "peer": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@react-native-community/cli": { + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-12.3.6.tgz", + "integrity": "sha512-647OSi6xBb8FbwFqX9zsJxOzu685AWtrOUWHfOkbKD+5LOpGORw+GQo0F9rWZnB68rLQyfKUZWJeaD00pGv5fw==", + "peer": true, + "dependencies": { + "@react-native-community/cli-clean": "12.3.6", + "@react-native-community/cli-config": "12.3.6", + "@react-native-community/cli-debugger-ui": "12.3.6", + "@react-native-community/cli-doctor": "12.3.6", + "@react-native-community/cli-hermes": "12.3.6", + "@react-native-community/cli-plugin-metro": "12.3.6", + "@react-native-community/cli-server-api": "12.3.6", + "@react-native-community/cli-tools": "12.3.6", + "@react-native-community/cli-types": "12.3.6", + "chalk": "^4.1.2", + "commander": "^9.4.1", + "deepmerge": "^4.3.0", + "execa": "^5.0.0", + "find-up": "^4.1.0", + "fs-extra": "^8.1.0", + "graceful-fs": "^4.1.3", + "prompts": "^2.4.2", + "semver": "^7.5.2" + }, + "bin": { + "react-native": "build/bin.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native-community/cli-clean": { + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-clean/-/cli-clean-12.3.6.tgz", + "integrity": "sha512-gUU29ep8xM0BbnZjwz9MyID74KKwutq9x5iv4BCr2im6nly4UMf1B1D+V225wR7VcDGzbgWjaezsJShLLhC5ig==", + "peer": true, + "dependencies": { + "@react-native-community/cli-tools": "12.3.6", + "chalk": "^4.1.2", + "execa": "^5.0.0" + } + }, + "node_modules/@react-native-community/cli-config": { + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-config/-/cli-config-12.3.6.tgz", + "integrity": "sha512-JGWSYQ9EAK6m2v0abXwFLEfsqJ1zkhzZ4CV261QZF9MoUNB6h57a274h1MLQR9mG6Tsh38wBUuNfEPUvS1vYew==", + "peer": true, + "dependencies": { + "@react-native-community/cli-tools": "12.3.6", + "chalk": "^4.1.2", + "cosmiconfig": "^5.1.0", + "deepmerge": "^4.3.0", + "glob": "^7.1.3", + "joi": "^17.2.1" + } + }, + "node_modules/@react-native-community/cli-config/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@react-native-community/cli-config/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "peer": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@react-native-community/cli-config/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@react-native-community/cli-debugger-ui": { + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-12.3.6.tgz", + "integrity": "sha512-SjUKKsx5FmcK9G6Pb6UBFT0s9JexVStK5WInmANw75Hm7YokVvHEgtprQDz2Uvy5znX5g2ujzrkIU//T15KQzA==", + "peer": true, + "dependencies": { + "serve-static": "^1.13.1" + } + }, + "node_modules/@react-native-community/cli-doctor": { + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-doctor/-/cli-doctor-12.3.6.tgz", + "integrity": "sha512-fvBDv2lTthfw4WOQKkdTop2PlE9GtfrlNnpjB818MhcdEnPjfQw5YaTUcnNEGsvGomdCs1MVRMgYXXwPSN6OvQ==", + "peer": true, + "dependencies": { + "@react-native-community/cli-config": "12.3.6", + "@react-native-community/cli-platform-android": "12.3.6", + "@react-native-community/cli-platform-ios": "12.3.6", + "@react-native-community/cli-tools": "12.3.6", + "chalk": "^4.1.2", + "command-exists": "^1.2.8", + "deepmerge": "^4.3.0", + "envinfo": "^7.10.0", + "execa": "^5.0.0", + "hermes-profile-transformer": "^0.0.6", + "node-stream-zip": "^1.9.1", + "ora": "^5.4.1", + "semver": "^7.5.2", + "strip-ansi": "^5.2.0", + "wcwidth": "^1.0.1", + "yaml": "^2.2.1" + } + }, + "node_modules/@react-native-community/cli-doctor/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "peer": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@react-native-community/cli-hermes": { + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-hermes/-/cli-hermes-12.3.6.tgz", + "integrity": "sha512-sNGwfOCl8OAIjWCkwuLpP8NZbuO0dhDI/2W7NeOGDzIBsf4/c4MptTrULWtGIH9okVPLSPX0NnRyGQ+mSwWyuQ==", + "peer": true, + "dependencies": { + "@react-native-community/cli-platform-android": "12.3.6", + "@react-native-community/cli-tools": "12.3.6", + "chalk": "^4.1.2", + "hermes-profile-transformer": "^0.0.6" + } + }, + "node_modules/@react-native-community/cli-platform-android": { + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-android/-/cli-platform-android-12.3.6.tgz", + "integrity": "sha512-DeDDAB8lHpuGIAPXeeD9Qu2+/wDTFPo99c8uSW49L0hkmZJixzvvvffbGQAYk32H0TmaI7rzvzH+qzu7z3891g==", + "peer": true, + "dependencies": { + "@react-native-community/cli-tools": "12.3.6", + "chalk": "^4.1.2", + "execa": "^5.0.0", + "fast-xml-parser": "^4.2.4", + "glob": "^7.1.3", + "logkitty": "^0.7.1" + } + }, + "node_modules/@react-native-community/cli-platform-android/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@react-native-community/cli-platform-android/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "peer": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@react-native-community/cli-platform-android/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@react-native-community/cli-platform-ios": { + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-ios/-/cli-platform-ios-12.3.6.tgz", + "integrity": "sha512-3eZ0jMCkKUO58wzPWlvAPRqezVKm9EPZyaPyHbRPWU8qw7JqkvnRlWIaYDGpjCJgVW4k2hKsEursLtYKb188tg==", + "peer": true, + "dependencies": { + "@react-native-community/cli-tools": "12.3.6", + "chalk": "^4.1.2", + "execa": "^5.0.0", + "fast-xml-parser": "^4.0.12", + "glob": "^7.1.3", + "ora": "^5.4.1" + } + }, + "node_modules/@react-native-community/cli-platform-ios/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@react-native-community/cli-platform-ios/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "peer": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@react-native-community/cli-platform-ios/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@react-native-community/cli-plugin-metro": { + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-plugin-metro/-/cli-plugin-metro-12.3.6.tgz", + "integrity": "sha512-3jxSBQt4fkS+KtHCPSyB5auIT+KKIrPCv9Dk14FbvOaEh9erUWEm/5PZWmtboW1z7CYeNbFMeXm9fM2xwtVOpg==", + "peer": true + }, + "node_modules/@react-native-community/cli-server-api": { + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-server-api/-/cli-server-api-12.3.6.tgz", + "integrity": "sha512-80NIMzo8b2W+PL0Jd7NjiJW9mgaT8Y8wsIT/lh6mAvYH7mK0ecDJUYUTAAv79Tbo1iCGPAr3T295DlVtS8s4yQ==", + "peer": true, + "dependencies": { + "@react-native-community/cli-debugger-ui": "12.3.6", + "@react-native-community/cli-tools": "12.3.6", + "compression": "^1.7.1", + "connect": "^3.6.5", + "errorhandler": "^1.5.1", + "nocache": "^3.0.1", + "pretty-format": "^26.6.2", + "serve-static": "^1.13.1", + "ws": "^7.5.1" + } + }, + "node_modules/@react-native-community/cli-server-api/node_modules/@jest/types": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "peer": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/@react-native-community/cli-server-api/node_modules/@types/yargs": { + "version": "15.0.19", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.19.tgz", + "integrity": "sha512-2XUaGVmyQjgyAZldf0D0c14vvo/yv0MhQBSTJcejMMaitsn3nxCB6TmH4G0ZQf+uxROOa9mpanoSm8h6SG/1ZA==", + "peer": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@react-native-community/cli-server-api/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@react-native-community/cli-server-api/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@react-native-community/cli-server-api/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@react-native-community/cli-server-api/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "peer": true + }, + "node_modules/@react-native-community/cli-server-api/node_modules/pretty-format": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "peer": true, + "dependencies": { + "@jest/types": "^26.6.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@react-native-community/cli-server-api/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "peer": true + }, + "node_modules/@react-native-community/cli-server-api/node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "peer": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@react-native-community/cli-tools": { + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-12.3.6.tgz", + "integrity": "sha512-FPEvZn19UTMMXUp/piwKZSh8cMEfO8G3KDtOwo53O347GTcwNrKjgZGtLSPELBX2gr+YlzEft3CoRv2Qmo83fQ==", + "peer": true, + "dependencies": { + "appdirsjs": "^1.2.4", + "chalk": "^4.1.2", + "find-up": "^5.0.0", + "mime": "^2.4.1", + "node-fetch": "^2.6.0", + "open": "^6.2.0", + "ora": "^5.4.1", + "semver": "^7.5.2", + "shell-quote": "^1.7.3", + "sudo-prompt": "^9.0.0" + } + }, + "node_modules/@react-native-community/cli-types": { + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-12.3.6.tgz", + "integrity": "sha512-xPqTgcUtZowQ8WKOkI9TLGBwH2bGggOC4d2FFaIRST3gTcjrEeGRNeR5aXCzJFIgItIft8sd7p2oKEdy90+01Q==", + "peer": true, + "dependencies": { + "joi": "^17.2.1" + } + }, + "node_modules/@react-native-community/cli/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "peer": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/@react-native-community/cli/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "peer": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@react-native-community/cli/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "peer": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/@react-native-community/cli/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "peer": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@react-native-community/cli/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "peer": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@react-native-community/cli/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "peer": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@react-native-community/cli/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "peer": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@react-native-community/cli/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "peer": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/@react-native/assets-registry": { + "version": "0.73.1", + "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.73.1.tgz", + "integrity": "sha512-2FgAbU7uKM5SbbW9QptPPZx8N9Ke2L7bsHb+EhAanZjFZunA9PaYtyjUQ1s7HD+zDVqOQIvjkpXSv7Kejd2tqg==", + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/babel-plugin-codegen": { + "version": "0.73.4", + "resolved": "https://registry.npmjs.org/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.73.4.tgz", + "integrity": "sha512-XzRd8MJGo4Zc5KsphDHBYJzS1ryOHg8I2gOZDAUCGcwLFhdyGu1zBNDJYH2GFyDrInn9TzAbRIf3d4O+eltXQQ==", + "peer": true, + "dependencies": { + "@react-native/codegen": "0.73.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/babel-preset": { + "version": "0.73.21", + "resolved": "https://registry.npmjs.org/@react-native/babel-preset/-/babel-preset-0.73.21.tgz", + "integrity": "sha512-WlFttNnySKQMeujN09fRmrdWqh46QyJluM5jdtDNrkl/2Hx6N4XeDUGhABvConeK95OidVO7sFFf7sNebVXogA==", + "peer": true, + "dependencies": { + "@babel/core": "^7.20.0", + "@babel/plugin-proposal-async-generator-functions": "^7.0.0", + "@babel/plugin-proposal-class-properties": "^7.18.0", + "@babel/plugin-proposal-export-default-from": "^7.0.0", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.0", + "@babel/plugin-proposal-numeric-separator": "^7.0.0", + "@babel/plugin-proposal-object-rest-spread": "^7.20.0", + "@babel/plugin-proposal-optional-catch-binding": "^7.0.0", + "@babel/plugin-proposal-optional-chaining": "^7.20.0", + "@babel/plugin-syntax-dynamic-import": "^7.8.0", + "@babel/plugin-syntax-export-default-from": "^7.0.0", + "@babel/plugin-syntax-flow": "^7.18.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.0.0", + "@babel/plugin-syntax-optional-chaining": "^7.0.0", + "@babel/plugin-transform-arrow-functions": "^7.0.0", + "@babel/plugin-transform-async-to-generator": "^7.20.0", + "@babel/plugin-transform-block-scoping": "^7.0.0", + "@babel/plugin-transform-classes": "^7.0.0", + "@babel/plugin-transform-computed-properties": "^7.0.0", + "@babel/plugin-transform-destructuring": "^7.20.0", + "@babel/plugin-transform-flow-strip-types": "^7.20.0", + "@babel/plugin-transform-function-name": "^7.0.0", + "@babel/plugin-transform-literals": "^7.0.0", + "@babel/plugin-transform-modules-commonjs": "^7.0.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.0.0", + "@babel/plugin-transform-parameters": "^7.0.0", + "@babel/plugin-transform-private-methods": "^7.22.5", + "@babel/plugin-transform-private-property-in-object": "^7.22.11", + "@babel/plugin-transform-react-display-name": "^7.0.0", + "@babel/plugin-transform-react-jsx": "^7.0.0", + "@babel/plugin-transform-react-jsx-self": "^7.0.0", + "@babel/plugin-transform-react-jsx-source": "^7.0.0", + "@babel/plugin-transform-runtime": "^7.0.0", + "@babel/plugin-transform-shorthand-properties": "^7.0.0", + "@babel/plugin-transform-spread": "^7.0.0", + "@babel/plugin-transform-sticky-regex": "^7.0.0", + "@babel/plugin-transform-typescript": "^7.5.0", + "@babel/plugin-transform-unicode-regex": "^7.0.0", + "@babel/template": "^7.0.0", + "@react-native/babel-plugin-codegen": "0.73.4", + "babel-plugin-transform-flow-enums": "^0.0.2", + "react-refresh": "^0.14.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@babel/core": "*" + } + }, + "node_modules/@react-native/codegen": { + "version": "0.73.3", + "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.73.3.tgz", + "integrity": "sha512-sxslCAAb8kM06vGy9Jyh4TtvjhcP36k/rvj2QE2Jdhdm61KvfafCATSIsOfc0QvnduWFcpXUPvAVyYwuv7PYDg==", + "peer": true, + "dependencies": { + "@babel/parser": "^7.20.0", + "flow-parser": "^0.206.0", + "glob": "^7.1.1", + "invariant": "^2.2.4", + "jscodeshift": "^0.14.0", + "mkdirp": "^0.5.1", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@babel/preset-env": "^7.1.6" + } + }, + "node_modules/@react-native/codegen/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@react-native/codegen/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "peer": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@react-native/codegen/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@react-native/codegen/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "peer": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/@react-native/community-cli-plugin": { + "version": "0.73.17", + "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.73.17.tgz", + "integrity": "sha512-F3PXZkcHg+1ARIr6FRQCQiB7ZAA+MQXGmq051metRscoLvgYJwj7dgC8pvgy0kexzUkHu5BNKrZeySzUft3xuQ==", + "peer": true, + "dependencies": { + "@react-native-community/cli-server-api": "12.3.6", + "@react-native-community/cli-tools": "12.3.6", + "@react-native/dev-middleware": "0.73.8", + "@react-native/metro-babel-transformer": "0.73.15", + "chalk": "^4.0.0", + "execa": "^5.1.1", + "metro": "^0.80.3", + "metro-config": "^0.80.3", + "metro-core": "^0.80.3", + "node-fetch": "^2.2.0", + "readline": "^1.3.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/debugger-frontend": { + "version": "0.73.3", + "resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.73.3.tgz", + "integrity": "sha512-RgEKnWuoo54dh7gQhV7kvzKhXZEhpF9LlMdZolyhGxHsBqZ2gXdibfDlfcARFFifPIiaZ3lXuOVVa4ei+uPgTw==", + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/dev-middleware": { + "version": "0.73.8", + "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.73.8.tgz", + "integrity": "sha512-oph4NamCIxkMfUL/fYtSsE+JbGOnrlawfQ0kKtDQ5xbOjPKotKoXqrs1eGwozNKv7FfQ393stk1by9a6DyASSg==", + "peer": true, + "dependencies": { + "@isaacs/ttlcache": "^1.4.1", + "@react-native/debugger-frontend": "0.73.3", + "chrome-launcher": "^0.15.2", + "chromium-edge-launcher": "^1.0.0", + "connect": "^3.6.5", + "debug": "^2.2.0", + "node-fetch": "^2.2.0", + "open": "^7.0.3", + "serve-static": "^1.13.1", + "temp-dir": "^2.0.0", + "ws": "^6.2.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/dev-middleware/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/@react-native/dev-middleware/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "peer": true + }, + "node_modules/@react-native/dev-middleware/node_modules/open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "peer": true, + "dependencies": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@react-native/dev-middleware/node_modules/ws": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz", + "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==", + "peer": true, + "dependencies": { + "async-limiter": "~1.0.0" + } + }, + "node_modules/@react-native/gradle-plugin": { + "version": "0.73.4", + "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.73.4.tgz", + "integrity": "sha512-PMDnbsZa+tD55Ug+W8CfqXiGoGneSSyrBZCMb5JfiB3AFST3Uj5e6lw8SgI/B6SKZF7lG0BhZ6YHZsRZ5MlXmg==", + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/js-polyfills": { + "version": "0.73.1", + "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.73.1.tgz", + "integrity": "sha512-ewMwGcumrilnF87H4jjrnvGZEaPFCAC4ebraEK+CurDDmwST/bIicI4hrOAv+0Z0F7DEK4O4H7r8q9vH7IbN4g==", + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/metro-babel-transformer": { + "version": "0.73.15", + "resolved": "https://registry.npmjs.org/@react-native/metro-babel-transformer/-/metro-babel-transformer-0.73.15.tgz", + "integrity": "sha512-LlkSGaXCz+xdxc9819plmpsl4P4gZndoFtpjN3GMBIu6f7TBV0GVbyJAU4GE8fuAWPVSVL5ArOcdkWKSbI1klw==", + "peer": true, + "dependencies": { + "@babel/core": "^7.20.0", + "@react-native/babel-preset": "0.73.21", + "hermes-parser": "0.15.0", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@babel/core": "*" + } + }, + "node_modules/@react-native/normalize-colors": { + "version": "0.73.2", + "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.73.2.tgz", + "integrity": "sha512-bRBcb2T+I88aG74LMVHaKms2p/T8aQd8+BZ7LuuzXlRfog1bMWWn/C5i0HVuvW4RPtXQYgIlGiXVDy9Ir1So/w==", + "peer": true + }, + "node_modules/@react-native/virtualized-lists": { + "version": "0.73.4", + "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.73.4.tgz", + "integrity": "sha512-HpmLg1FrEiDtrtAbXiwCgXFYyloK/dOIPIuWW3fsqukwJEWAiTzm1nXGJ7xPU5XTHiWZ4sKup5Ebaj8z7iyWog==", + "peer": true, + "dependencies": { + "invariant": "^2.2.4", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react-native": "*" + } + }, + "node_modules/@rollup/plugin-commonjs": { + "version": "25.0.7", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.7.tgz", + "integrity": "sha512-nEvcR+LRjEjsaSsc4x3XZfCCvZIaSMenZu/OiwOKGN2UhQpAYI7ru7czFvyWbErlpoGjnSX3D5Ch5FcMA3kRWQ==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "commondir": "^1.0.1", + "estree-walker": "^2.0.2", + "glob": "^8.0.3", + "is-reference": "1.2.1", + "magic-string": "^0.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.68.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-commonjs/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@rollup/plugin-commonjs/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@rollup/plugin-json": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz", + "integrity": "sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.1.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "15.2.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz", + "integrity": "sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-builtin-module": "^3.2.1", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.78.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-replace": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.5.tgz", + "integrity": "sha512-rYO4fOi8lMaTg/z5Jb+hKnrHHVn8j2lwkqwyS4kTRhKyWOLf2wST2sWXr4WzWiTcoHTp2sTjqUbqIj2E39slKQ==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "magic-string": "^0.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-terser": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", + "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==", + "dev": true, + "dependencies": { + "serialize-javascript": "^6.0.1", + "smob": "^1.0.0", + "terser": "^5.17.4" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-typescript": { + "version": "11.1.6", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-11.1.6.tgz", + "integrity": "sha512-R92yOmIACgYdJ7dJ97p4K69I8gg6IEHt8M7dUBxN3W6nrO8uUxX5ixl0yU/N3aZTi8WhPuICvOHXQvF6FaykAA==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.1.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.14.0||^3.0.0||^4.0.0", + "tslib": "*", + "typescript": ">=3.7.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + }, + "tslib": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz", + "integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.14.3.tgz", + "integrity": "sha512-X9alQ3XM6I9IlSlmC8ddAvMSyG1WuHk5oUnXGw+yUBs3BFoTizmG1La/Gr8fVJvDWAq+zlYTZ9DBgrlKRVY06g==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.14.3.tgz", + "integrity": "sha512-eQK5JIi+POhFpzk+LnjKIy4Ks+pwJ+NXmPxOCSvOKSNRPONzKuUvWE+P9JxGZVxrtzm6BAYMaL50FFuPe0oWMQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.14.3.tgz", + "integrity": "sha512-Od4vE6f6CTT53yM1jgcLqNfItTsLt5zE46fdPaEmeFHvPs5SjZYlLpHrSiHEKR1+HdRfxuzXHjDOIxQyC3ptBA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.14.3.tgz", + "integrity": "sha512-0IMAO21axJeNIrvS9lSe/PGthc8ZUS+zC53O0VhF5gMxfmcKAP4ESkKOCwEi6u2asUrt4mQv2rjY8QseIEb1aw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.14.3.tgz", + "integrity": "sha512-ge2DC7tHRHa3caVEoSbPRJpq7azhG+xYsd6u2MEnJ6XzPSzQsTKyXvh6iWjXRf7Rt9ykIUWHtl0Uz3T6yXPpKw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.14.3.tgz", + "integrity": "sha512-ljcuiDI4V3ySuc7eSk4lQ9wU8J8r8KrOUvB2U+TtK0TiW6OFDmJ+DdIjjwZHIw9CNxzbmXY39wwpzYuFDwNXuw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.14.3.tgz", + "integrity": "sha512-Eci2us9VTHm1eSyn5/eEpaC7eP/mp5n46gTRB3Aar3BgSvDQGJZuicyq6TsH4HngNBgVqC5sDYxOzTExSU+NjA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.14.3.tgz", + "integrity": "sha512-UrBoMLCq4E92/LCqlh+blpqMz5h1tJttPIniwUgOFJyjWI1qrtrDhhpHPuFxULlUmjFHfloWdixtDhSxJt5iKw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.14.3.tgz", + "integrity": "sha512-5aRjvsS8q1nWN8AoRfrq5+9IflC3P1leMoy4r2WjXyFqf3qcqsxRCfxtZIV58tCxd+Yv7WELPcO9mY9aeQyAmw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.14.3.tgz", + "integrity": "sha512-sk/Qh1j2/RJSX7FhEpJn8n0ndxy/uf0kI/9Zc4b1ELhqULVdTfN6HL31CDaTChiBAOgLcsJ1sgVZjWv8XNEsAQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.14.3.tgz", + "integrity": "sha512-jOO/PEaDitOmY9TgkxF/TQIjXySQe5KVYB57H/8LRP/ux0ZoO8cSHCX17asMSv3ruwslXW/TLBcxyaUzGRHcqg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.14.3.tgz", + "integrity": "sha512-8ybV4Xjy59xLMyWo3GCfEGqtKV5M5gCSrZlxkPGvEPCGDLNla7v48S662HSGwRd6/2cSneMQWiv+QzcttLrrOA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.14.3.tgz", + "integrity": "sha512-s+xf1I46trOY10OqAtZ5Rm6lzHre/UiLA1J2uOhCFXWkbZrJRkYBPO6FhvGfHmdtQ3Bx793MNa7LvoWFAm93bg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.14.3.tgz", + "integrity": "sha512-+4h2WrGOYsOumDQ5S2sYNyhVfrue+9tc9XcLWLh+Kw3UOxAvrfOrSMFon60KspcDdytkNDh7K2Vs6eMaYImAZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.14.3.tgz", + "integrity": "sha512-T1l7y/bCeL/kUwh9OD4PQT4aM7Bq43vX05htPJJ46RTI4r5KNt6qJRzAfNfM+OYMNEVBWQzR2Gyk+FXLZfogGw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.14.3.tgz", + "integrity": "sha512-/BypzV0H1y1HzgYpxqRaXGBRqfodgoBBCcsrujT6QRcakDQdfU+Lq9PENPh5jB4I44YWq+0C2eHsHya+nZY1sA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sideway/address": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", + "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", + "peer": true, + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", + "peer": true + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", + "peer": true + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==" + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", + "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "peer": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@sinonjs/fake-timers/node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "peer": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/formatio": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.2.tgz", + "integrity": "sha512-B8SEsgd8gArBLMD6zpRw3juQ2FVSsmdd7qlevyDqzS9WTCtvF55/gAL+h6gue8ZvPYcdiPdvueM/qm//9XzyTQ==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1", + "@sinonjs/samsam": "^3.1.0" + } + }, + "node_modules/@sinonjs/samsam": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.3.tgz", + "integrity": "sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.3.0", + "array-from": "^2.1.1", + "lodash": "^4.17.15" + } + }, + "node_modules/@sinonjs/text-encoding": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", + "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", + "dev": true + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.1.tgz", + "integrity": "sha512-dzJtaDAAoXx4GCOJpbB2eG/Qj8VDpdwkLsWGzGm+0L7E8/434RyMbAHmk9ubXWVAb9nXmc44jUf8GKqVDiKezg==", + "dev": true + }, + "node_modules/@teppeis/multimaps": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@teppeis/multimaps/-/multimaps-3.0.0.tgz", + "integrity": "sha512-ID7fosbc50TbT0MK0EG12O+gAP3W3Aa/Pz4DaTtQtEvlc9Odaqi0de+xuZ7Li2GtK4HzEX7IuRWS/JmZLksR3Q==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==" + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, + "node_modules/@types/cbor-js": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@types/cbor-js/-/cbor-js-0.1.1.tgz", + "integrity": "sha512-pfCx/EZC7VNBThwAQ0XvGPOXYm8BUk+gSVonaIGcEKBuqGJHTdcwAGW8WZkdRs/u9n9yOt1pBoPTCS1s8ZYpEQ==", + "dev": true + }, + "node_modules/@types/chai": { + "version": "4.3.14", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.14.tgz", + "integrity": "sha512-Wj71sXE4Q4AkGdG9Tvq1u/fquNz9EdG4LIJMwVVII7ashjD/8cf8fyIfJAjRr6YcsXnSE8cOGQPq1gqeR8z+3w==", + "dev": true + }, + "node_modules/@types/chai-as-promised": { + "version": "7.1.8", + "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-7.1.8.tgz", + "integrity": "sha512-ThlRVIJhr69FLlh6IctTXFkmhtP3NpMZ2QGq69StYLyKZFp/HOp1VdKZj7RvfNWYYcJ1xlbLGLLWj1UvP5u/Gw==", + "dev": true, + "dependencies": { + "@types/chai": "*" + } + }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", + "dev": true + }, + "node_modules/@types/cors": { + "version": "2.8.17", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", + "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cucumber": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@types/cucumber/-/cucumber-7.0.0.tgz", + "integrity": "sha512-cr5NN8/jmbw3vDKTQfGW0cSzDtkvxixu9bUD6po9U6OEF04XLuukTDldFG34ccDscLkA8bYnZ7VjxP79cIC7tg==", + "deprecated": "This is a stub types definition. @cucumber/cucumber provides its own type definitions, so you do not need this installed.", + "dev": true, + "dependencies": { + "@cucumber/cucumber": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/@types/expect": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/@types/expect/-/expect-24.3.0.tgz", + "integrity": "sha512-aq5Z+YFBz5o2b6Sp1jigx5nsmoZMK5Ceurjwy6PZmRv7dEi1jLtkARfvB1ME+OXJUG+7TZUDcv3WoCr/aor6dQ==", + "deprecated": "This is a stub types definition. expect provides its own type definitions, so you do not need this installed.", + "dev": true, + "dependencies": { + "expect": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "optional": true + }, + "node_modules/@types/lil-uuid": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@types/lil-uuid/-/lil-uuid-0.1.3.tgz", + "integrity": "sha512-UozexIWHw7bnQtbfdMqv1u82JmMl63t7lrCXpX6kByNH1F77j+Cdeqx28djuveoFvan9YUYrvK+ys1/hKIOgeA==", + "dev": true + }, + "node_modules/@types/mocha": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz", + "integrity": "sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==", + "dev": true + }, + "node_modules/@types/nock": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/@types/nock/-/nock-9.3.1.tgz", + "integrity": "sha512-eOVHXS5RnWOjTVhu3deCM/ruy9E6JCgeix2g7wpFiekQh3AaEAK1cz43tZDukKmtSmQnwvSySq7ubijCA32I7Q==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "20.12.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", + "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/node-fetch": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", + "dev": true, + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.0" + } + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true + }, + "node_modules/@types/pubnub": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@types/pubnub/-/pubnub-7.4.2.tgz", + "integrity": "sha512-Vjkol3ix8IMrFdwtrLP9XkWc93cWDYpfs4tK6pvOUi8/G5+og2NRJ0AcGhMAQ4wuciHxDzJNkpPIGpRAgYAa4A==", + "dev": true + }, + "node_modules/@types/resolve": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "dev": true + }, + "node_modules/@types/sinon": { + "version": "17.0.3", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-17.0.3.tgz", + "integrity": "sha512-j3uovdn8ewky9kRBG19bOwaZbexJu/XjtkHyjvUgt4xfPFz18dcORIMqnYh66Fx3Powhcr85NT5+er3+oViapw==", + "dev": true, + "dependencies": { + "@types/sinonjs__fake-timers": "*" + } + }, + "node_modules/@types/sinonjs__fake-timers": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.5.tgz", + "integrity": "sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==", + "dev": true + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==" + }, + "node_modules/@types/text-encoding": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/text-encoding/-/text-encoding-0.0.39.tgz", + "integrity": "sha512-gRPvgL1aMgP6Pv92Rs310cJvVQ86DSF62E7K30g1FoGmmYWXoNuXT8PV835iAVeiAZkRwr2IW37KuyDn9ljmeA==", + "dev": true + }, + "node_modules/@types/underscore": { + "version": "1.11.15", + "resolved": "https://registry.npmjs.org/@types/underscore/-/underscore-1.11.15.tgz", + "integrity": "sha512-HP38xE+GuWGlbSRq9WrZkousaQ7dragtZCruBVMi0oX1migFZavZ3OROKHSkNp/9ouq82zrWtZpg18jFnVN96g==", + "dev": true + }, + "node_modules/@types/uuid": { + "version": "9.0.8", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", + "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==", + "dev": true + }, + "node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.0.tgz", + "integrity": "sha512-GJWR0YnfrKnsRoluVO3PRb9r5aMZriiMMM/RHj5nnTrBy1/wIgk76XCtCKcnXGjpZQJQRFtGV9/0JJ6n30uwpQ==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.7.0", + "@typescript-eslint/type-utils": "7.7.0", + "@typescript-eslint/utils": "7.7.0", + "@typescript-eslint/visitor-keys": "7.7.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.7.0.tgz", + "integrity": "sha512-fNcDm3wSwVM8QYL4HKVBggdIPAy9Q41vcvC/GtDobw3c4ndVT3K6cqudUmjHPw8EAp4ufax0o58/xvWaP2FmTg==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "7.7.0", + "@typescript-eslint/types": "7.7.0", + "@typescript-eslint/typescript-estree": "7.7.0", + "@typescript-eslint/visitor-keys": "7.7.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.7.0.tgz", + "integrity": "sha512-/8INDn0YLInbe9Wt7dK4cXLDYp0fNHP5xKLHvZl3mOT5X17rK/YShXaiNmorl+/U4VKCVIjJnx4Ri5b0y+HClw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.7.0", + "@typescript-eslint/visitor-keys": "7.7.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.7.0.tgz", + "integrity": "sha512-bOp3ejoRYrhAlnT/bozNQi3nio9tIgv3U5C0mVDdZC7cpcQEDZXvq8inrHYghLVwuNABRqrMW5tzAv88Vy77Sg==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "7.7.0", + "@typescript-eslint/utils": "7.7.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.7.0.tgz", + "integrity": "sha512-G01YPZ1Bd2hn+KPpIbrAhEWOn5lQBrjxkzHkWvP6NucMXFtfXoevK82hzQdpfuQYuhkvFDeQYbzXCjR1z9Z03w==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.0.tgz", + "integrity": "sha512-8p71HQPE6CbxIBy2kWHqM1KGrC07pk6RJn40n0DSc6bMOBBREZxSDJ+BmRzc8B5OdaMh1ty3mkuWRg4sCFiDQQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.7.0", + "@typescript-eslint/visitor-keys": "7.7.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.7.0.tgz", + "integrity": "sha512-LKGAXMPQs8U/zMRFXDZOzmMKgFv3COlxUQ+2NMPhbqgVm6R1w+nU1i4836Pmxu9jZAuIeyySNrN/6Rc657ggig==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.15", + "@types/semver": "^7.5.8", + "@typescript-eslint/scope-manager": "7.7.0", + "@typescript-eslint/types": "7.7.0", + "@typescript-eslint/typescript-estree": "7.7.0", + "semver": "^7.6.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.0.tgz", + "integrity": "sha512-h0WHOj8MhdhY8YWkzIF30R379y0NqyOHExI9N9KCzvmu05EgG4FumeYa3ccfKUSphyWkWQE1ybVrgz/Pbam6YA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.7.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "peer": true, + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/agentkeepalive": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.2.tgz", + "integrity": "sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ==", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/anser": { + "version": "1.4.10", + "resolved": "https://registry.npmjs.org/anser/-/anser-1.4.10.tgz", + "integrity": "sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==", + "peer": true + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-fragments": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ansi-fragments/-/ansi-fragments-0.2.1.tgz", + "integrity": "sha512-DykbNHxuXQwUDRv5ibc2b0x7uw7wmwOGLBUd5RmaQ5z8Lhx19vwvKV+FAsM5rEA6dEcHxX+/Ad5s9eF2k2bB+w==", + "peer": true, + "dependencies": { + "colorette": "^1.0.7", + "slice-ansi": "^2.0.0", + "strip-ansi": "^5.0.0" + } + }, + "node_modules/ansi-fragments/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "peer": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/appdirsjs": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/appdirsjs/-/appdirsjs-1.2.7.tgz", + "integrity": "sha512-Quji6+8kLBC3NnBeo14nPDq0+2jUs5s3/xEye+udFHumHhRk4M7aAMXp/PBJqkKYGuuyR9M/6Dq7d2AViiGmhw==", + "peer": true + }, + "node_modules/arg": { + "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", "dev": true }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-from": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", + "integrity": "sha512-GQTc6Uupx1FCavi5mPzBvVT7nEOeWMmUA9P95wpfpW1XwMSKs+KaymD5C2Up7KAUKg/mYwbsUYzdZWcoajlNZg==", + "dev": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "peer": true + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dev": true, + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/assertion-error-formatter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/assertion-error-formatter/-/assertion-error-formatter-3.0.0.tgz", + "integrity": "sha512-6YyAVLrEze0kQ7CmJfUgrLHb+Y7XghmL2Ie7ijVa2Y9ynP3LV+VDiwFk62Dn0qtqbmY0BT0ss6p1xxpiF2PYbQ==", + "dev": true, + "dependencies": { + "diff": "^4.0.1", + "pad-right": "^0.2.2", + "repeat-string": "^1.6.1" + } + }, + "node_modules/ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "peer": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", + "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", + "dev": true + }, + "node_modules/babel-core": { + "version": "7.0.0-bridge.0", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz", + "integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==", + "peer": true, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.10", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.10.tgz", + "integrity": "sha512-rpIuu//y5OX6jVU+a5BCn1R5RSZYWAl2Nar76iwaOdycqb6JPxediskWFMMl7stfwNJR4b7eiQvh5fB5TEQJTQ==", + "peer": true, + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.1", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "peer": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.4.tgz", + "integrity": "sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg==", + "peer": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.1", + "core-js-compat": "^3.36.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.1.tgz", + "integrity": "sha512-JfTApdE++cgcTWjsiCQlLyFBMbTUft9ja17saCc93lgV33h4tuCVj7tlvu//qpLwaG+3yEz7/KhahGrUMkVq9g==", + "peer": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-transform-flow-enums": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-flow-enums/-/babel-plugin-transform-flow-enums-0.0.2.tgz", + "integrity": "sha512-g4aaCrDDOsWjbm0PUUeVnkcVd6AKJsVc/MbnPhEotEpkeJQP6b8nzewohQi7+QS8UyPehOhGWn0nOwjvWpmMvQ==", + "peer": true, + "dependencies": { + "@babel/plugin-syntax-flow": "^7.12.1" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "dev": true, + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/basic-ftp": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", + "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dev": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/becke-ch--regex--s0-0-v1--base--pl--lib": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/becke-ch--regex--s0-0-v1--base--pl--lib/-/becke-ch--regex--s0-0-v1--base--pl--lib-1.4.0.tgz", + "integrity": "sha512-FnWonOyaw7Vivg5nIkrUll9HSS5TjFbyuURAiDssuL6VxrBe3ERzudRxOcWRhZYlP89UArMDikz7SapRPQpmZQ==", + "dev": true, + "peer": true + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "peer": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "peer": true, + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "peer": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true, + "peer": true + }, + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/browserslist": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "peer": true, + "dependencies": { + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "peer": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ==", + "peer": true, + "dependencies": { + "callsites": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/caller-callsite/node_modules/callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ==", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A==", + "peer": true, + "dependencies": { + "caller-callsite": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001611", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001611.tgz", + "integrity": "sha512-19NuN1/3PjA3QI8Eki55N8my4LzfkMCRLgCVfrl/slbSAchQfV0+GwjPrK3rq37As4UCLlM/DHajbKkAqbv92Q==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "peer": true + }, + "node_modules/capital-case": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/capital-case/-/capital-case-1.0.4.tgz", + "integrity": "sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3", + "upper-case-first": "^2.0.2" + } + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "dev": true + }, + "node_modules/cbor-js": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/cbor-js/-/cbor-js-0.1.0.tgz", + "integrity": "sha512-7sQ/TvDZPl7csT1Sif9G0+MA0I0JOVah8+wWlJVQdVEgIbCzlN/ab3x+uvMNsc34TUvO6osQTAmB2ls80JX6tw==" + }, + "node_modules/cbor-sync": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cbor-sync/-/cbor-sync-1.0.4.tgz", + "integrity": "sha512-GWlXN4wiz0vdWWXBU71Dvc1q3aBo0HytqwAZnXF1wOwjqNnDWA1vZ1gDMFLlqohak31VQzmhiYfiCX5QSSfagA==" + }, + "node_modules/chai": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", + "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.0.8" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chai-as-promised": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz", + "integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==", + "dev": true, + "dependencies": { + "check-error": "^1.0.2" + }, + "peerDependencies": { + "chai": ">= 2.1.2 < 5" + } + }, + "node_modules/chai-nock": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/chai-nock/-/chai-nock-1.3.0.tgz", + "integrity": "sha512-O3j1bW3ACoUu/sLGYSoX50c1p8dbTkCjw3/dereqzl9BL2XsQAUVC18sJpg3hVwpCk71rjWGumCmHy87t5W+Pg==", + "dev": true, + "dependencies": { + "chai": "^4.2.0", + "deep-equal": "^1.0.1" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/chalk/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/chalk/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chrome-launcher": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.2.tgz", + "integrity": "sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==", + "peer": true, + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0" + }, + "bin": { + "print-chrome-path": "bin/print-chrome-path.js" + }, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/chrome-launcher/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chromium-edge-launcher": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/chromium-edge-launcher/-/chromium-edge-launcher-1.0.0.tgz", + "integrity": "sha512-pgtgjNKZ7i5U++1g1PWv75umkHvhVTDOQIZ+sjeUX9483S7Y6MUvO0lrd7ShGlQlFHMN4SwKTCq/X8hWrbv2KA==", + "peer": true, + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0", + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + } + }, + "node_modules/chromium-edge-launcher/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chromium-edge-launcher/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "peer": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/class-transformer": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", + "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==", + "dev": true + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "peer": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "peer": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-table3": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", + "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/cliui/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "peer": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "peer": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/colorette": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", + "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", + "peer": true + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/command-exists": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", + "peer": true + }, + "node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "peer": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "peer": true, + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "peer": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "peer": true + }, + "node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/core-js-compat": { + "version": "3.37.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.0.tgz", + "integrity": "sha512-vYq4L+T8aS5UuFg4UwDhc7YNRWVeVZwltad9C/jV3R2LgVOpS9BDr7l/WL6BN0dbV3k1XejPTHqqEzJgsa0frA==", + "peer": true, + "dependencies": { + "browserslist": "^4.23.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-pure": { + "version": "3.37.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.37.0.tgz", + "integrity": "sha512-d3BrpyFr5eD4KcbRvQ3FTUx/KWmaDesr7+a3+1+P46IUnNoEt+oiLijPINZMEon7w9oGkIINWxrBAU9DEciwFQ==", + "dev": true, + "hasInstallScript": true, + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "peer": true, + "dependencies": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cosmiconfig/node_modules/import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==", + "peer": true, + "dependencies": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cosmiconfig/node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "peer": true, + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cosmiconfig/node_modules/resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cucumber": { + "version": "6.0.7", + "resolved": "https://registry.npmjs.org/cucumber/-/cucumber-6.0.7.tgz", + "integrity": "sha512-pN3AgWxHx8rOi+wOlqjASNETOjf3TgeyqhMNLQam7nSTXgQzju1oAmXkleRQRcXvpVvejcDHiZBLFSfBkqbYpA==", + "deprecated": "Cucumber is publishing new releases under @cucumber/cucumber", + "dev": true, + "peer": true, + "dependencies": { + "assertion-error-formatter": "^3.0.0", + "bluebird": "^3.4.1", + "cli-table3": "^0.5.1", + "colors": "^1.1.2", + "commander": "^3.0.1", + "cucumber-expressions": "^8.1.0", + "cucumber-tag-expressions": "^2.0.2", + "duration": "^0.2.1", + "escape-string-regexp": "^2.0.0", + "figures": "^3.0.0", + "gherkin": "5.0.0", + "glob": "^7.1.3", + "indent-string": "^4.0.0", + "is-generator": "^1.0.2", + "is-stream": "^2.0.0", + "knuth-shuffle-seeded": "^1.0.6", + "lodash": "^4.17.14", + "mz": "^2.4.0", + "progress": "^2.0.0", + "resolve": "^1.3.3", + "serialize-error": "^4.1.0", + "stack-chain": "^2.0.0", + "stacktrace-js": "^2.0.0", + "string-argv": "^0.3.0", + "title-case": "^2.1.1", + "util-arity": "^1.0.2", + "verror": "^1.9.0" + }, + "bin": { + "cucumber-js": "bin/cucumber-js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cucumber-expressions": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/cucumber-expressions/-/cucumber-expressions-8.3.0.tgz", + "integrity": "sha512-cP2ya0EiorwXBC7Ll7Cj7NELYbasNv9Ty42L4u7sso9KruWemWG1ZiTq4PMqir3SNDSrbykoqI5wZgMbLEDjLQ==", + "deprecated": "This package is now published under @cucumber/cucumber-expressions", + "dev": true, + "peer": true, + "dependencies": { + "becke-ch--regex--s0-0-v1--base--pl--lib": "^1.4.0", + "xregexp": "^4.2.4" + } + }, + "node_modules/cucumber-pretty": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/cucumber-pretty/-/cucumber-pretty-6.0.1.tgz", + "integrity": "sha512-9uOIZ8x3lgCPROqYc7kqe2e7UrH5TZPZCdj5fVPze1XViG9yv8/8MnFsAnVINDYWVhiql8DJHb3UrZfIPHYH/A==", + "dev": true, + "dependencies": { + "cli-table3": "^0.6.0", + "colors": "^1.4.0", + "figures": "^3.2.0" + }, + "peerDependencies": { + "cucumber": ">=6.0.0 <7.0.0" + } + }, + "node_modules/cucumber-tag-expressions": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/cucumber-tag-expressions/-/cucumber-tag-expressions-2.0.3.tgz", + "integrity": "sha512-+x5j1IfZrBtbvYHuoUX0rl4nUGxaey6Do9sM0CABmZfDCcWXuuRm1fQeCaklIYQgOFHQ6xOHvDSdkMHHpni6tQ==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dev": true, + "peer": true + }, + "node_modules/cucumber-tsflow": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/cucumber-tsflow/-/cucumber-tsflow-4.4.4.tgz", + "integrity": "sha512-oe2fPcAxWljZTc4+u0whbXIxZvjWzXfsieoY/TGuHY4aDLLOCFVLOVIxV8bKEI53PQhxJH809VugWHe2DB+nJg==", + "dev": true, + "dependencies": { + "callsites": "^3.1.0", + "log4js": "^6.3.0", + "source-map-support": "^0.5.19", + "underscore": "^1.8.3" + }, + "peerDependencies": { + "@cucumber/cucumber": "^7 || ^8 || ^9 || ^10" + } + }, + "node_modules/cucumber/node_modules/ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/cucumber/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/cucumber/node_modules/cli-table3": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz", + "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", + "dev": true, + "peer": true, + "dependencies": { + "object-assign": "^4.1.0", + "string-width": "^2.1.1" + }, + "engines": { + "node": ">=6" + }, + "optionalDependencies": { + "colors": "^1.1.2" + } + }, + "node_modules/cucumber/node_modules/commander": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", + "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==", + "dev": true, + "peer": true + }, + "node_modules/cucumber/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "peer": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cucumber/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/cucumber/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/cucumber/node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "peer": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cucumber/node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==", + "dev": true + }, + "node_modules/d": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", + "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", + "dev": true, + "peer": true, + "dependencies": { + "es5-ext": "^0.10.64", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", + "engines": { + "node": ">= 14" + } + }, + "node_modules/date-format": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", + "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/dayjs": { + "version": "1.11.10", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", + "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==", + "peer": true + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-equal": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.2.tgz", + "integrity": "sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==", + "dev": true, + "dependencies": { + "is-arguments": "^1.1.1", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.5.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "peer": true, + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/degenerator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "dependencies": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/denodeify": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/denodeify/-/denodeify-1.2.1.tgz", + "integrity": "sha512-KNTihKNmQENUZeKu5fzfpzRqR5S2VMp4gl9RFHiWzj9DfvYQPMJ6XHKNaQxaGCXwPk6y9yme3aUoaiAe+KX+vg==", + "peer": true + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/deprecated-react-native-prop-types": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-5.0.0.tgz", + "integrity": "sha512-cIK8KYiiGVOFsKdPMmm1L3tA/Gl+JopXL6F5+C7x39MyPsQYnP57Im/D6bNUzcborD7fcMwiwZqcBdBXXZucYQ==", + "peer": true, + "dependencies": { + "@react-native/normalize-colors": "^0.73.0", + "invariant": "^2.2.4", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/di": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", + "dev": true + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-serialize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==", + "dev": true, + "dependencies": { + "custom-event": "~1.0.0", + "ent": "~2.2.0", + "extend": "^3.0.0", + "void-elements": "^2.0.0" + } + }, + "node_modules/duration": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/duration/-/duration-0.2.2.tgz", + "integrity": "sha512-06kgtea+bGreF5eKYgI/36A6pLXggY7oR4p1pq4SmdFBn1ReOL5D8RhG64VrqfTTKNucqqtBAwEj8aB88mcqrg==", + "dev": true, + "peer": true, + "dependencies": { + "d": "1", + "es5-ext": "~0.10.46" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dev": true, + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/ecc-jsbn/node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "dev": true + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/electron-to-chromium": { + "version": "1.4.740", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.740.tgz", + "integrity": "sha512-Yvg5i+iyv7Xm18BRdVPVm8lc7kgxM3r6iwqCH2zB7QZy1kZRNmd0Zqm0zcD9XoFREE5/5rwIuIAOT+/mzGcnZg==", + "peer": true + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/engine.io": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.4.tgz", + "integrity": "sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==", + "dev": true, + "dependencies": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz", + "integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", + "dev": true + }, + "node_modules/envinfo": { + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.12.0.tgz", + "integrity": "sha512-Iw9rQJBGpJRd3rwXm9ft/JiGoAZmLxxJZELYDQoPRZ4USVhkKtIcNBPw6U+/K2mBpaqM25JSV6Yl4Az9vO2wJg==", + "peer": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "dependencies": { + "stackframe": "^1.3.4" + } + }, + "node_modules/errorhandler": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/errorhandler/-/errorhandler-1.5.1.tgz", + "integrity": "sha512-rcOwbfvP1WTViVoUjcfZicVzjhjTuhSMntHh6mW3IrEiyE6mJyXvsToJUJGlGlw/2xU9P5whlWNGlIDVeCiT4A==", + "peer": true, + "dependencies": { + "accepts": "~1.3.7", + "escape-html": "~1.0.3" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", "dev": true, "dependencies": { - "sprintf-js": "~1.0.2" + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" } }, - "node_modules/array-from": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", - "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", - "dev": true - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "dev": true, "engines": { - "node": ">=8" + "node": ">= 0.4" } }, - "node_modules/arraybuffer.slice": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", - "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", - "dev": true - }, - "node_modules/arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "node_modules/es5-ext": { + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", "dev": true, + "hasInstallScript": true, + "peer": true, + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=0.10" } }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" - }, - "node_modules/asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", "dev": true, + "peer": true, "dependencies": { - "safer-buffer": "~2.1.0" + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" } }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true + }, + "node_modules/es6-shim": { + "version": "0.35.8", + "resolved": "https://registry.npmjs.org/es6-shim/-/es6-shim-0.35.8.tgz", + "integrity": "sha512-Twf7I2v4/1tLoIXMT8HlqaBSS5H2wQTs2wx3MNYCI8K1R1/clXyCazrcVCPm/FuO9cyV8+leEaZOWD5C253NDg==", + "dev": true + }, + "node_modules/es6-symbol": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", + "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", "dev": true, + "peer": true, + "dependencies": { + "d": "^1.0.2", + "ext": "^1.7.0" + }, "engines": { - "node": ">=0.8" + "node": ">=0.12" } }, - "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "node_modules/esbuild": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", + "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, "engines": { - "node": "*" + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.19.12", + "@esbuild/android-arm": "0.19.12", + "@esbuild/android-arm64": "0.19.12", + "@esbuild/android-x64": "0.19.12", + "@esbuild/darwin-arm64": "0.19.12", + "@esbuild/darwin-x64": "0.19.12", + "@esbuild/freebsd-arm64": "0.19.12", + "@esbuild/freebsd-x64": "0.19.12", + "@esbuild/linux-arm": "0.19.12", + "@esbuild/linux-arm64": "0.19.12", + "@esbuild/linux-ia32": "0.19.12", + "@esbuild/linux-loong64": "0.19.12", + "@esbuild/linux-mips64el": "0.19.12", + "@esbuild/linux-ppc64": "0.19.12", + "@esbuild/linux-riscv64": "0.19.12", + "@esbuild/linux-s390x": "0.19.12", + "@esbuild/linux-x64": "0.19.12", + "@esbuild/netbsd-x64": "0.19.12", + "@esbuild/openbsd-x64": "0.19.12", + "@esbuild/sunos-x64": "0.19.12", + "@esbuild/win32-arm64": "0.19.12", + "@esbuild/win32-ia32": "0.19.12", + "@esbuild/win32-x64": "0.19.12" } }, - "node_modules/assertion-error-formatter": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/assertion-error-formatter/-/assertion-error-formatter-3.0.0.tgz", - "integrity": "sha512-6YyAVLrEze0kQ7CmJfUgrLHb+Y7XghmL2Ie7ijVa2Y9ynP3LV+VDiwFk62Dn0qtqbmY0BT0ss6p1xxpiF2PYbQ==", - "dev": true, - "dependencies": { - "diff": "^4.0.1", - "pad-right": "^0.2.2", - "repeat-string": "^1.6.1" + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "engines": { + "node": ">=6" } }, - "node_modules/ast-types": { - "version": "0.13.4", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", - "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", "dependencies": { - "tslib": "^2.0.1" + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" }, "engines": { - "node": ">=4" + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" } }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "node_modules/eslint": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, "engines": { - "node": "*" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", - "dev": true - }, - "node_modules/backo2": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", - "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", - "dev": true - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/base64-arraybuffer": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz", - "integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI=", + "node_modules/eslint-plugin-mocha": { + "version": "10.4.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-10.4.2.tgz", + "integrity": "sha512-cur4dVYnSEWTBwdqIBQFxa/9siAhesu0TX+lbJ4ClE9j0eNMNe6BSx3vkFFNz6tGoveyMyELFXa30f3fvuAVDg==", "dev": true, + "dependencies": { + "eslint-utils": "^3.0.0", + "globals": "^13.24.0", + "rambda": "^7.4.0" + }, "engines": { - "node": ">= 0.6.0" + "node": ">=14.0.0" + }, + "peerDependencies": { + "eslint": ">=7.0.0" } }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" + "node_modules/eslint-plugin-prettier": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", + "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.6" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": "*", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true }, - { - "type": "consulting", - "url": "https://feross.org/support" + "eslint-config-prettier": { + "optional": true } - ] + } }, - "node_modules/base64id": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", - "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true, "engines": { - "node": "^4.5.0 || >= 5.9" + "node": ">=10" } }, - "node_modules/basic-ftp": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.4.tgz", - "integrity": "sha512-8PzkB0arJFV4jJWSGOYR+OEic6aeKMu/osRhBULN6RY0ykby6LKhbmuQ5ublvaas5BOwboah5D87nrHyuh8PPA==", + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, "engines": { - "node": ">=10.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "node_modules/eslint/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "dependencies": { - "tweetnacl": "^0.14.3" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/becke-ch--regex--s0-0-v1--base--pl--lib": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/becke-ch--regex--s0-0-v1--base--pl--lib/-/becke-ch--regex--s0-0-v1--base--pl--lib-1.4.0.tgz", - "integrity": "sha512-FnWonOyaw7Vivg5nIkrUll9HSS5TjFbyuURAiDssuL6VxrBe3ERzudRxOcWRhZYlP89UArMDikz7SapRPQpmZQ==", - "dev": true, - "peer": true - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/blob": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", - "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==", - "dev": true - }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, - "node_modules/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==", + "node_modules/eslint/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.8.1", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.9.7", - "raw-body": "2.4.3", - "type-is": "~1.6.18" + "argparse": "^2.0.1" }, - "engines": { - "node": ">= 0.8" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "dependencies": { - "ms": "2.0.0" + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", "dev": true, + "peer": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.10" } }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" }, "engines": { - "node": ">=8" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } }, - "node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" } }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, "engines": { - "node": "*" + "node": ">=4.0" } }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "dev": true }, - "node_modules/builtin-modules": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz", - "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==", - "dev": true, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", "dev": true, + "peer": true, + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "peer": true, "engines": { - "node": ">= 0.8" + "node": ">=6" } }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "peer": true, "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "node_modules/execa/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "peer": true + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", "dev": true, + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, "engines": { - "node": ">=6" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "node_modules/ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", "dev": true, - "engines": { - "node": ">=6" + "peer": true, + "dependencies": { + "type": "^2.7.2" } }, - "node_modules/capital-case": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/capital-case/-/capital-case-1.0.4.tgz", - "integrity": "sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==", + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "node_modules/extract-zip": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz", + "integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==", "dev": true, "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3", - "upper-case-first": "^2.0.2" + "concat-stream": "^1.6.2", + "debug": "^2.6.9", + "mkdirp": "^0.5.4", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" } }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true - }, - "node_modules/cbor-js": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/cbor-js/-/cbor-js-0.1.0.tgz", - "integrity": "sha1-yAzmEg84fo+qdDcN/aIdlluPx/k=" - }, - "node_modules/cbor-sync": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cbor-sync/-/cbor-sync-1.0.4.tgz", - "integrity": "sha512-GWlXN4wiz0vdWWXBU71Dvc1q3aBo0HytqwAZnXF1wOwjqNnDWA1vZ1gDMFLlqohak31VQzmhiYfiCX5QSSfagA==" - }, - "node_modules/chai": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.4.tgz", - "integrity": "sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA==", + "node_modules/extract-zip/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^3.0.1", - "get-func-name": "^2.0.0", - "pathval": "^1.1.1", - "type-detect": "^4.0.5" - }, - "engines": { - "node": ">=4" + "ms": "2.0.0" } }, - "node_modules/chai-as-promised": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz", - "integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==", + "node_modules/extract-zip/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "dependencies": { - "check-error": "^1.0.2" + "minimist": "^1.2.6" }, - "peerDependencies": { - "chai": ">= 2.1.2 < 5" + "bin": { + "mkdirp": "bin/cmd.js" } }, - "node_modules/chai-nock": { + "node_modules/extract-zip/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/extsprintf": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/chai-nock/-/chai-nock-1.3.0.tgz", - "integrity": "sha512-O3j1bW3ACoUu/sLGYSoX50c1p8dbTkCjw3/dereqzl9BL2XsQAUVC18sJpg3hVwpCk71rjWGumCmHy87t5W+Pg==", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", "dev": true, - "dependencies": { - "chai": "^4.2.0", - "deep-equal": "^1.0.1" - } + "engines": [ + "node >=0.6.0" + ] }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" }, "engines": { - "node": ">=4" + "node": ">=8.6.0" } }, - "node_modules/check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, "engines": { - "node": "*" + "node": ">= 6" } }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fast-xml-parser": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.3.6.tgz", + "integrity": "sha512-M2SovcRxD4+vC493Uc2GZVcZaj66CCJhWurC4viynVSTvrpErCShNcDz1lAho6n9REQKvL/ll4A4/fw6Y9z8nw==", "funding": [ { - "type": "individual", - "url": "https://paulmillr.com/funding/" + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + }, + { + "type": "paypal", + "url": "https://paypal.me/naturalintelligence" } ], + "peer": true, "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" + "strnum": "^1.0.5" }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "bin": { + "fxparser": "src/cli/cli.js" } }, - "node_modules/class-transformer": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", - "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==", - "dev": true, - "peer": true - }, - "node_modules/cli-table3": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", - "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, "dependencies": { - "string-width": "^4.2.0" - }, - "engines": { - "node": "10.* || >= 12.*" - }, - "optionalDependencies": { - "@colors/colors": "1.5.0" + "reusify": "^1.0.4" } }, - "node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "peer": true, "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" + "bser": "2.1.1" } }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", "dev": true, "dependencies": { - "color-name": "1.1.3" + "pend": "~1.2.0" } }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", "dev": true, - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dependencies": { - "delayed-stream": "~1.0.0" + "escape-string-regexp": "^1.0.5" }, "engines": { - "node": ">= 0.8" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, "engines": { - "node": ">= 10" + "node": ">=0.8.0" } }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "node_modules/component-bind": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", - "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=", - "dev": true - }, - "node_modules/component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" - }, - "node_modules/component-inherit": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", - "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "node_modules/concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, - "engines": [ - "node >= 0.8" - ], "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, - "node_modules/connect": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", - "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", - "dev": true, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", "dependencies": { "debug": "2.6.9", - "finalhandler": "1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", "parseurl": "~1.3.3", - "utils-merge": "1.0.1" + "statuses": "~1.5.0", + "unpipe": "~1.0.0" }, "engines": { - "node": ">= 0.10.0" + "node": ">= 0.8" } }, - "node_modules/connect/node_modules/debug": { + "node_modules/finalhandler/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "dependencies": { "ms": "2.0.0" } }, - "node_modules/connect/node_modules/ms": { + "node_modules/finalhandler/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "node_modules/content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", - "dev": true, + "node_modules/finalhandler/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dependencies": { + "ee-first": "1.1.1" + }, "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, - "node_modules/cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", - "dev": true, + "node_modules/find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "peer": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, "engines": { - "node": ">= 0.6" + "node": ">=6" } }, - "node_modules/cookiejar": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", - "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==" + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/core-js-pure": { - "version": "3.26.0", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.26.0.tgz", - "integrity": "sha512-LiN6fylpVBVwT8twhhluD9TzXmZQQsr2I2eIKtWNbZI1XMfBT7CV18itaN6RA7EtQd/SDdRx/wzvAShX2HvhQA==", + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", "dev": true, - "hasInstallScript": true, - "peer": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" + "bin": { + "flat": "cli.js" } }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "node_modules/flow-enums-runtime": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/flow-enums-runtime/-/flow-enums-runtime-0.0.6.tgz", + "integrity": "sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==", + "peer": true + }, + "node_modules/flow-parser": { + "version": "0.206.0", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.206.0.tgz", + "integrity": "sha512-HVzoK3r6Vsg+lKvlIZzaWNBVai+FXTX1wdYhz/wVlH13tb/gOdLXmlTqy6odmTBhT5UoWUbq0k8263Qhr9d88w==", + "peer": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], "engines": { - "node": ">= 8" + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } } }, - "node_modules/cross-spawn/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", "dev": true, "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" }, "engines": { - "node": ">= 8" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/cucumber": { - "version": "6.0.7", - "resolved": "https://registry.npmjs.org/cucumber/-/cucumber-6.0.7.tgz", - "integrity": "sha512-pN3AgWxHx8rOi+wOlqjASNETOjf3TgeyqhMNLQam7nSTXgQzju1oAmXkleRQRcXvpVvejcDHiZBLFSfBkqbYpA==", - "deprecated": "Cucumber is publishing new releases under @cucumber/cucumber", + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", "dev": true, - "peer": true, + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", "dependencies": { - "assertion-error-formatter": "^3.0.0", - "bluebird": "^3.4.1", - "cli-table3": "^0.5.1", - "colors": "^1.1.2", - "commander": "^3.0.1", - "cucumber-expressions": "^8.1.0", - "cucumber-tag-expressions": "^2.0.2", - "duration": "^0.2.1", - "escape-string-regexp": "^2.0.0", - "figures": "^3.0.0", - "gherkin": "5.0.0", - "glob": "^7.1.3", - "indent-string": "^4.0.0", - "is-generator": "^1.0.2", - "is-stream": "^2.0.0", - "knuth-shuffle-seeded": "^1.0.6", - "lodash": "^4.17.14", - "mz": "^2.4.0", - "progress": "^2.0.0", - "resolve": "^1.3.3", - "serialize-error": "^4.1.0", - "stack-chain": "^2.0.0", - "stacktrace-js": "^2.0.0", - "string-argv": "^0.3.0", - "title-case": "^2.1.1", - "util-arity": "^1.0.2", - "verror": "^1.9.0" - }, - "bin": { - "cucumber-js": "bin/cucumber-js" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" }, "engines": { - "node": ">=8" + "node": ">= 6" } }, - "node_modules/cucumber-expressions": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/cucumber-expressions/-/cucumber-expressions-8.3.0.tgz", - "integrity": "sha512-cP2ya0EiorwXBC7Ll7Cj7NELYbasNv9Ty42L4u7sso9KruWemWG1ZiTq4PMqir3SNDSrbykoqI5wZgMbLEDjLQ==", - "deprecated": "This package is now published under @cucumber/cucumber-expressions", - "dev": true, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "peer": true, - "dependencies": { - "becke-ch--regex--s0-0-v1--base--pl--lib": "^1.4.0", - "xregexp": "^4.2.4" + "engines": { + "node": ">= 0.6" } }, - "node_modules/cucumber-expressions/node_modules/xregexp": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.4.1.tgz", - "integrity": "sha512-2u9HwfadaJaY9zHtRRnH6BY6CQVNQKkYm3oLtC9gJXXzfsbACg5X5e4EZZGVAH+YIfa+QA9lsFQTTe3HURF3ag==", + "node_modules/fs-extra": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", + "integrity": "sha512-VerQV6vEKuhDWD2HGOybV6v5I73syoc/cXAbKlgTC7M/oFVEtklWlp9QH2Ijw3IaWDOQcMkldSPa7zXy79Z/UQ==", "dev": true, - "peer": true, "dependencies": { - "@babel/runtime-corejs3": "^7.12.1" + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0" } }, - "node_modules/cucumber-pretty": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/cucumber-pretty/-/cucumber-pretty-6.0.1.tgz", - "integrity": "sha512-9uOIZ8x3lgCPROqYc7kqe2e7UrH5TZPZCdj5fVPze1XViG9yv8/8MnFsAnVINDYWVhiql8DJHb3UrZfIPHYH/A==", - "dev": true, - "dependencies": { - "cli-table3": "^0.6.0", - "colors": "^1.4.0", - "figures": "^3.2.0" - }, - "peerDependencies": { - "cucumber": ">=6.0.0 <7.0.0" + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/cucumber-tag-expressions": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/cucumber-tag-expressions/-/cucumber-tag-expressions-2.0.3.tgz", - "integrity": "sha512-+x5j1IfZrBtbvYHuoUX0rl4nUGxaey6Do9sM0CABmZfDCcWXuuRm1fQeCaklIYQgOFHQ6xOHvDSdkMHHpni6tQ==", + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true, - "peer": true + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "peer": true, + "engines": { + "node": ">=6.9.0" + } }, - "node_modules/cucumber-tsflow": { - "version": "4.0.0-rc.11", - "resolved": "https://registry.npmjs.org/cucumber-tsflow/-/cucumber-tsflow-4.0.0-rc.11.tgz", - "integrity": "sha512-VK/RhJOOxS4KAH6UIkfLsDE2+H7OtP/+cwzx139gldqHP08hoYk/fMwOoXlGWXOOX2O3amJ6RTS0YMF2xCA8Bw==", - "dev": true, - "dependencies": { - "callsites": "^3.1.0", - "log4js": "^6.3.0", - "source-map-support": "^0.5.19", - "underscore": "^1.8.3" - }, - "peerDependencies": { - "@cucumber/cucumber": ">7.0.0-rc || >7.0.0" + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/cucumber/node_modules/ansi-regex": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", - "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", "dev": true, - "peer": true, "engines": { - "node": ">=4" + "node": "*" } }, - "node_modules/cucumber/node_modules/cli-table3": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz", - "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dev": true, - "peer": true, "dependencies": { - "object-assign": "^4.1.0", - "string-width": "^2.1.1" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" }, "engines": { - "node": ">=6" + "node": ">= 0.4" }, - "optionalDependencies": { - "colors": "^1.1.2" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/cucumber/node_modules/commander": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", - "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==", - "dev": true, - "peer": true - }, - "node_modules/cucumber/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "peer": true, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cucumber/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "node_modules/get-tsconfig": { + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.3.tgz", + "integrity": "sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg==", "dev": true, - "peer": true, - "engines": { - "node": ">=4" + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, - "node_modules/cucumber/node_modules/string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "peer": true, + "node_modules/get-uri": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.3.tgz", + "integrity": "sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==", "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.2", + "debug": "^4.3.4", + "fs-extra": "^11.2.0" }, "engines": { - "node": ">=4" + "node": ">= 14" } }, - "node_modules/cucumber/node_modules/strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", - "dev": true, - "peer": true, + "node_modules/get-uri/node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", "dependencies": { - "ansi-regex": "^3.0.0" + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": ">=4" + "node": ">=14.14" } }, - "node_modules/custom-event": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", - "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", - "dev": true - }, - "node_modules/d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "dev": true, + "node_modules/get-uri/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dependencies": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" } }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", "dev": true, "dependencies": { "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/data-uri-to-buffer": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.1.tgz", - "integrity": "sha512-MZd3VlchQkp8rdend6vrx7MmVDJzSNTBvghvKjirLkD+WTChA3KUf0jkE68Q4UyctNqI11zZO9/x2Yx+ub5Cvg==", - "engines": { - "node": ">= 14" } }, - "node_modules/date-format": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.3.tgz", - "integrity": "sha512-7P3FyqDcfeznLZp2b+OMitV9Sz2lUnsT87WaTat9nVwqsBkTzPG3lPLNwW3en6F4pHUiWzr6vb8CLhjdK9bcxQ==", + "node_modules/gherkin": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/gherkin/-/gherkin-5.0.0.tgz", + "integrity": "sha512-Y+93z2Nh+TNIKuKEf+6M0FQrX/z0Yv9C2LFfc5NlcGJWRrrTeI/jOg2374y1FOw6ZYQ3RgJBezRkli7CLDubDA==", + "deprecated": "This package is now published under @cucumber/gherkin", "dev": true, - "engines": { - "node": ">=4.0" + "peer": true, + "bin": { + "gherkin-javascript": "bin/gherkin" } }, - "node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "node_modules/glob": { + "version": "10.3.12", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", + "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", + "dev": true, "dependencies": { - "ms": "2.1.2" + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.6", + "minimatch": "^9.0.1", + "minipass": "^7.0.4", + "path-scurry": "^1.10.2" + }, + "bin": { + "glob": "dist/esm/bin.mjs" }, "engines": { - "node": ">=6.0" + "node": ">=16 || 14 >=14.17" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, "engines": { - "node": ">=0.10.0" + "node": ">=10.13.0" } }, - "node_modules/deep-eql": { + "node_modules/global-dirs": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", + "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", "dev": true, "dependencies": { - "type-detect": "^4.0.0" + "ini": "2.0.0" }, "engines": { - "node": ">=0.12" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/deep-equal": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", - "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "dependencies": { - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.1", - "is-regex": "^1.0.4", - "object-is": "^1.0.1", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.2.0" + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "node_modules/globals/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, "dependencies": { - "object-keys": "^1.0.12" + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" }, "engines": { - "node": ">= 0.4" - } - }, - "node_modules/degenerator": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", - "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", - "dependencies": { - "ast-types": "^0.13.4", - "escodegen": "^2.1.0", - "esprima": "^4.0.1" + "node": ">=10" }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "engines": { - "node": ">=0.4.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/dezalgo": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", - "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", "dependencies": { - "asap": "^2.0.0", - "wrappy": "1" + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/di": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", - "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", - "dev": true + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true }, - "node_modules/diff-sequences": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", - "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", "dev": true, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=4" } }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", "dev": true, "dependencies": { - "path-type": "^4.0.0" + "ajv": "^6.12.3", + "har-schema": "^2.0.0" }, "engines": { - "node": ">=8" + "node": ">=6" } }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "node_modules/has-ansi": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-4.0.1.tgz", + "integrity": "sha512-Qr4RtTm30xvEdqUXbSBVWDu+PrTokJOwe/FU+VdfJPk+MXAPoeOzKpRyrDTnZIJwAkQ4oBLTU53nu0HrkF/Z2A==", "dev": true, "dependencies": { - "esutils": "^2.0.2" + "ansi-regex": "^4.1.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=8" } }, - "node_modules/dom-serialize": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", - "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", - "dev": true, - "dependencies": { - "custom-event": "~1.0.0", - "ent": "~2.2.0", - "extend": "^3.0.0", - "void-elements": "^2.0.0" + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" } }, - "node_modules/duration": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/duration/-/duration-0.2.2.tgz", - "integrity": "sha512-06kgtea+bGreF5eKYgI/36A6pLXggY7oR4p1pq4SmdFBn1ReOL5D8RhG64VrqfTTKNucqqtBAwEj8aB88mcqrg==", + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, "dependencies": { - "d": "1", - "es5-ext": "~0.10.46" + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/durations": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/durations/-/durations-3.4.2.tgz", - "integrity": "sha512-V/lf7y33dGaypZZetVI1eu7BmvkbC4dItq12OElLRpKuaU5JxQstV2zHwLv8P7cNbQ+KL1WD80zMCTx5dNC4dg==", + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true, - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", - "dev": true - }, - "node_modules/encodeurl": { + "node_modules/has-tostringtag": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, "engines": { - "node": ">= 0.8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/engine.io": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.5.0.tgz", - "integrity": "sha512-21HlvPUKaitDGE4GXNtQ7PLP0Sz4aWLddMPw2VTyFz1FVZqu/kZsJUO8WNpKuE/OCL7nkfRaOui2ZCJloGznGA==", + "node_modules/hasha": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-2.2.0.tgz", + "integrity": "sha512-jZ38TU/EBiGKrmyTNNZgnvCZHNowiRI4+w/I9noMlekHTZH3KyGgvJLmhSgykeAQ9j2SYPDosM0Bg3wHfzibAQ==", "dev": true, "dependencies": { - "accepts": "~1.3.4", - "base64id": "2.0.0", - "cookie": "~0.4.1", - "debug": "~4.1.0", - "engine.io-parser": "~2.2.0", - "ws": "~7.4.2" + "is-stream": "^1.0.1", + "pinkie-promise": "^2.0.0" }, "engines": { - "node": ">=8.0.0" + "node": ">=0.10.0" } }, - "node_modules/engine.io-client": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.5.2.tgz", - "integrity": "sha512-QEqIp+gJ/kMHeUun7f5Vv3bteRHppHH/FMBQX/esFj/fuYfjyUKWGMo3VCvIP/V8bE9KcjHmRZrhIz2Z9oNsDA==", + "node_modules/hasha/node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dependencies": { - "component-emitter": "~1.3.0", - "component-inherit": "0.0.3", - "debug": "~3.1.0", - "engine.io-parser": "~2.2.0", - "has-cors": "1.1.0", - "indexof": "0.0.1", - "parseqs": "0.0.6", - "parseuri": "0.0.6", - "ws": "~7.4.2", - "xmlhttprequest-ssl": "~1.6.2", - "yeast": "0.1.2" + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" } }, - "node_modules/engine.io-client/node_modules/debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true, - "dependencies": { - "ms": "2.0.0" + "bin": { + "he": "bin/he" } }, - "node_modules/engine.io-client/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "node_modules/hermes-estree": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.15.0.tgz", + "integrity": "sha512-lLYvAd+6BnOqWdnNbP/Q8xfl8LOGw4wVjfrNd9Gt8eoFzhNBRVD95n4l2ksfMVOoxuVyegs85g83KS9QOsxbVQ==", + "peer": true }, - "node_modules/engine.io-parser": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.1.tgz", - "integrity": "sha512-x+dN/fBH8Ro8TFwJ+rkB2AmuVw9Yu2mockR/p3W8f8YtExwFgDvBDi0GWyb4ZLkpahtDGZgtr3zLovanJghPqg==", - "dev": true, + "node_modules/hermes-parser": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.15.0.tgz", + "integrity": "sha512-Q1uks5rjZlE9RjMMjSUCkGrEIPI5pKJILeCtK1VmTj7U4pf3wVPoo+cxfu+s4cBAPy2JzikIIdCZgBoR6x7U1Q==", + "peer": true, "dependencies": { - "after": "0.8.2", - "arraybuffer.slice": "~0.0.7", - "base64-arraybuffer": "0.1.4", - "blob": "0.0.5", - "has-binary2": "~1.0.2" + "hermes-estree": "0.15.0" } }, - "node_modules/engine.io/node_modules/debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", - "dev": true, + "node_modules/hermes-profile-transformer": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/hermes-profile-transformer/-/hermes-profile-transformer-0.0.6.tgz", + "integrity": "sha512-cnN7bQUm65UWOy6cbGcCcZ3rpwW8Q/j4OP5aWRhEry4Z2t2aR1cjrbp0BS+KiBN0smvP1caBgAuxutvyvJILzQ==", + "peer": true, "dependencies": { - "ms": "^2.1.1" + "source-map": "^0.7.3" + }, + "engines": { + "node": ">=8" } }, - "node_modules/ent": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", + "node_modules/hermes-profile-transformer/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "peer": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, - "node_modules/error-stack-parser": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", - "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", - "dev": true, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "dependencies": { - "stackframe": "^1.3.4" + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" } }, - "node_modules/es5-ext": { - "version": "0.10.53", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", - "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", "dev": true, "dependencies": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.3", - "next-tick": "~1.0.0" + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" } }, - "node_modules/es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", "dev": true, "dependencies": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" } }, - "node_modules/es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", - "dev": true + "node_modules/https-proxy-agent": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } }, - "node_modules/es6-shim": { - "version": "0.35.6", - "resolved": "https://registry.npmjs.org/es6-shim/-/es6-shim-0.35.6.tgz", - "integrity": "sha512-EmTr31wppcaIAgblChZiuN/l9Y7DPyw8Xtbg7fIVngn6zMW+IEBJDJngeKC3x6wr0V/vcA2wqeFnaw1bFJbDdA==", - "dev": true + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "peer": true, + "engines": { + "node": ">=10.17.0" + } }, - "node_modules/es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", - "dev": true, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", "dependencies": { - "d": "^1.0.1", - "ext": "^1.1.2" + "ms": "^2.0.0" } }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, "engines": { - "node": ">=6" + "node": ">=0.10.0" } }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", - "dev": true + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", "dev": true, "engines": { - "node": ">=0.8.0" + "node": ">= 4" } }, - "node_modules/escodegen": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", - "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "node_modules/image-size": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.1.1.tgz", + "integrity": "sha512-541xKlUw6jr/6gGuk92F+mYM5zaFAc5ahphvkqvNe2bQ6gVBkd6bfrmVJ2t4KDAfikAYZyIqTnktX3i6/aQDrQ==", + "peer": true, "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2" + "queue": "6.0.2" }, "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" + "image-size": "bin/image-size.js" }, "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" + "node": ">=16.x" } }, - "node_modules/eslint": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.37.0.tgz", - "integrity": "sha512-NU3Ps9nI05GUoVMxcZx1J8CNR6xOvUT4jAUMH5+z8lpp3aEdPVCImKw6PWG4PY+Vfkpr+jvMpxs/qoE7wq0sPw==", + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.2", - "@eslint/js": "8.37.0", - "@humanwhocodes/config-array": "^0.11.8", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-visitor-keys": "^3.4.0", - "espree": "^9.5.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=6" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint-plugin-mocha": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-10.0.3.tgz", - "integrity": "sha512-9mM7PZGxfejpjey+MrG0Cu3Lc8MyA5E2s7eUCdHXgS4SY/H9zLuwa7wVAjnEaoDjbBilA+0bPEB+iMO7lBUPcg==", - "dev": true, - "dependencies": { - "eslint-utils": "^3.0.0", - "ramda": "^0.27.1" - }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "eslint": ">=7.0.0" + "node": ">=0.8.19" } }, - "node_modules/eslint-plugin-prettier": { + "node_modules/indent-string": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz", - "integrity": "sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ==", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true, - "dependencies": { - "prettier-linter-helpers": "^1.0.0" - }, "engines": { - "node": ">=6.0.0" - }, - "peerDependencies": { - "eslint": ">=7.28.0", - "prettier": ">=2.0.0" - }, - "peerDependenciesMeta": { - "eslint-config-prettier": { - "optional": true - } + "node": ">=8" } }, - "node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "peer": true, "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "loose-envify": "^1.0.0" + } + }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">= 12" } }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "node_modules/ip-address/node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==" + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", "dev": true, "dependencies": { - "eslint-visitor-keys": "^2.0.0" + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" }, "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "node_modules/is-binary-path": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, "engines": { - "node": ">=10" + "node": ">=8" } }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", - "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", + "node_modules/is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", "dev": true, + "dependencies": { + "builtin-modules": "^3.3.0" + }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=6" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" + "hasown": "^2.0.0" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/eslint/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "has-tostringtag": "^1.0.0" }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/eslint/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, + "node_modules/is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw==", + "peer": true, "engines": { - "node": ">=7.0.0" + "node": ">=0.10.0" } }, - "node_modules/eslint/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "peer": true, + "bin": { + "is-docker": "cli.js" + }, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, "engines": { - "node": ">=10.13.0" + "node": ">=0.10.0" } }, - "node_modules/eslint/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "engines": { "node": ">=8" } }, - "node_modules/eslint/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "node_modules/is-generator": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-generator/-/is-generator-1.0.3.tgz", + "integrity": "sha512-G56jBpbJeg7ds83HW1LuShNs8J73Fv3CPz/bmROHOHlnKkN8sWb9ujiagjmxxMUywftgq48HlBZELKKqFLk0oA==", "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } + "peer": true }, - "node_modules/eslint/node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" + "is-extglob": "^2.1.1" }, "engines": { - "node": ">= 0.8.0" + "node": ">=0.10.0" } }, - "node_modules/eslint/node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "node_modules/is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", "dev": true, "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" }, "engines": { - "node": ">= 0.8.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "peer": true, "engines": { - "node": ">= 0.8.0" + "node": ">=8" } }, - "node_modules/eslint/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "engines": { - "node": ">=8" + "node": ">=0.12.0" } }, - "node_modules/eslint/node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, "engines": { - "node": ">= 0.8.0" + "node": ">=8" } }, - "node_modules/espree": { - "version": "9.5.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", - "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", "dev": true, - "dependencies": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.0" - }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=8" } }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "peer": true, + "dependencies": { + "isobject": "^3.0.1" }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "node_modules/is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", "dev": true, "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" + "@types/estree": "*" } }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "dev": true, "dependencies": { - "estraverse": "^5.2.0" + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" }, "engines": { - "node": ">=4.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "engines": { - "node": ">=4.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", "dev": true }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true - }, - "node_modules/expect": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", - "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", - "dev": true, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "peer": true, "dependencies": { - "@jest/types": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1" + "is-docker": "^2.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=8" } }, - "node_modules/ext": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.6.0.tgz", - "integrity": "sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg==", + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/isbinaryfile": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", "dev": true, - "dependencies": { - "type": "^2.5.0" + "engines": { + "node": ">= 8.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" } }, - "node_modules/ext/node_modules/type": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.6.0.tgz", - "integrity": "sha512-eiDBDOmkih5pMbo9OqsqPRGMljLodLcwd5XD5JbtNB0o89xZAwynY9EdCDsJU7LtcVCClu9DvM7/0Ep1hYX3EQ==", - "dev": true + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", "dev": true }, - "node_modules/extract-zip": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz", - "integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==", + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", "dev": true, "dependencies": { - "concat-stream": "^1.6.2", - "debug": "^2.6.9", - "mkdirp": "^0.5.4", - "yauzl": "^2.10.0" + "@isaacs/cliui": "^8.0.2" }, - "bin": { - "extract-zip": "cli.js" + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" } }, - "node_modules/extract-zip/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", "dev": true, "dependencies": { - "ms": "2.0.0" + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/extract-zip/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true, - "engines": [ - "node >=0.6.0" - ] - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-diff": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", - "dev": true, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "peer": true, "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" }, "engines": { - "node": ">=8.6.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "node_modules/fast-safe-stringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } }, - "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", "dev": true, "dependencies": { - "reusify": "^1.0.4" + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", - "dev": true, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", "dependencies": { - "pend": "~1.2.0" + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "peer": true, "dependencies": { - "escape-string-regexp": "^1.0.5" + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", "dependencies": { - "flat-cache": "^3.0.4" + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "peer": true, "dependencies": { - "to-regex-range": "^5.0.1" + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "dev": true, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "peer": true, "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" }, "engines": { - "node": ">= 0.8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, + "node_modules/joi": { + "version": "17.12.3", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.12.3.tgz", + "integrity": "sha512-2RRziagf555owrm9IRVtdKynOBeITiDpuZqIpgwqXShPncPKNiRQoiGsl/T8SQdq+8ugRzH2LqY67irr2y/d+g==", + "peer": true, "dependencies": { - "ms": "2.0.0" + "@hapi/hoek": "^9.3.0", + "@hapi/topo": "^5.1.0", + "@sideway/address": "^4.1.5", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" } }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "argparse": "^1.0.7", + "esprima": "^4.0.0" }, - "engines": { - "node": ">=10" + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" + }, + "node_modules/jsc-android": { + "version": "250231.0.0", + "resolved": "https://registry.npmjs.org/jsc-android/-/jsc-android-250231.0.0.tgz", + "integrity": "sha512-rS46PvsjYmdmuz1OAWXY/1kCYG7pnf1TBqeTiOJr1iDz7s5DLxxC9n/ZMknLDxzYzNVfI7R95MH10emSSG1Wuw==", + "peer": true + }, + "node_modules/jsc-safe-url": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/jsc-safe-url/-/jsc-safe-url-0.2.4.tgz", + "integrity": "sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q==", + "peer": true + }, + "node_modules/jscodeshift": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.14.0.tgz", + "integrity": "sha512-7eCC1knD7bLUPuSCwXsMZUH51O8jIcoVyKtI6P0XM0IVzlGjckPy3FIwQlorzbN0Sg79oK+RlohN32Mqf/lrYA==", + "peer": true, + "dependencies": { + "@babel/core": "^7.13.16", + "@babel/parser": "^7.13.16", + "@babel/plugin-proposal-class-properties": "^7.13.0", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.13.8", + "@babel/plugin-proposal-optional-chaining": "^7.13.12", + "@babel/plugin-transform-modules-commonjs": "^7.13.8", + "@babel/preset-flow": "^7.13.13", + "@babel/preset-typescript": "^7.13.0", + "@babel/register": "^7.13.16", + "babel-core": "^7.0.0-bridge.0", + "chalk": "^4.1.2", + "flow-parser": "0.*", + "graceful-fs": "^4.2.4", + "micromatch": "^4.0.4", + "neo-async": "^2.5.0", + "node-dir": "^0.1.17", + "recast": "^0.21.0", + "temp": "^0.8.4", + "write-file-atomic": "^2.3.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "bin": { + "jscodeshift": "bin/jscodeshift.js" + }, + "peerDependencies": { + "@babel/preset-env": "^7.1.6" } }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "peer": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "peer": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true + }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, + "optional": true, + "dependencies": { + "minimist": "^1.2.0" + }, "bin": { - "flat": "cli.js" + "json5": "lib/cli.js" } }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "node_modules/jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", "dev": true, "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=0.6.0" } }, - "node_modules/flatted": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", - "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "node_modules/jsprim/node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", "dev": true }, - "node_modules/follow-redirects": { - "version": "1.15.4", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", - "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==", + "node_modules/jsprim/node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } + "engines": [ + "node >=0.6.0" ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" } }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "node_modules/just-extend": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", + "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", + "dev": true + }, + "node_modules/karma": { + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.3.tgz", + "integrity": "sha512-LuucC/RE92tJ8mlCwqEoRWXP38UMAqpnq98vktmS9SznSoUPPUJQbc91dHcxcunROvfQjdORVA/YFviH+Xci9Q==", "dev": true, + "dependencies": { + "@colors/colors": "1.5.0", + "body-parser": "^1.19.0", + "braces": "^3.0.2", + "chokidar": "^3.5.1", + "connect": "^3.7.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.1", + "glob": "^7.1.7", + "graceful-fs": "^4.2.6", + "http-proxy": "^1.18.1", + "isbinaryfile": "^4.0.8", + "lodash": "^4.17.21", + "log4js": "^6.4.1", + "mime": "^2.5.2", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.5", + "qjobs": "^1.2.0", + "range-parser": "^1.2.1", + "rimraf": "^3.0.2", + "socket.io": "^4.7.2", + "source-map": "^0.6.1", + "tmp": "^0.2.1", + "ua-parser-js": "^0.7.30", + "yargs": "^16.1.1" + }, + "bin": { + "karma": "bin/karma" + }, "engines": { - "node": "*" + "node": ">= 10" + } + }, + "node_modules/karma-chai": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/karma-chai/-/karma-chai-0.1.0.tgz", + "integrity": "sha512-mqKCkHwzPMhgTYca10S90aCEX9+HjVjjrBFAsw36Zj7BlQNbokXXCAe6Ji04VUMsxcY5RLP7YphpfO06XOubdg==", + "dev": true, + "peerDependencies": { + "chai": "*", + "karma": ">=0.10.9" } }, - "node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "node_modules/karma-chrome-launcher": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.2.0.tgz", + "integrity": "sha512-rE9RkUPI7I9mAxByQWkGJFXfFD6lE4gC5nPuZdobf/QdTEJI6EU4yIay/cfU/xV4ZxlM5JiTv7zWYgA64NpS5Q==", "dev": true, "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" + "which": "^1.2.1" } }, - "node_modules/formidable": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz", - "integrity": "sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==", + "node_modules/karma-chrome-launcher/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, "dependencies": { - "dezalgo": "^1.0.4", - "hexoid": "^1.0.0", - "once": "^1.4.0", - "qs": "^6.11.0" + "isexe": "^2.0.0" }, - "funding": { - "url": "https://ko-fi.com/tunnckoCore/commissions" + "bin": { + "which": "bin/which" } }, - "node_modules/formidable/node_modules/qs": { - "version": "6.11.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", - "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", + "node_modules/karma-mocha": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/karma-mocha/-/karma-mocha-2.0.1.tgz", + "integrity": "sha512-Tzd5HBjm8his2OA4bouAsATYEpZrp9vC7z5E5j4C5Of5Rrs1jY67RAwXNcVmd/Bnk1wgvQRou0zGVLey44G4tQ==", + "dev": true, "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "minimist": "^1.2.3" } }, - "node_modules/fs-extra": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", - "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", + "node_modules/karma-phantomjs-launcher": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/karma-phantomjs-launcher/-/karma-phantomjs-launcher-1.0.4.tgz", + "integrity": "sha512-tf4P3plsE7wb5Pqh8GJ6RnElxfI/UM4MtVnjbSIZFpdFJlKnjRzfIx8MLCcSYJBwZ1+qSKFz4uBe3XNoq2t3KA==", + "deprecated": "PhantomJS development have stopped, use puppeteer or similar", "dev": true, "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "klaw": "^1.0.0" + "lodash": "^4.0.1", + "phantomjs-prebuilt": "^2.1.7" + }, + "peerDependencies": { + "karma": ">=0.9" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "node_modules/karma-sinon-chai": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/karma-sinon-chai/-/karma-sinon-chai-2.0.2.tgz", + "integrity": "sha512-SDgh6V0CUd+7ruL1d3yG6lFzmJNGRNQuEuCYXLaorruNP9nwQfA7hpsp4clx4CbOo5Gsajh3qUOT7CrVStUKMw==", "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "peerDependencies": { + "chai": ">=3.5.0", + "sinon": ">=2.1.0", + "sinon-chai": ">=2.9.0" } }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true + "node_modules/karma-sourcemap-loader": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/karma-sourcemap-loader/-/karma-sourcemap-loader-0.3.8.tgz", + "integrity": "sha512-zorxyAakYZuBcHRJE+vbrK2o2JXLFWK8VVjiT/6P+ltLBUGUvqTEkUiQ119MGdOrK7mrmxXHZF1/pfT6GgIZ6g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2" + } }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "node_modules/karma-spec-reporter": { + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/karma-spec-reporter/-/karma-spec-reporter-0.0.32.tgz", + "integrity": "sha512-ZXsYERZJMTNRR2F3QN11OWF5kgnT/K2dzhM+oY3CDyMrDI3TjIWqYGG7c15rR9wjmy9lvdC+CCshqn3YZqnNrA==", "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" + "dependencies": { + "colors": "^1.1.2" + }, + "peerDependencies": { + "karma": ">=0.9" } }, - "node_modules/get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "node_modules/karma/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "engines": { - "node": "*" + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "node_modules/karma/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/get-uri": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.2.tgz", - "integrity": "sha512-5KLucCJobh8vBY1K07EFV4+cPZH3mrV9YeAruUseCQKHB58SGjjT2l9/eA9LD082IiuMjSlFJEcdJ27TXvbZNw==", + "node_modules/karma/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, "dependencies": { - "basic-ftp": "^5.0.2", - "data-uri-to-buffer": "^6.0.0", - "debug": "^4.3.4", - "fs-extra": "^8.1.0" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">= 14" + "node": "*" } }, - "node_modules/get-uri/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/karma/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, "dependencies": { - "ms": "2.1.2" + "minimist": "^1.2.6" }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "bin": { + "mkdirp": "bin/cmd.js" } }, - "node_modules/get-uri/node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "node_modules/kew": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz", + "integrity": "sha512-IG6nm0+QtAMdXt9KvbgbGdvY50RSrw+U4sGZg+KlrSKPJEwVE5JVoI3d7RWfSMdBQneRheeAOj3lIjX5VL/9RQ==", + "dev": true + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "peer": true, "engines": { - "node": ">=6 <7 || >=8" + "node": ">=0.10.0" } }, - "node_modules/get-uri/node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "node_modules/klaw": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", + "integrity": "sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==", + "dev": true, "optionalDependencies": { - "graceful-fs": "^4.1.6" + "graceful-fs": "^4.1.9" } }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/knuth-shuffle-seeded": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/knuth-shuffle-seeded/-/knuth-shuffle-seeded-1.0.6.tgz", + "integrity": "sha512-9pFH0SplrfyKyojCLxZfMcvkhf5hH0d+UwR9nTVJ/DDQJGuzcXjTwB7TP7sDfehSudlGGaOLblmEWqv04ERVWg==", "dev": true, "dependencies": { - "assert-plus": "^1.0.0" + "seed-random": "~2.2.0" } }, - "node_modules/gherkin": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/gherkin/-/gherkin-5.0.0.tgz", - "integrity": "sha512-Y+93z2Nh+TNIKuKEf+6M0FQrX/z0Yv9C2LFfc5NlcGJWRrrTeI/jOg2374y1FOw6ZYQ3RgJBezRkli7CLDubDA==", - "deprecated": "This package is now published under @cucumber/gherkin", - "dev": true, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", "peer": true, - "bin": { - "gherkin-javascript": "bin/gherkin" + "engines": { + "node": ">=6" } }, - "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" }, "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">= 0.8.0" } }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, + "node_modules/lighthouse-logger": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.4.2.tgz", + "integrity": "sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==", + "peer": true, "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" + "debug": "^2.6.9", + "marky": "^1.2.2" } }, - "node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", - "dev": true, + "node_modules/lighthouse-logger/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "peer": true, "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "ms": "2.0.0" } }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, + "node_modules/lighthouse-logger/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "peer": true + }, + "node_modules/lil-uuid": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/lil-uuid/-/lil-uuid-0.1.1.tgz", + "integrity": "sha512-GhWI8f61tBlMeqULZ1QWhFiiyFIFdPlg//S8Udq1wjq1FJhpFKTfnbduSxAQjueofeUtpr7UvQ/lIK/sKUF8dg==" + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" + "p-locate": "^5.0.0" }, "engines": { "node": ">=10" @@ -3730,578 +9809,698 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "peer": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "node_modules/growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true, - "engines": { - "node": ">=4.x" - } + "node_modules/lodash.mergewith": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", + "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", + "dev": true }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true, - "engines": { - "node": ">=4" - } + "node_modules/lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==", + "peer": true }, - "node_modules/har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "deprecated": "this library is no longer supported", - "dev": true, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "dependencies": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" }, "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "node_modules/log4js": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.9.1.tgz", + "integrity": "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==", + "dev": true, "dependencies": { - "function-bind": "^1.1.1" + "date-format": "^4.0.14", + "debug": "^4.3.4", + "flatted": "^3.2.7", + "rfdc": "^1.3.0", + "streamroller": "^3.1.5" }, "engines": { - "node": ">= 0.4.0" + "node": ">=8.0" } }, - "node_modules/has-binary2": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", - "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", - "dev": true, + "node_modules/logkitty": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/logkitty/-/logkitty-0.7.1.tgz", + "integrity": "sha512-/3ER20CTTbahrCrpYfPn7Xavv9diBROZpoXGVZDWMw4b/X4uuUwAC0ki85tgsdMRONURyIJbcOvS94QsUBYPbQ==", + "peer": true, "dependencies": { - "isarray": "2.0.1" + "ansi-fragments": "^0.2.1", + "dayjs": "^1.8.15", + "yargs": "^15.1.0" + }, + "bin": { + "logkitty": "bin/logkitty.js" } }, - "node_modules/has-binary2/node_modules/isarray": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", - "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", - "dev": true - }, - "node_modules/has-cors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", - "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=", - "dev": true - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, + "node_modules/logkitty/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "node_modules/logkitty/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "peer": true, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=6" } }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, + "node_modules/logkitty/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "peer": true, "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" } }, - "node_modules/hasha": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/hasha/-/hasha-2.2.0.tgz", - "integrity": "sha1-eNfL/B5tZjA/55g3NlmEUXsvbuE=", - "dev": true, + "node_modules/logkitty/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "peer": true, "dependencies": { - "is-stream": "^1.0.1", - "pinkie-promise": "^2.0.0" + "color-name": "~1.1.4" }, "engines": { - "node": ">=0.10.0" + "node": ">=7.0.0" } }, - "node_modules/hasha/node_modules/is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } + "node_modules/logkitty/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "peer": true }, - "node_modules/he": { + "node_modules/logkitty/node_modules/decamelize": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "bin": { - "he": "bin/he" + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "peer": true, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/hexoid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", - "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==", + "node_modules/logkitty/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "peer": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, "engines": { "node": ">=8" } }, - "node_modules/http-errors": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", - "dev": true, + "node_modules/logkitty/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "peer": true, "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.1" + "p-locate": "^4.1.0" }, "engines": { - "node": ">= 0.6" + "node": ">=8" } }, - "node_modules/http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "dev": true, + "node_modules/logkitty/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "peer": true, "dependencies": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" + "p-try": "^2.0.0" }, "engines": { - "node": ">=8.0.0" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/http-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", - "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", + "node_modules/logkitty/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "peer": true, "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" + "p-limit": "^2.2.0" }, "engines": { - "node": ">= 14" + "node": ">=8" } }, - "node_modules/http-proxy-agent/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/logkitty/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "peer": true, "dependencies": { - "ms": "2.1.2" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">=8" } }, - "node_modules/http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, + "node_modules/logkitty/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "peer": true + }, + "node_modules/logkitty/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "peer": true, "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" }, "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" + "node": ">=8" } }, - "node_modules/https-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", - "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", + "node_modules/logkitty/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "peer": true, "dependencies": { - "agent-base": "^7.0.2", - "debug": "4" + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" }, "engines": { - "node": ">= 14" + "node": ">=6" } }, - "node_modules/humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", + "node_modules/lolex": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-4.2.0.tgz", + "integrity": "sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg==", + "dev": true + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "peer": true, "dependencies": { - "ms": "^2.0.0" + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" } }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", "dev": true, "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" + "get-func-name": "^2.0.1" } }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", "dev": true, - "engines": { - "node": ">= 4" + "dependencies": { + "tslib": "^2.0.3" } }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "14 || >=16.14" } }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "node_modules/luxon": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.2.1.tgz", + "integrity": "sha512-QrwPArQCNLAKGO/C+ZIilgIuDnEnKx5QYODdDtbFaxzsbZcc/a7WFq7MhsVYgRlwawLtvOUESTlfJ+hc/USqPg==", "dev": true, "engines": { - "node": ">=0.8.19" + "node": ">=12" } }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "node_modules/magic-string": { + "version": "0.30.10", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", + "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + } + }, + "node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "peer": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, "engines": { - "node": ">=8" + "node": ">=6" } }, - "node_modules/indexof": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "node_modules/make-dir/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "peer": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "peer": true, "dependencies": { - "once": "^1.3.0", - "wrappy": "1" + "tmpl": "1.0.5" } }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "node_modules/marky": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/marky/-/marky-1.2.5.tgz", + "integrity": "sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q==", + "peer": true + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } }, - "node_modules/ip": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz", - "integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==" + "node_modules/memoize-one": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", + "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==", + "peer": true }, - "node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "peer": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/metro": { + "version": "0.80.8", + "resolved": "https://registry.npmjs.org/metro/-/metro-0.80.8.tgz", + "integrity": "sha512-in7S0W11mg+RNmcXw+2d9S3zBGmCARDxIwoXJAmLUQOQoYsRP3cpGzyJtc7WOw8+FXfpgXvceD0u+PZIHXEL7g==", + "peer": true, "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "@babel/code-frame": "^7.0.0", + "@babel/core": "^7.20.0", + "@babel/generator": "^7.20.0", + "@babel/parser": "^7.20.0", + "@babel/template": "^7.0.0", + "@babel/traverse": "^7.20.0", + "@babel/types": "^7.20.0", + "accepts": "^1.3.7", + "chalk": "^4.0.0", + "ci-info": "^2.0.0", + "connect": "^3.6.5", + "debug": "^2.2.0", + "denodeify": "^1.2.1", + "error-stack-parser": "^2.0.6", + "graceful-fs": "^4.2.4", + "hermes-parser": "0.20.1", + "image-size": "^1.0.2", + "invariant": "^2.2.4", + "jest-worker": "^29.6.3", + "jsc-safe-url": "^0.2.2", + "lodash.throttle": "^4.1.1", + "metro-babel-transformer": "0.80.8", + "metro-cache": "0.80.8", + "metro-cache-key": "0.80.8", + "metro-config": "0.80.8", + "metro-core": "0.80.8", + "metro-file-map": "0.80.8", + "metro-resolver": "0.80.8", + "metro-runtime": "0.80.8", + "metro-source-map": "0.80.8", + "metro-symbolicate": "0.80.8", + "metro-transform-plugins": "0.80.8", + "metro-transform-worker": "0.80.8", + "mime-types": "^2.1.27", + "node-fetch": "^2.2.0", + "nullthrows": "^1.1.1", + "rimraf": "^3.0.2", + "serialize-error": "^2.1.0", + "source-map": "^0.5.6", + "strip-ansi": "^6.0.0", + "throat": "^5.0.0", + "ws": "^7.5.1", + "yargs": "^17.6.2" }, - "engines": { - "node": ">= 0.4" + "bin": { + "metro": "src/cli.js" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=18" } }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, + "node_modules/metro-babel-transformer": { + "version": "0.80.8", + "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.80.8.tgz", + "integrity": "sha512-TTzNwRZb2xxyv4J/+yqgtDAP2qVqH3sahsnFu6Xv4SkLqzrivtlnyUbaeTdJ9JjtADJUEjCbgbFgUVafrXdR9Q==", + "peer": true, "dependencies": { - "binary-extensions": "^2.0.0" + "@babel/core": "^7.20.0", + "hermes-parser": "0.20.1", + "nullthrows": "^1.1.1" }, "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", - "dev": true, + "node_modules/metro-babel-transformer/node_modules/hermes-estree": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.20.1.tgz", + "integrity": "sha512-SQpZK4BzR48kuOg0v4pb3EAGNclzIlqMj3Opu/mu7bbAoFw6oig6cEt/RAi0zTFW/iW6Iz9X9ggGuZTAZ/yZHg==", + "peer": true + }, + "node_modules/metro-babel-transformer/node_modules/hermes-parser": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.20.1.tgz", + "integrity": "sha512-BL5P83cwCogI8D7rrDCgsFY0tdYUtmFP9XaXtl2IQjC+2Xo+4okjfXintlTxcIwl4qeGddEl28Z11kbVIw0aNA==", + "peer": true, "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "hermes-estree": "0.20.1" } }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, + "node_modules/metro-cache": { + "version": "0.80.8", + "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.80.8.tgz", + "integrity": "sha512-5svz+89wSyLo7BxdiPDlwDTgcB9kwhNMfNhiBZPNQQs1vLFXxOkILwQiV5F2EwYT9DEr6OPZ0hnJkZfRQ8lDYQ==", + "peer": true, "dependencies": { - "has-tostringtag": "^1.0.0" + "metro-core": "0.80.8", + "rimraf": "^3.0.2" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=18" } }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, + "node_modules/metro-cache-key": { + "version": "0.80.8", + "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.80.8.tgz", + "integrity": "sha512-qWKzxrLsRQK5m3oH8ePecqCc+7PEhR03cJE6Z6AxAj0idi99dHOSitTmY0dclXVB9vP2tQIAE8uTd8xkYGk8fA==", + "peer": true, "engines": { - "node": ">=0.10.0" + "node": ">=18" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, + "node_modules/metro-config": { + "version": "0.80.8", + "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.80.8.tgz", + "integrity": "sha512-VGQJpfJawtwRzGzGXVUoohpIkB0iPom4DmSbAppKfumdhtLA8uVeEPp2GM61kL9hRvdbMhdWA7T+hZFDlo4mJA==", + "peer": true, + "dependencies": { + "connect": "^3.6.5", + "cosmiconfig": "^5.0.5", + "jest-validate": "^29.6.3", + "metro": "0.80.8", + "metro-cache": "0.80.8", + "metro-core": "0.80.8", + "metro-runtime": "0.80.8" + }, "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/is-generator": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-generator/-/is-generator-1.0.3.tgz", - "integrity": "sha1-wUwhBX7TbjKNuANHlmxpP4hjifM=", - "dev": true - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, + "node_modules/metro-core": { + "version": "0.80.8", + "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.80.8.tgz", + "integrity": "sha512-g6lud55TXeISRTleW6SHuPFZHtYrpwNqbyFIVd9j9Ofrb5IReiHp9Zl8xkAfZQp8v6ZVgyXD7c130QTsCz+vBw==", + "peer": true, "dependencies": { - "is-extglob": "^2.1.1" + "lodash.throttle": "^4.1.1", + "metro-resolver": "0.80.8" }, "engines": { - "node": ">=0.10.0" + "node": ">=18" } }, - "node_modules/is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", - "dev": true - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, + "node_modules/metro-file-map": { + "version": "0.80.8", + "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.80.8.tgz", + "integrity": "sha512-eQXMFM9ogTfDs2POq7DT2dnG7rayZcoEgRbHPXvhUWkVwiKkro2ngcBE++ck/7A36Cj5Ljo79SOkYwHaWUDYDw==", + "peer": true, + "dependencies": { + "anymatch": "^3.0.3", + "debug": "^2.2.0", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.4", + "invariant": "^2.2.4", + "jest-worker": "^29.6.3", + "micromatch": "^4.0.4", + "node-abort-controller": "^3.1.1", + "nullthrows": "^1.1.1", + "walker": "^1.0.7" + }, "engines": { - "node": ">=0.12.0" + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, + "node_modules/metro-file-map/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/metro-file-map/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "peer": true + }, + "node_modules/metro-minify-terser": { + "version": "0.80.8", + "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.80.8.tgz", + "integrity": "sha512-y8sUFjVvdeUIINDuW1sejnIjkZfEF+7SmQo0EIpYbWmwh+kq/WMj74yVaBWuqNjirmUp1YNfi3alT67wlbBWBQ==", + "peer": true, + "dependencies": { + "terser": "^5.15.0" + }, "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true, + "node_modules/metro-resolver": { + "version": "0.80.8", + "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.80.8.tgz", + "integrity": "sha512-JdtoJkP27GGoZ2HJlEsxs+zO7jnDUCRrmwXJozTlIuzLHMRrxgIRRby9fTCbMhaxq+iA9c+wzm3iFb4NhPmLbQ==", + "peer": true, "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/is-reference": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", - "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", - "dev": true, + "node_modules/metro-runtime": { + "version": "0.80.8", + "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.80.8.tgz", + "integrity": "sha512-2oScjfv6Yb79PelU1+p8SVrCMW9ZjgEiipxq7jMRn8mbbtWzyv3g8Mkwr+KwOoDFI/61hYPUbY8cUnu278+x1g==", + "peer": true, "dependencies": { - "@types/estree": "*" + "@babel/runtime": "^7.0.0" + }, + "engines": { + "node": ">=18" } }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, + "node_modules/metro-source-map": { + "version": "0.80.8", + "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.80.8.tgz", + "integrity": "sha512-+OVISBkPNxjD4eEKhblRpBf463nTMk3KMEeYS8Z4xM/z3qujGJGSsWUGRtH27+c6zElaSGtZFiDMshEb8mMKQg==", + "peer": true, "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "@babel/traverse": "^7.20.0", + "@babel/types": "^7.20.0", + "invariant": "^2.2.4", + "metro-symbolicate": "0.80.8", + "nullthrows": "^1.1.1", + "ob1": "0.80.8", + "source-map": "^0.5.6", + "vlq": "^1.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=18" } }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, + "node_modules/metro-source-map/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "peer": true, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "engines": { - "node": ">=10" + "node_modules/metro-symbolicate": { + "version": "0.80.8", + "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.80.8.tgz", + "integrity": "sha512-nwhYySk79jQhwjL9QmOUo4wS+/0Au9joEryDWw7uj4kz2yvw1uBjwmlql3BprQCBzRdB3fcqOP8kO8Es+vE31g==", + "peer": true, + "dependencies": { + "invariant": "^2.2.4", + "metro-source-map": "0.80.8", + "nullthrows": "^1.1.1", + "source-map": "^0.5.6", + "through2": "^2.0.1", + "vlq": "^1.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "bin": { + "metro-symbolicate": "src/index.js" + }, + "engines": { + "node": ">=18" } }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "node_modules/isbinaryfile": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.8.tgz", - "integrity": "sha512-53h6XFniq77YdW+spoRrebh0mnmTxRPTlcuIArO57lmMdq4uBKFKaeTjnb92oYWrSn/LVL+LT+Hap2tFQj8V+w==", - "dev": true, + "node_modules/metro-symbolicate/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "peer": true, "engines": { - "node": ">= 8.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/gjtorikian/" + "node": ">=0.10.0" } }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true + "node_modules/metro-transform-plugins": { + "version": "0.80.8", + "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.80.8.tgz", + "integrity": "sha512-sSu8VPL9Od7w98MftCOkQ1UDeySWbsIAS5I54rW22BVpPnI3fQ42srvqMLaJUQPjLehUanq8St6OMBCBgH/UWw==", + "peer": true, + "dependencies": { + "@babel/core": "^7.20.0", + "@babel/generator": "^7.20.0", + "@babel/template": "^7.0.0", + "@babel/traverse": "^7.20.0", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=18" + } }, - "node_modules/jest-diff": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", - "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", - "dev": true, + "node_modules/metro-transform-worker": { + "version": "0.80.8", + "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.80.8.tgz", + "integrity": "sha512-+4FG3TQk3BTbNqGkFb2uCaxYTfsbuFOCKMMURbwu0ehCP8ZJuTUramkaNZoATS49NSAkRgUltgmBa4YaKZ5mqw==", + "peer": true, "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" + "@babel/core": "^7.20.0", + "@babel/generator": "^7.20.0", + "@babel/parser": "^7.20.0", + "@babel/types": "^7.20.0", + "metro": "0.80.8", + "metro-babel-transformer": "0.80.8", + "metro-cache": "0.80.8", + "metro-cache-key": "0.80.8", + "metro-minify-terser": "0.80.8", + "metro-source-map": "0.80.8", + "metro-transform-plugins": "0.80.8", + "nullthrows": "^1.1.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=18" } }, - "node_modules/jest-diff/node_modules/ansi-styles": { + "node_modules/metro/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, + "peer": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -4312,27 +10511,31 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-diff/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, + "node_modules/metro/node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "peer": true + }, + "node_modules/metro/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "peer": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=12" } }, - "node_modules/jest-diff/node_modules/color-convert": { + "node_modules/metro/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, + "peer": true, "dependencies": { "color-name": "~1.1.4" }, @@ -4340,1718 +10543,1827 @@ "node": ">=7.0.0" } }, - "node_modules/jest-diff/node_modules/color-name": { + "node_modules/metro/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "peer": true }, - "node_modules/jest-diff/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" + "node_modules/metro/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "peer": true, + "dependencies": { + "ms": "2.0.0" } }, - "node_modules/jest-diff/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, + "node_modules/metro/node_modules/hermes-estree": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.20.1.tgz", + "integrity": "sha512-SQpZK4BzR48kuOg0v4pb3EAGNclzIlqMj3Opu/mu7bbAoFw6oig6cEt/RAi0zTFW/iW6Iz9X9ggGuZTAZ/yZHg==", + "peer": true + }, + "node_modules/metro/node_modules/hermes-parser": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.20.1.tgz", + "integrity": "sha512-BL5P83cwCogI8D7rrDCgsFY0tdYUtmFP9XaXtl2IQjC+2Xo+4okjfXintlTxcIwl4qeGddEl28Z11kbVIw0aNA==", + "peer": true, "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "hermes-estree": "0.20.1" } }, - "node_modules/jest-get-type": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", - "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", - "dev": true, + "node_modules/metro/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "peer": true + }, + "node_modules/metro/node_modules/serialize-error": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz", + "integrity": "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==", + "peer": true, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=0.10.0" } }, - "node_modules/jest-matcher-utils": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", - "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" - }, + "node_modules/metro/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "peer": true, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=0.10.0" } }, - "node_modules/jest-matcher-utils/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, + "node_modules/metro/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "peer": true, "dependencies": { - "color-convert": "^2.0.1" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/jest-matcher-utils/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, + "node_modules/metro/node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "peer": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/metro/node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "peer": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=12" } }, - "node_modules/jest-matcher-utils/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, + "node_modules/metro/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dependencies": { - "color-name": "~1.1.4" + "braces": "^3.0.2", + "picomatch": "^2.3.1" }, "engines": { - "node": ">=7.0.0" + "node": ">=8.6" } }, - "node_modules/jest-matcher-utils/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } }, - "node_modules/jest-matcher-utils/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "engines": { - "node": ">=8" + "node": ">= 0.6" } }, - "node_modules/jest-matcher-utils/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=8" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", "dev": true, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=16 || 14 >=14.17" } }, - "node_modules/jest-message-util/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/mkdirp": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.6.tgz", + "integrity": "sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" + "bin": { + "mkdirp": "dist/cjs/src/bin.js" }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/jest-message-util/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/mocha": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.4.0.tgz", + "integrity": "sha512-eqhGB8JKapEYcC4ytX/xrzKforgEc3j1pGlAXVy3eRwrtAy5/nIfT1SvgGzfN0XZZxeLq0aQWkOUAmqIJiv+bA==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "8.1.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" }, - "engines": { - "node": ">=10" + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "engines": { + "node": ">= 14.0.0" } }, - "node_modules/jest-message-util/node_modules/color-convert": { + "node_modules/mocha/node_modules/argparse": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/mocha/node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], "dependencies": { - "color-name": "~1.1.4" + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" }, "engines": { - "node": ">=7.0.0" + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" } }, - "node_modules/jest-message-util/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "node_modules/mocha/node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } }, - "node_modules/jest-message-util/node_modules/has-flag": { + "node_modules/mocha/node_modules/escape-string-regexp": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-message-util/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/mocha/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/jest-worker": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", - "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "node_modules/mocha/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" + "is-glob": "^4.0.1" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 6" } }, - "node_modules/jest-worker/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/mocha/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, - "engines": { - "node": ">=8" + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/mocha/node_modules/minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/js-sdsl": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", - "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/mocha/node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" + "dependencies": { + "randombytes": "^2.1.0" } }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, - "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", "dev": true, "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" } }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "peer": true }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true + "node_modules/netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "engines": { + "node": ">= 0.4.0" + } }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "dev": true, + "peer": true }, - "node_modules/jsonfile": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "node_modules/nise": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/nise/-/nise-1.5.3.tgz", + "integrity": "sha512-Ymbac/94xeIrMf59REBPOv0thr+CJVFMhrlAkW/gjCIE58BGQdCj0x7KRCb3yz+Ga2Rz3E9XXSvUyyxqqhjQAQ==", "dev": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" + "dependencies": { + "@sinonjs/formatio": "^3.2.1", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "lolex": "^5.0.1", + "path-to-regexp": "^1.7.0" } }, - "node_modules/jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "node_modules/nise/node_modules/lolex": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-5.1.2.tgz", + "integrity": "sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A==", "dev": true, "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - }, - "engines": { - "node": ">=0.6.0" + "@sinonjs/commons": "^1.7.0" } }, - "node_modules/jsprim/node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "node_modules/jsprim/node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", "dev": true, - "engines": [ - "node >=0.6.0" - ], "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" + "lower-case": "^2.0.2", + "tslib": "^2.0.3" } }, - "node_modules/just-extend": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", - "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", - "dev": true + "node_modules/nocache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/nocache/-/nocache-3.0.4.tgz", + "integrity": "sha512-WDD0bdg9mbq6F4mRxEYcPWwfA1vxd0mrvKOyxI7Xj/atfRHVeutzuWByG//jfm4uPzp0y4Kj051EORCBSQMycw==", + "peer": true, + "engines": { + "node": ">=12.0.0" + } }, - "node_modules/karma": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/karma/-/karma-5.2.3.tgz", - "integrity": "sha512-tHdyFADhVVPBorIKCX8A37iLHxc6RBRphkSoQ+MLKdAtFn1k97tD8WUGi1KlEtDZKL3hui0qhsY9HXUfSNDYPQ==", + "node_modules/nock": { + "version": "14.0.0-beta.5", + "resolved": "https://registry.npmjs.org/nock/-/nock-14.0.0-beta.5.tgz", + "integrity": "sha512-u255tf4DYvyErTlPZA9uTfXghiZZy+NflUOFONPVKZ5tP0yaHwKig28zyFOLhu8y5YcCRC+V5vDk4HHileh2iw==", "dev": true, "dependencies": { - "body-parser": "^1.19.0", - "braces": "^3.0.2", - "chokidar": "^3.4.2", - "colors": "^1.4.0", - "connect": "^3.7.0", - "di": "^0.0.1", - "dom-serialize": "^2.2.1", - "glob": "^7.1.6", - "graceful-fs": "^4.2.4", - "http-proxy": "^1.18.1", - "isbinaryfile": "^4.0.6", - "lodash": "^4.17.19", - "log4js": "^6.2.1", - "mime": "^2.4.5", - "minimatch": "^3.0.4", - "qjobs": "^1.2.0", - "range-parser": "^1.2.1", - "rimraf": "^3.0.2", - "socket.io": "^2.3.0", - "source-map": "^0.6.1", - "tmp": "0.2.1", - "ua-parser-js": "0.7.22", - "yargs": "^15.3.1" - }, - "bin": { - "karma": "bin/karma" + "json-stringify-safe": "^5.0.1", + "propagate": "^2.0.0" }, "engines": { - "node": ">= 10" + "node": ">= 18" } }, - "node_modules/karma-chai": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/karma-chai/-/karma-chai-0.1.0.tgz", - "integrity": "sha1-vuWtQEAFF4Ea40u5RfdikJEIt5o=", - "dev": true, - "peerDependencies": { - "chai": "*", - "karma": ">=0.10.9" + "node_modules/node-abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", + "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", + "peer": true + }, + "node_modules/node-dir": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", + "integrity": "sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==", + "peer": true, + "dependencies": { + "minimatch": "^3.0.2" + }, + "engines": { + "node": ">= 0.10.5" } }, - "node_modules/karma-chrome-launcher": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.0.tgz", - "integrity": "sha512-3dPs/n7vgz1rxxtynpzZTvb9y/GIaW8xjAwcIGttLbycqoFtI7yo1NGnQi6oFTherRE+GIhCAHZC4vEqWGhNvg==", - "dev": true, + "node_modules/node-dir/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "peer": true, "dependencies": { - "which": "^1.2.1" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/karma-mocha": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/karma-mocha/-/karma-mocha-2.0.1.tgz", - "integrity": "sha512-Tzd5HBjm8his2OA4bouAsATYEpZrp9vC7z5E5j4C5Of5Rrs1jY67RAwXNcVmd/Bnk1wgvQRou0zGVLey44G4tQ==", - "dev": true, + "node_modules/node-dir/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "peer": true, "dependencies": { - "minimist": "^1.2.3" + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, - "node_modules/karma-phantomjs-launcher": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/karma-phantomjs-launcher/-/karma-phantomjs-launcher-1.0.4.tgz", - "integrity": "sha1-0jyjSAG9qYY60xjju0vUBisTrNI=", - "dev": true, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "dependencies": { - "lodash": "^4.0.1", - "phantomjs-prebuilt": "^2.1.7" + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" }, "peerDependencies": { - "karma": ">=0.9" + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } } }, - "node_modules/karma-sinon-chai": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/karma-sinon-chai/-/karma-sinon-chai-2.0.2.tgz", - "integrity": "sha512-SDgh6V0CUd+7ruL1d3yG6lFzmJNGRNQuEuCYXLaorruNP9nwQfA7hpsp4clx4CbOo5Gsajh3qUOT7CrVStUKMw==", - "dev": true, - "peerDependencies": { - "chai": ">=3.5.0", - "sinon": ">=2.1.0", - "sinon-chai": ">=2.9.0" + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "peer": true + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "peer": true + }, + "node_modules/node-stream-zip": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/node-stream-zip/-/node-stream-zip-1.15.0.tgz", + "integrity": "sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw==", + "peer": true, + "engines": { + "node": ">=0.12.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/antelle" } }, - "node_modules/karma-sourcemap-loader": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/karma-sourcemap-loader/-/karma-sourcemap-loader-0.3.8.tgz", - "integrity": "sha512-zorxyAakYZuBcHRJE+vbrK2o2JXLFWK8VVjiT/6P+ltLBUGUvqTEkUiQ119MGdOrK7mrmxXHZF1/pfT6GgIZ6g==", + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, "dependencies": { - "graceful-fs": "^4.1.2" + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" } }, - "node_modules/karma-spec-reporter": { - "version": "0.0.32", - "resolved": "https://registry.npmjs.org/karma-spec-reporter/-/karma-spec-reporter-0.0.32.tgz", - "integrity": "sha1-LpxyB+pyZ3EmAln4K+y1QyCeRAo=", + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, - "dependencies": { - "colors": "^1.1.2" - }, - "peerDependencies": { - "karma": ">=0.9" + "bin": { + "semver": "bin/semver" } }, - "node_modules/kew": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz", - "integrity": "sha1-edk9LTM2PW/dKXCzNdkUGtWR15s=", - "dev": true - }, - "node_modules/klaw": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", - "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", - "dev": true, - "optionalDependencies": { - "graceful-fs": "^4.1.9" + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/knuth-shuffle-seeded": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/knuth-shuffle-seeded/-/knuth-shuffle-seeded-1.0.6.tgz", - "integrity": "sha1-AfG2VzOqdUDuCNiwF0Fk0iCB5OE=", - "dev": true, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "peer": true, "dependencies": { - "seed-random": "~2.2.0" + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/lil-uuid": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/lil-uuid/-/lil-uuid-0.1.1.tgz", - "integrity": "sha1-+e3PI/AOQr9D8PhD2Y2LU/M0HxY=" + "node_modules/nullthrows": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", + "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==", + "peer": true }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "*" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "node_modules/ob1": { + "version": "0.80.8", + "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.80.8.tgz", + "integrity": "sha512-QHJQk/lXMmAW8I7AIM3in1MSlwe1umR72Chhi8B7Xnq6mzjhBKkA6Fy/zAhQnGkA4S912EPCEvTij5yh+EQTAA==", + "peer": true, + "engines": { + "node": ">=18" + } }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, - "node_modules/log-symbols/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/log-symbols/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/log-symbols/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dependencies": { - "color-name": "~1.1.4" + "ee-first": "1.1.1" }, "engines": { - "node": ">=7.0.0" + "node": ">= 0.8" } }, - "node_modules/log-symbols/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/log-symbols/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "peer": true, "engines": { - "node": ">=8" + "node": ">= 0.8" } }, - "node_modules/log-symbols/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "wrappy": "1" } }, - "node_modules/log4js": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.4.1.tgz", - "integrity": "sha512-iUiYnXqAmNKiIZ1XSAitQ4TmNs8CdZYTAWINARF3LjnsLN8tY5m0vRwd6uuWj/yNY0YHxeZodnbmxKFUOM2rMg==", - "dev": true, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "peer": true, "dependencies": { - "date-format": "^4.0.3", - "debug": "^4.3.3", - "flatted": "^3.2.4", - "rfdc": "^1.3.0", - "streamroller": "^3.0.2" + "mimic-fn": "^2.1.0" }, "engines": { - "node": ">=8.0" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lolex": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-4.2.0.tgz", - "integrity": "sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg==", - "dev": true - }, - "node_modules/lower-case": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", - "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", - "dev": true, + "node_modules/open": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-6.4.0.tgz", + "integrity": "sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==", + "peer": true, "dependencies": { - "tslib": "^2.0.3" + "is-wsl": "^1.1.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "node_modules/open/node_modules/is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==", + "peer": true, "engines": { - "node": ">=12" + "node": ">=4" } }, - "node_modules/magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "dev": true, "dependencies": { - "sourcemap-codec": "^1.4.4" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", - "dev": true, + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, "engines": { - "node": ">= 0.6" + "node": ">= 0.8.0" } }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "peer": true, + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, "engines": { - "node": ">= 8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dependencies": { + "yocto-queue": "^0.1.0" + }, "engines": { - "node": ">= 0.6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" + "p-limit": "^3.0.2" }, "engines": { - "node": ">=8.6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", - "bin": { - "mime": "cli.js" - }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "engines": { - "node": ">=4.0.0" + "node": ">=6" } }, - "node_modules/mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", + "node_modules/pac-proxy-agent": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.1.tgz", + "integrity": "sha512-ASV8yU4LLKBAjqIPMbrgtaKIvxQri/yh2OpI+S6hVa9JRkUI3Y3NPFbfngDtY7oFtSMD3w31Xns89mDa3Feo5A==", + "dependencies": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.2", + "pac-resolver": "^7.0.0", + "socks-proxy-agent": "^8.0.2" + }, "engines": { - "node": ">= 0.6" + "node": ">= 14" } }, - "node_modules/mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "node_modules/pac-resolver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", "dependencies": { - "mime-db": "1.51.0" + "degenerator": "^5.0.0", + "netmask": "^2.0.2" }, "engines": { - "node": ">= 0.6" + "node": ">= 14" } }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/pad-right": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/pad-right/-/pad-right-0.2.2.tgz", + "integrity": "sha512-4cy8M95ioIGolCoMmm2cMntGR1lPLEbOMzOKu8bzjuJP6JpzEMQcDHmh7hHLYGgob+nKe1YHFMaG4V59HQa89g==", "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "repeat-string": "^1.5.2" }, "engines": { - "node": "*" + "node": ">=0.10.0" } }, - "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, "dependencies": { - "minimist": "^1.2.5" + "callsites": "^3.0.0" }, - "bin": { - "mkdirp": "bin/cmd.js" + "engines": { + "node": ">=6" } }, - "node_modules/mocha": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.1.tgz", - "integrity": "sha512-T7uscqjJVS46Pq1XDXyo9Uvey9gd3huT/DD9cYBb4K2Xc/vbKRPUWK067bxDQRK0yIz6Jxk73IrnimvASzBNAQ==", + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "dependencies": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.3", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.2.0", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "3.0.4", - "ms": "2.1.3", - "nanoid": "3.2.0", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "which": "2.0.2", - "workerpool": "6.2.0", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha" + "engines": { + "node": ">=8" }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" + "node": ">=0.10.0" } }, - "node_modules/mocha/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-scurry": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", + "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { - "node": ">=8" + "node": ">=16 || 14 >=14.17" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/mocha/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "node_modules/path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, + "dependencies": { + "isarray": "0.0.1" + } + }, + "node_modules/path-to-regexp/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", "dev": true }, - "node_modules/mocha/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" + "engines": { + "node": ">=8" } }, - "node_modules/mocha/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, "engines": { - "node": ">=7.0.0" + "node": "*" } }, - "node_modules/mocha/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", "dev": true }, - "node_modules/mocha/node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "dev": true + }, + "node_modules/phantomjs-prebuilt": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.16.tgz", + "integrity": "sha512-PIiRzBhW85xco2fuj41FmsyuYHKjKuXWmhjy3A/Y+CMpN/63TV+s9uzfVhsUwFe0G77xWtHBG8xmXf5BqEUEuQ==", + "deprecated": "this package is now deprecated", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "es6-promise": "^4.0.3", + "extract-zip": "^1.6.5", + "fs-extra": "^1.0.0", + "hasha": "^2.2.0", + "kew": "^0.7.0", + "progress": "^1.1.8", + "request": "^2.81.0", + "request-progress": "^2.0.1", + "which": "^1.2.10" + }, + "bin": { + "phantomjs": "bin/phantomjs" + } + }, + "node_modules/phantomjs-prebuilt/node_modules/progress": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "integrity": "sha512-UdA8mJ4weIkUBO224tIarHzuHs4HuYiJvsuGT7j/SPQiUJVjYvNDBIPa0hAorduOfjGohB/qHWRa/lrrWX/mXw==", "dev": true, "engines": { - "node": ">=0.3.1" + "node": ">=0.4.0" } }, - "node_modules/mocha/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "node_modules/phantomjs-prebuilt/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "engines": { - "node": ">=10" + "node": ">=8.6" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/mocha/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "peer": true, "engines": { - "node": ">=8" + "node": ">=6" } }, - "node_modules/mocha/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/mocha/node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "pinkie": "^2.0.0" }, "engines": { - "node": "*" + "node": ">=0.10.0" } }, - "node_modules/mocha/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "peer": true, + "engines": { + "node": ">= 6" + } }, - "node_modules/mocha/node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, + "node_modules/pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "peer": true, "dependencies": { - "randombytes": "^2.1.0" + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=6" } }, - "node_modules/mocha/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "peer": true, "dependencies": { - "has-flag": "^4.0.0" + "locate-path": "^3.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "node": ">=6" } }, - "node_modules/mocha/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "peer": true, "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" }, "engines": { - "node": ">= 8" + "node": ">=6" } }, - "node_modules/mocha/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "peer": true, "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "p-try": "^2.0.0" }, "engines": { - "node": ">=10" + "node": ">=6" }, "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/mocha/node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mocha/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "peer": true, "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "p-limit": "^2.0.0" }, "engines": { - "node": ">=10" + "node": ">=6" } }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "node_modules/pkg-dir/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "peer": true, + "engines": { + "node": ">=4" + } }, - "node_modules/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/nanoid": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", - "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==", + "node_modules/prettier": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", "dev": true, "bin": { - "nanoid": "bin/nanoid.cjs" + "prettier": "bin/prettier.cjs" }, "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, "engines": { - "node": ">= 0.6" + "node": ">=6.0.0" } }, - "node_modules/netmask": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", - "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, "engines": { - "node": ">= 0.4.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/next-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", - "dev": true + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, - "node_modules/nise": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/nise/-/nise-1.5.3.tgz", - "integrity": "sha512-Ymbac/94xeIrMf59REBPOv0thr+CJVFMhrlAkW/gjCIE58BGQdCj0x7KRCb3yz+Ga2Rz3E9XXSvUyyxqqhjQAQ==", + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true, - "dependencies": { - "@sinonjs/formatio": "^3.2.1", - "@sinonjs/text-encoding": "^0.7.1", - "just-extend": "^4.0.2", - "lolex": "^5.0.1", - "path-to-regexp": "^1.7.0" + "engines": { + "node": ">=0.4.0" } }, - "node_modules/nise/node_modules/lolex": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-5.1.2.tgz", - "integrity": "sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A==", - "dev": true, + "node_modules/promise": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", + "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", + "peer": true, "dependencies": { - "@sinonjs/commons": "^1.7.0" + "asap": "~2.0.6" } }, - "node_modules/no-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", - "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", - "dev": true, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "peer": true, "dependencies": { - "lower-case": "^2.0.2", - "tslib": "^2.0.3" + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" } }, - "node_modules/nock": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/nock/-/nock-9.6.1.tgz", - "integrity": "sha512-EDgl/WgNQ0C1BZZlASOQkQdE6tAWXJi8QQlugqzN64JJkvZ7ILijZuG24r4vCC7yOfnm6HKpne5AGExLGCeBWg==", - "dev": true, - "engines": [ - "node >= 4.0" - ], + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "peer": true, "dependencies": { - "chai": "^4.1.2", - "debug": "^3.1.0", - "deep-equal": "^1.0.0", - "json-stringify-safe": "^5.0.1", - "lodash": "^4.17.5", - "mkdirp": "^0.5.0", - "propagate": "^1.0.0", - "qs": "^6.5.1", - "semver": "^5.5.0" + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" } }, - "node_modules/nock/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "peer": true }, - "node_modules/nock/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "node_modules/propagate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz", + "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==", "dev": true, - "bin": { - "semver": "bin/semver" + "engines": { + "node": ">= 8" } }, - "node_modules/node-fetch": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", - "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", - "dev": true, + "node_modules/property-expr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz", + "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==", + "dev": true + }, + "node_modules/proxy-agent": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.4.0.tgz", + "integrity": "sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==", "dependencies": { - "whatwg-url": "^5.0.0" + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.3", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.0.1", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.2" }, "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } + "node": ">= 14" } }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, + "node_modules/proxy-agent/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", "engines": { - "node": ">=0.10.0" + "node": ">=12" } }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "engines": { - "node": "*" + "node": ">=6" } }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "node_modules/qjobs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", "dev": true, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.9" } }, - "node_modules/object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "side-channel": "^1.0.4" }, "engines": { - "node": ">= 0.4" + "node": ">=0.6" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" + "node_modules/queue": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", + "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", + "peer": true, + "dependencies": { + "inherits": "~2.0.3" } }, - "node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true, - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dependencies": { - "wrappy": "1" - } + "node_modules/rambda": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/rambda/-/rambda-7.5.0.tgz", + "integrity": "sha512-y/M9weqWAH4iopRd7EHDEQQvpFPHj1AA3oHozE9tfITHUtTR7Z9PSlIRRG2l1GuW7sefC1cXFfIcF+cgnShdBA==", + "dev": true }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, "dependencies": { - "yocto-queue": "^0.1.0" - }, + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 0.6" } }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dev": true, "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">= 0.8" } }, - "node_modules/pac-proxy-agent": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.1.tgz", - "integrity": "sha512-ASV8yU4LLKBAjqIPMbrgtaKIvxQri/yh2OpI+S6hVa9JRkUI3Y3NPFbfngDtY7oFtSMD3w31Xns89mDa3Feo5A==", + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "peer": true, "dependencies": { - "@tootallnate/quickjs-emscripten": "^0.23.0", - "agent-base": "^7.0.2", - "debug": "^4.3.4", - "get-uri": "^6.0.1", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.2", - "pac-resolver": "^7.0.0", - "socks-proxy-agent": "^8.0.2" + "loose-envify": "^1.1.0" }, "engines": { - "node": ">= 14" + "node": ">=0.10.0" } }, - "node_modules/pac-proxy-agent/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/react-devtools-core": { + "version": "4.28.5", + "resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-4.28.5.tgz", + "integrity": "sha512-cq/o30z9W2Wb4rzBefjv5fBalHU0rJGZCHAkf/RHSBWSSYwh8PlQTqqOJmgIIbBtpj27T6FIPXeomIjZtCNVqA==", + "peer": true, "dependencies": { - "ms": "2.1.2" - }, + "shell-quote": "^1.6.1", + "ws": "^7" + } + }, + "node_modules/react-devtools-core/node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "peer": true, "engines": { - "node": ">=6.0" + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" }, "peerDependenciesMeta": { - "supports-color": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { "optional": true } } }, - "node_modules/pac-resolver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.0.tgz", - "integrity": "sha512-Fd9lT9vJbHYRACT8OhCbZBbxr6KRSawSovFpy8nDGshaK99S/EBhVIHp9+crhxrsZOuvLpgL1n23iyPg6Rl2hg==", + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, + "node_modules/react-native": { + "version": "0.73.6", + "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.73.6.tgz", + "integrity": "sha512-oqmZe8D2/VolIzSPZw+oUd6j/bEmeRHwsLn1xLA5wllEYsZ5zNuMsDus235ONOnCRwexqof/J3aztyQswSmiaA==", + "peer": true, "dependencies": { - "degenerator": "^5.0.0", - "ip": "^1.1.8", - "netmask": "^2.0.2" + "@jest/create-cache-key-function": "^29.6.3", + "@react-native-community/cli": "12.3.6", + "@react-native-community/cli-platform-android": "12.3.6", + "@react-native-community/cli-platform-ios": "12.3.6", + "@react-native/assets-registry": "0.73.1", + "@react-native/codegen": "0.73.3", + "@react-native/community-cli-plugin": "0.73.17", + "@react-native/gradle-plugin": "0.73.4", + "@react-native/js-polyfills": "0.73.1", + "@react-native/normalize-colors": "0.73.2", + "@react-native/virtualized-lists": "0.73.4", + "abort-controller": "^3.0.0", + "anser": "^1.4.9", + "ansi-regex": "^5.0.0", + "base64-js": "^1.5.1", + "chalk": "^4.0.0", + "deprecated-react-native-prop-types": "^5.0.0", + "event-target-shim": "^5.0.1", + "flow-enums-runtime": "^0.0.6", + "invariant": "^2.2.4", + "jest-environment-node": "^29.6.3", + "jsc-android": "^250231.0.0", + "memoize-one": "^5.0.0", + "metro-runtime": "^0.80.3", + "metro-source-map": "^0.80.3", + "mkdirp": "^0.5.1", + "nullthrows": "^1.1.1", + "pretty-format": "^26.5.2", + "promise": "^8.3.0", + "react-devtools-core": "^4.27.7", + "react-refresh": "^0.14.0", + "react-shallow-renderer": "^16.15.0", + "regenerator-runtime": "^0.13.2", + "scheduler": "0.24.0-canary-efb381bbf-20230505", + "stacktrace-parser": "^0.1.10", + "whatwg-fetch": "^3.0.0", + "ws": "^6.2.2", + "yargs": "^17.6.2" + }, + "bin": { + "react-native": "cli.js" }, "engines": { - "node": ">= 14" + "node": ">=18" + }, + "peerDependencies": { + "react": "18.2.0" } }, - "node_modules/pad-right": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/pad-right/-/pad-right-0.2.2.tgz", - "integrity": "sha1-b7ySQEXSRPKiokRQMGDTv8YAl3Q=", - "dev": true, + "node_modules/react-native-url-polyfill": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/react-native-url-polyfill/-/react-native-url-polyfill-2.0.0.tgz", + "integrity": "sha512-My330Do7/DvKnEvwQc0WdcBnFPploYKp9CYlefDXzIdEaA+PAhDYllkvGeEroEzvc4Kzzj2O4yVdz8v6fjRvhA==", "dependencies": { - "repeat-string": "^1.5.2" + "whatwg-url-without-unicode": "8.0.0-3" }, - "engines": { - "node": ">=0.10.0" + "peerDependencies": { + "react-native": "*" } }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, + "node_modules/react-native/node_modules/@jest/types": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "peer": true, "dependencies": { - "callsites": "^3.0.0" + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" }, "engines": { - "node": ">=6" + "node": ">= 10.14.2" } }, - "node_modules/parseqs": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz", - "integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==", - "dev": true - }, - "node_modules/parseuri": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz", - "integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==", - "dev": true - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true, - "engines": { - "node": ">= 0.8" + "node_modules/react-native/node_modules/@types/yargs": { + "version": "15.0.19", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.19.tgz", + "integrity": "sha512-2XUaGVmyQjgyAZldf0D0c14vvo/yv0MhQBSTJcejMMaitsn3nxCB6TmH4G0ZQf+uxROOa9mpanoSm8h6SG/1ZA==", + "peer": true, + "dependencies": { + "@types/yargs-parser": "*" } }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, + "node_modules/react-native/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "peer": true, "engines": { "node": ">=8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, + "node_modules/react-native/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "dev": true, + "node_modules/react-native/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "peer": true, "dependencies": { - "isarray": "0.0.1" - } - }, - "node_modules/path-to-regexp/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true, + "node_modules/react-native/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, "engines": { - "node": "*" + "node": ">=7.0.0" } }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", - "dev": true - }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true + "node_modules/react-native/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "peer": true }, - "node_modules/phantomjs-prebuilt": { - "version": "2.1.16", - "resolved": "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.16.tgz", - "integrity": "sha1-79ISpKOWbTZHaE6ouniFSb4q7+8=", - "deprecated": "this package is now deprecated", - "dev": true, - "hasInstallScript": true, + "node_modules/react-native/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "peer": true, "dependencies": { - "es6-promise": "^4.0.3", - "extract-zip": "^1.6.5", - "fs-extra": "^1.0.0", - "hasha": "^2.2.0", - "kew": "^0.7.0", - "progress": "^1.1.8", - "request": "^2.81.0", - "request-progress": "^2.0.1", - "which": "^1.2.10" + "minimist": "^1.2.6" }, "bin": { - "phantomjs": "bin/phantomjs" + "mkdirp": "bin/cmd.js" } }, - "node_modules/phantomjs-prebuilt/node_modules/progress": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", - "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", - "dev": true, + "node_modules/react-native/node_modules/pretty-format": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "peer": true, + "dependencies": { + "@jest/types": "^26.6.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^17.0.1" + }, "engines": { - "node": ">=0.4.0" + "node": ">= 10" } }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } + "node_modules/react-native/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "peer": true }, - "node_modules/pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } + "node_modules/react-native/node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "peer": true }, - "node_modules/pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, + "node_modules/react-native/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "peer": true, "dependencies": { - "pinkie": "^2.0.0" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/prettier": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", - "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" + "node": ">=10" }, - "engines": { - "node": ">=10.13.0" + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, + "node_modules/react-native/node_modules/ws": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz", + "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==", + "peer": true, "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" + "async-limiter": "~1.0.0" } }, - "node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "dev": true, + "node_modules/react-native/node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "peer": true, "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=12" } }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, + "node_modules/react-native/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "peer": true, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=12" } }, - "node_modules/pretty-format/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, + "node_modules/react-refresh": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", + "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==", + "peer": true, "engines": { - "node": ">=0.4.0" + "node": ">=0.10.0" } }, - "node_modules/propagate": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/propagate/-/propagate-1.0.0.tgz", - "integrity": "sha1-AMLa7t2iDofjeCs0Stuhzd1q1wk=", - "dev": true, - "engines": [ - "node >= 0.8.1" - ] + "node_modules/react-shallow-renderer": { + "version": "16.15.0", + "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz", + "integrity": "sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==", + "peer": true, + "dependencies": { + "object-assign": "^4.1.1", + "react-is": "^16.12.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0" + } }, - "node_modules/proxy-agent": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.1.tgz", - "integrity": "sha512-Rb5RVBy1iyqOtNl15Cw/llpeLH8bsb37gM1FUfKQ+Wck6xHlbAhWGUFiTRHtkjqGTA5pSHz6+0hrPW/oECihPQ==", + "node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, "dependencies": { - "agent-base": "^7.0.2", - "debug": "^4.3.4", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.2", - "lru-cache": "^7.14.1", - "pac-proxy-agent": "^7.0.1", - "proxy-from-env": "^1.1.0", - "socks-proxy-agent": "^8.0.2" + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" }, "engines": { - "node": ">= 14" + "node": ">=8" } }, - "node_modules/proxy-agent/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, "dependencies": { - "ms": "2.1.2" + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" }, "engines": { - "node": ">=6.0" + "node": ">=8" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" - }, - "node_modules/psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/qjobs": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", - "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "node_modules/read-pkg-up/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, "engines": { - "node": ">=0.9" + "node": ">=8" } }, - "node_modules/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==", + "node_modules/read-pkg-up/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, "engines": { - "node": ">=0.6" + "node": ">=6" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/ramda": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.2.tgz", - "integrity": "sha512-SbiLPU40JuJniHexQSAgad32hfwd+DRUdwF2PlVuI5RZD0/vahUco7R8vD86J/tcEKKF9vZrUVwgtmGCqlCKyA==", - "dev": true - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "node_modules/read-pkg-up/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "dependencies": { - "safe-buffer": "^5.1.0" + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", "dev": true, "engines": { - "node": ">= 0.6" + "node": ">=8" } }, - "node_modules/raw-body": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz", - "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==", + "node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", "dev": true, - "dependencies": { - "bytes": "3.1.2", - "http-errors": "1.8.1", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, "engines": { - "node": ">= 0.8" + "node": ">=8" } }, "node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -6074,19 +12386,79 @@ "node": ">=8.10.0" } }, + "node_modules/readline": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/readline/-/readline-1.3.0.tgz", + "integrity": "sha512-k2d6ACCkiNYz222Fs/iNze30rRJ1iIicW7JuX/7/cozvih6YCkFZH+J6mAFDVgv0dRBaAyr4jDqC95R2y4IADg==", + "peer": true + }, + "node_modules/recast": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.21.5.tgz", + "integrity": "sha512-hjMmLaUXAm1hIuTqOdeYObMslq/q+Xff6QE3Y2P+uoHAg2nmVlLBps2hzh1UJDdMtDTMXOFewK6ky51JQIeECg==", + "peer": true, + "dependencies": { + "ast-types": "0.15.2", + "esprima": "~4.0.0", + "source-map": "~0.6.1", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/recast/node_modules/ast-types": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.15.2.tgz", + "integrity": "sha512-c27loCv9QkZinsa5ProX751khO9DJl/AcB5c2KNtA6NRvHKS0PgLfcftz72KVq504vB0Gku5s2kUZzDBvQWvHg==", + "peer": true, + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/reflect-metadata": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", - "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.1.tgz", + "integrity": "sha512-i5lLI6iw9AU3Uu4szRNPPEkomnkjRTaVt9hy/bn5g/oSzekBSMeLZblcjP74AW0vBabqERLLIrz+gR8QYR54Tw==", + "deprecated": "This version has a critical bug in fallback handling. Please upgrade to reflect-metadata@0.2.2 or newer.", "dev": true }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "peer": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "peer": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", - "dev": true, + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", "peer": true }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, "node_modules/regexp-match-indices": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regexp-match-indices/-/regexp-match-indices-1.0.2.tgz", @@ -6097,22 +12469,24 @@ } }, "node_modules/regexp-tree": { - "version": "0.1.24", - "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.24.tgz", - "integrity": "sha512-s2aEVuLhvnVJW6s/iPgEGK6R+/xngd2jNQ+xy4bXNDKxZKJH6jpPHY6kVeVv1IeLCHgswRj+Kl3ELaDjG6V1iw==", + "version": "0.1.27", + "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz", + "integrity": "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==", "dev": true, "bin": { "regexp-tree": "bin/regexp-tree" } }, "node_modules/regexp.prototype.flags": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz", - "integrity": "sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" }, "engines": { "node": ">= 0.4" @@ -6121,22 +12495,48 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "peer": true, + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, "engines": { - "node": ">=8" + "node": ">=4" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "peer": true, + "dependencies": { + "jsesc": "~0.5.0" }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "peer": true, + "bin": { + "jsesc": "bin/jsesc" } }, "node_modules/repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", "dev": true, "engines": { "node": ">=0.10" @@ -6177,12 +12577,26 @@ "node_modules/request-progress": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-2.0.1.tgz", - "integrity": "sha1-XTa7V5YcZzqlt4jbyBQf3yO0Tgg=", + "integrity": "sha512-dxdraeZVUNEn9AvLrxkgB2k6buTlym71dJk1fk4v8j3Ou3RKNm07BcgbHdj2lLgYGfqX71F+awb1MR+tWPFJzA==", "dev": true, "dependencies": { "throttleit": "^1.0.0" } }, + "node_modules/request/node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, "node_modules/request/node_modules/qs": { "version": "6.5.3", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", @@ -6205,8 +12619,7 @@ "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true, + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "engines": { "node": ">=0.10.0" } @@ -6215,21 +12628,20 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true + "peer": true }, "node_modules/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", "dev": true }, "node_modules/resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dev": true, + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dependencies": { - "is-core-module": "^2.8.1", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -6261,6 +12673,15 @@ "node": ">=8" } }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/resolve-pkg/node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -6270,6 +12691,25 @@ "node": ">=8" } }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "peer": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "peer": true + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -6281,16 +12721,15 @@ } }, "node_modules/rfdc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", - "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz", + "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==", "dev": true }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, "dependencies": { "glob": "^7.1.3" }, @@ -6301,25 +12740,84 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/rollup": { - "version": "2.68.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.68.0.tgz", - "integrity": "sha512-XrMKOYK7oQcTio4wyTz466mucnd8LzkiZLozZ4Rz0zQD+HeX4nUK4B8GrTX/2EvN2/vBF/i2WnaXboPxo0JylA==", + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.14.3.tgz", + "integrity": "sha512-ag5tTQKYsj1bhrFC9+OEWqb5O6VYgtQDO9hPDBMmIbePwhfSr+ExlcU741t8Dhw5DkPCQf6noz0jb36D6W9/hw==", "dev": true, + "dependencies": { + "@types/estree": "1.0.5" + }, "bin": { "rollup": "dist/bin/rollup" }, "engines": { - "node": ">=10.0.0" + "node": ">=18.0.0", + "npm": ">=8.0.0" }, "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.14.3", + "@rollup/rollup-android-arm64": "4.14.3", + "@rollup/rollup-darwin-arm64": "4.14.3", + "@rollup/rollup-darwin-x64": "4.14.3", + "@rollup/rollup-linux-arm-gnueabihf": "4.14.3", + "@rollup/rollup-linux-arm-musleabihf": "4.14.3", + "@rollup/rollup-linux-arm64-gnu": "4.14.3", + "@rollup/rollup-linux-arm64-musl": "4.14.3", + "@rollup/rollup-linux-powerpc64le-gnu": "4.14.3", + "@rollup/rollup-linux-riscv64-gnu": "4.14.3", + "@rollup/rollup-linux-s390x-gnu": "4.14.3", + "@rollup/rollup-linux-x64-gnu": "4.14.3", + "@rollup/rollup-linux-x64-musl": "4.14.3", + "@rollup/rollup-win32-arm64-msvc": "4.14.3", + "@rollup/rollup-win32-ia32-msvc": "4.14.3", + "@rollup/rollup-win32-x64-msvc": "4.14.3", "fsevents": "~2.3.2" } }, "node_modules/rollup-plugin-gzip": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/rollup-plugin-gzip/-/rollup-plugin-gzip-3.0.1.tgz", - "integrity": "sha512-yzyrbe5cn/3yTqtGpVb+0kQXiqKLZpNpRTGpItc11b8c9IhawpjZPPLMkh1Q7gl6UsHIVjcw9LeEdvom9H3klw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-gzip/-/rollup-plugin-gzip-3.1.2.tgz", + "integrity": "sha512-9xemMyvCjkklgNpu6jCYqQAbvCLJzA2nilkiOGzFuXTUX3cXEFMwIhsIBRF7kTKD/SnZ1tNPcxFm4m4zJ3VfNQ==", "dev": true, "engines": { "node": ">=10.0.0" @@ -6328,21 +12826,30 @@ "rollup": ">=2.0.0" } }, - "node_modules/rollup-plugin-terser": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", - "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", + "node_modules/rollup-plugin-string": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-string/-/rollup-plugin-string-3.0.0.tgz", + "integrity": "sha512-vqyzgn9QefAgeKi+Y4A7jETeIAU1zQmS6VotH6bzm/zmUQEnYkpIGRaOBPY41oiWYV4JyBoGAaBjYMYuv+6wVw==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.10.4", - "jest-worker": "^26.2.1", - "serialize-javascript": "^4.0.0", - "terser": "^5.0.0" - }, - "peerDependencies": { - "rollup": "^2.0.0" + "rollup-pluginutils": "^2.4.1" } }, + "node_modules/rollup-pluginutils": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", + "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", + "dev": true, + "dependencies": { + "estree-walker": "^0.6.1" + } + }, + "node_modules/rollup-pluginutils/node_modules/estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "dev": true + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -6369,8 +12876,7 @@ "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "node_modules/safer-buffer": { "version": "2.1.2", @@ -6378,16 +12884,25 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, + "node_modules/scheduler": { + "version": "0.24.0-canary-efb381bbf-20230505", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.24.0-canary-efb381bbf-20230505.tgz", + "integrity": "sha512-ABvovCDe/k9IluqSh4/ISoq8tIJnW8euVAWYt5j/bg6dRnqwQwiGO1F/V4AyK96NGF/FB04FhOUDuWj8IKfABA==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, "node_modules/seed-random": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/seed-random/-/seed-random-2.2.0.tgz", - "integrity": "sha1-KpsZ4lCoFwmSMaW5mk2vgLf77VQ=", + "integrity": "sha512-34EQV6AAHQGhoc0tn/96a9Fsi6v2xdqe/dMUwljGRaFOzR3EgRmECvD0O8vi8X+/uQ50LGHfkNu/Eue5TPKZkQ==", "dev": true }, "node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -6409,10 +12924,71 @@ "node": ">=10" } }, - "node_modules/semver/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "peer": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "peer": true + }, + "node_modules/send/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "peer": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "peer": true + }, + "node_modules/send/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "peer": true, + "engines": { + "node": ">= 0.8" + } }, "node_modules/serialize-error": { "version": "4.1.0", @@ -6438,31 +13014,88 @@ } }, "node_modules/serialize-javascript": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", - "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, "dependencies": { "randombytes": "^2.1.0" } }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "peer": true, + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "peer": true + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "peer": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -6474,28 +13107,54 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "engines": { "node": ">=8" } }, + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/sinon": { "version": "7.5.0", "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.5.0.tgz", "integrity": "sha512-AoD0oJWerp0/rY9czP/D6hDTTUYGpObhZjMpd7Cl/A6+j0xBE+ayL/ldfggkBXUs0IkvIiM1ljM8+WkOc5k78Q==", + "deprecated": "16.1.1", "dev": true, "dependencies": { "@sinonjs/commons": "^1.4.0", @@ -6526,157 +13185,151 @@ "node": ">=0.3.1" } }, - "node_modules/slash": { + "node_modules/sinon/node_modules/has-flag": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, "engines": { - "node": ">=8" - } - }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" + "node": ">=4" } }, - "node_modules/socket.io": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.4.1.tgz", - "integrity": "sha512-Si18v0mMXGAqLqCVpTxBa8MGqriHGQh8ccEOhmsmNS3thNCGBwO8WGrwMibANsWtQQ5NStdZwHqZR3naJVFc3w==", + "node_modules/sinon/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "dependencies": { - "debug": "~4.1.0", - "engine.io": "~3.5.0", - "has-binary2": "~1.0.2", - "socket.io-adapter": "~1.1.0", - "socket.io-client": "2.4.0", - "socket.io-parser": "~3.4.0" + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" } }, - "node_modules/socket.io-adapter": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz", - "integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==", - "dev": true + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "peer": true }, - "node_modules/socket.io-client": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.4.0.tgz", - "integrity": "sha512-M6xhnKQHuuZd4Ba9vltCLT9oa+YvTsP8j9NcEiLElfIg8KeYPyhWOes6x4t+LTAC8enQbE/995AdTem2uNyKKQ==", - "dev": true, - "dependencies": { - "backo2": "1.0.2", - "component-bind": "1.0.0", - "component-emitter": "~1.3.0", - "debug": "~3.1.0", - "engine.io-client": "~3.5.0", - "has-binary2": "~1.0.2", - "indexof": "0.0.1", - "parseqs": "0.0.6", - "parseuri": "0.0.6", - "socket.io-parser": "~3.3.0", - "to-array": "0.1.4" + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "engines": { + "node": ">=8" } }, - "node_modules/socket.io-client/node_modules/debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, + "node_modules/slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "peer": true, "dependencies": { - "ms": "2.0.0" + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "engines": { + "node": ">=6" } }, - "node_modules/socket.io-client/node_modules/isarray": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", - "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", - "dev": true + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "peer": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } }, - "node_modules/socket.io-client/node_modules/ms": { + "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "peer": true, + "engines": { + "node": ">=4" + } }, - "node_modules/socket.io-client/node_modules/socket.io-parser": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.2.tgz", - "integrity": "sha512-FJvDBuOALxdCI9qwRrO/Rfp9yfndRtc1jSgVgV8FDraihmSP/MLGD5PEuJrNfjALvcQ+vMDM/33AWOYP/JSjDg==", - "dev": true, - "dependencies": { - "component-emitter": "~1.3.0", - "debug": "~3.1.0", - "isarray": "2.0.1" + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" } }, - "node_modules/socket.io-parser": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.4.1.tgz", - "integrity": "sha512-11hMgzL+WCLWf1uFtHSNvliI++tcRUWdoeYuwIl+Axvwy9z2gQM+7nJyN3STj1tLj5JyIUH8/gpDGxzAlDdi0A==", + "node_modules/smob": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz", + "integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==", + "dev": true + }, + "node_modules/socket.io": { + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz", + "integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==", "dev": true, "dependencies": { - "component-emitter": "1.2.1", - "debug": "~4.1.0", - "isarray": "2.0.1" + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.5.2", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" } }, - "node_modules/socket.io-parser/node_modules/component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", - "dev": true - }, - "node_modules/socket.io-parser/node_modules/debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "node_modules/socket.io-adapter": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.4.tgz", + "integrity": "sha512-wDNHGXGewWAjQPt3pyeYBtpWSq9cLE5UW1ZUPL/2eGK9jtse/FpXib7epSTsz0Q0m+6sg6Y4KtcFTlah1bdOVg==", "dev": true, "dependencies": { - "ms": "^2.1.1" + "debug": "~4.3.4", + "ws": "~8.11.0" } }, - "node_modules/socket.io-parser/node_modules/isarray": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", - "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", - "dev": true - }, - "node_modules/socket.io/node_modules/debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", "dev": true, "dependencies": { - "ms": "^2.1.1" + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" } }, "node_modules/socks": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", - "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", "dependencies": { - "ip": "^2.0.0", + "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" }, "engines": { - "node": ">= 10.13.0", + "node": ">= 10.0.0", "npm": ">= 3.0.0" } }, "node_modules/socks-proxy-agent": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.2.tgz", - "integrity": "sha512-8zuqoLv1aP/66PHF5TqwJ7Czm3Yv32urJQHrVyhD7mmA6d61Zv8cIXQYPTWwmg6qlupnPvs/QKDmfa4P/qct2g==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.3.tgz", + "integrity": "sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A==", "dependencies": { - "agent-base": "^7.0.2", + "agent-base": "^7.1.1", "debug": "^4.3.4", "socks": "^2.7.1" }, @@ -6684,32 +13337,10 @@ "node": ">= 14" } }, - "node_modules/socks-proxy-agent/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/socks/node_modules/ip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", - "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==" - }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "devOptional": true, "engines": { "node": ">=0.10.0" } @@ -6718,28 +13349,52 @@ "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz", + "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==", "dev": true }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" }, "node_modules/sshpk": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", "dev": true, "dependencies": { "asn1": "~0.2.3", @@ -6761,26 +13416,33 @@ "node": ">=0.10.0" } }, + "node_modules/sshpk/node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "dev": true + }, "node_modules/stack-chain": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/stack-chain/-/stack-chain-2.0.0.tgz", "integrity": "sha512-GGrHXePi305aW7XQweYZZwiRwR7Js3MWoK/EHzzB9ROdc75nCnjSJVi21rdAGxFl+yCx2L2qdfl5y7NO4lTyqg==", - "dev": true + "dev": true, + "peer": true }, "node_modules/stack-generator": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/stack-generator/-/stack-generator-2.0.5.tgz", - "integrity": "sha512-/t1ebrbHkrLrDuNMdeAcsvynWgoH/i4o8EGGfX7dEYDoTXOYVAkEpFdtshlvabzc6JlJ8Kf9YdFEoz7JkzGN9Q==", + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/stack-generator/-/stack-generator-2.0.10.tgz", + "integrity": "sha512-mwnua/hkqM6pF4k8SnmZ2zfETsRUpWXREfA/goT8SLCV4iOFa4bzOX2nDipWAZFPTjLvQB82f5yaodMVhK0yJQ==", "dev": true, + "peer": true, "dependencies": { - "stackframe": "^1.1.1" + "stackframe": "^1.3.4" } }, "node_modules/stack-utils": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", - "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", - "dev": true, + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", "dependencies": { "escape-string-regexp": "^2.0.0" }, @@ -6788,36 +13450,28 @@ "node": ">=10" } }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/stackframe": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", - "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", - "dev": true + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==" }, "node_modules/stacktrace-gps": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/stacktrace-gps/-/stacktrace-gps-3.0.4.tgz", - "integrity": "sha512-qIr8x41yZVSldqdqe6jciXEaSCKw1U8XTXpjDuy0ki/apyTn/r3w9hDAAQOhZdxvsC93H+WwwEu5cq5VemzYeg==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/stacktrace-gps/-/stacktrace-gps-3.1.2.tgz", + "integrity": "sha512-GcUgbO4Jsqqg6RxfyTHFiPxdPqF+3LFmQhm7MgCuYQOYuWyqxo5pwRPz5d/u6/WYJdEnWfK4r+jGbyD8TSggXQ==", "dev": true, + "peer": true, "dependencies": { "source-map": "0.5.6", - "stackframe": "^1.1.1" + "stackframe": "^1.3.4" } }, "node_modules/stacktrace-gps/node_modules/source-map": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", - "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=", + "integrity": "sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA==", "dev": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -6827,75 +13481,92 @@ "resolved": "https://registry.npmjs.org/stacktrace-js/-/stacktrace-js-2.0.2.tgz", "integrity": "sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg==", "dev": true, + "peer": true, "dependencies": { "error-stack-parser": "^2.0.6", "stack-generator": "^2.0.5", "stacktrace-gps": "^3.0.4" } }, + "node_modules/stacktrace-parser": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz", + "integrity": "sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==", + "peer": true, + "dependencies": { + "type-fest": "^0.7.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/stacktrace-parser/node_modules/type-fest": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", + "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==", + "peer": true, + "engines": { + "node": ">=8" + } + }, "node_modules/statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "dev": true, + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "engines": { "node": ">= 0.6" } }, "node_modules/streamroller": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.0.2.tgz", - "integrity": "sha512-ur6y5S5dopOaRXBuRIZ1u6GC5bcEXHRZKgfBjfCglMhmIf+roVCECjvkEYzNQOXIN2/JPnkMPW/8B3CZoKaEPA==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz", + "integrity": "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==", "dev": true, "dependencies": { - "date-format": "^4.0.3", - "debug": "^4.1.1", - "fs-extra": "^10.0.0" + "date-format": "^4.0.14", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" }, "engines": { "node": ">=8.0" } }, "node_modules/streamroller/node_modules/fs-extra": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz", - "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "dev": true, "dependencies": { "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" }, "engines": { - "node": ">=12" + "node": ">=6 <7 || >=8" } }, "node_modules/streamroller/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", "dev": true, - "dependencies": { - "universalify": "^2.0.0" - }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "node_modules/streamroller/node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true, "engines": { - "node": ">= 10.0.0" + "node": ">= 4.0.0" } }, "node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -6913,7 +13584,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -6923,13 +13593,34 @@ "node": ">=8" } }, - "node_modules/string-width/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } }, "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", @@ -6941,16 +13632,42 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, "node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, "optional": true, "engines": { "node": ">=4" } }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "peer": true, + "engines": { + "node": ">=6" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -6963,102 +13680,142 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/superagent": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.1.2.tgz", - "integrity": "sha512-6WTxW1EB6yCxV5VFOIPQruWGHqc3yI7hEmZK6h+pyk69Lk/Ut7rLUY6W/ONF2MjBuGjvmMiIpsrVJ2vjrHlslA==", + "node_modules/strnum": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", + "peer": true + }, + "node_modules/sudo-prompt": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/sudo-prompt/-/sudo-prompt-9.2.1.tgz", + "integrity": "sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw==", + "peer": true + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dependencies": { - "component-emitter": "^1.3.0", - "cookiejar": "^2.1.4", - "debug": "^4.3.4", - "fast-safe-stringify": "^2.1.1", - "form-data": "^4.0.0", - "formidable": "^2.1.2", - "methods": "^1.1.2", - "mime": "2.6.0", - "qs": "^6.11.0", - "semver": "^7.3.8" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=6.4.0 <13 || >=14" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/superagent/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/synckit": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", + "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", + "dev": true, "dependencies": { - "ms": "2.1.2" + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.0" + "node": "^14.18.0 || >=16.0.0" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "funding": { + "url": "https://opencollective.com/unts" } }, - "node_modules/superagent/node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "node_modules/temp": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.4.tgz", + "integrity": "sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==", + "peer": true, "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "rimraf": "~2.6.2" }, "engines": { - "node": ">= 6" + "node": ">=6.0.0" + } + }, + "node_modules/temp-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", + "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/temp/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/superagent/node_modules/qs": { - "version": "6.11.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", - "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", + "node_modules/temp/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "peer": true, "dependencies": { - "side-channel": "^1.0.4" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" }, "engines": { - "node": ">=0.6" + "node": "*" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/temp/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "peer": true, "dependencies": { - "has-flag": "^3.0.0" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=4" + "node": "*" } }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" + "node_modules/temp/node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "peer": true, + "dependencies": { + "glob": "^7.1.3" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "bin": { + "rimraf": "bin.js" } }, "node_modules/terser": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.11.0.tgz", - "integrity": "sha512-uCA9DLanzzWSsN1UirKwylhhRz3aKPInlfmpGfw8VN6jHsAtu8HJtIpeeHHK23rxnE/cDc+yvmq5wqkIC6Kn0A==", - "dev": true, + "version": "5.30.3", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.30.3.tgz", + "integrity": "sha512-STdUgOUx8rLbMGO9IOwHLpCqolkDITFFQSMYYwKE1N2lY6MVSaeoi10z/EhWxRc6ybqoVmKSkhKYH/XUpl7vSA==", "dependencies": { - "acorn": "^8.5.0", + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", "commander": "^2.20.0", - "source-map": "~0.7.2", "source-map-support": "~0.5.20" }, "bin": { @@ -7071,22 +13828,18 @@ "node_modules/terser/node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, - "node_modules/terser/node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true, - "engines": { - "node": ">= 8" - } + "node_modules/text-encoding": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.7.0.tgz", + "integrity": "sha512-oJQ3f1hrOnbRLOcwKz0Liq2IcrvDeZRHXhd9RgLrsT+DjWY/nty1Hi7v3dtkaEYbPYe0mUoOfzRrMwfXXwgPUA==", + "deprecated": "no longer maintained" }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, "node_modules/thenify": { @@ -7101,7 +13854,7 @@ "node_modules/thenify-all": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", "dev": true, "dependencies": { "thenify": ">= 3.1.0 < 4" @@ -7110,10 +13863,35 @@ "node": ">=0.8" } }, + "node_modules/throat": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", + "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", + "peer": true + }, "node_modules/throttleit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", - "integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.1.tgz", + "integrity": "sha512-vDZpf9Chs9mAdfY046mcPt8fg5QSZr37hEH4TXYBnDF+izxgrbRGUAAaBvIk/fJm9aOFCGFd1EsNg5AZCbnQCQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "peer": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/tiny-case": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz", + "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==", "dev": true }, "node_modules/title-case": { @@ -7145,28 +13923,33 @@ } }, "node_modules/tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", "dev": true, - "dependencies": { - "rimraf": "^3.0.0" - }, "engines": { - "node": ">=8.17.0" + "node": ">=14.14" } }, - "node_modules/to-array": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", - "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=", - "dev": true + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "peer": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "peer": true, + "engines": { + "node": ">=4" + } }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "dependencies": { "is-number": "^7.0.0" }, @@ -7178,11 +13961,16 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true, "engines": { "node": ">=0.6" } }, + "node_modules/toposort": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", + "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==", + "dev": true + }, "node_modules/tough-cookie": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", @@ -7199,8 +13987,19 @@ "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", - "dev": true + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } }, "node_modules/ts-dedent": { "version": "2.2.0", @@ -7212,9 +14011,9 @@ } }, "node_modules/ts-mocha": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/ts-mocha/-/ts-mocha-9.0.2.tgz", - "integrity": "sha512-WyQjvnzwrrubl0JT7EC1yWmNpcsU3fOuBFfdps30zbmFBgKniSaSOyZMZx+Wq7kytUs5CY+pEbSYEbGfIKnXTw==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/ts-mocha/-/ts-mocha-10.0.0.tgz", + "integrity": "sha512-VRfgDO+iiuJFlNB18tzOfypJ21xn2xbuZyDvJvqpTbWgkAgD17ONGr8t+Tl8rcBtOBdjXp5e/Rk+d39f7XBHRw==", "dev": true, "dependencies": { "ts-node": "7.0.1" @@ -7229,7 +14028,7 @@ "tsconfig-paths": "^3.5.0" }, "peerDependencies": { - "mocha": "^3.X.X || ^4.X.X || ^5.X.X || ^6.X.X || ^7.X.X || ^8.X.X || ^9.X.X" + "mocha": "^3.X.X || ^4.X.X || ^5.X.X || ^6.X.X || ^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X" } }, "node_modules/ts-mocha/node_modules/diff": { @@ -7241,6 +14040,18 @@ "node": ">=0.3.1" } }, + "node_modules/ts-mocha/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, "node_modules/ts-mocha/node_modules/ts-node": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", @@ -7266,16 +14077,16 @@ "node_modules/ts-mocha/node_modules/yn": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", - "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=", + "integrity": "sha512-uTv8J/wiWTgUTg+9vLTi//leUl5vDQS6uii/emeTb2ssY7vl6QWf2fFbIIGjnhjvbdKlU0ed7QPgY1htTC86jQ==", "dev": true, "engines": { "node": ">=4" } }, "node_modules/ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", @@ -7316,61 +14127,46 @@ } }, "node_modules/tsconfig-paths": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz", - "integrity": "sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==", + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", "dev": true, "optional": true, "dependencies": { "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.0", + "json5": "^1.0.2", + "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "optional": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, "node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "node_modules/tsx": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.7.2.tgz", + "integrity": "sha512-BCNd4kz6fz12fyrgCTEdZHGJ9fWTGeUzXmQysh0RVocDY3h4frk05ZNCXSy4kIenF7y/QnrdiVpTsyNRn6vlAw==", "dev": true, "dependencies": { - "tslib": "^1.8.1" + "esbuild": "~0.19.10", + "get-tsconfig": "^4.7.2" + }, + "bin": { + "tsx": "dist/cli.mjs" }, "engines": { - "node": ">= 6" + "node": ">=18.0.0" }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + "optionalDependencies": { + "fsevents": "~2.3.3" } }, - "node_modules/tsutils/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "dev": true, "dependencies": { "safe-buffer": "^5.0.1" @@ -7382,31 +14178,43 @@ "node_modules/tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", "dev": true }, "node_modules/type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", - "dev": true + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true, + "peer": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } }, "node_modules/type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, "engines": { "node": ">=4" } }, "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "version": "4.15.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.15.0.tgz", + "integrity": "sha512-tB9lu0pQpX5KJq54g+oHOLumOx+pMep4RaM6liXh2PKmVRFF+/vAtUP0ZaJ0kOySfVNjF6doBWPHhBhISKdlIA==", "dev": true, "engines": { - "node": ">=10" + "node": ">=16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -7428,54 +14236,142 @@ "node_modules/typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", "dev": true }, "node_modules/typescript": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", - "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" } }, "node_modules/ua-parser-js": { - "version": "0.7.22", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.22.tgz", - "integrity": "sha512-YUxzMjJ5T71w6a8WWVcMGM6YWOTX27rCoIQgLXiWaxqXSx9D7DNjiGWn1aJIRSQ5qr0xuhra77bSIh6voR/46Q==", + "version": "0.7.37", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.37.tgz", + "integrity": "sha512-xV8kqRKM+jhMvcHWUKthV9fNebIzrNy//2O9ZwWcfiBFR5f25XVZPLlEajk/sf3Ra15V92isyQqnIEXRDaZWEA==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], "engines": { "node": "*" } }, "node_modules/underscore": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.2.tgz", - "integrity": "sha512-ekY1NhRzq0B08g4bGuX4wd2jZx5GnKz6mKSqFL4nqBlfyMGiG10gDFhDTMEfYmDL6Jy0FUIZp7wiRB+0BP7J2g==", + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", "dev": true }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "peer": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "peer": true, + "engines": { + "node": ">=4" + } + }, "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "engines": { - "node": ">= 4.0.0" + "node": ">= 10.0.0" } }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "dev": true, + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "engines": { "node": ">= 0.8" } }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "peer": true, + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, "node_modules/upper-case": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", @@ -7504,30 +14400,31 @@ "node_modules/util-arity": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/util-arity/-/util-arity-1.1.0.tgz", - "integrity": "sha1-WdAa8f2z/t4KxOYysKtfbOl8kzA=", + "integrity": "sha512-kkyIsXKwemfSy8ZEoaIz06ApApnWsk5hQO0vLjZS6UkBiGiW++Jsyb8vSBoc0WKlffGoGs5yYy/j5pp8zckrFA==", "dev": true }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "dev": true, + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "engines": { "node": ">= 0.4.0" } }, "node_modules/uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", "dev": true, - "peer": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], "bin": { "uuid": "dist/bin/uuid" } @@ -7538,11 +14435,30 @@ "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "dev": true }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/verror": { "version": "1.10.1", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.1.tgz", "integrity": "sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==", "dev": true, + "peer": true, "dependencies": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", @@ -7555,71 +14471,155 @@ "node_modules/verror/node_modules/core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true, + "peer": true + }, + "node_modules/vlq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz", + "integrity": "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==", + "peer": true }, "node_modules/void-elements": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", - "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", + "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", "dev": true, "engines": { "node": ">=0.10.0" } }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "peer": true, + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "peer": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", - "dev": true + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-fetch": { + "version": "3.6.20", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", + "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==", + "peer": true }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", - "dev": true, + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, - "node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, + "node_modules/whatwg-url-without-unicode": { + "version": "8.0.0-3", + "resolved": "https://registry.npmjs.org/whatwg-url-without-unicode/-/whatwg-url-without-unicode-8.0.0-3.tgz", + "integrity": "sha512-HoKuzZrUlgpz35YO27XgD28uh/WJH4B0+3ttFqRo//lmq+9T/mIOJ6kqmINI9HpUpz1imRC/nR/lxKpJiv0uig==", + "dependencies": { + "buffer": "^5.4.3", + "punycode": "^2.1.1", + "webidl-conversions": "^5.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/whatwg-url-without-unicode/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/whatwg-url-without-unicode/node_modules/webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dependencies": { "isexe": "^2.0.0" }, "bin": { - "which": "bin/which" + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" } }, "node_modules/which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "peer": true + }, + "node_modules/workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", "dev": true }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/workerpool": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", - "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", - "dev": true - }, - "node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "dependencies": { "ansi-styles": "^4.0.0", @@ -7627,10 +14627,13 @@ "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", @@ -7645,7 +14648,7 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/color-convert": { + "node_modules/wrap-ansi-cjs/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", @@ -7657,213 +14660,221 @@ "node": ">=7.0.0" } }, - "node_modules/wrap-ansi/node_modules/color-name": { + "node_modules/wrap-ansi-cjs/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "node_modules/ws": { - "version": "7.4.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", - "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true, "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "node": ">=12" }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/xmlhttprequest-ssl": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.6.3.tgz", - "integrity": "sha512-3XfeQE/wNkvrIktn2Kf0869fC0BN6UpydVasGIeSm2B1Llihf7/0UfZM+eCkOw3P7bP4+qPgqhm7ZoxuJtFU0Q==", + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, "engines": { - "node": ">=0.4.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true }, - "node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, "engines": { - "node": ">=10" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/write-file-atomic": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "peer": true, "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" } }, - "node_modules/yargs-unparser/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "node_modules/write-file-atomic/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "peer": true + }, + "node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", "dev": true, "engines": { - "node": ">=10" + "node": ">=10.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } } }, - "node_modules/yargs-unparser/node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "node_modules/xmlbuilder": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", "dev": true, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8.0" } }, - "node_modules/yargs/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "node_modules/xregexp": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.4.1.tgz", + "integrity": "sha512-2u9HwfadaJaY9zHtRRnH6BY6CQVNQKkYm3oLtC9gJXXzfsbACg5X5e4EZZGVAH+YIfa+QA9lsFQTTe3HURF3ag==", "dev": true, + "peer": true, "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, + "@babel/runtime-corejs3": "^7.12.1" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "peer": true, "engines": { - "node": ">=8" + "node": ">=0.4" } }, - "node_modules/yargs/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/yargs/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yaml": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.1.tgz", + "integrity": "sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==", + "bin": { + "yaml": "bin.mjs" }, "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 14" } }, - "node_modules/yargs/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, "dependencies": { - "p-limit": "^2.2.0" + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" }, "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/yargs/node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", "dev": true, "engines": { - "node": ">=6" + "node": ">=10" } }, - "node_modules/yargs/node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", "dev": true, "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" }, "engines": { - "node": ">=6" + "node": ">=10" } }, "node_modules/yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", "dev": true, "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } }, - "node_modules/yeast": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", - "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=", - "dev": true - }, "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", @@ -7877,13 +14888,36 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, "engines": { "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/yup": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/yup/-/yup-1.2.0.tgz", + "integrity": "sha512-PPqYKSAXjpRCgLgLKVGPA33v5c/WgEx3wi6NFjIiegz90zSwyMpvTFp/uGcVnnbx6to28pgnzp/q8ih3QRjLMQ==", + "dev": true, + "dependencies": { + "property-expr": "^2.0.5", + "tiny-case": "^1.0.3", + "toposort": "^2.0.2", + "type-fest": "^2.19.0" + } + }, + "node_modules/yup/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/package.json b/package.json index ac243ddc9..c28f88b83 100644 --- a/package.json +++ b/package.json @@ -1,25 +1,26 @@ { "name": "pubnub", - "version": "7.6.3", + "version": "8.0.0", "author": "PubNub ", "description": "Publish & Subscribe Real-time Messaging with PubNub", "scripts": { "build": "npm run build:node && npm run build:web", - "build:web": "rollup -c rollup.config.js", + "build:web": "rollup -c ./rollup.config.js --bundleConfigAsCjs", "build:node": "tsc -p tsconfig.json", "test": "npm run test:web && npm run test:node", - "test:web": "karma start ./karma/web.config.js", - "test:node": "ts-mocha -p tsconfig.mocha.json --config .mocharc.yml", + "test:web": "karma start karma/web.config.cjs", + "test:node": "TS_NODE_PROJECT='./tsconfig.json' mocha --project tsconfig.mocha.json", "clean": "rimraf lib dist upload", - "lint": "eslint \"src/**/*\" --config .eslintrc.js", + "lint": "eslint \"src/**/*\" --config .eslintrc.cjs", "ci": "npm run clean && npm run build && npm run lint && npm run test", - "ci:web": "npm run clean && npm run build && npm run lint && npm run test:web", - "ci:node": "npm run clean && npm run build && npm run lint && npm run test:node", - "test:feature:objectsv2:node": "ts-mocha -p tsconfig.mocha.json --no-config --require test/setup.js --reporter spec test/dist/objectsv2.test.js", - "test:feature:fileupload:node": "ts-mocha -p tsconfig.mocha.json --no-config --require test/setup.js --reporter spec test/feature/file_upload.node.test.js", + "ci:web": "npm run clean && npm run build:web && npm run lint && npm run test:web", + "ci:node": "npm run clean && npm run build:node && npm run lint && npm run test:node", + "test:feature:objectsv2:node": "NODE_ENV=test TS_NODE_PROJECT='./tsconfig.json' mocha --project tsconfig.mocha.json --require tsx --no-config --reporter spec test/dist/objectsv2.test.ts", + "test:feature:fileupload:node": "NODE_ENV=test TS_NODE_PROJECT='./tsconfig.json' mocha --project tsconfig.mocha.json --require tsx --no-config --reporter spec test/feature/file_upload.node.test.ts", "test:contract": "npm run test:contract:prepare && npm run test:contract:start", "test:contract:prepare": "rimraf test/specs && git clone --branch master --depth 1 git@github.com:pubnub/sdk-specifications.git test/specs", - "test:contract:start": "cucumber-js -p default --tags 'not @na=js'", + "test:contract:specific": "TS_NODE_PROJECT='./test/contract/tsconfig.json' cucumber-js --require test/contract/definitions/grant.ts dist/contract/contract/features --tags '@featureSet=eventEngine and @contract=subscribeReceivingRecovery and not @na=js'", + "test:contract:start": "cucumber-js -p default --tags '@featureSet=access and @contract=grantAllPermissions and not @na=js and not @skip'", "test:contract:beta": "cucumber-js -p default --tags 'not @na=js and @beta and not @skip'", "contract:refresh": "rimraf dist/contract && git clone --branch master git@github.com:pubnub/service-contract-mock.git dist/contract && npm install --prefix dist/contract && npm run refresh-files --prefix dist/contract", "contract:server": "npm start --prefix dist/contract consumer", @@ -55,37 +56,47 @@ "buffer": "^6.0.3", "cbor-js": "^0.1.0", "cbor-sync": "^1.0.4", + "form-data": "^4.0.0", "lil-uuid": "^0.1.1", - "superagent": "^8.1.2", - "proxy-agent": "^6.3.0" + "node-fetch": "^2.7.0", + "proxy-agent": "^6.3.0", + "react-native-url-polyfill": "^2.0.0", + "text-encoding": "^0.7.0" }, "devDependencies": { - "@cucumber/cucumber": "^7.3.1", + "@cucumber/cucumber": "^10.4.0", "@cucumber/pretty-formatter": "^1.0.0", - "@rollup/plugin-commonjs": "^21.0.2", - "@rollup/plugin-json": "^4.1.0", - "@rollup/plugin-node-resolve": "^13.1.3", - "@rollup/plugin-typescript": "^8.3.1", - "@types/chai": "^4.3.3", + "@rollup/plugin-commonjs": "^25.0.7", + "@rollup/plugin-json": "^6.1.0", + "@rollup/plugin-node-resolve": "^15.2.3", + "@rollup/plugin-replace": "^5.0.5", + "@rollup/plugin-terser": "^0.4.4", + "@rollup/plugin-typescript": "^11.1.6", + "@types/cbor-js": "^0.1.1", + "@types/chai": "^4.3.14", + "@types/chai-as-promised": "^7.1.8", "@types/cucumber": "^7.0.0", "@types/expect": "^24.3.0", + "@types/lil-uuid": "^0.1.3", "@types/mocha": "^9.1.0", "@types/nock": "^9.3.1", - "@types/node-fetch": "^2.6.3", - "@types/pubnub": "^7.2.0", - "@typescript-eslint/eslint-plugin": "^5.12.1", - "@typescript-eslint/parser": "^5.12.1", - "chai": "^4.3.4", + "@types/node-fetch": "^2.6.11", + "@types/sinon": "^17.0.3", + "@types/text-encoding": "^0.0.39", + "@types/underscore": "^1.11.15", + "@typescript-eslint/eslint-plugin": "^7.4.0", + "@typescript-eslint/parser": "^7.4.0", + "chai": "^4.4.1", "chai-as-promised": "^7.1.1", "chai-nock": "^1.2.0", "cucumber-pretty": "^6.0.1", - "cucumber-tsflow": "^4.0.0-rc.11", - "es6-shim": "^0.35.6", - "eslint": "^8.9.0", - "eslint-plugin-mocha": "^10.0.3", - "eslint-plugin-prettier": "^4.0.0", + "cucumber-tsflow": "^4.4.4", + "es6-shim": "^0.35.8", + "eslint": "^8.57.0", + "eslint-plugin-mocha": "^10.4.1", + "eslint-plugin-prettier": "^5.1.3", "js-yaml": "^3.13.1", - "karma": "^5.0.3", + "karma": "6.4.3", "karma-chai": "^0.1.0", "karma-chrome-launcher": "^3.1.0", "karma-mocha": "^2.0.1", @@ -93,25 +104,25 @@ "karma-sinon-chai": "^2.0.2", "karma-sourcemap-loader": "^0.3.7", "karma-spec-reporter": "0.0.32", - "mocha": "^9.2.1", - "nock": "^9.6.1", - "node-fetch": "^2.6.9", + "mocha": "10.4.0", + "nock": "^14.0.0-beta.5", "phantomjs-prebuilt": "^2.1.16", - "prettier": "^2.5.1", + "prettier": "^3.2.5", "rimraf": "^3.0.2", - "rollup": "^2.68.0", - "rollup-plugin-gzip": "^3.0.1", - "rollup-plugin-terser": "^7.0.2", + "rollup": "^4.13.2", + "rollup-plugin-gzip": "^3.1.2", + "rollup-plugin-string": "^3.0.0", "sinon": "^7.5.0", "sinon-chai": "^3.3.0", "source-map-support": "^0.5.21", - "ts-mocha": "^9.0.2", - "ts-node": "^10.9.1", - "typescript": "^4.8.4", + "ts-mocha": "^10.0.0", + "ts-node": "^10.9.2", + "tsx": "^4.7.1", + "typescript": "^5.4.5", "underscore": "^1.9.2" }, "license": "SEE LICENSE IN LICENSE", "engine": { - "node": ">=0.8" + "node": ">=18" } -} \ No newline at end of file +} diff --git a/rollup.config.js b/rollup.config.js index 2892fe84e..9eeb322f3 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,37 +1,84 @@ import { join, basename, dirname } from 'path'; import typescript from '@rollup/plugin-typescript'; -import commonjs from '@rollup/plugin-commonjs'; import resolve from '@rollup/plugin-node-resolve'; +import commonjs from '@rollup/plugin-commonjs'; +import replace from '@rollup/plugin-replace'; import json from '@rollup/plugin-json'; -import { terser } from 'rollup-plugin-terser'; -import gzipPlugin from 'rollup-plugin-gzip'; +const gzipPlugin = require('rollup-plugin-gzip').default; +import terser from '@rollup/plugin-terser'; import { browser, version } from './package.json'; -import tsConfig from './tsconfig.rollup.json'; + +const SERVICE_WORKER_CDN = 'https://cdn.pubnub.com/sdk/javascript'; export default [ { - input: 'src/web/index.js', + input: 'src/web/index.ts', output: { file: browser, format: 'umd', name: 'PubNub', }, - plugins: [json(), resolve({ browser: true }), commonjs(), typescript(tsConfig), terser()], + plugins: [ + json(), + resolve({ browser: true }), + replace({ + SERVICE_WORKER_FILE_PLACEHOLDER: join(dirname(browser), basename(browser, '.min.js') + '.worker.min.js'), + SERVICE_WORKER_CDN, + preventAssignment: true, + }), + commonjs(), + typescript({ tsconfig: 'tsconfig.rollup.json' }), + terser(), + ], }, { - input: 'src/web/index.js', + input: 'src/web/index.ts', output: { file: join(dirname(browser), basename(browser, '.min.js') + '.js'), format: 'umd', name: 'PubNub', }, - plugins: [json(), resolve({ browser: true }), commonjs(), typescript(tsConfig)], + plugins: [ + json(), + resolve({ browser: true }), + replace({ + SERVICE_WORKER_FILE_PLACEHOLDER: join(dirname(browser), basename(browser, '.min.js') + '.worker.js'), + SERVICE_WORKER_CDN, + preventAssignment: true, + }), + commonjs(), + typescript({ tsconfig: 'tsconfig.rollup.json' }), + ], + }, + { + input: 'src/transport/service-worker/subscription-service-worker.ts', + output: { + file: join(dirname(browser), basename(browser, '.min.js') + '.worker.min.js'), + format: 'umd', + name: 'PubNub', + }, + plugins: [ + json(), + resolve({ browser: true }), + commonjs(), + typescript({ tsconfig: 'tsconfig.rollup.json' }), + terser(), + ], + }, + { + input: 'src/transport/service-worker/subscription-service-worker.ts', + output: { + file: join(dirname(browser), basename(browser, '.min.js') + '.worker.js'), + format: 'umd', + name: 'PubNub', + }, + plugins: [json(), resolve({ browser: true }), commonjs(), typescript({ tsconfig: 'tsconfig.rollup.json' })], }, { - input: 'src/web/index.js', + input: 'src/web/index.ts', output: { file: `upload/gzip/pubnub.${version}.min.js`, format: 'umd', @@ -40,37 +87,129 @@ export default [ plugins: [ json(), resolve({ browser: true }), + replace({ + SERVICE_WORKER_FILE_PLACEHOLDER: `pubnub.worker.${version}.min.js`, + SERVICE_WORKER_CDN, + preventAssignment: true, + }), commonjs(), - typescript(tsConfig), + typescript({ tsconfig: 'tsconfig.rollup.json' }), terser(), gzipPlugin({ fileName: '' }), ], }, { - input: 'src/web/index.js', + input: 'src/web/index.ts', output: { file: `upload/gzip/pubnub.${version}.js`, format: 'umd', name: 'PubNub', }, - plugins: [json(), resolve({ browser: true }), commonjs(), typescript(tsConfig), gzipPlugin({ fileName: '' })], + plugins: [ + json(), + resolve({ browser: true }), + replace({ + SERVICE_WORKER_FILE_PLACEHOLDER: `pubnub.worker.${version}.js`, + SERVICE_WORKER_CDN, + preventAssignment: true, + }), + commonjs(), + typescript({ tsconfig: 'tsconfig.rollup.json' }), + gzipPlugin({ fileName: '' }), + ], }, { - input: 'src/web/index.js', + input: 'src/web/index.ts', output: { file: `upload/normal/pubnub.${version}.min.js`, format: 'umd', name: 'PubNub', }, - plugins: [json(), resolve({ browser: true }), commonjs(), typescript(tsConfig), terser()], + plugins: [ + json(), + resolve({ browser: true }), + replace({ + SERVICE_WORKER_FILE_PLACEHOLDER: `pubnub.worker.${version}.min.js`, + SERVICE_WORKER_CDN, + preventAssignment: true, + }), + commonjs(), + typescript({ tsconfig: 'tsconfig.rollup.json' }), + terser(), + ], }, { - input: 'src/web/index.js', + input: 'src/web/index.ts', output: { file: `upload/normal/pubnub.${version}.js`, format: 'umd', name: 'PubNub', }, - plugins: [json(), resolve({ browser: true }), commonjs(), typescript(tsConfig)], + plugins: [ + json(), + resolve({ browser: true }), + replace({ + SERVICE_WORKER_FILE_PLACEHOLDER: `pubnub.worker.${version}.js`, + SERVICE_WORKER_CDN, + preventAssignment: true, + }), + commonjs(), + typescript({ tsconfig: 'tsconfig.rollup.json' }), + ], + }, + { + input: 'src/transport/service-worker/subscription-service-worker.ts', + output: { + file: `upload/gzip/pubnub.worker.${version}.min.js`, + format: 'umd', + name: 'PubNub', + }, + plugins: [ + json(), + resolve({ browser: true }), + commonjs(), + typescript({ tsconfig: 'tsconfig.rollup.json' }), + terser(), + gzipPlugin({ fileName: '' }), + ], + }, + { + input: 'src/transport/service-worker/subscription-service-worker.ts', + output: { + file: `upload/gzip/pubnub.worker.${version}.js`, + format: 'umd', + name: 'PubNub', + }, + plugins: [ + json(), + resolve({ browser: true }), + commonjs(), + typescript({ tsconfig: 'tsconfig.rollup.json' }), + gzipPlugin({ fileName: '' }), + ], + }, + { + input: 'src/transport/service-worker/subscription-service-worker.ts', + output: { + file: `upload/normal/pubnub.worker.${version}.min.js`, + format: 'umd', + name: 'PubNub', + }, + plugins: [ + json(), + resolve({ browser: true }), + commonjs(), + typescript({ tsconfig: 'tsconfig.rollup.json' }), + terser(), + ], + }, + { + input: 'src/transport/service-worker/subscription-service-worker.ts', + output: { + file: `upload/normal/pubnub.worker.${version}.js`, + format: 'umd', + name: 'PubNub', + }, + plugins: [json(), resolve({ browser: true }), commonjs(), typescript({ tsconfig: 'tsconfig.rollup.json' })], }, ]; diff --git a/src/cbor/common.js b/src/cbor/common.js deleted file mode 100644 index 4ada3eb24..000000000 --- a/src/cbor/common.js +++ /dev/null @@ -1,29 +0,0 @@ -export default class { - _base64ToBinary; - - _cborReader; - - constructor(decode, base64ToBinary) { - this._base64ToBinary = base64ToBinary; - this._decode = decode; - } - - decodeToken(tokenString) { - let padding = ''; - - if (tokenString.length % 4 === 3) { - padding = '='; - } else if (tokenString.length % 4 === 2) { - padding = '=='; - } - - const cleaned = tokenString.replace(/-/gi, '+').replace(/_/gi, '/') + padding; - const result = this._decode(this._base64ToBinary(cleaned)); - - if (typeof result === 'object') { - return result; - } - - return undefined; - } -} diff --git a/src/cbor/common.ts b/src/cbor/common.ts new file mode 100644 index 000000000..a4149ca82 --- /dev/null +++ b/src/cbor/common.ts @@ -0,0 +1,32 @@ +/** + * Cbor decoder module. + */ + +/** + * CBOR data decoder. + */ +export default class Cbor { + constructor( + private readonly decode: (arrayBuffer: ArrayBuffer) => Record, + private readonly base64ToBinary: (paddedInput: string) => ArrayBuffer, + ) {} + + /** + * Decode CBOR base64-encoded object. + * + * @param tokenString - Base64-encoded token. + * + * @returns Token object decoded from CBOR. + */ + decodeToken(tokenString: string): Record | undefined { + let padding = ''; + + if (tokenString.length % 4 === 3) padding = '='; + else if (tokenString.length % 4 === 2) padding = '=='; + + const cleaned = tokenString.replace(/-/gi, '+').replace(/_/gi, '/') + padding; + const result = this.decode(this.base64ToBinary(cleaned)); + + return typeof result === 'object' ? result : undefined; + } +} diff --git a/src/core/components/config.js b/src/core/components/config.js deleted file mode 100644 index 7b7cb1840..000000000 --- a/src/core/components/config.js +++ /dev/null @@ -1,386 +0,0 @@ -/* */ -/* global location */ - -import uuidGenerator from './uuid'; - -const PRESENCE_TIMEOUT_MINIMUM = 20; -const PRESENCE_TIMEOUT_DEFAULT = 300; - -const makeDefaultOrigins = () => Array.from({ length: 20 }, (_, i) => `ps${i + 1}.pndsn.com`); - -export default class { - subscribeKey; - publishKey; - secretKey; - cipherKey; - authKey; - UUID; - proxy; - - /* - if _useInstanceId is true, this instanceId will be added to all requests - */ - instanceId; - - /* - If the SDK is running as part of another SDK built atop of it, allow a custom pnsdk with name and version. - */ - sdkName; - - /* - keep track of the SDK family for identifier generator - */ - sdkFamily; - - /* - If the SDK is operated by a partner, allow a custom pnsdk item for them. - */ - partnerId; - - /* - filter expression to pass along when subscribing. - */ - filterExpression; - - /* - configuration to supress leave events; when a presence leave is performed - this configuration will disallow the leave event from happening - */ - suppressLeaveEvents; - - /* - use SSL for http requests? - */ - secure; - - // Custom optional origin. - origin; - - // log verbosity: true to output lots of info - logVerbosity; - - // if instanceId config is true, the SDK will pass the unique instance identifier to the server as instanceId= - useInstanceId; - - // if requestId config is true, the SDK will pass a unique request identifier with each request as request_id= - useRequestId; - - // use connection keep-alive for http requests - keepAlive; - - keepAliveSettings; - - // if autoNetworkDetection config is true, the SDK will emit NetworkUp and NetworkDown - // when there changes in the networking - autoNetworkDetection; - - // configure retry policy configuration. - retryConfiguration; - - // alert when a heartbeat works out. - announceSuccessfulHeartbeats; - - announceFailedHeartbeats; - - /* - how long the server will wait before declaring that the client is gone. - */ - _presenceTimeout; - - /* - how often (in seconds) the client should announce its presence to server - */ - _heartbeatInterval; - - /* - how long to wait for the server when running the subscribe loop - */ - _subscribeRequestTimeout; - - /* - how long to wait for the server when making transactional requests - */ - _transactionalRequestTimeout; - - /* - use send beacon API when unsubscribing. - https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon - */ - _useSendBeacon; - - /* - allow frameworks to append to the PNSDK parameter - the key should be an identifier for the specific framework to prevent duplicates - */ - _PNSDKSuffix; - - /* - if set, the SDK will alert if more messages arrive in one subscribe than the theshold - */ - requestMessageCountThreshold; - - /* - Restore subscription list on disconnection. - */ - restore; - - /* - support for client deduping - */ - dedupeOnSubscribe; - - maximumCacheSize; - - /* - support custom encryption and decryption functions. - */ - customEncrypt; // function to support custome encryption of messages - - customDecrypt; // function used to decrypt old version messages - - // File Upload - - // How many times the publish-file should be retried before giving up - fileUploadPublishRetryLimit; - useRandomIVs; - enableEventEngine; - maintainPresenceState; - - /* - set cryptoModule to encrypt/decrypt messages and files. - */ - cryptoModule; - - constructor({ setup }) { - this._PNSDKSuffix = {}; - - this.instanceId = `pn-${uuidGenerator.createUUID()}`; - this.secretKey = setup.secretKey || setup.secret_key; - this.subscribeKey = setup.subscribeKey || setup.subscribe_key; - this.publishKey = setup.publishKey || setup.publish_key; - this.sdkName = setup.sdkName; - this.sdkFamily = setup.sdkFamily; - this.partnerId = setup.partnerId; - this.setAuthKey(setup.authKey); - this.cryptoModule = setup.cryptoModule; - - this.setFilterExpression(setup.filterExpression); - - if (typeof setup.origin !== 'string' && !Array.isArray(setup.origin) && setup.origin !== undefined) { - throw new Error('Origin must be either undefined, a string or a list of strings.'); - } - - this.origin = setup.origin || makeDefaultOrigins(); - this.secure = setup.ssl || false; - this.restore = setup.restore || false; - this.proxy = setup.proxy; - this.keepAlive = setup.keepAlive; - this.keepAliveSettings = setup.keepAliveSettings; - this.autoNetworkDetection = setup.autoNetworkDetection || false; - - this.dedupeOnSubscribe = setup.dedupeOnSubscribe || false; - this.maximumCacheSize = setup.maximumCacheSize || 100; - - this.customEncrypt = setup.customEncrypt; - this.customDecrypt = setup.customDecrypt; - - this.fileUploadPublishRetryLimit = setup.fileUploadPublishRetryLimit ?? 5; - this.useRandomIVs = setup.useRandomIVs ?? true; - - this.enableEventEngine = setup.enableEventEngine ?? false; - this.maintainPresenceState = setup.maintainPresenceState ?? true; - - // if location config exist and we are in https, force secure to true. - if (typeof location !== 'undefined' && location.protocol === 'https:') { - this.secure = true; - } - - this.logVerbosity = setup.logVerbosity || false; - this.suppressLeaveEvents = setup.suppressLeaveEvents || false; - - this.announceFailedHeartbeats = setup.announceFailedHeartbeats || true; - this.announceSuccessfulHeartbeats = setup.announceSuccessfulHeartbeats || false; - - this.useInstanceId = setup.useInstanceId || false; - this.useRequestId = setup.useRequestId || false; - - this.requestMessageCountThreshold = setup.requestMessageCountThreshold; - - if (setup.retryConfiguration) { - this._setRetryConfiguration(setup.retryConfiguration); - } - - // set timeout to how long a transaction request will wait for the server (default 15 seconds) - this.setTransactionTimeout(setup.transactionalRequestTimeout || 15 * 1000); - // set timeout to how long a subscribe event loop will run (default 310 seconds) - this.setSubscribeTimeout(setup.subscribeRequestTimeout || 310 * 1000); - // set config on beacon (https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon) usage - this.setSendBeaconConfig(setup.useSendBeacon || true); - // how long the SDK will report the client to be alive before issuing a timeout - if (setup.presenceTimeout) { - this.setPresenceTimeout(setup.presenceTimeout); - } else { - this._presenceTimeout = PRESENCE_TIMEOUT_DEFAULT; - } - - if (setup.heartbeatInterval != null) { - this.setHeartbeatInterval(setup.heartbeatInterval); - } - - if (typeof setup.userId === 'string') { - if (typeof setup.uuid === 'string') { - throw new Error('Only one of the following configuration options has to be provided: `uuid` or `userId`'); - } - - this.setUserId(setup.userId); - } else { - if (typeof setup.uuid !== 'string') { - throw new Error('One of the following configuration options has to be provided: `uuid` or `userId`'); - } - - this.setUUID(setup.uuid); - } - this.setCipherKey(setup.cipherKey, setup); - } - - // exposed setters - getAuthKey() { - return this.authKey; - } - - setAuthKey(val) { - this.authKey = val; - return this; - } - - setCipherKey(val, setup, modules) { - this.cipherKey = val; - if (this.cipherKey) { - this.cryptoModule = - setup.cryptoModule ?? setup.initCryptoModule({ cipherKey: this.cipherKey, useRandomIVs: this.useRandomIVs }); - if (modules) modules.cryptoModule = this.cryptoModule; - } - return this; - } - - getUUID() { - return this.UUID; - } - - setUUID(val) { - if (!val || typeof val !== 'string' || val.trim().length === 0) { - throw new Error('Missing uuid parameter. Provide a valid string uuid'); - } - this.UUID = val; - return this; - } - - getUserId() { - return this.UUID; - } - - setUserId(value) { - if (!value || typeof value !== 'string' || value.trim().length === 0) { - throw new Error('Missing or invalid userId parameter. Provide a valid string userId'); - } - - this.UUID = value; - return this; - } - - getFilterExpression() { - return this.filterExpression; - } - - setFilterExpression(val) { - this.filterExpression = val; - return this; - } - - getPresenceTimeout() { - return this._presenceTimeout; - } - - setPresenceTimeout(val) { - if (val >= PRESENCE_TIMEOUT_MINIMUM) { - this._presenceTimeout = val; - } else { - this._presenceTimeout = PRESENCE_TIMEOUT_MINIMUM; - - // eslint-disable-next-line no-console - console.log('WARNING: Presence timeout is less than the minimum. Using minimum value: ', this._presenceTimeout); - } - - this.setHeartbeatInterval(this._presenceTimeout / 2 - 1); - - return this; - } - - setProxy(proxy) { - this.proxy = proxy; - } - - getHeartbeatInterval() { - return this._heartbeatInterval; - } - - setHeartbeatInterval(val) { - this._heartbeatInterval = val; - return this; - } - - // deprecated setters. - getSubscribeTimeout() { - return this._subscribeRequestTimeout; - } - - setSubscribeTimeout(val) { - this._subscribeRequestTimeout = val; - return this; - } - - getTransactionTimeout() { - return this._transactionalRequestTimeout; - } - - setTransactionTimeout(val) { - this._transactionalRequestTimeout = val; - return this; - } - - isSendBeaconEnabled() { - return this._useSendBeacon; - } - - setSendBeaconConfig(val) { - this._useSendBeacon = val; - return this; - } - - getVersion() { - return '7.6.3'; - } - - _setRetryConfiguration(configuration) { - if (configuration.minimumdelay < 2) { - throw new Error('Minimum delay can not be set less than 2 seconds for retry'); - } - if (configuration.maximumDelay > 150) { - throw new Error('Maximum delay can not be set more than 150 seconds for retry'); - } - if (configuration.maximumDelay && maximumRetry > 6) { - throw new Error('Maximum retry for exponential retry policy can not be more than 6'); - } else if (configuration.maximumRetry > 10) { - throw new Error('Maximum retry for linear retry policy can not be more than 10'); - } - this.retryConfiguration = configuration; - } - - _addPnsdkSuffix(name, suffix) { - this._PNSDKSuffix[name] = suffix; - } - - _getPnsdkSuffix(separator) { - return Object.keys(this._PNSDKSuffix).reduce((result, key) => result + separator + this._PNSDKSuffix[key], ''); - } -} diff --git a/src/core/components/configuration.ts b/src/core/components/configuration.ts new file mode 100644 index 000000000..7bf76b8d6 --- /dev/null +++ b/src/core/components/configuration.ts @@ -0,0 +1,220 @@ +/** + * {@link PubNub} client configuration module. + */ + +import { ExtendedConfiguration, PlatformConfiguration, PrivateClientConfiguration } from '../interfaces/configuration'; +import { CryptoModule, CryptorConfiguration } from '../interfaces/crypto-module'; +import { PubNubFileConstructor, PubNubFileInterface } from '../types/file'; +import uuidGenerator from './uuid'; +import { Payload } from '../types/api'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Whether encryption (if set) should use random initialization vector or not. + */ +const USE_RANDOM_INITIALIZATION_VECTOR = true; +// endregion + +/** + * Crypto Module instance configuration function. + * + * Function will be used each time when `cipherKey` will be changed. + */ +type SetupCryptoModule = (configuration: CryptorConfiguration) => CryptoModule | undefined; + +/** + * Internal state of the {@link PrivateClientConfiguration} to store temporarily information. + */ +type PrivateConfigurationFields = { + /** + * Frameworks suffixes. + * + * Frameworks built atop of PubNub SDK can add key/value pairs which will be added to the + * `pnsdk` query parameter. + * @private + */ + _pnsdkSuffix: Record; + + /** + * Unique PubNub client instance identifier. + */ + _instanceId: string; + + /** + * Crypto Module configuration callback. + * + * Callback allow to setup Crypto Module in platform-independent way. + */ + _setupCryptoModule?: SetupCryptoModule; + + /** + * Configured crypto module. + */ + _cryptoModule?: CryptoModule; + + /** + * Currently used data encryption / decryption key. + */ + _cipherKey: string | undefined; +}; + +/** + * Create {@link PubNub} client private configuration object. + * + * @param base - User- and platform-provided configuration. + * @param setupCryptoModule - Platform-provided {@link CryptoModule} configuration block. + * + * @returns `PubNub` client private configuration. + */ +export const makeConfiguration = ( + base: ExtendedConfiguration & PlatformConfiguration, + setupCryptoModule?: SetupCryptoModule, +): PrivateClientConfiguration & PrivateConfigurationFields => { + // Ensure that retry policy has proper configuration (if has been set). + base.retryConfiguration?.validate(); + + base.useRandomIVs ??= USE_RANDOM_INITIALIZATION_VECTOR; + // Override origin value. + base.origin = standardOrigin(base.ssl ?? false, base.origin!); + + const cryptoModule = base.cryptoModule; + if (cryptoModule) delete base.cryptoModule; + + const clientConfiguration: PrivateClientConfiguration & PrivateConfigurationFields = { + ...base, + _pnsdkSuffix: {}, + _instanceId: `pn-${uuidGenerator.createUUID()}`, + _cryptoModule: undefined, + _cipherKey: undefined, + _setupCryptoModule: setupCryptoModule, + get instanceId(): string | undefined { + if (this.useInstanceId) return this._instanceId; + return undefined; + }, + getUserId() { + return this.userId!; + }, + setUserId(value: string) { + if (!value || typeof value !== 'string' || value.trim().length === 0) + throw new Error('Missing or invalid userId parameter. Provide a valid string userId'); + + this.userId = value; + }, + getAuthKey() { + return this.authKey; + }, + setAuthKey(authKey: string | null) { + this.authKey = authKey; + }, + getFilterExpression() { + return this.filterExpression; + }, + setFilterExpression(expression: string | null | undefined) { + this.filterExpression = expression; + }, + getCipherKey(): string | undefined { + return this._cipherKey; + }, + setCipherKey(key: string) { + this._cipherKey = key; + + if (!key && this._cryptoModule) { + this._cryptoModule = undefined; + return; + } else if (!key || !this._setupCryptoModule) return; + + this._cryptoModule = this._setupCryptoModule({ + cipherKey: key, + useRandomIVs: base.useRandomIVs, + customEncrypt: this.getCustomEncrypt(), + customDecrypt: this.getCustomDecrypt(), + }); + }, + getCryptoModule(): CryptoModule | undefined { + return this._cryptoModule; + }, + getUseRandomIVs(): boolean | undefined { + return base.useRandomIVs; + }, + setPresenceTimeout(value: number): void { + this.heartbeatInterval = value / 2 - 1; + this.presenceTimeout = value; + }, + getPresenceTimeout(): number { + return this.presenceTimeout!; + }, + getHeartbeatInterval(): number | undefined { + return this.heartbeatInterval; + }, + setHeartbeatInterval(interval: number) { + this.heartbeatInterval = interval; + }, + getTransactionTimeout(): number { + return this.transactionalRequestTimeout!; + }, + getSubscribeTimeout(): number { + return this.subscribeRequestTimeout!; + }, + get PubNubFile(): PubNubFileConstructor | undefined { + return base.PubNubFile; + }, + get version(): string { + return '8.0.0'; + }, + getVersion(): string { + return this.version; + }, + _addPnsdkSuffix(name: string, suffix: string | number) { + this._pnsdkSuffix[name] = `${suffix}`; + }, + _getPnsdkSuffix(separator: string): string { + const sdk = Object.values(this._pnsdkSuffix).join(separator); + return sdk.length > 0 ? separator + sdk : ''; + }, + + // -------------------------------------------------------- + // ---------------------- Deprecated ---------------------- + // -------------------------------------------------------- + // region Deprecated + + getUUID(): string { + return this.getUserId(); + }, + setUUID(value: string) { + this.setUserId(value); + }, + getCustomEncrypt(): ((data: string | Payload) => string) | undefined { + return base.customEncrypt; + }, + getCustomDecrypt(): ((data: string) => string) | undefined { + return base.customDecrypt; + }, + // endregion + }; + + // Setup `CryptoModule` if possible. + if (base.cipherKey) clientConfiguration.setCipherKey(base.cipherKey); + else if (cryptoModule) clientConfiguration._cryptoModule = cryptoModule; + + return clientConfiguration; +}; + +/** + * Decide {@lin PubNub} service REST API origin. + * + * @param secure - Whether preferred to use secured connection or not. + * @param origin - User-provided or default origin. + * + * @returns `PubNub` REST API endpoints origin. + */ +const standardOrigin = (secure: boolean, origin: string | string[]): string => { + const protocol = secure ? 'https://' : 'http://'; + + if (typeof origin === 'string') return `${protocol}${origin}`; + + return `${protocol}${origin[Math.floor(Math.random() * origin.length)]}`; +}; diff --git a/src/core/components/cryptography/index.js b/src/core/components/cryptography/index.js deleted file mode 100644 index 8d6b400e3..000000000 --- a/src/core/components/cryptography/index.js +++ /dev/null @@ -1,173 +0,0 @@ -import { decode } from '../base64_codec'; -import CryptoJS from './hmac-sha256'; - -function bufferToWordArray(b) { - const wa = []; - let i; - for (i = 0; i < b.length; i += 1) { - wa[(i / 4) | 0] |= b[i] << (24 - 8 * i); - } - - return CryptoJS.lib.WordArray.create(wa, b.length); -} - -export default class { - _config; - - _iv; - - _allowedKeyEncodings; - - _allowedKeyLengths; - - _allowedModes; - - _defaultOptions; - - constructor({ config }) { - this._config = config; - this._iv = '0123456789012345'; - - this._allowedKeyEncodings = ['hex', 'utf8', 'base64', 'binary']; - this._allowedKeyLengths = [128, 256]; - this._allowedModes = ['ecb', 'cbc']; - - this._defaultOptions = { - encryptKey: true, - keyEncoding: 'utf8', - keyLength: 256, - mode: 'cbc', - }; - } - - HMACSHA256(data) { - const hash = CryptoJS.HmacSHA256(data, this._config.secretKey); - return hash.toString(CryptoJS.enc.Base64); - } - - SHA256(s) { - return CryptoJS.SHA256(s).toString(CryptoJS.enc.Hex); - } - - _parseOptions(incomingOptions) { - // Defaults - const options = incomingOptions || {}; - if (!options.hasOwnProperty('encryptKey')) options.encryptKey = this._defaultOptions.encryptKey; - if (!options.hasOwnProperty('keyEncoding')) options.keyEncoding = this._defaultOptions.keyEncoding; - if (!options.hasOwnProperty('keyLength')) options.keyLength = this._defaultOptions.keyLength; - if (!options.hasOwnProperty('mode')) options.mode = this._defaultOptions.mode; - - // Validation - if (this._allowedKeyEncodings.indexOf(options.keyEncoding.toLowerCase()) === -1) { - options.keyEncoding = this._defaultOptions.keyEncoding; - } - - if (this._allowedKeyLengths.indexOf(parseInt(options.keyLength, 10)) === -1) { - options.keyLength = this._defaultOptions.keyLength; - } - - if (this._allowedModes.indexOf(options.mode.toLowerCase()) === -1) { - options.mode = this._defaultOptions.mode; - } - - return options; - } - - _decodeKey(key, options) { - if (options.keyEncoding === 'base64') { - return CryptoJS.enc.Base64.parse(key); - } - if (options.keyEncoding === 'hex') { - return CryptoJS.enc.Hex.parse(key); - } - return key; - } - - _getPaddedKey(key, options) { - key = this._decodeKey(key, options); - if (options.encryptKey) { - return CryptoJS.enc.Utf8.parse(this.SHA256(key).slice(0, 32)); - } - return key; - } - - _getMode(options) { - if (options.mode === 'ecb') { - return CryptoJS.mode.ECB; - } - return CryptoJS.mode.CBC; - } - - _getIV(options) { - return options.mode === 'cbc' ? CryptoJS.enc.Utf8.parse(this._iv) : null; - } - - _getRandomIV() { - return CryptoJS.lib.WordArray.random(16); - } - - encrypt(data, customCipherKey, options) { - if (this._config.customEncrypt) { - return this._config.customEncrypt(data); - } - return this.pnEncrypt(data, customCipherKey, options); - } - - decrypt(data, customCipherKey, options) { - if (this._config.customDecrypt) { - return this._config.customDecrypt(data); - } - return this.pnDecrypt(data, customCipherKey, options); - } - - pnEncrypt(data, customCipherKey, options) { - if (!customCipherKey && !this._config.cipherKey) return data; - options = this._parseOptions(options); - const mode = this._getMode(options); - const cipherKey = this._getPaddedKey(customCipherKey || this._config.cipherKey, options); - - if (this._config.useRandomIVs) { - const waIv = this._getRandomIV(); - const waPayload = CryptoJS.AES.encrypt(data, cipherKey, { iv: waIv, mode }).ciphertext; - - return waIv.clone().concat(waPayload.clone()).toString(CryptoJS.enc.Base64); - } - const iv = this._getIV(options); - const encryptedHexArray = CryptoJS.AES.encrypt(data, cipherKey, { iv, mode }).ciphertext; - const base64Encrypted = encryptedHexArray.toString(CryptoJS.enc.Base64); - return base64Encrypted || data; - } - - pnDecrypt(data, customCipherKey, options) { - if (!customCipherKey && !this._config.cipherKey) return data; - options = this._parseOptions(options); - const mode = this._getMode(options); - const cipherKey = this._getPaddedKey(customCipherKey || this._config.cipherKey, options); - if (this._config.useRandomIVs) { - const ciphertext = new Uint8ClampedArray(decode(data)); - - const iv = bufferToWordArray(ciphertext.slice(0, 16)); - const payload = bufferToWordArray(ciphertext.slice(16)); - - try { - const plainJSON = CryptoJS.AES.decrypt({ ciphertext: payload }, cipherKey, { iv, mode }).toString( - CryptoJS.enc.Utf8, - ); - const plaintext = JSON.parse(plainJSON); - return plaintext; - } catch (e) { - return null; - } - } else { - const iv = this._getIV(options); - try { - const ciphertext = CryptoJS.enc.Base64.parse(data); - const plainJSON = CryptoJS.AES.decrypt({ ciphertext }, cipherKey, { iv, mode }).toString(CryptoJS.enc.Utf8); - const plaintext = JSON.parse(plainJSON); - return plaintext; - } catch (e) { - return null; - } - } - } -} diff --git a/src/core/components/cryptography/index.ts b/src/core/components/cryptography/index.ts new file mode 100644 index 000000000..98215f205 --- /dev/null +++ b/src/core/components/cryptography/index.ts @@ -0,0 +1,309 @@ +/** + * Legacy cryptography module. + */ + +import { CryptorConfiguration } from '../../interfaces/crypto-module'; +import { Payload } from '../../types/api'; +import { decode } from '../base64_codec'; +import CryptoJS from './hmac-sha256'; + +/** + * Convert bytes array to words array. + * + * @param b - Bytes array (buffer) which should be converted. + * + * @returns Word sized array. + */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +function bufferToWordArray(b: string | any[] | Uint8ClampedArray) { + const wa: number[] = []; + let i; + for (i = 0; i < b.length; i += 1) { + wa[(i / 4) | 0] |= b[i] << (24 - 8 * i); + } + + // @ts-expect-error Bundled library without types. + return CryptoJS.lib.WordArray.create(wa, b.length); +} + +/** + * Legacy cryptor configuration options. + */ +type CryptoConfiguration = { + encryptKey?: boolean; + keyEncoding?: 'hex' | 'utf8' | 'base64' | 'binary'; + keyLength?: 128 | 256; + mode?: 'ecb' | 'cbc'; +}; + +export default class { + /** + * Crypto initialization vector. + */ + private iv = '0123456789012345'; + + /** + * List os allowed cipher key encodings. + */ + private allowedKeyEncodings = ['hex', 'utf8', 'base64', 'binary']; + + /** + * Allowed cipher key lengths. + */ + private allowedKeyLengths = [128, 256]; + + /** + * Allowed crypto modes. + */ + private allowedModes = ['ecb', 'cbc']; + + /** + * Default cryptor configuration options. + */ + private readonly defaultOptions: Required; + + constructor(private readonly configuration: CryptorConfiguration) { + this.defaultOptions = { + encryptKey: true, + keyEncoding: 'utf8', + keyLength: 256, + mode: 'cbc', + }; + } + + /** + * Generate HMAC-SHA256 hash from input data. + * + * @param data - Data from which hash should be generated. + * + * @returns HMAC-SHA256 hash from provided `data`. + */ + public HMACSHA256(data: string): string { + // @ts-expect-error Bundled library without types. + const hash = CryptoJS.HmacSHA256(data, this.configuration.secretKey); + // @ts-expect-error Bundled library without types. + return hash.toString(CryptoJS.enc.Base64); + } + + /** + * Generate SHA256 hash from input data. + * + * @param data - Data from which hash should be generated. + * + * @returns SHA256 hash from provided `data`. + */ + public SHA256(data: string): string { + // @ts-expect-error Bundled library without types. + return CryptoJS.SHA256(data).toString(CryptoJS.enc.Hex); + } + + /** + * Encrypt provided data. + * + * @param data - Source data which should be encrypted. + * @param [customCipherKey] - Custom cipher key (different from defined on client level). + * @param [options] - Specific crypto configuration options. + * + * @returns Encrypted `data`. + */ + public encrypt(data: string | Payload, customCipherKey?: string, options?: CryptoConfiguration) { + if (this.configuration.customEncrypt) return this.configuration.customEncrypt(data); + + return this.pnEncrypt(data as string, customCipherKey, options); + } + + /** + * Decrypt provided data. + * + * @param data - Encrypted data which should be decrypted. + * @param [customCipherKey] - Custom cipher key (different from defined on client level). + * @param [options] - Specific crypto configuration options. + * + * @returns Decrypted `data`. + */ + public decrypt(data: string, customCipherKey?: string, options?: CryptoConfiguration) { + if (this.configuration.customDecrypt) return this.configuration.customDecrypt(data); + + return this.pnDecrypt(data, customCipherKey, options); + } + + /** + * Encrypt provided data. + * + * @param data - Source data which should be encrypted. + * @param [customCipherKey] - Custom cipher key (different from defined on client level). + * @param [options] - Specific crypto configuration options. + * + * @returns Encrypted `data` as string. + */ + private pnEncrypt(data: string, customCipherKey?: string, options?: CryptoConfiguration): string { + const decidedCipherKey = customCipherKey ?? this.configuration.cipherKey; + if (!decidedCipherKey) return data; + + options = this.parseOptions(options); + const mode = this.getMode(options); + const cipherKey = this.getPaddedKey(decidedCipherKey, options); + + if (this.configuration.useRandomIVs) { + const waIv = this.getRandomIV(); + // @ts-expect-error Bundled library without types. + const waPayload = CryptoJS.AES.encrypt(data, cipherKey, { iv: waIv, mode }).ciphertext; + + // @ts-expect-error Bundled library without types. + return waIv.clone().concat(waPayload.clone()).toString(CryptoJS.enc.Base64); + } + + const iv = this.getIV(options); + // @ts-expect-error Bundled library without types. + const encryptedHexArray = CryptoJS.AES.encrypt(data, cipherKey, { iv, mode }).ciphertext; + // @ts-expect-error Bundled library without types. + const base64Encrypted = encryptedHexArray.toString(CryptoJS.enc.Base64); + + return base64Encrypted || data; + } + + /** + * Decrypt provided data. + * + * @param data - Encrypted data which should be decrypted. + * @param [customCipherKey] - Custom cipher key (different from defined on client level). + * @param [options] - Specific crypto configuration options. + * + * @returns Decrypted `data`. + */ + private pnDecrypt(data: string, customCipherKey?: string, options?: CryptoConfiguration): Payload | null { + const decidedCipherKey = customCipherKey ?? this.configuration.cipherKey; + if (!decidedCipherKey) return data; + + options = this.parseOptions(options); + const mode = this.getMode(options); + const cipherKey = this.getPaddedKey(decidedCipherKey, options); + + if (this.configuration.useRandomIVs) { + const ciphertext = new Uint8ClampedArray(decode(data)); + + const iv = bufferToWordArray(ciphertext.slice(0, 16)); + const payload = bufferToWordArray(ciphertext.slice(16)); + + try { + // @ts-expect-error Bundled library without types. + const plainJSON = CryptoJS.AES.decrypt({ ciphertext: payload }, cipherKey, { iv, mode }).toString( + // @ts-expect-error Bundled library without types. + CryptoJS.enc.Utf8, + ); + return JSON.parse(plainJSON); + } catch (e) { + return null; + } + } else { + const iv = this.getIV(options); + try { + // @ts-expect-error Bundled library without types. + const ciphertext = CryptoJS.enc.Base64.parse(data); + // @ts-expect-error Bundled library without types. + const plainJSON = CryptoJS.AES.decrypt({ ciphertext }, cipherKey, { iv, mode }).toString(CryptoJS.enc.Utf8); + return JSON.parse(plainJSON); + } catch (e) { + return null; + } + } + } + + /** + * Pre-process provided custom crypto configuration. + * + * @param incomingOptions - Configuration which should be pre-processed before use. + * + * @returns Normalized crypto configuration options. + */ + private parseOptions(incomingOptions?: CryptoConfiguration): Required { + if (!incomingOptions) return this.defaultOptions; + + // Defaults + const options = { + encryptKey: incomingOptions.encryptKey ?? this.defaultOptions.encryptKey, + keyEncoding: incomingOptions.keyEncoding ?? this.defaultOptions.keyEncoding, + keyLength: incomingOptions.keyLength ?? this.defaultOptions.keyLength, + mode: incomingOptions.mode ?? this.defaultOptions.mode, + }; + + // Validation + if (this.allowedKeyEncodings.indexOf(options.keyEncoding!.toLowerCase()) === -1) + options.keyEncoding = this.defaultOptions.keyEncoding; + if (this.allowedKeyLengths.indexOf(options.keyLength!) === -1) options.keyLength = this.defaultOptions.keyLength; + if (this.allowedModes.indexOf(options.mode!.toLowerCase()) === -1) options.mode = this.defaultOptions.mode; + + return options; + } + + /** + * Decode provided cipher key. + * + * @param key - Key in `encoding` provided by `options`. + * @param options - Crypto configuration options with cipher key details. + * + * @returns Array buffer with decoded key. + */ + private decodeKey(key: string, options: CryptoConfiguration) { + // @ts-expect-error Bundled library without types. + if (options.keyEncoding === 'base64') return CryptoJS.enc.Base64.parse(key); + // @ts-expect-error Bundled library without types. + if (options.keyEncoding === 'hex') return CryptoJS.enc.Hex.parse(key); + + return key; + } + + /** + * Add padding to the cipher key. + * + * @param key - Key which should be padded. + * @param options - Crypto configuration options with cipher key details. + * + * @returns Properly padded cipher key. + */ + private getPaddedKey(key: string, options: CryptoConfiguration) { + key = this.decodeKey(key, options); + + // @ts-expect-error Bundled library without types. + if (options.encryptKey) return CryptoJS.enc.Utf8.parse(this.SHA256(key).slice(0, 32)); + + return key; + } + + /** + * Cipher mode. + * + * @param options - Crypto configuration with information about cipher mode. + * + * @returns Crypto cipher mode. + */ + private getMode(options: CryptoConfiguration) { + // @ts-expect-error Bundled library without types. + if (options.mode === 'ecb') return CryptoJS.mode.ECB; + + // @ts-expect-error Bundled library without types. + return CryptoJS.mode.CBC; + } + + /** + * Cipher initialization vector. + * + * @param options - Crypto configuration with information about cipher mode. + * + * @returns Initialization vector. + */ + private getIV(options: CryptoConfiguration) { + // @ts-expect-error Bundled library without types. + return options.mode === 'cbc' ? CryptoJS.enc.Utf8.parse(this.iv) : null; + } + + /** + * Random initialization vector. + * + * @returns Generated random initialization vector. + */ + private getRandomIV() { + // @ts-expect-error Bundled library without types. + return CryptoJS.lib.WordArray.random(16); + } +} diff --git a/src/core/components/deduping_manager.js b/src/core/components/deduping_manager.js index 7ac8aa613..ab8aa9607 100644 --- a/src/core/components/deduping_manager.js +++ b/src/core/components/deduping_manager.js @@ -1,7 +1,5 @@ /* */ -import Config from './config'; - const hashCode = (payload) => { let hash = 0; if (payload.length === 0) return hash; @@ -24,8 +22,8 @@ export default class { } getKey(message) { - const hashedPayload = hashCode(JSON.stringify(message.payload)).toString(); - const timetoken = message.publishMetaData.publishTimetoken; + const hashedPayload = hashCode(JSON.stringify(message.message)).toString(); + const timetoken = message.timetoken; return `${timetoken}-${hashedPayload}`; } diff --git a/src/core/components/endpoint.js b/src/core/components/endpoint.js deleted file mode 100644 index 0cce04a57..000000000 --- a/src/core/components/endpoint.js +++ /dev/null @@ -1,280 +0,0 @@ -import uuidGenerator from './uuid'; -import utils from '../utils'; -import operationConstants from '../constants/operations'; -import categoryConstants from '../constants/categories'; - -export class PubNubError extends Error { - constructor(message, status) { - super(message); - this.name = this.constructor.name; - this.status = status; - this.message = message; - - Object.setPrototypeOf(this, new.target.prototype); - } -} - -function createError(errorPayload, type) { - errorPayload.type = type; - errorPayload.error = true; - return errorPayload; -} - -export function createValidationError(message) { - return createError({ message }, 'validationError'); -} - -function decideURL(endpoint, modules, incomingParams) { - if (endpoint.usePost && endpoint.usePost(modules, incomingParams)) { - return endpoint.postURL(modules, incomingParams); - } - if (endpoint.usePatch && endpoint.usePatch(modules, incomingParams)) { - return endpoint.patchURL(modules, incomingParams); - } - if (endpoint.useGetFile && endpoint.useGetFile(modules, incomingParams)) { - return endpoint.getFileURL(modules, incomingParams); - } - return endpoint.getURL(modules, incomingParams); -} - -export function generatePNSDK(config) { - if (config.sdkName) { - return config.sdkName; - } - - let base = `PubNub-JS-${config.sdkFamily}`; - - if (config.partnerId) { - base += `-${config.partnerId}`; - } - - base += `/${config.getVersion()}`; - - const pnsdkSuffix = config._getPnsdkSuffix(' '); - - if (pnsdkSuffix.length > 0) { - base += pnsdkSuffix; - } - - return base; -} - -function getHttpMethod(modules, endpoint, incomingParams) { - if (endpoint.usePost && endpoint.usePost(modules, incomingParams)) { - return 'POST'; - } - if (endpoint.usePatch && endpoint.usePatch(modules, incomingParams)) { - return 'PATCH'; - } - if (endpoint.useDelete && endpoint.useDelete(modules, incomingParams)) { - return 'DELETE'; - } - if (endpoint.useGetFile && endpoint.useGetFile(modules, incomingParams)) { - return 'GETFILE'; - } - return 'GET'; -} - -export function signRequest(modules, url, outgoingParams, incomingParams, endpoint) { - const { config, crypto } = modules; - - let httpMethod = getHttpMethod(modules, endpoint, incomingParams); - - outgoingParams.timestamp = Math.floor(new Date().getTime() / 1000); - - // This is because of a server-side bug, old publish using post should be deprecated - if ( - endpoint.getOperation() === 'PNPublishOperation' && - endpoint.usePost && - endpoint.usePost(modules, incomingParams) - ) { - httpMethod = 'GET'; - } - - if (httpMethod === 'GETFILE') { - httpMethod = 'GET'; - } - - let signInput = `${httpMethod}\n${config.publishKey}\n${url}\n${utils.signPamFromParams(outgoingParams)}\n`; - - if (httpMethod === 'POST') { - const payload = endpoint.postPayload(modules, incomingParams); - if (typeof payload === 'string') { - signInput += payload; - } else { - signInput += JSON.stringify(payload); - } - } else if (httpMethod === 'PATCH') { - const payload = endpoint.patchPayload(modules, incomingParams); - if (typeof payload === 'string') { - signInput += payload; - } else { - signInput += JSON.stringify(payload); - } - } - - let signature = `v2.${crypto.HMACSHA256(signInput)}`; - signature = signature.replace(/\+/g, '-'); - signature = signature.replace(/\//g, '_'); - signature = signature.replace(/=+$/, ''); - - outgoingParams.signature = signature; -} - -export default function (modules, endpoint, ...args) { - const { networking, config, telemetryManager, tokenManager } = modules; - const requestId = uuidGenerator.createUUID(); - let callback = null; - let promiseComponent = null; - let incomingParams = {}; - - if ( - endpoint.getOperation() === operationConstants.PNTimeOperation || - endpoint.getOperation() === operationConstants.PNChannelGroupsOperation - ) { - callback = args[0]; - } else { - incomingParams = args[0]; - callback = args[1]; - } - - // bridge in Promise support. - if (typeof Promise !== 'undefined' && !callback) { - promiseComponent = utils.createPromise(); - } - - const validationResult = endpoint.validateParams(modules, incomingParams); - - if (validationResult) { - if (callback) { - return callback(createValidationError(validationResult)); - } - if (promiseComponent) { - promiseComponent.reject( - new PubNubError('Validation failed, check status for details', createValidationError(validationResult)), - ); - return promiseComponent.promise; - } - return; - } - - let outgoingParams = endpoint.prepareParams(modules, incomingParams); - const url = decideURL(endpoint, modules, incomingParams); - let callInstance; - const networkingParams = { - url, - operation: endpoint.getOperation(), - timeout: endpoint.getRequestTimeout(modules), - headers: endpoint.getRequestHeaders ? endpoint.getRequestHeaders() : {}, - ignoreBody: typeof endpoint.ignoreBody === 'function' ? endpoint.ignoreBody(modules) : false, - forceBuffered: - typeof endpoint.forceBuffered === 'function' ? endpoint.forceBuffered(modules, incomingParams) : null, - abortSignal: - typeof endpoint.getAbortSignal === 'function' ? endpoint.getAbortSignal(modules, incomingParams) : null, - }; - - outgoingParams.uuid = config.UUID; - outgoingParams.pnsdk = generatePNSDK(config); - - // Add telemetry information (if there is any available). - const telemetryLatencies = telemetryManager.operationsLatencyForRequest(); - if (Object.keys(telemetryLatencies).length) { - outgoingParams = { ...outgoingParams, ...telemetryLatencies }; - } - - if (config.useInstanceId) { - outgoingParams.instanceid = config.instanceId; - } - - if (config.useRequestId) { - outgoingParams.requestid = requestId; - } - - if (endpoint.isAuthSupported()) { - const tokenOrKey = tokenManager.getToken() || config.getAuthKey(); - - if (tokenOrKey) { - outgoingParams.auth = tokenOrKey; - } - } - - if (config.secretKey) { - signRequest(modules, url, outgoingParams, incomingParams, endpoint); - } - - const onResponse = (status, payload) => { - if (status.error) { - if (endpoint.handleError) { - endpoint.handleError(modules, incomingParams, status); - } - if (callback) { - callback(status); - } else if (promiseComponent) { - promiseComponent.reject(new PubNubError('PubNub call failed, check status for details', status)); - } - return; - } - - // Stop endpoint latency tracking. - telemetryManager.stopLatencyMeasure(endpoint.getOperation(), requestId); - - let responseP = endpoint.handleResponse(modules, payload, incomingParams); - - if (typeof responseP?.then !== 'function') { - responseP = Promise.resolve(responseP); - } - - responseP - .then((result) => { - if (callback) { - callback(status, result); - } else if (promiseComponent) { - promiseComponent.fulfill(result); - } - }) - .catch((e) => { - if (callback) { - let errorData = e; - - if (endpoint.getOperation() === operationConstants.PNSubscribeOperation) { - errorData = { - statusCode: 400, - error: true, - operation: endpoint.getOperation(), - errorData: e, - category: categoryConstants.PNUnknownCategory, - }; - } - - callback(errorData, null); - } else if (promiseComponent) { - promiseComponent.reject(new PubNubError('PubNub call failed, check status for details', e)); - } - }); - }; - - // Start endpoint latency tracking. - telemetryManager.startLatencyMeasure(endpoint.getOperation(), requestId); - - if (getHttpMethod(modules, endpoint, incomingParams) === 'POST') { - const payload = endpoint.postPayload(modules, incomingParams); - callInstance = networking.POST(outgoingParams, payload, networkingParams, onResponse); - } else if (getHttpMethod(modules, endpoint, incomingParams) === 'PATCH') { - const payload = endpoint.patchPayload(modules, incomingParams); - callInstance = networking.PATCH(outgoingParams, payload, networkingParams, onResponse); - } else if (getHttpMethod(modules, endpoint, incomingParams) === 'DELETE') { - callInstance = networking.DELETE(outgoingParams, networkingParams, onResponse); - } else if (getHttpMethod(modules, endpoint, incomingParams) === 'GETFILE') { - callInstance = networking.GETFILE(outgoingParams, networkingParams, onResponse); - } else { - callInstance = networking.GET(outgoingParams, networkingParams, onResponse); - } - - if (endpoint.getOperation() === operationConstants.PNSubscribeOperation) { - return callInstance; - } - - if (promiseComponent) { - return promiseComponent.promise; - } -} diff --git a/src/core/components/eventEmitter.js b/src/core/components/eventEmitter.js deleted file mode 100644 index 6dde752b8..000000000 --- a/src/core/components/eventEmitter.js +++ /dev/null @@ -1,289 +0,0 @@ -export default class EventEmitter { - modules; - listenerManager; - getFileUrl; - - _channelListenerMap; - _groupListenerMap; - _decoder; - constructor({ modules, listenerManager, getFileUrl }) { - this.modules = modules; - this.listenerManager = listenerManager; - this.getFileUrl = getFileUrl; - this._channelListenerMap = new Map(); - this._groupListenerMap = new Map(); - if (modules.cryptoModule) this._decoder = new TextDecoder(); - } - emitEvent(e) { - const { channel, publishMetaData } = e; - let { subscriptionMatch } = e; - if (channel === subscriptionMatch) { - subscriptionMatch = null; - } - - if (e.channel.endsWith('-pnpres')) { - const announce = {}; - announce.channel = null; - announce.subscription = null; - - if (channel) { - announce.channel = channel.substring(0, channel.lastIndexOf('-pnpres')); - } - - if (subscriptionMatch) { - announce.subscription = subscriptionMatch.substring(0, subscriptionMatch.lastIndexOf('-pnpres')); - } - - announce.action = e.payload.action; - announce.state = e.payload.data; - announce.timetoken = publishMetaData.timetoken; - announce.occupancy = e.payload.occupancy; - announce.uuid = e.payload.uuid; - announce.timestamp = e.payload.timestamp; - - if (e.payload.join) { - announce.join = e.payload.join; - } - - if (e.payload.leave) { - announce.leave = e.payload.leave; - } - - if (e.payload.timeout) { - announce.timeout = e.payload.timeout; - } - // deprecated --> - announce.actualChannel = subscriptionMatch != null ? channel : null; - announce.subscribedChannel = subscriptionMatch != null ? subscriptionMatch : channel; - // <-- deprecated - - this.listenerManager.announcePresence(announce); - this._announce('presence', announce, announce.channel, announce.subscription); - } else if (e.messageType === 1) { - const announce = {}; - announce.channel = null; - announce.subscription = null; - - announce.channel = channel; - announce.subscription = subscriptionMatch; - announce.timetoken = publishMetaData.timetoken; - announce.publisher = e.issuingClientId; - if (e.userMetadata) { - announce.userMetadata = e.userMetadata; - } - - announce.message = e.payload; - - this.listenerManager.announceSignal(announce); - this._announce('signal', announce, announce.channel, announce.subscription); - } else if (e.messageType === 2) { - const announce = {}; - announce.channel = null; - announce.subscription = null; - announce.channel = channel; - announce.subscription = subscriptionMatch; - announce.timetoken = publishMetaData.timetoken; - announce.publisher = e.issuingClientId; - if (e.userMetadata) { - announce.userMetadata = e.userMetadata; - } - announce.message = { - event: e.payload.event, - type: e.payload.type, - data: e.payload.data, - }; - this.listenerManager.announceObjects(announce); - this._announce('objects', announce, announce.channel, announce.subscription); - if (e.payload.type === 'uuid') { - const eventData = this._renameChannelField(announce); - const userEvent = { - ...eventData, - message: { - ...eventData.message, - event: this._renameEvent(eventData.message.event), - type: 'user', - }, - }; - this.listenerManager.announceUser(userEvent); - this._announce('user', userEvent, announce.channel, announce.subscription); - } else if (e.payload.type === 'channel') { - const eventData = this._renameChannelField(announce); - const spaceEvent = { - ...eventData, - message: { - ...eventData.message, - event: this._renameEvent(eventData.message.event), - type: 'space', - }, - }; - this.listenerManager.announceSpace(spaceEvent); - this._announce('space', spaceEvent, announce.channel, announce.subscription); - } else if (e.payload.type === 'membership') { - const eventData = this._renameChannelField(announce); - const { uuid: user, channel: space, ...membershipData } = eventData.message.data; - membershipData.user = user; - membershipData.space = space; - const membershipEvent = { - ...eventData, - message: { - ...eventData.message, - event: this._renameEvent(eventData.message.event), - data: membershipData, - }, - }; - this.listenerManager.announceMembership(membershipEvent); - this._announce('membership', membershipEvent, announce.channel, announce.subscription); - } - } else if (e.messageType === 3) { - const announce = {}; - announce.channel = channel; - announce.subscription = subscriptionMatch; - announce.timetoken = publishMetaData.timetoken; - announce.publisher = e.issuingClientId; - announce.data = { - messageTimetoken: e.payload.data.messageTimetoken, - actionTimetoken: e.payload.data.actionTimetoken, - type: e.payload.data.type, - uuid: e.issuingClientId, - value: e.payload.data.value, - }; - announce.event = e.payload.event; - this.listenerManager.announceMessageAction(announce); - this._announce('messageAction', announce, announce.channel, announce.subscription); - } else if (e.messageType === 4) { - const announce = {}; - announce.channel = channel; - announce.subscription = subscriptionMatch; - announce.timetoken = publishMetaData.timetoken; - announce.publisher = e.issuingClientId; - - let msgPayload = e.payload; - - if (this.modules.cryptoModule) { - let decryptedPayload; - try { - const decryptedData = this.modules.cryptoModule.decrypt(e.payload); - decryptedPayload = - decryptedData instanceof ArrayBuffer ? JSON.parse(this._decoder.decode(decryptedData)) : decryptedData; - } catch (e) { - decryptedPayload = null; - announce.error = `Error while decrypting message content: ${e.message}`; - } - if (decryptedPayload !== null) { - msgPayload = decryptedPayload; - } - } - - if (e.userMetadata) { - announce.userMetadata = e.userMetadata; - } - - announce.message = msgPayload.message; - - announce.file = { - id: msgPayload.file.id, - name: msgPayload.file.name, - url: this.getFileUrl({ - id: msgPayload.file.id, - name: msgPayload.file.name, - channel, - }), - }; - - this.listenerManager.announceFile(announce); - this._announce('file', announce, announce.channel, announce.subscription); - } else { - const announce = {}; - announce.channel = null; - announce.subscription = null; - - announce.channel = channel; - announce.subscription = subscriptionMatch; - announce.timetoken = publishMetaData.timetoken; - announce.publisher = e.issuingClientId; - - if (e.userMetadata) { - announce.userMetadata = e.userMetadata; - } - - if (this.modules.cryptoModule) { - let decryptedPayload; - try { - const decryptedData = this.modules.cryptoModule.decrypt(e.payload); - decryptedPayload = - decryptedData instanceof ArrayBuffer ? JSON.parse(this._decoder.decode(decryptedData)) : decryptedData; - } catch (e) { - decryptedPayload = null; - announce.error = `Error while decrypting message content: ${e.message}`; - } - if (decryptedPayload != null) { - announce.message = decryptedPayload; - } else { - announce.message = e.payload; - } - } else { - announce.message = e.payload; - } - // deprecated --> - announce.actualChannel = subscriptionMatch != null ? channel : null; - announce.subscribedChannel = subscriptionMatch != null ? subscriptionMatch : channel; - // <-- deprecated - - this.listenerManager.announceMessage(announce); - this._announce('message', announce, announce.channel, announce.subscription); - } - } - - addListener(l, channels, groups) { - if (!(channels && groups)) { - this.listenerManager.addListener(l); - } else { - channels?.forEach((c) => { - if (this._channelListenerMap[c]) { - if (!this._channelListenerMap[c].includes(l)) this._channelListenerMap[c].push(l); - } else { - this._channelListenerMap[c] = [l]; - } - }); - groups?.forEach((g) => { - if (this._groupListenerMap[g]) { - if (!this._groupListenerMap[g].includes(l)) this._groupListenerMap[g].push(l); - } else { - this._groupListenerMap[g] = [l]; - } - }); - } - } - - removeListener(listener, channels, groups) { - if (!(channels && groups)) { - this.listenerManager.removeListener(listener); - } else { - channels?.forEach((c) => { - this._channelListenerMap[c] = this._channelListenerMap[c]?.filter((l) => l !== listener); - }); - groups?.forEach((g) => { - this._groupListenerMap[g] = this._groupListenerMap[g]?.filter((l) => l !== listener); - }); - } - } - - removeAllListeners() { - this.listenerManager.removeAllListeners(); - } - - _renameEvent(e) { - return e === 'set' ? 'updated' : 'removed'; - } - - _renameChannelField(announce) { - const { channel, ...eventData } = announce; - eventData.spaceId = channel; - return eventData; - } - - _announce(type, event, channel, group) { - this._channelListenerMap[channel]?.forEach((l) => l[type] && l[type](event)); - this._groupListenerMap[group]?.forEach((l) => l[type] && l[type](event)); - } -} diff --git a/src/core/components/eventEmitter.ts b/src/core/components/eventEmitter.ts new file mode 100644 index 000000000..7f10d3112 --- /dev/null +++ b/src/core/components/eventEmitter.ts @@ -0,0 +1,197 @@ +import { Listener, ListenerManager } from './listener_manager'; +import * as Subscription from '../types/api/subscription'; +import { PubNubEventType } from '../endpoints/subscribe'; + +export default class EventEmitter { + /** + * Map of channels to listener callbacks for them. + */ + private readonly channelListenerMap: Map = new Map(); + + /** + * Map of channel group names to the listener callbacks for them. + */ + private readonly groupListenerMap: Map = new Map(); + + constructor(private readonly listenerManager: ListenerManager) {} + + /** + * Emit specific real-time event. + * + * Proper listener will be notified basing on event `type`. + * + * @param event - Received real-time event. + */ + emitEvent(event: Subscription.SubscriptionResponse['messages'][number]) { + if (event.type === PubNubEventType.Message) { + this.listenerManager.announceMessage(event.data); + this.announce('message', event.data, event.data.channel, event.data.subscription); + } else if (event.type === PubNubEventType.Signal) { + this.listenerManager.announceSignal(event.data); + this.announce('signal', event.data, event.data.channel, event.data.subscription); + } else if (event.type === PubNubEventType.Presence) { + this.listenerManager.announcePresence(event.data); + this.announce('presence', event.data, event.data.channel, event.data.subscription); + } else if (event.type === PubNubEventType.AppContext) { + const { data: objectEvent } = event; + const { message: object } = objectEvent; + this.listenerManager.announceObjects(objectEvent); + this.announce('objects', objectEvent, objectEvent.channel, objectEvent.subscription); + + if (object.type === 'uuid') { + const { message, channel, ...restEvent } = objectEvent; + const { event, type, ...restObject } = object; + const userEvent: Subscription.UserAppContextObject = { + ...restEvent, + spaceId: channel, + message: { + ...restObject, + event: event === 'set' ? 'updated' : 'removed', + type: 'user', + }, + }; + + this.listenerManager.announceUser(userEvent); + this.announce('user', userEvent, userEvent.spaceId, userEvent.subscription); + } else if (object.type === 'channel') { + const { message, channel, ...restEvent } = objectEvent; + const { event, type, ...restObject } = object; + const spaceEvent: Subscription.SpaceAppContextObject = { + ...restEvent, + spaceId: channel, + message: { + ...restObject, + event: event === 'set' ? 'updated' : 'removed', + type: 'space', + }, + }; + + this.listenerManager.announceSpace(spaceEvent); + this.announce('space', spaceEvent, spaceEvent.spaceId, spaceEvent.subscription); + } else if (object.type === 'membership') { + const { message, channel, ...restEvent } = objectEvent; + const { event, data, ...restObject } = object; + const { uuid, channel: channelMeta, ...restData } = data; + const membershipEvent: Subscription.VSPMembershipAppContextObject = { + ...restEvent, + spaceId: channel, + message: { + ...restObject, + event: event === 'set' ? 'updated' : 'removed', + data: { + ...restData, + user: uuid, + space: channelMeta, + }, + }, + }; + + this.listenerManager.announceMembership(membershipEvent); + this.announce('membership', membershipEvent, membershipEvent.spaceId, membershipEvent.subscription); + } + } else if (event.type === PubNubEventType.MessageAction) { + this.listenerManager.announceMessageAction(event.data); + this.announce('messageAction', event.data, event.data.channel, event.data.subscription); + } else if (event.type === PubNubEventType.Files) { + this.listenerManager.announceFile(event.data); + this.announce('file', event.data, event.data.channel, event.data.subscription); + } + } + + /** + * Register real-time event listener for specific channels and groups. + * + * @param listener - Listener with event callbacks to handle different types of events. + * @param channels - List of channels for which listener should be registered. + * @param groups - List of channel groups for which listener should be registered. + */ + public addListener(listener: Listener, channels?: string[], groups?: string[]) { + // Register event-listener listener globally. + if (!(channels && groups)) { + this.listenerManager.addListener(listener); + } else { + channels?.forEach((channel) => { + if (this.channelListenerMap.has(channel)) { + const channelListeners = this.channelListenerMap.get(channel)!; + if (!channelListeners.includes(listener)) channelListeners.push(listener); + } else this.channelListenerMap.set(channel, [listener]); + }); + + groups?.forEach((group) => { + if (this.groupListenerMap.has(group)) { + const groupListeners = this.groupListenerMap.get(group)!; + if (!groupListeners.includes(listener)) groupListeners.push(listener); + } else this.groupListenerMap.set(group, [listener]); + }); + } + } + + /** + * Remove real-time event listener. + * + * @param listener - Event listeners which should be removed. + * @param channels - List of channels for which listener should be removed. + * @param groups - List of channel groups for which listener should be removed. + */ + public removeListener(listener: Listener, channels?: string[], groups?: string[]) { + if (!(channels && groups)) { + this.listenerManager.removeListener(listener); + } else { + channels?.forEach((channel) => { + if (this.channelListenerMap.has(channel)) { + this.channelListenerMap.set( + channel, + this.channelListenerMap.get(channel)!.filter((channelListener) => channelListener !== listener), + ); + } + }); + + groups?.forEach((group) => { + if (this.groupListenerMap.has(group)) { + this.groupListenerMap.set( + group, + this.groupListenerMap.get(group)!.filter((groupListener) => groupListener !== listener), + ); + } + }); + } + } + + /** + * Clear all real-time event listeners. + */ + public removeAllListeners() { + this.listenerManager.removeAllListeners(); + this.channelListenerMap.clear(); + this.groupListenerMap.clear(); + } + + /** + * Announce real-time event to all listeners. + * + * @param type - Type of event which should be announced. + * @param event - Announced real-time event payload. + * @param channel - Name of the channel for which registered listeners should be notified. + * @param group - Name of the channel group for which registered listeners should be notified. + */ + private announce( + type: T, + event: Listener[T] extends ((arg: infer P) => void) | undefined ? P : never, + channel: string, + group?: string | null, + ) { + if (event && this.channelListenerMap.has(channel)) + this.channelListenerMap.get(channel)!.forEach((listener) => { + const typedListener = listener[type]; + // @ts-expect-error Dynamic events mapping. + if (typedListener) typedListener(event); + }); + + if (group && this.groupListenerMap.has(group)) + this.groupListenerMap.get(group)!.forEach((listener) => { + const typedListener = listener[type]; + // @ts-expect-error Dynamic events mapping. + if (typedListener) typedListener(event); + }); + } +} diff --git a/src/core/components/listener_manager.js b/src/core/components/listener_manager.js deleted file mode 100644 index fb41c1f2d..000000000 --- a/src/core/components/listener_manager.js +++ /dev/null @@ -1,102 +0,0 @@ -import categoryConstants from '../constants/categories'; - -export default class { - _listeners; - - constructor() { - this._listeners = []; - } - - addListener(newListener) { - if (this._listeners.includes(newListener)) { - return; - } - this._listeners.push(newListener); - } - - removeListener(deprecatedListener) { - const newListeners = []; - - this._listeners.forEach((listener) => { - if (listener !== deprecatedListener) newListeners.push(listener); - }); - - this._listeners = newListeners; - } - - removeAllListeners() { - this._listeners = []; - } - - announcePresence(announce) { - this._listeners.forEach((listener) => { - if (listener.presence) listener.presence(announce); - }); - } - - announceStatus(announce) { - this._listeners.forEach((listener) => { - if (listener.status) listener.status(announce); - }); - } - - announceMessage(announce) { - this._listeners.forEach((listener) => { - if (listener.message) listener.message(announce); - }); - } - - announceSignal(announce) { - this._listeners.forEach((listener) => { - if (listener.signal) listener.signal(announce); - }); - } - - announceMessageAction(announce) { - this._listeners.forEach((listener) => { - if (listener.messageAction) listener.messageAction(announce); - }); - } - - announceFile(announce) { - this._listeners.forEach((listener) => { - if (listener.file) listener.file(announce); - }); - } - - announceObjects(announce) { - this._listeners.forEach((listener) => { - if (listener.objects) listener.objects(announce); - }); - } - - announceUser(announce) { - this._listeners.forEach((listener) => { - if (listener.user) listener.user(announce); - }); - } - - announceSpace(announce) { - this._listeners.forEach((listener) => { - if (listener.space) listener.space(announce); - }); - } - - announceMembership(announce) { - this._listeners.forEach((listener) => { - if (listener.membership) listener.membership(announce); - }); - } - - announceNetworkUp() { - const networkStatus = {}; - networkStatus.category = categoryConstants.PNNetworkUpCategory; - this.announceStatus(networkStatus); - } - - announceNetworkDown() { - const networkStatus = {}; - networkStatus.category = categoryConstants.PNNetworkDownCategory; - this.announceStatus(networkStatus); - } -} diff --git a/src/core/components/listener_manager.ts b/src/core/components/listener_manager.ts new file mode 100644 index 000000000..49e4c47d5 --- /dev/null +++ b/src/core/components/listener_manager.ts @@ -0,0 +1,279 @@ +/** + * Events listener manager module. + */ + +import * as Subscription from '../types/api/subscription'; +import StatusCategory from '../constants/categories'; +import { Status, StatusEvent } from '../types/api'; + +/** + * Real-time events listener. + */ +export type Listener = { + /** + * Real-time message events listener. + * + * @param message - Received message. + */ + message?: (message: Subscription.Message) => void; + + /** + * Real-time message signal listener. + * + * @param signal - Received signal. + */ + signal?: (signal: Subscription.Signal) => void; + + /** + * Real-time presence change events listener. + * + * @param presence - Received presence chane information. + */ + presence?: (presence: Subscription.Presence) => void; + + /** + * Real-time App Context Objects change events listener. + * + * @param object - Changed App Context Object information. + */ + objects?: (object: Subscription.AppContextObject) => void; + + /** + * Real-time message actions events listener. + * + * @param action - Message action information. + */ + messageAction?: (action: Subscription.MessageAction) => void; + + /** + * Real-time file share events listener. + * + * @param file - Shared file information. + */ + file?: (file: Subscription.File) => void; + + /** + * Real-time PubNub client status change event. + * + * @param status - PubNub client status information + */ + status?: (status: Status | StatusEvent) => void; + + // -------------------------------------------------------- + // ---------------------- Deprecated ---------------------- + // -------------------------------------------------------- + // region Deprecated + + /** + * Real-time User App Context Objects change events listener. + * + * @param user - User App Context Object information. + * + * @deprecated Use {@link objects} listener callback instead. + */ + user?: (user: Subscription.UserAppContextObject) => void; + + /** + * Real-time Space App Context Objects change events listener. + * + * @param space - Space App Context Object information. + * + * @deprecated Use {@link objects} listener callback instead. + */ + space?: (space: Subscription.SpaceAppContextObject) => void; + + /** + * Real-time VSP Membership App Context Objects change events listener. + * + * @param membership - VSP Membership App Context Object information. + * + * @deprecated Use {@link objects} listener callback instead. + */ + membership?: (membership: Subscription.VSPMembershipAppContextObject) => void; + // endregion +}; + +/** + * Real-time listeners' manager. + */ +export class ListenerManager { + /** + * List of registered event listeners. + */ + private listeners: Listener[] = []; + + /** + * Register new real-time events listener. + * + * @param listener - Listener with event callbacks to handle different types of events. + */ + public addListener(listener: Listener) { + if (this.listeners.includes(listener)) return; + + this.listeners.push(listener); + } + + /** + * Remove real-time event listener. + * + * @param listener - Event listeners which should be removed. + */ + public removeListener(listener: Listener) { + this.listeners = this.listeners.filter((storedListener) => storedListener !== listener); + } + + /** + * Clear all real-time event listeners. + */ + public removeAllListeners() { + this.listeners = []; + } + + /** + * Announce PubNub client status change event. + * + * @param status - PubNub client status. + */ + public announceStatus(status: Status | StatusEvent) { + this.listeners.forEach((listener) => { + if (listener.status) listener.status(status); + }); + } + + /** + * Announce channel presence change event. + * + * @param presence - Channel presence change information. + */ + public announcePresence(presence: Subscription.Presence) { + this.listeners.forEach((listener) => { + if (listener.presence) listener.presence(presence); + }); + } + + /** + * Announce real-time message event. + * + * @param message - Received real-time message. + */ + public announceMessage(message: Subscription.Message) { + this.listeners.forEach((listener) => { + if (listener.message) listener.message(message); + }); + } + + /** + * Announce real-time signal event. + * + * @param signal - Received real-time signal. + */ + public announceSignal(signal: Subscription.Signal) { + this.listeners.forEach((listener) => { + if (listener.signal) listener.signal(signal); + }); + } + + /** + * Announce message actions change event. + * + * @param messageAction - Message action change information. + */ + public announceMessageAction(messageAction: Subscription.MessageAction) { + this.listeners.forEach((listener) => { + if (listener.messageAction) listener.messageAction(messageAction); + }); + } + + /** + * Announce fie share event. + * + * @param file - Shared file information. + */ + public announceFile(file: Subscription.File) { + this.listeners.forEach((listener) => { + if (listener.file) listener.file(file); + }); + } + + /** + * Announce App Context Object change event. + * + * @param object - App Context change information. + */ + public announceObjects(object: Subscription.AppContextObject) { + this.listeners.forEach((listener) => { + if (listener.objects) listener.objects(object); + }); + } + + /** + * Announce network up status. + */ + public announceNetworkUp() { + this.listeners.forEach((listener) => { + if (listener.status) { + listener.status({ + category: StatusCategory.PNNetworkUpCategory, + }); + } + }); + } + + /** + * Announce network down status. + */ + public announceNetworkDown() { + this.listeners.forEach((listener) => { + if (listener.status) { + listener.status({ + category: StatusCategory.PNNetworkDownCategory, + }); + } + }); + } + + // -------------------------------------------------------- + // ---------------------- Deprecated ---------------------- + // -------------------------------------------------------- + // region Deprecated + + /** + * Announce User App Context Object change event. + * + * @param user - User App Context change information. + * + * @deprecated Use {@link announceObjects} method instead. + */ + public announceUser(user: Subscription.UserAppContextObject) { + this.listeners.forEach((listener) => { + if (listener.user) listener.user(user); + }); + } + + /** + * Announce Space App Context Object change event. + * + * @param space - Space App Context change information. + * + * @deprecated Use {@link announceObjects} method instead. + */ + public announceSpace(space: Subscription.SpaceAppContextObject) { + this.listeners.forEach((listener) => { + if (listener.space) listener.space(space); + }); + } + + /** + * Announce VSP Membership App Context Object change event. + * + * @param membership - VSP Membership App Context change information. + * + * @deprecated Use {@link announceObjects} method instead. + */ + public announceMembership(membership: Subscription.VSPMembershipAppContextObject) { + this.listeners.forEach((listener) => { + if (listener.membership) listener.membership(membership); + }); + } + // endregion +} diff --git a/src/core/components/push_payload.js b/src/core/components/push_payload.js deleted file mode 100644 index c9ab4fc85..000000000 --- a/src/core/components/push_payload.js +++ /dev/null @@ -1,545 +0,0 @@ -/* */ -/* eslint max-classes-per-file: ["error", 5] */ - -class BaseNotificationPayload { - _subtitle; - - _payload; - - _badge; - - _sound; - - _title; - - _body; - - get payload() { - return this._payload; - } - - set title(value) { - this._title = value; - } - - set subtitle(value) { - this._subtitle = value; - } - - set body(value) { - this._body = value; - } - - set badge(value) { - this._badge = value; - } - - set sound(value) { - this._sound = value; - } - - constructor(payload, title, body) { - this._payload = payload; - - this._setDefaultPayloadStructure(); - this.title = title; - this.body = body; - } - - _setDefaultPayloadStructure() { - // Empty. - } - - toObject() { - return {}; - } -} - -export class APNSNotificationPayload extends BaseNotificationPayload { - _configurations; - - _apnsPushType; - - _isSilent; - - set configurations(value) { - if (!value || !value.length) return; - - this._configurations = value; - } - - get notification() { - return this._payload.aps; - } - - get title() { - return this._title; - } - - set title(value) { - if (!value || !value.length) return; - - this._payload.aps.alert.title = value; - this._title = value; - } - - get subtitle() { - return this._subtitle; - } - - set subtitle(value) { - if (!value || !value.length) return; - - this._payload.aps.alert.subtitle = value; - this._subtitle = value; - } - - get body() { - return this._body; - } - - set body(value) { - if (!value || !value.length) return; - - this._payload.aps.alert.body = value; - this._body = value; - } - - get badge() { - return this._badge; - } - - set badge(value) { - if (value === undefined || value === null) return; - - this._payload.aps.badge = value; - this._badge = value; - } - - get sound() { - return this._sound; - } - - set sound(value) { - if (!value || !value.length) return; - - this._payload.aps.sound = value; - this._sound = value; - } - - set silent(value) { - this._isSilent = value; - } - - _setDefaultPayloadStructure() { - this._payload.aps = { alert: {} }; - } - - toObject() { - const payload = { ...this._payload }; - /** @type {{alert: Object, badge: number, sound: string}} */ - const { aps } = payload; - let { alert } = aps; - - if (this._isSilent) { - aps['content-available'] = 1; - } - - if (this._apnsPushType === 'apns2') { - if (!this._configurations || !this._configurations.length) { - throw new ReferenceError('APNS2 configuration is missing'); - } - - const configurations = []; - this._configurations.forEach((configuration) => { - configurations.push(this._objectFromAPNS2Configuration(configuration)); - }); - - if (configurations.length) { - payload.pn_push = configurations; - } - } - - if (!alert || !Object.keys(alert).length) { - delete aps.alert; - } - - if (this._isSilent) { - delete aps.alert; - delete aps.badge; - delete aps.sound; - alert = {}; - } - - return this._isSilent || Object.keys(alert).length ? payload : null; - } - - _objectFromAPNS2Configuration(configuration) { - if (!configuration.targets || !configuration.targets.length) { - throw new ReferenceError('At least one APNS2 target should be provided'); - } - - const targets = []; - configuration.targets.forEach((target) => { - targets.push(this._objectFromAPNSTarget(target)); - }); - - const { collapseId, expirationDate } = configuration; - const objectifiedConfiguration = { auth_method: 'token', targets, version: 'v2' }; - - if (collapseId && collapseId.length) { - objectifiedConfiguration.collapse_id = collapseId; - } - - if (expirationDate) { - objectifiedConfiguration.expiration = expirationDate.toISOString(); - } - - return objectifiedConfiguration; - } - - _objectFromAPNSTarget(target) { - if (!target.topic || !target.topic.length) { - throw new TypeError("Target 'topic' undefined."); - } - - const { topic, environment = 'development', excludedDevices = [] } = target; - - const objectifiedTarget = { topic, environment }; - - if (excludedDevices.length) { - objectifiedTarget.excluded_devices = excludedDevices; - } - - return objectifiedTarget; - } -} - -export class MPNSNotificationPayload extends BaseNotificationPayload { - _backContent; - - _backTitle; - - _count; - - _type; - - get backContent() { - return this._backContent; - } - - set backContent(value) { - if (!value || !value.length) return; - - this._payload.back_content = value; - this._backContent = value; - } - - get backTitle() { - return this._backTitle; - } - - set backTitle(value) { - if (!value || !value.length) return; - - this._payload.back_title = value; - this._backTitle = value; - } - - get count() { - return this._count; - } - - set count(value) { - if (value === undefined || value === null) return; - - this._payload.count = value; - this._count = value; - } - - get title() { - return this._title; - } - - set title(value) { - if (!value || !value.length) return; - - this._payload.title = value; - this._title = value; - } - - get type() { - return this._type; - } - - set type(value) { - if (!value || !value.length) return; - - this._payload.type = value; - this._type = value; - } - - get subtitle() { - return this.backTitle; - } - - set subtitle(value) { - this.backTitle = value; - } - - get body() { - return this.backContent; - } - - set body(value) { - this.backContent = value; - } - - get badge() { - return this.count; - } - - set badge(value) { - this.count = value; - } - - toObject() { - return Object.keys(this._payload).length ? { ...this._payload } : null; - } -} - -export class FCMNotificationPayload extends BaseNotificationPayload { - _isSilent; - - _icon; - - _tag; - - get notification() { - return this._payload.notification; - } - - get data() { - return this._payload.data; - } - - get title() { - return this._title; - } - - set title(value) { - if (!value || !value.length) return; - - this._payload.notification.title = value; - this._title = value; - } - - get body() { - return this._body; - } - - set body(value) { - if (!value || !value.length) return; - - this._payload.notification.body = value; - this._body = value; - } - - get sound() { - return this._sound; - } - - set sound(value) { - if (!value || !value.length) return; - - this._payload.notification.sound = value; - this._sound = value; - } - - get icon() { - return this._icon; - } - - set icon(value) { - if (!value || !value.length) return; - - this._payload.notification.icon = value; - this._icon = value; - } - - get tag() { - return this._tag; - } - - set tag(value) { - if (!value || !value.length) return; - - this._payload.notification.tag = value; - this._tag = value; - } - - set silent(value) { - this._isSilent = value; - } - - _setDefaultPayloadStructure() { - this._payload.notification = {}; - this._payload.data = {}; - } - - toObject() { - let data = { ...this._payload.data }; - let notification = null; - const payload = {}; - - /** - * Check whether additional data has been passed outside of 'data' object - * and put it into it if required. - */ - if (Object.keys(this._payload).length > 2) { - const { notification: initialNotification, data: initialData, ...additionalData } = this._payload; - - data = { ...data, ...additionalData }; - } - - if (this._isSilent) { - data.notification = this._payload.notification; - } else { - notification = this._payload.notification; - } - - if (Object.keys(data).length) { - payload.data = data; - } - - if (notification && Object.keys(notification).length) { - payload.notification = notification; - } - - return Object.keys(payload).length ? payload : null; - } -} - -class NotificationsPayload { - _payload; - - _debugging; - - _subtitle; - - _badge; - - _sound; - - _title; - - _body; - - apns; - - mpns; - - fcm; - - set debugging(value) { - this._debugging = value; - } - - get title() { - return this._title; - } - - get body() { - return this._body; - } - - get subtitle() { - return this._subtitle; - } - - set subtitle(value) { - this._subtitle = value; - this.apns.subtitle = value; - this.mpns.subtitle = value; - this.fcm.subtitle = value; - } - - get badge() { - return this._badge; - } - - set badge(value) { - this._badge = value; - this.apns.badge = value; - this.mpns.badge = value; - this.fcm.badge = value; - } - - get sound() { - return this._sound; - } - - set sound(value) { - this._sound = value; - this.apns.sound = value; - this.mpns.sound = value; - this.fcm.sound = value; - } - - constructor(title, body) { - this._payload = { apns: {}, mpns: {}, fcm: {} }; - this._title = title; - this._body = body; - - this.apns = new APNSNotificationPayload(this._payload.apns, title, body); - this.mpns = new MPNSNotificationPayload(this._payload.mpns, title, body); - this.fcm = new FCMNotificationPayload(this._payload.fcm, title, body); - } - - /** - * Build notifications platform for requested platforms. - * - * @param {Array} platforms - List of platforms for which payload - * should be added to final dictionary. Supported values: gcm, apns, apns2, - * mpns. - * - * @returns {Object} Object with data, which can be sent with publish method - * call and trigger remote notifications for specified platforms. - */ - buildPayload(platforms) { - const payload = {}; - - if (platforms.includes('apns') || platforms.includes('apns2')) { - this.apns._apnsPushType = platforms.includes('apns') ? 'apns' : 'apns2'; - const apnsPayload = this.apns.toObject(); - - if (apnsPayload && Object.keys(apnsPayload).length) { - payload.pn_apns = apnsPayload; - } - } - - if (platforms.includes('mpns')) { - const mpnsPayload = this.mpns.toObject(); - - if (mpnsPayload && Object.keys(mpnsPayload).length) { - payload.pn_mpns = mpnsPayload; - } - } - - if (platforms.includes('fcm')) { - const fcmPayload = this.fcm.toObject(); - - if (fcmPayload && Object.keys(fcmPayload).length) { - payload.pn_gcm = fcmPayload; - } - } - - if (Object.keys(payload).length && this._debugging) { - payload.pn_debug = true; - } - - return payload; - } -} - -export default NotificationsPayload; diff --git a/src/core/components/push_payload.ts b/src/core/components/push_payload.ts new file mode 100644 index 000000000..4f0cee394 --- /dev/null +++ b/src/core/components/push_payload.ts @@ -0,0 +1,893 @@ +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +// region APNS2 +/** + * Payload for `pn_apns` field in published message. + */ +type APNSPayload = { + /** + * Payload for Apple Push Notification Service. + */ + aps: { + /** + * Configuration of visual notification representation. + */ + alert?: { + /** + * First line title. + * + * Title which is shown in bold on the first line of notification bubble. + */ + title?: string; + + /** + * Second line title. + * + * Subtitle which is shown under main title with smaller font. + */ + subtitle?: string; + + /** + * Notification body. + * + * Body which is shown to the user after interaction with notification. + */ + body?: string; + }; + + /** + * Unread notifications count badge value. + */ + badge?: number | null; + + /** + * Name of the file from resource bundle which should be played when notification received. + */ + sound?: string; + + /** + * Silent notification flag. + */ + 'content-available'?: 1; + }; + + /** + * APNS2 payload recipients information. + */ + pn_push: PubNubAPNS2Configuration[]; +}; + +/** + * APNS2 configuration type. + */ +type APNS2Configuration = { + /** + * Notification group / collapse identifier. Value will be used in APNS POST request as `apns-collapse-id` header + * value. + */ + collapseId?: string; + + /** + * Date till which APNS will try to deliver notification to target device. Value will be used in APNS POST request as + * `apns-expiration` header value. + */ + expirationDate?: Date; + + /** + * List of topics which should receive this notification. + */ + targets: APNS2Target[]; +}; + +/** + * Preformatted for PubNub service `APNS2` configuration type. + */ +type PubNubAPNS2Configuration = { + /** + * PubNub service authentication method for APNS. + */ + auth_method: 'token'; + + /** + * Target entities which should receive notification. + */ + targets: PubNubAPNS2Target[]; + + /** + * Notifications group collapse identifier. + */ + collapse_id?: string; + + /** + * Notification receive expiration date. + * + * Date after which notification won't be delivered. + */ + expiration?: string; + + /** + * APNS protocol version. + */ + version: 'v2'; +}; + +/** + * APNS2 configuration target type. + */ +type APNS2Target = { + /** + * Notifications topic name (usually it is bundle identifier of application for Apple platform). + * + * **Important:** Required only if `pushGateway` is set to `apns2`. + */ + topic: string; + + /** + * Environment within which registered devices to which notifications should be delivered. + * + * Available: + * - `development` + * - `production` + * + * @default `development` + */ + environment?: 'development' | 'production'; + + /** + * List of devices (their push tokens) to which this notification shouldn't be delivered. + */ + excludedDevices?: string[]; +}; + +/** + * Preformatted for PubNub service `APNS2` configuration target type. + */ +type PubNubAPNS2Target = Omit & { + /** + * List of devices (their push tokens) to which this notification shouldn't be delivered. + */ + excluded_devices?: string[]; +}; +// endregion + +// region FCM +/** + * Payload for `pn_gcm` field in published message. + */ +type FCMPayload = { + /** + * Configuration of visual notification representation. + */ + notification?: { + /** + * First line title. + * + * Title which is shown in bold on the first line of notification bubble. + */ + title?: string; + + /** + * Notification body. + * + * Body which is shown to the user after interaction with notification. + */ + body?: string; + + /** + * Name of the icon file from resource bundle which should be shown on notification. + */ + icon?: string; + + /** + * Name of the file from resource bundle which should be played when notification received. + */ + sound?: string; + + tag?: string; + }; + + /** + * Configuration of data notification. + * + * Silent notification configuration. + */ + data?: { notification?: FCMPayload['notification'] }; +}; +// endregion +// endregion + +/** + * Base notification payload object. + */ +class BaseNotificationPayload { + /** + * Notification main title. + */ + protected _title?: string; + + /** + * Notification second-line title. + */ + protected _subtitle?: string; + + /** + * Name of the sound which should be played for received notification. + */ + protected _sound?: string; + + /** + * Value which should be placed on application badge (if required). + */ + protected _badge?: number | null; + + /** + * Notification main body message. + */ + protected _body?: string; + + /** + * Object in resulting message where notification payload should be added. + */ + protected _payload: unknown; + + constructor(payload: unknown, title?: string, body?: string) { + this._payload = payload; + + this.setDefaultPayloadStructure(); + this.title = title; + this.body = body; + } + + /** + * Retrieve resulting notification payload content for message. + * + * @returns Preformatted push notification payload data. + */ + get payload(): unknown { + return this._payload; + } + + /** + * Update notification title. + * + * @param value - New notification title. + */ + set title(value: string | undefined) { + this._title = value; + } + + /** + * Update notification subtitle. + * + * @param value - New second-line notification title. + */ + set subtitle(value: string | undefined) { + this._subtitle = value; + } + + /** + * Update notification body. + * + * @param value - Update main notification message (shown when expanded). + */ + set body(value: string | undefined) { + this._body = value; + } + + /** + * Update application badge number. + * + * @param value - Number which should be shown in application badge upon receiving notification. + */ + set badge(value: number | null | undefined) { + this._badge = value; + } + + /** + * Update notification sound. + * + * @param value - Name of the sound file which should be played upon notification receive. + */ + set sound(value: string | undefined) { + this._sound = value; + } + + /** + * Platform-specific structure initialization. + */ + protected setDefaultPayloadStructure() {} + + /** + * Translate data object into PubNub push notification payload object. + * + * @returns Preformatted push notification payload. + */ + public toObject(): unknown { + return {}; + } +} + +/** + * Message payload for Apple Push Notification Service. + */ +export class APNSNotificationPayload extends BaseNotificationPayload { + /** + * List with notification receivers information. + */ + private _configurations?: APNS2Configuration[]; + + /** + * Type of push notification service for which payload will be created. + */ + private _apnsPushType: 'apns' | 'apns2' = 'apns'; + + /** + * Whether resulting payload should trigger silent notification or not. + */ + private _isSilent: boolean = false; + + get payload(): APNSPayload { + return this._payload as APNSPayload; + } + + /** + * Update notification receivers configuration. + * + * @param value - New APNS2 configurations. + */ + set configurations(value: APNS2Configuration[]) { + if (!value || !value.length) return; + + this._configurations = value; + } + + /** + * Notification payload. + * + * @returns Platform-specific part of PubNub notification payload. + */ + get notification() { + return this.payload.aps; + } + + /** + * Notification title. + * + * @returns Main notification title. + */ + get title() { + return this._title; + } + + /** + * Update notification title. + * + * @param value - New notification title. + */ + set title(value) { + if (!value || !value.length) return; + + this.payload.aps.alert!.title = value; + this._title = value; + } + + /** + * Notification subtitle. + * + * @returns Second-line notification title. + */ + get subtitle() { + return this._subtitle; + } + + /** + * Update notification subtitle. + * + * @param value - New second-line notification title. + */ + set subtitle(value) { + if (!value || !value.length) return; + + this.payload.aps.alert!.subtitle = value; + this._subtitle = value; + } + + /** + * Notification body. + * + * @returns Main notification message (shown when expanded). + */ + get body() { + return this._body; + } + + /** + * Update notification body. + * + * @param value - Update main notification message (shown when expanded). + */ + set body(value) { + if (!value || !value.length) return; + + this.payload.aps.alert!.body = value; + this._body = value; + } + + /** + * Retrieve unread notifications number. + * + * @returns Number of unread notifications which should be shown on application badge. + */ + get badge() { + return this._badge; + } + + /** + * Update application badge number. + * + * @param value - Number which should be shown in application badge upon receiving notification. + */ + set badge(value) { + if (value === undefined || value === null) return; + + this.payload.aps.badge = value; + this._badge = value; + } + + /** + * Retrieve notification sound file. + * + * @returns Notification sound file name from resource bundle. + */ + get sound() { + return this._sound; + } + + /** + * Update notification sound. + * + * @param value - Name of the sound file which should be played upon notification receive. + */ + set sound(value) { + if (!value || !value.length) return; + + this.payload.aps.sound = value; + this._sound = value; + } + + /** + * Set whether notification should be silent or not. + * + * `content-available` notification type will be used to deliver silent notification if set to `true`. + * + * @param value - Whether notification should be sent as silent or not. + */ + set silent(value: boolean) { + this._isSilent = value; + } + + protected setDefaultPayloadStructure() { + this.payload.aps = { alert: {} }; + } + + public toObject(): APNSPayload | null { + const payload = { ...this.payload }; + const { aps } = payload; + let { alert } = aps; + + if (this._isSilent) aps['content-available'] = 1; + + if (this._apnsPushType === 'apns2') { + if (!this._configurations || !this._configurations.length) + throw new ReferenceError('APNS2 configuration is missing'); + + const configurations: PubNubAPNS2Configuration[] = []; + this._configurations.forEach((configuration) => { + configurations.push(this.objectFromAPNS2Configuration(configuration)); + }); + + if (configurations.length) payload.pn_push = configurations; + } + + if (!alert || !Object.keys(alert).length) delete aps.alert; + + if (this._isSilent) { + delete aps.alert; + delete aps.badge; + delete aps.sound; + alert = {}; + } + + return this._isSilent || (alert && Object.keys(alert).length) ? payload : null; + } + + /** + * Create PubNub push notification service APNS2 configuration information object. + * + * @param configuration - Source user-provided APNS2 configuration. + * + * @returns Preformatted for PubNub service APNS2 configuration information. + */ + private objectFromAPNS2Configuration(configuration: APNS2Configuration): PubNubAPNS2Configuration { + if (!configuration.targets || !configuration.targets.length) + throw new ReferenceError('At least one APNS2 target should be provided'); + + const { collapseId, expirationDate } = configuration; + const objectifiedConfiguration: PubNubAPNS2Configuration = { + auth_method: 'token', + targets: configuration.targets.map((target) => this.objectFromAPNSTarget(target)), + version: 'v2', + }; + + if (collapseId && collapseId.length) objectifiedConfiguration.collapse_id = collapseId; + if (expirationDate) objectifiedConfiguration.expiration = expirationDate.toISOString(); + + return objectifiedConfiguration; + } + + /** + * Create PubNub push notification service APNS2 target information object. + * + * @param target - Source user-provided data. + * + * @returns Preformatted for PubNub service APNS2 target information. + */ + private objectFromAPNSTarget(target: APNS2Target): PubNubAPNS2Target { + if (!target.topic || !target.topic.length) throw new TypeError("Target 'topic' undefined."); + + const { topic, environment = 'development', excludedDevices = [] } = target; + const objectifiedTarget: PubNubAPNS2Target = { topic, environment }; + + if (excludedDevices.length) objectifiedTarget.excluded_devices = excludedDevices; + + return objectifiedTarget; + } +} + +/** + * Message payload for Firebase Clouse Messaging service. + */ +export class FCMNotificationPayload extends BaseNotificationPayload { + /** + * Whether resulting payload should trigger silent notification or not. + */ + private _isSilent?: boolean; + + /** + * Name of the icon file from resource bundle which should be shown on notification. + */ + private _icon?: string; + + private _tag?: string; + + get payload(): FCMPayload { + return this._payload as FCMPayload; + } + + /** + * Notification payload. + * + * @returns Platform-specific part of PubNub notification payload. + */ + get notification() { + return this.payload.notification; + } + + /** + * Silent notification payload. + * + * @returns Silent notification payload (data notification). + */ + get data() { + return this.payload.data; + } + + /** + * Notification title. + * + * @returns Main notification title. + */ + get title() { + return this._title; + } + + /** + * Update notification title. + * + * @param value - New notification title. + */ + set title(value) { + if (!value || !value.length) return; + + this.payload.notification!.title = value; + this._title = value; + } + + /** + * Notification body. + * + * @returns Main notification message (shown when expanded). + */ + get body() { + return this._body; + } + + /** + * Update notification body. + * + * @param value - Update main notification message (shown when expanded). + */ + set body(value) { + if (!value || !value.length) return; + + this.payload.notification!.body = value; + this._body = value; + } + + /** + * Retrieve notification sound file. + * + * @returns Notification sound file name from resource bundle. + */ + get sound() { + return this._sound; + } + + /** + * Update notification sound. + * + * @param value - Name of the sound file which should be played upon notification receive. + */ + set sound(value) { + if (!value || !value.length) return; + + this.payload.notification!.sound = value; + this._sound = value; + } + + /** + * Retrieve notification icon file. + * + * @returns Notification icon file name from resource bundle. + */ + get icon() { + return this._icon; + } + + /** + * Update notification icon. + * + * @param value - Name of the icon file which should be shown on notification. + */ + set icon(value) { + if (!value || !value.length) return; + + this.payload.notification!.icon = value; + this._icon = value; + } + + get tag() { + return this._tag; + } + + set tag(value) { + if (!value || !value.length) return; + + this.payload.notification!.tag = value; + this._tag = value; + } + + /** + * Set whether notification should be silent or not. + * + * All notification data will be sent under `data` field if set to `true`. + * + * @param value - Whether notification should be sent as silent or not. + */ + set silent(value: boolean) { + this._isSilent = value; + } + + protected setDefaultPayloadStructure() { + this.payload.notification = {}; + this.payload.data = {}; + } + + public toObject(): FCMPayload | null { + let data = { ...this.payload.data }; + let notification = null; + const payload: FCMPayload = {}; + + // Check whether additional data has been passed outside 'data' object and put it into it if required. + if (Object.keys(this.payload).length > 2) { + const { notification: initialNotification, data: initialData, ...additionalData } = this.payload; + + data = { ...data, ...additionalData }; + } + + if (this._isSilent) data.notification = this.payload.notification; + else notification = this.payload.notification; + + if (Object.keys(data).length) payload.data = data; + if (notification && Object.keys(notification).length) payload.notification = notification; + + return Object.keys(payload).length ? payload : null; + } +} + +class NotificationsPayload { + /** + * Resulting message payload for notification services. + */ + private readonly _payload; + + /** + * Whether notifications debugging session should be used or not. + */ + private _debugging?: boolean; + /** + * First line title. + * + * Title which is shown in bold on the first line of notification bubble. + */ + private readonly _title: string; + + /** + * Second line title. + * + * Subtitle which is shown under main title with smaller font. + */ + private _subtitle?: string; + + /** + * Notification main body message. + */ + private readonly _body: string; + + /** + * Value which should be placed on application badge (if required). + */ + private _badge?: number; + + /** + * Name of the file from resource bundle which should be played when notification received. + */ + private _sound?: string; + + /** + * APNS-specific message payload. + */ + public apns; + + /** + * FCM-specific message payload. + */ + public fcm; + + constructor(title: string, body: string) { + this._payload = { apns: {}, fcm: {} }; + this._title = title; + this._body = body; + + this.apns = new APNSNotificationPayload(this._payload.apns, title, body); + this.fcm = new FCMNotificationPayload(this._payload.fcm, title, body); + } + + set debugging(value: boolean) { + this._debugging = value; + } + + /** + * Notification title. + * + * @returns Main notification title. + */ + get title() { + return this._title; + } + + /** + * Notification subtitle. + * + * @returns Second-line notification title. + */ + get subtitle() { + return this._subtitle; + } + + /** + * Update notification subtitle. + * + * @param value - New second-line notification title. + */ + set subtitle(value) { + this._subtitle = value; + this.apns.subtitle = value; + this.fcm.subtitle = value; + } + + /** + * Notification body. + * + * @returns Main notification message (shown when expanded). + */ + get body() { + return this._body; + } + + /** + * Retrieve unread notifications number. + * + * @returns Number of unread notifications which should be shown on application badge. + */ + get badge() { + return this._badge; + } + + /** + * Update application badge number. + * + * @param value - Number which should be shown in application badge upon receiving notification. + */ + set badge(value: number | undefined) { + this._badge = value; + this.apns.badge = value; + this.fcm.badge = value; + } + + /** + * Retrieve notification sound file. + * + * @returns Notification sound file name from resource bundle. + */ + get sound() { + return this._sound; + } + + /** + * Update notification sound. + * + * @param value - Name of the sound file which should be played upon notification receive. + */ + set sound(value) { + this._sound = value; + this.apns.sound = value; + this.fcm.sound = value; + } + + /** + * Build notifications platform for requested platforms. + * + * @param platforms - List of platforms for which payload should be added to final dictionary. Supported values: + * gcm, apns, and apns2. + * + * @returns Object with data, which can be sent with publish method call and trigger remote notifications for + * specified platforms. + */ + buildPayload(platforms: string[]) { + const payload: { pn_apns?: APNSPayload; pn_gcm?: FCMPayload; pn_debug?: boolean } = {}; + + if (platforms.includes('apns') || platforms.includes('apns2')) { + // @ts-expect-error Override APNS version. + this.apns._apnsPushType = platforms.includes('apns') ? 'apns' : 'apns2'; + const apnsPayload = this.apns.toObject(); + + if (apnsPayload && Object.keys(apnsPayload).length) payload.pn_apns = apnsPayload; + } + + if (platforms.includes('fcm')) { + const fcmPayload = this.fcm.toObject(); + + if (fcmPayload && Object.keys(fcmPayload).length) payload.pn_gcm = fcmPayload; + } + + if (Object.keys(payload).length && this._debugging) payload.pn_debug = true; + + return payload; + } +} + +export default NotificationsPayload; diff --git a/src/core/components/reconnection_manager.js b/src/core/components/reconnection_manager.js deleted file mode 100644 index 6d221bd01..000000000 --- a/src/core/components/reconnection_manager.js +++ /dev/null @@ -1,34 +0,0 @@ -import TimeEndpoint from '../endpoints/time'; - -export default class { - _reconnectionCallback; - - _timeEndpoint; - - _timeTimer; - - constructor({ timeEndpoint }) { - this._timeEndpoint = timeEndpoint; - } - - onReconnection(reconnectionCallback) { - this._reconnectionCallback = reconnectionCallback; - } - - startPolling() { - this._timeTimer = setInterval(this._performTimeLoop.bind(this), 3000); - } - - stopPolling() { - clearInterval(this._timeTimer); - } - - _performTimeLoop() { - this._timeEndpoint((status) => { - if (!status.error) { - clearInterval(this._timeTimer); - this._reconnectionCallback(); - } - }); - } -} diff --git a/src/core/components/reconnection_manager.ts b/src/core/components/reconnection_manager.ts new file mode 100644 index 000000000..eac22539b --- /dev/null +++ b/src/core/components/reconnection_manager.ts @@ -0,0 +1,56 @@ +/** + * Subscription reconnection-manager. + * + * **Note:** Reconnection manger rely on legacy time-based availability check. + */ + +import { PubNubCore } from '../pubnub-common'; + +export class ReconnectionManager { + /** + * Successful availability check callback. + * + * @private + */ + private callback?: () => void; + + /** + * Time REST API call timer. + */ + private timeTimer?: number | null; + + constructor(private readonly time: typeof PubNubCore.prototype.time) {} + + /** + * Configure reconnection handler. + * + * @param callback - Successful availability check notify callback. + */ + public onReconnect(callback: () => void) { + this.callback = callback; + } + + /** + * Start periodic "availability" check. + */ + public startPolling() { + this.timeTimer = setInterval(() => this.callTime(), 3000) as unknown as number; + } + + /** + * Stop periodic "availability" check. + */ + public stopPolling() { + if (this.timeTimer) clearInterval(this.timeTimer); + this.timeTimer = null; + } + + private callTime() { + this.time((status) => { + if (!status.error) { + this.stopPolling(); + if (this.callback) this.callback(); + } + }); + } +} diff --git a/src/core/components/request.ts b/src/core/components/request.ts new file mode 100644 index 000000000..c0f328c73 --- /dev/null +++ b/src/core/components/request.ts @@ -0,0 +1,182 @@ +import { CancellationController, TransportMethod, TransportRequest } from '../types/transport-request'; +import { TransportResponse } from '../types/transport-response'; +import RequestOperation from '../constants/operations'; +import { PubNubFileInterface } from '../types/file'; +import { Request } from '../interfaces/request'; +import { Query } from '../types/api'; +import uuidGenerator from './uuid'; + +/** + * Base REST API request class. + */ +export abstract class AbstractRequest implements Request { + /** + * Service `ArrayBuffer` response decoder. + */ + protected static decoder = new TextDecoder(); + + /** + * Request cancellation controller. + */ + private _cancellationController: CancellationController | null; + + /** + * Unique request identifier. + */ + requestIdentifier = uuidGenerator.createUUID(); + + /** + * Construct base request. + * + * Constructed request by default won't be cancellable and performed using `GET` HTTP method. + * + * @param params - Request configuration parameters. + */ + protected constructor(private readonly params?: { method?: TransportMethod; cancellable?: boolean }) { + this._cancellationController = null; + } + + /** + * Retrieve configured cancellation controller. + * + * @returns Cancellation controller. + */ + public get cancellationController(): CancellationController | null { + return this._cancellationController; + } + + /** + * Update request cancellation controller. + * + * Controller itself provided by transport provider implementation and set only when request + * sending has been scheduled. + * + * @param controller - Cancellation controller or `null` to reset it. + */ + public set cancellationController(controller: CancellationController | null) { + this._cancellationController = controller; + } + /** + * Abort request if possible. + */ + abort(): void { + if (this && this.cancellationController) this.cancellationController.abort(); + } + + /** + * Target REST API endpoint operation type. + */ + operation(): RequestOperation { + throw Error('Should be implemented by subclass.'); + } + + /** + * Validate user-provided data before scheduling request. + * + * @returns Error message if request can't be sent without missing or malformed parameters. + */ + validate(): string | undefined { + return undefined; + } + + /** + * Parse service response. + * + * @param _response - Raw service response which should be parsed. + */ + async parse(_response: TransportResponse): Promise { + throw Error('Should be implemented by subclass.'); + } + + /** + * Create platform-agnostic request object. + * + * @returns Request object which can be processed using platform-specific requirements. + */ + request(): TransportRequest { + const request: TransportRequest = { + method: this.params?.method ?? TransportMethod.GET, + path: this.path, + queryParameters: this.queryParameters, + cancellable: this.params?.cancellable ?? false, + timeout: 10000, + identifier: this.requestIdentifier, + }; + + // Attach headers (if required). + const headers = this.headers; + if (headers) request.headers = headers; + + // Attach body (if required). + if (request.method === TransportMethod.POST || request.method === TransportMethod.PATCH) { + const [body, formData] = [this.body, this.formData]; + if (formData) request.formData = formData; + if (body) request.body = body; + } + + return request; + } + + /** + * Target REST API endpoint request headers getter. + * + * @returns Key/value headers which should be used with request. + */ + protected get headers(): Record | undefined { + return undefined; + } + + /** + * Target REST API endpoint request path getter. + * + * @returns REST API path. + */ + protected get path(): string { + throw Error('`path` getter should be implemented by subclass.'); + } + + /** + * Target REST API endpoint request query parameters getter. + * + * @returns Key/value pairs which should be appended to the REST API path. + */ + protected get queryParameters(): Query { + return {}; + } + + protected get formData(): Record[] | undefined { + return undefined; + } + + /** + * Target REST API Request body payload getter. + * + * @returns Buffer of stringified data which should be sent with `POST` or `PATCH` request. + */ + protected get body(): ArrayBuffer | PubNubFileInterface | string | undefined { + return undefined; + } + + /** + * Deserialize service response. + * + * @param response - Transparent response object with headers and body information. + * + * @returns Deserialized data or `undefined` in case of `JSON.parse(..)` error. + */ + protected deserializeResponse(response: TransportResponse): ServiceResponse | undefined { + const contentType = response.headers['content-type']; + if (!contentType || (contentType.indexOf('javascript') === -1 && contentType.indexOf('json') === -1)) + return undefined; + + const json = AbstractRequest.decoder.decode(response.body); + + try { + const parsedJson = JSON.parse(json); + return parsedJson as ServiceResponse; + } catch (error) { + console.error('Error parsing JSON response:', error); + return undefined; + } + } +} diff --git a/src/core/components/stringify_buffer_keys.js b/src/core/components/stringify_buffer_keys.js deleted file mode 100644 index 379318f57..000000000 --- a/src/core/components/stringify_buffer_keys.js +++ /dev/null @@ -1,32 +0,0 @@ -export function stringifyBufferKeys(obj) { - const isObject = (value) => value && typeof value === 'object' && value.constructor === Object; - const isString = (value) => typeof value === 'string' || value instanceof String; - const isNumber = (value) => typeof value === 'number' && isFinite(value); - - if (!isObject(obj)) { - return obj; - } - - const normalizedObject = {}; - - Object.keys(obj).forEach((key) => { - const keyIsString = isString(key); - let stringifiedKey = key; - const value = obj[key]; - - if (Array.isArray(key) || (keyIsString && key.indexOf(',') >= 0)) { - const bytes = keyIsString ? key.split(',') : key; - - stringifiedKey = bytes.reduce((string, byte) => { - string += String.fromCharCode(byte); - return string; - }, ''); - } else if (isNumber(key) || (keyIsString && !isNaN(key))) { - stringifiedKey = String.fromCharCode(keyIsString ? parseInt(key, 10) : 10); - } - - normalizedObject[stringifiedKey] = isObject(value) ? stringifyBufferKeys(value) : value; - }); - - return normalizedObject; -} diff --git a/src/core/components/stringify_buffer_keys.ts b/src/core/components/stringify_buffer_keys.ts new file mode 100644 index 000000000..2b9247ff1 --- /dev/null +++ b/src/core/components/stringify_buffer_keys.ts @@ -0,0 +1,30 @@ +export function stringifyBufferKeys(obj: unknown): Record { + const isObject = (value: unknown): value is Record => + typeof value === 'object' && value !== null && value.constructor === Object; + const isString = (value: unknown): value is string => typeof value === 'string' || value instanceof String; + const isNumber = (value: unknown): value is number => typeof value === 'number' && isFinite(value); + + if (!isObject(obj)) return obj as Record; + + const normalizedObject: Record = {}; + + Object.keys(obj).forEach((key) => { + const keyIsString = isString(key); + let stringifiedKey = key; + const value = obj[key]; + + if (keyIsString && key.indexOf(',') >= 0) { + const bytes = key.split(',').map(Number); + + stringifiedKey = bytes.reduce((string, byte) => { + return string + String.fromCharCode(byte); + }, ''); + } else if (isNumber(key) || (keyIsString && !isNaN(Number(key)))) { + stringifiedKey = String.fromCharCode(isNumber(key) ? key : parseInt(key, 10)); + } + + normalizedObject[stringifiedKey] = isObject(value) ? stringifyBufferKeys(value) : value; + }); + + return normalizedObject; +} diff --git a/src/core/components/subscription-manager.ts b/src/core/components/subscription-manager.ts new file mode 100644 index 000000000..3f295c200 --- /dev/null +++ b/src/core/components/subscription-manager.ts @@ -0,0 +1,569 @@ +/** + * Subscription manager module. + */ + +import { Payload, ResultCallback, Status, StatusCallback, StatusEvent } from '../types/api'; +import { RequestParameters as SubscribeRequestParameters } from '../endpoints/subscribe'; +import { PrivateClientConfiguration } from '../interfaces/configuration'; +import { HeartbeatRequest } from '../endpoints/presence/heartbeat'; +import { ReconnectionManager } from './reconnection_manager'; +import * as Subscription from '../types/api/subscription'; +import { ListenerManager } from './listener_manager'; +import StatusCategory from '../constants/categories'; +import Categories from '../constants/categories'; +import * as Presence from '../types/api/presence'; +import DedupingManager from './deduping_manager'; +import { PubNubCore } from '../pubnub-common'; +import EventEmitter from './eventEmitter'; + +/** + * Subscription loop manager. + */ +export class SubscriptionManager { + /** + * Connection availability check manager. + */ + private readonly reconnectionManager: ReconnectionManager; + + /** + * Real-time events deduplication manager. + */ + private readonly dedupingManager: DedupingManager; + + /** + * Map between channel / group name and `state` associated with `uuid` there. + */ + private readonly presenceState: Record; + + /** + * List of channel groups for which heartbeat calls should be performed. + */ + private readonly heartbeatChannelGroups: Record>; + + /** + * List of channels for which heartbeat calls should be performed. + */ + private readonly heartbeatChannels: Record>; + + /** + * List of channel groups for which real-time presence change events should be observed. + */ + private readonly presenceChannelGroups: Record>; + + /** + * List of channels for which real-time presence change events should be observed. + */ + private readonly presenceChannels: Record>; + + /** + * New list of channel groups to which manager will try to subscribe, + */ + private pendingChannelGroupSubscriptions: Set; + + /** + * New list of channels to which manager will try to subscribe, + */ + private pendingChannelSubscriptions: Set; + + /** + * List of channel groups for which real-time events should be observed. + */ + private readonly channelGroups: Record>; + + /** + * List of channels for which real-time events should be observed. + */ + private readonly channels: Record>; + + /** + * Timetoken which is used by the current subscription loop. + */ + private currentTimetoken: string | number; + + /** + * Timetoken which has been used with previous subscription loop. + */ + private lastTimetoken: string | number; + + /** + * User-provided timetoken or timetoken for catch up. + */ + private storedTimetoken: string | number | null; + + /** + * Timetoken's region. + */ + private region?: number | null; + + private heartbeatTimer: number | null; + + /** + * Whether subscription status change has been announced or not. + */ + private subscriptionStatusAnnounced: boolean; + + /** + * Whether PubNub client is online right now. + */ + private isOnline: boolean; + + /** + * Active subscription request abort method. + * + * **Note:** Reference updated with each subscribe call. + */ + private _subscribeAbort?: { + /** + * Request abort caller. + */ + (): void; + + /** + * Abort controller owner identifier. + */ + identifier: string; + } | null; + + constructor( + private readonly configuration: PrivateClientConfiguration, + private readonly listenerManager: ListenerManager, + private readonly eventEmitter: EventEmitter, + private readonly subscribeCall: ( + parameters: Omit, + callback: ResultCallback, + ) => void, + private readonly heartbeatCall: ( + parameters: Presence.PresenceHeartbeatParameters, + callback: StatusCallback, + ) => void, + private readonly leaveCall: (parameters: Presence.PresenceLeaveParameters, callback: StatusCallback) => void, + time: typeof PubNubCore.prototype.time, + ) { + this.reconnectionManager = new ReconnectionManager(time); + this.dedupingManager = new DedupingManager({ config: this.configuration }); + this.heartbeatChannelGroups = {}; + this.heartbeatChannels = {}; + this.presenceChannelGroups = {}; + this.presenceChannels = {}; + this.heartbeatTimer = null; + this.presenceState = {}; + this.pendingChannelGroupSubscriptions = new Set(); + this.pendingChannelSubscriptions = new Set(); + this.channelGroups = {}; + this.channels = {}; + + this.currentTimetoken = '0'; + this.lastTimetoken = '0'; + this.storedTimetoken = null; + + this.subscriptionStatusAnnounced = false; + this.isOnline = true; + } + + // region Information + get subscribedChannels(): string[] { + return Object.keys(this.channels); + } + + get subscribedChannelGroups(): string[] { + return Object.keys(this.channelGroups); + } + + get abort() { + return this._subscribeAbort; + } + + set abort(call: typeof this._subscribeAbort) { + this._subscribeAbort = call; + } + // endregion + + // region Subscription + + public disconnect() { + this.stopSubscribeLoop(); + this.stopHeartbeatTimer(); + this.reconnectionManager.stopPolling(); + } + + public reconnect() { + this.startSubscribeLoop(); + this.startHeartbeatTimer(); + } + + /** + * Update channels and groups used in subscription loop. + * + * @param parameters - Subscribe configuration parameters. + */ + public subscribe(parameters: Subscription.SubscribeParameters) { + const { channels, channelGroups, timetoken, withPresence = false, withHeartbeats = false } = parameters; + + if (timetoken) { + this.lastTimetoken = this.currentTimetoken; + this.currentTimetoken = timetoken; + } + + if (this.currentTimetoken !== '0' && this.currentTimetoken !== 0) { + this.storedTimetoken = this.currentTimetoken; + this.currentTimetoken = 0; + } + + channels?.forEach((channel) => { + this.pendingChannelSubscriptions.add(channel); + this.channels[channel] = {}; + + if (withPresence) this.presenceChannels[channel] = {}; + if (withHeartbeats || this.configuration.getHeartbeatInterval()) this.heartbeatChannels[channel] = {}; + }); + + channelGroups?.forEach((group) => { + this.pendingChannelGroupSubscriptions.add(group); + this.channelGroups[group] = {}; + + if (withPresence) this.presenceChannelGroups[group] = {}; + if (withHeartbeats || this.configuration.getHeartbeatInterval()) this.heartbeatChannelGroups[group] = {}; + }); + + this.subscriptionStatusAnnounced = false; + this.reconnect(); + } + + public unsubscribe(parameters: Presence.PresenceLeaveParameters, isOffline?: boolean) { + let { channels, channelGroups } = parameters; + + const actualChannelGroups: Set = new Set(); + const actualChannels: Set = new Set(); + + channels?.forEach((channel) => { + if (channel in this.channels) { + delete this.channels[channel]; + actualChannels.add(channel); + + if (channel in this.heartbeatChannels) delete this.heartbeatChannels[channel]; + } + + if (channel in this.presenceState) delete this.presenceState[channel]; + if (channel in this.presenceChannels) { + delete this.presenceChannels[channel]; + actualChannels.add(channel); + } + }); + + channelGroups?.forEach((group) => { + if (group in this.channelGroups) { + delete this.channelGroups[group]; + actualChannelGroups.add(group); + + if (group in this.heartbeatChannelGroups) delete this.heartbeatChannelGroups[group]; + } + + if (group in this.presenceState) delete this.presenceState[group]; + if (group in this.presenceChannelGroups) { + delete this.presenceChannelGroups[group]; + actualChannelGroups.add(group); + } + }); + + // There is no need to unsubscribe to empty list of data sources. + if (actualChannels.size === 0 && actualChannelGroups.size === 0) return; + + if (this.configuration.suppressLeaveEvents === false && !isOffline) { + channelGroups = Array.from(actualChannelGroups); + channels = Array.from(actualChannels); + + this.leaveCall({ channels, channelGroups }, (status) => { + const { error, ...restOfStatus } = status; + let errorMessage: string | undefined; + + if (error) { + if ( + status.errorData && + typeof status.errorData === 'object' && + 'message' in status.errorData && + typeof status.errorData.message === 'string' + ) + errorMessage = status.errorData.message; + else if ('message' in status && typeof status.message === 'string') errorMessage = status.message; + } + + this.listenerManager.announceStatus({ + ...restOfStatus, + error: errorMessage ?? false, + affectedChannels: channels, + affectedChannelGroups: channelGroups, + currentTimetoken: this.currentTimetoken, + lastTimetoken: this.lastTimetoken, + } as StatusEvent); + }); + } + + if ( + Object.keys(this.channels).length === 0 && + Object.keys(this.presenceChannels).length === 0 && + Object.keys(this.channelGroups).length === 0 && + Object.keys(this.presenceChannelGroups).length === 0 + ) { + this.lastTimetoken = 0; + this.currentTimetoken = 0; + this.storedTimetoken = null; + this.region = null; + this.reconnectionManager.stopPolling(); + } + + this.reconnect(); + } + + public unsubscribeAll(isOffline?: boolean) { + this.unsubscribe( + { + channels: this.subscribedChannels, + channelGroups: this.subscribedChannelGroups, + }, + isOffline, + ); + } + + private startSubscribeLoop() { + this.stopSubscribeLoop(); + const channelGroups = [...Object.keys(this.channelGroups)]; + const channels = [...Object.keys(this.channels)]; + + Object.keys(this.presenceChannelGroups).forEach((group) => channelGroups.push(`${group}-pnpres`)); + Object.keys(this.presenceChannels).forEach((channel) => channels.push(`${channel}-pnpres`)); + + // There is no need to start subscription loop for empty list of data sources. + if (channels.length === 0 && channelGroups.length === 0) return; + + this.subscribeCall( + { + channels, + channelGroups, + state: this.presenceState, + heartbeat: this.configuration.getPresenceTimeout(), + timetoken: this.currentTimetoken, + region: this.region !== null ? this.region : undefined, + filterExpression: this.configuration.filterExpression, + }, + (status, result) => { + this.processSubscribeResponse(status, result); + }, + ); + } + + private stopSubscribeLoop() { + if (this._subscribeAbort) { + this._subscribeAbort(); + this._subscribeAbort = null; + } + } + + /** + * Process subscribe REST API endpoint response. + */ + private processSubscribeResponse(status: Status, result: Subscription.SubscriptionResponse | null) { + if (status.error) { + // Ignore aborted request. + if ( + (typeof status.errorData === 'object' && + 'name' in status.errorData && + status.errorData.name === 'AbortError') || + status.category === StatusCategory.PNCancelledCategory + ) + return; + + if (status.category === Categories.PNTimeoutCategory) { + this.startSubscribeLoop(); + } else if (status.category === Categories.PNNetworkIssuesCategory) { + this.disconnect(); + + if (status.error && this.configuration.autoNetworkDetection && this.isOnline) { + this.isOnline = false; + this.listenerManager.announceNetworkDown(); + } + + this.reconnectionManager.onReconnect(() => { + if (this.configuration.autoNetworkDetection && !this.isOnline) { + this.isOnline = true; + this.listenerManager.announceNetworkUp(); + } + + this.reconnect(); + this.subscriptionStatusAnnounced = true; + + const reconnectedAnnounce = { + category: Categories.PNReconnectedCategory, + operation: status.operation, + lastTimetoken: this.lastTimetoken, + currentTimetoken: this.currentTimetoken, + }; + this.listenerManager.announceStatus(reconnectedAnnounce); + }); + + this.reconnectionManager.startPolling(); + this.listenerManager.announceStatus(status); + } else if (status.category === Categories.PNBadRequestCategory) { + this.stopHeartbeatTimer(); + this.listenerManager.announceStatus(status); + } else { + this.listenerManager.announceStatus(status); + } + + return; + } + + if (this.storedTimetoken) { + this.currentTimetoken = this.storedTimetoken; + this.storedTimetoken = null; + } else { + this.lastTimetoken = this.currentTimetoken; + this.currentTimetoken = result!.cursor.timetoken; + } + + if (!this.subscriptionStatusAnnounced) { + const connected: StatusEvent = { + category: StatusCategory.PNConnectedCategory, + operation: status.operation, + affectedChannels: Array.from(this.pendingChannelSubscriptions), + subscribedChannels: this.subscribedChannels, + affectedChannelGroups: Array.from(this.pendingChannelGroupSubscriptions), + lastTimetoken: this.lastTimetoken, + currentTimetoken: this.currentTimetoken, + }; + + this.subscriptionStatusAnnounced = true; + this.listenerManager.announceStatus(connected); + + // Clear pending channels and groups. + this.pendingChannelGroupSubscriptions.clear(); + this.pendingChannelSubscriptions.clear(); + } + + const { messages } = result!; + const { requestMessageCountThreshold, dedupeOnSubscribe } = this.configuration; + + if (requestMessageCountThreshold && messages.length >= requestMessageCountThreshold) { + this.listenerManager.announceStatus({ + category: StatusCategory.PNRequestMessageCountExceededCategory, + operation: status.operation, + }); + } + + try { + messages.forEach((message) => { + if (dedupeOnSubscribe) { + if (this.dedupingManager.isDuplicate(message.data)) return; + this.dedupingManager.addEntry(message.data); + } + + this.eventEmitter.emitEvent(message); + }); + } catch (e) { + const errorStatus: Status = { + error: true, + category: StatusCategory.PNUnknownCategory, + errorData: e as Error, + statusCode: 0, + }; + this.listenerManager.announceStatus(errorStatus); + } + + this.region = result!.cursor.region; + this.startSubscribeLoop(); + } + // endregion + + // region Presence + /** + * Update `uuid` state which should be sent with subscribe request. + * + * @param parameters - Channels and groups with state which should be associated to `uuid`. + */ + public setState(parameters: { state: Payload; channels?: string[]; channelGroups?: string[] }) { + const { state, channels, channelGroups } = parameters; + channels?.forEach((channel) => channel in this.channels && (this.presenceState[channel] = state)); + channelGroups?.forEach((group) => group in this.channelGroups && (this.presenceState[group] = state)); + } + + /** + * Manual presence management. + * + * @param parameters - Desired presence state for provided list of channels and groups. + */ + public changePresence(parameters: { connected: boolean; channels?: string[]; channelGroups?: string[] }) { + const { connected, channels, channelGroups } = parameters; + + if (connected) { + channels?.forEach((channel) => (this.heartbeatChannels[channel] = {})); + channelGroups?.forEach((group) => (this.heartbeatChannelGroups[group] = {})); + } else { + channels?.forEach((channel) => { + if (channel in this.heartbeatChannels) delete this.heartbeatChannels[channel]; + }); + channelGroups?.forEach((group) => { + if (group in this.heartbeatChannelGroups) delete this.heartbeatChannelGroups[group]; + }); + + if (this.configuration.suppressLeaveEvents === false) { + this.leaveCall({ channels, channelGroups }, (status) => this.listenerManager.announceStatus(status)); + } + } + + this.reconnect(); + } + + private startHeartbeatTimer() { + this.stopHeartbeatTimer(); + + const heartbeatInterval = this.configuration.getHeartbeatInterval(); + if (!heartbeatInterval || heartbeatInterval === 0) return; + + this.sendHeartbeat(); + this.heartbeatTimer = setInterval(() => this.sendHeartbeat(), heartbeatInterval * 1000) as unknown as number; + } + + /** + * Stop heartbeat. + * + * Stop timer which trigger {@link HeartbeatRequest} sending with configured presence intervals. + */ + private stopHeartbeatTimer() { + if (!this.heartbeatTimer) return; + + clearInterval(this.heartbeatTimer); + this.heartbeatTimer = null; + } + + /** + * Send heartbeat request. + */ + private sendHeartbeat() { + const heartbeatChannelGroups = Object.keys(this.heartbeatChannelGroups); + const heartbeatChannels = Object.keys(this.heartbeatChannels); + + // There is no need to start heartbeat loop if there is no channels and groups to use. + if (heartbeatChannels.length === 0 && heartbeatChannelGroups.length === 0) return; + + this.heartbeatCall( + { + channels: heartbeatChannels, + channelGroups: heartbeatChannelGroups, + heartbeat: this.configuration.getPresenceTimeout(), + state: this.presenceState, + }, + (status) => { + if (status.error && this.configuration.announceFailedHeartbeats) this.listenerManager.announceStatus(status); + if (status.error && this.configuration.autoNetworkDetection && this.isOnline) { + this.isOnline = false; + this.disconnect(); + this.listenerManager.announceNetworkDown(); + this.reconnect(); + } + + if (!status.error && this.configuration.announceSuccessfulHeartbeats) + this.listenerManager.announceStatus(status); + }, + ); + } + // endregion +} diff --git a/src/core/components/subscription_manager.js b/src/core/components/subscription_manager.js deleted file mode 100644 index 1dd6fbed2..000000000 --- a/src/core/components/subscription_manager.js +++ /dev/null @@ -1,579 +0,0 @@ -import ReconnectionManager from './reconnection_manager'; -import DedupingManager from './deduping_manager'; -import utils from '../utils'; -import categoryConstants from '../constants/categories'; - -export default class { - _crypto; - - _config; - - _listenerManager; - - _reconnectionManager; - - _leaveEndpoint; - - _heartbeatEndpoint; - - _setStateEndpoint; - - _subscribeEndpoint; - - _getFileUrl; - - _channels; - - _presenceChannels; - - _heartbeatChannels; - - _heartbeatChannelGroups; - - _channelGroups; - - _presenceChannelGroups; - - _currentTimetoken; - - _lastTimetoken; - - _storedTimetoken; - - _region; - - _subscribeCall; - - _heartbeatTimer; - - _subscriptionStatusAnnounced; - - _autoNetworkDetection; - - _isOnline; - - // store pending connection elements - _pendingChannelSubscriptions; - - _pendingChannelGroupSubscriptions; - // - - _cryptoModule; - - _decoder; - - _dedupingManager; - - _eventEmitter; - - constructor({ - subscribeEndpoint, - leaveEndpoint, - heartbeatEndpoint, - setStateEndpoint, - timeEndpoint, - getFileUrl, - config, - crypto, - listenerManager, - cryptoModule, - eventEmitter, - }) { - this._listenerManager = listenerManager; - this._config = config; - - this._leaveEndpoint = leaveEndpoint; - this._heartbeatEndpoint = heartbeatEndpoint; - this._setStateEndpoint = setStateEndpoint; - this._subscribeEndpoint = subscribeEndpoint; - this._getFileUrl = getFileUrl; - - this._crypto = crypto; - this._cryptoModule = cryptoModule; - - this._channels = {}; - this._presenceChannels = {}; - - this._heartbeatChannels = {}; - this._heartbeatChannelGroups = {}; - - this._channelGroups = {}; - this._presenceChannelGroups = {}; - - this._pendingChannelSubscriptions = []; - this._pendingChannelGroupSubscriptions = []; - - this._currentTimetoken = 0; - this._lastTimetoken = 0; - this._storedTimetoken = null; - - this._subscriptionStatusAnnounced = false; - - this._isOnline = true; - - this._reconnectionManager = new ReconnectionManager({ timeEndpoint }); - this._dedupingManager = new DedupingManager({ config }); - - if (this._cryptoModule) this._decoder = new TextDecoder(); - - this._eventEmitter = eventEmitter; - } - - adaptStateChange(args, callback) { - const { state, channels = [], channelGroups = [], withHeartbeat = false } = args; - - channels.forEach((channel) => { - if (channel in this._channels) this._channels[channel].state = state; - }); - - channelGroups.forEach((channelGroup) => { - if (channelGroup in this._channelGroups) { - this._channelGroups[channelGroup].state = state; - } - }); - - if (withHeartbeat) { - let presenceState = {}; - channels.forEach((channel) => (presenceState[channel] = state)); - channelGroups.forEach((group) => (presenceState[group] = state)); - return this._heartbeatEndpoint( - { channels: channels, channelGroups: channelGroups, state: presenceState }, - callback, - ); - } - - return this._setStateEndpoint({ state, channels, channelGroups }, callback); - } - - adaptPresenceChange(args) { - const { connected, channels = [], channelGroups = [] } = args; - - if (connected) { - channels.forEach((channel) => { - this._heartbeatChannels[channel] = { state: {} }; - }); - - channelGroups.forEach((channelGroup) => { - this._heartbeatChannelGroups[channelGroup] = { state: {} }; - }); - } else { - channels.forEach((channel) => { - if (channel in this._heartbeatChannels) { - delete this._heartbeatChannels[channel]; - } - }); - - channelGroups.forEach((channelGroup) => { - if (channelGroup in this._heartbeatChannelGroups) { - delete this._heartbeatChannelGroups[channelGroup]; - } - }); - - if (this._config.suppressLeaveEvents === false) { - this._leaveEndpoint({ channels, channelGroups }, (status) => { - this._listenerManager.announceStatus(status); - }); - } - } - - this.reconnect(); - } - - adaptSubscribeChange(args) { - const { timetoken, channels = [], channelGroups = [], withPresence = false, withHeartbeats = false } = args; - - if (!this._config.subscribeKey || this._config.subscribeKey === '') { - // eslint-disable-next-line - if (console && console.log) { - console.log('subscribe key missing; aborting subscribe'); //eslint-disable-line - } - return; - } - - if (timetoken) { - this._lastTimetoken = this._currentTimetoken; - this._currentTimetoken = timetoken; - } - - // reset the current timetoken to get a connect event. - // $FlowFixMe - if (this._currentTimetoken !== '0' && this._currentTimetoken !== 0) { - this._storedTimetoken = this._currentTimetoken; - this._currentTimetoken = 0; - } - - channels.forEach((channel) => { - this._channels[channel] = { state: {} }; - if (withPresence) this._presenceChannels[channel] = {}; - if (withHeartbeats || this._config.getHeartbeatInterval()) this._heartbeatChannels[channel] = {}; - - this._pendingChannelSubscriptions.push(channel); - }); - - channelGroups.forEach((channelGroup) => { - this._channelGroups[channelGroup] = { state: {} }; - if (withPresence) this._presenceChannelGroups[channelGroup] = {}; - if (withHeartbeats || this._config.getHeartbeatInterval()) this._heartbeatChannelGroups[channelGroup] = {}; - - this._pendingChannelGroupSubscriptions.push(channelGroup); - }); - - this._subscriptionStatusAnnounced = false; - this.reconnect(); - } - - adaptUnsubscribeChange(args, isOffline) { - const { channels = [], channelGroups = [] } = args; - - // keep track of which channels and channel groups - // we are going to unsubscribe from. - const actualChannels = []; - const actualChannelGroups = []; - // - - channels.forEach((channel) => { - if (channel in this._channels) { - delete this._channels[channel]; - actualChannels.push(channel); - - if (channel in this._heartbeatChannels) { - delete this._heartbeatChannels[channel]; - } - } - if (channel in this._presenceChannels) { - delete this._presenceChannels[channel]; - actualChannels.push(channel); - } - }); - - channelGroups.forEach((channelGroup) => { - if (channelGroup in this._channelGroups) { - delete this._channelGroups[channelGroup]; - actualChannelGroups.push(channelGroup); - - if (channelGroup in this._heartbeatChannelGroups) { - delete this._heartbeatChannelGroups[channelGroup]; - } - } - if (channelGroup in this._presenceChannelGroups) { - delete this._presenceChannelGroups[channelGroup]; - actualChannelGroups.push(channelGroup); - } - }); - - // no-op if there are no channels and cg's to unsubscribe from. - if (actualChannels.length === 0 && actualChannelGroups.length === 0) { - return; - } - - if (this._config.suppressLeaveEvents === false && !isOffline) { - this._leaveEndpoint({ channels: actualChannels, channelGroups: actualChannelGroups }, (status) => { - status.affectedChannels = actualChannels; - status.affectedChannelGroups = actualChannelGroups; - status.currentTimetoken = this._currentTimetoken; - status.lastTimetoken = this._lastTimetoken; - this._listenerManager.announceStatus(status); - }); - } - - // if we have nothing to subscribe to, reset the timetoken. - if ( - Object.keys(this._channels).length === 0 && - Object.keys(this._presenceChannels).length === 0 && - Object.keys(this._channelGroups).length === 0 && - Object.keys(this._presenceChannelGroups).length === 0 - ) { - this._lastTimetoken = 0; - this._currentTimetoken = 0; - this._storedTimetoken = null; - this._region = null; - this._reconnectionManager.stopPolling(); - } - - this.reconnect(); - } - - unsubscribeAll(isOffline) { - this.adaptUnsubscribeChange( - { - channels: this.getSubscribedChannels(), - channelGroups: this.getSubscribedChannelGroups(), - }, - isOffline, - ); - } - - getHeartbeatChannels() { - return Object.keys(this._heartbeatChannels); - } - - getHeartbeatChannelGroups() { - return Object.keys(this._heartbeatChannelGroups); - } - - getSubscribedChannels() { - return Object.keys(this._channels); - } - - getSubscribedChannelGroups() { - return Object.keys(this._channelGroups); - } - - reconnect() { - this._startSubscribeLoop(); - this._registerHeartbeatTimer(); - } - - disconnect() { - this._stopSubscribeLoop(); - this._stopHeartbeatTimer(); - this._reconnectionManager.stopPolling(); - } - - _registerHeartbeatTimer() { - this._stopHeartbeatTimer(); - - // if the interval is 0 or undefined, do not queue up heartbeating - if (this._config.getHeartbeatInterval() === 0 || this._config.getHeartbeatInterval() === undefined) { - return; - } - - this._performHeartbeatLoop(); - // $FlowFixMe - this._heartbeatTimer = setInterval( - this._performHeartbeatLoop.bind(this), - this._config.getHeartbeatInterval() * 1000, - ); - } - - _stopHeartbeatTimer() { - if (this._heartbeatTimer) { - // $FlowFixMe - clearInterval(this._heartbeatTimer); - this._heartbeatTimer = null; - } - } - - _performHeartbeatLoop() { - const heartbeatChannels = this.getHeartbeatChannels(); - - const heartbeatChannelGroups = this.getHeartbeatChannelGroups(); - - const presenceState = {}; - - if (heartbeatChannels.length === 0 && heartbeatChannelGroups.length === 0) { - return; - } - - this.getSubscribedChannels().forEach((channel) => { - const channelState = this._channels[channel].state; - if (Object.keys(channelState).length) { - presenceState[channel] = channelState; - } - }); - - this.getSubscribedChannelGroups().forEach((channelGroup) => { - const channelGroupState = this._channelGroups[channelGroup].state; - if (Object.keys(channelGroupState).length) { - presenceState[channelGroup] = channelGroupState; - } - }); - - const onHeartbeat = (status) => { - if (status.error && this._config.announceFailedHeartbeats) { - this._listenerManager.announceStatus(status); - } - - if (status.error && this._config.autoNetworkDetection && this._isOnline) { - this._isOnline = false; - this.disconnect(); - this._listenerManager.announceNetworkDown(); - this.reconnect(); - } - - if (!status.error && this._config.announceSuccessfulHeartbeats) { - this._listenerManager.announceStatus(status); - } - }; - - this._heartbeatEndpoint( - { - channels: heartbeatChannels, - channelGroups: heartbeatChannelGroups, - state: presenceState, - }, - onHeartbeat.bind(this), - ); - } - - _startSubscribeLoop() { - this._stopSubscribeLoop(); - const presenceState = {}; - const channels = []; - const channelGroups = []; - - Object.keys(this._channels).forEach((channel) => { - const channelState = this._channels[channel].state; - - if (Object.keys(channelState).length) { - presenceState[channel] = channelState; - } - - channels.push(channel); - }); - Object.keys(this._presenceChannels).forEach((channel) => { - channels.push(`${channel}-pnpres`); - }); - - Object.keys(this._channelGroups).forEach((channelGroup) => { - const channelGroupState = this._channelGroups[channelGroup].state; - - if (Object.keys(channelGroupState).length) { - presenceState[channelGroup] = channelGroupState; - } - - channelGroups.push(channelGroup); - }); - Object.keys(this._presenceChannelGroups).forEach((channelGroup) => { - channelGroups.push(`${channelGroup}-pnpres`); - }); - - if (channels.length === 0 && channelGroups.length === 0) { - return; - } - - const subscribeArgs = { - channels, - channelGroups, - state: presenceState, - timetoken: this._currentTimetoken, - filterExpression: this._config.filterExpression, - region: this._region, - }; - - this._subscribeCall = this._subscribeEndpoint(subscribeArgs, this._processSubscribeResponse.bind(this)); - } - - _processSubscribeResponse(status, payload) { - if (status.error) { - // if error comes from request abort, ignore - if (status.errorData && status.errorData.message === 'Aborted') { - return; - } - - // if we timeout from server, restart the loop. - if (status.category === categoryConstants.PNTimeoutCategory) { - this._startSubscribeLoop(); - } else if (status.category === categoryConstants.PNNetworkIssuesCategory) { - // we lost internet connection, alert the reconnection manager and terminate all loops - this.disconnect(); - - if (status.error && this._config.autoNetworkDetection && this._isOnline) { - this._isOnline = false; - this._listenerManager.announceNetworkDown(); - } - - this._reconnectionManager.onReconnection(() => { - if (this._config.autoNetworkDetection && !this._isOnline) { - this._isOnline = true; - this._listenerManager.announceNetworkUp(); - } - this.reconnect(); - this._subscriptionStatusAnnounced = true; - const reconnectedAnnounce = { - category: categoryConstants.PNReconnectedCategory, - operation: status.operation, - lastTimetoken: this._lastTimetoken, - currentTimetoken: this._currentTimetoken, - }; - this._listenerManager.announceStatus(reconnectedAnnounce); - }); - - this._reconnectionManager.startPolling(); - this._listenerManager.announceStatus(status); - } else if (status.category === categoryConstants.PNBadRequestCategory) { - this._stopHeartbeatTimer(); - this._listenerManager.announceStatus(status); - } else { - this._listenerManager.announceStatus(status); - } - - return; - } - - if (this._storedTimetoken) { - this._currentTimetoken = this._storedTimetoken; - this._storedTimetoken = null; - } else { - this._lastTimetoken = this._currentTimetoken; - this._currentTimetoken = payload.metadata.timetoken; - } - - if (!this._subscriptionStatusAnnounced) { - const connectedAnnounce = {}; - connectedAnnounce.category = categoryConstants.PNConnectedCategory; - connectedAnnounce.operation = status.operation; - connectedAnnounce.affectedChannels = this._pendingChannelSubscriptions; - connectedAnnounce.subscribedChannels = this.getSubscribedChannels(); - connectedAnnounce.affectedChannelGroups = this._pendingChannelGroupSubscriptions; - connectedAnnounce.lastTimetoken = this._lastTimetoken; - connectedAnnounce.currentTimetoken = this._currentTimetoken; - this._subscriptionStatusAnnounced = true; - this._listenerManager.announceStatus(connectedAnnounce); - - // clear the pending connections list - this._pendingChannelSubscriptions = []; - this._pendingChannelGroupSubscriptions = []; - } - - const messages = payload.messages || []; - const { requestMessageCountThreshold, dedupeOnSubscribe } = this._config; - - if (requestMessageCountThreshold && messages.length >= requestMessageCountThreshold) { - const countAnnouncement = {}; - countAnnouncement.category = categoryConstants.PNRequestMessageCountExceededCategory; - countAnnouncement.operation = status.operation; - this._listenerManager.announceStatus(countAnnouncement); - } - - messages.forEach((message) => { - const { channel } = message; - let { subscriptionMatch } = message; - - if (channel === subscriptionMatch) { - subscriptionMatch = null; - } - - if (dedupeOnSubscribe) { - if (this._dedupingManager.isDuplicate(message)) { - return; - } - this._dedupingManager.addEntry(message); - } - - this._eventEmitter.emitEvent(message); - }); - - this._region = payload.metadata.region; - this._startSubscribeLoop(); - } - - _stopSubscribeLoop() { - if (this._subscribeCall) { - if (typeof this._subscribeCall.abort === 'function') { - this._subscribeCall.abort(); - } - this._subscribeCall = null; - } - } - - _renameEvent(e) { - return e === 'set' ? 'updated' : 'removed'; - } - - _renameChannelField(announce) { - const { channel, ...eventData } = announce; - eventData.spaceId = channel; - return eventData; - } -} diff --git a/src/core/components/telemetry_manager.js b/src/core/components/telemetry_manager.js deleted file mode 100644 index fa4392df4..000000000 --- a/src/core/components/telemetry_manager.js +++ /dev/null @@ -1,151 +0,0 @@ -/* */ -import operationConstants from '../constants/operations'; - -export default class { - _maximumSamplesCount = 100; - - _trackedLatencies = {}; - - _latencies = {}; - - _telemetryExcludeOperations = [ - operationConstants.PNSubscribeOperation, - operationConstants.PNReceiveMessagesOperation, - operationConstants.PNHandshakeOperation, - ]; - - constructor(configuration) { - this._maximumSamplesCount = configuration.maximumSamplesCount || this._maximumSamplesCount; - } - - /** - * Compose object with latency information of recently used API endpoints. - * - * @return {Object} Object with request query key/value pairs. - */ - operationsLatencyForRequest() { - const latencies = {}; - - Object.keys(this._latencies).forEach((endpointName) => { - const operationLatencies = this._latencies[endpointName]; - const averageLatency = this._averageLatency(operationLatencies); - - if (averageLatency > 0) { - latencies[`l_${endpointName}`] = averageLatency; - } - }); - - return latencies; - } - - startLatencyMeasure(operationType, identifier) { - if (this._telemetryExcludeOperations.includes(operationType) || !identifier) { - return; - } - - this._trackedLatencies[identifier] = Date.now(); - } - - stopLatencyMeasure(operationType, identifier) { - if (this._telemetryExcludeOperations.includes(operationType) || !identifier) { - return; - } - - const endpointName = this._endpointName(operationType); - /** @type Array */ - let endpointLatencies = this._latencies[endpointName]; - const startDate = this._trackedLatencies[identifier]; - - if (!endpointLatencies) { - this._latencies[endpointName] = []; - endpointLatencies = this._latencies[endpointName]; - } - - endpointLatencies.push(Date.now() - startDate); - - // Truncate samples count if there is more then configured. - if (endpointLatencies.length > this._maximumSamplesCount) { - endpointLatencies.splice(0, endpointLatencies.length - this._maximumSamplesCount); - } - - delete this._trackedLatencies[identifier]; - } - - _averageLatency(latencies) { - const arrayReduce = (accumulatedLatency, latency) => accumulatedLatency + latency; - - return Math.floor(latencies.reduce(arrayReduce, 0) / latencies.length); - } - - _endpointName(operationType) { - let operation = null; - - switch (operationType) { - case operationConstants.PNPublishOperation: - operation = 'pub'; - break; - case operationConstants.PNSignalOperation: - operation = 'sig'; - break; - case operationConstants.PNHistoryOperation: - case operationConstants.PNFetchMessagesOperation: - case operationConstants.PNDeleteMessagesOperation: - case operationConstants.PNMessageCounts: - operation = 'hist'; - break; - case operationConstants.PNUnsubscribeOperation: - case operationConstants.PNWhereNowOperation: - case operationConstants.PNHereNowOperation: - case operationConstants.PNHeartbeatOperation: - case operationConstants.PNSetStateOperation: - case operationConstants.PNGetStateOperation: - operation = 'pres'; - break; - case operationConstants.PNAddChannelsToGroupOperation: - case operationConstants.PNRemoveChannelsFromGroupOperation: - case operationConstants.PNChannelGroupsOperation: - case operationConstants.PNRemoveGroupOperation: - case operationConstants.PNChannelsForGroupOperation: - operation = 'cg'; - break; - case operationConstants.PNPushNotificationEnabledChannelsOperation: - case operationConstants.PNRemoveAllPushNotificationsOperation: - operation = 'push'; - break; - case operationConstants.PNCreateUserOperation: - case operationConstants.PNUpdateUserOperation: - case operationConstants.PNDeleteUserOperation: - case operationConstants.PNGetUserOperation: - case operationConstants.PNGetUsersOperation: - case operationConstants.PNCreateSpaceOperation: - case operationConstants.PNUpdateSpaceOperation: - case operationConstants.PNDeleteSpaceOperation: - case operationConstants.PNGetSpaceOperation: - case operationConstants.PNGetSpacesOperation: - case operationConstants.PNGetMembersOperation: - case operationConstants.PNUpdateMembersOperation: - case operationConstants.PNGetMembershipsOperation: - case operationConstants.PNUpdateMembershipsOperation: - operation = 'obj'; - break; - case operationConstants.PNAddMessageActionOperation: - case operationConstants.PNRemoveMessageActionOperation: - case operationConstants.PNGetMessageActionsOperation: - operation = 'msga'; - break; - case operationConstants.PNAccessManagerGrant: - case operationConstants.PNAccessManagerAudit: - operation = 'pam'; - break; - case operationConstants.PNAccessManagerGrantToken: - case operationConstants.PNAccessManagerRevokeToken: - operation = 'pamv3'; - break; - default: - operation = 'time'; - break; - } - - return operation; - } -} diff --git a/src/core/components/token_manager.js b/src/core/components/token_manager.js deleted file mode 100644 index 72dfa8617..000000000 --- a/src/core/components/token_manager.js +++ /dev/null @@ -1,157 +0,0 @@ -export default class { - _config; - - _cbor; - - _token; - - constructor(config, cbor) { - this._config = config; - this._cbor = cbor; - } - - setToken(token) { - if (token && token.length > 0) { - this._token = token; - } else { - this._token = undefined; - } - } - - getToken() { - return this._token; - } - - extractPermissions(permissions) { - const permissionsResult = { - read: false, - write: false, - manage: false, - delete: false, - get: false, - update: false, - join: false, - }; - - /* eslint-disable */ - - if ((permissions & 128) === 128) { - permissionsResult.join = true; - } - - if ((permissions & 64) === 64) { - permissionsResult.update = true; - } - - if ((permissions & 32) === 32) { - permissionsResult.get = true; - } - - if ((permissions & 8) === 8) { - permissionsResult.delete = true; - } - - if ((permissions & 4) === 4) { - permissionsResult.manage = true; - } - - if ((permissions & 2) === 2) { - permissionsResult.write = true; - } - - if ((permissions & 1) === 1) { - permissionsResult.read = true; - } - - /* eslint-enable */ - - return permissionsResult; - } - - parseToken(tokenString) { - const parsed = this._cbor.decodeToken(tokenString); - - if (parsed !== undefined) { - const uuidResourcePermissions = parsed.res.uuid ? Object.keys(parsed.res.uuid) : []; - const channelResourcePermissions = Object.keys(parsed.res.chan); - const groupResourcePermissions = Object.keys(parsed.res.grp); - const uuidPatternPermissions = parsed.pat.uuid ? Object.keys(parsed.pat.uuid) : []; - const channelPatternPermissions = Object.keys(parsed.pat.chan); - const groupPatternPermissions = Object.keys(parsed.pat.grp); - - const result = { - version: parsed.v, - timestamp: parsed.t, - ttl: parsed.ttl, - authorized_uuid: parsed.uuid, - }; - - const uuidResources = uuidResourcePermissions.length > 0; - const channelResources = channelResourcePermissions.length > 0; - const groupResources = groupResourcePermissions.length > 0; - - if (uuidResources || channelResources || groupResources) { - result.resources = {}; - - if (uuidResources) { - result.resources.uuids = {}; - uuidResourcePermissions.forEach((id) => { - result.resources.uuids[id] = this.extractPermissions(parsed.res.uuid[id]); - }); - } - - if (channelResources) { - result.resources.channels = {}; - channelResourcePermissions.forEach((id) => { - result.resources.channels[id] = this.extractPermissions(parsed.res.chan[id]); - }); - } - - if (groupResources) { - result.resources.groups = {}; - groupResourcePermissions.forEach((id) => { - result.resources.groups[id] = this.extractPermissions(parsed.res.grp[id]); - }); - } - } - - const uuidPatterns = uuidPatternPermissions.length > 0; - const channelPatterns = channelPatternPermissions.length > 0; - const groupPatterns = groupPatternPermissions.length > 0; - - if (uuidPatterns || channelPatterns || groupPatterns) { - result.patterns = {}; - - if (uuidPatterns) { - result.patterns.uuids = {}; - uuidPatternPermissions.forEach((id) => { - result.patterns.uuids[id] = this.extractPermissions(parsed.pat.uuid[id]); - }); - } - - if (channelPatterns) { - result.patterns.channels = {}; - channelPatternPermissions.forEach((id) => { - result.patterns.channels[id] = this.extractPermissions(parsed.pat.chan[id]); - }); - } - - if (groupPatterns) { - result.patterns.groups = {}; - groupPatternPermissions.forEach((id) => { - result.patterns.groups[id] = this.extractPermissions(parsed.pat.grp[id]); - }); - } - } - - if (Object.keys(parsed.meta).length > 0) { - result.meta = parsed.meta; - } - - result.signature = parsed.sig; - - return result; - } - return undefined; - } -} diff --git a/src/core/components/token_manager.ts b/src/core/components/token_manager.ts new file mode 100644 index 000000000..97c5944d3 --- /dev/null +++ b/src/core/components/token_manager.ts @@ -0,0 +1,333 @@ +/** + * PubNub Access Token Manager module. + */ + +import Cbor from '../../cbor/common'; +import { Payload } from '../types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +type Token = { + /** + * Token version. + */ + version: number; + + /** + * Token generation date time. + */ + timestamp: number; + + /** + * Maximum duration (in minutes) during which token will be valid. + */ + ttl: number; + + /** + * Permissions granted to specific resources. + */ + resources?: Partial>>; + + /** + * Permissions granted to resources which match specified regular expression. + */ + patterns?: Partial>>; + + /** + * The uuid that is exclusively authorized to use this token to make API requests. + */ + authorized_uuid?: string; + + /** + * PAM token content signature. + */ + signature: ArrayBuffer; + + /** + * Additional information which has been added to the token. + */ + meta?: Payload; +}; + +/** + * Granted resource permissions. + * + * **Note:** Following operations doesn't require any permissions: + * - unsubscribe from channel / channel group + * - where now + */ +type Permissions = { + /** + * Resource read permission. + * + * Read permission required for: + * - subscribe to channel / channel group (including presence versions `-pnpres`) + * - here now + * - get presence state + * - set presence state + * - fetch history + * - fetch messages count + * - list shared files + * - download shared file + * - enable / disable push notifications + * - get message actions + * - get history with message actions + */ + read: boolean; + + /** + * Resource write permission. + * + * Write permission required for: + * - publish message / signal + * - share file + * - add message actions + */ + write: boolean; + + /** + * Resource manage permission. + * + * Manage permission required for: + * - add / remove channels to / from the channel group + * - list channels in group + * - remove channel group + * - set / remove channel members + */ + manage: boolean; + + /** + * Resource delete permission. + * + * Delete permission required for: + * - delete messages from history + * - delete shared file + * - delete user metadata + * - delete channel metadata + * - remove message action + */ + delete: boolean; + + /** + * Resource get permission. + * + * Get permission required for: + * - get user metadata + * - get channel metadata + * - get channel members + */ + get: boolean; + + /** + * Resource update permission. + * + * Update permissions required for: + * - set user metadata + * - set channel metadata + * - set / remove user membership + */ + update: boolean; + + /** + * Resource `join` permission. + * + * `Join` permission required for: + * - set / remove channel members + */ + join: boolean; +}; + +/** + * Raw parsed token. + * + * Representation of data stored in base64-encoded access token. + */ +type RawToken = { + /** + * Token version. + */ + v: number; + + /** + * Token generation date time. + */ + t: number; + + /** + * Maximum duration (in minutes) during which token will be valid. + */ + ttl: number; + + /** + * Permissions granted to specific resources. + */ + res: Record<'chan' | 'grp' | 'uuid', Record>; + + /** + * Permissions granted to resources which match specified regular expression. + */ + pat: Record<'chan' | 'grp' | 'uuid', Record>; + + /** + * The uuid that is exclusively authorized to use this token to make API requests. + */ + uuid?: string; + + /** + * PAM token content signature. + */ + sig: ArrayBuffer; + + /** + * Additional information which has been added to the token. + */ + meta?: Payload; +}; +// endregion + +/** + * REST API access token manager. + * + * Manager maintains active access token and let parse it to get information about permissions. + */ +export class TokenManager { + /** + * Currently used REST API Access token. + */ + private token?: string; + + constructor(private readonly cbor: Cbor) {} + + /** + * Update REST API access token. + * + * **Note:** Token will be applied only for next requests and won't affect ongoing requests. + * + * @param [token] - Access token which should be used to access PubNub REST API. + */ + public setToken(token?: string) { + if (token && token.length > 0) this.token = token; + else this.token = undefined; + } + + /** + * REST API access token. + * + * @returns Previously configured REST API access token. + */ + public getToken() { + return this.token; + } + + /** + * Parse Base64-encoded access token. + * + * @param tokenString - Base64-encoded access token. + * + * @returns Information about resources and permissions which has been granted for them. + */ + public parseToken(tokenString: string) { + const parsed = this.cbor.decodeToken(tokenString) as RawToken; + + if (parsed !== undefined) { + const uuidResourcePermissions = parsed.res.uuid ? Object.keys(parsed.res.uuid) : []; + const channelResourcePermissions = Object.keys(parsed.res.chan); + const groupResourcePermissions = Object.keys(parsed.res.grp); + const uuidPatternPermissions = parsed.pat.uuid ? Object.keys(parsed.pat.uuid) : []; + const channelPatternPermissions = Object.keys(parsed.pat.chan); + const groupPatternPermissions = Object.keys(parsed.pat.grp); + + const result: Token = { + version: parsed.v, + timestamp: parsed.t, + ttl: parsed.ttl, + authorized_uuid: parsed.uuid, + signature: parsed.sig, + }; + + const uuidResources = uuidResourcePermissions.length > 0; + const channelResources = channelResourcePermissions.length > 0; + const groupResources = groupResourcePermissions.length > 0; + + if (uuidResources || channelResources || groupResources) { + result.resources = {}; + + if (uuidResources) { + const uuids: typeof result.resources.uuids = (result.resources.uuids = {}); + uuidResourcePermissions.forEach((id) => (uuids[id] = this.extractPermissions(parsed.res.uuid[id]))); + } + + if (channelResources) { + const channels: typeof result.resources.channels = (result.resources.channels = {}); + channelResourcePermissions.forEach((id) => (channels[id] = this.extractPermissions(parsed.res.chan[id]))); + } + + if (groupResources) { + const groups: typeof result.resources.groups = (result.resources.groups = {}); + groupResourcePermissions.forEach((id) => (groups[id] = this.extractPermissions(parsed.res.grp[id]))); + } + } + + const uuidPatterns = uuidPatternPermissions.length > 0; + const channelPatterns = channelPatternPermissions.length > 0; + const groupPatterns = groupPatternPermissions.length > 0; + + if (uuidPatterns || channelPatterns || groupPatterns) { + result.patterns = {}; + + if (uuidPatterns) { + const uuids: typeof result.patterns.uuids = (result.patterns.uuids = {}); + uuidPatternPermissions.forEach((id) => (uuids[id] = this.extractPermissions(parsed.pat.uuid[id]))); + } + + if (channelPatterns) { + const channels: typeof result.patterns.channels = (result.patterns.channels = {}); + channelPatternPermissions.forEach((id) => (channels[id] = this.extractPermissions(parsed.pat.chan[id]))); + } + + if (groupPatterns) { + const groups: typeof result.patterns.groups = (result.patterns.groups = {}); + groupPatternPermissions.forEach((id) => (groups[id] = this.extractPermissions(parsed.pat.grp[id]))); + } + } + + if (parsed.meta && Object.keys(parsed.meta).length > 0) result.meta = parsed.meta; + + return result; + } + + return undefined; + } + + /** + * Extract resource access permission information. + * + * @param permissions - Bit-encoded resource permissions. + * + * @returns Human-readable resource permissions. + */ + private extractPermissions(permissions: number) { + const permissionsResult: Permissions = { + read: false, + write: false, + manage: false, + delete: false, + get: false, + update: false, + join: false, + }; + + if ((permissions & 128) === 128) permissionsResult.join = true; + if ((permissions & 64) === 64) permissionsResult.update = true; + if ((permissions & 32) === 32) permissionsResult.get = true; + if ((permissions & 8) === 8) permissionsResult.delete = true; + if ((permissions & 4) === 4) permissionsResult.manage = true; + if ((permissions & 2) === 2) permissionsResult.write = true; + if ((permissions & 1) === 1) permissionsResult.read = true; + + return permissionsResult; + } +} diff --git a/src/core/components/uuid.js b/src/core/components/uuid.ts similarity index 72% rename from src/core/components/uuid.js rename to src/core/components/uuid.ts index a22f987f7..023de232a 100644 --- a/src/core/components/uuid.js +++ b/src/core/components/uuid.ts @@ -5,6 +5,7 @@ export default { if (uuidGenerator.uuid) { return uuidGenerator.uuid(); } + // @ts-expect-error Depending on module type it may be callable. return uuidGenerator(); }, }; diff --git a/src/core/constants/categories.js b/src/core/constants/categories.js deleted file mode 100644 index bf48a79d1..000000000 --- a/src/core/constants/categories.js +++ /dev/null @@ -1,36 +0,0 @@ -/* */ -export default { - // SDK will announce when the network appears to be connected again. - PNNetworkUpCategory: 'PNNetworkUpCategory', - - // SDK will announce when the network appears to down. - PNNetworkDownCategory: 'PNNetworkDownCategory', - - // call failed when network was unable to complete the call. - PNNetworkIssuesCategory: 'PNNetworkIssuesCategory', - - // network call timed out - PNTimeoutCategory: 'PNTimeoutCategory', - - // server responded with bad response - PNBadRequestCategory: 'PNBadRequestCategory', - - // server responded with access denied - PNAccessDeniedCategory: 'PNAccessDeniedCategory', - - // something strange happened; please check the logs. - PNUnknownCategory: 'PNUnknownCategory', - - // on reconnection - PNReconnectedCategory: 'PNReconnectedCategory', - - PNConnectedCategory: 'PNConnectedCategory', - - PNRequestMessageCountExceededCategory: 'PNRequestMessageCountExceededCategory', - - PNDisconnectedCategory: 'PNDisconnectedCategory', - - PNConnectionErrorCategory: 'PNConnectionErrorCategory', - - PNDisconnectedUnexpectedlyCategory: 'PNDisconnectedUnexpectedlyCategory', -}; diff --git a/src/core/constants/categories.ts b/src/core/constants/categories.ts new file mode 100644 index 000000000..6550b4538 --- /dev/null +++ b/src/core/constants/categories.ts @@ -0,0 +1,99 @@ +/** + * Request processing status categories. + */ +enum StatusCategory { + /** + * Call failed when network was unable to complete the call. + */ + PNNetworkIssuesCategory = 'PNNetworkIssuesCategory', + + /** + * Network call timed out. + */ + PNTimeoutCategory = 'PNTimeoutCategory', + + /** + * Request has been cancelled. + */ + PNCancelledCategory = 'PNCancelledCategory', + + /** + * Server responded with bad response. + */ + PNBadRequestCategory = 'PNBadRequestCategory', + + /** + * Server responded with access denied. + */ + PNAccessDeniedCategory = 'PNAccessDeniedCategory', + + /** + * Incomplete parameters provided for used endpoint. + */ + PNValidationErrorCategory = 'PNValidationErrorCategory', + + /** + * PubNub request acknowledgment status. + * + * Some API endpoints respond with request processing status w/o useful data. + */ + PNAcknowledgmentCategory = 'PNAcknowledgmentCategory', + + /** + * Something strange happened; please check the logs. + */ + PNUnknownCategory = 'PNUnknownCategory', + + // -------------------------------------------------------- + // --------------------- Network status ------------------- + // -------------------------------------------------------- + + /** + * SDK will announce when the network appears to be connected again. + */ + PNNetworkUpCategory = 'PNNetworkUpCategory', + + /** + * SDK will announce when the network appears to down. + */ + PNNetworkDownCategory = 'PNNetworkDownCategory', + + // -------------------------------------------------------- + // -------------------- Real-time events ------------------ + // -------------------------------------------------------- + + /** + * PubNub client reconnected to the real-time updates stream. + */ + PNReconnectedCategory = 'PNReconnectedCategory', + + /** + * PubNub client connected to the real-time updates stream. + */ + PNConnectedCategory = 'PNConnectedCategory', + + /** + * Received real-time updates exceed specified threshold. + * + * After temporary disconnection and catchup, this category means that potentially some + * real-time updates have been pushed into `storage` and need to be requested separately. + */ + PNRequestMessageCountExceededCategory = 'PNRequestMessageCountExceededCategory', + + /** + * PubNub client disconnected from the real-time updates streams. + */ + PNDisconnectedCategory = 'PNDisconnectedCategory', + + /** + * PubNub client wasn't able to connect to the real-time updates streams. + */ + PNConnectionErrorCategory = 'PNConnectionErrorCategory', + + /** + * PubNub client unexpectedly disconnected from the real-time updates streams. + */ + PNDisconnectedUnexpectedlyCategory = 'PNDisconnectedUnexpectedlyCategory', +} + +export default StatusCategory; diff --git a/src/core/constants/operations.js b/src/core/constants/operations.js deleted file mode 100644 index 7d1ffcaca..000000000 --- a/src/core/constants/operations.js +++ /dev/null @@ -1,92 +0,0 @@ -/* */ -export default { - PNTimeOperation: 'PNTimeOperation', - - PNHistoryOperation: 'PNHistoryOperation', - PNDeleteMessagesOperation: 'PNDeleteMessagesOperation', - PNFetchMessagesOperation: 'PNFetchMessagesOperation', - PNMessageCounts: 'PNMessageCountsOperation', - - // pubsub - PNSubscribeOperation: 'PNSubscribeOperation', - PNUnsubscribeOperation: 'PNUnsubscribeOperation', - PNPublishOperation: 'PNPublishOperation', - PNSignalOperation: 'PNSignalOperation', - - // Actions API - PNAddMessageActionOperation: 'PNAddActionOperation', - PNRemoveMessageActionOperation: 'PNRemoveMessageActionOperation', - PNGetMessageActionsOperation: 'PNGetMessageActionsOperation', - - // Objects API - PNCreateUserOperation: 'PNCreateUserOperation', - PNUpdateUserOperation: 'PNUpdateUserOperation', - PNDeleteUserOperation: 'PNDeleteUserOperation', - PNGetUserOperation: 'PNGetUsersOperation', - PNGetUsersOperation: 'PNGetUsersOperation', - PNCreateSpaceOperation: 'PNCreateSpaceOperation', - PNUpdateSpaceOperation: 'PNUpdateSpaceOperation', - PNDeleteSpaceOperation: 'PNDeleteSpaceOperation', - PNGetSpaceOperation: 'PNGetSpacesOperation', - PNGetSpacesOperation: 'PNGetSpacesOperation', - PNGetMembersOperation: 'PNGetMembersOperation', - PNUpdateMembersOperation: 'PNUpdateMembersOperation', - PNGetMembershipsOperation: 'PNGetMembershipsOperation', - PNUpdateMembershipsOperation: 'PNUpdateMembershipsOperation', - - // File Upload API v1 - PNListFilesOperation: 'PNListFilesOperation', - PNGenerateUploadUrlOperation: 'PNGenerateUploadUrlOperation', - PNPublishFileOperation: 'PNPublishFileOperation', - PNGetFileUrlOperation: 'PNGetFileUrlOperation', - PNDownloadFileOperation: 'PNDownloadFileOperation', - - // Objects API v2 - // UUID - PNGetAllUUIDMetadataOperation: 'PNGetAllUUIDMetadataOperation', - PNGetUUIDMetadataOperation: 'PNGetUUIDMetadataOperation', - PNSetUUIDMetadataOperation: 'PNSetUUIDMetadataOperation', - PNRemoveUUIDMetadataOperation: 'PNRemoveUUIDMetadataOperation', - // channel - PNGetAllChannelMetadataOperation: 'PNGetAllChannelMetadataOperation', - PNGetChannelMetadataOperation: 'PNGetChannelMetadataOperation', - PNSetChannelMetadataOperation: 'PNSetChannelMetadataOperation', - PNRemoveChannelMetadataOperation: 'PNRemoveChannelMetadataOperation', - // member - // PNGetMembersOperation: 'PNGetMembersOperation', - PNSetMembersOperation: 'PNSetMembersOperation', - // PNGetMembershipsOperation: 'PNGetMembersOperation', - PNSetMembershipsOperation: 'PNSetMembershipsOperation', - - // push - PNPushNotificationEnabledChannelsOperation: 'PNPushNotificationEnabledChannelsOperation', - PNRemoveAllPushNotificationsOperation: 'PNRemoveAllPushNotificationsOperation', - // - - // presence - PNWhereNowOperation: 'PNWhereNowOperation', - PNSetStateOperation: 'PNSetStateOperation', - PNHereNowOperation: 'PNHereNowOperation', - PNGetStateOperation: 'PNGetStateOperation', - PNHeartbeatOperation: 'PNHeartbeatOperation', - // - - // channel group - PNChannelGroupsOperation: 'PNChannelGroupsOperation', - PNRemoveGroupOperation: 'PNRemoveGroupOperation', - PNChannelsForGroupOperation: 'PNChannelsForGroupOperation', - PNAddChannelsToGroupOperation: 'PNAddChannelsToGroupOperation', - PNRemoveChannelsFromGroupOperation: 'PNRemoveChannelsFromGroupOperation', - // - - // PAM - PNAccessManagerGrant: 'PNAccessManagerGrant', - PNAccessManagerGrantToken: 'PNAccessManagerGrantToken', - PNAccessManagerAudit: 'PNAccessManagerAudit', - PNAccessManagerRevokeToken: 'PNAccessManagerRevokeToken', - // - - // subscription utilities - PNHandshakeOperation: 'PNHandshakeOperation', - PNReceiveMessagesOperation: 'PNReceiveMessagesOperation', -}; diff --git a/src/core/constants/operations.ts b/src/core/constants/operations.ts new file mode 100644 index 000000000..196dc98cd --- /dev/null +++ b/src/core/constants/operations.ts @@ -0,0 +1,298 @@ +/* */ +enum RequestOperation { + // -------------------------------------------------------- + // ---------------------- Publish API --------------------- + // -------------------------------------------------------- + /** + * Data publish REST API operation. + */ + PNPublishOperation = 'PNPublishOperation', + + /** + * Signal sending REST API operation. + */ + PNSignalOperation = 'PNSignalOperation', + + // -------------------------------------------------------- + // --------------------- Subscribe API -------------------- + // -------------------------------------------------------- + /** + * Subscribe for real-time updates REST API operation. + * + * User's presence change on specified entities will trigger `join` event. + */ + PNSubscribeOperation = 'PNSubscribeOperation', + + /** + * Unsubscribe from real-time updates REST API operation. + * + * User's presence change on specified entities will trigger `leave` event. + */ + PNUnsubscribeOperation = 'PNUnsubscribeOperation', + + // -------------------------------------------------------- + // --------------------- Presence API --------------------- + // -------------------------------------------------------- + + /** + * Fetch user's presence information REST API operation. + */ + PNWhereNowOperation = 'PNWhereNowOperation', + + /** + * Fetch channel's presence information REST API operation. + */ + PNHereNowOperation = 'PNHereNowOperation', + + /** + * Fetch global presence information REST API operation. + */ + PNGlobalHereNowOperation = 'PNGlobalHereNowOperation', + + /** + * Update user's information associated with specified channel REST API operation. + */ + PNSetStateOperation = 'PNSetStateOperation', + + /** + * Fetch user's information associated with the specified channel REST API operation. + */ + PNGetStateOperation = 'PNGetStateOperation', + + /** + * Announce presence on managed channels REST API operation. + */ + PNHeartbeatOperation = 'PNHeartbeatOperation', + + // -------------------------------------------------------- + // ----------------- Message Reaction API ----------------- + // -------------------------------------------------------- + + /** + * Add a reaction to the specified message REST API operation. + */ + PNAddMessageActionOperation = 'PNAddActionOperation', + + /** + * Remove reaction from the specified message REST API operation. + */ + PNRemoveMessageActionOperation = 'PNRemoveMessageActionOperation', + + /** + * Fetch reactions for specific message REST API operation. + */ + PNGetMessageActionsOperation = 'PNGetMessageActionsOperation', + + PNTimeOperation = 'PNTimeOperation', + + // -------------------------------------------------------- + // ---------------------- Storage API --------------------- + // -------------------------------------------------------- + + /** + * Channel history REST API operation. + */ + PNHistoryOperation = 'PNHistoryOperation', + + /** + * Delete messages from channel history REST API operation. + */ + PNDeleteMessagesOperation = 'PNDeleteMessagesOperation', + + /** + * History for channels REST API operation. + */ + PNFetchMessagesOperation = 'PNFetchMessagesOperation', + + /** + * Number of messages for channels in specified time frame REST API operation. + */ + PNMessageCounts = 'PNMessageCountsOperation', + + // -------------------------------------------------------- + // -------------------- App Context API ------------------- + // -------------------------------------------------------- + + /** + * Fetch users metadata REST API operation. + */ + PNGetAllUUIDMetadataOperation = 'PNGetAllUUIDMetadataOperation', + + /** + * Fetch user metadata REST API operation. + */ + PNGetUUIDMetadataOperation = 'PNGetUUIDMetadataOperation', + + /** + * Set user metadata REST API operation. + */ + PNSetUUIDMetadataOperation = 'PNSetUUIDMetadataOperation', + + /** + * Remove user metadata REST API operation. + */ + PNRemoveUUIDMetadataOperation = 'PNRemoveUUIDMetadataOperation', + + /** + * Fetch channels metadata REST API operation. + */ + PNGetAllChannelMetadataOperation = 'PNGetAllChannelMetadataOperation', + + /** + * Fetch channel metadata REST API operation. + */ + PNGetChannelMetadataOperation = 'PNGetChannelMetadataOperation', + + /** + * Set channel metadata REST API operation. + */ + PNSetChannelMetadataOperation = 'PNSetChannelMetadataOperation', + + /** + * Remove channel metadata REST API operation. + */ + PNRemoveChannelMetadataOperation = 'PNRemoveChannelMetadataOperation', + + /** + * Fetch channel members REST API operation. + */ + PNGetMembersOperation = 'PNGetMembersOperation', + + /** + * Update channel members REST API operation. + */ + PNSetMembersOperation = 'PNSetMembersOperation', + + /** + * Fetch channel memberships REST API operation. + */ + PNGetMembershipsOperation = 'PNGetMembershipsOperation', + + /** + * Update channel memberships REST API operation. + */ + PNSetMembershipsOperation = 'PNSetMembershipsOperation', + + // -------------------------------------------------------- + // -------------------- File Upload API ------------------- + // -------------------------------------------------------- + + /** + * Fetch list of files sent to the channel REST API operation. + */ + PNListFilesOperation = 'PNListFilesOperation', + + /** + * Retrieve file upload URL REST API operation. + */ + PNGenerateUploadUrlOperation = 'PNGenerateUploadUrlOperation', + + /** + * Upload file to the channel REST API operation. + */ + PNPublishFileOperation = 'PNPublishFileOperation', + + /** + * Publish File Message to the channel REST API operation. + */ + PNPublishFileMessageOperation = 'PNPublishFileMessageOperation', + + /** + * Retrieve file download URL REST API operation. + */ + PNGetFileUrlOperation = 'PNGetFileUrlOperation', + + /** + * Download file from the channel REST API operation. + */ + PNDownloadFileOperation = 'PNDownloadFileOperation', + + /** + * Delete file sent to the channel REST API operation. + */ + PNDeleteFileOperation = 'PNDeleteFileOperation', + + // -------------------------------------------------------- + // -------------------- Mobile Push API ------------------- + // -------------------------------------------------------- + + /** + * Register channels with device push notifications REST API operation. + */ + PNAddPushNotificationEnabledChannelsOperation = 'PNAddPushNotificationEnabledChannelsOperation', + + /** + * Unregister channels with device push notifications REST API operation. + */ + PNRemovePushNotificationEnabledChannelsOperation = 'PNRemovePushNotificationEnabledChannelsOperation', + + /** + * Fetch list of channels with enabled push notifications for device REST API operation. + */ + PNPushNotificationEnabledChannelsOperation = 'PNPushNotificationEnabledChannelsOperation', + + /** + * Disable push notifications for device REST API operation. + */ + PNRemoveAllPushNotificationsOperation = 'PNRemoveAllPushNotificationsOperation', + + // -------------------------------------------------------- + // ------------------ Channel Groups API ------------------ + // -------------------------------------------------------- + + /** + * Fetch channels groups list REST API operation. + */ + PNChannelGroupsOperation = 'PNChannelGroupsOperation', + + /** + * Remove specified channel group REST API operation. + */ + PNRemoveGroupOperation = 'PNRemoveGroupOperation', + + /** + * Fetch list of channels for the specified channel group REST API operation. + */ + PNChannelsForGroupOperation = 'PNChannelsForGroupOperation', + + /** + * Add list of channels to the specified channel group REST API operation. + */ + PNAddChannelsToGroupOperation = 'PNAddChannelsToGroupOperation', + + /** + * Remove list of channels from the specified channel group REST API operation. + */ + PNRemoveChannelsFromGroupOperation = 'PNRemoveChannelsFromGroupOperation', + + // -------------------------------------------------------- + // ----------------------- PAM API ------------------------ + // -------------------------------------------------------- + + /** + * Generate authorized token REST API operation. + */ + PNAccessManagerGrant = 'PNAccessManagerGrant', + + /** + * Generate authorized token REST API operation. + */ + PNAccessManagerGrantToken = 'PNAccessManagerGrantToken', + + PNAccessManagerAudit = 'PNAccessManagerAudit', + + /** + * Revoke authorized token REST API operation. + */ + PNAccessManagerRevokeToken = 'PNAccessManagerRevokeToken', + // + + // -------------------------------------------------------- + // ---------------- Subscription Utility ------------------ + // -------------------------------------------------------- + + PNHandshakeOperation = 'PNHandshakeOperation', + PNReceiveMessagesOperation = 'PNReceiveMessagesOperation', +} + +export default RequestOperation; diff --git a/src/core/endpoints/access_manager/audit.js b/src/core/endpoints/access_manager/audit.js deleted file mode 100644 index dcbab0a74..000000000 --- a/src/core/endpoints/access_manager/audit.js +++ /dev/null @@ -1,49 +0,0 @@ -/* */ - -import operationConstants from '../../constants/operations'; - -export function getOperation() { - return operationConstants.PNAccessManagerAudit; -} - -export function validateParams(modules) { - const { config } = modules; - - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules) { - const { config } = modules; - return `/v2/auth/audit/sub-key/${config.subscribeKey}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return false; -} - -export function prepareParams(modules, incomingParams) { - const { channel, channelGroup, authKeys = [] } = incomingParams; - const params = {}; - - if (channel) { - params.channel = channel; - } - - if (channelGroup) { - params['channel-group'] = channelGroup; - } - - if (authKeys.length > 0) { - params.auth = authKeys.join(','); - } - - return params; -} - -export function handleResponse(modules, serverResponse) { - return serverResponse.payload; -} diff --git a/src/core/endpoints/access_manager/audit.ts b/src/core/endpoints/access_manager/audit.ts new file mode 100644 index 000000000..e9aa8b8fd --- /dev/null +++ b/src/core/endpoints/access_manager/audit.ts @@ -0,0 +1,110 @@ +/** + * PAM Audit REST API module. + */ + +import { createValidationError, PubNubError } from '../../../errors/pubnub-error'; +import { TransportResponse } from '../../types/transport-response'; +import { PubNubAPIError } from '../../../errors/pubnub-api-error'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import * as PAM from '../../types/api/access-panager'; +import { KeySet, Query } from '../../types/api'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Auth keys for which permissions should be audited. + */ +const AUTH_KEYS: string[] = []; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = PAM.AuditParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Permissions audit human-readable result. + */ + message: string; + + /** + * Retrieved permissions information. + */ + payload: PAM.PermissionsResponse; + + /** + * Name of the service which provided response. + */ + service: string; +}; +// endregion + +/** + * Permissions audit request. + */ +export class AuditRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + + // Apply default request parameters. + this.parameters.authKeys ??= AUTH_KEYS; + } + + operation(): RequestOperation { + return RequestOperation.PNAccessManagerAudit; + } + + validate(): string | undefined { + if (!this.parameters.keySet.subscribeKey) return 'Missing Subscribe Key'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + return serviceResponse.payload; + } + + protected get path(): string { + return `/v2/auth/audit/sub-key/${this.parameters.keySet.subscribeKey}`; + } + + protected get queryParameters(): Query { + const { channel, channelGroup, authKeys } = this.parameters; + + return { + ...(channel ? { channel } : {}), + ...(channelGroup ? { 'channel-group': channelGroup } : {}), + ...(authKeys && authKeys.length ? { auth: authKeys.join(',') } : {}), + }; + } +} diff --git a/src/core/endpoints/access_manager/grant.js b/src/core/endpoints/access_manager/grant.js deleted file mode 100644 index 9d63f84a8..000000000 --- a/src/core/endpoints/access_manager/grant.js +++ /dev/null @@ -1,84 +0,0 @@ -/* */ -import operationConstants from '../../constants/operations'; - -export function getOperation() { - return operationConstants.PNAccessManagerGrant; -} - -export function validateParams(modules, incomingParams) { - const { config } = modules; - - if (!config.subscribeKey) return 'Missing Subscribe Key'; - if (!config.publishKey) return 'Missing Publish Key'; - if (!config.secretKey) return 'Missing Secret Key'; - if (incomingParams.uuids != null && !incomingParams.authKeys) { - return 'authKeys are required for grant request on uuids'; - } - if (incomingParams.uuids != null && (incomingParams.channels != null || incomingParams.channelGroups != null)) { - return 'Both channel/channelgroup and uuid cannot be used in the same request'; - } -} - -export function getURL(modules) { - const { config } = modules; - return `/v2/auth/grant/sub-key/${config.subscribeKey}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return false; -} - -export function prepareParams(modules, incomingParams) { - const { - channels = [], - channelGroups = [], - uuids = [], - ttl, - read = false, - write = false, - manage = false, - get = false, - join = false, - update = false, - authKeys = [], - } = incomingParams; - const deleteParam = incomingParams.delete; - const params = {}; - - params.r = read ? '1' : '0'; - params.w = write ? '1' : '0'; - params.m = manage ? '1' : '0'; - params.d = deleteParam ? '1' : '0'; - params.g = get ? '1' : '0'; - params.j = join ? '1' : '0'; - params.u = update ? '1' : '0'; - - if (channels.length > 0) { - params.channel = channels.join(','); - } - - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); - } - - if (authKeys.length > 0) { - params.auth = authKeys.join(','); - } - - if (uuids.length > 0) { - params['target-uuid'] = uuids.join(','); - } - - if (ttl || ttl === 0) { - params.ttl = ttl; - } - return params; -} - -export function handleResponse() { - return {}; -} diff --git a/src/core/endpoints/access_manager/grant.ts b/src/core/endpoints/access_manager/grant.ts new file mode 100644 index 000000000..43b98208d --- /dev/null +++ b/src/core/endpoints/access_manager/grant.ts @@ -0,0 +1,186 @@ +/** + * PAM Grant REST API module. + */ + +import { createValidationError, PubNubError } from '../../../errors/pubnub-error'; +import { TransportResponse } from '../../types/transport-response'; +import { PubNubAPIError } from '../../../errors/pubnub-api-error'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import * as PAM from '../../types/api/access-panager'; +import { KeySet, Query } from '../../types/api'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Resources `read` permission. + */ +const READ_PERMISSION = false; + +/** + * Resources `write` permission. + */ +const WRITE_PERMISSION = false; + +/** + * Resources `delete` permission. + */ +const DELETE_PERMISSION = false; + +/** + * Resources `get` permission. + */ +const GET_PERMISSION = false; + +/** + * Resources `update` permission. + */ +const UPDATE_PERMISSION = false; + +/** + * Resources `manage` permission. + */ +const MANAGE_PERMISSION = false; + +/** + * Resources `join` permission. + */ +const JOIN_PERMISSION = false; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = PAM.GrantParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Permissions grant human-readable result. + */ + message: string; + + /** + * Granted permissions' information. + */ + payload: PAM.PermissionsResponse; + + /** + * Name of the service which provided response. + */ + service: string; +}; +// endregion + +/** + * Grant permissions request. + */ +export class GrantRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + + // Apply defaults. + this.parameters.channels ??= []; + this.parameters.channelGroups ??= []; + this.parameters.uuids ??= []; + this.parameters.read ??= READ_PERMISSION; + this.parameters.write ??= WRITE_PERMISSION; + this.parameters.delete ??= DELETE_PERMISSION; + this.parameters.get ??= GET_PERMISSION; + this.parameters.update ??= UPDATE_PERMISSION; + this.parameters.manage ??= MANAGE_PERMISSION; + this.parameters.join ??= JOIN_PERMISSION; + } + + operation(): RequestOperation { + return RequestOperation.PNAccessManagerGrant; + } + + validate(): string | undefined { + const { + keySet: { subscribeKey, publishKey, secretKey }, + uuids = [], + channels = [], + channelGroups = [], + authKeys = [], + } = this.parameters; + + if (!subscribeKey) return 'Missing Subscribe Key'; + if (!publishKey) return 'Missing Publish Key'; + if (!secretKey) return 'Missing Secret Key'; + + if (uuids.length !== 0 && authKeys.length === 0) return 'authKeys are required for grant request on uuids'; + + if (uuids.length && (channels.length !== 0 || channelGroups.length !== 0)) + return 'Both channel/channel group and uuid cannot be used in the same request'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + return serviceResponse.payload; + } + + protected get path(): string { + return `/v2/auth/grant/sub-key/${this.parameters.keySet.subscribeKey}`; + } + + protected get queryParameters(): Query { + const { + channels, + channelGroups, + authKeys, + uuids, + read, + write, + manage, + delete: del, + get, + join, + update, + ttl, + } = this.parameters; + + return { + ...(channels && channels?.length > 0 ? { channel: channels.join(',') } : {}), + ...(channelGroups && channelGroups?.length > 0 ? { 'channel-group': channelGroups.join(',') } : {}), + ...(authKeys && authKeys?.length > 0 ? { auth: authKeys.join(',') } : {}), + ...(uuids && uuids?.length > 0 ? { 'target-uuid': uuids.join(',') } : {}), + r: read ? '1' : '0', + w: write ? '1' : '0', + m: manage ? '1' : '0', + d: del ? '1' : '0', + g: get ? '1' : '0', + j: join ? '1' : '0', + u: update ? '1' : '0', + ...(ttl || ttl === 0 ? { ttl } : {}), + }; + } +} diff --git a/src/core/endpoints/access_manager/grant_token.js b/src/core/endpoints/access_manager/grant_token.js deleted file mode 100644 index 1e0ae8e25..000000000 --- a/src/core/endpoints/access_manager/grant_token.js +++ /dev/null @@ -1,299 +0,0 @@ -import operationConstants from '../../constants/operations'; - -export function getOperation() { - return operationConstants.PNAccessManagerGrantToken; -} - -function hasVspTerms(incomingParams) { - const hasAuthorizedUserId = incomingParams?.authorizedUserId !== undefined; - const hasUserResources = incomingParams?.resources?.users !== undefined; - const hasSpaceResources = incomingParams?.resources?.spaces !== undefined; - const hasUserPatterns = incomingParams?.patterns?.users !== undefined; - const hasSpacePatterns = incomingParams?.patterns?.spaces !== undefined; - - return hasUserPatterns || hasUserResources || hasSpacePatterns || hasSpaceResources || hasAuthorizedUserId; -} - -export function extractPermissions(permissions) { - let permissionsResult = 0; - - if (permissions.join) { - permissionsResult |= 128; - } - - if (permissions.update) { - permissionsResult |= 64; - } - - if (permissions.get) { - permissionsResult |= 32; - } - - if (permissions.delete) { - permissionsResult |= 8; - } - - if (permissions.manage) { - permissionsResult |= 4; - } - - if (permissions.write) { - permissionsResult |= 2; - } - - if (permissions.read) { - permissionsResult |= 1; - } - - return permissionsResult; -} - -function prepareMessagePayloadVsp(_modules, { ttl, resources, patterns, meta, authorizedUserId }) { - const params = { - ttl: 0, - permissions: { - resources: { - channels: {}, - groups: {}, - uuids: {}, - users: {}, // not used, needed for api backward compatibility - spaces: {}, // not used, needed for api backward compatibility - }, - patterns: { - channels: {}, - groups: {}, - uuids: {}, - users: {}, // not used, needed for api backward compatibility - spaces: {}, // not used, needed for api backward compatibility - }, - meta: {}, - }, - }; - - if (resources) { - const { users, spaces, groups } = resources; - - if (users) { - Object.keys(users).forEach((userID) => { - params.permissions.resources.uuids[userID] = extractPermissions(users[userID]); - }); - } - - if (spaces) { - Object.keys(spaces).forEach((spaceId) => { - params.permissions.resources.channels[spaceId] = extractPermissions(spaces[spaceId]); - }); - } - - if (groups) { - Object.keys(groups).forEach((group) => { - params.permissions.resources.groups[group] = extractPermissions(groups[group]); - }); - } - } - - if (patterns) { - const { users, spaces, groups } = patterns; - - if (users) { - Object.keys(users).forEach((userId) => { - params.permissions.patterns.uuids[userId] = extractPermissions(users[userId]); - }); - } - - if (spaces) { - Object.keys(spaces).forEach((spaceId) => { - params.permissions.patterns.channels[spaceId] = extractPermissions(spaces[spaceId]); - }); - } - - if (groups) { - Object.keys(groups).forEach((group) => { - params.permissions.patterns.groups[group] = extractPermissions(groups[group]); - }); - } - } - - if (ttl || ttl === 0) { - params.ttl = ttl; - } - - if (meta) { - params.permissions.meta = meta; - } - - if (authorizedUserId) { - params.permissions.uuid = `${authorizedUserId}`; // ensure this is a string - } - - return params; -} - -function prepareMessagePayload(_modules, incomingParams) { - if (hasVspTerms(incomingParams)) { - return prepareMessagePayloadVsp(_modules, incomingParams); - } - - const { ttl, resources, patterns, meta, authorized_uuid } = incomingParams; - - const params = { - ttl: 0, - permissions: { - resources: { - channels: {}, - groups: {}, - uuids: {}, - users: {}, // not used, needed for api backward compatibility - spaces: {}, // not used, needed for api backward compatibility - }, - patterns: { - channels: {}, - groups: {}, - uuids: {}, - users: {}, // not used, needed for api backward compatibility - spaces: {}, // not used, needed for api backward compatibility - }, - meta: {}, - }, - }; - - if (resources) { - const { uuids, channels, groups } = resources; - - if (uuids) { - Object.keys(uuids).forEach((uuid) => { - params.permissions.resources.uuids[uuid] = extractPermissions(uuids[uuid]); - }); - } - - if (channels) { - Object.keys(channels).forEach((channel) => { - params.permissions.resources.channels[channel] = extractPermissions(channels[channel]); - }); - } - - if (groups) { - Object.keys(groups).forEach((group) => { - params.permissions.resources.groups[group] = extractPermissions(groups[group]); - }); - } - } - - if (patterns) { - const { uuids, channels, groups } = patterns; - - if (uuids) { - Object.keys(uuids).forEach((uuid) => { - params.permissions.patterns.uuids[uuid] = extractPermissions(uuids[uuid]); - }); - } - - if (channels) { - Object.keys(channels).forEach((channel) => { - params.permissions.patterns.channels[channel] = extractPermissions(channels[channel]); - }); - } - - if (groups) { - Object.keys(groups).forEach((group) => { - params.permissions.patterns.groups[group] = extractPermissions(groups[group]); - }); - } - } - - if (ttl || ttl === 0) { - params.ttl = ttl; - } - - if (meta) { - params.permissions.meta = meta; - } - - if (authorized_uuid) { - params.permissions.uuid = `${authorized_uuid}`; // ensure this is a string - } - - return params; -} - -export function validateParams(modules, incomingParams) { - const { config } = modules; - - if (!config.subscribeKey) return 'Missing Subscribe Key'; - if (!config.publishKey) return 'Missing Publish Key'; - if (!config.secretKey) return 'Missing Secret Key'; - - if (!incomingParams.resources && !incomingParams.patterns) return 'Missing either Resources or Patterns.'; - - const hasAuthorizedUuid = incomingParams?.authorized_uuid !== undefined; - const hasUuidResources = incomingParams?.resources?.uuids !== undefined; - const hasChannelResources = incomingParams?.resources?.channels !== undefined; - const hasGroupResources = incomingParams?.resources?.groups !== undefined; - const hasUuidPatterns = incomingParams?.patterns?.uuids !== undefined; - const hasChannelPatterns = incomingParams?.patterns?.channels !== undefined; - const hasGroupPatterns = incomingParams?.patterns?.groups !== undefined; - - const hasLegacyTerms = - hasAuthorizedUuid || - hasUuidResources || - hasUuidPatterns || - hasChannelResources || - hasChannelPatterns || - hasGroupResources || - hasGroupPatterns; - - if (hasVspTerms(incomingParams) && hasLegacyTerms) { - return ( - 'Cannot mix `users`, `spaces` and `authorizedUserId` ' + - 'with `uuids`, `channels`, `groups` and `authorized_uuid`' - ); - } - - if ( - (incomingParams.resources && - (!incomingParams.resources.uuids || Object.keys(incomingParams.resources.uuids).length === 0) && - (!incomingParams.resources.channels || Object.keys(incomingParams.resources.channels).length === 0) && - (!incomingParams.resources.groups || Object.keys(incomingParams.resources.groups).length === 0) && - (!incomingParams.resources.users || Object.keys(incomingParams.resources.users).length === 0) && - (!incomingParams.resources.spaces || Object.keys(incomingParams.resources.spaces).length === 0)) || - (incomingParams.patterns && - (!incomingParams.patterns.uuids || Object.keys(incomingParams.patterns.uuids).length === 0) && - (!incomingParams.patterns.channels || Object.keys(incomingParams.patterns.channels).length === 0) && - (!incomingParams.patterns.groups || Object.keys(incomingParams.patterns.groups).length === 0) && - (!incomingParams.patterns.users || Object.keys(incomingParams.patterns.users).length === 0) && - (!incomingParams.patterns.spaces || Object.keys(incomingParams.patterns.spaces).length === 0)) - ) { - return 'Missing values for either Resources or Patterns.'; - } -} - -export function postURL(modules) { - const { config } = modules; - return `/v3/pam/${config.subscribeKey}/grant`; -} - -export function usePost() { - return true; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return false; -} - -export function prepareParams() { - return {}; -} - -export function postPayload(modules, incomingParams) { - return prepareMessagePayload(modules, incomingParams); -} - -export function handleResponse(modules, response) { - const { token } = response.data; - - return token; -} diff --git a/src/core/endpoints/access_manager/grant_token.ts b/src/core/endpoints/access_manager/grant_token.ts new file mode 100644 index 000000000..cd9b898dd --- /dev/null +++ b/src/core/endpoints/access_manager/grant_token.ts @@ -0,0 +1,271 @@ +/** + * PAM Grant Token REST API module. + */ + +import { createValidationError, PubNubError } from '../../../errors/pubnub-error'; +import { TransportResponse } from '../../types/transport-response'; +import { PubNubAPIError } from '../../../errors/pubnub-api-error'; +import { TransportMethod } from '../../types/transport-request'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import * as PAM from '../../types/api/access-panager'; +import { KeySet } from '../../types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = (PAM.GrantTokenParameters | PAM.ObjectsGrantTokenParameters) & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Permissions group payload. + * + * User can configure permissions per-resource or per-resource which match RegExp. + */ +type PermissionPayload = { + /** + * Object containing `uuid` metadata permissions. + */ + uuids?: Record; + + /** + * Object containing `channel` permissions. + */ + channels?: Record; + + /** + * Object containing `channel group` permissions. + */ + groups?: Record; + + /** + * Extra metadata to be published with the request. + * + * **Important:** Values must be scalar only; `arrays` or `objects` aren't supported. + */ + meta?: PAM.Metadata; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Request processing result data. + */ + data: { + /** + * Permissions token grant human-readable result. + */ + message: string; + + /** + * Generate token with requested permissions. + */ + token: string; + }; + + /** + * Name of the service which provided response. + */ + service: string; +}; +// endregion + +/** + * Grant token permissions request. + */ +export class GrantTokenRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super({ method: TransportMethod.POST }); + + // Apply defaults. + this.parameters.resources ??= {}; + this.parameters.patterns ??= {}; + } + + operation(): RequestOperation { + return RequestOperation.PNAccessManagerGrantToken; + } + + validate(): string | undefined { + const { + keySet: { subscribeKey, publishKey, secretKey }, + resources, + patterns, + } = this.parameters; + + if (!subscribeKey) return 'Missing Subscribe Key'; + if (!publishKey) return 'Missing Publish Key'; + if (!secretKey) return 'Missing Secret Key'; + if (!resources && !patterns) return 'Missing either Resources or Patterns'; + + if ( + this.isVspPermissions(this.parameters) && + ('channels' in (this.parameters.resources ?? {}) || + 'uuids' in (this.parameters.resources ?? {}) || + 'groups' in (this.parameters.resources ?? {}) || + 'channels' in (this.parameters.patterns ?? {}) || + 'uuids' in (this.parameters.patterns ?? {}) || + 'groups' in (this.parameters.patterns ?? {})) + ) + return ( + 'Cannot mix `users`, `spaces` and `authorizedUserId` with `uuids`, `channels`,' + + ' `groups` and `authorized_uuid`' + ); + + let permissionsEmpty = true; + [this.parameters.resources, this.parameters.patterns].forEach((refPerm) => { + Object.keys(refPerm ?? {}).forEach((scope) => { + // @ts-expect-error Permissions with backward compatibility. + if (refPerm && permissionsEmpty && Object.keys(refPerm[scope] ?? {}).length > 0) { + permissionsEmpty = false; + } + }); + }); + + if (permissionsEmpty) return 'Missing values for either Resources or Patterns'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + return serviceResponse.data.token; + } + + protected get path(): string { + return `/v3/pam/${this.parameters.keySet.subscribeKey}/grant`; + } + + protected get body(): string { + const { ttl, meta } = this.parameters; + const body: Record = { ...(ttl || ttl === 0 ? { ttl } : {}) }; + const uuid = this.isVspPermissions(this.parameters) + ? this.parameters.authorizedUserId + : this.parameters.authorized_uuid; + + const permissions: Record> = {}; + const resourcePermissions: PermissionPayload = {}; + const patternPermissions: PermissionPayload = {}; + const mapPermissions = ( + name: string, + permissionBit: number, + type: keyof PermissionPayload, + permissions: PermissionPayload, + ) => { + if (!permissions[type]) permissions[type] = {}; + permissions[type]![name] = permissionBit; + }; + + const { resources, patterns } = this.parameters; + [resources, patterns].forEach((refPerm, idx) => { + const target = idx === 0 ? resourcePermissions : patternPermissions; + let channelsPermissions: Record = {}; + let channelGroupsPermissions: Record = {}; + let uuidsPermissions: Record = {}; + + if (!target.channels) target.channels = {}; + if (!target.groups) target.groups = {}; + if (!target.uuids) target.uuids = {}; + // @ts-expect-error Not used, needed for api backward compatibility + if (!target.users) target.users = {}; + // @ts-expect-error Not used, needed for api backward compatibility + if (!target.spaces) target.spaces = {}; + + if (refPerm) { + // Check whether working with legacy Objects permissions. + if ('spaces' in refPerm || 'users' in refPerm) { + channelsPermissions = refPerm.spaces ?? {}; + uuidsPermissions = refPerm.users ?? {}; + } else if ('channels' in refPerm || 'uuids' in refPerm || 'groups' in refPerm) { + channelsPermissions = refPerm.channels ?? {}; + channelGroupsPermissions = refPerm.groups ?? {}; + uuidsPermissions = refPerm.uuids ?? {}; + } + } + + Object.keys(channelsPermissions).forEach((channel) => + mapPermissions(channel, this.extractPermissions(channelsPermissions[channel]), 'channels', target), + ); + + Object.keys(channelGroupsPermissions).forEach((groups) => + mapPermissions(groups, this.extractPermissions(channelGroupsPermissions[groups]), 'groups', target), + ); + + Object.keys(uuidsPermissions).forEach((uuids) => + mapPermissions(uuids, this.extractPermissions(uuidsPermissions[uuids]), 'uuids', target), + ); + }); + + if (uuid) permissions.uuid = `${uuid}`; + permissions.resources = resourcePermissions; + permissions.patterns = patternPermissions; + permissions.meta = meta ?? {}; + body.permissions = permissions; + + return JSON.stringify(body); + } + + /** + * Extract permissions bit from permission configuration object. + * + * @param permissions - User provided scope-based permissions. + * + * @returns Permissions bit. + */ + private extractPermissions( + permissions: PAM.UuidTokenPermissions | PAM.ChannelTokenPermissions | PAM.ChannelGroupTokenPermissions, + ): number { + let permissionsResult = 0; + + if ('join' in permissions && permissions.join) permissionsResult |= 128; + if ('update' in permissions && permissions.update) permissionsResult |= 64; + if ('get' in permissions && permissions.get) permissionsResult |= 32; + if ('delete' in permissions && permissions.delete) permissionsResult |= 8; + if ('manage' in permissions && permissions.manage) permissionsResult |= 4; + if ('write' in permissions && permissions.write) permissionsResult |= 2; + if ('read' in permissions && permissions.read) permissionsResult |= 1; + + return permissionsResult; + } + + /** + * Check whether provided parameters is part of legacy VSP access token configuration. + * + * @param parameters - Parameters which should be checked. + * + * @returns VSP request parameters if it is legacy configuration. + */ + private isVspPermissions( + parameters: PAM.GrantTokenParameters | PAM.ObjectsGrantTokenParameters, + ): parameters is PAM.ObjectsGrantTokenParameters { + return ( + 'authorizedUserId' in parameters || + 'spaces' in (parameters.resources ?? {}) || + 'users' in (parameters.resources ?? {}) || + 'spaces' in (parameters.patterns ?? {}) || + 'users' in (parameters.patterns ?? {}) + ); + } +} diff --git a/src/core/endpoints/access_manager/revoke_token.js b/src/core/endpoints/access_manager/revoke_token.js deleted file mode 100644 index ab457f2db..000000000 --- a/src/core/endpoints/access_manager/revoke_token.js +++ /dev/null @@ -1,37 +0,0 @@ -/** */ - -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -const endpoint = { - getOperation: () => operationConstants.PNAccessManagerRevokeToken, - - validateParams: (modules, token) => { - const { secretKey } = modules.config; - if (!secretKey) { - return 'Missing Secret Key'; - } - - if (!token) { - return "token can't be empty"; - } - }, - - getURL: ({ config }, token) => `/v3/pam/${config.subscribeKey}/grant/${utils.encodeString(token)}`, - useDelete: () => true, - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => false, - - prepareParams: ({ config }) => ({ - uuid: config.getUUID(), - }), - - handleResponse: (_, response) => ({ - status: response.status, - data: response.data, - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/access_manager/revoke_token.ts b/src/core/endpoints/access_manager/revoke_token.ts new file mode 100644 index 000000000..da4d95578 --- /dev/null +++ b/src/core/endpoints/access_manager/revoke_token.ts @@ -0,0 +1,91 @@ +/** + * PAM Revoke Token REST API module. + */ + +import { createValidationError, PubNubError } from '../../../errors/pubnub-error'; +import { TransportResponse } from '../../types/transport-response'; +import { PubNubAPIError } from '../../../errors/pubnub-api-error'; +import { TransportMethod } from '../../types/transport-request'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import * as PAM from '../../types/api/access-panager'; +import { encodeString } from '../../utils'; +import { KeySet } from '../../types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = PAM.RevokeParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Request processing result data. + */ + data: Record; + + /** + * Name of the service which provided response. + */ + service: string; +}; +// endregion + +/** + * Access token revoke request. + * + * Invalidate token and permissions which has been granted for it. + */ +export class RevokeTokenRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super({ method: TransportMethod.DELETE }); + } + + operation(): RequestOperation { + return RequestOperation.PNAccessManagerRevokeToken; + } + + validate(): string | undefined { + if (!this.parameters.keySet.secretKey) return 'Missing Secret Key'; + if (!this.parameters.token) return "token can't be empty"; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + return {}; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + token, + } = this.parameters; + + return `/v3/pam/${subscribeKey}/grant/${encodeString(token)}`; + } +} diff --git a/src/core/endpoints/actions/add_message_action.js b/src/core/endpoints/actions/add_message_action.js deleted file mode 100644 index e07ebb6cc..000000000 --- a/src/core/endpoints/actions/add_message_action.js +++ /dev/null @@ -1,56 +0,0 @@ -/* */ - -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -export function getOperation() { - return operationConstants.PNAddMessageActionOperation; -} - -export function validateParams({ config }, incomingParams) { - const { action, channel, messageTimetoken } = incomingParams; - - if (!messageTimetoken) return 'Missing message timetoken'; - if (!config.subscribeKey) return 'Missing Subscribe Key'; - if (!channel) return 'Missing message channel'; - if (!action) return 'Missing Action'; - if (!action.value) return 'Missing Action.value'; - if (!action.type) return 'Missing Action.type'; - if (action.type.length > 15) return 'Action.type value exceed maximum length of 15'; -} - -export function usePost() { - return true; -} - -export function postURL({ config }, incomingParams) { - const { channel, messageTimetoken } = incomingParams; - - return `/v1/message-actions/${config.subscribeKey}/channel/${utils.encodeString( - channel, - )}/message/${messageTimetoken}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function getRequestHeaders() { - return { 'Content-Type': 'application/json' }; -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams() { - return {}; -} - -export function postPayload(modules, incomingParams) { - return incomingParams.action; -} - -export function handleResponse(modules, addMessageActionResponse) { - return { data: addMessageActionResponse.data }; -} diff --git a/src/core/endpoints/actions/add_message_action.ts b/src/core/endpoints/actions/add_message_action.ts new file mode 100644 index 000000000..e14a4142a --- /dev/null +++ b/src/core/endpoints/actions/add_message_action.ts @@ -0,0 +1,105 @@ +/** + * Add Message Action REST API module. + */ + +import { createValidationError, PubNubError } from '../../../errors/pubnub-error'; +import { TransportResponse } from '../../types/transport-response'; +import { PubNubAPIError } from '../../../errors/pubnub-api-error'; +import { TransportMethod } from '../../types/transport-request'; +import * as MessageAction from '../../types/api/message-action'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import { encodeString } from '../../utils'; +import { KeySet } from '../../types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = MessageAction.AddMessageActionParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Request processing result data. + */ + data: MessageAction.MessageAction; +}; +// endregion + +/** + * Add Message Reaction request. + */ +export class AddMessageActionRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super({ method: TransportMethod.POST }); + } + + operation(): RequestOperation { + return RequestOperation.PNAddMessageActionOperation; + } + + validate(): string | undefined { + const { + keySet: { subscribeKey }, + action, + channel, + messageTimetoken, + } = this.parameters; + + if (!subscribeKey) return 'Missing Subscribe Key'; + if (!channel) return 'Missing message channel'; + if (!messageTimetoken) return 'Missing message timetoken'; + if (!action) return 'Missing Action'; + if (!action.value) return 'Missing Action.value'; + if (!action.type) return 'Missing Action.type'; + if (action.type.length > 15) return 'Action.type value exceed maximum length of 15'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + return { data: serviceResponse.data }; + } + + protected get headers(): Record | undefined { + return { 'Content-Type': 'application/json' }; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channel, + messageTimetoken, + } = this.parameters; + + return `/v1/message-actions/${subscribeKey}/channel/${encodeString(channel)}/message/${messageTimetoken}`; + } + + protected get body(): ArrayBuffer | string | undefined { + return JSON.stringify(this.parameters.action); + } +} diff --git a/src/core/endpoints/actions/get_message_actions.js b/src/core/endpoints/actions/get_message_actions.js deleted file mode 100644 index ebe4fbb7d..000000000 --- a/src/core/endpoints/actions/get_message_actions.js +++ /dev/null @@ -1,51 +0,0 @@ -/* */ -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -export function getOperation() { - return operationConstants.PNGetMessageActionsOperation; -} - -export function validateParams({ config }, incomingParams) { - const { channel } = incomingParams; - - if (!config.subscribeKey) return 'Missing Subscribe Key'; - if (!channel) return 'Missing message channel'; -} - -export function getURL({ config }, incomingParams) { - const { channel } = incomingParams; - - return `/v1/message-actions/${config.subscribeKey}/channel/${utils.encodeString(channel)}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams(modules, incomingParams) { - const { limit, start, end } = incomingParams; - const outgoingParams = {}; - - if (limit) outgoingParams.limit = limit; - if (start) outgoingParams.start = start; - if (end) outgoingParams.end = end; - - return outgoingParams; -} - -export function handleResponse(modules, getMessageActionsResponse) { - /** @type GetMessageActionsResponse */ - const response = { data: getMessageActionsResponse.data, start: null, end: null }; - - if (response.data.length) { - response.end = response.data[response.data.length - 1].actionTimetoken; - response.start = response.data[0].actionTimetoken; - } - - return response; -} diff --git a/src/core/endpoints/actions/get_message_actions.ts b/src/core/endpoints/actions/get_message_actions.ts new file mode 100644 index 000000000..60a729830 --- /dev/null +++ b/src/core/endpoints/actions/get_message_actions.ts @@ -0,0 +1,111 @@ +/** + * Get Message Actions REST API module. + */ + +import { createValidationError, PubNubError } from '../../../errors/pubnub-error'; +import { TransportResponse } from '../../types/transport-response'; +import { PubNubAPIError } from '../../../errors/pubnub-api-error'; +import * as MessageAction from '../../types/api/message-action'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import { KeySet, Query } from '../../types/api'; +import { encodeString } from '../../utils'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = MessageAction.GetMessageActionsParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Retrieved list of message actions. + */ + data: MessageAction.MessageAction[]; + + /** + * More message actions fetch information. + */ + more?: MessageAction.MoreMessageActions; +}; +// endregion + +/** + * Fetch channel message actions request. + */ +export class GetMessageActionsRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + } + + operation(): RequestOperation { + return RequestOperation.PNGetMessageActionsOperation; + } + + validate(): string | undefined { + if (!this.parameters.keySet.subscribeKey) return 'Missing Subscribe Key'; + if (!this.parameters.channel) return 'Missing message channel'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + let start: string | null = null; + let end: string | null = null; + + if (serviceResponse.data.length > 0) { + start = serviceResponse.data[0].actionTimetoken; + end = serviceResponse.data[serviceResponse.data.length - 1].actionTimetoken; + } + + return { + data: serviceResponse.data, + more: serviceResponse.more, + start, + end, + }; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channel, + } = this.parameters; + + return `/v1/message-actions/${subscribeKey}/channel/${encodeString(channel)}`; + } + + protected get queryParameters(): Query { + const { limit, start, end } = this.parameters; + + return { + ...(start ? { start } : {}), + ...(end ? { end } : {}), + ...(limit ? { limit } : {}), + }; + } +} diff --git a/src/core/endpoints/actions/remove_message_action.js b/src/core/endpoints/actions/remove_message_action.js deleted file mode 100644 index 479cfb2e6..000000000 --- a/src/core/endpoints/actions/remove_message_action.js +++ /dev/null @@ -1,45 +0,0 @@ -/* */ - -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -export function getOperation() { - return operationConstants.PNRemoveMessageActionOperation; -} - -export function validateParams({ config }, incomingParams) { - const { channel, actionTimetoken, messageTimetoken } = incomingParams; - - if (!messageTimetoken) return 'Missing message timetoken'; - if (!actionTimetoken) return 'Missing action timetoken'; - if (!config.subscribeKey) return 'Missing Subscribe Key'; - if (!channel) return 'Missing message channel'; -} - -export function useDelete() { - return true; -} - -export function getURL({ config }, incomingParams) { - const { channel, actionTimetoken, messageTimetoken } = incomingParams; - - return `/v1/message-actions/${config.subscribeKey}/channel/${utils.encodeString( - channel, - )}/message/${messageTimetoken}/action/${actionTimetoken}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams() { - return {}; -} - -export function handleResponse(modules, removeMessageActionResponse) { - return { data: removeMessageActionResponse.data }; -} diff --git a/src/core/endpoints/actions/remove_message_action.ts b/src/core/endpoints/actions/remove_message_action.ts new file mode 100644 index 000000000..a7b397d7c --- /dev/null +++ b/src/core/endpoints/actions/remove_message_action.ts @@ -0,0 +1,97 @@ +/** + * Remove Message Action REST API module. + */ + +import { createValidationError, PubNubError } from '../../../errors/pubnub-error'; +import { TransportResponse } from '../../types/transport-response'; +import { PubNubAPIError } from '../../../errors/pubnub-api-error'; +import { TransportMethod } from '../../types/transport-request'; +import * as MessageAction from '../../types/api/message-action'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import { encodeString } from '../../utils'; +import { KeySet } from '../../types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = MessageAction.RemoveMessageActionParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Request processing result data. + */ + data: Record; +}; +// endregion + +/** + * Remove specific message action request. + */ +export class RemoveMessageAction extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super({ method: TransportMethod.DELETE }); + } + + operation(): RequestOperation { + return RequestOperation.PNRemoveMessageActionOperation; + } + + validate(): string | undefined { + const { + keySet: { subscribeKey }, + channel, + messageTimetoken, + actionTimetoken, + } = this.parameters; + + if (!subscribeKey) return 'Missing Subscribe Key'; + if (!channel) return 'Missing message action channel'; + if (!messageTimetoken) return 'Missing message timetoken'; + if (!actionTimetoken) return 'Missing action timetoken'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + return { data: serviceResponse.data }; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channel, + actionTimetoken, + messageTimetoken, + } = this.parameters; + + return `/v1/message-actions/${subscribeKey}/channel/${encodeString( + channel, + )}/message/${messageTimetoken}/action/${actionTimetoken}`; + } +} diff --git a/src/core/endpoints/channel_groups/add_channels.js b/src/core/endpoints/channel_groups/add_channels.js deleted file mode 100644 index 804decdf6..000000000 --- a/src/core/endpoints/channel_groups/add_channels.js +++ /dev/null @@ -1,42 +0,0 @@ -/* */ -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -export function getOperation() { - return operationConstants.PNAddChannelsToGroupOperation; -} - -export function validateParams(modules, incomingParams) { - const { channels, channelGroup } = incomingParams; - const { config } = modules; - - if (!channelGroup) return 'Missing Channel Group'; - if (!channels || channels.length === 0) return 'Missing Channels'; - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules, incomingParams) { - const { channelGroup } = incomingParams; - const { config } = modules; - return `/v1/channel-registration/sub-key/${config.subscribeKey}/channel-group/${utils.encodeString(channelGroup)}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams(modules, incomingParams) { - const { channels = [] } = incomingParams; - - return { - add: channels.join(','), - }; -} - -export function handleResponse() { - return {}; -} diff --git a/src/core/endpoints/channel_groups/add_channels.ts b/src/core/endpoints/channel_groups/add_channels.ts new file mode 100644 index 000000000..326e742c9 --- /dev/null +++ b/src/core/endpoints/channel_groups/add_channels.ts @@ -0,0 +1,104 @@ +/** + * Add channel group channels REST API module. + */ + +import { createValidationError, PubNubError } from '../../../errors/pubnub-error'; +import { TransportResponse } from '../../types/transport-response'; +import { PubNubAPIError } from '../../../errors/pubnub-api-error'; +import * as ChannelGroups from '../../types/api/channel-groups'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import { KeySet, Query } from '../../types/api'; +import { encodeString } from '../../utils'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = ChannelGroups.ManageChannelGroupChannelsParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Channel group channels addition human-readable result. + */ + message: string; + + /** + * Name of the service which provided response. + */ + service: string; + + /** + * Whether response represent service error or not. + */ + error: boolean; +}; +// endregion + +/** + * Add channel group channels request. + */ +export class AddChannelGroupChannelsRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + } + + operation(): RequestOperation { + return RequestOperation.PNAddChannelsToGroupOperation; + } + + validate(): string | undefined { + const { + keySet: { subscribeKey }, + channels, + channelGroup, + } = this.parameters; + + if (!subscribeKey) return 'Missing Subscribe Key'; + if (!channelGroup) return 'Missing Channel Group'; + if (!channels) return 'Missing channels'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + return {}; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channelGroup, + } = this.parameters; + + return `/v1/channel-registration/sub-key/${subscribeKey}/channel-group/${encodeString(channelGroup)}`; + } + + protected get queryParameters(): Query { + return { add: this.parameters.channels.join(',') }; + } +} diff --git a/src/core/endpoints/channel_groups/delete_group.js b/src/core/endpoints/channel_groups/delete_group.js deleted file mode 100644 index 1dff624d6..000000000 --- a/src/core/endpoints/channel_groups/delete_group.js +++ /dev/null @@ -1,40 +0,0 @@ -/* */ - -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -export function getOperation() { - return operationConstants.PNRemoveGroupOperation; -} - -export function validateParams(modules, incomingParams) { - const { channelGroup } = incomingParams; - const { config } = modules; - - if (!channelGroup) return 'Missing Channel Group'; - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules, incomingParams) { - const { channelGroup } = incomingParams; - const { config } = modules; - return `/v1/channel-registration/sub-key/${config.subscribeKey}/channel-group/${utils.encodeString( - channelGroup, - )}/remove`; -} - -export function isAuthSupported() { - return true; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function prepareParams() { - return {}; -} - -export function handleResponse() { - return {}; -} diff --git a/src/core/endpoints/channel_groups/delete_group.ts b/src/core/endpoints/channel_groups/delete_group.ts new file mode 100644 index 000000000..e06a68c28 --- /dev/null +++ b/src/core/endpoints/channel_groups/delete_group.ts @@ -0,0 +1,93 @@ +/** + * Delete channel group REST API module. + */ + +import { createValidationError, PubNubError } from '../../../errors/pubnub-error'; +import { TransportResponse } from '../../types/transport-response'; +import { PubNubAPIError } from '../../../errors/pubnub-api-error'; +import * as ChannelGroups from '../../types/api/channel-groups'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import { KeySet } from '../../types/api'; +import { encodeString } from '../../utils'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = ChannelGroups.DeleteChannelGroupParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Delete channel group human-readable result. + */ + message: string; + + /** + * Name of the service which provided response. + */ + service: string; + + /** + * Whether response represent service error or not. + */ + error: boolean; +}; +// endregion + +/** + * Channel group delete request. + */ +export class DeleteChannelGroupRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + } + + operation(): RequestOperation { + return RequestOperation.PNRemoveGroupOperation; + } + + validate(): string | undefined { + if (!this.parameters.keySet.subscribeKey) return 'Missing Subscribe Key'; + if (!this.parameters.channelGroup) return 'Missing Channel Group'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + return {}; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channelGroup, + } = this.parameters; + + return `/v1/channel-registration/sub-key/${subscribeKey}/channel-group/${encodeString(channelGroup)}/remove`; + } +} diff --git a/src/core/endpoints/channel_groups/list_channels.js b/src/core/endpoints/channel_groups/list_channels.js deleted file mode 100644 index 245857d5e..000000000 --- a/src/core/endpoints/channel_groups/list_channels.js +++ /dev/null @@ -1,39 +0,0 @@ -/* */ -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -export function getOperation() { - return operationConstants.PNChannelsForGroupOperation; -} - -export function validateParams(modules, incomingParams) { - const { channelGroup } = incomingParams; - const { config } = modules; - - if (!channelGroup) return 'Missing Channel Group'; - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules, incomingParams) { - const { channelGroup } = incomingParams; - const { config } = modules; - return `/v1/channel-registration/sub-key/${config.subscribeKey}/channel-group/${utils.encodeString(channelGroup)}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams() { - return {}; -} - -export function handleResponse(modules, serverResponse) { - return { - channels: serverResponse.payload.channels, - }; -} diff --git a/src/core/endpoints/channel_groups/list_channels.ts b/src/core/endpoints/channel_groups/list_channels.ts new file mode 100644 index 000000000..d5bf3b8fa --- /dev/null +++ b/src/core/endpoints/channel_groups/list_channels.ts @@ -0,0 +1,108 @@ +/** + * List channel group channels REST API module. + */ + +import { createValidationError, PubNubError } from '../../../errors/pubnub-error'; +import { TransportResponse } from '../../types/transport-response'; +import { PubNubAPIError } from '../../../errors/pubnub-api-error'; +import * as ChannelGroups from '../../types/api/channel-groups'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import { encodeString } from '../../utils'; +import { KeySet } from '../../types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = ChannelGroups.ListChannelGroupChannelsParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * List channel group channels human-readable result. + */ + message: string; + + /** + * Name of the service which provided response. + */ + service: string; + + /** + * Whether response represent service error or not. + */ + error: boolean; + + /** + * Retrieved registered channels information. + */ + payload: { + /** + * Channel group for which channels has been received. + */ + group: string; + + /** + * List of channels registered in channel {@link group}. + */ + channels: string[]; + }; +}; +// endregion + +/** + * List Channel Group Channels request. + */ +export class ListChannelGroupChannels extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + } + + operation(): RequestOperation { + return RequestOperation.PNChannelsForGroupOperation; + } + + validate(): string | undefined { + if (!this.parameters.keySet.subscribeKey) return 'Missing Subscribe Key'; + if (!this.parameters.channelGroup) return 'Missing Channel Group'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + return { channels: serviceResponse.payload.channels }; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channelGroup, + } = this.parameters; + + return `/v1/channel-registration/sub-key/${subscribeKey}/channel-group/${encodeString(channelGroup)}`; + } +} diff --git a/src/core/endpoints/channel_groups/list_groups.js b/src/core/endpoints/channel_groups/list_groups.js deleted file mode 100644 index 8642f397f..000000000 --- a/src/core/endpoints/channel_groups/list_groups.js +++ /dev/null @@ -1,36 +0,0 @@ -/* */ - -import operationConstants from '../../constants/operations'; - -export function getOperation() { - return operationConstants.PNChannelGroupsOperation; -} - -export function validateParams(modules) { - const { config } = modules; - - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules) { - const { config } = modules; - return `/v1/channel-registration/sub-key/${config.subscribeKey}/channel-group`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams() { - return {}; -} - -export function handleResponse(modules, serverResponse) { - return { - groups: serverResponse.payload.groups, - }; -} diff --git a/src/core/endpoints/channel_groups/list_groups.ts b/src/core/endpoints/channel_groups/list_groups.ts new file mode 100644 index 000000000..2d4ef4a02 --- /dev/null +++ b/src/core/endpoints/channel_groups/list_groups.ts @@ -0,0 +1,101 @@ +/** + * List All Channel Groups REST API module. + */ + +import { createValidationError, PubNubError } from '../../../errors/pubnub-error'; +import { TransportResponse } from '../../types/transport-response'; +import { PubNubAPIError } from '../../../errors/pubnub-api-error'; +import * as ChannelGroups from '../../types/api/channel-groups'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import { KeySet } from '../../types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * List all channel groups human-readable result. + */ + message: string; + + /** + * Name of the service which provided response. + */ + service: string; + + /** + * Whether response represent service error or not. + */ + error: boolean; + + /** + * Retrieved registered channels information. + */ + payload: { + /** + * Subscription key for which list of channel groups has been received. + */ + sub_key: string; + + /** + * List of channel groups created for {@link sub_key}. + */ + groups: string[]; + }; +}; +// endregion + +/** + * List all channel groups request. + */ +export class ListChannelGroupsRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + } + + operation(): RequestOperation { + return RequestOperation.PNChannelGroupsOperation; + } + + validate(): string | undefined { + if (!this.parameters.keySet.subscribeKey) return 'Missing Subscribe Key'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + return { groups: serviceResponse.payload.groups }; + } + + protected get path(): string { + return `/v1/channel-registration/sub-key/${this.parameters.keySet.subscribeKey}/channel-group`; + } +} diff --git a/src/core/endpoints/channel_groups/remove_channels.js b/src/core/endpoints/channel_groups/remove_channels.js deleted file mode 100644 index 54c664f55..000000000 --- a/src/core/endpoints/channel_groups/remove_channels.js +++ /dev/null @@ -1,42 +0,0 @@ -/* */ -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -export function getOperation() { - return operationConstants.PNRemoveChannelsFromGroupOperation; -} - -export function validateParams(modules, incomingParams) { - const { channels, channelGroup } = incomingParams; - const { config } = modules; - - if (!channelGroup) return 'Missing Channel Group'; - if (!channels || channels.length === 0) return 'Missing Channels'; - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules, incomingParams) { - const { channelGroup } = incomingParams; - const { config } = modules; - return `/v1/channel-registration/sub-key/${config.subscribeKey}/channel-group/${utils.encodeString(channelGroup)}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams(modules, incomingParams) { - const { channels = [] } = incomingParams; - - return { - remove: channels.join(','), - }; -} - -export function handleResponse() { - return {}; -} diff --git a/src/core/endpoints/channel_groups/remove_channels.ts b/src/core/endpoints/channel_groups/remove_channels.ts new file mode 100644 index 000000000..0301d36e5 --- /dev/null +++ b/src/core/endpoints/channel_groups/remove_channels.ts @@ -0,0 +1,107 @@ +/** + * Remove channel group channels REST API module. + */ + +import { createValidationError, PubNubError } from '../../../errors/pubnub-error'; +import { TransportResponse } from '../../types/transport-response'; +import { PubNubAPIError } from '../../../errors/pubnub-api-error'; +import * as ChannelGroups from '../../types/api/channel-groups'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import { KeySet, Query } from '../../types/api'; +import { encodeString } from '../../utils'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = ChannelGroups.ManageChannelGroupChannelsParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Channel group channels manage human-readable result. + */ + message: string; + + /** + * Name of the service which provided response. + */ + service: string; + + /** + * Whether response represent service error or not. + */ + error: boolean; +}; +// endregion + +/** + * Remove channel group channels request. + */ +// prettier-ignore +export class RemoveChannelGroupChannelsRequest extends AbstractRequest< + ChannelGroups.ManageChannelGroupChannelsResponse +> { + constructor(private readonly parameters: RequestParameters) { + super(); + } + + operation(): RequestOperation { + return RequestOperation.PNRemoveChannelsFromGroupOperation; + } + + validate(): string | undefined { + const { + keySet: { subscribeKey }, + channels, + channelGroup, + } = this.parameters; + + if (!subscribeKey) return 'Missing Subscribe Key'; + if (!channelGroup) return 'Missing Channel Group'; + if (!channels) return 'Missing channels'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + return {}; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channelGroup, + } = this.parameters; + + return `/v1/channel-registration/sub-key/${subscribeKey}/channel-group/${encodeString(channelGroup)}`; + } + + protected get queryParameters(): Query { + return { remove: this.parameters.channels.join(',') }; + } +} diff --git a/src/core/endpoints/endpoint.js b/src/core/endpoints/endpoint.js deleted file mode 100644 index cead0ebfb..000000000 --- a/src/core/endpoints/endpoint.js +++ /dev/null @@ -1,3 +0,0 @@ -/** */ - -// endpoint definition structure diff --git a/src/core/endpoints/fetch_messages.js b/src/core/endpoints/fetch_messages.js deleted file mode 100644 index bb4c0d3be..000000000 --- a/src/core/endpoints/fetch_messages.js +++ /dev/null @@ -1,127 +0,0 @@ -/* */ -import operationConstants from '../constants/operations'; -import utils from '../utils'; - -function __processMessage(modules, message) { - const result = {}; - if (!modules.cryptoModule) { - result.payload = message; - return result; - } - try { - const decryptedData = modules.cryptoModule.decrypt(message); - const decryptedPayload = - decryptedData instanceof ArrayBuffer ? JSON.parse(new TextDecoder().decode(decryptedData)) : decryptedData; - result.payload = decryptedPayload; - return result; - } catch (e) { - if (modules.config.logVerbosity && console && console.log) console.log('decryption error', e.message); - result.payload = message; - result.error = `Error while decrypting message content: ${e.message}`; - } - return result; -} - -export function getOperation() { - return operationConstants.PNFetchMessagesOperation; -} - -export function validateParams(modules, incomingParams) { - const { channels, includeMessageActions = false } = incomingParams; - const { config } = modules; - - if (!channels || channels.length === 0) return 'Missing channels'; - if (!config.subscribeKey) return 'Missing Subscribe Key'; - - if (includeMessageActions && channels.length > 1) { - throw new TypeError( - 'History can return actions data for a single channel only. ' + - 'Either pass a single channel or disable the includeMessageActions flag.', - ); - } -} - -export function getURL(modules, incomingParams) { - const { channels = [], includeMessageActions = false } = incomingParams; - const { config } = modules; - const endpoint = !includeMessageActions ? 'history' : 'history-with-actions'; - - const stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return `/v3/${endpoint}/sub-key/${config.subscribeKey}/channel/${utils.encodeString(stringifiedChannels)}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams(modules, incomingParams) { - const { - channels, - start, - end, - includeMessageActions, - count, - stringifiedTimeToken = false, - includeMeta = false, - includeUuid, - includeUUID = true, - includeMessageType = true, - } = incomingParams; - const outgoingParams = {}; - - if (count) { - outgoingParams.max = count; - } else { - outgoingParams.max = channels.length > 1 || includeMessageActions === true ? 25 : 100; - } - if (start) outgoingParams.start = start; - if (end) outgoingParams.end = end; - if (stringifiedTimeToken) outgoingParams.string_message_token = 'true'; - if (includeMeta) outgoingParams.include_meta = 'true'; - if (includeUUID && includeUuid !== false) outgoingParams.include_uuid = 'true'; - if (includeMessageType) outgoingParams.include_message_type = 'true'; - - return outgoingParams; -} - -export function handleResponse(modules, serverResponse) { - const response = { - channels: {}, - }; - - Object.keys(serverResponse.channels || {}).forEach((channelName) => { - response.channels[channelName] = []; - - (serverResponse.channels[channelName] || []).forEach((messageEnvelope) => { - const announce = {}; - const processedMessgeResult = __processMessage(modules, messageEnvelope.message); - announce.channel = channelName; - announce.timetoken = messageEnvelope.timetoken; - announce.message = processedMessgeResult.payload; - announce.messageType = messageEnvelope.message_type; - announce.uuid = messageEnvelope.uuid; - - if (messageEnvelope.actions) { - announce.actions = messageEnvelope.actions; - - // This should be kept for few updates for existing clients consistency. - announce.data = messageEnvelope.actions; - } - if (messageEnvelope.meta) { - announce.meta = messageEnvelope.meta; - } - if (processedMessgeResult.error) announce.error = processedMessgeResult.error; - - response.channels[channelName].push(announce); - }); - }); - if (serverResponse.more) { - response.more = serverResponse.more; - } - - return response; -} diff --git a/src/core/endpoints/fetch_messages.ts b/src/core/endpoints/fetch_messages.ts new file mode 100644 index 000000000..cb5927495 --- /dev/null +++ b/src/core/endpoints/fetch_messages.ts @@ -0,0 +1,347 @@ +/** + * Fetch messages REST API module. + */ + +import { createValidationError, PubNubError } from '../../errors/pubnub-error'; +import { TransportResponse } from '../types/transport-response'; +import { PubNubAPIError } from '../../errors/pubnub-api-error'; +import { CryptoModule } from '../interfaces/crypto-module'; +import { AbstractRequest } from '../components/request'; +import * as FileSharing from '../types/api/file-sharing'; +import RequestOperation from '../constants/operations'; +import { KeySet, Payload, Query } from '../types/api'; +import * as History from '../types/api/history'; +import { encodeNames } from '../utils'; + +// -------------------------------------------------------- +// ---------------------- Defaults ------------------------ +// -------------------------------------------------------- +// region Defaults + +/** + * Whether verbose logging enabled or not. + */ +const LOG_VERBOSITY = false; + +/** + * Whether message type should be returned or not. + */ +const INCLUDE_MESSAGE_TYPE = true; + +/** + * Whether timetokens should be returned as strings by default or not. + */ +const STRINGIFY_TIMETOKENS = false; + +/** + * Whether message publisher `uuid` should be returned or not. + */ +const INCLUDE_UUID = true; + +/** + * Default number of messages which can be returned for single channel, and it is maximum as well. + */ +const SINGLE_CHANNEL_MESSAGES_COUNT = 100; + +/** + * Default number of messages which can be returned for multiple channels or when fetched + * message actions. + */ +const MULTIPLE_CHANNELS_MESSAGES_COUNT = 25; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = History.FetchMessagesParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; + + /** + * Published data encryption module. + */ + crypto?: CryptoModule; + + /** + * File download Url generation function. + * + * @param parameters - File download Url request configuration parameters. + * + * @returns File download Url. + */ + getFileUrl: (parameters: FileSharing.FileUrlParameters) => string; + + /** + * Whether verbose logging enabled or not. + * + * @default `false` + */ + logVerbosity?: boolean; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Whether service response represent error or not. + */ + error: boolean; + + /** + * Human-readable error explanation. + */ + error_message: string; + + /** + * List of previously published messages per requested channel. + */ + channels: { + [p: string]: { + /** + * Message payload (decrypted). + */ + message: History.FetchedMessage['message']; + + /** + * When message has been received by PubNub service. + */ + timetoken: string; + + /** + * Message publisher unique identifier. + */ + uuid?: string; + + /** + * PubNub-defined message type. + */ + message_type?: History.PubNubMessageType | null; + + /** + * Additional data which has been published along with message to be used with real-time + * events filter expression. + */ + meta?: Payload; + + /** + * List of message reactions. + */ + actions?: History.Actions; + + /** + * Custom published data type (user-provided). + */ + type?: string; + + /** + * Space in which message has been received. + */ + space_id?: string; + }[]; + }; + + /** + * Additional message actions fetch information. + */ + more?: History.MoreActions; +}; +// endregion + +/** + * Fetch messages from channels request. + */ +export class FetchMessagesRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + + // Apply defaults. + const includeMessageActions = parameters.includeMessageActions ?? false; + const defaultCount = + parameters.channels.length > 1 || includeMessageActions + ? MULTIPLE_CHANNELS_MESSAGES_COUNT + : SINGLE_CHANNEL_MESSAGES_COUNT; + if (!parameters.count) parameters.count = defaultCount; + else parameters.count = Math.min(parameters.count, defaultCount); + + if (parameters.includeUuid) parameters.includeUUID = parameters.includeUuid; + else parameters.includeUUID ??= INCLUDE_UUID; + parameters.stringifiedTimeToken ??= STRINGIFY_TIMETOKENS; + parameters.includeMessageType ??= INCLUDE_MESSAGE_TYPE; + parameters.logVerbosity ??= LOG_VERBOSITY; + } + + operation(): RequestOperation { + return RequestOperation.PNFetchMessagesOperation; + } + + validate(): string | undefined { + const { + keySet: { subscribeKey }, + channels, + includeMessageActions, + } = this.parameters; + + if (!subscribeKey) return 'Missing Subscribe Key'; + if (!channels) return 'Missing channels'; + if (includeMessageActions !== undefined && includeMessageActions && channels.length > 1) + return ( + 'History can return actions data for a single channel only. Either pass a single channel ' + + 'or disable the includeMessageActions flag.' + ); + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + const responseChannels = serviceResponse.channels ?? {}; + const channels: History.FetchMessagesResponse['channels'] = {}; + + Object.keys(responseChannels).forEach((channel) => { + // Map service response to expected data object type structure. + channels[channel] = responseChannels[channel].map((payload) => { + // `null` message type means regular message. + if (payload.message_type === null) payload.message_type = History.PubNubMessageType.Message; + const processedPayload = this.processPayload(channel, payload); + + const item = { + channel, + timetoken: payload.timetoken, + message: processedPayload.payload, + messageType: payload.message_type, + uuid: payload.uuid, + }; + + if (payload.actions) { + const itemWithActions = item as unknown as History.FetchedMessageWithActions; + itemWithActions.actions = payload.actions; + + // Backward compatibility for existing users. + // TODO: Remove in next release. + itemWithActions.data = payload.actions; + } + + if (payload.meta) (item as History.FetchedMessage).meta = payload.meta; + if (processedPayload.error) (item as History.FetchedMessage).error = processedPayload.error; + + return item as History.FetchedMessage; + }); + }); + + if (serviceResponse.more) + return { channels, more: serviceResponse.more } as History.FetchMessagesWithActionsResponse; + + return { channels } as History.FetchMessagesResponse; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channels, + includeMessageActions, + } = this.parameters; + const endpoint = !includeMessageActions! ? 'history' : 'history-with-actions'; + + return `/v3/${endpoint}/sub-key/${subscribeKey}/channel/${encodeNames(channels)}`; + } + + protected get queryParameters(): Query { + const { start, end, count, includeMessageType, includeMeta, includeUUID, stringifiedTimeToken } = this.parameters; + + return { + max: count!, + ...(start ? { start } : {}), + ...(end ? { end } : {}), + ...(stringifiedTimeToken! ? { string_message_token: 'true' } : {}), + ...(includeMeta !== undefined && includeMeta ? { include_meta: 'true' } : {}), + ...(includeUUID! ? { include_uuid: 'true' } : {}), + ...(includeMessageType! ? { include_message_type: 'true' } : {}), + }; + } + + /** + * Parse single channel data entry. + * + * @param channel - Channel for which {@link payload} should be processed. + * @param payload - Source payload which should be processed and parsed to expected type. + * + * @returns + */ + private processPayload( + channel: string, + payload: ServiceResponse['channels'][string][number], + ): { + payload: History.FetchedMessage['message']; + error?: string; + } { + const { crypto, logVerbosity } = this.parameters; + if (!crypto || typeof payload.message !== 'string') return { payload: payload.message }; + + let decryptedPayload: History.FetchedMessage['message']; + let error: string | undefined; + + try { + const decryptedData = crypto.decrypt(payload.message); + decryptedPayload = + decryptedData instanceof ArrayBuffer + ? JSON.parse(FetchMessagesRequest.decoder.decode(decryptedData)) + : decryptedData; + } catch (err) { + if (logVerbosity!) console.log(`decryption error`, (err as Error).message); + decryptedPayload = payload.message; + error = `Error while decrypting message content: ${(err as Error).message}`; + } + + if ( + !error && + decryptedPayload && + payload.message_type == History.PubNubMessageType.Files && + typeof decryptedPayload === 'object' && + this.isFileMessage(decryptedPayload) + ) { + const fileMessage = decryptedPayload; + return { + payload: { + message: fileMessage.message, + file: { + ...fileMessage.file, + url: this.parameters.getFileUrl({ channel, id: fileMessage.file.id, name: fileMessage.file.name }), + }, + }, + error, + }; + } + + return { payload: decryptedPayload, error }; + } + + /** + * Check whether `payload` potentially represents file message. + * + * @param payload - Fetched message payload. + * + * @returns `true` if payload can be {@link History#FileMessage|FileMessage}. + */ + private isFileMessage(payload: History.FetchedMessage['message']): payload is History.FileMessage['message'] { + return (payload as History.FileMessage['message']).file !== undefined; + } +} diff --git a/src/core/endpoints/file_upload/delete_file.js b/src/core/endpoints/file_upload/delete_file.js deleted file mode 100644 index 3d3d8f88a..000000000 --- a/src/core/endpoints/file_upload/delete_file.js +++ /dev/null @@ -1,39 +0,0 @@ -/** */ - -import operationConstants from '../../constants/operations'; - -import utils from '../../utils'; - -const endpoint = { - getOperation: () => operationConstants.PNListFilesOperation, - - validateParams: (_, params) => { - if (!params?.channel) { - return "channel can't be empty"; - } - - if (!params?.id) { - return "file id can't be empty"; - } - - if (!params?.name) { - return "file name can't be empty"; - } - }, - - useDelete: () => true, - getURL: ({ config }, params) => - `/v1/files/${config.subscribeKey}/channels/${utils.encodeString(params.channel)}/files/${params.id}/${params.name}`, - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => true, - - prepareParams: () => ({}), - - handleResponse: (_, response) => ({ - status: response.status, - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/file_upload/delete_file.ts b/src/core/endpoints/file_upload/delete_file.ts new file mode 100644 index 000000000..7ccacb914 --- /dev/null +++ b/src/core/endpoints/file_upload/delete_file.ts @@ -0,0 +1,84 @@ +/** + * Delete file REST API module. + */ + +import { createValidationError, PubNubError } from '../../../errors/pubnub-error'; +import { TransportResponse } from '../../types/transport-response'; +import { PubNubAPIError } from '../../../errors/pubnub-api-error'; +import { TransportMethod } from '../../types/transport-request'; +import { AbstractRequest } from '../../components/request'; +import * as FileSharing from '../../types/api/file-sharing'; +import RequestOperation from '../../constants/operations'; +import { encodeString } from '../../utils'; +import { KeySet } from '../../types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = FileSharing.DeleteFileParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request processing result status code. + */ + status: number; +}; +// endregion + +/** + * Delete File request. + */ +export class DeleteFileRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super({ method: TransportMethod.DELETE }); + } + + operation(): RequestOperation { + return RequestOperation.PNDeleteFileOperation; + } + + validate(): string | undefined { + const { channel, id, name } = this.parameters; + + if (!channel) return "channel can't be empty"; + if (!id) return "file id can't be empty"; + if (!name) return "file name can't be empty"; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + return serviceResponse; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + id, + channel, + name, + } = this.parameters; + + return `/v1/files/${subscribeKey}/channels/${encodeString(channel)}/files/${id}/${name}`; + } +} diff --git a/src/core/endpoints/file_upload/download_file.js b/src/core/endpoints/file_upload/download_file.js deleted file mode 100644 index 3668f6336..000000000 --- a/src/core/endpoints/file_upload/download_file.js +++ /dev/null @@ -1,56 +0,0 @@ -// Download_file.js - -/** */ - -import operationConstants from '../../constants/operations'; - -import utils from '../../utils'; - -const endpoint = { - getOperation: () => operationConstants.PNDownloadFileOperation, - - validateParams: (_, params) => { - if (!params?.channel) { - return "channel can't be empty"; - } - - if (!params?.name) { - return "name can't be empty"; - } - - if (!params?.id) { - return "id can't be empty"; - } - }, - - useGetFile: () => true, - - getFileURL: ({ config }, params) => - `/v1/files/${config.subscribeKey}/channels/${utils.encodeString(params.channel)}/files/${params.id}/${params.name}`, - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => true, - ignoreBody: () => true, - forceBuffered: () => true, - - prepareParams: () => ({}), - - handleResponse: async ({ PubNubFile, config, cryptography, cryptoModule }, res, params) => { - let { body } = res.response; - if (PubNubFile.supportsEncryptFile && (params.cipherKey || cryptoModule)) { - body = - params.cipherKey == null - ? (await cryptoModule.decryptFile(PubNubFile.create({ data: body, name: params.name }), PubNubFile)).data - : await cryptography.decrypt(params.cipherKey ?? config.cipherKey, body); - } - - return PubNubFile.create({ - data: body, - name: res.response.name ?? params.name, - mimeType: res.response.type, - }); - }, -}; - -export default endpoint; diff --git a/src/core/endpoints/file_upload/download_file.ts b/src/core/endpoints/file_upload/download_file.ts new file mode 100644 index 000000000..6f91ec76a --- /dev/null +++ b/src/core/endpoints/file_upload/download_file.ts @@ -0,0 +1,101 @@ +/** + * Download File REST API module. + */ + +import { PubNubBasicFileParameters, PubNubFileConstructor, PubNubFileInterface } from '../../types/file'; +import { TransportResponse } from '../../types/transport-response'; +import { CryptoModule } from '../../interfaces/crypto-module'; +import { Cryptography } from '../../interfaces/cryptography'; +import { AbstractRequest } from '../../components/request'; +import * as FileSharing from '../../types/api/file-sharing'; +import RequestOperation from '../../constants/operations'; +import { encodeString } from '../../utils'; +import { KeySet } from '../../types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = FileSharing.DownloadFileParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; + + /** + * File object constructor. + */ + PubNubFile: PubNubFileConstructor; + + /** + * Send file decryption module. + */ + crypto?: CryptoModule; + + /** + * Legacy cryptography module. + */ + cryptography?: Cryptography; +}; +// endregion + +/** + * Download File request. + */ +export class DownloadFileRequest< + PlatformFile extends Partial = Record, +> extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + } + + operation(): RequestOperation { + return RequestOperation.PNDownloadFileOperation; + } + + validate(): string | undefined { + const { channel, id, name } = this.parameters; + + if (!channel) return "channel can't be empty"; + if (!id) return "file id can't be empty"; + if (!name) return "file name can't be empty"; + } + + async parse(response: TransportResponse): Promise { + const { cipherKey, crypto, cryptography, name, PubNubFile } = this.parameters; + const mimeType = response.headers['content-type']; + let decryptedFile: PubNubFileInterface | undefined; + let body = response.body!; + + if (PubNubFile.supportsEncryptFile && (cipherKey || crypto)) { + if (cipherKey && cryptography) body = await cryptography.decrypt(cipherKey, body); + else if (!cipherKey && crypto) + decryptedFile = await crypto.decryptFile(PubNubFile.create({ data: body, name: name, mimeType }), PubNubFile); + } + + return ( + decryptedFile + ? decryptedFile + : PubNubFile.create({ + data: body, + name, + mimeType, + }) + ) as PlatformFile; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channel, + id, + name, + } = this.parameters; + + return `/v1/files/${subscribeKey}/channels/${encodeString(channel)}/files/${id}/${name}`; + } +} diff --git a/src/core/endpoints/file_upload/generate_upload_url.js b/src/core/endpoints/file_upload/generate_upload_url.js deleted file mode 100644 index cb7861978..000000000 --- a/src/core/endpoints/file_upload/generate_upload_url.js +++ /dev/null @@ -1,41 +0,0 @@ -/** */ - -import operationConstants from '../../constants/operations'; - -import utils from '../../utils'; - -const endpoint = { - getOperation: () => operationConstants.PNGenerateUploadUrlOperation, - - validateParams: (_, params) => { - if (!params?.channel) { - return "channel can't be empty"; - } - - if (!params?.name) { - return "name can't be empty"; - } - }, - - usePost: () => true, - postURL: ({ config }, params) => - `/v1/files/${config.subscribeKey}/channels/${utils.encodeString(params.channel)}/generate-upload-url`, - - postPayload: (_, params) => ({ - name: params.name, - }), - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => true, - - prepareParams: () => ({}), - - handleResponse: (_, response) => ({ - status: response.status, - data: response.data, - file_upload_request: response.file_upload_request, - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/file_upload/generate_upload_url.ts b/src/core/endpoints/file_upload/generate_upload_url.ts new file mode 100644 index 000000000..8f1b43b1c --- /dev/null +++ b/src/core/endpoints/file_upload/generate_upload_url.ts @@ -0,0 +1,148 @@ +/** + * Generate file upload URL REST API request. + */ + +import { createValidationError, PubNubError } from '../../../errors/pubnub-error'; +import { TransportResponse } from '../../types/transport-response'; +import { PubNubAPIError } from '../../../errors/pubnub-api-error'; +import { TransportMethod } from '../../types/transport-request'; +import { AbstractRequest } from '../../components/request'; +import * as FileSharing from '../../types/api/file-sharing'; +import RequestOperation from '../../constants/operations'; +import { encodeString } from '../../utils'; +import { KeySet } from '../../types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = FileSharing.GenerateFileUploadUrlParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * File upload URL generation result status code. + */ + status: number; + + /** + * PubNub Service response. + */ + data: { + /** + * Unique file identifier. + * + * Unique file identifier, and it's {@link name} can be used to download file from the channel + * later. + */ + id: string; + + /** + * Actual file name under which file has been stored. + * + * File name and unique {@link id} can be used to download file from the channel later. + * + * **Note:** Actual file name may be different from the one which has been used during file + * upload. + */ + name: string; + }; + + /** + * PubNub service response extension. + */ + file_upload_request: { + /** + * Pre-signed URL for file upload. + */ + url: string; + + /** + * HTTP method which should be used for file upload. + */ + method: string; + + /** + * Expiration date (ISO 8601 format) for the pre-signed upload request. + */ + expiration_date: string; + + /** + * An array of form fields to be used in the pre-signed POST request. + * + * **Important:** Form data fields should be passed in exact same order as received from + * the PubNub service. + */ + form_fields: { + /** + * Form data field name. + */ + name: string; + /** + * Form data field value. + */ + value: string; + }[]; + }; +}; +// endregion + +/** + * Generate File Upload Url request. + */ +export class GenerateFileUploadUrlRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super({ method: TransportMethod.POST }); + } + + operation(): RequestOperation { + return RequestOperation.PNGenerateUploadUrlOperation; + } + + validate(): string | undefined { + if (!this.parameters.channel) return "channel can't be empty"; + if (!this.parameters.name) return "'name' can't be empty"; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + return { + id: serviceResponse.data.id, + name: serviceResponse.data.name, + url: serviceResponse.file_upload_request.url, + formFields: serviceResponse.file_upload_request.form_fields, + }; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channel, + } = this.parameters; + + return `/v1/files/${subscribeKey}/channels/${encodeString(channel)}/generate-upload-url`; + } + + protected get body(): ArrayBuffer | string | undefined { + return JSON.stringify({ name: this.parameters.name }); + } +} diff --git a/src/core/endpoints/file_upload/get_file_url.js b/src/core/endpoints/file_upload/get_file_url.js deleted file mode 100644 index 01169563b..000000000 --- a/src/core/endpoints/file_upload/get_file_url.js +++ /dev/null @@ -1,63 +0,0 @@ -/** */ - -import { PubNubError, createValidationError, signRequest, generatePNSDK } from '../../components/endpoint'; - -import utils from '../../utils'; - -export default (modules, { channel, id, name }) => { - const { config, networking, tokenManager } = modules; - - if (!channel) { - throw new PubNubError( - 'Validation failed, check status for details', - createValidationError("channel can't be empty"), - ); - } - - if (!id) { - throw new PubNubError( - 'Validation failed, check status for details', - createValidationError("file id can't be empty"), - ); - } - - if (!name) { - throw new PubNubError( - 'Validation failed, check status for details', - createValidationError("file name can't be empty"), - ); - } - - const url = `/v1/files/${config.subscribeKey}/channels/${utils.encodeString(channel)}/files/${id}/${name}`; - const params = {}; - - params.uuid = config.getUUID(); - params.pnsdk = generatePNSDK(config); - - const tokenOrKey = tokenManager.getToken() || config.getAuthKey(); - if (tokenOrKey) { - params.auth = tokenOrKey; - } - - if (config.secretKey) { - signRequest( - modules, - url, - params, - {}, - { - getOperation: () => 'PubNubGetFileUrlOperation', - }, - ); - } - - const queryParams = Object.keys(params) - .map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`) - .join('&'); - - if (queryParams !== '') { - return `${networking.getStandardOrigin()}${url}?${queryParams}`; - } - - return `${networking.getStandardOrigin()}${url}`; -}; diff --git a/src/core/endpoints/file_upload/get_file_url.ts b/src/core/endpoints/file_upload/get_file_url.ts new file mode 100644 index 000000000..300ed96d6 --- /dev/null +++ b/src/core/endpoints/file_upload/get_file_url.ts @@ -0,0 +1,70 @@ +/** + * File sharing REST API module. + */ + +import { TransportResponse } from '../../types/transport-response'; +import { TransportMethod } from '../../types/transport-request'; +import { AbstractRequest } from '../../components/request'; +import * as FileSharing from '../../types/api/file-sharing'; +import RequestOperation from '../../constants/operations'; +import { encodeString } from '../../utils'; +import { KeySet } from '../../types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = FileSharing.FileUrlParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; +// endregion + +/** + * File download Url generation request. + * + * Local request which generates Url to download shared file from the specific channel. + */ +export class GetFileDownloadUrlRequest extends AbstractRequest { + /** + * Construct file download Url generation request. + * + * @param parameters - Request configuration. + */ + constructor(private readonly parameters: RequestParameters) { + super({ method: TransportMethod.LOCAL }); + } + + operation(): RequestOperation { + return RequestOperation.PNGetFileUrlOperation; + } + + validate(): string | undefined { + const { channel, id, name } = this.parameters; + + if (!channel) return "channel can't be empty"; + if (!id) return "file id can't be empty"; + if (!name) return "file name can't be empty"; + } + + async parse(response: TransportResponse): Promise { + return response.url; + } + + protected get path(): string { + const { + channel, + id, + name, + keySet: { subscribeKey }, + } = this.parameters; + + return `/v1/files/${subscribeKey}/channels/${encodeString(channel)}/files/${id}/${name}`; + } +} diff --git a/src/core/endpoints/file_upload/list_files.js b/src/core/endpoints/file_upload/list_files.js deleted file mode 100644 index 5a04502c6..000000000 --- a/src/core/endpoints/file_upload/list_files.js +++ /dev/null @@ -1,45 +0,0 @@ -/** */ - -import operationConstants from '../../constants/operations'; - -import utils from '../../utils'; - -const endpoint = { - getOperation: () => operationConstants.PNListFilesOperation, - - validateParams: (_, params) => { - if (!params?.channel) { - return "channel can't be empty"; - } - }, - - getURL: ({ config }, params) => - `/v1/files/${config.subscribeKey}/channels/${utils.encodeString(params.channel)}/files`, - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => true, - - prepareParams: (_, params) => { - const outParams = {}; - - if (params.limit) { - outParams.limit = params.limit; - } - - if (params.next) { - outParams.next = params.next; - } - - return outParams; - }, - - handleResponse: (_, response) => ({ - status: response.status, - data: response.data, - next: response.next, - count: response.count, - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/file_upload/list_files.ts b/src/core/endpoints/file_upload/list_files.ts new file mode 100644 index 000000000..0d1f95304 --- /dev/null +++ b/src/core/endpoints/file_upload/list_files.ts @@ -0,0 +1,112 @@ +/** + * List Files REST API module. + */ + +import { createValidationError, PubNubError } from '../../../errors/pubnub-error'; +import { TransportResponse } from '../../types/transport-response'; +import { PubNubAPIError } from '../../../errors/pubnub-api-error'; +import { AbstractRequest } from '../../components/request'; +import * as FileSharing from '../../types/api/file-sharing'; +import RequestOperation from '../../constants/operations'; +import { KeySet, Query } from '../../types/api'; +import { encodeString } from '../../utils'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Number of files to return in response. + */ +const LIMIT = 100; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = FileSharing.ListFilesParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request processing result status code. + */ + status: number; + + /** + * List of shared files for specified channel. + */ + data: FileSharing.SharedFile[]; + + /** + * Next files list page token. + */ + next: string; + + /** + * Number of returned files. + */ + count: number; +}; +// endregion + +/** + * Files List request. + */ +export class FilesListRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + + // Apply default request parameters. + this.parameters.limit ??= LIMIT; + } + + operation(): RequestOperation { + return RequestOperation.PNListFilesOperation; + } + + validate(): string | undefined { + if (!this.parameters.channel) return "channel can't be empty"; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + return serviceResponse; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channel, + } = this.parameters; + + return `/v1/files/${subscribeKey}/channels/${encodeString(channel)}/files`; + } + + protected get queryParameters(): Query { + const { limit, next } = this.parameters; + + return { limit: limit!, ...(next ? { next } : {}) }; + } +} diff --git a/src/core/endpoints/file_upload/publish_file.js b/src/core/endpoints/file_upload/publish_file.js deleted file mode 100644 index 3a111935f..000000000 --- a/src/core/endpoints/file_upload/publish_file.js +++ /dev/null @@ -1,79 +0,0 @@ -/** */ - -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; -import { encode } from '../../components/base64_codec'; - -const preparePayload = (modules, payload) => { - let stringifiedPayload = JSON.stringify(payload); - if (modules.cryptoModule) { - const encrypted = modules.cryptoModule.encrypt(stringifiedPayload); - stringifiedPayload = typeof encrypted === 'string' ? encrypted : encode(encrypted); - stringifiedPayload = JSON.stringify(stringifiedPayload); - } - return stringifiedPayload || ''; -}; - -const endpoint = { - getOperation: () => operationConstants.PNPublishFileOperation, - - validateParams: (_, params) => { - if (!params?.channel) { - return "channel can't be empty"; - } - - if (!params?.fileId) { - return "file id can't be empty"; - } - - if (!params?.fileName) { - return "file name can't be empty"; - } - }, - - getURL: (modules, params) => { - const { publishKey, subscribeKey } = modules.config; - - const message = { - message: params.message, - file: { - name: params.fileName, - id: params.fileId, - }, - }; - - const payload = preparePayload(modules, message); - - return `/v1/files/publish-file/${publishKey}/${subscribeKey}/0/${utils.encodeString( - params.channel, - )}/0/${utils.encodeString(payload)}`; - }, - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => true, - - prepareParams: (_, params) => { - const outParams = {}; - - if (params.ttl) { - outParams.ttl = params.ttl; - } - - if (params.storeInHistory !== undefined) { - outParams.store = params.storeInHistory ? '1' : '0'; - } - - if (params.meta && typeof params.meta === 'object') { - outParams.meta = JSON.stringify(params.meta); - } - - return outParams; - }, - - handleResponse: (_, response) => ({ - timetoken: response['2'], - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/file_upload/publish_file.ts b/src/core/endpoints/file_upload/publish_file.ts new file mode 100644 index 000000000..a88fd5682 --- /dev/null +++ b/src/core/endpoints/file_upload/publish_file.ts @@ -0,0 +1,134 @@ +/** + * Publish File Message REST API module. + */ + +import { createValidationError, PubNubError } from '../../../errors/pubnub-error'; +import { TransportResponse } from '../../types/transport-response'; +import { CryptoModule } from '../../interfaces/crypto-module'; +import { AbstractRequest } from '../../components/request'; +import * as FileSharing from '../../types/api/file-sharing'; +import RequestOperation from '../../constants/operations'; +import { KeySet, Payload, Query } from '../../types/api'; +import { encode } from '../../components/base64_codec'; +import { encodeString } from '../../utils'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Whether published file messages should be stored in the channel's history. + */ +const STORE_IN_HISTORY = true; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = FileSharing.PublishFileMessageParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; + + /** + * Published data encryption module. + */ + crypto?: CryptoModule; +}; + +/** + * Service success response. + */ +type ServiceResponse = [0 | 1, string, string]; +// endregion + +export class PublishFileMessageRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + + // Apply default request parameters. + this.parameters.storeInHistory ??= STORE_IN_HISTORY; + } + + operation(): RequestOperation { + return RequestOperation.PNPublishFileMessageOperation; + } + + validate(): string | undefined { + const { channel, fileId, fileName } = this.parameters; + + if (!channel) return "channel can't be empty"; + if (!fileId) return "file id can't be empty"; + if (!fileName) return "file name can't be empty"; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return { timetoken: serviceResponse[2] }; + } + + protected get path(): string { + const { + message, + channel, + keySet: { publishKey, subscribeKey }, + fileId, + fileName, + } = this.parameters; + + const fileMessage = { + file: { + name: fileName, + id: fileId, + }, + ...(message ? { message } : {}), + }; + + return `/v1/files/publish-file/${publishKey}/${subscribeKey}/0/${encodeString(channel)}/0/${encodeString( + this.prepareMessagePayload(fileMessage), + )}`; + } + + protected get queryParameters(): Query { + const { storeInHistory, ttl, meta } = this.parameters; + return { + store: storeInHistory! ? '1' : '0', + ...(ttl ? { ttl } : {}), + ...(meta && typeof meta === 'object' ? { meta: JSON.stringify(meta) } : {}), + }; + } + + /** + * Pre-process provided data. + * + * Data will be "normalized" and encrypted if `cryptoModule` has been provided. + * + * @param payload - User-provided data which should be pre-processed before use. + * + * @returns Payload which can be used as part of request URL or body. + * + * @throws {Error} in case if provided `payload` or results of `encryption` can't be stringified. + */ + private prepareMessagePayload(payload: Payload): string { + const { crypto } = this.parameters; + if (!crypto) return JSON.stringify(payload) || ''; + + const encrypted = crypto.encrypt(JSON.stringify(payload)); + + return JSON.stringify(typeof encrypted === 'string' ? encrypted : encode(encrypted)); + } +} diff --git a/src/core/endpoints/file_upload/send_file.js b/src/core/endpoints/file_upload/send_file.js deleted file mode 100644 index f2d2fb810..000000000 --- a/src/core/endpoints/file_upload/send_file.js +++ /dev/null @@ -1,130 +0,0 @@ -import { PubNubError, createValidationError } from '../../components/endpoint'; - -const sendFile = function ({ - generateUploadUrl, - publishFile, - modules: { PubNubFile, config, cryptography, cryptoModule, networking }, -}) { - return async ({ channel, file: input, message, cipherKey, meta, ttl, storeInHistory }) => { - if (!channel) { - throw new PubNubError( - 'Validation failed, check status for details', - createValidationError("channel can't be empty"), - ); - } - - if (!input) { - throw new PubNubError( - 'Validation failed, check status for details', - createValidationError("file can't be empty"), - ); - } - - let file = PubNubFile.create(input); - - const { - file_upload_request: { url, form_fields: formFields }, - data: { id, name }, - } = await generateUploadUrl({ channel, name: file.name }); - - if (PubNubFile.supportsEncryptFile && (cipherKey || cryptoModule)) { - file = - cipherKey == null - ? await cryptoModule.encryptFile(file, PubNubFile) - : await cryptography.encryptFile(cipherKey, file, PubNubFile); - } - - let formFieldsWithMimeType = formFields; - - if (file.mimeType) { - formFieldsWithMimeType = formFields.map((entry) => { - if (entry.key === 'Content-Type') return { key: entry.key, value: file.mimeType }; - return entry; - }); - } - - let result; - - try { - if (PubNubFile.supportsFileUri && input.uri) { - result = await networking.POSTFILE(url, formFieldsWithMimeType, await file.toFileUri()); - } else if (PubNubFile.supportsFile) { - result = await networking.POSTFILE(url, formFieldsWithMimeType, await file.toFile()); - } else if (PubNubFile.supportsBuffer) { - result = await networking.POSTFILE(url, formFieldsWithMimeType, await file.toBuffer()); - } else if (PubNubFile.supportsBlob) { - result = await networking.POSTFILE(url, formFieldsWithMimeType, await file.toBlob()); - } else { - throw new Error('Unsupported environment'); - } - } catch (e) { - if (e.response && typeof e.response.text === 'string') { - const errorBody = e.response.text; - const reason = /(.*)<\/Message>/gi.exec(errorBody); - throw new PubNubError(reason ? `Upload to bucket failed: ${reason[1]}` : 'Upload to bucket failed.', e); - } else { - throw new PubNubError('Upload to bucket failed.', e); - } - } - - if (result.status !== 204) { - throw new PubNubError('Upload to bucket was unsuccessful', result); - } - - let retries = config.fileUploadPublishRetryLimit; - let wasSuccessful = false; - - let publishResult = { timetoken: '0' }; - - do { - try { - /* eslint-disable-next-line no-await-in-loop */ - publishResult = await publishFile({ - channel, - message, - fileId: id, - fileName: name, - meta, - storeInHistory, - ttl, - }); - - wasSuccessful = true; - } catch (e) { - retries -= 1; - } - } while (!wasSuccessful && retries > 0); - - if (!wasSuccessful) { - throw new PubNubError( - 'Publish failed. You may want to execute that operation manually using pubnub.publishFile', - { - channel, - id, - name, - }, - ); - } else { - return { - timetoken: publishResult.timetoken, - id, - name, - }; - } - }; -}; - -export default (deps) => { - const f = sendFile(deps); - - return (params, cb) => { - const resultP = f(params); - - if (typeof cb === 'function') { - resultP.then((result) => cb(null, result)).catch((error) => cb(error, null)); - - return resultP; - } - return resultP; - }; -}; diff --git a/src/core/endpoints/file_upload/send_file.ts b/src/core/endpoints/file_upload/send_file.ts new file mode 100644 index 000000000..0c50dfae6 --- /dev/null +++ b/src/core/endpoints/file_upload/send_file.ts @@ -0,0 +1,197 @@ +import { PubNubFileConstructor, PubNubFileInterface } from '../../types/file'; +import { GenerateFileUploadUrlRequest } from './generate_upload_url'; +import { CryptoModule } from '../../interfaces/crypto-module'; +import { Cryptography } from '../../interfaces/cryptography'; +import { AbstractRequest } from '../../components/request'; +import * as FileSharing from '../../types/api/file-sharing'; +import { PubNubError } from '../../../errors/pubnub-error'; +import RequestOperation from '../../constants/operations'; +import { UploadFileRequest } from './upload-file'; +import { PubNubAPIError } from '../../../errors/pubnub-api-error'; +import { KeySet } from '../../types/api'; +import StatusCategory from '../../constants/categories'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = FileSharing.SendFileParameters & { + /** + * How many times should retry file message publish. + */ + fileUploadPublishRetryLimit: number; + + /** + * PubNub REST API access key set. + */ + keySet: KeySet; + + /** + * {@link PubNub} File object constructor. + */ + PubNubFile: PubNubFileConstructor; + + /** + * Request sending method. + * + * @param request - Request which should be processed. + */ + sendRequest: (request: AbstractRequest) => Promise; + + /** + * File message publish method. + * + * @param parameters - File message request parameters. + */ + publishFile: ( + parameters: FileSharing.PublishFileMessageParameters, + ) => Promise; + + /** + * If passed, will encrypt the payloads. + * + * @deprecated Pass it to {@link crypto} module instead. + */ + cipherKey?: string; + + /** + * Published data encryption module. + */ + crypto?: CryptoModule; + + /** + * Legacy cryptography module. + */ + cryptography?: Cryptography; +}; +// endregion + +/** + * Send file composed request. + */ +export class SendFileRequest { + /** + * File object for upload. + */ + private file?: PubNubFileInterface; + + constructor(private readonly parameters: RequestParameters) { + this.file = this.parameters.PubNubFile?.create(parameters.file); + + if (!this.file) throw new Error('File upload error: unable to create File object.'); + } + + /** + * Process user-input and upload file. + * + * @returns File upload request response. + */ + public async process(): Promise { + let fileName: string | undefined; + let fileId: string | undefined; + + return this.generateFileUploadUrl() + .then((result) => { + fileName = result.name; + fileId = result.id; + return this.uploadFile(result); + }) + .then((result) => { + if (result.status !== 204) { + throw new PubNubError('Upload to bucket was unsuccessful', { + error: true, + statusCode: result.status, + category: StatusCategory.PNUnknownCategory, + operation: RequestOperation.PNPublishFileOperation, + errorData: { message: result.message }, + }); + } + }) + .then(() => this.publishFileMessage(fileId!, fileName!)) + .catch((error: Error) => { + if (error instanceof PubNubError) throw error; + + const apiError = !(error instanceof PubNubAPIError) ? PubNubAPIError.create(error) : error; + throw new PubNubError('File upload error.', apiError.toStatus(RequestOperation.PNPublishFileOperation)); + }); + } + + /** + * Generate pre-signed file upload Url. + * + * @returns File upload credentials. + */ + private async generateFileUploadUrl(): Promise { + const request = new GenerateFileUploadUrlRequest({ + ...this.parameters, + name: this.file!.name, + keySet: this.parameters.keySet, + }); + + return this.parameters.sendRequest(request); + } + + /** + * Prepare and upload {@link PubNub} File object to remote storage. + * + * @param uploadParameters - File upload request parameters. + * + * @returns + */ + private async uploadFile(uploadParameters: FileSharing.GenerateFileUploadUrlResponse) { + const { cipherKey, PubNubFile, crypto, cryptography } = this.parameters; + const { id, name, url, formFields } = uploadParameters; + + // Encrypt file if possible. + if (this.parameters.PubNubFile!.supportsEncryptFile) { + if (!cipherKey && crypto) this.file = (await crypto.encryptFile(this.file!, PubNubFile!))!; + else if (cipherKey && cryptography) + this.file = (await cryptography.encryptFile(cipherKey, this.file!, PubNubFile!))!; + } + + return this.parameters.sendRequest( + new UploadFileRequest({ + fileId: id, + fileName: name, + file: this.file!, + uploadUrl: url, + formFields, + }), + ); + } + + private async publishFileMessage(fileId: string, fileName: string): Promise { + let result: FileSharing.PublishFileMessageResponse = { timetoken: '0' }; + let retries = this.parameters.fileUploadPublishRetryLimit; + let publishError: PubNubError | undefined; + let wasSuccessful = false; + + do { + try { + result = await this.parameters.publishFile({ ...this.parameters, fileId, fileName }); + wasSuccessful = true; + } catch (error: unknown) { + if (error instanceof PubNubError) publishError = error; + retries -= 1; + } + } while (!wasSuccessful && retries > 0); + + if (!wasSuccessful) { + throw new PubNubError( + 'Publish failed. You may want to execute that operation manually using pubnub.publishFile', + { + error: true, + category: publishError!.status?.category ?? StatusCategory.PNUnknownCategory, + statusCode: publishError!.status?.statusCode ?? 0, + channel: this.parameters.channel, + id: fileId, + name: fileName, + }, + ); + } else return { status: 200, timetoken: result.timetoken, id: fileId, name: fileName }; + } +} diff --git a/src/core/endpoints/file_upload/types.js b/src/core/endpoints/file_upload/types.js deleted file mode 100644 index 0975b9062..000000000 --- a/src/core/endpoints/file_upload/types.js +++ /dev/null @@ -1 +0,0 @@ -/** */ diff --git a/src/core/endpoints/file_upload/upload-file.ts b/src/core/endpoints/file_upload/upload-file.ts new file mode 100644 index 000000000..7147e819c --- /dev/null +++ b/src/core/endpoints/file_upload/upload-file.ts @@ -0,0 +1,70 @@ +/** + * Upload file REST API request. + */ + +import { TransportResponse } from '../../types/transport-response'; +import { TransportMethod, TransportRequest } from '../../types/transport-request'; +import { AbstractRequest } from '../../components/request'; +import * as FileSharing from '../../types/api/file-sharing'; +import RequestOperation from '../../constants/operations'; +import { PubNubFileInterface } from '../../types/file'; + +/** + * File Upload request. + */ +export class UploadFileRequest extends AbstractRequest { + constructor(private readonly parameters: FileSharing.UploadFileParameters) { + super({ method: TransportMethod.POST }); + + // Use file's actual mime type if available. + const mimeType = parameters.file.mimeType; + if (mimeType) { + parameters.formFields = parameters.formFields.map((entry) => { + if (entry.name === 'Content-Type') return { name: entry.name, value: mimeType }; + return entry; + }); + } + } + + operation(): RequestOperation { + return RequestOperation.PNPublishFileOperation; + } + + validate(): string | undefined { + const { fileId, fileName, file, uploadUrl } = this.parameters; + + if (!fileId) return "Validation failed: file 'id' can't be empty"; + if (!fileName) return "Validation failed: file 'name' can't be empty"; + if (!file) return "Validation failed: 'file' can't be empty"; + if (!uploadUrl) return "Validation failed: file upload 'url' can't be empty"; + } + + async parse(response: TransportResponse): Promise { + return { + status: response.status, + message: response.body ? UploadFileRequest.decoder.decode(response.body) : 'OK', + }; + } + + request(): TransportRequest { + return { + ...super.request(), + origin: new URL(this.parameters.uploadUrl).origin, + timeout: 300, + }; + } + + protected get path(): string { + const { pathname, search } = new URL(this.parameters.uploadUrl); + + return `${pathname}${search}`; + } + + protected get body(): ArrayBuffer | PubNubFileInterface | string | undefined { + return this.parameters.file; + } + + protected get formData(): Record[] | undefined { + return this.parameters.formFields; + } +} diff --git a/src/core/endpoints/history/delete_messages.js b/src/core/endpoints/history/delete_messages.js deleted file mode 100644 index aaf8b12d7..000000000 --- a/src/core/endpoints/history/delete_messages.js +++ /dev/null @@ -1,50 +0,0 @@ -/* */ - -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -export function getOperation() { - return operationConstants.PNDeleteMessagesOperation; -} - -export function validateParams(modules, incomingParams) { - const { channel } = incomingParams; - const { config } = modules; - - if (!channel) return 'Missing channel'; - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function useDelete() { - return true; -} - -export function getURL(modules, incomingParams) { - const { channel } = incomingParams; - const { config } = modules; - - return `/v3/history/sub-key/${config.subscribeKey}/channel/${utils.encodeString(channel)}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams(modules, incomingParams) { - const { start, end } = incomingParams; - - const outgoingParams = {}; - - if (start) outgoingParams.start = start; - if (end) outgoingParams.end = end; - - return outgoingParams; -} - -export function handleResponse(modules, serverResponse) { - return serverResponse.payload; -} diff --git a/src/core/endpoints/history/delete_messages.ts b/src/core/endpoints/history/delete_messages.ts new file mode 100644 index 000000000..f2a4f8269 --- /dev/null +++ b/src/core/endpoints/history/delete_messages.ts @@ -0,0 +1,98 @@ +/** + * Delete messages REST API module. + */ + +import { createValidationError, PubNubError } from '../../../errors/pubnub-error'; +import type { TransportResponse } from '../../types/transport-response'; +import { PubNubAPIError } from '../../../errors/pubnub-api-error'; +import { TransportMethod } from '../../types/transport-request'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import * as History from '../../types/api/history'; +import { KeySet, Query } from '../../types/api'; +import { encodeString } from '../../utils'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = History.DeleteMessagesParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Whether service response represent error or not. + */ + error: boolean; + + /** + * Human-readable error explanation. + */ + error_message: string; +}; +// endregion + +/** + * Delete messages from channel history. + */ +export class DeleteMessageRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super({ method: TransportMethod.DELETE }); + } + + operation(): RequestOperation { + return RequestOperation.PNDeleteMessagesOperation; + } + + validate(): string | undefined { + if (!this.parameters.keySet.subscribeKey) return 'Missing Subscribe Key'; + if (!this.parameters.channel) return 'Missing channel'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + return {}; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channel, + } = this.parameters; + + return `/v3/history/sub-key/${subscribeKey}/channel/${encodeString(channel)}`; + } + + protected get queryParameters(): Query { + const { start, end } = this.parameters; + + return { + ...(start ? { start } : {}), + ...(end ? { end } : {}), + }; + } +} diff --git a/src/core/endpoints/history/get_history.js b/src/core/endpoints/history/get_history.js deleted file mode 100644 index bf76c52a2..000000000 --- a/src/core/endpoints/history/get_history.js +++ /dev/null @@ -1,92 +0,0 @@ -/* */ -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -function __processMessage(modules, message) { - const result = {}; - if (!modules.cryptoModule) { - result.payload = message; - return result; - } - try { - const decryptedData = modules.cryptoModule.decrypt(message); - const decryptedPayload = - decryptedData instanceof ArrayBuffer ? JSON.parse(new TextDecoder().decode(decryptedData)) : decryptedData; - result.payload = decryptedPayload; - return result; - } catch (e) { - if (modules.config.logVerbosity && console && console.log) console.log('decryption error', e.message); - result.payload = message; - result.error = `Error while decrypting message content: ${e.message}`; - } - return result; -} - -export function getOperation() { - return operationConstants.PNHistoryOperation; -} - -export function validateParams(modules, incomingParams) { - const { channel } = incomingParams; - const { config } = modules; - - if (!channel) return 'Missing channel'; - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules, incomingParams) { - const { channel } = incomingParams; - const { config } = modules; - return `/v2/history/sub-key/${config.subscribeKey}/channel/${utils.encodeString(channel)}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams(modules, incomingParams) { - const { start, end, reverse, count = 100, stringifiedTimeToken = false, includeMeta = false } = incomingParams; - const outgoingParams = { - include_token: 'true', - }; - - outgoingParams.count = count; - if (start) outgoingParams.start = start; - if (end) outgoingParams.end = end; - if (stringifiedTimeToken) outgoingParams.string_message_token = 'true'; - if (reverse != null) outgoingParams.reverse = reverse.toString(); - if (includeMeta) outgoingParams.include_meta = 'true'; - - return outgoingParams; -} - -export function handleResponse(modules, serverResponse) { - const response = { - messages: [], - startTimeToken: serverResponse[1], - endTimeToken: serverResponse[2], - }; - - if (Array.isArray(serverResponse[0])) { - serverResponse[0].forEach((serverHistoryItem) => { - const processedMessgeResult = __processMessage(modules, serverHistoryItem.message); - const item = { - timetoken: serverHistoryItem.timetoken, - entry: processedMessgeResult.payload, - }; - - if (serverHistoryItem.meta) { - item.meta = serverHistoryItem.meta; - } - if (processedMessgeResult.error) item.error = processedMessgeResult.error; - - response.messages.push(item); - }); - } - - return response; -} diff --git a/src/core/endpoints/history/get_history.ts b/src/core/endpoints/history/get_history.ts new file mode 100644 index 000000000..206a05b57 --- /dev/null +++ b/src/core/endpoints/history/get_history.ts @@ -0,0 +1,210 @@ +/** + * Get history REST API module. + */ + +import { createValidationError, PubNubError } from '../../../errors/pubnub-error'; +import { TransportResponse } from '../../types/transport-response'; +import { CryptoModule } from '../../interfaces/crypto-module'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import { KeySet, Payload, Query } from '../../types/api'; +import * as History from '../../types/api/history'; +import { encodeString } from '../../utils'; + +// -------------------------------------------------------- +// ---------------------- Defaults ------------------------ +// -------------------------------------------------------- +// region Defaults + +/** + * Whether verbose logging enabled or not. + */ +const LOG_VERBOSITY = false; + +/** + * Whether associated message metadata should be returned or not. + */ +const INCLUDE_METADATA = false; + +/** + * Whether timetokens should be returned as strings by default or not. + */ +const STRINGIFY_TIMETOKENS = false; + +/** + * Default and maximum number of messages which should be returned. + */ +const MESSAGES_COUNT = 100; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = History.GetHistoryParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; + + /** + * Published data encryption module. + */ + crypto?: CryptoModule; + + /** + * Whether verbose logging enabled or not. + * + * @default `false` + */ + logVerbosity?: boolean; +}; + +/** + * Service success response. + */ +type ServiceResponse = [ + /** + * List of previously published messages. + */ + { + /** + * Message payload (decrypted). + */ + message: Payload; + + /** + * When message has been received by PubNub service. + */ + timetoken: string | number; + + /** + * Additional data which has been published along with message to be used with real-time + * events filter expression. + */ + meta?: Payload; + }[], + + /** + * Received messages timeline start. + */ + string | number, + + /** + * Received messages timeline end. + */ + string | number, +]; +// endregion + +/** + * Get single channel messages request. + */ +export class GetHistoryRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + + // Apply defaults. + if (parameters.count) parameters.count = Math.min(parameters.count, MESSAGES_COUNT); + else parameters.count = MESSAGES_COUNT; + + parameters.stringifiedTimeToken ??= STRINGIFY_TIMETOKENS; + parameters.includeMeta ??= INCLUDE_METADATA; + parameters.logVerbosity ??= LOG_VERBOSITY; + } + + operation(): RequestOperation { + return RequestOperation.PNHistoryOperation; + } + + validate(): string | undefined { + if (!this.parameters.keySet.subscribeKey) return 'Missing Subscribe Key'; + if (!this.parameters.channel) return 'Missing channel'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + const messages = serviceResponse[0]; + const startTimeToken = serviceResponse[1]; + const endTimeToken = serviceResponse[2]; + + // Handle malformed get history response. + if (!Array.isArray(messages)) return { messages: [], startTimeToken, endTimeToken }; + + return { + messages: messages.map((payload) => { + const processedPayload = this.processPayload(payload.message); + const item: History.GetHistoryResponse['messages'][number] = { + entry: processedPayload.payload, + timetoken: payload.timetoken, + }; + + if (processedPayload.error) item.error = processedPayload.error; + if (payload.meta) item.meta = payload.meta; + + return item; + }), + startTimeToken, + endTimeToken, + }; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channel, + } = this.parameters; + + return `/v2/history/sub-key/${subscribeKey}/channel/${encodeString(channel)}`; + } + + protected get queryParameters(): Query { + const { start, end, reverse, count, stringifiedTimeToken, includeMeta } = this.parameters; + + return { + count: count!, + include_token: 'true', + ...(start ? { start } : {}), + ...(end ? { end } : {}), + ...(stringifiedTimeToken! ? { string_message_token: 'true' } : {}), + ...(reverse !== undefined && reverse !== null ? { reverse: reverse.toString() } : {}), + ...(includeMeta! ? { include_meta: 'true' } : {}), + }; + } + + private processPayload(payload: Payload): { payload: Payload; error?: string } { + const { crypto, logVerbosity } = this.parameters; + if (!crypto || typeof payload !== 'string') return { payload }; + + let decryptedPayload: string; + let error: string | undefined; + + try { + const decryptedData = crypto.decrypt(payload); + decryptedPayload = + decryptedData instanceof ArrayBuffer + ? JSON.parse(GetHistoryRequest.decoder.decode(decryptedData)) + : decryptedData; + } catch (err) { + if (logVerbosity!) console.log(`decryption error`, (err as Error).message); + decryptedPayload = payload; + error = `Error while decrypting message content: ${(err as Error).message}`; + } + + return { + payload: decryptedPayload, + error, + }; + } +} diff --git a/src/core/endpoints/history/message_counts.js b/src/core/endpoints/history/message_counts.js deleted file mode 100644 index 6e00cfcc7..000000000 --- a/src/core/endpoints/history/message_counts.js +++ /dev/null @@ -1,55 +0,0 @@ -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -export function getOperation() { - return operationConstants.PNMessageCounts; -} - -export function validateParams(modules, incomingParams) { - const { channels, timetoken, channelTimetokens } = incomingParams; - const { config } = modules; - - if (!channels) return 'Missing channel'; - if (timetoken && channelTimetokens) return 'timetoken and channelTimetokens are incompatible together'; - if (channelTimetokens && channelTimetokens.length > 1 && channels.length !== channelTimetokens.length) { - return 'Length of channelTimetokens and channels do not match'; - } - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules, incomingParams) { - const { channels } = incomingParams; - const { config } = modules; - - const stringifiedChannels = channels.join(','); - - return `/v3/history/sub-key/${config.subscribeKey}/message-counts/${utils.encodeString(stringifiedChannels)}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams(modules, incomingParams) { - const { timetoken, channelTimetokens } = incomingParams; - const outgoingParams = {}; - - if (channelTimetokens && channelTimetokens.length === 1) { - const [tt] = channelTimetokens; - outgoingParams.timetoken = tt; - } else if (channelTimetokens) { - outgoingParams.channelsTimetoken = channelTimetokens.join(','); - } else if (timetoken) { - outgoingParams.timetoken = timetoken; - } - - return outgoingParams; -} - -export function handleResponse(modules, serverResponse) { - return { channels: serverResponse.channels }; -} diff --git a/src/core/endpoints/history/message_counts.ts b/src/core/endpoints/history/message_counts.ts new file mode 100644 index 000000000..6672fe8e4 --- /dev/null +++ b/src/core/endpoints/history/message_counts.ts @@ -0,0 +1,124 @@ +/** + * Messages count REST API module. + */ + +import { createValidationError, PubNubError } from '../../../errors/pubnub-error'; +import { TransportResponse } from '../../types/transport-response'; +import { PubNubAPIError } from '../../../errors/pubnub-api-error'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import * as History from '../../types/api/history'; +import { KeySet, Query } from '../../types/api'; +import { encodeNames } from '../../utils'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = History.MessageCountParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Whether service response represent error or not. + */ + error: boolean; + + /** + * Human-readable error explanation. + */ + error_message: string; + + /** + * Map of channel names to the number of counted messages. + */ + channels: Record; + + /** + * Map of channel names to pre-computed REST API paths to fetch more. + */ + more: { + [p: string]: { + /** + * Pre-computed message count REST API url to fetch more information. + */ + url: string; + /** + * Whether there is more information available or not. + */ + is_more: boolean; + }; + }; +}; +// endregion + +export class MessageCountRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + } + + operation(): RequestOperation { + return RequestOperation.PNMessageCounts; + } + + validate(): string | undefined { + const { + keySet: { subscribeKey }, + channels, + timetoken, + channelTimetokens, + } = this.parameters; + + if (!subscribeKey) return 'Missing Subscribe Key'; + if (!channels) return 'Missing channels'; + if (timetoken && channelTimetokens) return '`timetoken` and `channelTimetokens` are incompatible together'; + if (!timetoken && !channelTimetokens) return '`timetoken` or `channelTimetokens` need to be set'; + if (channelTimetokens && channelTimetokens.length > 1 && channelTimetokens.length !== channels.length) + return 'Length of `channelTimetokens` and `channels` do not match'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + return { channels: serviceResponse.channels }; + } + + protected get path(): string { + return `/v3/history/sub-key/${this.parameters.keySet.subscribeKey}/message-counts/${encodeNames( + this.parameters.channels, + )}`; + } + + protected get queryParameters(): Query { + let { channelTimetokens } = this.parameters; + if (this.parameters.timetoken) channelTimetokens = [this.parameters.timetoken]; + + return { + ...(channelTimetokens!.length === 1 ? { timetoken: channelTimetokens![0] } : {}), + ...(channelTimetokens!.length > 1 ? { channelsTimetoken: channelTimetokens!.join(',') } : {}), + }; + } +} diff --git a/src/core/endpoints/objects/channel/get.js b/src/core/endpoints/objects/channel/get.js deleted file mode 100644 index e5f6f6fb2..000000000 --- a/src/core/endpoints/objects/channel/get.js +++ /dev/null @@ -1,40 +0,0 @@ -import operationConstants from '../../../constants/operations'; - -import utils from '../../../utils'; - -const endpoint = { - getOperation: () => operationConstants.PNGetChannelMetadataOperation, - - validateParams: (_, params) => { - if (!params?.channel) { - return 'Channel cannot be empty'; - } - }, - - getURL: ({ config }, params) => `/v2/objects/${config.subscribeKey}/channels/${utils.encodeString(params.channel)}`, - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => true, - - prepareParams: (_, params) => { - const queryParams = {}; - queryParams.include = ['status', 'type', 'custom']; - - if (params?.include) { - if (params.include?.customFields === false) { - queryParams.include.pop(); - } - } - queryParams.include = queryParams.include.join(','); - - return queryParams; - }, - - handleResponse: (_, response) => ({ - status: response.status, - data: response.data, - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/objects/channel/get.ts b/src/core/endpoints/objects/channel/get.ts new file mode 100644 index 000000000..3c1534218 --- /dev/null +++ b/src/core/endpoints/objects/channel/get.ts @@ -0,0 +1,91 @@ +/** + * Get Channel Metadata REST API module. + */ + +import { createValidationError, PubNubError } from '../../../../errors/pubnub-error'; +import { TransportResponse } from '../../../types/transport-response'; +import { PubNubAPIError } from '../../../../errors/pubnub-api-error'; +import { AbstractRequest } from '../../../components/request'; +import RequestOperation from '../../../constants/operations'; +import * as AppContext from '../../../types/api/app-context'; +import { KeySet, Query } from '../../../types/api'; +import { encodeString } from '../../../utils'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Whether `Channel` custom field should be included by default or not. + */ +const INCLUDE_CUSTOM_FIELDS = true; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = AppContext.GetChannelMetadataParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; +// endregion + +/** + * Get Channel Metadata request. + */ +export class GetChannelMetadataRequest< + Response extends AppContext.GetChannelMetadataResponse, + Custom extends AppContext.CustomData = AppContext.CustomData, +> extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + + // Apply default request parameters. + parameters.include ??= {}; + parameters.include.customFields ??= INCLUDE_CUSTOM_FIELDS; + } + + operation(): RequestOperation { + return RequestOperation.PNGetChannelMetadataOperation; + } + + validate(): string | undefined { + if (!this.parameters.channel) return 'Channel cannot be empty'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + return serviceResponse; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channel, + } = this.parameters; + + return `/v2/objects/${subscribeKey}/channels/${encodeString(channel)}`; + } + + protected get queryParameters(): Query { + return { + include: ['status', 'type', ...(this.parameters.include!.customFields ? ['custom'] : [])].join(','), + }; + } +} diff --git a/src/core/endpoints/objects/channel/get_all.js b/src/core/endpoints/objects/channel/get_all.js deleted file mode 100644 index 79ced13ef..000000000 --- a/src/core/endpoints/objects/channel/get_all.js +++ /dev/null @@ -1,66 +0,0 @@ -import operationConstants from '../../../constants/operations'; - -const endpoint = { - getOperation: () => operationConstants.PNGetAllChannelMetadataOperation, - - validateParams: () => { - // No required parameters. - }, - - getURL: ({ config }) => `/v2/objects/${config.subscribeKey}/channels`, - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => true, - - prepareParams: (_modules, params) => { - const queryParams = {}; - queryParams.include = ['status', 'type']; - - if (params?.include) { - if (params.include?.customFields) { - queryParams.include.push('custom'); - } - } - queryParams.include = queryParams.include.join(','); - - if (params?.include?.totalCount) { - queryParams.count = params.include?.totalCount; - } - - if (params?.page?.next) { - queryParams.start = params.page?.next; - } - - if (params?.page?.prev) { - queryParams.end = params.page?.prev; - } - - if (params?.filter) { - queryParams.filter = params.filter; - } - - queryParams.limit = params?.limit ?? 100; - - if (params?.sort) { - queryParams.sort = Object.entries(params.sort ?? {}).map(([key, value]) => { - if (value === 'asc' || value === 'desc') { - return `${key}:${value}`; - } - return key; - }); - } - - return queryParams; - }, - - handleResponse: (_, response) => ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - prev: response.prev, - next: response.next, - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/objects/channel/get_all.ts b/src/core/endpoints/objects/channel/get_all.ts new file mode 100644 index 000000000..cd442c42f --- /dev/null +++ b/src/core/endpoints/objects/channel/get_all.ts @@ -0,0 +1,105 @@ +/** + * Get All Channel Metadata REST API module. + */ + +import { createValidationError, PubNubError } from '../../../../errors/pubnub-error'; +import { TransportResponse } from '../../../types/transport-response'; +import { PubNubAPIError } from '../../../../errors/pubnub-api-error'; +import { AbstractRequest } from '../../../components/request'; +import RequestOperation from '../../../constants/operations'; +import * as AppContext from '../../../types/api/app-context'; +import { KeySet, Query } from '../../../types/api'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Whether `Channel` custom fields should be included in response or not. + */ +const INCLUDE_CUSTOM_FIELDS = false; + +/** + * Whether total number of channels should be included in response or not. + */ +const INCLUDE_TOTAL_COUNT = false; + +/** + * Number of objects to return in response. + */ +const LIMIT = 100; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- + +// region Types +/** + * Request configuration parameters. + */ +type RequestParameters = + AppContext.GetAllMetadataParameters> & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; + }; +// endregion + +/** + * Get All Channels Metadata request. + */ +export class GetAllChannelsMetadataRequest< + Response extends AppContext.GetAllChannelMetadataResponse, + Custom extends AppContext.CustomData = AppContext.CustomData, +> extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + + // Apply default request parameters. + parameters.include ??= {}; + parameters.include.customFields ??= INCLUDE_CUSTOM_FIELDS; + parameters.include.totalCount ??= INCLUDE_TOTAL_COUNT; + parameters.limit ??= LIMIT; + } + + operation(): RequestOperation { + return RequestOperation.PNGetAllChannelMetadataOperation; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + return serviceResponse; + } + + protected get path(): string { + return `/v2/objects/${this.parameters.keySet.subscribeKey}/channels`; + } + + protected get queryParameters(): Query { + const { include, page, filter, sort, limit } = this.parameters; + const sorting = Object.entries(sort ?? {}).map(([option, order]) => + order !== null ? `${option}:${order}` : option, + ); + + return { + include: ['status', 'type', ...(include!.customFields ? ['custom'] : [])].join(','), + count: `${include!.totalCount!}`, + ...(filter ? { filter } : {}), + ...(page?.next ? { start: page.next } : {}), + ...(page?.prev ? { end: page.prev } : {}), + ...(limit ? { limit } : {}), + ...(sorting.length ? { sort: sorting } : {}), + }; + } +} diff --git a/src/core/endpoints/objects/channel/remove.js b/src/core/endpoints/objects/channel/remove.js deleted file mode 100644 index a05026494..000000000 --- a/src/core/endpoints/objects/channel/remove.js +++ /dev/null @@ -1,31 +0,0 @@ -/** */ - -import operationConstants from '../../../constants/operations'; - -import utils from '../../../utils'; - -const endpoint = { - getOperation: () => operationConstants.PNRemoveChannelMetadataOperation, - - validateParams: (_, params) => { - if (!params?.channel) { - return 'Channel cannot be empty'; - } - }, - - getURL: ({ config }, params) => `/v2/objects/${config.subscribeKey}/channels/${utils.encodeString(params.channel)}`, - useDelete: () => true, - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => true, - - prepareParams: () => ({}), - - handleResponse: (_, response) => ({ - status: response.status, - data: response.data, - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/objects/channel/remove.ts b/src/core/endpoints/objects/channel/remove.ts new file mode 100644 index 000000000..50918491d --- /dev/null +++ b/src/core/endpoints/objects/channel/remove.ts @@ -0,0 +1,70 @@ +/** + * Remove Channel Metadata REST API module. + */ + +import { createValidationError, PubNubError } from '../../../../errors/pubnub-error'; +import { TransportResponse } from '../../../types/transport-response'; +import { PubNubAPIError } from '../../../../errors/pubnub-api-error'; +import { TransportMethod } from '../../../types/transport-request'; +import { AbstractRequest } from '../../../components/request'; +import RequestOperation from '../../../constants/operations'; +import * as AppContext from '../../../types/api/app-context'; +import { encodeString } from '../../../utils'; +import { KeySet } from '../../../types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = AppContext.RemoveChannelMetadataParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; +// endregion + +/** + * Remove Channel Metadata request. + */ +export class RemoveChannelMetadataRequest< + Response extends AppContext.RemoveChannelMetadataResponse, +> extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super({ method: TransportMethod.DELETE }); + } + + operation(): RequestOperation { + return RequestOperation.PNRemoveChannelMetadataOperation; + } + + validate(): string | undefined { + if (!this.parameters.channel) return 'Channel cannot be empty'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + return serviceResponse; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channel, + } = this.parameters; + + return `/v2/objects/${subscribeKey}/channels/${encodeString(channel)}`; + } +} diff --git a/src/core/endpoints/objects/channel/set.js b/src/core/endpoints/objects/channel/set.js deleted file mode 100644 index 7f3d4f78c..000000000 --- a/src/core/endpoints/objects/channel/set.js +++ /dev/null @@ -1,49 +0,0 @@ -/** */ - -import operationConstants from '../../../constants/operations'; - -import utils from '../../../utils'; - -const endpoint = { - getOperation: () => operationConstants.PNSetChannelMetadataOperation, - - validateParams: (_, params) => { - if (!params?.channel) { - return 'Channel cannot be empty'; - } - - if (!params?.data) { - return 'Data cannot be empty'; - } - }, - - usePatch: () => true, - - patchURL: ({ config }, params) => `/v2/objects/${config.subscribeKey}/channels/${utils.encodeString(params.channel)}`, - - patchPayload: (_, params) => params.data, - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => true, - - prepareParams: (_, params) => { - const queryParams = {}; - queryParams.include = ['status', 'type', 'custom']; - - if (params?.include) { - if (params.include?.customFields === false) { - queryParams.include.pop(); - } - } - queryParams.include = queryParams.include.join(','); - return queryParams; - }, - - handleResponse: (_, response) => ({ - status: response.status, - data: response.data, - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/objects/channel/set.ts b/src/core/endpoints/objects/channel/set.ts new file mode 100644 index 000000000..555604d2c --- /dev/null +++ b/src/core/endpoints/objects/channel/set.ts @@ -0,0 +1,97 @@ +/** + * Set Channel Metadata REST API module. + */ + +import { createValidationError, PubNubError } from '../../../../errors/pubnub-error'; +import { TransportResponse } from '../../../types/transport-response'; +import { PubNubAPIError } from '../../../../errors/pubnub-api-error'; +import { TransportMethod } from '../../../types/transport-request'; +import { AbstractRequest } from '../../../components/request'; +import RequestOperation from '../../../constants/operations'; +import * as AppContext from '../../../types/api/app-context'; +import { KeySet, Query } from '../../../types/api'; +import { encodeString } from '../../../utils'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Whether `Channel` custom field should be included by default or not. + */ +const INCLUDE_CUSTOM_FIELDS = true; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = AppContext.SetChannelMetadataParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; +// endregion + +/** + * Set Channel Metadata request. + */ +export class SetChannelMetadataRequest< + Response extends AppContext.SetChannelMetadataResponse, + Custom extends AppContext.CustomData = AppContext.CustomData, +> extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super({ method: TransportMethod.PATCH }); + + // Apply default request parameters. + parameters.include ??= {}; + parameters.include.customFields ??= INCLUDE_CUSTOM_FIELDS; + } + + operation(): RequestOperation { + return RequestOperation.PNSetChannelMetadataOperation; + } + + validate(): string | undefined { + if (!this.parameters.channel) return 'Channel cannot be empty'; + if (!this.parameters.data) return 'Data cannot be empty'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + return serviceResponse; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channel, + } = this.parameters; + + return `/v2/objects/${subscribeKey}/channels/${encodeString(channel)}`; + } + + protected get queryParameters(): Query { + return { + include: ['status', 'type', ...(this.parameters.include!.customFields ? ['custom'] : [])].join(','), + }; + } + + protected get body(): ArrayBuffer | string | undefined { + return JSON.stringify(this.parameters.data); + } +} diff --git a/src/core/endpoints/objects/member/get.js b/src/core/endpoints/objects/member/get.js deleted file mode 100644 index 5ce830599..000000000 --- a/src/core/endpoints/objects/member/get.js +++ /dev/null @@ -1,93 +0,0 @@ -/** */ - -import operationConstants from '../../../constants/operations'; - -import utils from '../../../utils'; - -const endpoint = { - getOperation: () => operationConstants.PNGetMembersOperation, - - validateParams: (_, params) => { - if (!params?.channel) { - return 'channel cannot be empty'; - } - }, - - getURL: ({ config }, params) => - `/v2/objects/${config.subscribeKey}/channels/${utils.encodeString(params.channel)}/uuids`, - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => true, - - prepareParams: (_modules, params) => { - const queryParams = {}; - queryParams.include = []; - - if (params?.include) { - if (params.include?.statusField) { - queryParams.include.push('status'); - } - - if (params.include?.customFields) { - queryParams.include.push('custom'); - } - - if (params.include?.UUIDFields) { - queryParams.include.push('uuid'); - } - - if (params.include?.customUUIDFields) { - queryParams.include.push('uuid.custom'); - } - - if (params.include?.UUIDStatusField) { - queryParams.include.push('uuid.status'); - } - - if (params.include?.UUIDTypeField) { - queryParams.include.push('uuid.type'); - } - } - queryParams.include = queryParams.include.join(','); - - if (params?.include?.totalCount) { - queryParams.count = params.include?.totalCount; - } - - if (params?.page?.next) { - queryParams.start = params.page?.next; - } - - if (params?.page?.prev) { - queryParams.end = params.page?.prev; - } - - if (params?.filter) { - queryParams.filter = params.filter; - } - - queryParams.limit = params?.limit ?? 100; - - if (params?.sort) { - queryParams.sort = Object.entries(params.sort ?? {}).map(([key, value]) => { - if (value === 'asc' || value === 'desc') { - return `${key}:${value}`; - } - return key; - }); - } - - return queryParams; - }, - - handleResponse: (_, response) => ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - prev: response.prev, - next: response.next, - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/objects/member/get.ts b/src/core/endpoints/objects/member/get.ts new file mode 100644 index 000000000..1b80c78b8 --- /dev/null +++ b/src/core/endpoints/objects/member/get.ts @@ -0,0 +1,153 @@ +/** + * Get Channel Members REST API module. + */ + +import { createValidationError, PubNubError } from '../../../../errors/pubnub-error'; +import { TransportResponse } from '../../../types/transport-response'; +import { PubNubAPIError } from '../../../../errors/pubnub-api-error'; +import { AbstractRequest } from '../../../components/request'; +import RequestOperation from '../../../constants/operations'; +import * as AppContext from '../../../types/api/app-context'; +import { KeySet, Query } from '../../../types/api'; +import { encodeString } from '../../../utils'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Whether `Member` custom field should be included in response or not. + */ +const INCLUDE_CUSTOM_FIELDS = false; + +/** + * Whether member's status field should be included in response or not. + */ +const INCLUDE_STATUS = false; + +/** + * Whether total number of members should be included in response or not. + */ +const INCLUDE_TOTAL_COUNT = false; + +/** + * Whether `UUID` fields should be included in response or not. + */ +const INCLUDE_UUID_FIELDS = false; + +/** + * Whether `UUID` status field should be included in response or not. + */ +const INCLUDE_UUID_STATUS_FIELD = false; + +/** + * Whether `UUID` type field should be included in response or not. + */ +const INCLUDE_UUID_TYPE_FIELD = false; + +/** + * Whether `UUID` custom field should be included in response or not. + */ +const INCLUDE_UUID_CUSTOM_FIELDS = false; + +/** + * Number of objects to return in response. + */ +const LIMIT = 100; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = AppContext.GetMembersParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; +// endregion + +/** + * Get Channel Members request. + */ +export class GetChannelMembersRequest< + Response extends AppContext.GetMembersResponse, + MembersCustom extends AppContext.CustomData = AppContext.CustomData, + UUIDCustom extends AppContext.CustomData = AppContext.CustomData, +> extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + + // Apply default request parameters. + parameters.include ??= {}; + parameters.include.customFields ??= INCLUDE_CUSTOM_FIELDS; + parameters.include.totalCount ??= INCLUDE_TOTAL_COUNT; + parameters.include.statusField ??= INCLUDE_STATUS; + parameters.include.UUIDFields ??= INCLUDE_UUID_FIELDS; + parameters.include.customUUIDFields ??= INCLUDE_UUID_CUSTOM_FIELDS; + parameters.include.UUIDStatusField ??= INCLUDE_UUID_STATUS_FIELD; + parameters.include.UUIDTypeField ??= INCLUDE_UUID_TYPE_FIELD; + parameters.limit ??= LIMIT; + } + + operation(): RequestOperation { + return RequestOperation.PNSetMembersOperation; + } + + validate(): string | undefined { + if (!this.parameters.channel) return 'Channel cannot be empty'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + return serviceResponse; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channel, + } = this.parameters; + + return `/v2/objects/${subscribeKey}/channels/${encodeString(channel)}/uuids`; + } + + protected get queryParameters(): Query { + const { include, page, filter, sort, limit } = this.parameters; + const sorting = Object.entries(sort ?? {}).map(([option, order]) => + order !== null ? `${option}:${order}` : option, + ); + const includeFlags: string[] = []; + + if (include!.statusField) includeFlags.push('status'); + if (include!.customFields) includeFlags.push('custom'); + if (include!.UUIDFields) includeFlags.push('uuid'); + if (include!.UUIDStatusField) includeFlags.push('uuid.status'); + if (include!.UUIDTypeField) includeFlags.push('uuid.type'); + if (include!.customUUIDFields) includeFlags.push('uuid.custom'); + + return { + count: `${include!.totalCount!}`, + ...(includeFlags.length > 0 ? { include: includeFlags.join(',') } : {}), + ...(filter ? { filter } : {}), + ...(page?.next ? { start: page.next } : {}), + ...(page?.prev ? { end: page.prev } : {}), + ...(limit ? { limit } : {}), + ...(sorting.length ? { sort: sorting } : {}), + }; + } +} diff --git a/src/core/endpoints/objects/member/set.js b/src/core/endpoints/objects/member/set.js deleted file mode 100644 index e80f3163e..000000000 --- a/src/core/endpoints/objects/member/set.js +++ /dev/null @@ -1,107 +0,0 @@ -import operationConstants from '../../../constants/operations'; - -import utils from '../../../utils'; - -const endpoint = { - getOperation: () => operationConstants.PNSetMembersOperation, - - validateParams: (_, params) => { - if (!params?.channel) { - return 'Channel cannot be empty'; - } - - if (!params?.uuids || params?.uuids.length === 0) { - return 'UUIDs cannot be empty'; - } - }, - - usePatch: () => true, - - patchURL: ({ config }, params) => - `/v2/objects/${config.subscribeKey}/channels/${utils.encodeString(params.channel)}/uuids`, - - patchPayload: (_, params) => ({ - set: [], - delete: [], - [params.type]: params.uuids.map((uuid) => { - if (typeof uuid === 'string') { - return { - uuid: { - id: uuid, - }, - }; - } - return { - uuid: { id: uuid.id }, - custom: uuid.custom, - status: uuid.status, - }; - }), - }), - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => true, - - prepareParams: (_modules, params) => { - const queryParams = {}; - queryParams.include = ['uuid.status', 'uuid.type', 'type']; - - if (params?.include) { - if (params.include?.customFields) { - queryParams.include.push('custom'); - } - - if (params.include?.customUUIDFields) { - queryParams.include.push('uuid.custom'); - } - - if (params.include?.UUIDFields) { - queryParams.include.push('uuid'); - } - } - - queryParams.include = queryParams.include.join(','); - - if (params?.include?.totalCount) { - queryParams.count = true; - } - - if (params?.page?.next) { - queryParams.start = params.page?.next; - } - - if (params?.page?.prev) { - queryParams.end = params.page?.prev; - } - - if (params?.filter) { - queryParams.filter = params.filter; - } - - if (params.limit != null) { - queryParams.limit = params.limit; - } - - if (params?.sort) { - queryParams.sort = Object.entries(params.sort ?? {}).map(([key, value]) => { - if (value === 'asc' || value === 'desc') { - return `${key}:${value}`; - } - return key; - }); - } - - return queryParams; - }, - - handleResponse: (_, response) => ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - prev: response.prev, - next: response.next, - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/objects/member/set.ts b/src/core/endpoints/objects/member/set.ts new file mode 100644 index 000000000..c5bb2500d --- /dev/null +++ b/src/core/endpoints/objects/member/set.ts @@ -0,0 +1,155 @@ +/** + * Set Channel Members REST API module. + */ + +import { createValidationError, PubNubError } from '../../../../errors/pubnub-error'; +import { TransportResponse } from '../../../types/transport-response'; +import { PubNubAPIError } from '../../../../errors/pubnub-api-error'; +import { TransportMethod } from '../../../types/transport-request'; +import { AbstractRequest } from '../../../components/request'; +import RequestOperation from '../../../constants/operations'; +import * as AppContext from '../../../types/api/app-context'; +import { KeySet, Query } from '../../../types/api'; +import { encodeString } from '../../../utils'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Whether `Member` custom field should be included in response or not. + */ +const INCLUDE_CUSTOM_FIELDS = false; + +/** + * Whether total number of members should be included in response or not. + */ +const INCLUDE_TOTAL_COUNT = false; + +/** + * Whether `UUID` fields should be included in response or not. + */ +const INCLUDE_UUID_FIELDS = false; + +/** + * Whether `UUID` custom field should be included in response or not. + */ +const INCLUDE_UUID_CUSTOM_FIELDS = false; + +/** + * Number of objects to return in response. + */ +const LIMIT = 100; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = AppContext.SetChannelMembersParameters & { + /** + * Type of change in channel members list. + */ + type: 'set' | 'delete'; + + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; +// endregion + +/** + * Set Channel Members request. + */ +export class SetChannelMembersRequest< + Response extends AppContext.SetMembersResponse, + MembersCustom extends AppContext.CustomData = AppContext.CustomData, + UUIDCustom extends AppContext.CustomData = AppContext.CustomData, +> extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super({ method: TransportMethod.PATCH }); + + // Apply default request parameters. + parameters.include ??= {}; + parameters.include.customFields ??= INCLUDE_CUSTOM_FIELDS; + parameters.include.totalCount ??= INCLUDE_TOTAL_COUNT; + parameters.include.UUIDFields ??= INCLUDE_UUID_FIELDS; + parameters.include.customUUIDFields ??= INCLUDE_UUID_CUSTOM_FIELDS; + parameters.limit ??= LIMIT; + } + + operation(): RequestOperation { + return RequestOperation.PNSetMembersOperation; + } + + validate(): string | undefined { + const { channel, uuids } = this.parameters; + + if (!channel) return 'Channel cannot be empty'; + if (!uuids || uuids.length === 0) return 'UUIDs cannot be empty'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + return serviceResponse; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channel, + } = this.parameters; + + return `/v2/objects/${subscribeKey}/channels/${encodeString(channel)}/uuids`; + } + + protected get queryParameters(): Query { + const { include, page, filter, sort, limit } = this.parameters; + const sorting = Object.entries(sort ?? {}).map(([option, order]) => + order !== null ? `${option}:${order}` : option, + ); + const includeFlags: string[] = ['uuid.status', 'uuid.type', 'type']; + + if (include!.customFields) includeFlags.push('custom'); + if (include!.UUIDFields) includeFlags.push('uuid'); + if (include!.customUUIDFields) includeFlags.push('uuid.custom'); + + return { + count: `${include!.totalCount!}`, + ...(includeFlags.length > 0 ? { include: includeFlags.join(',') } : {}), + ...(filter ? { filter } : {}), + ...(page?.next ? { start: page.next } : {}), + ...(page?.prev ? { end: page.prev } : {}), + ...(limit ? { limit } : {}), + ...(sorting.length ? { sort: sorting } : {}), + }; + } + + protected get body(): string { + const { uuids, type } = this.parameters; + + return JSON.stringify({ + [`${type}`]: uuids.map((uuid) => { + if (typeof uuid === 'string') { + return { uuid: { id: uuid } }; + } else { + return { uuid: { id: uuid.id }, status: uuid.status, custom: uuid.custom }; + } + }), + }); + } +} diff --git a/src/core/endpoints/objects/membership/get.js b/src/core/endpoints/objects/membership/get.js deleted file mode 100644 index 3f3dc94dd..000000000 --- a/src/core/endpoints/objects/membership/get.js +++ /dev/null @@ -1,89 +0,0 @@ -import operationConstants from '../../../constants/operations'; - -import utils from '../../../utils'; - -const endpoint = { - getOperation: () => operationConstants.PNGetMembershipsOperation, - - validateParams: () => { - // No required parameters. - }, - - getURL: ({ config }, params) => - `/v2/objects/${config.subscribeKey}/uuids/${utils.encodeString(params?.uuid ?? config.getUUID())}/channels`, - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => true, - - prepareParams: (_modules, params) => { - const queryParams = {}; - queryParams.include = []; - - if (params?.include) { - if (params.include?.statusField) { - queryParams.include.push('status'); - } - - if (params.include?.customFields) { - queryParams.include.push('custom'); - } - - if (params.include?.channelFields) { - queryParams.include.push('channel'); - } - - if (params.include?.customChannelFields) { - queryParams.include.push('channel.custom'); - } - - if (params.include?.channelStatusField) { - queryParams.include.push('channel.status'); - } - - if (params.include?.channelTypeField) { - queryParams.include.push('channel.type'); - } - } - queryParams.include = queryParams.include.join(','); - - if (params?.include?.totalCount) { - queryParams.count = params.include?.totalCount; - } - - if (params?.page?.next) { - queryParams.start = params.page?.next; - } - - if (params?.page?.prev) { - queryParams.end = params.page?.prev; - } - - if (params?.filter) { - queryParams.filter = params.filter; - } - - queryParams.limit = params?.limit ?? 100; - - if (params?.sort) { - queryParams.sort = Object.entries(params.sort ?? {}).map(([key, value]) => { - if (value === 'asc' || value === 'desc') { - return `${key}:${value}`; - } - return key; - }); - } - - return queryParams; - }, - - handleResponse: (_, response) => ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - prev: response.prev, - next: response.next, - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/objects/membership/get.ts b/src/core/endpoints/objects/membership/get.ts new file mode 100644 index 000000000..34e2b6dab --- /dev/null +++ b/src/core/endpoints/objects/membership/get.ts @@ -0,0 +1,156 @@ +/** + * Get UUID Memberships REST API module. + */ + +import { createValidationError, PubNubError } from '../../../../errors/pubnub-error'; +import { TransportResponse } from '../../../types/transport-response'; +import { PubNubAPIError } from '../../../../errors/pubnub-api-error'; +import { AbstractRequest } from '../../../components/request'; +import RequestOperation from '../../../constants/operations'; +import * as AppContext from '../../../types/api/app-context'; +import { KeySet, Query } from '../../../types/api'; +import { encodeString } from '../../../utils'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Whether `Membership` custom field should be included in response or not. + */ +const INCLUDE_CUSTOM_FIELDS = false; + +/** + * Whether membership's status field should be included in response or not. + */ +const INCLUDE_STATUS = false; + +/** + * Whether total number of memberships should be included in response or not. + */ +const INCLUDE_TOTAL_COUNT = false; + +/** + * Whether `Channel` fields should be included in response or not. + */ +const INCLUDE_CHANNEL_FIELDS = false; + +/** + * Whether `Channel` status field should be included in response or not. + */ +const INCLUDE_CHANNEL_STATUS_FIELD = false; + +/** + * Whether `Channel` type field should be included in response or not. + */ +const INCLUDE_CHANNEL_TYPE_FIELD = false; + +/** + * Whether `Channel` custom field should be included in response or not. + */ +const INCLUDE_CHANNEL_CUSTOM_FIELDS = false; + +/** + * Number of objects to return in response. + */ +const LIMIT = 100; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = AppContext.GetMembershipsParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; +// endregion + +/** + * Get UUID Memberships request. + */ +export class GetUUIDMembershipsRequest< + Response extends AppContext.GetMembershipsResponse, + MembersCustom extends AppContext.CustomData = AppContext.CustomData, + UUIDCustom extends AppContext.CustomData = AppContext.CustomData, +> extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + + // Apply default request parameters. + parameters.include ??= {}; + parameters.include.customFields ??= INCLUDE_CUSTOM_FIELDS; + parameters.include.totalCount ??= INCLUDE_TOTAL_COUNT; + parameters.include.statusField ??= INCLUDE_STATUS; + parameters.include.channelFields ??= INCLUDE_CHANNEL_FIELDS; + parameters.include.customChannelFields ??= INCLUDE_CHANNEL_CUSTOM_FIELDS; + parameters.include.channelStatusField ??= INCLUDE_CHANNEL_STATUS_FIELD; + parameters.include.channelTypeField ??= INCLUDE_CHANNEL_TYPE_FIELD; + parameters.limit ??= LIMIT; + + // Remap for backward compatibility. + if (this.parameters.userId) this.parameters.uuid = this.parameters.userId; + } + + operation(): RequestOperation { + return RequestOperation.PNGetMembershipsOperation; + } + + validate(): string | undefined { + if (!this.parameters.uuid) return "'uuid' cannot be empty"; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + return serviceResponse; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + uuid, + } = this.parameters; + + return `/v2/objects/${subscribeKey}/uuids/${encodeString(uuid!)}/channels`; + } + + protected get queryParameters(): Query { + const { include, page, filter, sort, limit } = this.parameters; + const sorting = Object.entries(sort ?? {}).map(([option, order]) => + order !== null ? `${option}:${order}` : option, + ); + const includeFlags: string[] = []; + + if (include!.statusField) includeFlags.push('status'); + if (include!.customFields) includeFlags.push('custom'); + if (include!.channelFields) includeFlags.push('channel'); + if (include!.channelStatusField) includeFlags.push('channel.status'); + if (include!.channelTypeField) includeFlags.push('channel.type'); + if (include!.customChannelFields) includeFlags.push('channel.custom'); + + return { + count: `${include!.totalCount!}`, + ...(includeFlags.length > 0 ? { include: includeFlags.join(',') } : {}), + ...(filter ? { filter } : {}), + ...(page?.next ? { start: page.next } : {}), + ...(page?.prev ? { end: page.prev } : {}), + ...(limit ? { limit } : {}), + ...(sorting.length ? { sort: sorting } : {}), + }; + } +} diff --git a/src/core/endpoints/objects/membership/set.js b/src/core/endpoints/objects/membership/set.js deleted file mode 100644 index f801d7c2a..000000000 --- a/src/core/endpoints/objects/membership/set.js +++ /dev/null @@ -1,105 +0,0 @@ -/** */ - -import operationConstants from '../../../constants/operations'; - -import utils from '../../../utils'; - -const endpoint = { - getOperation: () => operationConstants.PNSetMembershipsOperation, - - validateParams: (_, params) => { - if (!params?.channels || params?.channels.length === 0) { - return 'Channels cannot be empty'; - } - }, - - usePatch: () => true, - - patchURL: ({ config }, params) => - `/v2/objects/${config.subscribeKey}/uuids/${utils.encodeString(params.uuid ?? config.getUUID())}/channels`, - - patchPayload: (_, params) => ({ - set: [], - delete: [], - [params.type]: params.channels.map((channel) => { - if (typeof channel === 'string') { - return { - channel: { - id: channel, - }, - }; - } - return { - channel: { id: channel.id }, - custom: channel.custom, - status: channel.status, - }; - }), - }), - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => true, - - prepareParams: (_modules, params) => { - const queryParams = {}; - queryParams.include = ['channel.status', 'channel.type', 'status']; - - if (params?.include) { - if (params.include?.customFields) { - queryParams.include.push('custom'); - } - - if (params.include?.customChannelFields) { - queryParams.include.push('channel.custom'); - } - - if (params.include?.channelFields) { - queryParams.include.push('channel'); - } - } - - queryParams.include = queryParams.include.join(','); - - if (params?.include?.totalCount) { - queryParams.count = true; - } - - if (params?.page?.next) { - queryParams.start = params.page?.next; - } - - if (params?.page?.prev) { - queryParams.end = params.page?.prev; - } - - if (params?.filter) { - queryParams.filter = params.filter; - } - - if (params.limit != null) { - queryParams.limit = params.limit; - } - - if (params?.sort) { - queryParams.sort = Object.entries(params.sort ?? {}).map(([key, value]) => { - if (value === 'asc' || value === 'desc') { - return `${key}:${value}`; - } - return key; - }); - } - - return queryParams; - }, - - handleResponse: (_, response) => ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - prev: response.prev, - next: response.next, - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/objects/membership/set.ts b/src/core/endpoints/objects/membership/set.ts new file mode 100644 index 000000000..1633dcce1 --- /dev/null +++ b/src/core/endpoints/objects/membership/set.ts @@ -0,0 +1,158 @@ +/** + * Set UUID Memberships REST API module. + */ + +import { createValidationError, PubNubError } from '../../../../errors/pubnub-error'; +import { TransportResponse } from '../../../types/transport-response'; +import { PubNubAPIError } from '../../../../errors/pubnub-api-error'; +import { TransportMethod } from '../../../types/transport-request'; +import { AbstractRequest } from '../../../components/request'; +import RequestOperation from '../../../constants/operations'; +import * as AppContext from '../../../types/api/app-context'; +import { KeySet, Query } from '../../../types/api'; +import { encodeString } from '../../../utils'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Whether `Membership` custom field should be included in response or not. + */ +const INCLUDE_CUSTOM_FIELDS = false; + +/** + * Whether total number of memberships should be included in response or not. + */ +const INCLUDE_TOTAL_COUNT = false; + +/** + * Whether `Channel` fields should be included in response or not. + */ +const INCLUDE_CHANNEL_FIELDS = false; + +/** + * Whether `Channel` custom field should be included in response or not. + */ +const INCLUDE_CHANNEL_CUSTOM_FIELDS = false; + +/** + * Number of objects to return in response. + */ +const LIMIT = 100; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = AppContext.SetMembershipsParameters & { + /** + * Type of change in UUID memberships list. + */ + type: 'set' | 'delete'; + + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; +// endregion + +/** + * Set UUID Memberships request. + */ +export class SetUUIDMembershipsRequest< + Response extends AppContext.SetMembershipsResponse, + MembersCustom extends AppContext.CustomData = AppContext.CustomData, + UUIDCustom extends AppContext.CustomData = AppContext.CustomData, +> extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super({ method: TransportMethod.PATCH }); + + // Apply default request parameters. + parameters.include ??= {}; + parameters.include.customFields ??= INCLUDE_CUSTOM_FIELDS; + parameters.include.totalCount ??= INCLUDE_TOTAL_COUNT; + parameters.include.channelFields ??= INCLUDE_CHANNEL_FIELDS; + parameters.include.customChannelFields ??= INCLUDE_CHANNEL_CUSTOM_FIELDS; + parameters.limit ??= LIMIT; + + // Remap for backward compatibility. + if (this.parameters.userId) this.parameters.uuid = this.parameters.userId; + } + + operation(): RequestOperation { + return RequestOperation.PNSetMembershipsOperation; + } + + validate(): string | undefined { + const { uuid, channels } = this.parameters; + + if (!uuid) return "'uuid' cannot be empty"; + if (!channels || channels.length === 0) return 'Channels cannot be empty'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + return serviceResponse; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + uuid, + } = this.parameters; + + return `/v2/objects/${subscribeKey}/uuids/${encodeString(uuid!)}/channels`; + } + + protected get queryParameters(): Query { + const { include, page, filter, sort, limit } = this.parameters; + const sorting = Object.entries(sort ?? {}).map(([option, order]) => + order !== null ? `${option}:${order}` : option, + ); + const includeFlags: string[] = ['channel.status', 'channel.type', 'status']; + + if (include!.customFields) includeFlags.push('custom'); + if (include!.channelFields) includeFlags.push('channel'); + if (include!.customChannelFields) includeFlags.push('channel.custom'); + + return { + count: `${include!.totalCount!}`, + ...(includeFlags.length > 0 ? { include: includeFlags.join(',') } : {}), + ...(filter ? { filter } : {}), + ...(page?.next ? { start: page.next } : {}), + ...(page?.prev ? { end: page.prev } : {}), + ...(limit ? { limit } : {}), + ...(sorting.length ? { sort: sorting } : {}), + }; + } + + protected get body(): string { + const { channels, type } = this.parameters; + + return JSON.stringify({ + [`${type}`]: channels.map((channel) => { + if (typeof channel === 'string') { + return { channel: { id: channel } }; + } else { + return { channel: { id: channel.id }, status: channel.status, custom: channel.custom }; + } + }), + }); + } +} diff --git a/src/core/endpoints/objects/uuid/get.js b/src/core/endpoints/objects/uuid/get.js deleted file mode 100644 index 1721489d8..000000000 --- a/src/core/endpoints/objects/uuid/get.js +++ /dev/null @@ -1,44 +0,0 @@ -/** */ - -import operationConstants from '../../../constants/operations'; - -import utils from '../../../utils'; - -const endpoint = { - getOperation: () => operationConstants.PNGetUUIDMetadataOperation, - - validateParams: () => { - // No required parameters. - }, - - getURL: ({ config }, params) => - `/v2/objects/${config.subscribeKey}/uuids/${utils.encodeString(params?.uuid ?? config.getUUID())}`, - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => true, - - prepareParams: ({ config }, params) => { - const queryParams = {}; - - queryParams.uuid = params?.uuid ?? config.getUUID(); - queryParams.include = ['status', 'type', 'custom']; - - if (params?.include) { - if (params.include?.customFields === false) { - queryParams.include.pop(); - } - } - - queryParams.include = queryParams.include.join(','); - - return queryParams; - }, - - handleResponse: (_, response) => ({ - status: response.status, - data: response.data, - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/objects/uuid/get.ts b/src/core/endpoints/objects/uuid/get.ts new file mode 100644 index 000000000..7a93648aa --- /dev/null +++ b/src/core/endpoints/objects/uuid/get.ts @@ -0,0 +1,94 @@ +/** + * Get UUID Metadata REST API module. + */ + +import { createValidationError, PubNubError } from '../../../../errors/pubnub-error'; +import { TransportResponse } from '../../../types/transport-response'; +import { PubNubAPIError } from '../../../../errors/pubnub-api-error'; +import { AbstractRequest } from '../../../components/request'; +import RequestOperation from '../../../constants/operations'; +import * as AppContext from '../../../types/api/app-context'; +import { KeySet, Query } from '../../../types/api'; +import { encodeString } from '../../../utils'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Whether UUID custom field should be included by default or not. + */ +const INCLUDE_CUSTOM_FIELDS = true; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = AppContext.GetUUIDMetadataParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; +// endregion + +/** + * Get UUID Metadata request. + */ +export class GetUUIDMetadataRequest< + Response extends AppContext.GetUUIDMetadataResponse, + Custom extends AppContext.CustomData = AppContext.CustomData, +> extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + + // Apply default request parameters. + parameters.include ??= {}; + parameters.include.customFields ??= INCLUDE_CUSTOM_FIELDS; + + // Remap for backward compatibility. + if (this.parameters.userId) this.parameters.uuid = this.parameters.userId; + } + + operation(): RequestOperation { + return RequestOperation.PNGetUUIDMetadataOperation; + } + + validate(): string | undefined { + if (!this.parameters.uuid) return "'uuid' cannot be empty"; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + return serviceResponse; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + uuid, + } = this.parameters; + + return `/v2/objects/${subscribeKey}/uuids/${encodeString(uuid!)}`; + } + + protected get queryParameters(): Query { + const { include } = this.parameters; + + return { include: ['status', 'type', ...(include!.customFields ? ['custom'] : [])].join(',') }; + } +} diff --git a/src/core/endpoints/objects/uuid/get_all.js b/src/core/endpoints/objects/uuid/get_all.js deleted file mode 100644 index 1c3ef9d86..000000000 --- a/src/core/endpoints/objects/uuid/get_all.js +++ /dev/null @@ -1,67 +0,0 @@ -import operationConstants from '../../../constants/operations'; - -const endpoint = { - getOperation: () => operationConstants.PNGetAllUUIDMetadataOperation, - - validateParams: () => { - // No required parameters. - }, - - getURL: ({ config }) => `/v2/objects/${config.subscribeKey}/uuids`, - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => true, - - prepareParams: (_modules, params) => { - const queryParams = {}; - queryParams.include = ['status', 'type']; - - if (params?.include) { - if (params.include?.customFields) { - queryParams.include.push('custom'); - } - } - - queryParams.include = queryParams.include.join(','); - - if (params?.include?.totalCount) { - queryParams.count = params.include?.totalCount; - } - - if (params?.page?.next) { - queryParams.start = params.page?.next; - } - - if (params?.page?.prev) { - queryParams.end = params.page?.prev; - } - - if (params?.filter) { - queryParams.filter = params.filter; - } - - queryParams.limit = params?.limit ?? 100; - - if (params?.sort) { - queryParams.sort = Object.entries(params.sort ?? {}).map(([key, value]) => { - if (value === 'asc' || value === 'desc') { - return `${key}:${value}`; - } - return key; - }); - } - - return queryParams; - }, - - handleResponse: (_, response) => ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - next: response.next, - prev: response.prev, - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/objects/uuid/get_all.ts b/src/core/endpoints/objects/uuid/get_all.ts new file mode 100644 index 000000000..c7b5efca8 --- /dev/null +++ b/src/core/endpoints/objects/uuid/get_all.ts @@ -0,0 +1,96 @@ +/** + * Get All UUID Metadata REST API module. + */ + +import { createValidationError, PubNubError } from '../../../../errors/pubnub-error'; +import { TransportResponse } from '../../../types/transport-response'; +import { PubNubAPIError } from '../../../../errors/pubnub-api-error'; +import { AbstractRequest } from '../../../components/request'; +import RequestOperation from '../../../constants/operations'; +import * as AppContext from '../../../types/api/app-context'; +import { KeySet, Query } from '../../../types/api'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Whether `Channel` custom field should be included by default or not. + */ +const INCLUDE_CUSTOM_FIELDS = false; + +/** + * Number of objects to return in response. + */ +const LIMIT = 100; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = + AppContext.GetAllMetadataParameters> & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; + }; +// endregion + +export class GetAllUUIDMetadataRequest< + Response extends AppContext.GetAllUUIDMetadataResponse, + Custom extends AppContext.CustomData = AppContext.CustomData, +> extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + + // Apply default request parameters. + parameters.include ??= {}; + parameters.include.customFields ??= INCLUDE_CUSTOM_FIELDS; + parameters.limit ??= LIMIT; + } + + operation(): RequestOperation { + return RequestOperation.PNGetAllUUIDMetadataOperation; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + return serviceResponse; + } + + protected get path(): string { + return `/v2/objects/${this.parameters.keySet.subscribeKey}/uuids`; + } + + protected get queryParameters(): Query { + const { include, page, filter, sort, limit } = this.parameters; + const sorting = Object.entries(sort ?? {}).map(([option, order]) => + order !== null ? `${option}:${order}` : option, + ); + + return { + include: ['status', 'type', ...(include!.customFields ? ['custom'] : [])].join(','), + ...(include!.totalCount !== undefined ? { count: `${include!.totalCount}` } : {}), + ...(filter ? { filter } : {}), + ...(page?.next ? { start: page.next } : {}), + ...(page?.prev ? { end: page.prev } : {}), + ...(limit ? { limit } : {}), + ...(sorting.length ? { sort: sorting } : {}), + }; + } +} diff --git a/src/core/endpoints/objects/uuid/remove.js b/src/core/endpoints/objects/uuid/remove.js deleted file mode 100644 index a441c92db..000000000 --- a/src/core/endpoints/objects/uuid/remove.js +++ /dev/null @@ -1,32 +0,0 @@ -/** */ - -import operationConstants from '../../../constants/operations'; - -import utils from '../../../utils'; - -const endpoint = { - getOperation: () => operationConstants.PNRemoveUUIDMetadataOperation, - - validateParams: () => { - // No required parameters. - }, - - getURL: ({ config }, params) => - `/v2/objects/${config.subscribeKey}/uuids/${utils.encodeString(params?.uuid ?? config.getUUID())}`, - useDelete: () => true, - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => true, - - prepareParams: ({ config }, params) => ({ - uuid: params?.uuid ?? config.getUUID(), - }), - - handleResponse: (_, response) => ({ - status: response.status, - data: response.data, - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/objects/uuid/remove.ts b/src/core/endpoints/objects/uuid/remove.ts new file mode 100644 index 000000000..2bc521d6f --- /dev/null +++ b/src/core/endpoints/objects/uuid/remove.ts @@ -0,0 +1,73 @@ +/** + * Remove UUID Metadata REST API module. + */ + +import { createValidationError, PubNubError } from '../../../../errors/pubnub-error'; +import { TransportResponse } from '../../../types/transport-response'; +import { PubNubAPIError } from '../../../../errors/pubnub-api-error'; +import { TransportMethod } from '../../../types/transport-request'; +import { AbstractRequest } from '../../../components/request'; +import RequestOperation from '../../../constants/operations'; +import * as AppContext from '../../../types/api/app-context'; +import { KeySet } from '../../../types/api'; +import { encodeString } from '../../../utils'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = AppContext.RemoveUUIDMetadataParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; +// endregion + +/** + * Remove UUID Metadata request. + */ +export class RemoveUUIDMetadataRequest< + Response extends AppContext.RemoveUUIDMetadataResponse, +> extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super({ method: TransportMethod.DELETE }); + + // Remap for backward compatibility. + if (this.parameters.userId) this.parameters.uuid = this.parameters.userId; + } + + operation(): RequestOperation { + return RequestOperation.PNRemoveUUIDMetadataOperation; + } + + validate(): string | undefined { + if (!this.parameters.uuid) return "'uuid' cannot be empty"; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + return serviceResponse; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + uuid, + } = this.parameters; + + return `/v2/objects/${subscribeKey}/uuids/${encodeString(uuid!)}`; + } +} diff --git a/src/core/endpoints/objects/uuid/set.js b/src/core/endpoints/objects/uuid/set.js deleted file mode 100644 index ca111373c..000000000 --- a/src/core/endpoints/objects/uuid/set.js +++ /dev/null @@ -1,50 +0,0 @@ -/** */ - -import operationConstants from '../../../constants/operations'; - -import utils from '../../../utils'; - -const endpoint = { - getOperation: () => operationConstants.PNSetUUIDMetadataOperation, - - validateParams: (_, params) => { - if (!params?.data) { - return 'Data cannot be empty'; - } - }, - - usePatch: () => true, - - patchURL: ({ config }, params) => - `/v2/objects/${config.subscribeKey}/uuids/${utils.encodeString(params.uuid ?? config.getUUID())}`, - - patchPayload: (_, params) => params.data, - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => true, - - prepareParams: ({ config }, params) => { - const queryParams = {}; - - queryParams.uuid = params?.uuid ?? config.getUUID(); - queryParams.include = ['status', 'type', 'custom']; - - if (params?.include) { - if (params.include?.customFields === false) { - queryParams.include.pop(); - } - } - - queryParams.include = queryParams.include.join(','); - - return queryParams; - }, - - handleResponse: (_, response) => ({ - status: response.status, - data: response.data, - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/objects/uuid/set.ts b/src/core/endpoints/objects/uuid/set.ts new file mode 100644 index 000000000..9ba8736c7 --- /dev/null +++ b/src/core/endpoints/objects/uuid/set.ts @@ -0,0 +1,100 @@ +/** + * Set UUID Metadata REST API module. + */ + +import { createValidationError, PubNubError } from '../../../../errors/pubnub-error'; +import { TransportResponse } from '../../../types/transport-response'; +import { PubNubAPIError } from '../../../../errors/pubnub-api-error'; +import { TransportMethod } from '../../../types/transport-request'; +import { AbstractRequest } from '../../../components/request'; +import RequestOperation from '../../../constants/operations'; +import * as AppContext from '../../../types/api/app-context'; +import { KeySet, Query } from '../../../types/api'; +import { encodeString } from '../../../utils'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Whether `Channel` custom field should be included by default or not. + */ +const INCLUDE_CUSTOM_FIELDS = true; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = AppContext.SetUUIDMetadataParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; +// endregion + +/** + * Set UUID Metadata request. + */ +export class SetUUIDMetadataRequest< + Response extends AppContext.SetUUIDMetadataResponse, + Custom extends AppContext.CustomData = AppContext.CustomData, +> extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super({ method: TransportMethod.PATCH }); + + // Apply default request parameters. + parameters.include ??= {}; + parameters.include.customFields ??= INCLUDE_CUSTOM_FIELDS; + + // Remap for backward compatibility. + if (this.parameters.userId) this.parameters.uuid = this.parameters.userId; + } + + operation(): RequestOperation { + return RequestOperation.PNSetUUIDMetadataOperation; + } + + validate(): string | undefined { + if (!this.parameters.uuid) return "'uuid' cannot be empty"; + if (!this.parameters.data) return 'Data cannot be empty'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + return serviceResponse; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + uuid, + } = this.parameters; + + return `/v2/objects/${subscribeKey}/uuids/${encodeString(uuid!)}`; + } + + protected get queryParameters(): Query { + return { + include: ['status', 'type', ...(this.parameters.include!.customFields ? ['custom'] : [])].join(','), + }; + } + + protected get body(): ArrayBuffer | string | undefined { + return JSON.stringify(this.parameters.data); + } +} diff --git a/src/core/endpoints/presence/get_state.js b/src/core/endpoints/presence/get_state.js deleted file mode 100644 index c75caa82a..000000000 --- a/src/core/endpoints/presence/get_state.js +++ /dev/null @@ -1,53 +0,0 @@ -/* */ - -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -export function getOperation() { - return operationConstants.PNGetStateOperation; -} - -export function validateParams(modules) { - const { config } = modules; - - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules, incomingParams) { - const { config } = modules; - const { uuid = config.UUID, channels = [] } = incomingParams; - const stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return `/v2/presence/sub-key/${config.subscribeKey}/channel/${utils.encodeString(stringifiedChannels)}/uuid/${uuid}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams(modules, incomingParams) { - const { channelGroups = [] } = incomingParams; - const params = {}; - - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); - } - - return params; -} - -export function handleResponse(modules, serverResponse, incomingParams) { - const { channels = [], channelGroups = [] } = incomingParams; - let channelsResponse = {}; - - if (channels.length === 1 && channelGroups.length === 0) { - channelsResponse[channels[0]] = serverResponse.payload; - } else { - channelsResponse = serverResponse.payload; - } - - return { channels: channelsResponse }; -} diff --git a/src/core/endpoints/presence/get_state.ts b/src/core/endpoints/presence/get_state.ts new file mode 100644 index 000000000..ede87639e --- /dev/null +++ b/src/core/endpoints/presence/get_state.ts @@ -0,0 +1,121 @@ +/** + * Get Presence State REST API module. + */ + +import { createValidationError, PubNubError } from '../../../errors/pubnub-error'; +import { TransportResponse } from '../../types/transport-response'; +import { PubNubAPIError } from '../../../errors/pubnub-api-error'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import { KeySet, Payload, Query } from '../../types/api'; +import * as Presence from '../../types/api/presence'; +import { encodeNames } from '../../utils'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = Presence.GetPresenceStateParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Get presence state human-readable result. + */ + message: string; + + /** + * Name of the service which provided response. + */ + service: string; + + /** + * Whether response represent service error or not. + */ + uuid: string; + + /** + * Retrieved {@link uuid} per-channel associated presence state. + */ + payload: Record | Payload; +}; +// endregion + +/** + * Get `uuid` presence state request. + */ +export class GetPresenceStateRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + + // Apply defaults. + this.parameters.channels ??= []; + this.parameters.channelGroups ??= []; + } + + operation(): RequestOperation { + return RequestOperation.PNGetStateOperation; + } + + validate(): string | undefined { + const { + keySet: { subscribeKey }, + channels, + channelGroups, + } = this.parameters; + + if (!subscribeKey) return 'Missing Subscribe Key'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + const { channels = [], channelGroups = [] } = this.parameters; + const state: { channels: Record } = { channels: {} }; + + if (channels.length === 1 && channelGroups.length === 0) state.channels[channels[0]] = serviceResponse.payload; + else state.channels = serviceResponse.payload as Record; + + return state; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + uuid, + channels, + } = this.parameters; + + return `/v2/presence/sub-key/${subscribeKey}/channel/${encodeNames(channels ?? [], ',')}/uuid/${uuid}`; + } + + protected get queryParameters(): Query { + const { channelGroups } = this.parameters; + if (!channelGroups || channelGroups.length === 0) return {}; + + return { 'channel-group': channelGroups.join(',') }; + } +} diff --git a/src/core/endpoints/presence/heartbeat.js b/src/core/endpoints/presence/heartbeat.js deleted file mode 100644 index b5b0b7627..000000000 --- a/src/core/endpoints/presence/heartbeat.js +++ /dev/null @@ -1,49 +0,0 @@ -/* */ - -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -export function getOperation() { - return operationConstants.PNHeartbeatOperation; -} - -export function validateParams(modules) { - const { config } = modules; - - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules, incomingParams) { - const { config } = modules; - const { channels = [] } = incomingParams; - const stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return `/v2/presence/sub-key/${config.subscribeKey}/channel/${utils.encodeString(stringifiedChannels)}/heartbeat`; -} - -export function isAuthSupported() { - return true; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function prepareParams(modules, incomingParams) { - const { channelGroups = [], state } = incomingParams; - const { config } = modules; - const params = {}; - - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); - } - - if (state) { - params.state = JSON.stringify(state); - } - params.heartbeat = config.getPresenceTimeout(); - return params; -} - -export function handleResponse() { - return {}; -} diff --git a/src/core/endpoints/presence/heartbeat.ts b/src/core/endpoints/presence/heartbeat.ts new file mode 100644 index 000000000..80c26f1d3 --- /dev/null +++ b/src/core/endpoints/presence/heartbeat.ts @@ -0,0 +1,102 @@ +/** + * Announce heartbeat REST API module. + */ + +import { createValidationError, PubNubError } from '../../../errors/pubnub-error'; +import { TransportResponse } from '../../types/transport-response'; +import { PubNubAPIError } from '../../../errors/pubnub-api-error'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import * as Presence from '../../types/api/presence'; +import { KeySet, Query } from '../../types/api'; +import { encodeNames } from '../../utils'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = Presence.PresenceHeartbeatParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Presence heartbeat announce human-readable result. + */ + message: string; + + /** + * Name of the service which provided response. + */ + service: string; +}; +// endregion + +export class HeartbeatRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + } + + operation(): RequestOperation { + return RequestOperation.PNHeartbeatOperation; + } + + validate(): string | undefined { + const { + keySet: { subscribeKey }, + channels = [], + channelGroups = [], + } = this.parameters; + + if (!subscribeKey) return 'Missing Subscribe Key'; + if (channels.length === 0 && channelGroups.length === 0) + return 'Please provide a list of channels and/or channel-groups'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + return {}; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channels, + } = this.parameters; + + return `/v2/presence/sub-key/${subscribeKey}/channel/${encodeNames(channels ?? [], ',')}/heartbeat`; + } + + protected get queryParameters(): Query { + const { channelGroups, state, heartbeat } = this.parameters; + const query: Record = { heartbeat: `${heartbeat}` }; + + if (channelGroups && channelGroups.length !== 0) query['channel-group'] = channelGroups.join(','); + if (state) query.state = JSON.stringify(state); + + return query; + } +} diff --git a/src/core/endpoints/presence/here_now.js b/src/core/endpoints/presence/here_now.js deleted file mode 100644 index 53d707c1e..000000000 --- a/src/core/endpoints/presence/here_now.js +++ /dev/null @@ -1,133 +0,0 @@ -/* */ -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -export function getOperation() { - return operationConstants.PNHereNowOperation; -} - -export function validateParams(modules) { - const { config } = modules; - - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules, incomingParams) { - const { config } = modules; - const { channels = [], channelGroups = [] } = incomingParams; - let baseURL = `/v2/presence/sub-key/${config.subscribeKey}`; - - if (channels.length > 0 || channelGroups.length > 0) { - const stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - baseURL += `/channel/${utils.encodeString(stringifiedChannels)}`; - } - - return baseURL; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams(modules, incomingParams) { - const { channelGroups = [], includeUUIDs = true, includeState = false, queryParameters = {} } = incomingParams; - let params = {}; - - if (!includeUUIDs) params.disable_uuids = 1; - if (includeState) params.state = 1; - - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); - } - - params = { ...params, ...queryParameters }; - - return params; -} - -export function handleResponse(modules, serverResponse, incomingParams) { - const { channels = [], channelGroups = [], includeUUIDs = true, includeState = false } = incomingParams; - - const prepareSingularChannel = () => { - const response = {}; - const occupantsList = []; - response.totalChannels = 1; - response.totalOccupancy = serverResponse.occupancy; - response.channels = {}; - response.channels[channels[0]] = { - occupants: occupantsList, - name: channels[0], - occupancy: serverResponse.occupancy, - }; - - // We have had issues in the past with server returning responses - // that contain no uuids array - if (includeUUIDs && serverResponse.uuids) { - serverResponse.uuids.forEach((uuidEntry) => { - if (includeState) { - occupantsList.push({ state: uuidEntry.state, uuid: uuidEntry.uuid }); - } else { - occupantsList.push({ state: null, uuid: uuidEntry }); - } - }); - } - - return response; - }; - - const prepareMultipleChannel = () => { - const response = {}; - response.totalChannels = serverResponse.payload.total_channels; - response.totalOccupancy = serverResponse.payload.total_occupancy; - response.channels = {}; - - Object.keys(serverResponse.payload.channels).forEach((channelName) => { - const channelEntry = serverResponse.payload.channels[channelName]; - const occupantsList = []; - response.channels[channelName] = { - occupants: occupantsList, - name: channelName, - occupancy: channelEntry.occupancy, - }; - - if (includeUUIDs) { - channelEntry.uuids.forEach((uuidEntry) => { - if (includeState) { - occupantsList.push({ - state: uuidEntry.state, - uuid: uuidEntry.uuid, - }); - } else { - occupantsList.push({ state: null, uuid: uuidEntry }); - } - }); - } - - return response; - }); - - return response; - }; - - let response; - if (channels.length > 1 || channelGroups.length > 0 || (channelGroups.length === 0 && channels.length === 0)) { - response = prepareMultipleChannel(); - } else { - response = prepareSingularChannel(); - } - - return response; -} - -export function handleError(modules, params, status) { - if (status.statusCode === 402 && !this.getURL(modules, params).includes('channel')) { - status.errorData.message = - 'You have tried to perform a Global Here Now operation, ' + - 'your keyset configuration does not support that. Please provide a channel, ' + - 'or enable the Global Here Now feature from the Portal.'; - } -} diff --git a/src/core/endpoints/presence/here_now.ts b/src/core/endpoints/presence/here_now.ts new file mode 100644 index 000000000..79eaa7af3 --- /dev/null +++ b/src/core/endpoints/presence/here_now.ts @@ -0,0 +1,216 @@ +/** + * Channels / channel groups presence REST API module. + */ + +import { createValidationError, PubNubError } from '../../../errors/pubnub-error'; +import { TransportResponse } from '../../types/transport-response'; +import { PubNubAPIError } from '../../../errors/pubnub-api-error'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import { KeySet, Payload, Query } from '../../types/api'; +import * as Presence from '../../types/api/presence'; +import { encodeNames } from '../../utils'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Whether `uuid` should be included in response or not. + */ +const INCLUDE_UUID = true; + +/** + * Whether state associated with `uuid` should be included in response or not. + */ +const INCLUDE_STATE = false; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = Presence.HereNowParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type BasicServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Here now human-readable result. + */ + message: string; + + /** + * Name of the service which provided response. + */ + service: string; +}; + +/** + * Single channel here now service response. + */ +type SingleChannelServiceResponse = BasicServiceResponse & { + /** + * List of received channel subscribers. + * + * **Note:** Field is missing if `uuid` and `state` not included. + */ + uuids?: (string | { uuid: string; state?: Payload })[]; + + /** + * Total number of active subscribers. + */ + occupancy: number; +}; + +/** + * Multiple channels / channel groups here now service response. + */ +type MultipleChannelServiceResponse = BasicServiceResponse & { + /** + * Retrieved channels' presence. + */ + payload: { + /** + * Total number of channels for which presence information received. + */ + total_channels: number; + + /** + * Total occupancy for all retrieved channels. + */ + total_occupancy: number; + + /** + * List of channels to which `uuid` currently subscribed. + */ + channels?: { + [p: string]: { + /** + * List of received channel subscribers. + * + * **Note:** Field is missing if `uuid` and `state` not included. + */ + uuids: (string | { uuid: string; state?: Payload })[]; + + /** + * Total number of active subscribers in single channel. + */ + occupancy: number; + }; + }; + }; +}; + +/** + * Here now REST API service success response. + */ +type ServiceResponse = SingleChannelServiceResponse | MultipleChannelServiceResponse; +// endregion + +export class HereNowRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + + // Apply defaults. + this.parameters.queryParameters ??= {}; + this.parameters.includeUUIDs ??= INCLUDE_UUID; + this.parameters.includeState ??= INCLUDE_STATE; + } + + operation(): RequestOperation { + const { channels = [], channelGroups = [] } = this.parameters; + return channels.length === 0 && channelGroups.length === 0 + ? RequestOperation.PNGlobalHereNowOperation + : RequestOperation.PNHereNowOperation; + } + + validate(): string | undefined { + if (!this.parameters.keySet.subscribeKey) return 'Missing Subscribe Key'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + // Extract general presence information. + const totalChannels = 'occupancy' in serviceResponse ? 1 : serviceResponse.payload.total_channels; + const totalOccupancy = + 'occupancy' in serviceResponse ? serviceResponse.occupancy : serviceResponse.payload.total_channels; + const channelsPresence: Presence.HereNowResponse['channels'] = {}; + let channels: Required['channels'] = {}; + + // Remap single channel presence to multiple channels presence response. + if ('occupancy' in serviceResponse) { + const channel = this.parameters.channels![0]; + channels[channel] = { uuids: serviceResponse.uuids ?? [], occupancy: totalOccupancy }; + } else channels = serviceResponse.payload.channels ?? {}; + + Object.keys(channels).forEach((channel) => { + const channelEntry = channels[channel]; + channelsPresence[channel] = { + occupants: this.parameters.includeUUIDs! + ? channelEntry.uuids.map((uuid) => { + if (typeof uuid === 'string') return { uuid, state: null }; + return uuid; + }) + : [], + name: channel, + occupancy: channelEntry.occupancy, + }; + }); + + return { + totalChannels, + totalOccupancy, + channels: channelsPresence, + }; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channels, + channelGroups, + } = this.parameters; + let path = `/v2/presence/sub-key/${subscribeKey}`; + + if ((channels && channels.length > 0) || (channelGroups && channelGroups.length > 0)) + path += `/channel/${encodeNames(channels ?? [], ',')}`; + + return path; + } + + protected get queryParameters(): Query { + const { channelGroups, includeUUIDs, includeState, queryParameters } = this.parameters; + + return { + ...(!includeUUIDs! ? { disable_uuids: '1' } : {}), + ...(includeState ?? false ? { state: '1' } : {}), + ...(channelGroups && channelGroups.length > 0 ? { 'channel-group': channelGroups.join(',') } : {}), + ...queryParameters!, + }; + } +} diff --git a/src/core/endpoints/presence/leave.js b/src/core/endpoints/presence/leave.js deleted file mode 100644 index ed8962603..000000000 --- a/src/core/endpoints/presence/leave.js +++ /dev/null @@ -1,44 +0,0 @@ -/* */ - -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -export function getOperation() { - return operationConstants.PNUnsubscribeOperation; -} - -export function validateParams(modules) { - const { config } = modules; - - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules, incomingParams) { - const { config } = modules; - const { channels = [] } = incomingParams; - const stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return `/v2/presence/sub-key/${config.subscribeKey}/channel/${utils.encodeString(stringifiedChannels)}/leave`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams(modules, incomingParams) { - const { channelGroups = [] } = incomingParams; - const params = {}; - - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); - } - - return params; -} - -export function handleResponse() { - return {}; -} diff --git a/src/core/endpoints/presence/leave.ts b/src/core/endpoints/presence/leave.ts new file mode 100644 index 000000000..4dfb32194 --- /dev/null +++ b/src/core/endpoints/presence/leave.ts @@ -0,0 +1,108 @@ +/** + * Announce leave REST API module. + */ + +import { createValidationError, PubNubError } from '../../../errors/pubnub-error'; +import { TransportResponse } from '../../types/transport-response'; +import { PubNubAPIError } from '../../../errors/pubnub-api-error'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import * as Presence from '../../types/api/presence'; +import { KeySet, Query } from '../../types/api'; +import { encodeNames } from '../../utils'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = Presence.PresenceLeaveParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Leave presence human-readable result. + */ + message: string; + + /** + * Performed presence action. + */ + action: 'leave'; + + /** + * Name of the service which provided response. + */ + service: string; +}; +// endregion + +export class PresenceLeaveRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + + if (this.parameters.channelGroups) + this.parameters.channelGroups = Array.from(new Set(this.parameters.channelGroups)); + if (this.parameters.channels) this.parameters.channels = Array.from(new Set(this.parameters.channels)); + } + + operation(): RequestOperation { + return RequestOperation.PNUnsubscribeOperation; + } + + validate(): string | undefined { + const { + keySet: { subscribeKey }, + channels = [], + channelGroups = [], + } = this.parameters; + + if (!subscribeKey) return 'Missing Subscribe Key'; + if (channels.length === 0 && channelGroups.length === 0) + return 'At least one `channel` or `channel group` should be provided.'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + return {}; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channels, + } = this.parameters; + + return `/v2/presence/sub-key/${subscribeKey}/channel/${encodeNames(channels?.sort() ?? [], ',')}/leave`; + } + + protected get queryParameters(): Query { + const { channelGroups } = this.parameters; + if (!channelGroups || channelGroups.length === 0) return {}; + + return { 'channel-group': channelGroups.sort().join(',') }; + } +} diff --git a/src/core/endpoints/presence/set_state.js b/src/core/endpoints/presence/set_state.js deleted file mode 100644 index 53f419a5d..000000000 --- a/src/core/endpoints/presence/set_state.js +++ /dev/null @@ -1,50 +0,0 @@ -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -export function getOperation() { - return operationConstants.PNSetStateOperation; -} - -export function validateParams(modules, incomingParams) { - const { config } = modules; - const { state, channels = [], channelGroups = [] } = incomingParams; - - if (!state) return 'Missing State'; - if (!config.subscribeKey) return 'Missing Subscribe Key'; - if (channels.length === 0 && channelGroups.length === 0) { - return 'Please provide a list of channels and/or channel-groups'; - } -} - -export function getURL(modules, incomingParams) { - const { config } = modules; - const { channels = [] } = incomingParams; - const stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return `/v2/presence/sub-key/${config.subscribeKey}/channel/${utils.encodeString( - stringifiedChannels, - )}/uuid/${utils.encodeString(config.UUID)}/data`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams(modules, incomingParams) { - const { state, channelGroups = [] } = incomingParams; - const params = {}; - - params.state = JSON.stringify(state); - - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); - } - return params; -} - -export function handleResponse(modules, serverResponse) { - return { state: serverResponse.payload }; -} diff --git a/src/core/endpoints/presence/set_state.ts b/src/core/endpoints/presence/set_state.ts new file mode 100644 index 000000000..583ff2343 --- /dev/null +++ b/src/core/endpoints/presence/set_state.ts @@ -0,0 +1,119 @@ +/** + * Set Presence State REST API module. + */ + +import { createValidationError, PubNubError } from '../../../errors/pubnub-error'; +import { TransportResponse } from '../../types/transport-response'; +import { PubNubAPIError } from '../../../errors/pubnub-api-error'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import { KeySet, Payload, Query } from '../../types/api'; +import { encodeNames, encodeString } from '../../utils'; +import * as Presence from '../../types/api/presence'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = Presence.SetPresenceStateParameters & { + /** + * The subscriber uuid to associate state with. + */ + uuid: string; + + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Set presence state human-readable result. + */ + message: string; + + /** + * Name of the service which provided response. + */ + service: string; + + /** + * Associated presence state. + */ + payload: Payload; +}; +// endregion + +/** + * Set `uuid` presence state request. + */ +export class SetPresenceStateRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + } + + operation(): RequestOperation { + return RequestOperation.PNSetStateOperation; + } + + validate(): string | undefined { + const { + keySet: { subscribeKey }, + state, + channels = [], + channelGroups = [], + } = this.parameters; + + if (!subscribeKey) return 'Missing Subscribe Key'; + if (!state) return 'Missing State'; + if (channels?.length === 0 && channelGroups?.length === 0) + return 'Please provide a list of channels and/or channel-groups'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + return { state: serviceResponse.payload }; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + uuid, + channels, + } = this.parameters; + return `/v2/presence/sub-key/${subscribeKey}/channel/${encodeNames( + channels ?? [], + ',', + )}/uuid/${encodeString(uuid)}/data`; + } + + protected get queryParameters(): Query { + const { channelGroups, state } = this.parameters; + const query: Query = { state: JSON.stringify(state) }; + + if (channelGroups && channelGroups.length !== 0) query['channel-group'] = channelGroups.join(','); + + return query; + } +} diff --git a/src/core/endpoints/presence/where_now.js b/src/core/endpoints/presence/where_now.js deleted file mode 100644 index bc6daeb93..000000000 --- a/src/core/endpoints/presence/where_now.js +++ /dev/null @@ -1,40 +0,0 @@ -/* */ -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -export function getOperation() { - return operationConstants.PNWhereNowOperation; -} - -export function validateParams(modules) { - const { config } = modules; - - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules, incomingParams) { - const { config } = modules; - const { uuid = config.UUID } = incomingParams; - return `/v2/presence/sub-key/${config.subscribeKey}/uuid/${utils.encodeString(uuid)}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams() { - return {}; -} - -export function handleResponse(modules, serverResponse) { - // This is a quick fix for when the server does not include a payload - // in where now responses - if (!serverResponse.payload) { - return { channels: [] }; - } - return { channels: serverResponse.payload.channels }; -} diff --git a/src/core/endpoints/presence/where_now.ts b/src/core/endpoints/presence/where_now.ts new file mode 100644 index 000000000..379b578a3 --- /dev/null +++ b/src/core/endpoints/presence/where_now.ts @@ -0,0 +1,95 @@ +/** + * `uuid` presence REST API module. + */ + +import { createValidationError, PubNubError } from '../../../errors/pubnub-error'; +import { TransportResponse } from '../../types/transport-response'; +import { PubNubAPIError } from '../../../errors/pubnub-api-error'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import * as Presence from '../../types/api/presence'; +import { encodeString } from '../../utils'; +import { KeySet } from '../../types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = Required & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Where now human-readable result. + */ + message: string; + + /** + * Retrieved channels with `uuid` subscriber. + */ + payload?: { + /** + * List of channels to which `uuid` currently subscribed. + */ + channels: string[]; + }; + + /** + * Name of the service which provided response. + */ + service: string; +}; +// endregion + +export class WhereNowRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + } + + operation(): RequestOperation { + return RequestOperation.PNWhereNowOperation; + } + + validate(): string | undefined { + if (!this.parameters.keySet.subscribeKey) return 'Missing Subscribe Key'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } else if (serviceResponse.status >= 400) throw PubNubAPIError.create(response); + + if (!serviceResponse.payload) return { channels: [] }; + + return { channels: serviceResponse.payload.channels }; + } + protected get path(): string { + const { + keySet: { subscribeKey }, + uuid, + } = this.parameters; + + return `/v2/presence/sub-key/${subscribeKey}/uuid/${encodeString(uuid)}`; + } +} diff --git a/src/core/endpoints/publish.js b/src/core/endpoints/publish.js deleted file mode 100644 index 5fddd7d21..000000000 --- a/src/core/endpoints/publish.js +++ /dev/null @@ -1,91 +0,0 @@ -/* */ -import operationConstants from '../constants/operations'; -import utils from '../utils'; -import { encode } from '../components/base64_codec'; - -function prepareMessagePayload(modules, messagePayload) { - let stringifiedPayload = JSON.stringify(messagePayload); - - if (modules.cryptoModule) { - const encrypted = modules.cryptoModule.encrypt(stringifiedPayload); - stringifiedPayload = typeof encrypted === 'string' ? encrypted : encode(encrypted); - stringifiedPayload = JSON.stringify(stringifiedPayload); - } - return stringifiedPayload || ''; -} - -export function getOperation() { - return operationConstants.PNPublishOperation; -} - -export function validateParams({ config }, incomingParams) { - const { message, channel } = incomingParams; - - if (!channel) return 'Missing Channel'; - if (!message) return 'Missing Message'; - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function usePost(modules, incomingParams) { - const { sendByPost = false } = incomingParams; - return sendByPost; -} - -export function getURL(modules, incomingParams) { - const { config } = modules; - const { channel, message } = incomingParams; - const stringifiedPayload = prepareMessagePayload(modules, message); - return `/publish/${config.publishKey}/${config.subscribeKey}/0/${utils.encodeString(channel)}/0/${utils.encodeString( - stringifiedPayload, - )}`; -} - -export function postURL(modules, incomingParams) { - const { config } = modules; - const { channel } = incomingParams; - return `/publish/${config.publishKey}/${config.subscribeKey}/0/${utils.encodeString(channel)}/0`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function postPayload(modules, incomingParams) { - const { message } = incomingParams; - return prepareMessagePayload(modules, message); -} - -export function prepareParams(modules, incomingParams) { - const { meta, replicate = true, storeInHistory, ttl } = incomingParams; - const params = {}; - - if (storeInHistory != null) { - if (storeInHistory) { - params.store = '1'; - } else { - params.store = '0'; - } - } - - if (ttl) { - params.ttl = ttl; - } - - if (replicate === false) { - params.norep = 'true'; - } - - if (meta && typeof meta === 'object') { - params.meta = JSON.stringify(meta); - } - - return params; -} - -export function handleResponse(modules, serverResponse) { - return { timetoken: serverResponse[2] }; -} diff --git a/src/core/endpoints/publish.ts b/src/core/endpoints/publish.ts new file mode 100644 index 000000000..93f369c8b --- /dev/null +++ b/src/core/endpoints/publish.ts @@ -0,0 +1,220 @@ +/** + * Publish REST API module. + */ + +import { createValidationError, PubNubError } from '../../errors/pubnub-error'; +import { TransportResponse } from '../types/transport-response'; +import { TransportMethod } from '../types/transport-request'; +import { CryptoModule } from '../interfaces/crypto-module'; +import { AbstractRequest } from '../components/request'; +import RequestOperation from '../constants/operations'; +import { KeySet, Payload, Query } from '../types/api'; +import { encode } from '../components/base64_codec'; +import { encodeString } from '../utils'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Whether data is published used `POST` body or not. + */ +const SEND_BY_POST = false; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +export type PublishParameters = { + /** + * Channel name to publish messages to. + */ + channel: string; + + /** + * Data which should be sent to the `channel`. + * + * The message may be any valid JSON type including objects, arrays, strings, and numbers. + */ + message: Payload; + + /** + * Whether published data should be available with `Storage API` later or not. + * + * @default `true` + */ + storeInHistory?: boolean; + + /** + * Whether message should be sent as part of request POST body or not. + * + * @default `false` + */ + sendByPost?: boolean; + + /** + * Metadata, which should be associated with published data. + * + * Associated metadata can be utilized by message filtering feature. + */ + meta?: Payload; + + /** + * Specify duration during which data will be available with `Storage API`. + * + * - If `storeInHistory` = `true`, and `ttl` = `0`, the `message` is stored with no expiry time. + * - If `storeInHistory` = `true` and `ttl` = `X` (`X` is an Integer value), the `message` is + * stored with an expiry time of `X` hours. + * - If `storeInHistory` = `false`, the `ttl` parameter is ignored. + * - If `ttl` is not specified, then expiration of the `message` defaults back to the expiry value + * for the key. + */ + ttl?: number; + + /** + * Whether published data should be replicated across all data centers or not. + * + * @default `true` + * @deprecated + */ + replicate?: boolean; + + /** + * Indexed signature for deprecated parameters. + */ + [key: string]: string | number | boolean | undefined | Payload | CryptoModule; +}; + +/** + * Service success response. + */ +export type PublishResponse = { + /** + * High-precision time when published data has been received by the PubNub service. + */ + timetoken: string; +}; + +/** + * Request configuration parameters. + */ +type RequestParameters = PublishParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; + + /** + * Published data encryption module. + */ + crypto?: CryptoModule; +}; + +/** + * Service success response. + */ +type ServiceResponse = [0 | 1, string, string]; +// endregion + +/** + * Data publish request. + * + * Request will normalize and encrypt (if required) provided data and push it to the specified + * channel. + */ +export class PublishRequest extends AbstractRequest { + /** + * Construct data publish request. + * + * @param parameters - Request configuration. + */ + constructor(private readonly parameters: RequestParameters) { + super({ method: parameters.sendByPost ? TransportMethod.POST : TransportMethod.GET }); + + // Apply default request parameters. + this.parameters.sendByPost ??= SEND_BY_POST; + } + + operation(): RequestOperation { + return RequestOperation.PNPublishOperation; + } + + validate(): string | undefined { + const { + message, + channel, + keySet: { publishKey }, + } = this.parameters; + + if (!channel) return "Missing 'channel'"; + if (!message) return "Missing 'message'"; + if (!publishKey) return "Missing 'publishKey'"; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return { timetoken: serviceResponse[2] }; + } + + protected get path(): string { + const { message, channel, keySet } = this.parameters; + const stringifiedPayload = this.prepareMessagePayload(message); + + return `/publish/${keySet.publishKey}/${keySet.subscribeKey}/0/${encodeString(channel)}/0${ + !this.parameters.sendByPost ? `/${encodeString(stringifiedPayload)}` : '' + }`; + } + + protected get queryParameters(): Query { + const { meta, replicate, storeInHistory, ttl } = this.parameters; + const query: Query = {}; + + if (storeInHistory !== undefined) query.store = storeInHistory ? '1' : '0'; + if (ttl !== undefined) query.ttl = ttl; + if (replicate !== undefined && !replicate) query.norep = 'true'; + if (meta && typeof meta === 'object') query.meta = JSON.stringify(meta); + + return query; + } + + protected get headers(): Record | undefined { + return { 'Content-Type': 'application/json' }; + } + + protected get body(): ArrayBuffer | string | undefined { + return this.prepareMessagePayload(this.parameters.message); + } + + /** + * Pre-process provided data. + * + * Data will be "normalized" and encrypted if `cryptoModule` has been provided. + * + * @param payload - User-provided data which should be pre-processed before use. + * + * @returns Payload which can be used as part of request URL or body. + * + * @throws {Error} in case if provided `payload` or results of `encryption` can't be stringified. + */ + private prepareMessagePayload(payload: Payload): string { + const { crypto } = this.parameters; + if (!crypto) return JSON.stringify(payload) || ''; + + const encrypted = crypto.encrypt(JSON.stringify(payload)); + + return JSON.stringify(typeof encrypted === 'string' ? encrypted : encode(encrypted)); + } +} diff --git a/src/core/endpoints/push/add_push_channels.js b/src/core/endpoints/push/add_push_channels.js deleted file mode 100644 index 759a8ce63..000000000 --- a/src/core/endpoints/push/add_push_channels.js +++ /dev/null @@ -1,53 +0,0 @@ -/* */ - -import operationConstants from '../../constants/operations'; - -export function getOperation() { - return operationConstants.PNPushNotificationEnabledChannelsOperation; -} - -export function validateParams(modules, incomingParams) { - const { device, pushGateway, channels, topic } = incomingParams; - const { config } = modules; - - if (!device) return 'Missing Device ID (device)'; - if (!pushGateway) return 'Missing GW Type (pushGateway: gcm, apns or apns2)'; - if (pushGateway === 'apns2' && !topic) return 'Missing APNS2 topic'; - if (!channels || channels.length === 0) return 'Missing Channels'; - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules, incomingParams) { - const { device, pushGateway } = incomingParams; - const { config } = modules; - - if (pushGateway === 'apns2') { - return `/v2/push/sub-key/${config.subscribeKey}/devices-apns2/${device}`; - } - - return `/v1/push/sub-key/${config.subscribeKey}/devices/${device}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams(modules, incomingParams) { - const { pushGateway, channels = [], environment = 'development', topic } = incomingParams; - let parameters = { type: pushGateway, add: channels.join(',') }; - - if (pushGateway === 'apns2') { - parameters = { ...parameters, environment, topic }; - delete parameters.type; - } - - return parameters; -} - -export function handleResponse() { - return {}; -} diff --git a/src/core/endpoints/push/add_push_channels.ts b/src/core/endpoints/push/add_push_channels.ts new file mode 100644 index 000000000..8692f4b50 --- /dev/null +++ b/src/core/endpoints/push/add_push_channels.ts @@ -0,0 +1,59 @@ +/** + * Register Channels with Device push REST API module. + */ + +import { createValidationError, PubNubError } from '../../../errors/pubnub-error'; +import { TransportResponse } from '../../types/transport-response'; +import { BasePushNotificationChannelsRequest } from './push'; +import RequestOperation from '../../constants/operations'; +import * as Push from '../../types/api/push'; +import { KeySet } from '../../types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = Push.ManageDeviceChannelsParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = [0 | 1, string]; +// endregion + +/** + * Register channels with device push request. + */ +// prettier-ignore +export class AddDevicePushNotificationChannelsRequest extends BasePushNotificationChannelsRequest< + Push.ManageDeviceChannelsResponse +> { + constructor(parameters: RequestParameters) { + super({ ...parameters, action: 'add' }); + } + + operation(): RequestOperation { + return RequestOperation.PNAddPushNotificationEnabledChannelsOperation; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return {}; + } +} diff --git a/src/core/endpoints/push/list_push_channels.js b/src/core/endpoints/push/list_push_channels.js deleted file mode 100644 index 2241407d7..000000000 --- a/src/core/endpoints/push/list_push_channels.js +++ /dev/null @@ -1,54 +0,0 @@ -/* */ -import operationConstants from '../../constants/operations'; - -export function getOperation() { - return operationConstants.PNPushNotificationEnabledChannelsOperation; -} - -export function validateParams(modules, incomingParams) { - const { device, pushGateway, topic } = incomingParams; - const { config } = modules; - - if (!device) return 'Missing Device ID (device)'; - if (!pushGateway) return 'Missing GW Type (pushGateway: gcm, apns or apns2)'; - if (pushGateway === 'apns2' && !topic) return 'Missing APNS2 topic'; - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules, incomingParams) { - const { device, pushGateway } = incomingParams; - const { config } = modules; - - if (pushGateway === 'apns2') { - return `/v2/push/sub-key/${config.subscribeKey}/devices-apns2/${device}`; - } - - return `/v1/push/sub-key/${config.subscribeKey}/devices/${device}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams(modules, incomingParams) { - const { pushGateway, environment = 'development', topic, start, count } = incomingParams; - let parameters = { type: pushGateway }; - - if (pushGateway === 'apns2') { - parameters = { ...parameters, environment, topic }; - delete parameters.type; - } - - if (start) parameters.start = start; - if (count && count > 0) parameters.count = count; - - return parameters; -} - -export function handleResponse(modules, serverResponse) { - return { channels: serverResponse }; -} diff --git a/src/core/endpoints/push/list_push_channels.ts b/src/core/endpoints/push/list_push_channels.ts new file mode 100644 index 000000000..725bbbefc --- /dev/null +++ b/src/core/endpoints/push/list_push_channels.ts @@ -0,0 +1,59 @@ +/** + * List Device push enabled channels REST API module. + */ + +import { createValidationError, PubNubError } from '../../../errors/pubnub-error'; +import { TransportResponse } from '../../types/transport-response'; +import { BasePushNotificationChannelsRequest } from './push'; +import RequestOperation from '../../constants/operations'; +import * as Push from '../../types/api/push'; +import { KeySet } from '../../types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = Push.ListDeviceChannelsParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = string[]; +// endregion + +/** + * List device push enabled channels request. + */ +// prettier-ignore +export class ListDevicePushNotificationChannelsRequest extends BasePushNotificationChannelsRequest< + Push.ListDeviceChannelsResponse +> { + constructor(parameters: RequestParameters) { + super({ ...parameters, action: 'list' }); + } + + operation(): RequestOperation { + return RequestOperation.PNPushNotificationEnabledChannelsOperation; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return { channels: serviceResponse }; + } +} diff --git a/src/core/endpoints/push/push.ts b/src/core/endpoints/push/push.ts new file mode 100644 index 000000000..20e231d62 --- /dev/null +++ b/src/core/endpoints/push/push.ts @@ -0,0 +1,121 @@ +/** + * Manage channels enabled for device push REST API module. + */ + +import { TransportResponse } from '../../types/transport-response'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import { KeySet, Query } from '../../types/api'; +import * as Push from '../../types/api/push'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Environment for which APNS2 notifications + */ +const ENVIRONMENT = 'development'; + +/** + * Maximum number of channels in `list` response. + */ +const MAX_COUNT = 1000; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = (Push.ManageDeviceChannelsParameters | Push.RemoveDeviceParameters) & { + /** + * Action which should be performed. + */ + action: 'add' | 'remove' | 'remove-device' | 'list'; + + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; +// endregion + +/** + * Base push notification request. + */ +export class BasePushNotificationChannelsRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + + // Apply request defaults + if (this.parameters.pushGateway === 'apns2') this.parameters.environment ??= ENVIRONMENT; + if (this.parameters.count && this.parameters.count > MAX_COUNT) this.parameters.count = MAX_COUNT; + } + + operation(): RequestOperation { + throw Error('Should be implemented in subclass.'); + } + + validate(): string | undefined { + const { + keySet: { subscribeKey }, + action, + device, + pushGateway, + } = this.parameters; + + if (!subscribeKey) return 'Missing Subscribe Key'; + if (!device) return 'Missing Device ID (device)'; + if ( + (action === 'add' || action === 'remove') && + (!('channels' in this.parameters) || this.parameters.channels.length === 0) + ) + return 'Missing Channels'; + + if (!pushGateway) return 'Missing GW Type (pushGateway: gcm or apns2)'; + if (this.parameters.pushGateway === 'apns2' && !this.parameters.topic) return 'Missing APNS2 topic'; + } + + async parse(_response: TransportResponse): Promise { + throw Error('Should be implemented in subclass.'); + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + action, + device, + pushGateway, + } = this.parameters; + + let path = + pushGateway === 'apns2' + ? `/v2/push/sub-key/${subscribeKey}/devices-apns2/${device}` + : `/v1/push/sub-key/${subscribeKey}/devices/${device}`; + if (action === 'remove-device') path = `${path}/remove`; + + return path; + } + + protected get queryParameters(): Query { + const { start, count } = this.parameters; + let query: Query = { + type: this.parameters.pushGateway, + ...(start ? { start } : {}), + ...(count && count > 0 ? { count } : {}), + }; + + if ('channels' in this.parameters) query[this.parameters.action] = this.parameters.channels.join(','); + if (this.parameters.pushGateway === 'apns2') { + const { environment, topic } = this.parameters; + query = { ...query, environment: environment!, topic }; + } + + return query; + } +} diff --git a/src/core/endpoints/push/remove_device.js b/src/core/endpoints/push/remove_device.js deleted file mode 100644 index 1f1d350fb..000000000 --- a/src/core/endpoints/push/remove_device.js +++ /dev/null @@ -1,52 +0,0 @@ -/* */ - -import operationConstants from '../../constants/operations'; - -export function getOperation() { - return operationConstants.PNRemoveAllPushNotificationsOperation; -} - -export function validateParams(modules, incomingParams) { - const { device, pushGateway, topic } = incomingParams; - const { config } = modules; - - if (!device) return 'Missing Device ID (device)'; - if (!pushGateway) return 'Missing GW Type (pushGateway: gcm, apns or apns2)'; - if (pushGateway === 'apns2' && !topic) return 'Missing APNS2 topic'; - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules, incomingParams) { - const { device, pushGateway } = incomingParams; - const { config } = modules; - - if (pushGateway === 'apns2') { - return `/v2/push/sub-key/${config.subscribeKey}/devices-apns2/${device}/remove`; - } - - return `/v1/push/sub-key/${config.subscribeKey}/devices/${device}/remove`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams(modules, incomingParams) { - const { pushGateway, environment = 'development', topic } = incomingParams; - let parameters = { type: pushGateway }; - - if (pushGateway === 'apns2') { - parameters = { ...parameters, environment, topic }; - delete parameters.type; - } - - return parameters; -} - -export function handleResponse() { - return {}; -} diff --git a/src/core/endpoints/push/remove_device.ts b/src/core/endpoints/push/remove_device.ts new file mode 100644 index 000000000..5fd4235f3 --- /dev/null +++ b/src/core/endpoints/push/remove_device.ts @@ -0,0 +1,59 @@ +/** + * Unregister Device push REST API module. + */ + +import { createValidationError, PubNubError } from '../../../errors/pubnub-error'; +import { TransportResponse } from '../../types/transport-response'; +import { BasePushNotificationChannelsRequest } from './push'; +import RequestOperation from '../../constants/operations'; +import * as Push from '../../types/api/push'; +import { KeySet } from '../../types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = Push.RemoveDeviceParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = [0 | 1, string]; +// endregion + +/** + * Unregister device push notifications request. + */ +// prettier-ignore +export class RemoveDevicePushNotificationRequest extends BasePushNotificationChannelsRequest< + Push.RemoveDeviceResponse +> { + constructor(parameters: RequestParameters) { + super({ ...parameters, action: 'remove-device' }); + } + + operation(): RequestOperation { + return RequestOperation.PNRemoveAllPushNotificationsOperation; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return {}; + } +} diff --git a/src/core/endpoints/push/remove_push_channels.js b/src/core/endpoints/push/remove_push_channels.js deleted file mode 100644 index 16cc9bcfd..000000000 --- a/src/core/endpoints/push/remove_push_channels.js +++ /dev/null @@ -1,53 +0,0 @@ -/* */ - -import operationConstants from '../../constants/operations'; - -export function getOperation() { - return operationConstants.PNPushNotificationEnabledChannelsOperation; -} - -export function validateParams(modules, incomingParams) { - const { device, pushGateway, channels, topic } = incomingParams; - const { config } = modules; - - if (!device) return 'Missing Device ID (device)'; - if (!pushGateway) return 'Missing GW Type (pushGateway: gcm, apns or apns2)'; - if (pushGateway === 'apns2' && !topic) return 'Missing APNS2 topic'; - if (!channels || channels.length === 0) return 'Missing Channels'; - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules, incomingParams) { - const { device, pushGateway } = incomingParams; - const { config } = modules; - - if (pushGateway === 'apns2') { - return `/v2/push/sub-key/${config.subscribeKey}/devices-apns2/${device}`; - } - - return `/v1/push/sub-key/${config.subscribeKey}/devices/${device}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams(modules, incomingParams) { - const { pushGateway, channels = [], environment = 'development', topic } = incomingParams; - let parameters = { type: pushGateway, remove: channels.join(',') }; - - if (pushGateway === 'apns2') { - parameters = { ...parameters, environment, topic }; - delete parameters.type; - } - - return parameters; -} - -export function handleResponse() { - return {}; -} diff --git a/src/core/endpoints/push/remove_push_channels.ts b/src/core/endpoints/push/remove_push_channels.ts new file mode 100644 index 000000000..69a939045 --- /dev/null +++ b/src/core/endpoints/push/remove_push_channels.ts @@ -0,0 +1,59 @@ +/** + * Unregister Channels from Device push REST API module. + */ + +import { createValidationError, PubNubError } from '../../../errors/pubnub-error'; +import { TransportResponse } from '../../types/transport-response'; +import { BasePushNotificationChannelsRequest } from './push'; +import RequestOperation from '../../constants/operations'; +import * as Push from '../../types/api/push'; +import { KeySet } from '../../types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = Push.ManageDeviceChannelsParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = [0 | 1, string]; +// endregion + +/** + * Unregister channels from device push request. + */ +// prettier-ignore +export class RemoveDevicePushNotificationChannelsRequest extends BasePushNotificationChannelsRequest< + Push.ManageDeviceChannelsResponse +> { + constructor(parameters: RequestParameters) { + super({ ...parameters, action: 'remove' }); + } + + operation(): RequestOperation { + return RequestOperation.PNRemovePushNotificationEnabledChannelsOperation; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return {}; + } +} diff --git a/src/core/endpoints/signal.js b/src/core/endpoints/signal.js deleted file mode 100644 index ff7aa4802..000000000 --- a/src/core/endpoints/signal.js +++ /dev/null @@ -1,49 +0,0 @@ -/* */ - -import operationConstants from '../constants/operations'; -import utils from '../utils'; - -function prepareMessagePayload(modules, messagePayload) { - const stringifiedPayload = JSON.stringify(messagePayload); - - return stringifiedPayload; -} - -export function getOperation() { - return operationConstants.PNSignalOperation; -} - -export function validateParams({ config }, incomingParams) { - const { message, channel } = incomingParams; - - if (!channel) return 'Missing Channel'; - if (!message) return 'Missing Message'; - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules, incomingParams) { - const { config } = modules; - const { channel, message } = incomingParams; - const stringifiedPayload = prepareMessagePayload(modules, message); - return `/signal/${config.publishKey}/${config.subscribeKey}/0/${utils.encodeString(channel)}/0/${utils.encodeString( - stringifiedPayload, - )}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams() { - const params = {}; - - return params; -} - -export function handleResponse(modules, serverResponse) { - return { timetoken: serverResponse[2] }; -} diff --git a/src/core/endpoints/signal.ts b/src/core/endpoints/signal.ts new file mode 100644 index 000000000..b17379d89 --- /dev/null +++ b/src/core/endpoints/signal.ts @@ -0,0 +1,103 @@ +/** + * Signal REST API module. + */ + +import { createValidationError, PubNubError } from '../../errors/pubnub-error'; +import { TransportResponse } from '../types/transport-response'; +import { AbstractRequest } from '../components/request'; +import RequestOperation from '../constants/operations'; +import { KeySet, Payload } from '../types/api'; +import { encodeString } from '../utils'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +export type SignalParameters = { + /** + * Channel name to publish signal to. + */ + channel: string; + + /** + * Data which should be sent to the `channel`. + * + * The message may be any valid JSON type including objects, arrays, strings, and numbers. + */ + message: Payload; +}; + +/** + * Service success response. + */ +export type SignalResponse = { + /** + * High-precision time when published data has been received by the PubNub service. + */ + timetoken: string; +}; + +/** + * Request configuration parameters. + */ +type RequestParameters = SignalParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = [0 | 1, string, string]; +// endregion + +export class SignalRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + } + + operation(): RequestOperation { + return RequestOperation.PNSignalOperation; + } + + validate(): string | undefined { + const { + message, + channel, + keySet: { publishKey }, + } = this.parameters; + + if (!channel) return "Missing 'channel'"; + if (!message) return "Missing 'message'"; + if (!publishKey) return "Missing 'publishKey'"; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return { timetoken: serviceResponse[2] }; + } + + protected get path(): string { + const { + keySet: { publishKey, subscribeKey }, + channel, + message, + } = this.parameters; + const stringifiedPayload = JSON.stringify(message); + + return `/signal/${publishKey}/${subscribeKey}/0/${encodeString(channel)}/0/${encodeString(stringifiedPayload)}`; + } +} diff --git a/src/core/endpoints/subscribe.js b/src/core/endpoints/subscribe.js deleted file mode 100644 index 8058b094e..000000000 --- a/src/core/endpoints/subscribe.js +++ /dev/null @@ -1,89 +0,0 @@ -/* */ -import operationConstants from '../constants/operations'; -import utils from '../utils'; - -export function getOperation() { - return operationConstants.PNSubscribeOperation; -} - -export function validateParams(modules) { - const { config } = modules; - - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules, incomingParams) { - const { config } = modules; - const { channels = [] } = incomingParams; - const stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return `/v2/subscribe/${config.subscribeKey}/${utils.encodeString(stringifiedChannels)}/0`; -} - -export function getRequestTimeout({ config }) { - return config.getSubscribeTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams({ config }, incomingParams) { - const { state, channelGroups = [], timetoken, filterExpression, region } = incomingParams; - const params = { - heartbeat: config.getPresenceTimeout(), - }; - - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); - } - - if (filterExpression && filterExpression.length > 0) { - params['filter-expr'] = filterExpression; - } - - if (Object.keys(state).length) { - params.state = JSON.stringify(state); - } - - if (timetoken) { - params.tt = timetoken; - } - - if (region) { - params.tr = region; - } - - return params; -} - -export function handleResponse(modules, serverResponse) { - const messages = []; - - serverResponse.m.forEach((rawMessage) => { - const publishMetaData = { - timetoken: rawMessage.p.t, - region: rawMessage.p.r, - }; - const parsedMessage = { - shard: parseInt(rawMessage.a, 10), - subscriptionMatch: rawMessage.b, - channel: rawMessage.c, - messageType: rawMessage.e, - payload: rawMessage.d, - flags: rawMessage.f, - issuingClientId: rawMessage.i, - subscribeKey: rawMessage.k, - originationTimetoken: rawMessage.o, - userMetadata: rawMessage.u, - publishMetaData, - }; - messages.push(parsedMessage); - }); - - const metadata = { - timetoken: serverResponse.t.t, - region: serverResponse.t.r, - }; - - return { messages, metadata }; -} diff --git a/src/core/endpoints/subscribe.ts b/src/core/endpoints/subscribe.ts new file mode 100644 index 000000000..d31302ce5 --- /dev/null +++ b/src/core/endpoints/subscribe.ts @@ -0,0 +1,870 @@ +/** + * Subscription REST API module. + */ + +import { createValidationError, PubNubError } from '../../errors/pubnub-error'; +import { TransportResponse } from '../types/transport-response'; +import { CryptoModule } from '../interfaces/crypto-module'; +import * as Subscription from '../types/api/subscription'; +import { AbstractRequest } from '../components/request'; +import * as FileSharing from '../types/api/file-sharing'; +import RequestOperation from '../constants/operations'; +import * as AppContext from '../types/api/app-context'; +import { KeySet, Payload, Query } from '../types/api'; +import { encodeNames } from '../utils'; + +// -------------------------------------------------------- +// ---------------------- Defaults ------------------------ +// -------------------------------------------------------- +// region Defaults + +/** + * Whether should subscribe to channels / groups presence announcements or not. + */ +const WITH_PRESENCE = false; + +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * PubNub-defined event types by payload. + */ +export enum PubNubEventType { + /** + * Presence change event. + */ + Presence = -2, + + /** + * Regular message event. + * + * **Note:** This is default type assigned for non-presence events if `e` field is missing. + */ + Message = -1, + + /** + * Signal data event. + */ + Signal = 1, + + /** + * App Context object event. + */ + AppContext, + + /** + * Message reaction event. + */ + MessageAction, + + /** + * Files event. + */ + Files, +} + +/** + * Time cursor. + * + * Cursor used by subscription loop to identify point in time after which updates will be + * delivered. + */ +type SubscriptionCursor = { + /** + * PubNub high-precision timestamp. + * + * Aside of specifying exact time of receiving data / event this token used to catchup / + * follow on real-time updates. + */ + t: string; + + /** + * Data center region for which `timetoken` has been generated. + */ + r: number; +}; + +// endregion + +// region Presence service response +/** + * Periodical presence change service response. + */ +type PresenceIntervalData = { + /** + * Periodical subscribed channels and groups presence change announcement. + */ + action: 'interval'; + + /** + * Unix timestamp when presence event has been triggered. + */ + timestamp: number; + + /** + * The current occupancy after the presence change is updated. + */ + occupancy: number; + + /** + * The list of unique user identifiers that `joined` the channel since the last interval + * presence update. + */ + join?: string[]; + + /** + * The list of unique user identifiers that `left` the channel since the last interval + * presence update. + */ + leave?: string[]; + + /** + * The list of unique user identifiers that `timeout` the channel since the last interval + * presence update. + */ + timeout?: string[]; +}; + +/** + * Subscribed user presence information change service response. + */ +type PresenceChangeData = { + /** + * Change if user's presence. + * + * User's presence may change between: `join`, `leave` and `timeout`. + */ + action: 'join' | 'leave' | 'timeout'; + + /** + * Unix timestamp when presence event has been triggered. + */ + timestamp: number; + + /** + * Unique identification of the user for whom presence information changed. + */ + uuid: string; + + /** + * The current occupancy after the presence change is updated. + */ + occupancy: number; + + /** + * The user's state associated with the channel has been updated. + * + * @deprecated Use set state methods to specify associated user's data instead of passing to + * subscribe. + */ + data?: { [p: string]: Payload }; +}; + +/** + * Associated user presence state change service response. + */ +type PresenceStateChangeData = { + /** + * Subscribed user associated presence state change. + */ + action: 'state-change'; + + /** + * Unix timestamp when presence event has been triggered. + */ + timestamp: number; + + /** + * Unique identification of the user for whom associated presence state has been changed. + */ + uuid: string; + + /** + * The user's state associated with the channel has been updated. + */ + state: { [p: string]: Payload }; +}; + +/** + * Channel presence service response. + */ +export type PresenceData = PresenceIntervalData | PresenceChangeData | PresenceStateChangeData; +// endregion + +// region Message Actions service response +/** + * Message reaction change service response. + */ +export type MessageActionData = { + /** + * The type of event that happened during the message action update. + * + * Possible values are: + * - `added` - action has been added to the message + * - `removed` - action has been removed from message + */ + event: 'added' | 'removed'; + + /** + * Information about message action for which update has been generated. + */ + data: { + /** + * Timetoken of message for which action has been added / removed. + */ + messageTimetoken: string; + + /** + * Timetoken of message action which has been added / removed. + */ + actionTimetoken: string; + + /** + * Message action type. + */ + type: string; + + /** + * Value associated with message action {@link type}. + */ + value: string; + }; + + /** + * Name of service which generated update for message action. + */ + source: string; + + /** + * Version of service which generated update for message action. + */ + version: string; +}; +// endregion + +// region App Context service data +/** + * VSP Objects change events. + */ +type AppContextVSPEvents = 'updated' | 'removed'; + +/** + * App Context Objects change events. + */ +type AppContextEvents = 'set' | 'delete'; + +/** + * Common real-time App Context Object service response. + */ +type ObjectData = { + /** + * The type of event that happened during the object update. + */ + event: Event; + + /** + * App Context object type. + */ + type: Type; + + /** + * App Context object information. + * + * App Context object can be one of: + * - `channel` / `space` + * - `uuid` / `user` + * - `membership` + */ + data: AppContextObject; + + /** + * Name of service which generated update for object. + */ + source: string; + + /** + * Version of service which generated update for object. + */ + version: string; +}; + +/** + * `Channel` object change real-time service response. + */ +type ChannelObjectData = ObjectData< + AppContextEvents, + 'channel', + AppContext.ChannelMetadataObject +>; + +/** + * `Space` object change real-time service response. + */ +export type SpaceObjectData = ObjectData< + AppContextVSPEvents, + 'space', + AppContext.ChannelMetadataObject +>; + +/** + * `Uuid` object change real-time service response. + */ +type UuidObjectData = ObjectData>; + +/** + * `User` object change real-time service response. + */ +export type UserObjectData = ObjectData< + AppContextVSPEvents, + 'user', + AppContext.UUIDMetadataObject +>; + +/** + * `Membership` object change real-time service response. + */ +type MembershipObjectData = ObjectData< + AppContextEvents, + 'membership', + Omit, 'id'> & { + /** + * `Uuid` object which has been used to create relationship with `channel`. + */ + uuid: { + /** + * Unique `user` object identifier. + */ + id: string; + }; + + /** + * `Channel` object which has been used to create relationship with `uuid`. + */ + channel: { + /** + * Unique `channel` object identifier. + */ + id: string; + }; + } +>; + +/** + * VSP `Membership` object change real-time service response. + */ +export type VSPMembershipObjectData = ObjectData< + AppContextVSPEvents, + 'membership', + Omit, 'id'> & { + /** + * `User` object which has been used to create relationship with `space`. + */ + user: { + /** + * Unique `user` object identifier. + */ + id: string; + }; + + /** + * `Space` object which has been used to create relationship with `user`. + */ + space: { + /** + * Unique `channel` object identifier. + */ + id: string; + }; + } +>; + +/** + * App Context service response. + */ +export type AppContextObjectData = ChannelObjectData | UuidObjectData | MembershipObjectData; +// endregion + +// region File service response +/** + * File service response. + */ +export type FileData = { + /** + * Message which has been associated with uploaded file. + */ + message?: Payload; + + /** + * Information about uploaded file. + */ + file: { + /** + * Unique identifier of uploaded file. + */ + id: string; + + /** + * Actual name with which file has been stored. + */ + name: string; + }; +}; +// endregion + +/** + * Service response data envelope. + * + * Each entry from `m` list wrapped into this object. + */ +type Envelope = { + /** + * Shard number on which the event has been stored. + */ + a: string; + + /** + * A numeric representation of enabled debug flags. + */ + f: number; + + /** + * PubNub defined event type. + */ + e?: PubNubEventType; + + /** + * Identifier of client which sent message (set only when Publish REST API endpoint called with + * `uuid`). + */ + i?: string; + + /** + * Sequence number (set only when Publish REST API endpoint called with `seqn`). + */ + s?: number; + + /** + * Event "publish" time. + * + * This is the time when message has been received by {@link https://www.pubnub.com|PubNub} network. + */ + p: SubscriptionCursor; + + /** + * User-defined (local) "publish" time. + */ + o?: SubscriptionCursor; + + /** + * Name of channel where update received. + */ + c: string; + + /** + * Event payload. + * + * **Note:** One more type not mentioned here to keep type system working ({@link Payload}). + */ + d: PresenceData | MessageActionData | AppContextObjectData | FileData | string; + + /** + * Actual name of subscription through which event has been delivered. + * + * PubNub client can be used to subscribe to the group of channels to receive updates and + * (group name will be set for field). With this approach there will be no need to separately + * add *N* number of channels to `subscribe` method call. + */ + b?: string; + + /** + * User-provided metadata during `publish` method usage. + */ + u?: { [p: string]: Payload }; + + /** + * User provided message type (set only when `publish` called with `type`). + */ + mt?: string; + + /** + * Identifier of space into which message has been published (set only when `publish` called + * with `space_id`). + */ + si?: string; +}; + +/** + * Subscribe REST API service success response. + */ +type ServiceResponse = { + /** + * Next subscription cursor. + * + * The cursor contains information about the start of the next real-time update timeframe. + */ + t: SubscriptionCursor; + + /** + * List of updates. + * + * Contains list of real-time updates received using previous subscription cursor. + */ + m: Envelope[]; +}; + +/** + * Request configuration parameters. + */ +export type RequestParameters = Subscription.SubscribeParameters & { + /** + * Timetoken's region identifier. + */ + region?: number; + + /** + * Subscriber `userId` presence timeout. + * + * For how long (in seconds) user will be `online` without sending any new subscribe or + * heartbeat requests. + */ + heartbeat?: number; + + /** + * Real-time events filtering expression. + */ + filterExpression?: string | null; + + /** + * PubNub REST API access key set. + */ + keySet: KeySet; + + /** + * Received data decryption module. + */ + crypto?: CryptoModule; + + /** + * File download Url generation function. + * + * @param id - Unique identifier of the file which should be downloaded. + * @param name - Name with which file has been stored. + * @param channel - Name of the channel from which file should be downloaded. + */ + getFileUrl: (parameters: FileSharing.FileUrlParameters) => string; +}; +// endregion + +/** + * Base subscription request implementation. + * + * Subscription request used in small variations in two cases: + * - subscription manager + * - event engine + */ +export class BaseSubscribeRequest extends AbstractRequest { + constructor(protected readonly parameters: RequestParameters) { + super({ cancellable: true }); + + // Apply default request parameters. + this.parameters.withPresence ??= WITH_PRESENCE; + this.parameters.channelGroups ??= []; + this.parameters.channels ??= []; + } + + operation(): RequestOperation { + return RequestOperation.PNSubscribeOperation; + } + + validate(): string | undefined { + const { + keySet: { subscribeKey }, + channels, + channelGroups, + } = this.parameters; + + if (!subscribeKey) return 'Missing Subscribe Key'; + if (!channels && !channelGroups) return '`channels` and `channelGroups` both should not be empty'; + } + + async parse(response: TransportResponse): Promise { + let serviceResponse: ServiceResponse | undefined; + + try { + const json = AbstractRequest.decoder.decode(response.body); + const parsedJson = JSON.parse(json); + serviceResponse = parsedJson as ServiceResponse; + } catch (error) { + console.error('Error parsing JSON response:', error); + } + + if (!serviceResponse) { + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + } + + const events: Subscription.SubscriptionResponse['messages'] = serviceResponse.m.map((envelope) => { + let { e: eventType } = envelope; + + // Resolve missing event type. + eventType ??= envelope.c.endsWith('-pnpres') ? PubNubEventType.Presence : PubNubEventType.Message; + + // Check whether payload is string (potentially encrypted data). + if (typeof envelope.d === 'string') { + if (eventType == PubNubEventType.Message) { + return { + type: PubNubEventType.Message, + data: this.messageFromEnvelope(envelope), + }; + } + + return { + type: PubNubEventType.Files, + data: this.fileFromEnvelope(envelope), + }; + } else if (eventType == PubNubEventType.Message) { + return { + type: PubNubEventType.Message, + data: this.messageFromEnvelope(envelope), + }; + } else if (eventType === PubNubEventType.Presence) { + return { + type: PubNubEventType.Presence, + data: this.presenceEventFromEnvelope(envelope), + }; + } else if (eventType == PubNubEventType.Signal) { + return { + type: PubNubEventType.Signal, + data: this.signalFromEnvelope(envelope), + }; + } else if (eventType === PubNubEventType.AppContext) { + return { + type: PubNubEventType.AppContext, + data: this.appContextFromEnvelope(envelope), + }; + } else if (eventType === PubNubEventType.MessageAction) { + return { + type: PubNubEventType.MessageAction, + data: this.messageActionFromEnvelope(envelope), + }; + } + + return { + type: PubNubEventType.Files, + data: this.fileFromEnvelope(envelope), + }; + }); + + return { + cursor: { timetoken: serviceResponse.t.t, region: serviceResponse.t.r }, + messages: events, + }; + } + + protected get headers(): Record | undefined { + return { accept: 'text/javascript' }; + } + + // -------------------------------------------------------- + // ------------------ Envelope parsing -------------------- + // -------------------------------------------------------- + // region Envelope parsing + + private presenceEventFromEnvelope(envelope: Envelope): Subscription.Presence { + const { d: payload } = envelope; + const [channel, subscription] = this.subscriptionChannelFromEnvelope(envelope); + + // Clean up channel and subscription name from presence suffix. + const trimmedChannel = channel.replace('-pnpres', ''); + + // Backward compatibility with deprecated properties. + const actualChannel = subscription !== null ? trimmedChannel : null; + const subscribedChannel = subscription !== null ? subscription : trimmedChannel; + + if (typeof payload !== 'string' && 'data' in payload) { + // @ts-expect-error This is `state-change` object which should have `state` field. + payload['state'] = payload.data; + delete payload.data; + } + + return { + channel: trimmedChannel, + subscription, + actualChannel, + subscribedChannel, + timetoken: envelope.p.t, + ...(payload as PresenceData), + }; + } + + private messageFromEnvelope(envelope: Envelope): Subscription.Message { + const [channel, subscription] = this.subscriptionChannelFromEnvelope(envelope); + const [message, decryptionError] = this.decryptedData(envelope.d); + + // Backward compatibility with deprecated properties. + const actualChannel = subscription !== null ? channel : null; + const subscribedChannel = subscription !== null ? subscription : channel; + + // Basic message event payload. + const event: Subscription.Message = { + channel, + subscription, + actualChannel, + subscribedChannel, + timetoken: envelope.p.t, + publisher: envelope.i, + message, + }; + + if (envelope.u) event.userMetadata = envelope.u; + if (decryptionError) event.error = decryptionError; + + return event; + } + + private signalFromEnvelope(envelope: Envelope): Subscription.Signal { + const [channel, subscription] = this.subscriptionChannelFromEnvelope(envelope); + + const event: Subscription.Signal = { + channel, + subscription, + timetoken: envelope.p.t, + publisher: envelope.i, + message: envelope.d, + }; + + if (envelope.u) event.userMetadata = envelope.u; + + return event; + } + + private messageActionFromEnvelope(envelope: Envelope): Subscription.MessageAction { + const [channel, subscription] = this.subscriptionChannelFromEnvelope(envelope); + const action = envelope.d as MessageActionData; + + return { + channel, + subscription, + timetoken: envelope.p.t, + publisher: envelope.i, + event: action.event, + data: { + ...action.data, + uuid: envelope.i!, + }, + }; + } + + private appContextFromEnvelope(envelope: Envelope): Subscription.AppContextObject { + const [channel, subscription] = this.subscriptionChannelFromEnvelope(envelope); + const object = envelope.d as AppContextObjectData; + + return { + channel, + subscription, + timetoken: envelope.p.t, + message: object, + }; + } + + private fileFromEnvelope(envelope: Envelope): Subscription.File { + const [channel, subscription] = this.subscriptionChannelFromEnvelope(envelope); + const [file, decryptionError] = this.decryptedData(envelope.d); + let errorMessage = decryptionError; + + // Basic file event payload. + const event: Subscription.File = { + channel, + subscription, + timetoken: envelope.p.t, + publisher: envelope.i, + }; + + if (envelope.u) event.userMetadata = envelope.u; + if (!file) errorMessage ??= `File information payload is missing.`; + else if (typeof file === 'string') errorMessage ??= `Unexpected file information payload data type.`; + else { + event.message = file.message; + if (file.file) { + event.file = { + id: file.file.id, + name: file.file.name, + url: this.parameters.getFileUrl({ id: file.file.id, name: file.file.name, channel }), + }; + } + } + + if (errorMessage) event.error = errorMessage; + + return event; + } + // endregion + + private subscriptionChannelFromEnvelope(envelope: Envelope): [string, string | null] { + return [envelope.c, envelope.b === undefined ? envelope.c : envelope.b]; + } + + /** + * Decrypt provided `data`. + * + * @param [data] - Message or file information which should be decrypted if possible. + * + * @returns Tuple with decrypted data and decryption error (if any). + */ + private decryptedData(data: Payload): [T, string | undefined] { + if (!this.parameters.crypto || typeof data !== 'string') return [data as T, undefined]; + + let payload: Payload | null; + let error: string | undefined; + + try { + const decryptedData = this.parameters.crypto.decrypt(data); + payload = + decryptedData instanceof ArrayBuffer + ? JSON.parse(SubscribeRequest.decoder.decode(decryptedData)) + : decryptedData; + } catch (err) { + payload = null; + error = `Error while decrypting message content: ${(err as Error).message}`; + } + + return [(payload ?? data) as T, error]; + } +} + +/** + * Subscribe request. + */ +export class SubscribeRequest extends BaseSubscribeRequest { + protected get path(): string { + const { + keySet: { subscribeKey }, + channels, + } = this.parameters; + + return `/v2/subscribe/${subscribeKey}/${encodeNames(channels?.sort() ?? [], ',')}/0`; + } + + protected get queryParameters(): Query { + const { channelGroups, filterExpression, heartbeat, state, timetoken, region } = this.parameters; + const query: Query = {}; + + if (channelGroups && channelGroups.length > 0) query['channel-group'] = channelGroups.sort().join(','); + if (filterExpression && filterExpression.length > 0) query['filter-expr'] = filterExpression; + if (heartbeat) query.heartbeat = heartbeat; + if (state && Object.keys(state).length > 0) query['state'] = JSON.stringify(state); + if (timetoken !== undefined && typeof timetoken === 'string') { + if (timetoken.length > 0 && timetoken !== '0') query['tt'] = timetoken; + } else if (timetoken !== undefined && timetoken > 0) query['tt'] = timetoken; + + if (region) query['tr'] = region; + + return query; + } +} diff --git a/src/core/endpoints/subscriptionUtils/handshake.js b/src/core/endpoints/subscriptionUtils/handshake.js deleted file mode 100644 index 68487c68d..000000000 --- a/src/core/endpoints/subscriptionUtils/handshake.js +++ /dev/null @@ -1,45 +0,0 @@ -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -const endpoint = { - getOperation: () => operationConstants.PNHandshakeOperation, - - validateParams: (_, params) => { - if (!params?.channels && !params?.channelGroups) { - return 'channels and channleGroups both should not be empty'; - } - }, - - getURL: ({ config }, params) => { - const { channels = [] } = params; - const stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return `/v2/subscribe/${config.subscribeKey}/${utils.encodeString(stringifiedChannels)}/0`; - }, - - getRequestTimeout: ({ config }) => config.getSubscribeTimeout(), - - isAuthSupported: () => true, - - prepareParams: (_, params) => { - const outParams = {}; - if (params.channelGroups && params.channelGroups.length > 0) { - outParams['channel-group'] = params.channelGroups.join(','); - } - outParams.tt = 0; - if (params.state) { - outParams.state = JSON.stringify(params.state); - } - if (params.filterExpression && params.filterExpression.length > 0) { - outParams['filter-expr'] = params.filterExpression; - } - outParams.ee = ''; - return outParams; - }, - - handleResponse: (_, response) => ({ - region: response.t.r, - timetoken: response.t.t, - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/subscriptionUtils/handshake.ts b/src/core/endpoints/subscriptionUtils/handshake.ts new file mode 100644 index 000000000..cf3b70b87 --- /dev/null +++ b/src/core/endpoints/subscriptionUtils/handshake.ts @@ -0,0 +1,39 @@ +/** + * Handshake subscribe REST API module. + */ + +import RequestOperation from '../../constants/operations'; +import { BaseSubscribeRequest } from '../subscribe'; +import { encodeNames } from '../../utils'; +import { Query } from '../../types/api'; + +/** + * Handshake subscribe request. + * + * Separate subscribe request required by Event Engine. + */ +export class HandshakeSubscribeRequest extends BaseSubscribeRequest { + operation(): RequestOperation { + return RequestOperation.PNHandshakeOperation; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channels = [], + } = this.parameters; + + return `/v2/subscribe/${subscribeKey}/${encodeNames(channels.sort(), ',')}/0`; + } + + protected get queryParameters(): Query { + const { channelGroups, filterExpression, state } = this.parameters; + const query: Query = { tt: 0, ee: '' }; + + if (channelGroups && channelGroups.length > 0) query['channel-group'] = channelGroups.sort().join(','); + if (filterExpression && filterExpression.length > 0) query['filter-expr'] = filterExpression; + if (state && Object.keys(state).length > 0) query['state'] = JSON.stringify(state); + + return query; + } +} diff --git a/src/core/endpoints/subscriptionUtils/receiveMessages.js b/src/core/endpoints/subscriptionUtils/receiveMessages.js deleted file mode 100644 index 6558af81c..000000000 --- a/src/core/endpoints/subscriptionUtils/receiveMessages.js +++ /dev/null @@ -1,77 +0,0 @@ -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -const endpoint = { - getOperation: () => operationConstants.PNReceiveMessagesOperation, - - validateParams: (_, params) => { - if (!params?.channels && !params?.channelGroups) { - return 'channels and channleGroups both should not be empty'; - } - if (!params?.timetoken) { - return 'timetoken can not be empty'; - } - if (!params?.region) { - return 'region can not be empty'; - } - }, - - getURL: ({ config }, params) => { - const { channels = [] } = params; - const stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return `/v2/subscribe/${config.subscribeKey}/${utils.encodeString(stringifiedChannels)}/0`; - }, - - getRequestTimeout: ({ config }) => config.getSubscribeTimeout(), - - isAuthSupported: () => true, - - getAbortSignal: (_, params) => params.abortSignal, - - prepareParams: (_, params) => { - const outParams = {}; - if (params.channelGroups && params.channelGroups.length > 0) { - outParams['channel-group'] = params.channelGroups.join(','); - } - if (params.filterExpression && params.filterExpression.length > 0) { - outParams['filter-expr'] = params.filterExpression; - } - outParams.tt = params.timetoken; - outParams.tr = params.region; - outParams.ee = ''; - return outParams; - }, - - handleResponse: (_, response) => { - const parsedMessages = []; - - response.m.forEach((envelope) => { - const parsedMessage = { - shard: parseInt(envelope.a, 10), - subscriptionMatch: envelope.b, - channel: envelope.c, - messageType: envelope.e, - payload: envelope.d, - flags: envelope.f, - issuingClientId: envelope.i, - subscribeKey: envelope.k, - originationTimetoken: envelope.o, - userMetadata: envelope.u, - publishMetaData: { - timetoken: envelope.p.t, - region: envelope.p.r, - }, - }; - parsedMessages.push(parsedMessage); - }); - return { - messages: parsedMessages, - metadata: { - region: response.t.r, - timetoken: response.t.t, - }, - }; - }, -}; - -export default endpoint; diff --git a/src/core/endpoints/subscriptionUtils/receiveMessages.ts b/src/core/endpoints/subscriptionUtils/receiveMessages.ts new file mode 100644 index 000000000..66286f57b --- /dev/null +++ b/src/core/endpoints/subscriptionUtils/receiveMessages.ts @@ -0,0 +1,48 @@ +/** + * Receive messages subscribe REST API module. + */ + +import RequestOperation from '../../constants/operations'; +import { BaseSubscribeRequest } from '../subscribe'; +import { encodeNames } from '../../utils'; +import { Query } from '../../types/api'; + +/** + * Receive messages subscribe request. + */ +export class ReceiveMessagesSubscribeRequest extends BaseSubscribeRequest { + operation(): RequestOperation { + return RequestOperation.PNReceiveMessagesOperation; + } + + validate(): string | undefined { + const validationResult = super.validate(); + + if (validationResult) return validationResult; + if (!this.parameters.timetoken) return 'timetoken can not be empty'; + if (!this.parameters.region) return 'region can not be empty'; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channels = [], + } = this.parameters; + + return `/v2/subscribe/${subscribeKey}/${encodeNames(channels.sort(), ',')}/0`; + } + + protected get queryParameters(): Query { + const { channelGroups, filterExpression, timetoken, region } = this.parameters; + const query: Query = { ee: '' }; + + if (channelGroups && channelGroups.length > 0) query['channel-group'] = channelGroups.sort().join(','); + if (filterExpression && filterExpression.length > 0) query['filter-expr'] = filterExpression; + if (typeof timetoken === 'string') { + if (timetoken && timetoken.length > 0) query['tt'] = timetoken; + } else if (timetoken && timetoken > 0) query['tt'] = timetoken; + if (region) query['tr'] = region; + + return query; + } +} diff --git a/src/core/endpoints/time.js b/src/core/endpoints/time.js deleted file mode 100644 index f5996c0e4..000000000 --- a/src/core/endpoints/time.js +++ /dev/null @@ -1,32 +0,0 @@ -/* */ -import operationConstants from '../constants/operations'; - -export function getOperation() { - return operationConstants.PNTimeOperation; -} - -export function getURL() { - return '/time/0'; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function prepareParams() { - return {}; -} - -export function isAuthSupported() { - return false; -} - -export function handleResponse(modules, serverResponse) { - return { - timetoken: serverResponse[0], - }; -} - -export function validateParams() { - // pass -} diff --git a/src/core/endpoints/time.ts b/src/core/endpoints/time.ts new file mode 100644 index 000000000..564f6d84a --- /dev/null +++ b/src/core/endpoints/time.ts @@ -0,0 +1,55 @@ +/** + * Time REST API module. + */ + +import { createValidationError, PubNubError } from '../../errors/pubnub-error'; +import { TransportResponse } from '../types/transport-response'; +import { AbstractRequest } from '../components/request'; +import RequestOperation from '../constants/operations'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Service success response. + */ +export type TimeResponse = { + /** + * High-precision time when published data has been received by the PubNub service. + */ + timetoken: string; +}; + +/** + * Service success response. + */ +type ServiceResponse = [string]; +// endregion + +export class TimeRequest extends AbstractRequest { + constructor() { + super(); + } + + operation(): RequestOperation { + return RequestOperation.PNTimeOperation; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return { timetoken: serviceResponse[0] }; + } + + protected get path(): string { + return '/time/0'; + } +} diff --git a/src/core/interfaces/configuration.ts b/src/core/interfaces/configuration.ts new file mode 100644 index 000000000..4003f427b --- /dev/null +++ b/src/core/interfaces/configuration.ts @@ -0,0 +1,789 @@ +/** + * {@link PubNub} client configuration module. + */ + +import { PubNubFileConstructor, PubNubFileInterface } from '../types/file'; +import { RequestRetryPolicy } from '../../event-engine/core/retryPolicy'; +import { CryptoModule } from './crypto-module'; +import { KeySet, Payload } from '../types/api'; +import { PubNubError } from '../../errors/pubnub-error'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- + +// region Defaults +/** + * Whether secured connection should be used by or not. + */ +const USE_SSL = true; + +/** + * Whether PubNub client should catch up subscription after network issues. + */ +const RESTORE = false; + +/** + * Whether network availability change should be announced with `PNNetworkDownCategory` and + * `PNNetworkUpCategory` state or not. + */ +const AUTO_NETWORK_DETECTION = false; + +/** + * Whether messages should be de-duplicated before announcement or not. + */ +const DEDUPE_ON_SUBSCRIBE = false; + +/** + * Maximum cache which should be used for message de-duplication functionality. + */ +const DEDUPE_CACHE_SIZE = 100; + +/** + * Maximum number of file message publish retries. + */ +const FILE_PUBLISH_RETRY_LIMIT = 5; + +/** + * Whether subscription event engine should be used or not. + */ +const ENABLE_EVENT_ENGINE = false; + +/** + * Whether configured user presence state should be maintained by the PubNub client or not. + */ +const MAINTAIN_PRESENCE_STATE = true; + +/** + * Whether PubNub client should try to utilize existing TCP connection for new requests or not. + */ +const KEEP_ALIVE = false; + +/** + * Whether verbose logging should be enabled or not. + */ +const USE_VERBOSE_LOGGING = false; + +/** + * Whether leave events should be suppressed or not. + */ +const SUPPRESS_LEAVE_EVENTS = false; + +/** + * Whether heartbeat request failure should be announced or not. + */ +const ANNOUNCE_HEARTBEAT_FAILURE = true; + +/** + * Whether heartbeat request success should be announced or not. + */ +const ANNOUNCE_HEARTBEAT_SUCCESS = false; + +/** + * Whether PubNub client instance id should be added to the requests or not. + */ +const USE_INSTANCE_ID = false; + +/** + * Whether unique identifier should be added to the request or not. + */ +const USE_REQUEST_ID = true; + +/** + * Transactional requests timeout. + */ +const TRANSACTIONAL_REQUEST_TIMEOUT = 15; + +/** + * Subscription request timeout. + */ +const SUBSCRIBE_REQUEST_TIMEOUT = 310; + +/** + * Default user presence timeout. + */ +const PRESENCE_TIMEOUT = 300; + +/** + * Minimum user presence timeout. + */ +const PRESENCE_TIMEOUT_MINIMUM = 20; +// endregion + +/** + * Base user-provided PubNub client configuration. + */ +export type UserConfiguration = { + /** + * Specifies the `subscribeKey` to be used for subscribing to a channel and message publishing. + */ + subscribeKey: string; + + /** + * Specifies the `subscribe_key` to be used for subscribing to a channel and message publishing. + * + * @deprecated Use the {@link subscribeKey} instead. + */ + subscribe_key?: string; + + /** + * Specifies the `publishKey` to be used for publishing messages to a channel. + */ + publishKey?: string; + + /** + * Specifies the `publish_key` to be used for publishing messages to a channel. + * + * @deprecated Use the {@link publishKey} instead. + */ + publish_key?: string; + + /** + * Specifies the `secretKey` to be used for request signatures computation. + */ + secretKey?: string; + + /** + * Specifies the `secret_key` to be used for request signatures computation. + * + * @deprecated Use the {@link secretKey} instead. + */ + secret_key?: string; + + /** + * Unique PubNub client user identifier. + * + * Unique `userId` to identify the user or the device that connects to PubNub. + * It's a UTF-8 encoded string of up to 64 alphanumeric characters. + * + * If you don't set the `userId`, you won't be able to connect to PubNub. + */ + userId?: string; + + /** + * If Access Manager enabled, this key will be used on all requests. + */ + authKey?: string | null; + + /** + * Log HTTP information. + * + * @default `false` + */ + logVerbosity?: boolean; + + /** + * If set to true, requests will be made over HTTPS. + * + * @default `true` for v4.20.0 onwards, `false` before v4.20.0 + */ + ssl?: boolean; + + /** + * If a custom domain is required, SDK accepts it here. + * + * @default `ps.pndsn.com` + */ + origin?: string | string[]; + + /** + * How long the server will consider the client alive for presence.The value is in seconds. + * + * @default `300` + */ + presenceTimeout?: number; + + /** + * How often the client will announce itself to server.The value is in seconds. + * + * @default `not set` + */ + heartbeatInterval?: number; + + /** + * Transactional requests timeout in milliseconds. + * + * Maximum duration for which PubNub client should wait for transactional request completion. + * + * @default `15` seconds + */ + transactionalRequestTimeout?: number; + + /** + * Subscription requests timeout in milliseconds. + * + * Maximum duration for which PubNub client should wait for subscription request completion. + * + * @default `310` seconds + */ + subscribeRequestTimeout?: number; + + /** + * `true` to allow catch up on the front-end applications. + * + * @default `false` + */ + restore?: boolean; + + /** + * Whether to include the PubNub object instance ID in outgoing requests. + * + * @default `false` + */ + useInstanceId?: boolean; + + /** + * When `true` the SDK doesn't send out the leave requests. + * + * @default `false` + */ + suppressLeaveEvents?: boolean; + + /** + * `PNRequestMessageCountExceededCategory` is thrown when the number of messages into the + * payload is above of `requestMessageCountThreshold`. + * + * @default `100` + */ + requestMessageCountThreshold?: number; + + /** + * This flag announces when the network is down or up using the states `PNNetworkDownCategory` + * and `PNNetworkUpCategory`. + * + * @default `false` + */ + autoNetworkDetection?: boolean; + + /** + * Whether to use the standardized workflows for subscribe and presence. + * + * Note that the `maintainPresenceState` parameter is set to true by default, so make sure to + * disable it if you don't need to maintain presence state. For more information, refer to the + * param description in this table. + * + * + * @default `false` + */ + enableEventEngine?: boolean; + + /** + * Custom reconnection configuration parameters. + * + * `retryConfiguration: policy` is the type of policy to be used. + * + * Available values: + * - `PubNub.LinearRetryPolicy({ delay, maximumRetry })` + * - `PubNub.ExponentialRetryPolicy({ minimumDelay, maximumDelay, maximumRetry })` + * + * For more information, refer to + * {@link /docs/general/setup/connection-management#reconnection-policy|Reconnection Policy}. JavaScript doesn't + * support excluding endpoints. + * + * @default `not set` + */ + retryConfiguration?: RequestRetryPolicy; + + /** + * Whether the `state` set using `setState()` should be maintained for the current `userId`. + * This option works only when `enableEventEngine` is set to `true`. + * + * @default `true` + */ + maintainPresenceState?: boolean; + + /** + * `UUID` to use. You should set a unique `UUID` to identify the user or the device that + * connects to PubNub. + * If you don't set the `UUID`, you won't be able to connect to PubNub. + * + * @deprecated Use {@link userId} instead. + */ + uuid?: string; + + /** + * If set to `true`, SDK will use the same TCP connection for each HTTP request, instead of + * opening a new one for each new request. + * + * @default `false` + */ + keepAlive?: boolean; + + /** + * If the SDK is running as part of another SDK built atop of it, allow a custom `pnsdk` with + * name and version. + */ + sdkName?: string; + + /** + * If the SDK is operated by a partner, allow a custom `pnsdk` item for them. + */ + partnerId?: string; +}; + +/** + * Extended client configuration. + * + * Extended configuration contains unannounced configuration options. + */ +export type ExtendedConfiguration = UserConfiguration & { + /** + * PubNub Account key set. + */ + keySet: KeySet; + + /** + * Real-time updates filtering expression. + */ + filterExpression?: string | null; + + /** + * Whether messages should be de-duplicated on subscribe before announcement or not. + * + * @default `false` + */ + dedupeOnSubscribe: boolean; + + /** + * Maximum size of deduplication manager cache. + */ + maximumCacheSize: number; + + /** + * Whether unique request identifier should be used in request query or not. + * + * @default `false` + */ + useRequestId?: boolean; + + /** + * Whether heartbeat request success should be announced or not. + * + * @default `false` + */ + announceSuccessfulHeartbeats: boolean; + + /** + * Whether heartbeat request failure should be announced or not. + * + * @default `true` + */ + announceFailedHeartbeats: boolean; + + /** + * How many times file message publish attempt should be retried. + * + * @default `5` + */ + fileUploadPublishRetryLimit: number; +}; + +/** + * Platform-specific PubNub client configuration. + * + * Part of configuration which is added by platform-specific PubNub client initialization code. + */ +export type PlatformConfiguration = { + /** + * Track of the SDK family for identifier generator. + */ + sdkFamily: string; + + /** + * The cryptography module used for encryption and decryption of messages and files. Takes the + * {@link cipherKey} and {@link useRandomIVs} parameters as arguments. + * + * For more information, refer to the + * {@link /docs/sdks/javascript/api-reference/configuration#cryptomodule|cryptoModule} section. + * + * @default `not set` + */ + cryptoModule?: CryptoModule; + + /** + * Platform-specific file representation + */ + /* eslint-disable @typescript-eslint/no-explicit-any */ + PubNubFile?: PubNubFileConstructor; + + // region Deprecated parameters + /** + * If passed, will encrypt the payloads. + * + * @deprecated Pass it to `cryptoModule` instead. + */ + cipherKey?: string; + + /** + * When `true` the initialization vector (IV) is random for all requests (not just for file + * upload). + * When `false` the IV is hard-coded for all requests except for file upload. + * + * @default `true` + * + * @deprecated Pass it to `cryptoModule` instead. + */ + useRandomIVs?: boolean; + + /** + * Custom data encryption method. + * + * @deprecated Instead use {@link cryptoModule} for data encryption. + */ + customEncrypt?: (data: string | Payload) => string; + + /** + * Custom data decryption method. + * + * @deprecated Instead use {@link cryptoModule} for data decryption. + */ + customDecrypt?: (data: string) => string; + // endregion +}; + +/** + * User-provided configuration object interface. + * + * Interface contains limited set of settings manipulation and access. + */ +export interface ClientConfiguration { + /** + * Get a PubNub client user identifier. + * + * @returns Current PubNub client user identifier. + */ + getUserId(): string; + + /** + * Change the current PubNub client user identifier. + * + * **Important:** Change won't affect ongoing REST API calls. + * + * @param value - New PubNub client user identifier. + * + * @throws Error empty user identifier has been provided. + */ + setUserId(value: string): void; + + /** + * Change REST API endpoint access authorization key. + * + * @param authKey - New authorization key which should be used with new requests. + */ + setAuthKey(authKey: string | null): void; + + /** + * Real-time updates filtering expression. + * + * @returns Filtering expression. + */ + getFilterExpression(): string | undefined | null; + + /** + * Update real-time updates filtering expression. + * + * @param expression - New expression which should be used or `undefined` to disable filtering. + */ + setFilterExpression(expression: string | null | undefined): void; + + /** + * Change data encryption / decryption key. + * + * @param key - New key which should be used for data encryption / decryption. + */ + setCipherKey(key: string | undefined): void; + + /** + * Get PubNub SDK version. + * + * @returns Current SDK version. + */ + get version(): string; + + /** + * Get PubNub SDK version. + * + * @returns Current SDK version. + */ + getVersion(): string; + + /** + * Add framework's prefix. + * + * @param name - Name of the framework which would want to add own data into `pnsdk` suffix. + * @param suffix - Suffix with information about framework. + */ + _addPnsdkSuffix(name: string, suffix: string | number): void; + + // -------------------------------------------------------- + // ---------------------- Deprecated ---------------------- + // -------------------------------------------------------- + // region Deprecated + + /** + * Get a PubNub client user identifier. + * + * @returns Current PubNub client user identifier. + * + * @deprecated Use the {@link getUserId} or {@link userId} getter instead. + */ + getUUID(): string; + + /** + * Change the current PubNub client user identifier. + * + * **Important:** Change won't affect ongoing REST API calls. + * + * @param value - New PubNub client user identifier. + * + * @returns {Configuration} Reference to the configuration instance for easier chaining. + * + * @throws Error empty user identifier has been provided. + * + * @deprecated Use the {@link setUserId} or {@link userId} setter instead. + */ + setUUID(value: string): void; + // endregion +} + +/** + * Internal PubNub client configuration object interface. + */ +export interface PrivateClientConfiguration + extends ClientConfiguration, + Omit { + /** + * REST API endpoint access authorization key. + * + * It is required to have `authorization key` with required permissions to access REST API + * endpoints when `PAM` enabled for user key set. + */ + getAuthKey(): string | undefined | null; + + /** + * Data encryption / decryption module. + * + * @returns Data processing crypto module (if set). + */ + getCryptoModule(): CryptoModule | undefined; + + /** + * Retrieve user's presence timeout. + * + * @returns User's presence timeout value. + */ + getPresenceTimeout(): number; + + /** + * Change user's presence timeout. + * + * @param timeout - New timeout for user's presence. + */ + setPresenceTimeout(timeout: number): void; + + /** + * Retrieve heartbeat requests interval. + * + * @returns Heartbeat requests interval. + */ + getHeartbeatInterval(): number | undefined; + + /** + * Change heartbeat requests interval. + * + * @param interval - New presence request heartbeat intervals. + */ + setHeartbeatInterval(interval: number): void; + + /** + * Transactional request timeout. + * + * @returns Maximum duration in milliseconds for which PubNub client should wait for + * transactional request completion. + */ + getTransactionTimeout(): number; + + /** + * Subscription requests timeout. + * + * @returns Maximum duration in milliseconds for which PubNub client should wait for + * subscription request completion. + */ + getSubscribeTimeout(): number; + + /** + * PubNub file object constructor. + */ + get PubNubFile(): PubNubFileConstructor | undefined; + + /** + * Get PubNub client instance identifier. + * + * @returns Current PubNub client instance identifier. + */ + get instanceId(): string | undefined; + + /** + * Get SDK family identifier. + * + * @returns Current SDK family identifier. + */ + get sdkFamily(): string; + + /** + * Compose `pnsdk` suffix string. + * + * @param separator - String which will be used to join registered suffixes. + * + * @returns Concatenated `pnsdk` suffix string. + */ + _getPnsdkSuffix(separator: string): string; + + // -------------------------------------------------------- + // ---------------------- Deprecated ---------------------- + // -------------------------------------------------------- + // region Deprecated + + /** + * If passed, will encrypt the payloads. + * + * @deprecated Pass it to `cryptoModule` instead. + */ + getCipherKey(): string | undefined; + + /** + * When `true` the initialization vector (IV) is random for all requests (not just for file + * upload). + * When `false` the IV is hard-coded for all requests except for file upload. + * + * @default `true` + * + * @deprecated Pass it to `cryptoModule` instead. + */ + getUseRandomIVs(): boolean | undefined; + + /** + * Custom data encryption method. + * + * @deprecated Instead use {@link cryptoModule} for data encryption. + */ + getCustomEncrypt(): ((data: string | Payload) => string) | undefined; + + /** + * Custom data decryption method. + * + * @deprecated Instead use {@link cryptoModule} for data decryption. + */ + getCustomDecrypt(): ((data: string) => string) | undefined; + // endregion +} + +/** + * Apply configuration default values. + * + * @param configuration - User-provided configuration. + */ +export const setDefaults = (configuration: UserConfiguration): ExtendedConfiguration => { + // Copy configuration. + const configurationCopy = { ...configuration }; + configurationCopy.logVerbosity ??= USE_VERBOSE_LOGGING; + configurationCopy.ssl ??= USE_SSL; + configurationCopy.transactionalRequestTimeout ??= TRANSACTIONAL_REQUEST_TIMEOUT; + configurationCopy.subscribeRequestTimeout ??= SUBSCRIBE_REQUEST_TIMEOUT; + configurationCopy.restore ??= RESTORE; + configurationCopy.useInstanceId ??= USE_INSTANCE_ID; + configurationCopy.suppressLeaveEvents ??= SUPPRESS_LEAVE_EVENTS; + configurationCopy.requestMessageCountThreshold ??= DEDUPE_CACHE_SIZE; + configurationCopy.autoNetworkDetection ??= AUTO_NETWORK_DETECTION; + configurationCopy.enableEventEngine ??= ENABLE_EVENT_ENGINE; + configurationCopy.maintainPresenceState ??= MAINTAIN_PRESENCE_STATE; + configurationCopy.keepAlive ??= KEEP_ALIVE; + + if (configurationCopy.userId && configurationCopy.uuid) + throw new PubNubError("PubNub client configuration error: use only 'userId'"); + + configurationCopy.userId ??= configurationCopy.uuid; + + if (!configurationCopy.userId) throw new PubNubError("PubNub client configuration error: 'userId' not set"); + else if (configurationCopy.userId?.trim().length === 0) + throw new PubNubError("PubNub client configuration error: 'userId' is empty"); + + // Generate default origin subdomains. + if (!configurationCopy.origin) + configurationCopy.origin = Array.from({ length: 20 }, (_, i) => `ps${i + 1}.pndsn.com`); + + const keySet: KeySet = { + subscribeKey: configurationCopy.subscribeKey, + publishKey: configurationCopy.publishKey, + secretKey: configurationCopy.secretKey, + }; + + if (configurationCopy.presenceTimeout !== undefined && configurationCopy.presenceTimeout < PRESENCE_TIMEOUT_MINIMUM) { + configurationCopy.presenceTimeout = PRESENCE_TIMEOUT_MINIMUM; + // eslint-disable-next-line no-console + console.log('WARNING: Presence timeout is less than the minimum. Using minimum value: ', PRESENCE_TIMEOUT_MINIMUM); + } + + configurationCopy.presenceTimeout ??= PRESENCE_TIMEOUT; + + // Apply extended configuration defaults. + let announceSuccessfulHeartbeats = ANNOUNCE_HEARTBEAT_SUCCESS; + let announceFailedHeartbeats = ANNOUNCE_HEARTBEAT_FAILURE; + let fileUploadPublishRetryLimit = FILE_PUBLISH_RETRY_LIMIT; + let dedupeOnSubscribe = DEDUPE_ON_SUBSCRIBE; + const maximumCacheSize = DEDUPE_CACHE_SIZE; + let useRequestId = USE_REQUEST_ID; + + // @ts-expect-error Not documented legacy configuration options. + if (configurationCopy.dedupeOnSubscribe !== undefined && typeof configurationCopy.dedupeOnSubscribe === 'boolean') { + // @ts-expect-error Not documented legacy configuration options. + dedupeOnSubscribe = configurationCopy.dedupeOnSubscribe; + } + + // @ts-expect-error Not documented legacy configuration options. + if (configurationCopy.useRequestId !== undefined && typeof configurationCopy.useRequestId === 'boolean') { + // @ts-expect-error Not documented legacy configuration options. + useRequestId = configurationCopy.useRequestId; + } + + if ( + // @ts-expect-error Not documented legacy configuration options. + configurationCopy.announceSuccessfulHeartbeats !== undefined && + // @ts-expect-error Not documented legacy configuration options. + typeof configurationCopy.announceSuccessfulHeartbeats === 'boolean' + ) { + // @ts-expect-error Not documented legacy configuration options. + announceSuccessfulHeartbeats = configurationCopy.announceSuccessfulHeartbeats; + } + + if ( + // @ts-expect-error Not documented legacy configuration options. + configurationCopy.announceFailedHeartbeats !== undefined && + // @ts-expect-error Not documented legacy configuration options. + typeof configurationCopy.announceFailedHeartbeats === 'boolean' + ) { + // @ts-expect-error Not documented legacy configuration options. + announceFailedHeartbeats = configurationCopy.announceFailedHeartbeats; + } + + if ( + // @ts-expect-error Not documented legacy configuration options. + configurationCopy.fileUploadPublishRetryLimit !== undefined && + // @ts-expect-error Not documented legacy configuration options. + typeof configurationCopy.fileUploadPublishRetryLimit === 'number' + ) { + // @ts-expect-error Not documented legacy configuration options. + fileUploadPublishRetryLimit = configurationCopy.fileUploadPublishRetryLimit; + } + + return { + ...configurationCopy, + keySet, + dedupeOnSubscribe, + maximumCacheSize, + useRequestId, + announceSuccessfulHeartbeats, + announceFailedHeartbeats, + fileUploadPublishRetryLimit, + }; +}; diff --git a/src/core/interfaces/crypto-module.ts b/src/core/interfaces/crypto-module.ts new file mode 100644 index 000000000..29e173118 --- /dev/null +++ b/src/core/interfaces/crypto-module.ts @@ -0,0 +1,235 @@ +/** + * Crypto module. + */ + +import { PubNubFileConstructor, PubNubFileInterface } from '../types/file'; +import { Payload } from '../types/api'; + +/** + * Crypto module configuration. + */ +export type CryptoModuleConfiguration = { + default: C; + cryptors?: C[]; +}; + +export type CryptorConfiguration = { + /** + * Data encryption / decryption key. + */ + cipherKey?: string; + + /** + * Request sign secret key. + */ + secretKey?: string; + + /** + * Whether random initialization vector should be used or not. + * + * @default `true` + */ + useRandomIVs?: boolean; + + /** + * Custom data encryption method. + * + * @deprecated Instead use {@link cryptoModule} for data encryption. + */ + customEncrypt?: (data: string | Payload) => string; + + /** + * Custom data decryption method. + * + * @deprecated Instead use {@link cryptoModule} for data decryption. + */ + customDecrypt?: (data: string) => string; +}; + +/** + * Base crypto module interface. + */ +export interface CryptoModule { + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + // region Encryption + + /** + * Encrypt data. + * + * @param data - Data which should be encrypted using `CryptoModule`. + * + * @returns Data encryption result. + */ + encrypt(data: ArrayBuffer | string): ArrayBuffer | string; + + /** + * Encrypt file object. + * + * @param file - File object with data for encryption. + * @param File - File object constructor to create instance for encrypted data representation. + * + * @returns Asynchronous file encryption result. + */ + encryptFile( + file: PubNubFileInterface, + /* eslint-disable @typescript-eslint/no-explicit-any */ + File: PubNubFileConstructor, + ): Promise; + // endregion + + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + // region Decryption + + /** + * Encrypt data. + * + * @param data - Dta which should be encrypted using `CryptoModule`. + * + * @returns Data decryption result. + */ + decrypt(data: ArrayBuffer | string): ArrayBuffer | Payload | null; + + /** + * Decrypt file object. + * + * @param file - Encrypted file object with data for decryption. + * @param File - File object constructor to create instance for decrypted data representation. + * + * @returns Asynchronous file decryption result. + */ + decryptFile( + file: PubNubFileInterface, + /* eslint-disable @typescript-eslint/no-explicit-any */ + File: PubNubFileConstructor, + ): Promise; + // endregion +} + +export abstract class AbstractCryptoModule implements CryptoModule { + /** + * `String` to {@link ArrayBuffer} response decoder. + */ + protected static encoder = new TextEncoder(); + + /** + * {@link ArrayBuffer} to {@link string} decoder. + */ + protected static decoder = new TextDecoder(); + + defaultCryptor: C; + cryptors: C[]; + + // -------------------------------------------------------- + // --------------- Convenience functions ------------------ + // -------------------------------------------------------- + // region Convenience functions + + /** + * Construct crypto module with legacy cryptor for encryption and both legacy and AES-CBC + * cryptors for decryption. + * + * @param config Cryptors configuration options. + * + * @returns Crypto module which encrypts data using legacy cryptor. + * + * @throws Error if `config.cipherKey` not set. + */ + static legacyCryptoModule(config: CryptorConfiguration): CryptoModule { + throw new Error('Should be implemented by concrete crypto module implementation.'); + } + + /** + * Construct crypto module with AES-CBC cryptor for encryption and both AES-CBC and legacy + * cryptors for decryption. + * + * @param config Cryptors configuration options. + * + * @returns Crypto module which encrypts data using AES-CBC cryptor. + * + * @throws Error if `config.cipherKey` not set. + */ + static aesCbcCryptoModule(config: CryptorConfiguration): CryptoModule { + throw new Error('Should be implemented by concrete crypto module implementation.'); + } + // endregion + + constructor(configuration: CryptoModuleConfiguration) { + this.defaultCryptor = configuration.default; + this.cryptors = configuration.cryptors ?? []; + } + + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + // region Encryption + + /** + * Encrypt data. + * + * @param data - Data which should be encrypted using {@link CryptoModule}. + * + * @returns Data encryption result. + */ + abstract encrypt(data: ArrayBuffer | string): ArrayBuffer | string; + + /** + * Encrypt file object. + * + * @param file - File object with data for encryption. + * @param File - File object constructor to create instance for encrypted data representation. + * + * @returns Asynchronous file encryption result. + */ + abstract encryptFile( + file: PubNubFileInterface, + /* eslint-disable @typescript-eslint/no-explicit-any */ + File: PubNubFileConstructor, + ): Promise; + // endregion + + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + // region Decryption + + /** + * Encrypt data. + * + * @param data - Dta which should be encrypted using `CryptoModule`. + * + * @returns Data decryption result. + */ + abstract decrypt(data: ArrayBuffer | string): ArrayBuffer | Payload | null; + + /** + * Decrypt file object. + * + * @param file - Encrypted file object with data for decryption. + * @param File - File object constructor to create instance for decrypted data representation. + * + * @returns Asynchronous file decryption result. + */ + abstract decryptFile( + file: PubNubFileInterface, + /* eslint-disable @typescript-eslint/no-explicit-any */ + File: PubNubFileConstructor, + ): Promise; + // endregion + + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + // region Helpers + + /** + * Retrieve list of module's cryptors. + */ + protected getAllCryptors() { + return [this.defaultCryptor, ...this.cryptors]; + } + // endregion +} diff --git a/src/core/interfaces/cryptography.ts b/src/core/interfaces/cryptography.ts new file mode 100644 index 000000000..5e859c656 --- /dev/null +++ b/src/core/interfaces/cryptography.ts @@ -0,0 +1,70 @@ +/** + * Legacy Cryptography module interface. + */ + +import { PubNubFileConstructor, PubNubFileInterface } from '../types/file'; + +export interface Cryptography { + // region Encryption + /** + * Encrypt provided source data using specific encryption {@link key}. + * + * @param key - Data encryption key.
**Note:** Same key should be used to `decrypt` data. + * @param input - Source data for encryption. + * + * @returns Encrypted data as object or stream (depending on from source data type). + * + * @throws Error if unknown data type has been passed. + */ + encrypt(key: string, input: Types): Promise; + + /** + * Decrypt provided encrypted data using specific decryption {@link key}. + * + * @param key - Data decryption key.
**Note:** Should be the same as used to `encrypt` data. + * @param input - Encrypted data for decryption. + * + * @returns Decrypted data as object or stream (depending on from encrypted data type). + * + * @throws Error if unknown data type has been passed. + */ + decrypt(key: string, input: Types): Promise; + + /** + * Encrypt provided `PubNub` File object using specific encryption {@link key}. + * + * @param key - Key for `PubNub` File object encryption.
**Note:** Same key should be + * used to `decrypt` data. + * @param file - Source `PubNub` File object for encryption. + * @param File - Class constructor for `PubNub` File object. + * + * @returns Encrypted data as `PubNub` File object. + * + * @throws Error if file is empty or contains unsupported data type. + */ + encryptFile( + key: string, + file: PubNubFileInterface, + /* eslint-disable @typescript-eslint/no-explicit-any */ + File: PubNubFileConstructor, + ): Promise; + + /** + * Decrypt provided `PubNub` File object using specific decryption {@link key}. + * + * @param key - Key for `PubNub` File object decryption.
**Note:** Should be the same + * as used to `encrypt` data. + * @param file - Encrypted `PubNub` File object for decryption. + * @param File - Class constructor for `PubNub` File object. + * + * @returns Decrypted data as `PubNub` File object. + * + * @throws Error if file is empty or contains unsupported data type. + */ + decryptFile( + key: string, + file: PubNubFileInterface, + /* eslint-disable @typescript-eslint/no-explicit-any */ + File: PubNubFileConstructor, + ): Promise; +} diff --git a/src/core/interfaces/request.ts b/src/core/interfaces/request.ts new file mode 100644 index 000000000..77168006f --- /dev/null +++ b/src/core/interfaces/request.ts @@ -0,0 +1,38 @@ +import { TransportResponse } from '../types/transport-response'; +import { TransportRequest } from '../types/transport-request'; +import RequestOperation from '../constants/operations'; + +/** + * General REST API call request interface. + */ +export interface Request { + /** + * Type of request operation. + * + * PubNub REST API endpoint which will be called with request. + */ + operation(): RequestOperation; + + /** + * Validate provided request parameters. + * + * @returns Error message if request can't be sent without missing or malformed parameters. + */ + validate(): string | undefined; + + /** + * Compile all parameters into transparent data type. + * + * @returns Transport request which can be processed by the network layer. + */ + request(): TransportRequest; + + /** + * Process service response. + * + * @param [response] Successful request response from the service. + * + * @returns Service response mapped to the expected data type or `undefined` in case of error. + */ + parse(response: TransportResponse): Promise; +} diff --git a/src/core/interfaces/transport.ts b/src/core/interfaces/transport.ts new file mode 100644 index 000000000..701053900 --- /dev/null +++ b/src/core/interfaces/transport.ts @@ -0,0 +1,67 @@ +import { CancellationController, TransportRequest } from '../types/transport-request'; +import { TransportResponse } from '../types/transport-response'; + +/** + * Represents the configuration options for keeping the transport connection alive. + */ +export type TransportKeepAlive = { + /** + * The time interval in milliseconds for keeping the connection alive. + * + * @default 1000 + */ + keepAliveMsecs?: number; + + /** + * The maximum number of sockets allowed per host. + * + * @default Infinity + */ + maxSockets?: number; + + /** + * The maximum number of open and free sockets in the pool per host. + * + * @default 256 + */ + maxFreeSockets?: number; + + /** + * Timeout in milliseconds, after which the `idle` socket will be closed. + * + * @default 30000 + */ + timeout?: number; +}; + +/** + * This interface is used to send requests to the PubNub API. + * + * You can implement this interface for your types, or use one of the provided modules to use a + * transport library. + * + * @interface + */ +export interface Transport { + /** + * Make request sendable. + * + * @param req - The transport request to be processed. + * + * @returns - A promise that resolves to a transport response and request cancellation + * controller (if required). + */ + makeSendable(req: TransportRequest): [Promise, CancellationController | undefined]; + + /** + * Pre-processed request. + * + * Transport implementation may pre-process original transport requests before making + * platform-specific request objects from it. + * + * @param req - Transport request provided by the PubNub client. + * + * @returns Transport request with updated properties (if it was required). + */ + request(req: TransportRequest): TransportRequest; +} diff --git a/src/core/pubnub-channel-groups.ts b/src/core/pubnub-channel-groups.ts new file mode 100644 index 000000000..ea50e1ea1 --- /dev/null +++ b/src/core/pubnub-channel-groups.ts @@ -0,0 +1,222 @@ +/** + * PubNub Channel Groups API module. + */ + +import { RemoveChannelGroupChannelsRequest } from './endpoints/channel_groups/remove_channels'; +import { KeySet, ResultCallback, SendRequestFunction, StatusCallback } from './types/api'; +import { AddChannelGroupChannelsRequest } from './endpoints/channel_groups/add_channels'; +import { ListChannelGroupChannels } from './endpoints/channel_groups/list_channels'; +import { DeleteChannelGroupRequest } from './endpoints/channel_groups/delete_group'; +import { ListChannelGroupsRequest } from './endpoints/channel_groups/list_groups'; +import * as ChannelGroups from './types/api/channel-groups'; + +export default class PubnubChannelGroups { + constructor( + private readonly keySet: KeySet, + /* eslint-disable @typescript-eslint/no-explicit-any */ + private readonly sendRequest: SendRequestFunction, + ) {} + + // -------------------------------------------------------- + // ---------------------- Audit API ----------------------- + // -------------------------------------------------------- + // region Audit API + + /** + * Fetch channel group channels. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public listChannels( + parameters: ChannelGroups.ListChannelGroupChannelsParameters, + callback: ResultCallback, + ): void; + + /** + * Fetch channel group channels. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous get channel group channels response. + */ + public async listChannels( + parameters: ChannelGroups.ListChannelGroupChannelsParameters, + ): Promise; + + /** + * Fetch channel group channels. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get channel group channels response or `void` in case if `callback` + * provided. + */ + public async listChannels( + parameters: ChannelGroups.ListChannelGroupChannelsParameters, + callback?: ResultCallback, + ): Promise { + const request = new ListChannelGroupChannels({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + + // region Deprecated + /** + * Fetch all channel groups. + * + * @param callback - Request completion handler callback. + * + * @deprecated + */ + public listGroups(callback: ResultCallback): void; + + /** + * Fetch all channel groups. + * + * @returns Asynchronous get all channel groups response. + * + * @deprecated + */ + public async listGroups(): Promise; + + /** + * Fetch all channel groups. + * + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all channel groups response or `void` in case if `callback` provided. + * + * @deprecated + */ + public async listGroups( + callback?: ResultCallback, + ): Promise { + const request = new ListChannelGroupsRequest({ keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + // endregion + + // -------------------------------------------------------- + // ---------------------- Manage API ---------------------- + // -------------------------------------------------------- + // region Manage API + + /** + * Add channels to the channel group. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public addChannels(parameters: ChannelGroups.ManageChannelGroupChannelsParameters, callback: StatusCallback): void; + + /** + * Add channels to the channel group. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous add channels to the channel group response. + */ + public async addChannels( + parameters: ChannelGroups.ManageChannelGroupChannelsParameters, + ): Promise>; + + /** + * Add channels to the channel group. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous add channels to the channel group response or `void` in case if + * `callback` provided. + */ + public async addChannels( + parameters: ChannelGroups.ManageChannelGroupChannelsParameters, + callback?: StatusCallback, + ): Promise | void> { + const request = new AddChannelGroupChannelsRequest({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + + /** + * Remove channels from the channel group. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public removeChannels(parameters: ChannelGroups.ManageChannelGroupChannelsParameters, callback: StatusCallback): void; + + /** + * Remove channels from the channel group. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous remove channels from the channel group response. + */ + public async removeChannels( + parameters: ChannelGroups.ManageChannelGroupChannelsParameters, + ): Promise>; + + /** + * Remove channels from the channel group. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous remove channels from the channel group response or `void` in + * case if `callback` provided. + */ + public async removeChannels( + parameters: ChannelGroups.ManageChannelGroupChannelsParameters, + callback?: StatusCallback, + ): Promise | void> { + const request = new RemoveChannelGroupChannelsRequest({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + + /** + * Remove channel group. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public deleteGroup(parameters: ChannelGroups.DeleteChannelGroupParameters, callback: StatusCallback): void; + + /** + * Remove channel group. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous remove channel group response. + */ + public async deleteGroup(parameters: ChannelGroups.DeleteChannelGroupParameters): Promise>; + + /** + * Remove channel group. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous remove channel group response or `void` in case if `callback` provided. + */ + public async deleteGroup( + parameters: ChannelGroups.DeleteChannelGroupParameters, + callback?: StatusCallback, + ): Promise | void> { + const request = new DeleteChannelGroupRequest({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + + // endregion +} diff --git a/src/core/pubnub-common.js b/src/core/pubnub-common.js deleted file mode 100644 index 3aa12932e..000000000 --- a/src/core/pubnub-common.js +++ /dev/null @@ -1,847 +0,0 @@ -import Config from './components/config'; -import Crypto from './components/cryptography/index'; -import { encode } from './components/base64_codec'; -import SubscriptionManager from './components/subscription_manager'; -import TelemetryManager from './components/telemetry_manager'; -import NotificationsPayload from './components/push_payload'; -import ListenerManager from './components/listener_manager'; -import TokenManager from './components/token_manager'; - -import endpointCreator from './components/endpoint'; - -import * as addChannelsChannelGroupConfig from './endpoints/channel_groups/add_channels'; -import * as removeChannelsChannelGroupConfig from './endpoints/channel_groups/remove_channels'; -import * as deleteChannelGroupConfig from './endpoints/channel_groups/delete_group'; -import * as listChannelGroupsConfig from './endpoints/channel_groups/list_groups'; -import * as listChannelsInChannelGroupConfig from './endpoints/channel_groups/list_channels'; - -import * as addPushChannelsConfig from './endpoints/push/add_push_channels'; -import * as removePushChannelsConfig from './endpoints/push/remove_push_channels'; -import * as listPushChannelsConfig from './endpoints/push/list_push_channels'; -import * as removeDevicePushConfig from './endpoints/push/remove_device'; - -import * as presenceLeaveEndpointConfig from './endpoints/presence/leave'; -import * as presenceWhereNowEndpointConfig from './endpoints/presence/where_now'; -import * as presenceHeartbeatEndpointConfig from './endpoints/presence/heartbeat'; -import * as presenceGetStateConfig from './endpoints/presence/get_state'; -import * as presenceSetStateConfig from './endpoints/presence/set_state'; -import * as presenceHereNowConfig from './endpoints/presence/here_now'; - -// Actions API - -import * as addMessageActionEndpointConfig from './endpoints/actions/add_message_action'; -import * as removeMessageActionEndpointConfig from './endpoints/actions/remove_message_action'; -import * as getMessageActionEndpointConfig from './endpoints/actions/get_message_actions'; - -// File Upload API v1 - -import listFilesEndpointConfig from './endpoints/file_upload/list_files'; -import generateUploadUrlEndpointConfig from './endpoints/file_upload/generate_upload_url'; -import publishFileEndpointConfig from './endpoints/file_upload/publish_file'; -import sendFileFunction from './endpoints/file_upload/send_file'; -import getFileUrlFunction from './endpoints/file_upload/get_file_url'; -import downloadFileEndpointConfig from './endpoints/file_upload/download_file'; -import deleteFileEndpointConfig from './endpoints/file_upload/delete_file'; - -// Object API v2 -import getAllUUIDMetadataEndpointConfig from './endpoints/objects/uuid/get_all'; - -import getUUIDMetadataEndpointConfig from './endpoints/objects/uuid/get'; - -import setUUIDMetadataEndpointConfig from './endpoints/objects/uuid/set'; - -import removeUUIDMetadataEndpointConfig from './endpoints/objects/uuid/remove'; - -import getAllChannelMetadataEndpointConfig from './endpoints/objects/channel/get_all'; - -import getChannelMetadataEndpointConfig from './endpoints/objects/channel/get'; - -import setChannelMetadataEndpointConfig from './endpoints/objects/channel/set'; - -import removeChannelMetadataEndpointConfig from './endpoints/objects/channel/remove'; - -import getMembersV2EndpointConfig from './endpoints/objects/member/get'; - -import setMembersV2EndpointConfig from './endpoints/objects/member/set'; - -import getMembershipsV2EndpointConfig from './endpoints/objects/membership/get'; - -import setMembershipsV2EndpointConfig from './endpoints/objects/membership/set'; - -import * as auditEndpointConfig from './endpoints/access_manager/audit'; -import * as grantEndpointConfig from './endpoints/access_manager/grant'; -import * as grantTokenEndpointConfig from './endpoints/access_manager/grant_token'; -import revokeTokenEndpointConfig from './endpoints/access_manager/revoke_token'; - -import * as publishEndpointConfig from './endpoints/publish'; -import * as signalEndpointConfig from './endpoints/signal'; -import * as historyEndpointConfig from './endpoints/history/get_history'; -import * as deleteMessagesEndpointConfig from './endpoints/history/delete_messages'; -import * as messageCountsEndpointConfig from './endpoints/history/message_counts'; -import * as fetchMessagesEndpointConfig from './endpoints/fetch_messages'; -import * as timeEndpointConfig from './endpoints/time'; -import * as subscribeEndpointConfig from './endpoints/subscribe'; - -// subscription utilities -import handshakeEndpointConfig from './endpoints/subscriptionUtils/handshake'; -import receiveMessagesConfig from './endpoints/subscriptionUtils/receiveMessages'; - -import OPERATIONS from './constants/operations'; -import CATEGORIES from './constants/categories'; - -import uuidGenerator from './components/uuid'; -import { EventEngine } from '../event-engine'; -import { PresenceEventEngine } from '../event-engine/presence/presence'; -import { RetryPolicy } from '../event-engine/core/retryPolicy'; -import EventEmitter from './components/eventEmitter'; - -import { Channel } from '../entities/Channel'; -import { ChannelGroup } from '../entities/ChannelGroup'; -import { ChannelMetadata } from '../entities/ChannelMetadata'; -import { UserMetadata } from '../entities/UserMetadata'; -import { SubscriptionSet } from '../entities/SubscriptionSet'; - -export default class { - _config; - - _telemetryManager; - - _listenerManager; - - _tokenManager; - - // tell flow about the mounted endpoint - time; - - publish; - - fire; - - history; - - deleteMessages; - - messageCounts; - - fetchMessages; - - // - channelGroups; - - // - push; - - // - hereNow; - - whereNow; - - getState; - - setState; - // presence utility methods - iAmHere; - iAmAway; - setPresenceState; - - // subscription utility methods - handshake; - receiveMessages; - - // - grant; - - grantToken; - - audit; - - revokeToken; - - // - subscribe; - - signal; - - presence; - - unsubscribe; - - unsubscribeAll; - - // Actions API - addMessageAction; - - removeMessageAction; - - getMessageActions; - - // File Upload API v1 - - File; - - encryptFile; - - decryptFile; - - listFiles; - - sendFile; - - downloadFile; - - getFileUrl; - - deleteFile; - - publishFile; - - // Objects API v2 - - objects; - - // User - createUser; - - updateUser; - - fetchUser; - - removeUser; - - fetchUsers; - - // Space - createSpace; - - updateSpace; - - fetchSpace; - - removeSpace; - - fetchSpaces; - - // Membership - addMemberships; - - updateMemberships; - - fetchMemberships; - - removeMemberships; - - disconnect; - - reconnect; - - destroy; - - stop; - - getSubscribedChannels; - - getSubscribedChannelGroups; - - addListener; - - removeListener; - - removeAllListeners; - - parseToken; - - setToken; - - getToken; - - getAuthKey; - - setAuthKey; - - setCipherKey; - - setUUID; - - getUUID; - - setUserId; - - getUserId; - - getFilterExpression; - - setFilterExpression; - - setHeartbeatInterval; - - setProxy; - - encrypt; - - decrypt; - - _eventEmitter; - - constructor(setup) { - const { networking, cbor } = setup; - - const config = new Config({ setup }); - this._config = config; - const crypto = new Crypto({ config }); // LEGACY - - const { cryptography } = setup; - - networking.init(config); - - const tokenManager = new TokenManager(config, cbor); - this._tokenManager = tokenManager; - - const telemetryManager = new TelemetryManager({ - maximumSamplesCount: 60000, - }); - - this._telemetryManager = telemetryManager; - const cryptoModule = this._config.cryptoModule; - - const modules = { - config, - networking, - crypto, - cryptography, - tokenManager, - telemetryManager, - PubNubFile: setup.PubNubFile, - cryptoModule: cryptoModule, - }; - - this.File = setup.PubNubFile; - - this.encryptFile = function (key, file) { - if (arguments.length == 1 && typeof key != 'string' && modules.cryptoModule) { - file = key; - return modules.cryptoModule.encryptFile(file, this.File); - } - return cryptography.encryptFile(key, file, this.File); - }; - this.decryptFile = function (key, file) { - if (arguments.length == 1 && typeof key != 'string' && modules.cryptoModule) { - file = key; - return modules.cryptoModule.decryptFile(file, this.File); - } - return cryptography.decryptFile(key, file, this.File); - }; - - const timeEndpoint = endpointCreator.bind(this, modules, timeEndpointConfig); - const leaveEndpoint = endpointCreator.bind(this, modules, presenceLeaveEndpointConfig); - const heartbeatEndpoint = endpointCreator.bind(this, modules, presenceHeartbeatEndpointConfig); - const setStateEndpoint = endpointCreator.bind(this, modules, presenceSetStateConfig); - const subscribeEndpoint = endpointCreator.bind(this, modules, subscribeEndpointConfig); - - // managers - const listenerManager = new ListenerManager(); - this._listenerManager = listenerManager; - - this.iAmHere = endpointCreator.bind(this, modules, presenceHeartbeatEndpointConfig); - this.iAmAway = endpointCreator.bind(this, modules, presenceLeaveEndpointConfig); - this.setPresenceState = endpointCreator.bind(this, modules, presenceSetStateConfig); - this.handshake = endpointCreator.bind(this, modules, handshakeEndpointConfig); - this.receiveMessages = endpointCreator.bind(this, modules, receiveMessagesConfig); - - this._eventEmitter = new EventEmitter({ - modules: modules, - listenerManager: this._listenerManager, - getFileUrl: (params) => getFileUrlFunction(modules, params), - }); - if (config.enableEventEngine === true) { - if (config.maintainPresenceState) { - this.presenceState = {}; - this.setState = (args) => { - args.channels?.forEach((channel) => (this.presenceState[channel] = args.state)); - args.channelGroups?.forEach((group) => (this.presenceState[group] = args.state)); - return this.setPresenceState({ - channels: args.channels, - channelGroups: args.channelGroups, - state: this.presenceState, - }); - }; - } - - if (config.getHeartbeatInterval()) { - const presenceEventEngine = new PresenceEventEngine({ - heartbeat: this.iAmHere, - leave: this.iAmAway, - heartbeatDelay: () => - new Promise((resolve) => setTimeout(resolve, modules.config.getHeartbeatInterval() * 1000)), - retryDelay: (amount) => new Promise((resolve) => setTimeout(resolve, amount)), - config: modules.config, - presenceState: this.presenceState, - emitStatus: (status) => { - listenerManager.announceStatus(status); - }, - }); - this.presenceEventEngine = presenceEventEngine; - this.join = this.presenceEventEngine.join.bind(presenceEventEngine); - this.leave = this.presenceEventEngine.leave.bind(presenceEventEngine); - this.leaveAll = this.presenceEventEngine.leaveAll.bind(presenceEventEngine); - } - const eventEngine = new EventEngine({ - handshake: this.handshake, - receiveMessages: this.receiveMessages, - delay: (amount) => new Promise((resolve) => setTimeout(resolve, amount)), - join: this.join, - leave: this.leave, - leaveAll: this.leaveAll, - presenceState: this.presenceState, - config: modules.config, - emitMessages: (events) => { - for (const event of events) { - this._eventEmitter.emitEvent(event); - } - }, - emitStatus: (status) => { - listenerManager.announceStatus(status); - }, - }); - - this.subscribe = eventEngine.subscribe.bind(eventEngine); - this.unsubscribe = eventEngine.unsubscribe.bind(eventEngine); - this.unsubscribeAll = eventEngine.unsubscribeAll.bind(eventEngine); - this.reconnect = eventEngine.reconnect.bind(eventEngine); - this.disconnect = eventEngine.disconnect.bind(eventEngine); - this.destroy = eventEngine.dispose.bind(eventEngine); - this.getSubscribedChannels = eventEngine.getSubscribedChannels.bind(eventEngine); - this.getSubscribedChannelGroups = eventEngine.getSubscribedChannelGroups.bind(eventEngine); - this.eventEngine = eventEngine; - } else { - const subscriptionManager = new SubscriptionManager({ - timeEndpoint, - leaveEndpoint, - heartbeatEndpoint, - setStateEndpoint, - subscribeEndpoint, - crypto: modules.crypto, - config: modules.config, - listenerManager, - getFileUrl: (params) => getFileUrlFunction(modules, params), - cryptoModule: modules.cryptoModule, - eventEmitter: this._eventEmitter, - }); - - this.subscribe = subscriptionManager.adaptSubscribeChange.bind(subscriptionManager); - this.unsubscribe = subscriptionManager.adaptUnsubscribeChange.bind(subscriptionManager); - this.disconnect = subscriptionManager.disconnect.bind(subscriptionManager); - this.reconnect = subscriptionManager.reconnect.bind(subscriptionManager); - this.unsubscribeAll = subscriptionManager.unsubscribeAll.bind(subscriptionManager); - this.getSubscribedChannels = subscriptionManager.getSubscribedChannels.bind(subscriptionManager); - this.getSubscribedChannelGroups = subscriptionManager.getSubscribedChannelGroups.bind(subscriptionManager); - - this.setState = subscriptionManager.adaptStateChange.bind(subscriptionManager); - this.presence = subscriptionManager.adaptPresenceChange.bind(subscriptionManager); - - this.destroy = (isOffline) => { - subscriptionManager.unsubscribeAll(isOffline); - subscriptionManager.disconnect(); - }; - } - - this.addListener = this._eventEmitter.addListener.bind(this._eventEmitter); - this.removeListener = this._eventEmitter.removeListener.bind(this._eventEmitter); - this.removeAllListeners = this._eventEmitter.removeAllListeners.bind(this._eventEmitter); - - this.parseToken = tokenManager.parseToken.bind(tokenManager); - this.setToken = tokenManager.setToken.bind(tokenManager); - this.getToken = tokenManager.getToken.bind(tokenManager); - - /* channel groups */ - this.channelGroups = { - listGroups: endpointCreator.bind(this, modules, listChannelGroupsConfig), - listChannels: endpointCreator.bind(this, modules, listChannelsInChannelGroupConfig), - addChannels: endpointCreator.bind(this, modules, addChannelsChannelGroupConfig), - removeChannels: endpointCreator.bind(this, modules, removeChannelsChannelGroupConfig), - deleteGroup: endpointCreator.bind(this, modules, deleteChannelGroupConfig), - }; - /* push */ - this.push = { - addChannels: endpointCreator.bind(this, modules, addPushChannelsConfig), - removeChannels: endpointCreator.bind(this, modules, removePushChannelsConfig), - deleteDevice: endpointCreator.bind(this, modules, removeDevicePushConfig), - listChannels: endpointCreator.bind(this, modules, listPushChannelsConfig), - }; - /* presence */ - this.hereNow = endpointCreator.bind(this, modules, presenceHereNowConfig); - this.whereNow = endpointCreator.bind(this, modules, presenceWhereNowEndpointConfig); - this.getState = endpointCreator.bind(this, modules, presenceGetStateConfig); - /* PAM */ - this.grant = endpointCreator.bind(this, modules, grantEndpointConfig); - this.grantToken = endpointCreator.bind(this, modules, grantTokenEndpointConfig); - this.audit = endpointCreator.bind(this, modules, auditEndpointConfig); - this.revokeToken = endpointCreator.bind(this, modules, revokeTokenEndpointConfig); - this.publish = endpointCreator.bind(this, modules, publishEndpointConfig); - - this.fire = (args, callback) => { - args.replicate = false; - args.storeInHistory = false; - return this.publish(args, callback); - }; - - this.signal = endpointCreator.bind(this, modules, signalEndpointConfig); - - this.history = endpointCreator.bind(this, modules, historyEndpointConfig); - this.deleteMessages = endpointCreator.bind(this, modules, deleteMessagesEndpointConfig); - this.messageCounts = endpointCreator.bind(this, modules, messageCountsEndpointConfig); - this.fetchMessages = endpointCreator.bind(this, modules, fetchMessagesEndpointConfig); - - // Actions API - - this.addMessageAction = endpointCreator.bind(this, modules, addMessageActionEndpointConfig); - - this.removeMessageAction = endpointCreator.bind(this, modules, removeMessageActionEndpointConfig); - - this.getMessageActions = endpointCreator.bind(this, modules, getMessageActionEndpointConfig); - - // File Upload API v1 - - this.listFiles = endpointCreator.bind(this, modules, listFilesEndpointConfig); - - const generateUploadUrl = endpointCreator.bind(this, modules, generateUploadUrlEndpointConfig); - this.publishFile = endpointCreator.bind(this, modules, publishFileEndpointConfig); - - this.sendFile = sendFileFunction({ - generateUploadUrl, - publishFile: this.publishFile, - modules, - }); - - this.getFileUrl = (params) => getFileUrlFunction(modules, params); - - this.downloadFile = endpointCreator.bind(this, modules, downloadFileEndpointConfig); - - this.deleteFile = endpointCreator.bind(this, modules, deleteFileEndpointConfig); - - // entities - - this.channel = (name) => new Channel(name, this._eventEmitter, this); - this.channelGroup = (name) => new ChannelGroup(name, this._eventEmitter, this); - this.channelMetadata = (id) => new ChannelMetadata(id, this._eventEmitter, this); - this.userMetadata = (id) => new UserMetadata(id, this._eventEmitter, this); - this.subscriptionSet = (args) => - new SubscriptionSet({ - channels: args.channels, - channelGroups: args.channelGroups, - subscriptionOptions: args.subscriptionOptions, - eventEmitter: this._eventEmitter, - pubnub: this, - }); - - // Objects API v2 - - this.objects = { - getAllUUIDMetadata: endpointCreator.bind(this, modules, getAllUUIDMetadataEndpointConfig), - getUUIDMetadata: endpointCreator.bind(this, modules, getUUIDMetadataEndpointConfig), - setUUIDMetadata: endpointCreator.bind(this, modules, setUUIDMetadataEndpointConfig), - removeUUIDMetadata: endpointCreator.bind(this, modules, removeUUIDMetadataEndpointConfig), - - getAllChannelMetadata: endpointCreator.bind(this, modules, getAllChannelMetadataEndpointConfig), - getChannelMetadata: endpointCreator.bind(this, modules, getChannelMetadataEndpointConfig), - setChannelMetadata: endpointCreator.bind(this, modules, setChannelMetadataEndpointConfig), - removeChannelMetadata: endpointCreator.bind(this, modules, removeChannelMetadataEndpointConfig), - - getChannelMembers: endpointCreator.bind(this, modules, getMembersV2EndpointConfig), - setChannelMembers: (parameters, ...rest) => - endpointCreator.call( - this, - modules, - setMembersV2EndpointConfig, - { - type: 'set', - ...parameters, - }, - ...rest, - ), - removeChannelMembers: (parameters, ...rest) => - endpointCreator.call( - this, - modules, - setMembersV2EndpointConfig, - { - type: 'delete', - ...parameters, - }, - ...rest, - ), - - getMemberships: endpointCreator.bind(this, modules, getMembershipsV2EndpointConfig), - setMemberships: (parameters, ...rest) => - endpointCreator.call( - this, - modules, - setMembershipsV2EndpointConfig, - { - type: 'set', - ...parameters, - }, - ...rest, - ), - removeMemberships: (parameters, ...rest) => - endpointCreator.call( - this, - modules, - setMembershipsV2EndpointConfig, - { - type: 'delete', - ...parameters, - }, - ...rest, - ), - }; - - // User Apis - this.createUser = (args) => - this.objects.setUUIDMetadata({ - uuid: args.userId, - data: args.data, - include: args.include, - }); - - this.updateUser = this.createUser; - - this.removeUser = (args) => - this.objects.removeUUIDMetadata({ - uuid: args?.userId, - }); - - this.fetchUser = (args) => - this.objects.getUUIDMetadata({ - uuid: args?.userId, - include: args?.include, - }); - - this.fetchUsers = this.objects.getAllUUIDMetadata; - - // Space apis - this.createSpace = (args) => - this.objects.setChannelMetadata({ - channel: args.spaceId, - data: args.data, - include: args.include, - }); - - this.updateSpace = this.createSpace; - - this.removeSpace = (args) => - this.objects.removeChannelMetadata({ - channel: args.spaceId, - }); - - this.fetchSpace = (args) => - this.objects.getChannelMetadata({ - channel: args.spaceId, - include: args.include, - }); - - this.fetchSpaces = this.objects.getAllChannelMetadata; - - // Membership apis - this.addMemberships = (parameters) => { - if (typeof parameters.spaceId === 'string') { - return this.objects.setChannelMembers({ - channel: parameters.spaceId, - uuids: parameters.users?.map((user) => { - if (typeof user === 'string') { - return user; - } - return { - id: user.userId, - custom: user.custom, - status: user.status, - }; - }), - limit: 0, - }); - } else { - return this.objects.setMemberships({ - uuid: parameters.userId, - channels: parameters.spaces?.map((space) => { - if (typeof space === 'string') { - return space; - } - return { - id: space.spaceId, - custom: space.custom, - status: space.status, - }; - }), - limit: 0, - }); - } - }; - - this.updateMemberships = this.addMemberships; - - this.removeMemberships = (parameters) => { - if (typeof parameters.spaceId === 'string') { - return this.objects.removeChannelMembers({ - channel: parameters.spaceId, - uuids: parameters.userIds, - limit: 0, - }); - } else { - return this.objects.removeMemberships({ - uuid: parameters.userId, - channels: parameters.spaceIds, - limit: 0, - }); - } - }; - - this.fetchMemberships = (params) => { - if (typeof params.spaceId === 'string') { - return this.objects - .getChannelMembers({ - channel: params.spaceId, - filter: params.filter, - limit: params.limit, - page: params.page, - include: { - customFields: params.include.customFields, - UUIDFields: params.include.userFields, - customUUIDFields: params.include.customUserFields, - statusField: params.include.statusField, - UUIDStatusField: params.include.userStatusField, - UUIDTypeField: params.include.userTypeField, - totalCount: params.include.totalCount, - }, - sort: - params.sort != null - ? Object.fromEntries(Object.entries(params.sort).map(([k, v]) => [k.replace('user', 'uuid'), v])) - : null, - }) - .then((res) => { - res.data = res.data?.map((m) => { - return { - user: m.uuid, - custom: m.custom, - updated: m.updated, - eTag: m.eTag, - }; - }); - return res; - }); - } else { - return this.objects - .getMemberships({ - uuid: params.userId, - filter: params.filter, - limit: params.limit, - page: params.page, - include: { - customFields: params.include.customFields, - channelFields: params.include.spaceFields, - customChannelFields: params.include.customSpaceFields, - statusField: params.include.statusField, - channelStatusField: params.include.spaceStatusField, - channelTypeField: params.include.spaceTypeField, - totalCount: params.include.totalCount, - }, - sort: - params.sort != null - ? Object.fromEntries(Object.entries(params.sort).map(([k, v]) => [k.replace('space', 'channel'), v])) - : null, - }) - .then((res) => { - res.data = res.data?.map((m) => { - return { - space: m.channel, - custom: m.custom, - updated: m.updated, - eTag: m.eTag, - }; - }); - return res; - }); - } - }; - - this.time = timeEndpoint; - - // --- deprecated ------------------ - this.stop = this.destroy; // -------- - // --- deprecated ------------------ - - // mount crypto - this.encrypt = function (data, key) { - if (typeof key === 'undefined' && modules.cryptoModule) { - const encrypted = modules.cryptoModule.encrypt(data); - return typeof encrypted === 'string' ? encrypted : encode(encrypted); - } else { - return crypto.encrypt(data, key); - } - }; - this.decrypt = function (data, key) { - if (typeof key === 'undefined' && cryptoModule) { - const decrypted = modules.cryptoModule.decrypt(data); - return decrypted instanceof ArrayBuffer ? JSON.parse(new TextDecoder().decode(decrypted)) : decrypted; - } else { - return crypto.decrypt(data, key); - } - }; - - /* config */ - this.getAuthKey = modules.config.getAuthKey.bind(modules.config); - this.setAuthKey = modules.config.setAuthKey.bind(modules.config); - this.getUUID = modules.config.getUUID.bind(modules.config); - this.setUUID = modules.config.setUUID.bind(modules.config); - this.getUserId = modules.config.getUserId.bind(modules.config); - this.setUserId = modules.config.setUserId.bind(modules.config); - this.getFilterExpression = modules.config.getFilterExpression.bind(modules.config); - this.setFilterExpression = modules.config.setFilterExpression.bind(modules.config); - this.setCipherKey = (key) => modules.config.setCipherKey(key, setup, modules); - this.setHeartbeatInterval = modules.config.setHeartbeatInterval.bind(modules.config); - - if (networking.hasModule('proxy')) { - this.setProxy = (proxy) => { - modules.config.setProxy(proxy); - this.reconnect(); - }; - } - } - - getVersion() { - return this._config.getVersion(); - } - - _addPnsdkSuffix(name, suffix) { - this._config._addPnsdkSuffix(name, suffix); - } - - // network hooks to indicate network changes - networkDownDetected() { - this._listenerManager.announceNetworkDown(); - - if (this._config.restore) { - this.disconnect(); - } else { - this.destroy(true); - } - } - - networkUpDetected() { - this._listenerManager.announceNetworkUp(); - this.reconnect(); - } - - static notificationPayload(title, body) { - return new NotificationsPayload(title, body); - } - - static generateUUID() { - return uuidGenerator.createUUID(); - } - - static OPERATIONS = OPERATIONS; - - static CATEGORIES = CATEGORIES; - - static LinearRetryPolicy = RetryPolicy.LinearRetryPolicy; - static ExponentialRetryPolicy = RetryPolicy.ExponentialRetryPolicy; -} diff --git a/src/core/pubnub-common.ts b/src/core/pubnub-common.ts new file mode 100644 index 000000000..bfac679c0 --- /dev/null +++ b/src/core/pubnub-common.ts @@ -0,0 +1,3271 @@ +// region Imports +// region Components +import { Listener, ListenerManager } from './components/listener_manager'; +import { SubscriptionManager } from './components/subscription-manager'; +import NotificationsPayload from './components/push_payload'; +import { TokenManager } from './components/token_manager'; +import { AbstractRequest } from './components/request'; +import Crypto from './components/cryptography/index'; +import EventEmitter from './components/eventEmitter'; +import { encode } from './components/base64_codec'; +import uuidGenerator from './components/uuid'; +// endregion + +// region Types +import { Payload, ResultCallback, Status, StatusCallback } from './types/api'; +// endregion + +// region Component Interfaces +import { ClientConfiguration, PrivateClientConfiguration } from './interfaces/configuration'; +import { Cryptography } from './interfaces/cryptography'; +import { Transport } from './interfaces/transport'; +// endregion + +// region Constants +import RequestOperation from './constants/operations'; +import StatusCategory from './constants/categories'; +// endregion + +import { createValidationError, PubNubError } from '../errors/pubnub-error'; +import { PubNubAPIError } from '../errors/pubnub-api-error'; + +// region Event Engine +import { PresenceEventEngine } from '../event-engine/presence/presence'; +import { RetryPolicy } from '../event-engine/core/retryPolicy'; +import { EventEngine } from '../event-engine'; +// endregion +// region Publish & Signal +import * as Publish from './endpoints/publish'; +import * as Signal from './endpoints/signal'; +// endregion +// region Subscription +import { RequestParameters as SubscribeRequestParameters, SubscribeRequest } from './endpoints/subscribe'; +import { ReceiveMessagesSubscribeRequest } from './endpoints/subscriptionUtils/receiveMessages'; +import { HandshakeSubscribeRequest } from './endpoints/subscriptionUtils/handshake'; +import * as Subscription from './types/api/subscription'; +// endregion +// region Presence +import { GetPresenceStateRequest } from './endpoints/presence/get_state'; +import { SetPresenceStateRequest } from './endpoints/presence/set_state'; +import { HeartbeatRequest } from './endpoints/presence/heartbeat'; +import { PresenceLeaveRequest } from './endpoints/presence/leave'; +import { WhereNowRequest } from './endpoints/presence/where_now'; +import { HereNowRequest } from './endpoints/presence/here_now'; +import * as Presence from './types/api/presence'; +// endregion +// region Message Storage +import { DeleteMessageRequest } from './endpoints/history/delete_messages'; +import { MessageCountRequest } from './endpoints/history/message_counts'; +import { GetHistoryRequest } from './endpoints/history/get_history'; +import { FetchMessagesRequest } from './endpoints/fetch_messages'; +import * as History from './types/api/history'; +// endregion +// region Message Actions +import { GetMessageActionsRequest } from './endpoints/actions/get_message_actions'; +import { AddMessageActionRequest } from './endpoints/actions/add_message_action'; +import { RemoveMessageAction } from './endpoints/actions/remove_message_action'; +import * as MessageAction from './types/api/message-action'; +// endregion +// region File sharing +import { PublishFileMessageRequest } from './endpoints/file_upload/publish_file'; +import { GetFileDownloadUrlRequest } from './endpoints/file_upload/get_file_url'; +import { DeleteFileRequest } from './endpoints/file_upload/delete_file'; +import { FilesListRequest } from './endpoints/file_upload/list_files'; +import { SendFileRequest } from './endpoints/file_upload/send_file'; +import * as FileSharing from './types/api/file-sharing'; +import { PubNubFileInterface } from './types/file'; +// endregion +// region PubNub Access Manager +import { RevokeTokenRequest } from './endpoints/access_manager/revoke_token'; +import { GrantTokenRequest } from './endpoints/access_manager/grant_token'; +import { GrantRequest } from './endpoints/access_manager/grant'; +import { AuditRequest } from './endpoints/access_manager/audit'; +import * as PAM from './types/api/access-panager'; +// endregion +// region Entities +import { SubscriptionOptions } from '../entities/commonTypes'; +import { ChannelMetadata } from '../entities/ChannelMetadata'; +import { SubscriptionSet } from '../entities/SubscriptionSet'; +import { ChannelGroup } from '../entities/ChannelGroup'; +import { UserMetadata } from '../entities/UserMetadata'; +import { Channel } from '../entities/Channel'; +// endregion +// region Channel Groups +import PubNubChannelGroups from './pubnub-channel-groups'; +// endregion +// region Push Notifications +import PubNubPushNotifications from './pubnub-push'; +// endregion +// region App Context +import * as AppContext from './types/api/app-context'; +import PubNubObjects from './pubnub-objects'; +// endregion +// region Time +import * as Time from './endpoints/time'; +// endregion +import { encodeString } from './utils'; +import { DownloadFileRequest } from './endpoints/file_upload/download_file'; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +type ClientInstanceConfiguration = { + /** + * Client-provided configuration. + */ + configuration: PrivateClientConfiguration; + + /** + * Transport provider for requests execution. + */ + transport: Transport; + + /** + * REST API endpoints access tokens manager. + */ + tokenManager: TokenManager; + + /** + * Legacy crypto module implementation. + */ + cryptography?: Cryptography; + + /** + * Legacy crypto (legacy data encryption / decryption and request signature support). + */ + crypto?: Crypto; +}; +// endregion + +/** + * Platform-agnostic PubNub client core. + */ +export class PubNubCore< + CryptographyTypes, + FileConstructorParameters, + PlatformFile extends Partial = Record, +> { + /** + * PubNub client configuration. + */ + protected readonly _configuration: PrivateClientConfiguration; + + /** + * Subscription loop manager. + * + * **Note:** Manager created when EventEngine is off. + */ + private readonly subscriptionManager?: SubscriptionManager; + + /** + * Transport for network requests processing. + */ + protected readonly transport: Transport; + + /** + * REST API endpoints access tokens manager. + */ + private readonly tokenManager: TokenManager; + + /** + * Legacy crypto module implementation. + */ + private readonly cryptography?: Cryptography; + + /** + * Legacy crypto (legacy data encryption / decryption and request signature support). + */ + private readonly crypto?: Crypto; + + /** + * Real-time event listeners manager. + */ + protected readonly listenerManager: ListenerManager; + + /** + * User's presence event engine. + */ + private presenceEventEngine?: PresenceEventEngine; + + /** + * Subscription event engine. + */ + private readonly eventEngine?: EventEngine; + + /** + * Client-managed presence information. + */ + private readonly presenceState?: Record; + + /** + * Real-time events emitter. + */ + private readonly eventEmitter: EventEmitter; + + /** + * PubNub App Context REST API entry point. + */ + private readonly _objects: PubNubObjects; + + /** + * PubNub Channel Group REST API entry point. + */ + private readonly _channelGroups: PubNubChannelGroups; + + /** + * PubNub Push Notification REST API entry point. + */ + private readonly _push: PubNubPushNotifications; + + /** + * {@link ArrayBuffer} to {@link string} decoder. + */ + private static decoder = new TextDecoder(); + + // -------------------------------------------------------- + // ----------------------- Static ------------------------- + // -------------------------------------------------------- + + // region Static + /** + * Type of REST API endpoint which reported status. + */ + static OPERATIONS = RequestOperation; + + /** + * API call status category. + */ + static CATEGORIES = StatusCategory; + + /** + * Exponential retry policy constructor. + */ + static ExponentialRetryPolicy = RetryPolicy.ExponentialRetryPolicy; + + /** + * Linear retry policy constructor. + */ + static LinearRetryPolicy = RetryPolicy.LinearRetryPolicy; + + /** + * Construct notification payload which will trigger push notification. + * + * @param title - Title which will be shown on notification. + * @param body - Payload which will be sent as part of notification. + * + * @returns Pre-formatted message payload which will trigger push notification. + */ + static notificationPayload(title: string, body: string) { + return new NotificationsPayload(title, body); + } + + /** + * Generate unique identifier. + * + * @returns Unique identifier. + */ + static generateUUID() { + return uuidGenerator.createUUID(); + } + // endregion + + constructor(configuration: ClientInstanceConfiguration) { + this._configuration = configuration.configuration; + this.cryptography = configuration.cryptography; + this.tokenManager = configuration.tokenManager; + this.transport = configuration.transport; + this.crypto = configuration.crypto; + + // API group entry points initialization. + this._objects = new PubNubObjects(this._configuration, this.sendRequest.bind(this)); + this._channelGroups = new PubNubChannelGroups(this._configuration.keySet, this.sendRequest.bind(this)); + this._push = new PubNubPushNotifications(this._configuration.keySet, this.sendRequest.bind(this)); + + // Prepare for real-time events announcement. + this.listenerManager = new ListenerManager(); + this.eventEmitter = new EventEmitter(this.listenerManager); + + if (this._configuration.enableEventEngine) { + let heartbeatInterval = this._configuration.getHeartbeatInterval(); + this.presenceState = {}; + + if (heartbeatInterval) { + this.presenceEventEngine = new PresenceEventEngine({ + heartbeat: this.heartbeat.bind(this), + leave: (parameters) => this.makeUnsubscribe(parameters, () => {}), + heartbeatDelay: () => + new Promise((resolve, reject) => { + heartbeatInterval = this._configuration.getHeartbeatInterval(); + if (!heartbeatInterval) reject(new PubNubError('Heartbeat interval has been reset.')); + else setTimeout(resolve, heartbeatInterval * 1000); + }), + retryDelay: (amount) => new Promise((resolve) => setTimeout(resolve, amount)), + emitStatus: (status) => this.listenerManager.announceStatus(status), + config: this._configuration, + presenceState: this.presenceState, + }); + } + + this.eventEngine = new EventEngine({ + handshake: this.subscribeHandshake.bind(this), + receiveMessages: this.subscribeReceiveMessages.bind(this), + delay: (amount) => new Promise((resolve) => setTimeout(resolve, amount)), + join: this.join.bind(this), + leave: this.leave.bind(this), + leaveAll: this.leaveAll.bind(this), + presenceState: this.presenceState, + config: this._configuration, + emitMessages: (events) => { + try { + events.forEach((event) => this.eventEmitter.emitEvent(event)); + } catch (e) { + const errorStatus: Status = { + error: true, + category: StatusCategory.PNUnknownCategory, + errorData: e as Error, + statusCode: 0, + }; + this.listenerManager.announceStatus(errorStatus); + } + }, + emitStatus: (status) => this.listenerManager.announceStatus(status), + }); + } else { + this.subscriptionManager = new SubscriptionManager( + this._configuration, + this.listenerManager, + this.eventEmitter, + this.makeSubscribe.bind(this), + this.heartbeat.bind(this), + this.makeUnsubscribe.bind(this), + this.time.bind(this), + ); + } + } + + // -------------------------------------------------------- + // -------------------- Configuration ---------------------- + // -------------------------------------------------------- + // region Configuration + + /** + * PubNub client configuration. + * + * @returns Currently user PubNub client configuration. + */ + public get configuration(): ClientConfiguration { + return this._configuration; + } + + /** + * Current PubNub client configuration. + * + * @returns Currently user PubNub client configuration. + * + * @deprecated Use {@link configuration} getter instead. + */ + public get _config(): ClientConfiguration { + return this.configuration; + } + + /** + * REST API endpoint access authorization key. + * + * It is required to have `authorization key` with required permissions to access REST API + * endpoints when `PAM` enabled for user key set. + */ + get authKey(): string | undefined { + return this._configuration.authKey ?? undefined; + } + + /** + * REST API endpoint access authorization key. + * + * It is required to have `authorization key` with required permissions to access REST API + * endpoints when `PAM` enabled for user key set. + */ + getAuthKey(): string | undefined { + return this.authKey; + } + + /** + * Change REST API endpoint access authorization key. + * + * @param authKey - New authorization key which should be used with new requests. + */ + setAuthKey(authKey: string): void { + this._configuration.setAuthKey(authKey); + } + + /** + * Get a PubNub client user identifier. + * + * @returns Current PubNub client user identifier. + */ + get userId(): string { + return this._configuration.userId!; + } + + /** + * Change the current PubNub client user identifier. + * + * **Important:** Change won't affect ongoing REST API calls. + * + * @param value - New PubNub client user identifier. + * + * @throws Error empty user identifier has been provided. + */ + set userId(value: string) { + if (!value || typeof value !== 'string' || value.trim().length === 0) + throw new Error('Missing or invalid userId parameter. Provide a valid string userId'); + this._configuration.userId = value; + } + + /** + * Get a PubNub client user identifier. + * + * @returns Current PubNub client user identifier. + */ + getUserId(): string { + return this._configuration.userId!; + } + + /** + * Change the current PubNub client user identifier. + * + * **Important:** Change won't affect ongoing REST API calls. + * + * @param value - New PubNub client user identifier. + * + * @throws Error empty user identifier has been provided. + */ + setUserId(value: string): void { + if (!value || typeof value !== 'string' || value.trim().length === 0) + throw new Error('Missing or invalid userId parameter. Provide a valid string userId'); + this._configuration.userId = value; + } + + /** + * Real-time updates filtering expression. + * + * @returns Filtering expression. + */ + get filterExpression(): string | undefined { + return this._configuration.getFilterExpression() ?? undefined; + } + + /** + * Real-time updates filtering expression. + * + * @returns Filtering expression. + */ + getFilterExpression(): string | undefined { + return this.filterExpression; + } + + /** + * Update real-time updates filtering expression. + * + * @param expression - New expression which should be used or `undefined` to disable filtering. + */ + set filterExpression(expression: string | null | undefined) { + this._configuration.setFilterExpression(expression); + } + + /** + * Update real-time updates filtering expression. + * + * @param expression - New expression which should be used or `undefined` to disable filtering. + */ + setFilterExpression(expression: string | null): void { + this.filterExpression = expression; + } + + /** + * Dta encryption / decryption key. + * + * @returns Currently used key for data encryption / decryption. + */ + get cipherKey(): string | undefined { + return this._configuration.getCipherKey(); + } + + /** + * Change data encryption / decryption key. + * + * @param key - New key which should be used for data encryption / decryption. + */ + set cipherKey(key: string | undefined) { + this._configuration.setCipherKey(key); + } + + /** + * Change data encryption / decryption key. + * + * @param key - New key which should be used for data encryption / decryption. + */ + setCipherKey(key: string): void { + this.cipherKey = key; + } + + /** + * Change heartbeat requests interval. + * + * @param interval - New presence request heartbeat intervals. + */ + set heartbeatInterval(interval: number) { + this._configuration.setHeartbeatInterval(interval); + } + + /** + * Change heartbeat requests interval. + * + * @param interval - New presence request heartbeat intervals. + */ + setHeartbeatInterval(interval: number): void { + this.heartbeatInterval = interval; + } + + /** + * Get PubNub SDK version. + * + * @returns Current SDK version. + */ + getVersion(): string { + return this._configuration.getVersion(); + } + + /** + * Add framework's prefix. + * + * @param name - Name of the framework which would want to add own data into `pnsdk` suffix. + * @param suffix - Suffix with information about framework. + */ + _addPnsdkSuffix(name: string, suffix: string | number) { + this._configuration._addPnsdkSuffix(name, suffix); + } + + // -------------------------------------------------------- + // ---------------------- Deprecated ---------------------- + // -------------------------------------------------------- + // region Deprecated + + /** + * Get a PubNub client user identifier. + * + * @returns Current PubNub client user identifier. + * + * @deprecated Use the {@link getUserId} or {@link userId} getter instead. + */ + getUUID(): string { + return this.userId; + } + + /** + * Change the current PubNub client user identifier. + * + * **Important:** Change won't affect ongoing REST API calls. + * + * @param value - New PubNub client user identifier. + * + * @throws Error empty user identifier has been provided. + * + * @deprecated Use the {@link PubNubCore#setUserId} or {@link PubNubCore#userId} setter instead. + */ + setUUID(value: string) { + this.userId = value; + } + + /** + * Custom data encryption method. + * + * @deprecated Instead use {@link cryptoModule} for data encryption. + */ + get customEncrypt(): ((data: string) => string) | undefined { + return this._configuration.getCustomEncrypt(); + } + + /** + * Custom data decryption method. + * + * @deprecated Instead use {@link cryptoModule} for data decryption. + */ + get customDecrypt(): ((data: string) => string) | undefined { + return this._configuration.getCustomDecrypt(); + } + // endregion + // endregion + + // -------------------------------------------------------- + // ---------------------- Entities ------------------------ + // -------------------------------------------------------- + // region Entities + + /** + * Create a `Channel` entity. + * + * Entity can be used for the interaction with the following API: + * - `subscribe` + * + * @param name - Unique channel name. + * @returns `Channel` entity. + */ + public channel(name: string): Channel { + return new Channel(name, this.eventEmitter, this); + } + + /** + * Create a `ChannelGroup` entity. + * + * Entity can be used for the interaction with the following API: + * - `subscribe` + * + * @param name - Unique channel group name. + * @returns `ChannelGroup` entity. + */ + public channelGroup(name: string): ChannelGroup { + return new ChannelGroup(name, this.eventEmitter, this); + } + + /** + * Create a `ChannelMetadata` entity. + * + * Entity can be used for the interaction with the following API: + * - `subscribe` + * + * @param id - Unique channel metadata object identifier. + * @returns `ChannelMetadata` entity. + */ + public channelMetadata(id: string): ChannelMetadata { + return new ChannelMetadata(id, this.eventEmitter, this); + } + + /** + * Create a `UserMetadata` entity. + * + * Entity can be used for the interaction with the following API: + * - `subscribe` + * + * @param id - Unique user metadata object identifier. + * @returns `UserMetadata` entity. + */ + public userMetadata(id: string): UserMetadata { + return new UserMetadata(id, this.eventEmitter, this); + } + + /** + * Create subscriptions set object. + * + * @param parameters - Subscriptions set configuration parameters. + */ + public subscriptionSet(parameters: { + channels?: string[]; + channelGroups?: string[]; + subscriptionOptions?: SubscriptionOptions; + }): SubscriptionSet { + return new SubscriptionSet({ ...parameters, eventEmitter: this.eventEmitter, pubnub: this }); + } + // endregion + + // -------------------------------------------------------- + // ----------------------- Common ------------------------- + // -------------------------------------------------------- + + // region Common + /** + * Schedule request execution. + * + * @param request - REST API request. + * @param callback - Request completion handler callback. + * + * @returns Asynchronous request execution and response parsing result. + */ + private sendRequest( + request: AbstractRequest, + callback: ResultCallback, + ): void; + + /** + * Schedule request execution. + * + * @param request - REST API request. + * + * @returns Asynchronous request execution and response parsing result. + */ + private async sendRequest(request: AbstractRequest): Promise; + + /** + * Schedule request execution. + * + * @param request - REST API request. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous request execution and response parsing result or `void` in case if + * `callback` provided. + * + * @throws PubNubError in case of request processing error. + */ + private async sendRequest( + request: AbstractRequest, + callback?: ResultCallback, + ): Promise { + // Validate user-input. + const validationResult = request.validate(); + if (validationResult) { + if (callback) return callback(createValidationError(validationResult), null); + throw new PubNubError('Validation failed, check status for details', createValidationError(validationResult)); + } + + // Complete request configuration. + const transportRequest = request.request(); + if (transportRequest.formData && transportRequest.formData.length > 0) { + // Set 300 seconds file upload request delay. + transportRequest.timeout = 300; + } else { + if (request.operation() === RequestOperation.PNSubscribeOperation) + transportRequest.timeout = this._configuration.getSubscribeTimeout(); + else transportRequest.timeout = this._configuration.getTransactionTimeout(); + } + + // API request processing status. + const status: Status = { + error: false, + operation: request.operation(), + category: StatusCategory.PNAcknowledgmentCategory, + statusCode: 0, + }; + + const [sendableRequest, cancellationController] = this.transport.makeSendable(transportRequest); + + /** + * **Important:** Because of multiple environments where JS SDK can be used control over + * cancellation had to be inverted to let transport provider solve request cancellation task + * more efficiently. As result, cancellation controller can be retrieved and used only after + * request will be scheduled by transport provider. + */ + request.cancellationController = cancellationController ? cancellationController : null; + + return sendableRequest + .then((response) => { + status.statusCode = response.status; + + // Handle special case when request completed but not fully processed by PubNub service. + if (response.status !== 200 && response.status !== 204) { + const contentType = response.headers['content-type']; + if (contentType || contentType.indexOf('javascript') !== -1 || contentType.indexOf('json') !== -1) { + const json = JSON.parse(PubNubCore.decoder.decode(response.body)) as Payload; + if (typeof json === 'object' && 'error' in json && json.error && typeof json.error === 'object') + status.errorData = json.error; + } + } + + return request.parse(response); + }) + .then((parsed) => { + // Notify callback (if possible). + if (callback) return callback(status, parsed); + + return parsed; + }) + .catch((error: Error) => { + const apiError = !(error instanceof PubNubAPIError) ? PubNubAPIError.create(error) : error; + + // Notify callback (if possible). + if (callback) return callback(apiError.toStatus(request.operation()), null); + + throw apiError.toPubNubError( + request.operation(), + 'REST API request processing error, check status for details', + ); + }); + } + + /** + * Unsubscribe from all channels and groups. + * + * @param [isOffline] - Whether `offline` presence should be notified or not. + */ + public destroy(isOffline?: boolean): void { + if (this.subscriptionManager) { + this.subscriptionManager.unsubscribeAll(isOffline); + this.subscriptionManager.disconnect(); + } else if (this.eventEngine) this.eventEngine.dispose(); + } + + /** + * Unsubscribe from all channels and groups. + * + * @deprecated Use {@link destroy} method instead. + */ + public stop(): void { + this.destroy(); + } + // endregion + + // -------------------------------------------------------- + // ----------------------- Listener ----------------------- + // -------------------------------------------------------- + // region Listener + + /** + * Register real-time events listener. + * + * @param listener - Listener with event callbacks to handle different types of events. + */ + public addListener(listener: Listener): void { + this.listenerManager.addListener(listener); + } + + /** + * Remove real-time event listener. + * + * @param listener - Event listeners which should be removed. + */ + public removeListener(listener: Listener): void { + this.listenerManager.removeListener(listener); + } + + /** + * Clear all real-time event listeners. + */ + public removeAllListeners(): void { + this.listenerManager.removeAllListeners(); + } + + // endregion + + // -------------------------------------------------------- + // ---------------------- Publish API --------------------- + // -------------------------------------------------------- + // region Publish API + + /** + * Publish data to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public publish(parameters: Publish.PublishParameters, callback: ResultCallback): void; + + /** + * Publish data to a specific channel. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous publish data response. + */ + public async publish(parameters: Publish.PublishParameters): Promise; + + /** + * Publish data to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous publish data response or `void` in case if `callback` provided. + */ + async publish( + parameters: Publish.PublishParameters, + callback?: ResultCallback, + ): Promise { + const request = new Publish.PublishRequest({ + ...parameters, + keySet: this._configuration.keySet, + crypto: this._configuration.getCryptoModule(), + }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // -------------------------------------------------------- + // ---------------------- Signal API ---------------------- + // -------------------------------------------------------- + // region Signal API + + /** + * Signal data to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public signal(parameters: Signal.SignalParameters, callback: ResultCallback): void; + + /** + * Signal data to a specific channel. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous signal data response. + */ + public async signal(parameters: Signal.SignalParameters): Promise; + + /** + * Signal data to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous signal data response or `void` in case if `callback` provided. + */ + async signal( + parameters: Signal.SignalParameters, + callback?: ResultCallback, + ): Promise { + const request = new Signal.SignalRequest({ + ...parameters, + keySet: this._configuration.keySet, + }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // -------------------------------------------------------- + // ----------------------- Fire API ---------------------- + // -------------------------------------------------------- + // region Fire API + + /** + * `Fire` a data to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link publish} method instead. + */ + public fire(parameters: Publish.PublishParameters, callback: ResultCallback): void; + + /** + * `Fire` a data to a specific channel. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous signal data response. + * + * @deprecated Use {@link publish} method instead. + */ + public async fire(parameters: Publish.PublishParameters): Promise; + + /** + * `Fire` a data to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous signal data response or `void` in case if `callback` provided. + * + * @deprecated Use {@link publish} method instead. + */ + async fire( + parameters: Publish.PublishParameters, + callback?: ResultCallback, + ): Promise { + callback ??= () => {}; + return this.publish({ ...parameters, replicate: false, storeInHistory: false }, callback); + } + // endregion + + // -------------------------------------------------------- + // -------------------- Subscribe API --------------------- + // -------------------------------------------------------- + // region Subscribe API + + /** + * Get list of channels on which PubNub client currently subscribed. + * + * @returns List of active channels. + */ + public getSubscribedChannels(): string[] { + if (this.subscriptionManager) return this.subscriptionManager.subscribedChannels; + else if (this.eventEngine) return this.eventEngine.getSubscribedChannels(); + + return []; + } + + /** + * Get list of channel groups on which PubNub client currently subscribed. + * + * @returns List of active channel groups. + */ + public getSubscribedChannelGroups(): string[] { + if (this.subscriptionManager) return this.subscriptionManager.subscribedChannelGroups; + else if (this.eventEngine) return this.eventEngine.getSubscribedChannelGroups(); + + return []; + } + + /** + * Subscribe to specified channels and groups real-time events. + * + * @param parameters - Request configuration parameters. + */ + public subscribe(parameters: Subscription.SubscribeParameters): void { + if (this.subscriptionManager) this.subscriptionManager.subscribe(parameters); + else if (this.eventEngine) this.eventEngine.subscribe(parameters); + } + + /** + * Perform subscribe request. + * + * **Note:** Method passed into managers to let them use it when required. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + private makeSubscribe( + parameters: Omit, + callback: ResultCallback, + ): void { + const request = new SubscribeRequest({ + ...parameters, + keySet: this._configuration.keySet, + crypto: this._configuration.getCryptoModule(), + getFileUrl: this.getFileUrl.bind(this), + }); + + this.sendRequest(request, (status, result) => { + if (this.subscriptionManager && this.subscriptionManager.abort?.identifier === request.requestIdentifier) + this.subscriptionManager.abort = null; + + callback(status, result); + }); + + /** + * Allow subscription cancellation. + * + * **Note:** Had to be done after scheduling because transport provider return cancellation + * controller only when schedule new request. + */ + if (this.subscriptionManager) { + // Creating identifiable abort caller. + const callableAbort = () => request.abort(); + callableAbort.identifier = request.requestIdentifier; + + this.subscriptionManager.abort = callableAbort; + } + } + + /** + * Unsubscribe from specified channels and groups real-time events. + * + * @param parameters - Request configuration parameters. + */ + public unsubscribe(parameters: Presence.PresenceLeaveParameters): void { + if (this.subscriptionManager) this.subscriptionManager.unsubscribe(parameters); + else if (this.eventEngine) this.eventEngine.unsubscribe(parameters); + } + + /** + * Perform unsubscribe request. + * + * **Note:** Method passed into managers to let them use it when required. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + private makeUnsubscribe(parameters: Presence.PresenceLeaveParameters, callback: StatusCallback): void { + this.sendRequest( + new PresenceLeaveRequest({ + ...parameters, + keySet: this._configuration.keySet, + }), + callback, + ); + } + + /** + * Unsubscribe from all channels and groups. + */ + public unsubscribeAll() { + if (this.subscriptionManager) this.subscriptionManager.unsubscribeAll(); + else if (this.eventEngine) this.eventEngine.unsubscribeAll(); + } + + /** + * Temporarily disconnect from real-time events stream. + */ + public disconnect(): void { + if (this.subscriptionManager) this.subscriptionManager.disconnect(); + else if (this.eventEngine) this.eventEngine.disconnect(); + } + + /** + * Restore connection to the real-time events stream. + * + * @param parameters - Reconnection catch up configuration. **Note:** available only with + * enabled event engine. + */ + public reconnect(parameters?: { timetoken?: string; region?: number }): void { + if (this.subscriptionManager) this.subscriptionManager.reconnect(); + else if (this.eventEngine) this.eventEngine.reconnect(parameters ?? {}); + } + + /** + * Event engine handshake subscribe. + * + * @param parameters - Request configuration parameters. + */ + private async subscribeHandshake(parameters: Subscription.CancelableSubscribeParameters) { + const request = new HandshakeSubscribeRequest({ + ...parameters, + keySet: this._configuration.keySet, + crypto: this._configuration.getCryptoModule(), + getFileUrl: this.getFileUrl.bind(this), + }); + + const abortUnsubscribe = parameters.abortSignal.subscribe((err) => { + request.abort(); + }); + + /** + * Allow subscription cancellation. + * + * **Note:** Had to be done after scheduling because transport provider return cancellation + * controller only when schedule new request. + */ + const handshakeResponse = this.sendRequest(request); + return handshakeResponse.then((response) => { + abortUnsubscribe(); + return response.cursor; + }); + } + + /** + * Event engine receive messages subscribe. + * + * @param parameters - Request configuration parameters. + */ + private async subscribeReceiveMessages(parameters: Subscription.CancelableSubscribeParameters) { + const request = new ReceiveMessagesSubscribeRequest({ + ...parameters, + keySet: this._configuration.keySet, + crypto: this._configuration.getCryptoModule(), + getFileUrl: this.getFileUrl.bind(this), + }); + + const abortUnsubscribe = parameters.abortSignal.subscribe((err) => { + request.abort(); + }); + + /** + * Allow subscription cancellation. + * + * **Note:** Had to be done after scheduling because transport provider return cancellation + * controller only when schedule new request. + */ + const handshakeResponse = this.sendRequest(request); + return handshakeResponse.then((response) => { + abortUnsubscribe(); + return response; + }); + } + // endregion + + // -------------------------------------------------------- + // ------------------ Message Action API ------------------ + // -------------------------------------------------------- + // region Message Action API + + // region List + /** + * Get reactions to a specific message. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public getMessageActions( + parameters: MessageAction.GetMessageActionsParameters, + callback: ResultCallback, + ): void; + + /** + * Get reactions to a specific message. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous get reactions response. + */ + public async getMessageActions( + parameters: MessageAction.GetMessageActionsParameters, + ): Promise; + + /** + * Get reactions to a specific message. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get reactions response or `void` in case if `callback` provided. + */ + async getMessageActions( + parameters: MessageAction.GetMessageActionsParameters, + callback?: ResultCallback, + ): Promise { + const request = new GetMessageActionsRequest({ ...parameters, keySet: this._configuration.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Add + /** + * Add a reaction to a specific message. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public addMessageAction( + parameters: MessageAction.AddMessageActionParameters, + callback: ResultCallback, + ): void; + + /** + * Add a reaction to a specific message. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous add a reaction response. + */ + public async addMessageAction( + parameters: MessageAction.AddMessageActionParameters, + ): Promise; + + /** + * Add a reaction to a specific message. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous add a reaction response or `void` in case if `callback` provided. + */ + async addMessageAction( + parameters: MessageAction.AddMessageActionParameters, + callback?: ResultCallback, + ): Promise { + const request = new AddMessageActionRequest({ ...parameters, keySet: this._configuration.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Remove + /** + * Remove a reaction from a specific message. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public removeMessageAction( + parameters: MessageAction.RemoveMessageActionParameters, + callback: ResultCallback, + ): void; + + /** + * Remove a reaction from a specific message. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous remove a reaction response. + */ + public async removeMessageAction( + parameters: MessageAction.RemoveMessageActionParameters, + ): Promise; + + /** + * Remove a reaction from a specific message. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous remove a reaction response or `void` in case if `callback` provided. + */ + async removeMessageAction( + parameters: MessageAction.RemoveMessageActionParameters, + callback?: ResultCallback, + ): Promise { + const request = new RemoveMessageAction({ ...parameters, keySet: this._configuration.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + // endregion + + // -------------------------------------------------------- + // --------------- Message Persistence API ---------------- + // -------------------------------------------------------- + // region Message Persistence API + + // region Fetch Messages + /** + * Fetch messages history for channels. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public fetchMessages( + parameters: History.FetchMessagesParameters, + callback: ResultCallback, + ): void; + + /** + * Fetch messages history for channels. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous fetch messages response. + */ + public async fetchMessages(parameters: History.FetchMessagesParameters): Promise; + + /** + * Fetch messages history for channels. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous fetch messages response or `void` in case if `callback` provided. + */ + async fetchMessages( + parameters: History.FetchMessagesParameters, + callback?: ResultCallback, + ): Promise { + const request = new FetchMessagesRequest({ + ...parameters, + keySet: this._configuration.keySet, + crypto: this._configuration.getCryptoModule(), + getFileUrl: this.getFileUrl.bind(this), + }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Delete Messages + /** + * Delete messages from the channel history. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + * + * @deprecated + */ + public deleteMessages( + parameters: History.DeleteMessagesParameters, + callback: ResultCallback, + ): void; + + /** + * Delete messages from the channel history. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous delete messages response. + * + * @deprecated + */ + public async deleteMessages(parameters: History.DeleteMessagesParameters): Promise; + + /** + * Delete messages from the channel history. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous delete messages response or `void` in case if `callback` provided. + * + * @deprecated + */ + async deleteMessages( + parameters: History.DeleteMessagesParameters, + callback?: ResultCallback, + ): Promise { + const request = new DeleteMessageRequest({ ...parameters, keySet: this._configuration.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Count Messages + /** + * Count messages from the channels' history. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public messageCounts( + parameters: History.MessageCountParameters, + callback: ResultCallback, + ): void; + + /** + * Count messages from the channels' history. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous count messages response. + */ + public async messageCounts(parameters: History.MessageCountParameters): Promise; + + /** + * Count messages from the channels' history. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous count messages response or `void` in case if `callback` provided. + */ + async messageCounts( + parameters: History.MessageCountParameters, + callback?: ResultCallback, + ): Promise { + const request = new MessageCountRequest({ ...parameters, keySet: this._configuration.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Deprecated + // region Fetch History + /** + * Fetch single channel history. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + * + * @deprecated + */ + public history(parameters: History.GetHistoryParameters, callback: ResultCallback): void; + + /** + * Fetch single channel history. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous fetch channel history response. + * + * @deprecated + */ + public async history(parameters: History.GetHistoryParameters): Promise; + + /** + * Fetch single channel history. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous fetch channel history response or `void` in case if `callback` provided. + * + * @deprecated + */ + async history( + parameters: History.GetHistoryParameters, + callback?: ResultCallback, + ): Promise { + const request = new GetHistoryRequest({ + ...parameters, + keySet: this._configuration.keySet, + crypto: this._configuration.getCryptoModule(), + }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + // endregion + // endregion + + // -------------------------------------------------------- + // --------------------- Presence API --------------------- + // -------------------------------------------------------- + // region Presence API + + // region Here Now + /** + * Get channel's presence information. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public hereNow(parameters: Presence.HereNowParameters, callback: ResultCallback): void; + + /** + * Get channel presence information. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous get channel's presence response. + */ + public async hereNow(parameters: Presence.HereNowParameters): Promise; + + /** + * Get channel's presence information. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get channel's presence response or `void` in case if `callback` provided. + */ + async hereNow( + parameters: Presence.HereNowParameters, + callback?: ResultCallback, + ): Promise { + const request = new HereNowRequest({ ...parameters, keySet: this._configuration.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Where Now + /** + * Get user's presence information. + * + * Get list of channels to which `uuid` currently subscribed. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public whereNow(parameters: Presence.WhereNowParameters, callback: ResultCallback): void; + + /** + * Get user's presence information. + * + * Get list of channels to which `uuid` currently subscribed. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous get user's presence response. + */ + public async whereNow(parameters: Presence.WhereNowParameters): Promise; + + /** + * Get user's presence information. + * + * Get list of channels to which `uuid` currently subscribed. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get user's presence response or `void` in case if `callback` provided. + */ + async whereNow( + parameters: Presence.WhereNowParameters, + callback?: ResultCallback, + ): Promise { + const request = new WhereNowRequest({ + uuid: parameters.uuid ?? this._configuration.userId!, + keySet: this._configuration.keySet, + }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Get Presence State + /** + * Get associated user's data for channels and groups. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public getState( + parameters: Presence.GetPresenceStateParameters, + callback: ResultCallback, + ): void; + + /** + * Get associated user's data for channels and groups. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous get associated user's data response. + */ + public async getState(parameters: Presence.GetPresenceStateParameters): Promise; + + /** + * Get associated user's data for channels and groups. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get user's data response or `void` in case if `callback` provided. + */ + async getState( + parameters: Presence.GetPresenceStateParameters, + callback?: ResultCallback, + ): Promise { + const request = new GetPresenceStateRequest({ + ...parameters, + uuid: parameters.uuid ?? this._configuration.userId, + keySet: this._configuration.keySet, + }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Set Presence State + /** + * Set associated user's data for channels and groups. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public setState( + parameters: Presence.SetPresenceStateParameters | Presence.SetPresenceStateWithHeartbeatParameters, + callback: ResultCallback, + ): void; + + /** + * Set associated user's data for channels and groups. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous set associated user's data response. + */ + public async setState( + parameters: Presence.SetPresenceStateParameters | Presence.SetPresenceStateWithHeartbeatParameters, + ): Promise; + + /** + * Set associated user's data for channels and groups. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous set user's data response or `void` in case if `callback` provided. + */ + async setState( + parameters: Presence.SetPresenceStateParameters | Presence.SetPresenceStateWithHeartbeatParameters, + callback?: ResultCallback, + ): Promise { + const { keySet, userId: userId } = this._configuration; + const heartbeat = this._configuration.getPresenceTimeout(); + let request: AbstractRequest; + + // Maintain presence information (if required). + if (this._configuration.enableEventEngine && this.presenceState) { + const presenceState = this.presenceState; + parameters.channels?.forEach((channel) => (presenceState[channel] = parameters.state)); + + if ('channelGroups' in parameters) { + parameters.channelGroups?.forEach((group) => (presenceState[group] = parameters.state)); + } + } + + // Check whether state should be set with heartbeat or not. + if ('withHeartbeat' in parameters) { + request = new HeartbeatRequest({ ...parameters, keySet, heartbeat }); + } else { + request = new SetPresenceStateRequest({ ...parameters, keySet, uuid: userId! }); + } + + // Update state used by subscription manager. + if (this.subscriptionManager) this.subscriptionManager.setState(parameters); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Change presence state + /** + * Manual presence management. + * + * @param parameters - Desired presence state for provided list of channels and groups. + */ + public presence(parameters: { connected: boolean; channels?: string[]; channelGroups?: string[] }) { + this.subscriptionManager?.changePresence(parameters); + } + // endregion + + // region Heartbeat + /** + * Announce user presence + * + * @param parameters - Desired presence state for provided list of channels and groups. + * @param callback - Request completion handler callback. + */ + private async heartbeat( + parameters: Presence.PresenceHeartbeatParameters, + callback?: ResultCallback, + ) { + const request = new HeartbeatRequest({ + ...parameters, + keySet: this._configuration.keySet, + }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Join + /** + * Announce user `join` on specified list of channels and groups. + * + * @param parameters - List of channels and groups where `join` event should be sent. + */ + private join(parameters: { channels?: string[]; groups?: string[] }) { + this.presenceEventEngine?.join(parameters); + } + // endregion + + // region Leave + /** + * Announce user `leave` on specified list of channels and groups. + * + * @param parameters - List of channels and groups where `leave` event should be sent. + */ + private leave(parameters: { channels?: string[]; groups?: string[] }) { + this.presenceEventEngine?.leave(parameters); + } + + /** + * Announce user `leave` on all subscribed channels. + */ + private leaveAll() { + this.presenceEventEngine?.leaveAll(); + } + // endregion + // endregion + + // -------------------------------------------------------- + // ------------------------ PAM API ----------------------- + // -------------------------------------------------------- + // region PAM API + + // region Grant + /** + * Grant token permission. + * + * Generate access token with requested permissions. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public grantToken(parameters: PAM.GrantTokenParameters, callback: ResultCallback): void; + + /** + * Grant token permission. + * + * Generate access token with requested permissions. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous grant token response. + */ + public async grantToken(parameters: PAM.GrantTokenParameters): Promise; + + /** + * Grant token permission. + * + * Generate access token with requested permissions. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous grant token response or `void` in case if `callback` provided. + */ + async grantToken( + parameters: PAM.GrantTokenParameters, + callback?: ResultCallback, + ): Promise { + const request = new GrantTokenRequest({ ...parameters, keySet: this._configuration.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Revoke + /** + * Revoke token permission. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public revokeToken(parameters: PAM.RevokeParameters, callback: ResultCallback): void; + + /** + * Revoke token permission. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous revoke token response. + */ + public async revokeToken(parameters: PAM.RevokeParameters): Promise; + + /** + * Revoke token permission. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous revoke token response or `void` in case if `callback` provided. + */ + async revokeToken( + parameters: PAM.RevokeParameters, + callback?: ResultCallback, + ): Promise { + const request = new RevokeTokenRequest({ ...parameters, keySet: this._configuration.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Token Manipulation + /** + * Get current access token. + * + * @returns Previously configured access token using {@link setToken} method. + */ + public get token(): string | undefined { + return this.tokenManager.getToken(); + } + + /** + * Get current access token. + * + * @returns Previously configured access token using {@link setToken} method. + */ + public getToken(): string | undefined { + return this.token; + } + + /** + * Set current access token. + * + * @param token - New access token which should be used with next REST API endpoint calls. + */ + public set token(token: string | undefined) { + this.tokenManager.setToken(token); + } + + /** + * Set current access token. + * + * @param token - New access token which should be used with next REST API endpoint calls. + */ + public setToken(token: string | undefined): void { + this.token = token; + } + + /** + * Parse access token. + * + * Parse token to see what permissions token owner has. + * + * @param token - Token which should be parsed. + * + * @returns Token's permissions information for the resources. + */ + public parseToken(token: string) { + return this.tokenManager.parseToken(token); + } + // endregion + + // region Deprecated + // region Grant Auth Permissions + /** + * Grant auth key(s) permission. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link grantToken} and {@link setToken} methods instead. + */ + public grant(parameters: PAM.GrantParameters, callback: ResultCallback): void; + + /** + * Grant auth key(s) permission. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous grant auth key(s) permissions response. + * + * @deprecated Use {@link grantToken} and {@link setToken} methods instead. + */ + public async grant(parameters: PAM.GrantParameters): Promise; + + /** + * Grant auth key(s) permission. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous grant auth key(s) permissions or `void` in case if `callback` provided. + * + * @deprecated Use {@link grantToken} and {@link setToken} methods instead. + */ + async grant( + parameters: PAM.GrantParameters, + callback?: ResultCallback, + ): Promise { + const request = new GrantRequest({ ...parameters, keySet: this._configuration.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Audit Permissions + /** + * Audit auth key(s) permission. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + * + * @deprecated + */ + public audit(parameters: PAM.AuditParameters, callback: ResultCallback): void; + + /** + * Audit auth key(s) permission. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous audit auth key(s) permissions response. + * + * @deprecated + */ + public async audit(parameters: PAM.AuditParameters): Promise; + + /** + * Audit auth key(s) permission. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @deprecated + * + * @deprecated Use {@link grantToken} and {@link setToken} methods instead. + */ + async audit( + parameters: PAM.AuditParameters, + callback?: ResultCallback, + ): Promise { + const request = new AuditRequest({ ...parameters, keySet: this._configuration.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + // endregion + // endregion + + // -------------------------------------------------------- + // ------------------- App Context API -------------------- + // -------------------------------------------------------- + // region App Context API + + /** + * PubNub App Context API group. + */ + get objects(): PubNubObjects { + return this._objects; + } + + // region Deprecated API + /** + * Fetch a paginated list of User objects. + * + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link PubNubCore#objects.getAllUUIDMetadata} method instead. + */ + public fetchUsers( + callback: ResultCallback>, + ): void; + + /** + * Fetch a paginated list of User objects. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link PubNubCore#objects.getAllUUIDMetadata} method instead. + */ + public fetchUsers( + parameters: AppContext.GetAllMetadataParameters>, + callback: ResultCallback>, + ): void; + + /** + * Fetch a paginated list of User objects. + * + * @param [parameters] - Request configuration parameters. + * + * @returns Asynchronous get all User objects response. + * + * @deprecated Use {@link PubNubCore#objects.getAllUUIDMetadata} method instead. + */ + public async fetchUsers( + parameters?: AppContext.GetAllMetadataParameters>, + ): Promise>; + + /** + Fetch a paginated list of User objects. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all User objects response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.getAllUUIDMetadata} method instead. + */ + public async fetchUsers( + parametersOrCallback?: + | AppContext.GetAllMetadataParameters> + | ResultCallback>, + callback?: ResultCallback>, + ): Promise | void> { + return this.objects._getAllUUIDMetadata(parametersOrCallback, callback); + } + + /** + * Fetch User object for currently configured PubNub client `uuid`. + * + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link PubNubCore#objects.getUUIDMetadata} method instead. + */ + public fetchUser( + callback: ResultCallback>, + ): void; + + /** + * Fetch User object for currently configured PubNub client `uuid`. + * + * @param parameters - Request configuration parameters. Will fetch User object for currently + * configured PubNub client `uuid` if not set. + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link PubNubCore#objects.getUUIDMetadata} method instead. + */ + public fetchUser( + parameters: AppContext.GetUUIDMetadataParameters, + callback: ResultCallback>, + ): void; + + /** + * Fetch User object for currently configured PubNub client `uuid`. + * + * @param [parameters] - Request configuration parameters. Will fetch User object for currently + * configured PubNub client `uuid` if not set. + * + * @returns Asynchronous get User object response. + * + * @deprecated Use {@link PubNubCore#objects.getUUIDMetadata} method instead. + */ + public async fetchUser( + parameters?: AppContext.GetUUIDMetadataParameters, + ): Promise>; + + /** + * Fetch User object for currently configured PubNub client `uuid`. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get User object response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.getUUIDMetadata} method instead. + */ + async fetchUser( + parametersOrCallback?: + | AppContext.GetUUIDMetadataParameters + | ResultCallback>, + callback?: ResultCallback>, + ): Promise | void> { + return this.objects._getUUIDMetadata(parametersOrCallback, callback); + } + + /** + * Create User object. + * + * @param parameters - Request configuration parameters. Will create User object for currently + * configured PubNub client `uuid` if not set. + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link PubNubCore#objects.setUUIDMetadata} method instead. + */ + public createUser( + parameters: AppContext.SetUUIDMetadataParameters, + callback: ResultCallback>, + ): void; + + /** + * Create User object. + * + * @param parameters - Request configuration parameters. Will create User object for currently + * configured PubNub client `uuid` if not set. + * + * @returns Asynchronous create User object response. + * + * @deprecated Use {@link PubNubCore#objects.setUUIDMetadata} method instead. + */ + public async createUser( + parameters: AppContext.SetUUIDMetadataParameters, + ): Promise>; + + /** + * Create User object. + * + * @param parameters - Request configuration parameters. Will create User object for currently + * configured PubNub client `uuid` if not set. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous create User object response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.setUUIDMetadata} method instead. + */ + async createUser( + parameters: AppContext.SetUUIDMetadataParameters, + callback?: ResultCallback>, + ): Promise | void> { + return this.objects._setUUIDMetadata(parameters, callback); + } + + /** + * Update User object. + * + * @param parameters - Request configuration parameters. Will update User object for currently + * configured PubNub client `uuid` if not set. + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link PubNubCore#objects.setUUIDMetadata} method instead. + */ + public updateUser( + parameters: AppContext.SetUUIDMetadataParameters, + callback: ResultCallback>, + ): void; + + /** + * Update User object. + * + * @param parameters - Request configuration parameters. Will update User object for currently + * configured PubNub client `uuid` if not set. + * + * @returns Asynchronous update User object response. + * + * @deprecated Use {@link PubNubCore#objects.setUUIDMetadata} method instead. + */ + public async updateUser( + parameters: AppContext.SetUUIDMetadataParameters, + ): Promise>; + + /** + * Update User object. + * + * @param parameters - Request configuration parameters. Will update User object for currently + * configured PubNub client `uuid` if not set. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous update User object response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.setUUIDMetadata} method instead. + */ + async updateUser( + parameters: AppContext.SetUUIDMetadataParameters, + callback?: ResultCallback>, + ): Promise | void> { + return this.objects._setUUIDMetadata(parameters, callback); + } + + /** + * Remove a specific User object. + * + * @param callback - Request completion handler callback. Will remove User object for currently + * configured PubNub client `uuid` if not set. + * + * @deprecated Use {@link PubNubCore#objects.removeUUIDMetadata} method instead. + */ + public removeUser(callback: ResultCallback): void; + + /** + * Remove a specific User object. + * + * @param parameters - Request configuration parameters. Will remove User object for currently + * configured PubNub client `uuid` if not set. + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link PubNubCore#objects.removeUUIDMetadata} method instead. + */ + public removeUser( + parameters: AppContext.RemoveUUIDMetadataParameters, + callback: ResultCallback, + ): void; + + /** + * Remove a specific User object. + * + * @param [parameters] - Request configuration parameters. Will remove User object for currently + * configured PubNub client `uuid` if not set. + * + * @returns Asynchronous User object remove response. + * + * @deprecated Use {@link PubNubCore#objects.removeUUIDMetadata} method instead. + */ + public async removeUser( + parameters?: AppContext.RemoveUUIDMetadataParameters, + ): Promise; + + /** + * Remove a specific User object. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous User object remove response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.removeUUIDMetadata} method instead. + */ + public async removeUser( + parametersOrCallback?: + | AppContext.RemoveUUIDMetadataParameters + | ResultCallback, + callback?: ResultCallback, + ): Promise { + return this.objects._removeUUIDMetadata(parametersOrCallback, callback); + } + + /** + * Fetch a paginated list of Space objects. + * + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link PubNubCore#objects.getAllChannelMetadata} method instead. + */ + public fetchSpaces( + callback: ResultCallback>, + ): void; + + /** + * Fetch a paginated list of Space objects. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link PubNubCore#objects.getAllChannelMetadata} method instead. + */ + public fetchSpaces( + parameters: AppContext.GetAllMetadataParameters>, + callback: ResultCallback>, + ): void; + + /** + * Fetch a paginated list of Space objects. + * + * @param [parameters] - Request configuration parameters. + * + * @returns Asynchronous get all Space objects response. + * + * @deprecated Use {@link PubNubCore#objects.getAllChannelMetadata} method instead. + */ + public async fetchSpaces( + parameters?: AppContext.GetAllMetadataParameters>, + ): Promise>; + + /** + * Fetch a paginated list of Space objects. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all Space objects response or `void` in case if `callback` + * provided. + * + * @deprecated Use {@link PubNubCore#objects.getAllChannelMetadata} method instead. + */ + async fetchSpaces( + parametersOrCallback?: + | AppContext.GetAllMetadataParameters> + | ResultCallback>, + callback?: ResultCallback>, + ): Promise | void> { + return this.objects._getAllChannelMetadata(parametersOrCallback, callback); + } + + /** + * Fetch a specific Space object. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link PubNubCore#objects.getChannelMetadata} method instead. + */ + public fetchSpace( + parameters: AppContext.GetChannelMetadataParameters, + callback: ResultCallback>, + ): void; + + /** + * Fetch a specific Space object. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous get Channel metadata response. + * + * @deprecated Use {@link PubNubCore#objects.getChannelMetadata} method instead. + */ + public async fetchSpace( + parameters: AppContext.GetChannelMetadataParameters, + ): Promise>; + + /** + * Fetch a specific Space object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get Space object response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.getChannelMetadata} method instead. + */ + async fetchSpace( + parameters: AppContext.GetChannelMetadataParameters, + callback?: ResultCallback>, + ): Promise | void> { + return this.objects._getChannelMetadata(parameters, callback); + } + + /** + * Create specific Space object. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMetadata} method instead. + */ + public createSpace( + parameters: AppContext.SetChannelMetadataParameters, + callback: ResultCallback>, + ): void; + + /** + * Create specific Space object. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous create Space object response. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMetadata} method instead. + */ + public async createSpace( + parameters: AppContext.SetChannelMetadataParameters, + ): Promise>; + + /** + * Create specific Space object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous create Space object response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMetadata} method instead. + */ + async createSpace( + parameters: AppContext.SetChannelMetadataParameters, + callback?: ResultCallback>, + ): Promise | void> { + return this.objects._setChannelMetadata(parameters, callback); + } + + /** + * Update specific Space object. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMetadata} method instead. + */ + public updateSpace( + parameters: AppContext.SetChannelMetadataParameters, + callback: ResultCallback>, + ): void; + + /** + * Update specific Space object. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous update Space object response. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMetadata} method instead. + */ + public async updateSpace( + parameters: AppContext.SetChannelMetadataParameters, + ): Promise>; + + /** + * Update specific Space object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous update Space object response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMetadata} method instead. + */ + async updateSpace( + parameters: AppContext.SetChannelMetadataParameters, + callback?: ResultCallback>, + ): Promise | void> { + return this.objects._setChannelMetadata(parameters, callback); + } + + /** + * Remove Space object. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link PubNubCore#objects.removeChannelMetadata} method instead. + */ + public removeSpace( + parameters: AppContext.RemoveChannelMetadataParameters, + callback: ResultCallback, + ): void; + + /** + * Remove a specific Space object. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous Space object remove response. + * + * @deprecated Use {@link PubNubCore#objects.removeChannelMetadata} method instead. + */ + public async removeSpace( + parameters: AppContext.RemoveChannelMetadataParameters, + ): Promise; + + /** + * Remove a specific Space object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous Space object remove response or `void` in case if `callback` + * provided. + * + * @deprecated Use {@link PubNubCore#objects.removeChannelMetadata} method instead. + */ + async removeSpace( + parameters: AppContext.RemoveChannelMetadataParameters, + callback?: ResultCallback, + ): Promise { + return this.objects._removeChannelMetadata(parameters, callback); + } + + /** + * Fetch paginated list of specific Space members or specific User memberships. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link PubNubCore#objects.getChannelMembers} or {@link PubNubCore#objects.getMemberships} + * methods instead. + */ + public fetchMemberships< + RelationCustom extends AppContext.CustomData = AppContext.CustomData, + MetadataCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.GetMembershipsParameters | AppContext.GetMembersParameters, + callback: ResultCallback< + | AppContext.SpaceMembershipsResponse + | AppContext.UserMembersResponse + >, + ): void; + + /** + * Fetch paginated list of specific Space members or specific User memberships. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous get specific Space members or specific User memberships response. + * + * @deprecated Use {@link PubNubCore#objects.getChannelMembers} or {@link PubNubCore#objects.getMemberships} + * methods instead. + */ + public async fetchMemberships< + RelationCustom extends AppContext.CustomData = AppContext.CustomData, + MetadataCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.GetMembershipsParameters | AppContext.GetMembersParameters, + ): Promise< + | AppContext.SpaceMembershipsResponse + | AppContext.UserMembersResponse + >; + + /** + * Fetch paginated list of specific Space members or specific User memberships. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get specific Space members or specific User memberships response or + * `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.getChannelMembers} or {@link PubNubCore#objects.getMemberships} + * methods instead. + */ + public async fetchMemberships< + RelationCustom extends AppContext.CustomData = AppContext.CustomData, + MetadataCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.GetMembershipsParameters | AppContext.GetMembersParameters, + callback?: ResultCallback< + | AppContext.SpaceMembershipsResponse + | AppContext.UserMembersResponse + >, + ): Promise< + | AppContext.SpaceMembershipsResponse + | AppContext.UserMembersResponse + | void + > { + return this.objects.fetchMemberships(parameters, callback); + } + + /** + * Add members to specific Space or memberships specific User. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMembers} or {@link PubNubCore#objects.setMemberships} + * methods instead. + */ + public addMemberships< + Custom extends AppContext.CustomData = AppContext.CustomData, + MetadataCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.SetMembershipsParameters | AppContext.SetChannelMembersParameters, + callback: ResultCallback< + AppContext.SetMembershipsResponse | AppContext.SetMembersResponse + >, + ): void; + + /** + * Add members to specific Space or memberships specific User. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous add members to specific Space or memberships specific User response. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMembers} or {@link PubNubCore#objects.setMemberships} + * methods instead. + */ + public async addMemberships< + Custom extends AppContext.CustomData = AppContext.CustomData, + MetadataCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.SetMembershipsParameters | AppContext.SetChannelMembersParameters, + ): Promise< + AppContext.SetMembershipsResponse | AppContext.SetMembersResponse + >; + + /** + * Add members to specific Space or memberships specific User. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous add members to specific Space or memberships specific User response or + * `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMembers} or {@link PubNubCore#objects.setMemberships} + * methods instead. + */ + async addMemberships< + Custom extends AppContext.CustomData = AppContext.CustomData, + MetadataCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.SetMembershipsParameters | AppContext.SetChannelMembersParameters, + callback?: ResultCallback< + AppContext.SetMembershipsResponse | AppContext.SetMembersResponse + >, + ) { + return this.objects.addMemberships(parameters, callback); + } + + /** + * Update specific Space members or User memberships. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMembers} or {@link PubNubCore#objects.setMemberships} + * methods instead. + */ + public updateMemberships< + Custom extends AppContext.CustomData = AppContext.CustomData, + MetadataCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.SetMembershipsParameters | AppContext.SetChannelMembersParameters, + callback: ResultCallback< + AppContext.SetMembershipsResponse | AppContext.SetMembersResponse + >, + ): void; + + /** + * Update specific Space members or User memberships. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous update Space members or User memberships response. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMembers} or {@link PubNubCore#objects.setMemberships} + * methods instead. + */ + public async updateMemberships< + Custom extends AppContext.CustomData = AppContext.CustomData, + MetadataCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.SetMembershipsParameters | AppContext.SetChannelMembersParameters, + ): Promise< + AppContext.SetMembershipsResponse | AppContext.SetMembersResponse + >; + + /** + * Update specific Space members or User memberships. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous update Space members or User memberships response or `void` in case + * if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMembers} or {@link PubNubCore#objects.setMemberships} + * methods instead. + */ + async updateMemberships< + Custom extends AppContext.CustomData = AppContext.CustomData, + MetadataCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.SetMembershipsParameters | AppContext.SetChannelMembersParameters, + callback?: ResultCallback< + AppContext.SetMembershipsResponse | AppContext.SetMembersResponse + >, + ) { + return this.objects.addMemberships(parameters, callback); + } + + /** + * Remove User membership. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link PubNubCore#objects.removeMemberships} or {@link PubNubCore#objects.removeChannelMembers} + * methods instead + * from `objects` API group.. + */ + public removeMemberships< + RelationCustom extends AppContext.CustomData = AppContext.CustomData, + MetadataCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.RemoveMembersParameters | AppContext.RemoveMembershipsParameters, + callback: ResultCallback< + | AppContext.RemoveMembersResponse + | AppContext.RemoveMembershipsResponse + >, + ): void; + + /** + * Remove User membership. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous memberships modification response. + * + * @deprecated Use {@link PubNubCore#objects.removeMemberships} or {@link PubNubCore#objects.removeChannelMembers} + * methods instead + * from `objects` API group.. + */ + public async removeMemberships< + RelationCustom extends AppContext.CustomData = AppContext.CustomData, + MetadataCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.RemoveMembersParameters | AppContext.RemoveMembershipsParameters, + ): Promise>; + + /** + * Remove User membership. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous memberships modification response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.removeMemberships} or {@link PubNubCore#objects.removeChannelMembers} + * methods instead + * from `objects` API group.. + */ + public async removeMemberships< + RelationCustom extends AppContext.CustomData = AppContext.CustomData, + MetadataCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.RemoveMembersParameters | AppContext.RemoveMembershipsParameters, + callback?: ResultCallback< + | AppContext.RemoveMembersResponse + | AppContext.RemoveMembershipsResponse + >, + ): Promise< + | AppContext.RemoveMembersResponse + | AppContext.RemoveMembershipsResponse + | void + > { + if ('spaceId' in parameters) { + const spaceParameters = parameters as AppContext.RemoveMembersParameters; + const requestParameters = { + channel: spaceParameters.spaceId ?? spaceParameters.channel, + uuids: spaceParameters.userIds ?? spaceParameters.uuids, + limit: 0, + }; + if (callback) return this.objects.removeChannelMembers(requestParameters, callback); + return this.objects.removeChannelMembers(requestParameters); + } + + const userParameters = parameters as AppContext.RemoveMembershipsParameters; + const requestParameters = { + uuid: userParameters.userId, + channels: userParameters.spaceIds ?? userParameters.channels, + limit: 0, + }; + if (callback) return this.objects.removeMemberships(requestParameters, callback); + return this.objects.removeMemberships(requestParameters); + } + // endregion + // endregion + + // -------------------------------------------------------- + // ----------------- Channel Groups API ------------------- + // -------------------------------------------------------- + // region Channel Groups API + + /** + * PubNub Channel Groups API group. + */ + get channelGroups(): PubNubChannelGroups { + return this._channelGroups; + } + // endregion + + // -------------------------------------------------------- + // ---------------- Push Notifications API ----------------- + // -------------------------------------------------------- + // region Push Notifications API + + /** + * PubNub Push Notifications API group. + */ + get push(): PubNubPushNotifications { + return this._push; + } + // endregion + + // -------------------------------------------------------- + // ------------------ File sharing API -------------------- + // -------------------------------------------------------- + // region File sharing API + + // region Send + /** + * Share file to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public sendFile( + parameters: FileSharing.SendFileParameters, + callback: ResultCallback, + ): void; + + /** + * Share file to a specific channel. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous file sharing response. + */ + public async sendFile( + parameters: FileSharing.SendFileParameters, + ): Promise; + + /** + * Share file to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous file sharing response or `void` in case if `callback` provided. + */ + public async sendFile( + parameters: FileSharing.SendFileParameters, + callback?: ResultCallback, + ): Promise { + if (!this._configuration.PubNubFile) + throw new Error("Validation failed: 'PubNubFile' not configured or file upload not supported by the platform."); + + const sendFileRequest = new SendFileRequest({ + ...parameters, + keySet: this._configuration.keySet, + PubNubFile: this._configuration.PubNubFile, + fileUploadPublishRetryLimit: this._configuration.fileUploadPublishRetryLimit, + file: parameters.file, + sendRequest: this.sendRequest.bind(this), + publishFile: this.publishFile.bind(this), + crypto: this._configuration.getCryptoModule(), + cryptography: this.cryptography ? (this.cryptography as Cryptography) : undefined, + }); + + const status: Status = { + error: false, + operation: RequestOperation.PNPublishFileOperation, + category: StatusCategory.PNAcknowledgmentCategory, + statusCode: 0, + }; + + return sendFileRequest + .process() + .then((response) => { + status.statusCode = response.status; + + if (callback) return callback(status, response); + return response; + }) + .catch((error: unknown) => { + let errorStatus: Status | undefined; + if (error instanceof PubNubError) errorStatus = error.status; + else if (error instanceof PubNubAPIError) errorStatus = error.toStatus(status.operation!); + + // Notify callback (if possible). + if (callback && errorStatus) callback(errorStatus, null); + + throw new PubNubError('REST API request processing error, check status for details', errorStatus); + }); + } + // endregion + + // region Publish File Message + /** + * Publish file message to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public publishFile( + parameters: FileSharing.PublishFileMessageParameters, + callback: ResultCallback, + ): void; + + /** + * Publish file message to a specific channel. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous publish file message response. + */ + public async publishFile( + parameters: FileSharing.PublishFileMessageParameters, + ): Promise; + + /** + * Publish file message to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous publish file message response or `void` in case if `callback` provided. + */ + public async publishFile( + parameters: FileSharing.PublishFileMessageParameters, + callback?: ResultCallback, + ): Promise { + if (!this._configuration.PubNubFile) + throw new Error("Validation failed: 'PubNubFile' not configured or file upload not supported by the platform."); + + const request = new PublishFileMessageRequest({ + ...parameters, + keySet: this._configuration.keySet, + crypto: this._configuration.getCryptoModule(), + }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region List + /** + * Retrieve list of shared files in specific channel. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public listFiles( + parameters: FileSharing.ListFilesParameters, + callback: ResultCallback, + ): void; + + /** + * Retrieve list of shared files in specific channel. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous shared files list response. + */ + public async listFiles(parameters: FileSharing.ListFilesParameters): Promise; + + /** + * Retrieve list of shared files in specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous shared files list response or `void` in case if `callback` provided. + */ + public async listFiles( + parameters: FileSharing.ListFilesParameters, + callback?: ResultCallback, + ): Promise { + const request = new FilesListRequest({ ...parameters, keySet: this._configuration.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Get Download Url + /** + * Get file download Url. + * + * @param parameters - Request configuration parameters. + * + * @returns File download Url. + */ + public getFileUrl(parameters: FileSharing.FileUrlParameters): FileSharing.FileUrlResponse { + const request = this.transport.request( + new GetFileDownloadUrlRequest({ ...parameters, keySet: this._configuration.keySet }).request(), + ); + const query = request.queryParameters ?? {}; + const queryString = Object.keys(query) + .map((key) => { + const queryValue = query[key]; + if (!Array.isArray(queryValue)) return `${key}=${encodeString(queryValue)}`; + + return queryValue.map((value) => `${key}=${encodeString(value)}`).join('&'); + }) + .join('&'); + + return `${request.origin}${request.path}?${queryString}`; + } + // endregion + + // region Download + /** + * Download shared file from specific channel. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public downloadFile(parameters: FileSharing.DownloadFileParameters, callback: ResultCallback): void; + + /** + * Download shared file from specific channel. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous download shared file response. + */ + public async downloadFile(parameters: FileSharing.DownloadFileParameters): Promise; + + /** + * Download shared file from specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous download shared file response or `void` in case if `callback` provided. + */ + public async downloadFile( + parameters: FileSharing.DownloadFileParameters, + callback?: ResultCallback, + ): Promise { + if (!this._configuration.PubNubFile) + throw new Error("Validation failed: 'PubNubFile' not configured or file upload not supported by the platform."); + + const request = new DownloadFileRequest({ + ...parameters, + keySet: this._configuration.keySet, + PubNubFile: this._configuration.PubNubFile, + cryptography: this.cryptography ? (this.cryptography as Cryptography) : undefined, + crypto: this._configuration.getCryptoModule(), + }); + + if (callback) return this.sendRequest(request, callback); + return (await this.sendRequest(request)) as PlatformFile; + } + // endregion + + // region Delete + /** + * Delete shared file from specific channel. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public deleteFile( + parameters: FileSharing.DeleteFileParameters, + callback: ResultCallback, + ): void; + + /** + * Delete shared file from specific channel. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous delete shared file response. + */ + public async deleteFile(parameters: FileSharing.DeleteFileParameters): Promise; + + /** + * Delete shared file from specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous delete shared file response or `void` in case if `callback` provided. + */ + public async deleteFile( + parameters: FileSharing.DeleteFileParameters, + callback?: ResultCallback, + ): Promise { + const request = new DeleteFileRequest({ ...parameters, keySet: this._configuration.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + // endregion + + // -------------------------------------------------------- + // ---------------------- Time API ------------------------ + // -------------------------------------------------------- + // region Time API + + /** + Get current high-precision timetoken. + * + * @param callback - Request completion handler callback. + */ + public time(callback: ResultCallback): void; + + /** + * Get current high-precision timetoken. + * + * @returns Asynchronous get current timetoken response. + */ + public async time(): Promise; + + /** + Get current high-precision timetoken. + * + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get current timetoken response or `void` in case if `callback` provided. + */ + async time(callback?: ResultCallback): Promise { + const request = new Time.TimeRequest(); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // -------------------------------------------------------- + // ------------------ Cryptography API -------------------- + // -------------------------------------------------------- + // region Cryptography + // region Common + + /** + * Encrypt data. + * + * @param data - Stringified data which should be encrypted using `CryptoModule`. + * @deprecated + * @param [customCipherKey] - Cipher key which should be used to encrypt data. **Deprecated:** + * use {@link Configuration#cryptoModule|cryptoModule} instead. + * + * @returns Data encryption result as a string. + */ + public encrypt(data: string | Payload, customCipherKey?: string): string { + const cryptoModule = this._configuration.getCryptoModule(); + + if (!customCipherKey && cryptoModule && typeof data === 'string') { + const encrypted = cryptoModule.encrypt(data); + + return typeof encrypted === 'string' ? encrypted : encode(encrypted); + } + + if (!this.crypto) throw new Error('Encryption error: cypher key not set'); + + return this.crypto.encrypt(data, customCipherKey); + } + + /** + * Decrypt data. + * + * @param data - Stringified data which should be encrypted using `CryptoModule`. + * @param [customCipherKey] - Cipher key which should be used to decrypt data. **Deprecated:** + * use {@link Configuration#cryptoModule|cryptoModule} instead. + * + * @returns Data decryption result as an object. + */ + public decrypt(data: string, customCipherKey?: string): Payload | null { + const cryptoModule = this._configuration.getCryptoModule(); + if (!customCipherKey && cryptoModule) { + const decrypted = cryptoModule.decrypt(data); + + return decrypted instanceof ArrayBuffer ? JSON.parse(new TextDecoder().decode(decrypted)) : decrypted; + } + + if (!this.crypto) throw new Error('Decryption error: cypher key not set'); + + return this.crypto.decrypt(data, customCipherKey); + } + // endregion + + // region File + /** + * Encrypt file content. + * + * @param file - File which should be encrypted using `CryptoModule`. + * + * @returns Asynchronous file encryption result. + * + * @throws Error if source file not provided. + * @throws File constructor not provided. + * @throws Crypto module is missing (if non-legacy flow used). + */ + public async encryptFile(file: PubNubFileInterface): Promise; + + /** + * Encrypt file content. + * + * @param key - Cipher key which should be used to encrypt data. + * @param file - File which should be encrypted using legacy cryptography. + * + * @returns Asynchronous file encryption result. + * + * @throws Error if source file not provided. + * @throws File constructor not provided. + * @throws Crypto module is missing (if non-legacy flow used). + */ + public async encryptFile(key: string, file: PubNubFileInterface): Promise; + + /** + * Encrypt file content. + * + * @param keyOrFile - Cipher key which should be used to encrypt data or file which should be + * encrypted using `CryptoModule`. + * @param [file] - File which should be encrypted using legacy cryptography. + * + * @returns Asynchronous file encryption result. + * + * @throws Error if source file not provided. + * @throws File constructor not provided. + * @throws Crypto module is missing (if non-legacy flow used). + */ + public async encryptFile(keyOrFile: string | PubNubFileInterface, file?: PubNubFileInterface) { + if (typeof keyOrFile !== 'string') file = keyOrFile; + + if (!file) throw new Error('File encryption error. Source file is missing.'); + if (!this._configuration.PubNubFile) throw new Error('File encryption error. File constructor not configured.'); + if (typeof keyOrFile !== 'string' && !this._configuration.getCryptoModule()) + throw new Error('File encryption error. Crypto module not configured.'); + + if (typeof keyOrFile === 'string') { + if (!this.cryptography) throw new Error('File encryption error. File encryption not available'); + return this.cryptography.encryptFile(keyOrFile, file, this._configuration.PubNubFile); + } + + return this._configuration.getCryptoModule()?.encryptFile(file, this._configuration.PubNubFile); + } + + /** + * Decrypt file content. + * + * @param file - File which should be decrypted using legacy cryptography. + * + * @returns Asynchronous file decryption result. + * + * @throws Error if source file not provided. + * @throws File constructor not provided. + * @throws Crypto module is missing (if non-legacy flow used). + */ + public async decryptFile(file: PubNubFileInterface): Promise; + + /** + * Decrypt file content. + * + * @param key - Cipher key which should be used to decrypt data. + * @param [file] - File which should be decrypted using legacy cryptography. + * + * @returns Asynchronous file decryption result. + * + * @throws Error if source file not provided. + * @throws File constructor not provided. + * @throws Crypto module is missing (if non-legacy flow used). + */ + public async decryptFile(key: string | PubNubFileInterface, file?: PubNubFileInterface): Promise; + + /** + * Decrypt file content. + * + * @param keyOrFile - Cipher key which should be used to decrypt data or file which should be + * decrypted using `CryptoModule`. + * @param [file] - File which should be decrypted using legacy cryptography. + * + * @returns Asynchronous file decryption result. + * + * @throws Error if source file not provided. + * @throws File constructor not provided. + * @throws Crypto module is missing (if non-legacy flow used). + */ + public async decryptFile(keyOrFile: string | PubNubFileInterface, file?: PubNubFileInterface) { + if (typeof keyOrFile !== 'string') file = keyOrFile; + + if (!file) throw new Error('File encryption error. Source file is missing.'); + if (!this._configuration.PubNubFile) + throw new Error('File decryption error. File constructor' + ' not configured.'); + if (typeof keyOrFile === 'string' && !this._configuration.getCryptoModule()) + throw new Error('File decryption error. Crypto module not configured.'); + + if (typeof keyOrFile === 'string') { + if (!this.cryptography) throw new Error('File decryption error. File decryption not available'); + return this.cryptography.decryptFile(keyOrFile, file, this._configuration.PubNubFile); + } + + return this._configuration.getCryptoModule()?.decryptFile(file, this._configuration.PubNubFile); + } + // endregion + // endregion +} diff --git a/src/core/pubnub-objects.ts b/src/core/pubnub-objects.ts new file mode 100644 index 000000000..5d4a2152f --- /dev/null +++ b/src/core/pubnub-objects.ts @@ -0,0 +1,1096 @@ +/** + * PubNub Objects API module. + */ + +import { GetAllChannelsMetadataRequest } from './endpoints/objects/channel/get_all'; +import { RemoveChannelMetadataRequest } from './endpoints/objects/channel/remove'; +import { GetUUIDMembershipsRequest } from './endpoints/objects/membership/get'; +import { SetUUIDMembershipsRequest } from './endpoints/objects/membership/set'; +import { GetAllUUIDMetadataRequest } from './endpoints/objects/uuid/get_all'; +import { GetChannelMetadataRequest } from './endpoints/objects/channel/get'; +import { SetChannelMetadataRequest } from './endpoints/objects/channel/set'; +import { RemoveUUIDMetadataRequest } from './endpoints/objects/uuid/remove'; +import { GetChannelMembersRequest } from './endpoints/objects/member/get'; +import { SetChannelMembersRequest } from './endpoints/objects/member/set'; +import { KeySet, ResultCallback, SendRequestFunction } from './types/api'; +import { GetUUIDMetadataRequest } from './endpoints/objects/uuid/get'; +import { PrivateClientConfiguration } from './interfaces/configuration'; +import * as AppContext from './types/api/app-context'; +import { ChannelMetadataObject } from './types/api/app-context'; +import { SetUUIDMetadataRequest } from './endpoints/objects/uuid/set'; + +export default class PubNubObjects { + /** + * REST API endpoints access credentials. + */ + private readonly keySet: KeySet; + constructor( + private readonly configuration: PrivateClientConfiguration, + /* eslint-disable @typescript-eslint/no-explicit-any */ + private readonly sendRequest: SendRequestFunction, + ) { + this.keySet = configuration.keySet; + } + + // -------------------------------------------------------- + // ----------------------- UUID API ----------------------- + // -------------------------------------------------------- + // region UUID API + // region Get Metadata + + /** + * Fetch a paginated list of UUID Metadata objects. + * + * @param callback - Request completion handler callback. + */ + public getAllUUIDMetadata( + callback: ResultCallback>, + ): void; + + /** + * Fetch a paginated list of UUID Metadata objects. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public getAllUUIDMetadata( + parameters: AppContext.GetAllMetadataParameters>, + callback: ResultCallback>, + ): void; + + /** + * Fetch a paginated list of UUID Metadata objects. + * + * @param [parameters] - Request configuration parameters. + * + * @returns Asynchronous get all UUID metadata response. + */ + public async getAllUUIDMetadata( + parameters?: AppContext.GetAllMetadataParameters>, + ): Promise>; + + /** + * Fetch a paginated list of UUID Metadata objects. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all UUID metadata response or `void` in case if `callback` provided. + */ + async getAllUUIDMetadata( + parametersOrCallback?: + | AppContext.GetAllMetadataParameters> + | ResultCallback>, + callback?: ResultCallback>, + ): Promise | void> { + return this._getAllUUIDMetadata(parametersOrCallback, callback); + } + + /** + * Fetch a paginated list of UUID Metadata objects. + * + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all UUID metadata response or `void` in case if `callback` provided. + */ + async _getAllUUIDMetadata( + parametersOrCallback?: + | AppContext.GetAllMetadataParameters> + | ResultCallback>, + callback?: ResultCallback>, + ): Promise | void> { + // Get user request parameters. + const parameters: AppContext.GetAllMetadataParameters> = + parametersOrCallback && typeof parametersOrCallback !== 'function' ? parametersOrCallback : {}; + callback ??= typeof parametersOrCallback === 'function' ? parametersOrCallback : undefined; + + const request = new GetAllUUIDMetadataRequest({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + + /** + * Fetch UUID Metadata object for currently configured PubNub client `uuid`. + * + * @param callback - Request completion handler callback. + */ + public getUUIDMetadata( + callback: ResultCallback>, + ): void; + + /** + * Fetch a specific UUID Metadata object. + * + * @param parameters - Request configuration parameters. Will fetch UUID metadata object for + * currently configured PubNub client `uuid` if not set. + * @param callback - Request completion handler callback. + */ + public getUUIDMetadata( + parameters: AppContext.GetUUIDMetadataParameters, + callback: ResultCallback>, + ): void; + + /** + * Fetch a specific UUID Metadata object. + * + * @param [parameters] - Request configuration parameters. Will fetch UUID Metadata object for + * currently configured PubNub client `uuid` if not set. + * + * @returns Asynchronous get UUID metadata response. + */ + public async getUUIDMetadata( + parameters?: AppContext.GetUUIDMetadataParameters, + ): Promise>; + + /** + * Fetch a specific UUID Metadata object. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get UUID metadata response or `void` in case if `callback` provided. + */ + async getUUIDMetadata( + parametersOrCallback?: + | AppContext.GetUUIDMetadataParameters + | ResultCallback>, + callback?: ResultCallback>, + ): Promise | void> { + return this._getUUIDMetadata(parametersOrCallback, callback); + } + + /** + * Fetch a specific UUID Metadata object. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get UUID metadata response or `void` in case if `callback` provided. + */ + async _getUUIDMetadata( + parametersOrCallback?: + | AppContext.GetUUIDMetadataParameters + | ResultCallback>, + callback?: ResultCallback>, + ): Promise | void> { + // Get user request parameters. + const parameters: AppContext.GetUUIDMetadataParameters = + parametersOrCallback && typeof parametersOrCallback !== 'function' ? parametersOrCallback : {}; + callback ??= typeof parametersOrCallback === 'function' ? parametersOrCallback : undefined; + if (parameters.userId) parameters.uuid = parameters.userId; + parameters.uuid ??= this.configuration.userId; + + const request = new GetUUIDMetadataRequest({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Set Metadata + /** + * Update specific UUID Metadata object. + * + * @param parameters - Request configuration parameters. Will set UUID metadata for currently + * configured PubNub client `uuid` if not set. + * @param callback - Request completion handler callback. + */ + public setUUIDMetadata( + parameters: AppContext.SetUUIDMetadataParameters, + callback: ResultCallback>, + ): void; + + /** + * Update specific UUID Metadata object. + * + * @param parameters - Request configuration parameters. Will set UUID metadata for currently + * configured PubNub client `uuid` if not set. + * + * @returns Asynchronous set UUID metadata response. + */ + public async setUUIDMetadata( + parameters: AppContext.SetUUIDMetadataParameters, + ): Promise>; + + /** + * Update specific UUID Metadata object. + * + * @param parameters - Request configuration parameters. Will set UUID metadata for currently + * configured PubNub client `uuid` if not set. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous set UUID metadata response or `void` in case if `callback` provided. + */ + async setUUIDMetadata( + parameters: AppContext.SetUUIDMetadataParameters, + callback?: ResultCallback>, + ): Promise | void> { + return this._setUUIDMetadata(parameters, callback); + } + + /** + * Update specific UUID Metadata object. + * + * @param parameters - Request configuration parameters. Will set UUID metadata for currently + * configured PubNub client `uuid` if not set. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous set UUID metadata response or `void` in case if `callback` provided. + */ + async _setUUIDMetadata( + parameters: AppContext.SetUUIDMetadataParameters, + callback?: ResultCallback>, + ): Promise | void> { + if (parameters.userId) parameters.uuid = parameters.userId; + parameters.uuid ??= this.configuration.userId; + + const request = new SetUUIDMetadataRequest({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Remove Metadata + /** + * Remove UUID Metadata object for currently configured PubNub client `uuid`. + * + * @param callback - Request completion handler callback. + */ + public removeUUIDMetadata(callback: ResultCallback): void; + + /** + * Remove a specific UUID Metadata object. + * + * @param parameters - Request configuration parameters. Will remove UUID metadata for currently + * configured PubNub client `uuid` if not set. + * @param callback - Request completion handler callback. + */ + public removeUUIDMetadata( + parameters: AppContext.RemoveUUIDMetadataParameters, + callback: ResultCallback, + ): void; + + /** + * Remove a specific UUID Metadata object. + * + * @param [parameters] - Request configuration parameters. Will remove UUID metadata for currently + * configured PubNub client `uuid` if not set. + * + * @returns Asynchronous UUID metadata remove response. + */ + public async removeUUIDMetadata( + parameters?: AppContext.RemoveUUIDMetadataParameters, + ): Promise; + + /** + * Remove a specific UUID Metadata object. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous UUID metadata remove response or `void` in case if `callback` provided. + */ + public async removeUUIDMetadata( + parametersOrCallback?: + | AppContext.RemoveUUIDMetadataParameters + | ResultCallback, + callback?: ResultCallback, + ): Promise { + return this._removeUUIDMetadata(parametersOrCallback, callback); + } + + /** + * Remove a specific UUID Metadata object. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous UUID metadata remove response or `void` in case if `callback` provided. + */ + public async _removeUUIDMetadata( + parametersOrCallback?: + | AppContext.RemoveUUIDMetadataParameters + | ResultCallback, + callback?: ResultCallback, + ): Promise { + // Get user request parameters. + const parameters: AppContext.RemoveUUIDMetadataParameters = + parametersOrCallback && typeof parametersOrCallback !== 'function' ? parametersOrCallback : {}; + callback ??= typeof parametersOrCallback === 'function' ? parametersOrCallback : undefined; + if (parameters.userId) parameters.uuid = parameters.userId; + parameters.uuid ??= this.configuration.userId; + + const request = new RemoveUUIDMetadataRequest({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + // endregion + + // -------------------------------------------------------- + // --------------------- Channel API ---------------------- + // -------------------------------------------------------- + // region Channel API + // region Get Metadata + + /** + * Fetch a paginated list of Channel Metadata objects. + * + * @param callback - Request completion handler callback. + */ + public getAllChannelMetadata( + callback: ResultCallback>, + ): void; + + /** + * Fetch a paginated list of Channel Metadata objects. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public getAllChannelMetadata( + parameters: AppContext.GetAllMetadataParameters>, + callback: ResultCallback>, + ): void; + + /** + * Fetch a paginated list of Channel Metadata objects. + * + * @param [parameters] - Request configuration parameters. + * + * @returns Asynchronous get all Channel metadata response. + */ + public async getAllChannelMetadata( + parameters?: AppContext.GetAllMetadataParameters>, + ): Promise>; + + /** + * Fetch a paginated list of Channel Metadata objects. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all Channel metadata response or `void` in case if `callback` + * provided. + */ + async getAllChannelMetadata( + parametersOrCallback?: + | AppContext.GetAllMetadataParameters> + | ResultCallback>, + callback?: ResultCallback>, + ): Promise | void> { + return this._getAllChannelMetadata(parametersOrCallback, callback); + } + + /** + * Fetch a paginated list of Channel Metadata objects. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all Channel metadata response or `void` in case if `callback` + * provided. + */ + async _getAllChannelMetadata( + parametersOrCallback?: + | AppContext.GetAllMetadataParameters> + | ResultCallback>, + callback?: ResultCallback>, + ): Promise | void> { + // Get user request parameters. + const parameters: AppContext.GetAllMetadataParameters> = + parametersOrCallback && typeof parametersOrCallback !== 'function' ? parametersOrCallback : {}; + callback ??= typeof parametersOrCallback === 'function' ? parametersOrCallback : undefined; + + const request = new GetAllChannelsMetadataRequest({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + + /** + * Fetch Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public getChannelMetadata( + parameters: AppContext.GetChannelMetadataParameters, + callback: ResultCallback>, + ): void; + + /** + * Fetch a specific Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous get Channel metadata response. + */ + public async getChannelMetadata( + parameters: AppContext.GetChannelMetadataParameters, + ): Promise>; + + /** + * Fetch Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get Channel metadata response or `void` in case if `callback` provided. + */ + async getChannelMetadata( + parameters: AppContext.GetChannelMetadataParameters, + callback?: ResultCallback>, + ): Promise | void> { + return this._getChannelMetadata(parameters, callback); + } + + /** + * Fetch Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get Channel metadata response or `void` in case if `callback` provided. + */ + async _getChannelMetadata( + parameters: AppContext.GetChannelMetadataParameters, + callback?: ResultCallback>, + ): Promise | void> { + const request = new GetChannelMetadataRequest({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Set Metadata + /** + * Update specific Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public setChannelMetadata( + parameters: AppContext.SetChannelMetadataParameters, + callback: ResultCallback>, + ): void; + + /** + * Update specific Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous set Channel metadata response. + */ + public async setChannelMetadata( + parameters: AppContext.SetChannelMetadataParameters, + ): Promise>; + + /** + * Update specific Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous set Channel metadata response or `void` in case if `callback` provided. + */ + async setChannelMetadata( + parameters: AppContext.SetChannelMetadataParameters, + callback?: ResultCallback>, + ): Promise | void> { + return this._setChannelMetadata(parameters, callback); + } + + /** + * Update specific Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous set Channel metadata response or `void` in case if `callback` provided. + */ + async _setChannelMetadata( + parameters: AppContext.SetChannelMetadataParameters, + callback?: ResultCallback>, + ): Promise | void> { + const request = new SetChannelMetadataRequest({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Remove Metadata + /** + * Remove Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public removeChannelMetadata( + parameters: AppContext.RemoveChannelMetadataParameters, + callback: ResultCallback, + ): void; + + /** + * Remove a specific Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous Channel metadata remove response. + */ + public async removeChannelMetadata( + parameters: AppContext.RemoveChannelMetadataParameters, + ): Promise; + + /** + * Remove a specific Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous Channel metadata remove response or `void` in case if `callback` + * provided. + */ + async removeChannelMetadata( + parameters: AppContext.RemoveChannelMetadataParameters, + callback?: ResultCallback, + ): Promise { + return this._removeChannelMetadata(parameters, callback); + } + + /** + * Remove a specific Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous Channel metadata remove response or `void` in case if `callback` + * provided. + */ + async _removeChannelMetadata( + parameters: AppContext.RemoveChannelMetadataParameters, + callback?: ResultCallback, + ): Promise { + const request = new RemoveChannelMetadataRequest({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + // endregion + + // -------------------------------------------------------- + // -------------- Members / Membership API ---------------- + // -------------------------------------------------------- + // region Members API + // region Get Members + + /** + * Fetch a paginated list of Channel Member objects. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public getChannelMembers< + MemberCustom extends AppContext.CustomData = AppContext.CustomData, + UUIDCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.GetMembersParameters, + callback: ResultCallback>, + ): void; + + /** + * Fetch a paginated list of Channel Member objects. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous get Channel Members response. + */ + public async getChannelMembers< + MemberCustom extends AppContext.CustomData = AppContext.CustomData, + UUIDCustom extends AppContext.CustomData = AppContext.CustomData, + >(parameters: AppContext.GetMembersParameters): Promise>; + + /** + * Fetch a paginated list of Channel Member objects. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get Channel Members response or `void` in case if `callback` provided. + */ + async getChannelMembers< + MemberCustom extends AppContext.CustomData = AppContext.CustomData, + UUIDCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.GetMembersParameters, + callback?: ResultCallback>, + ): Promise | void> { + const request = new GetChannelMembersRequest({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Set Members + /** + * Update specific Channel Members list. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public setChannelMembers< + MemberCustom extends AppContext.CustomData = AppContext.CustomData, + UUIDCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.SetChannelMembersParameters, + callback: ResultCallback>, + ): void; + + /** + * Update specific Channel Members list. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous update Channel Members list response. + */ + public async setChannelMembers< + MemberCustom extends AppContext.CustomData = AppContext.CustomData, + UUIDCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.SetChannelMembersParameters, + ): Promise>; + + /** + * Update specific Channel Members list. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous update Channel members list response or `void` in case if `callback` + * provided. + */ + async setChannelMembers< + MemberCustom extends AppContext.CustomData = AppContext.CustomData, + UUIDCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.SetChannelMembersParameters, + callback?: ResultCallback>, + ): Promise | void> { + const request = new SetChannelMembersRequest({ ...parameters, type: 'set', keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Remove Members + /** + * Remove Members from the Channel. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public removeChannelMembers< + MemberCustom extends AppContext.CustomData = AppContext.CustomData, + UUIDCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.RemoveMembersParameters, + callback: ResultCallback>, + ): void; + + /** + * Remove Members from the Channel. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous Channel Members remove response. + */ + public async removeChannelMembers< + MemberCustom extends AppContext.CustomData = AppContext.CustomData, + UUIDCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.RemoveMembersParameters, + ): Promise>; + + /** + * Remove Members from the Channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous Channel Members remove response or `void` in case if `callback` provided. + */ + async removeChannelMembers< + MemberCustom extends AppContext.CustomData = AppContext.CustomData, + UUIDCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.RemoveMembersParameters, + callback?: ResultCallback>, + ): Promise | void> { + const request = new SetChannelMembersRequest({ ...parameters, type: 'delete', keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + // endregion + + // region Membership API + // region Get Membership + /** + * Fetch a specific UUID Memberships list for currently configured PubNub client `uuid`. + * + * @param callback - Request completion handler callback. + * + * @returns Asynchronous get UUID Memberships list response or `void` in case if `callback` + * provided. + */ + public getMemberships< + MembershipCustom extends AppContext.CustomData = AppContext.CustomData, + ChannelCustom extends AppContext.CustomData = AppContext.CustomData, + >(callback: ResultCallback>): void; + + /** + * Fetch a specific UUID Memberships list. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public getMemberships< + MembershipCustom extends AppContext.CustomData = AppContext.CustomData, + ChannelCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.GetMembershipsParameters, + callback: ResultCallback>, + ): void; + + /** + * Fetch a specific UUID Memberships list. + * + * @param [parameters] - Request configuration parameters. Will fetch UUID Memberships list for + * currently configured PubNub client `uuid` if not set. + * + * @returns Asynchronous get UUID Memberships list response. + */ + public async getMemberships< + MembershipCustom extends AppContext.CustomData = AppContext.CustomData, + ChannelCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters?: AppContext.GetMembershipsParameters, + ): Promise>; + + /** + * Fetch a specific UUID Memberships list. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get UUID Memberships response or `void` in case if `callback` provided. + */ + async getMemberships< + MembershipCustom extends AppContext.CustomData = AppContext.CustomData, + ChannelCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parametersOrCallback?: + | AppContext.GetMembershipsParameters + | ResultCallback>, + callback?: ResultCallback>, + ): Promise | void> { + // Get user request parameters. + const parameters: AppContext.GetMembershipsParameters = + parametersOrCallback && typeof parametersOrCallback !== 'function' ? parametersOrCallback : {}; + callback ??= typeof parametersOrCallback === 'function' ? parametersOrCallback : undefined; + if (parameters.userId) parameters.uuid = parameters.userId; + parameters.uuid ??= this.configuration.userId; + + const request = new GetUUIDMembershipsRequest({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Set Membership + /** + * Update specific UUID Memberships list. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public setMemberships< + MembershipCustom extends AppContext.CustomData = AppContext.CustomData, + ChannelCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.SetMembershipsParameters, + callback: ResultCallback>, + ): void; + + /** + * Update specific UUID Memberships list. + * + * @param parameters - Request configuration parameters or callback from overload. + * + * @returns Asynchronous update UUID Memberships list response. + */ + public async setMemberships< + MembershipCustom extends AppContext.CustomData = AppContext.CustomData, + ChannelCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.SetMembershipsParameters, + ): Promise>; + + /** + * Update specific UUID Memberships list. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous update UUID Memberships list response or `void` in case if `callback` + * provided. + */ + async setMemberships< + MembershipCustom extends AppContext.CustomData = AppContext.CustomData, + ChannelCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.SetMembershipsParameters, + callback?: ResultCallback>, + ): Promise | void> { + if (parameters.userId) parameters.uuid = parameters.userId; + parameters.uuid ??= this.configuration.userId; + + const request = new SetUUIDMembershipsRequest({ ...parameters, type: 'set', keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Remove Membership + /** + * Remove a specific UUID Memberships. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public removeMemberships< + MembershipCustom extends AppContext.CustomData = AppContext.CustomData, + ChannelCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.RemoveMembershipsParameters, + callback: ResultCallback>, + ): void; + + /** + * Remove a specific UUID Memberships. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous UUID Memberships remove response. + */ + public async removeMemberships< + MembershipCustom extends AppContext.CustomData = AppContext.CustomData, + ChannelCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.RemoveMembershipsParameters, + ): Promise>; + + /** + * Remove a specific UUID Memberships. + * + * @param parameters - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous UUID Memberships remove response or `void` in case if `callback` + * provided. + */ + async removeMemberships< + MembershipCustom extends AppContext.CustomData = AppContext.CustomData, + ChannelCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.RemoveMembershipsParameters, + callback?: ResultCallback>, + ): Promise | void> { + if (parameters.userId) parameters.uuid = parameters.userId; + parameters.uuid ??= this.configuration.userId; + + const request = new SetUUIDMembershipsRequest({ ...parameters, type: 'delete', keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + // endregion + + // -------------------------------------------------------- + // --------------------- Deprecated API ------------------- + // -------------------------------------------------------- + // region Deprecated + + /** + * Fetch paginated list of specific Space members or specific User memberships. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get specific Space members or specific User memberships response. + * + * @deprecated Use {@link PubNubObjects#getChannelMembers} or {@link PubNubObjects#getMemberships} methods instead. + */ + public async fetchMemberships< + RelationCustom extends AppContext.CustomData = AppContext.CustomData, + MetadataCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.GetMembershipsParameters | AppContext.GetMembersParameters, + callback?: ResultCallback< + | AppContext.SpaceMembershipsResponse + | AppContext.UserMembersResponse + >, + ): Promise< + | AppContext.SpaceMembershipsResponse + | AppContext.UserMembersResponse + | void + > { + if ('spaceId' in parameters) { + const spaceParameters = parameters as AppContext.GetMembersParameters; + const mappedParameters = { + channel: spaceParameters.spaceId ?? spaceParameters.channel, + filter: spaceParameters.filter, + limit: spaceParameters.limit, + page: spaceParameters.page, + include: { ...spaceParameters.include }, + sort: spaceParameters.sort + ? Object.fromEntries( + Object.entries(spaceParameters.sort).map(([key, value]) => [key.replace('user', 'uuid'), value]), + ) + : undefined, + } as AppContext.GetMembersParameters; + + // Map Members object to the older version. + const mapMembers = (response: AppContext.GetMembersResponse) => + ({ + status: response.status, + data: response.data.map((members) => ({ + user: members.uuid, + custom: members.custom, + updated: members.updated, + eTag: members.eTag, + })), + totalCount: response.totalCount, + next: response.next, + prev: response.prev, + }) as AppContext.UserMembersResponse; + + if (callback) + return this.getChannelMembers(mappedParameters, (status, result) => { + callback(status, result ? mapMembers(result) : result); + }); + return this.getChannelMembers(mappedParameters).then(mapMembers); + } + + const userParameters = parameters as AppContext.GetMembershipsParameters; + const mappedParameters = { + uuid: userParameters.userId ?? userParameters.uuid, + filter: userParameters.filter, + limit: userParameters.limit, + page: userParameters.page, + include: { ...userParameters.include }, + sort: userParameters.sort + ? Object.fromEntries( + Object.entries(userParameters.sort).map(([key, value]) => [key.replace('space', 'channel'), value]), + ) + : undefined, + } as AppContext.GetMembershipsParameters; + + // Map Memberships object to the older version. + const mapMemberships = ( + response: AppContext.GetMembershipsResponse, + ) => + ({ + status: response.status, + data: response.data.map((membership) => ({ + space: membership.channel, + custom: membership.custom, + updated: membership.updated, + eTag: membership.eTag, + })), + totalCount: response.totalCount, + next: response.next, + prev: response.prev, + }) as AppContext.SpaceMembershipsResponse; + + if (callback) + return this.getMemberships(mappedParameters, (status, result) => { + callback(status, result ? mapMemberships(result) : result); + }); + return this.getMemberships(mappedParameters).then(mapMemberships); + } + + /** + * Add members to specific Space or memberships specific User. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous add members to specific Space or memberships specific User response or + * `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubObjects#setChannelMembers} or {@link PubNubObjects#setMemberships} methods instead. + */ + async addMemberships< + Custom extends AppContext.CustomData = AppContext.CustomData, + MetadataCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.SetMembershipsParameters | AppContext.SetChannelMembersParameters, + callback?: ResultCallback< + AppContext.SetMembershipsResponse | AppContext.SetMembersResponse + >, + ): Promise< + | AppContext.SetMembershipsResponse + | AppContext.SetMembersResponse + | void + > { + if ('spaceId' in parameters) { + const spaceParameters = parameters as AppContext.SetChannelMembersParameters; + const mappedParameters = { + channel: spaceParameters.spaceId ?? spaceParameters.channel, + uuids: + spaceParameters.users?.map((user) => { + if (typeof user === 'string') return user; + user.userId; + return { id: user.userId, custom: user.custom }; + }) ?? spaceParameters.uuids, + limit: 0, + }; + + if (callback) return this.setChannelMembers(mappedParameters, callback); + return this.setChannelMembers(mappedParameters); + } + + const userParameters = parameters as AppContext.SetMembershipsParameters; + const mappedParameters = { + uuid: userParameters.userId ?? userParameters.uuid, + channels: + userParameters.spaces?.map((space) => { + if (typeof space === 'string') return space; + return { + id: space.spaceId, + custom: space.custom, + }; + }) ?? userParameters.channels, + limit: 0, + }; + + if (callback) return this.setMemberships(mappedParameters, callback); + return this.setMemberships(mappedParameters); + } + // endregion +} diff --git a/src/core/pubnub-push.ts b/src/core/pubnub-push.ts new file mode 100644 index 000000000..cc8e37b06 --- /dev/null +++ b/src/core/pubnub-push.ts @@ -0,0 +1,157 @@ +/** + * PubNub Push Notifications API module. + */ + +import { RemoveDevicePushNotificationChannelsRequest } from './endpoints/push/remove_push_channels'; +import { ListDevicePushNotificationChannelsRequest } from './endpoints/push/list_push_channels'; +import { AddDevicePushNotificationChannelsRequest } from './endpoints/push/add_push_channels'; +import { KeySet, ResultCallback, SendRequestFunction, StatusCallback } from './types/api'; +import { RemoveDevicePushNotificationRequest } from './endpoints/push/remove_device'; +import * as PushNotifications from './types/api/push-notifications'; +import * as Push from './types/api/push'; + +export default class PubNubPushNotifications { + constructor( + private readonly keySet: KeySet, + /* eslint-disable @typescript-eslint/no-explicit-any */ + private readonly sendRequest: SendRequestFunction, + ) {} + + // -------------------------------------------------------- + // ---------------------- Audit API ----------------------- + // -------------------------------------------------------- + // region Audit API + + /** + * Fetch device's push notification enabled channels. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public listChannels( + parameters: Push.ListDeviceChannelsParameters, + callback: ResultCallback, + ): void; + + /** + * Fetch device's push notification enabled channels. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous get device channels response. + */ + public async listChannels(parameters: Push.ListDeviceChannelsParameters): Promise; + + /** + * Fetch device's push notification enabled channels. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get device channels response or `void` in case if `callback` provided. + */ + public async listChannels( + parameters: Push.ListDeviceChannelsParameters, + callback?: ResultCallback, + ): Promise { + const request = new ListDevicePushNotificationChannelsRequest({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // -------------------------------------------------------- + // ---------------------- Manage API ---------------------- + // -------------------------------------------------------- + // region Manage API + + /** + * Enable push notifications on channels for device. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public addChannels(parameters: Push.ManageDeviceChannelsParameters, callback: StatusCallback): void; + + /** + * Enable push notifications on channels for device. + * + * @param parameters - Request configuration parameters. + */ + public async addChannels(parameters: Push.ManageDeviceChannelsParameters): Promise; + + /** + * Enable push notifications on channels for device. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + */ + public async addChannels(parameters: Push.ManageDeviceChannelsParameters, callback?: StatusCallback): Promise { + const request = new AddDevicePushNotificationChannelsRequest({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + + /** + * Disable push notifications on channels for device. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public removeChannels(parameters: Push.ManageDeviceChannelsParameters, callback: StatusCallback): void; + + /** + * Disable push notifications on channels for device. + * + * @param parameters - Request configuration parameters. + */ + public async removeChannels(parameters: Push.ManageDeviceChannelsParameters): Promise; + + /** + * Disable push notifications on channels for device. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + */ + public async removeChannels( + parameters: Push.ManageDeviceChannelsParameters, + callback?: StatusCallback, + ): Promise { + const request = new RemoveDevicePushNotificationChannelsRequest({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + + /** + * Disable push notifications for device. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public deleteDevice(parameters: Push.RemoveDeviceParameters, callback: StatusCallback): void; + + /** + * Disable push notifications for device. + * + * @param parameters - Request configuration parameters. + */ + public async deleteDevice(parameters: Push.RemoveDeviceParameters): Promise; + + /** + * Disable push notifications for device. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + */ + public async deleteDevice(parameters: Push.RemoveDeviceParameters, callback?: StatusCallback): Promise { + const request = new RemoveDevicePushNotificationRequest({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + + // endregion +} diff --git a/src/core/types/api/access-panager.ts b/src/core/types/api/access-panager.ts new file mode 100644 index 000000000..068d1afe2 --- /dev/null +++ b/src/core/types/api/access-panager.ts @@ -0,0 +1,564 @@ +// region Grant token +/** + * Metadata which will be associated with access token. + */ +export type Metadata = Record; + +/** + * Channel-specific token permissions. + */ +export type ChannelTokenPermissions = { + /** + * Whether `read` operations are permitted for corresponding level or not. + */ + read?: boolean; + + /** + * Whether `write` operations are permitted for corresponding level or not. + */ + write?: boolean; + + /** + * Whether `get` operations are permitted for corresponding level or not. + */ + get?: boolean; + + /** + * Whether `manage` operations are permitted for corresponding level or not. + */ + manage?: boolean; + + /** + * Whether `update` operations are permitted for corresponding level or not. + */ + update?: boolean; + + /** + * Whether `join` operations are permitted for corresponding level or not. + */ + join?: boolean; + + /** + * Whether `delete` operations are permitted for corresponding level or not. + */ + delete?: boolean; +}; + +/** + * Space-specific token permissions. + */ +type SpaceTokenPermissions = ChannelTokenPermissions; + +/** + * Channel group-specific token permissions. + */ +export type ChannelGroupTokenPermissions = { + /** + * Whether `read` operations are permitted for corresponding level or not. + */ + read?: boolean; + + /** + * Whether `manage` operations are permitted for corresponding level or not. + */ + manage?: boolean; +}; + +/** + * Uuid-specific token permissions. + */ +export type UuidTokenPermissions = { + /** + * Whether `get` operations are permitted for corresponding level or not. + */ + get?: boolean; + + /** + * Whether `update` operations are permitted for corresponding level or not. + */ + update?: boolean; + + /** + * Whether `delete` operations are permitted for corresponding level or not. + */ + delete?: boolean; +}; + +/** + * User-specific token permissions. + */ +type UserTokenPermissions = UuidTokenPermissions; + +/** + * Generate access token with permissions. + * + * Generate time-limited access token with required permissions for App Context objects. + */ +export type ObjectsGrantTokenParameters = { + /** + * Total number of minutes for which the token is valid. + * + * The minimum allowed value is `1`. + * The maximum is `43,200` minutes (`30` days). + */ + ttl: number; + + /** + * Object containing resource permissions. + */ + resources?: { + /** + * Object containing `spaces` metadata permissions. + */ + spaces?: Record; + + /** + * Object containing `users` permissions. + */ + users?: Record; + }; + + /** + * Object containing permissions to multiple resources specified by a RegEx pattern. + */ + patterns?: { + /** + * Object containing `spaces` metadata permissions. + */ + spaces?: Record; + + /** + * Object containing `users` permissions. + */ + users?: Record; + }; + + /** + * Extra metadata to be published with the request. + * + * **Important:** Values must be scalar only; `arrays` or `objects` aren't supported. + */ + meta?: Metadata; + + /** + * Single `userId` which is authorized to use the token to make API requests to PubNub. + */ + authorizedUserId?: string; +}; + +/** + * Generate token with permissions. + * + * Generate time-limited access token with required permissions for resources. + */ +export type GrantTokenParameters = { + /** + * Total number of minutes for which the token is valid. + * + * The minimum allowed value is `1`. + * The maximum is `43,200` minutes (`30` days). + */ + ttl: number; + + /** + * Object containing resource permissions. + */ + resources?: { + /** + * Object containing `uuid` metadata permissions. + */ + uuids?: Record; + + /** + * Object containing `channel` permissions. + */ + channels?: Record; + + /** + * Object containing `channel group` permissions. + */ + groups?: Record; + }; + + /** + * Object containing permissions to multiple resources specified by a RegEx pattern. + */ + patterns?: { + /** + * Object containing `uuid` metadata permissions to apply to all `uuids` matching the RegEx + * pattern. + */ + uuids?: Record; + + /** + * Object containing `channel` permissions to apply to all `channels` matching the RegEx + * pattern. + */ + channels?: Record; + + /** + * Object containing `channel group` permissions to apply to all `channel groups` matching the + * RegEx pattern. + */ + groups?: Record; + }; + + /** + * Extra metadata to be published with the request. + * + * **Important:** Values must be scalar only; `arrays` or `objects` aren't supported. + */ + meta?: Metadata; + + /** + * Single `uuid` which is authorized to use the token to make API requests to PubNub. + */ + authorized_uuid?: string; +}; + +/** + * Response with generated access token. + */ +export type GrantTokenResponse = string; +// endregion + +// region Revoke +export type RevokeParameters = { + /** + * Access token for which permissions should be revoked. + */ + token: string; +}; + +/** + * Response with revoked access token. + */ +export type RevokeTokenResponse = Record; +// endregion + +// -------------------------------------------------------- +// --------------------- Deprecated ----------------------- +// -------------------------------------------------------- +// region Deprecated + +/** + * Channel-specific permissions. + * + * Permissions include objects to the App Context Channel object as well. + */ +type ChannelPermissions = { + /** + * Whether `read` operations are permitted for corresponding level or not. + */ + r?: 0 | 1; + + /** + * Whether `write` operations are permitted for corresponding level or not. + */ + w?: 0 | 1; + + /** + * Whether `delete` operations are permitted for corresponding level or not. + */ + d?: 0 | 1; + + /** + * Whether `get` operations are permitted for corresponding level or not. + */ + g?: 0 | 1; + + /** + * Whether `update` operations are permitted for corresponding level or not. + */ + u?: 0 | 1; + + /** + * Whether `manage` operations are permitted for corresponding level or not. + */ + m?: 0 | 1; + + /** + * Whether `join` operations are permitted for corresponding level or not. + */ + j?: 0 | 1; + + /** + * Duration for which permissions has been granted. + */ + ttl?: number; +}; + +/** + * Channel group-specific permissions. + */ +type ChannelGroupPermissions = { + /** + * Whether `read` operations are permitted for corresponding level or not. + */ + r?: 0 | 1; + + /** + * Whether `manage` operations are permitted for corresponding level or not. + */ + m?: 0 | 1; + + /** + * Duration for which permissions has been granted. + */ + ttl?: number; +}; + +/** + * App Context User-specific permissions. + */ +type UserPermissions = { + /** + * Whether `get` operations are permitted for corresponding level or not. + */ + g?: 0 | 1; + + /** + * Whether `update` operations are permitted for corresponding level or not. + */ + u?: 0 | 1; + + /** + * Whether `delete` operations are permitted for corresponding level or not. + */ + d?: 0 | 1; + + /** + * Duration for which permissions has been granted. + */ + ttl?: number; +}; + +/** + * Common permissions audit response content. + */ +type BaseAuditResponse< + Level extends 'channel' | 'channel+auth' | 'channel-group' | 'channel-group+auth' | 'user' | 'subkey', +> = { + /** + * Permissions level. + */ + level: Level; + + /** + * Subscription key at which permissions has been granted. + */ + subscribe_key: string; + + /** + * Duration for which permissions has been granted. + */ + ttl?: number; +}; + +/** + * Auth keys permissions for specified `level`. + */ +type AuthKeysPermissions = { + /** + * Auth keys-based permissions for specified `level` permission. + */ + auths: Record; +}; + +/** + * Single channel permissions audit result. + */ +type ChannelPermissionsResponse = BaseAuditResponse<'channel+auth'> & { + /** + * Name of channel for which permissions audited. + */ + channel: string; +} & AuthKeysPermissions; + +/** + * Multiple channels permissions audit result. + */ +type ChannelsPermissionsResponse = BaseAuditResponse<'channel'> & { + /** + * Per-channel permissions. + */ + channels: Record>; +}; + +/** + * Single channel group permissions result. + */ +type ChannelGroupPermissionsResponse = BaseAuditResponse<'channel-group+auth'> & { + /** + * Name of channel group for which permissions audited. + */ + 'channel-group': string; +} & AuthKeysPermissions; + +/** + * Multiple channel groups permissions audit result. + */ +type ChannelGroupsPermissionsResponse = BaseAuditResponse<'channel'> & { + /** + * Per-channel group permissions. + */ + 'channel-groups': Record>; +}; + +/** + * App Context User permissions audit result. + */ +type UserPermissionsResponse = BaseAuditResponse<'user'> & { + /** + * Name of channel for which `user` permissions audited. + */ + channel: string; +} & AuthKeysPermissions; + +/** + * Global sub-key level permissions audit result. + */ +type SubKeyPermissionsResponse = BaseAuditResponse<'subkey'> & { + /** + * Per-channel permissions. + */ + channels: Record>; + + /** + * Per-channel group permissions. + */ + 'channel-groups': Record>; + + /** + * Per-object permissions. + */ + objects: Record>; +}; + +/** + * Response with permission information. + */ +export type PermissionsResponse = + | ChannelPermissionsResponse + | ChannelsPermissionsResponse + | ChannelGroupPermissionsResponse + | ChannelGroupsPermissionsResponse + | UserPermissionsResponse + | SubKeyPermissionsResponse; + +// region Audit +/** + * Audit permissions for provided auth keys / global permissions. + * + * Audit permissions on specific channel and / or channel group for the set of auth keys. + */ +export type AuditParameters = { + /** + * Name of channel for which channel-based permissions should be checked for {@link authKeys}. + */ + channel?: string; + + /** + * Name of channel group for which channel group-based permissions should be checked for {@link authKeys}. + */ + channelGroup?: string; + + /** + * List of auth keys for which permissions should be checked. + * + * Leave this empty to check channel / group -based permissions or global permissions. + * + * @default `[]` + */ + authKeys?: string[]; +}; +// endregion + +// region Grant +/** + * Grant permissions for provided auth keys / global permissions. + * + * Grant permissions on specific channel and / or channel group for the set of auth keys. + */ +export type GrantParameters = { + /** + * List of channels for which permissions should be granted. + */ + channels?: string[]; + + /** + * List of channel groups for which permissions should be granted. + */ + channelGroups?: string[]; + + /** + * List of App Context UUID for which permissions should be granted. + */ + uuids?: string[]; + + /** + * List of auth keys for which permissions should be granted on specified objects. + * + * Leave this empty to grant channel / group -based permissions or global permissions. + */ + authKeys?: string[]; + + /** + * Whether `read` operations are permitted for corresponding level or not. + * + * @default `false` + */ + read?: boolean; + + /** + * Whether `write` operations are permitted for corresponding level or not. + * + * @default `false` + */ + write?: boolean; + + /** + * Whether `delete` operations are permitted for corresponding level or not. + * + * @default `false` + */ + delete?: boolean; + + /** + * Whether `get` operations are permitted for corresponding level or not. + * + * @default `false` + */ + get?: boolean; + + /** + * Whether `update` operations are permitted for corresponding level or not. + * + * @default `false` + */ + update?: boolean; + + /** + * Whether `manage` operations are permitted for corresponding level or not. + * + * @default `false` + */ + manage?: boolean; + + /** + * Whether `join` operations are permitted for corresponding level or not. + * + * @default `false` + */ + join?: boolean; + + /** + * For how long permissions should be effective (in minutes). + * + * @default `1440` + */ + ttl?: number; +}; +// endregion + +// endregion diff --git a/src/core/types/api/app-context.ts b/src/core/types/api/app-context.ts new file mode 100644 index 000000000..ce5c5c51a --- /dev/null +++ b/src/core/types/api/app-context.ts @@ -0,0 +1,1104 @@ +/** + * Partial nullability helper type. + */ +type PartialNullable = { + [P in keyof T]?: T[P] | null; +}; + +/** + * Custom data which should be associated with metadata objects or their relation. + */ +export type CustomData = { + [key: string]: string | number | boolean | null; +}; + +/** + * Type provides shape of App Context parameters which is common to the all objects types to + * be updated. + */ +type ObjectParameters = { + custom?: Custom; +}; + +/** + * Type provides shape of App Context object which is common to the all objects types received + * from the PubNub service. + */ +export type ObjectData = { + /** + * Unique App Context object identifier. + * + * **Important:** For channel it is different from the channel metadata object name. + */ + id: string; + + /** + * Last date and time when App Context object has been updated. + * + * String built from date using ISO 8601. + */ + updated: string; + + /** + * App Context version hash. + */ + eTag: string; + + /** + * Additional data associated with App Context object. + * + * **Important:** Values must be scalars; only arrays or objects are supported. + * {@link /docs/sdks/javascript/api-reference/objects#app-context-filtering-language-definition|App Context + * filtering language} doesn’t support filtering by custom properties. + */ + custom?: Custom | null; +}; + +/** + * Type provides shape of object which let establish relation between metadata objects. + */ +type ObjectsRelation = { + /** + * App Context object unique identifier. + */ + id: string; + + /** + * App Context objects relation status. + */ + status?: string; + + /** + * Additional data associated with App Context object relation (membership or members). + * + * **Important:** Values must be scalars; only arrays or objects are supported. + * {@link /docs/sdks/javascript/api-reference/objects#app-context-filtering-language-definition|App Context + * filtering language} doesn’t support filtering by custom properties. + */ + custom?: Custom; +}; + +/** + * Response page cursor. + */ +type Page = { + /** + * Random string returned from the server, indicating a specific position in a data set. + * + * Used for forward pagination, it fetches the next page, allowing you to continue from where + * you left off. + */ + next?: string; + + /** + * Random string returned from the server, indicating a specific position in a data set. + * + * Used for backward pagination, it fetches the previous page, enabling access to earlier + * data. + * + * **Important:** Ignored if the `next` parameter is supplied. + */ + prev?: string; +}; + +/** + * Metadata objects include options. + * + * Allows to configure what additional information should be included into service response. + */ +type IncludeOptions = { + /** + * Whether to include total number of App Context objects in the response. + * + * @default `false` + */ + totalCount?: boolean; + + /** + * Whether to include App Context object `custom` field in the response. + * + * @default `false` + */ + customFields?: boolean; +}; + +/** + * Membership objects include options. + * + * Allows to configure what additional information should be included into service response. + */ +type MembershipsIncludeOptions = IncludeOptions & { + /** + * Whether to include all {@link ChannelMetadata} fields in the response. + * + * @default `false` + */ + channelFields?: boolean; + + /** + * Whether to include {@link ChannelMetadata} `custom` field in the response. + * + * @default `false` + */ + customChannelFields?: boolean; + + /** + * Whether to include the membership's status field in the response. + * + * @default `false` + */ + statusField?: boolean; + + /** + * Whether to include the channel's status field in the response. + * + * @default `false` + */ + channelStatusField?: boolean; + + /** + * Whether to include channel's type fields in the response. + * + * @default `false` + */ + channelTypeField?: boolean; +}; + +/** + * Members objects include options. + * + * Allows to configure what additional information should be included into service response. + */ +type MembersIncludeOptions = IncludeOptions & { + /** + * Whether to include all {@link UUIMetadata} fields in the response. + * + * @default `false` + */ + UUIDFields?: boolean; + + /** + * Whether to include {@link UUIMetadata} `custom` field in the response. + * + * @default `false` + */ + customUUIDFields?: boolean; + + /** + * Whether to include the members's status field in the response. + * + * @default `false` + */ + statusField?: boolean; + + /** + * Whether to include the user's status field in the response. + * + * @default `false` + */ + UUIDStatusField?: boolean; + + /** + * Whether to include user's type fields in the response. + * + * @default `false` + */ + UUIDTypeField?: boolean; +}; + +/** + * Type provides shape of App Context parameters which is common to the all objects types to + * fetch them by pages. + */ +type PagedRequestParameters = { + /** + * Fields which can be additionally included into response. + */ + include?: Include; + + /** + * Expression used to filter the results. + * + * Only objects whose properties satisfy the given expression are returned. The filter language is + * {@link /docs/sdks/javascript/api-reference/objects#app-context-filtering-language-definition|defined here}. + */ + filter?: string; + + /** + * Fetched App Context objects sorting options. + */ + sort?: Sort; + + /** + * Number of objects to return in response. + * + * **Important:** Maximum for this API is `100` objects per-response. + * + * @default `100` + */ + limit?: number; + + /** + * Response pagination configuration. + */ + page?: Page; +}; + +/** + * Type provides shape of App Context object fetch response which is common to the all objects + * types received from the PubNub service. + */ +type ObjectResponse = { + /** + * App Context objects list fetch result status code. + */ + status: number; + + /** + * Received App Context object information. + */ + data: ObjectType; +}; + +/** + * Type provides shape of App Context objects fetch response which is common to the all + * objects types received from the PubNub service. + */ +type PagedResponse = ObjectResponse & { + /** + * Total number of App Context objects in the response. + */ + totalCount?: number; + + /** + * Random string returned from the server, indicating a specific position in a data set. + * + * Used for forward pagination, it fetches the next page, allowing you to continue from where + * you left off. + */ + next?: string; + + /** + * Random string returned from the server, indicating a specific position in a data set. + * + * Used for backward pagination, it fetches the previous page, enabling access to earlier + * data. + * + * **Important:** Ignored if the `next` parameter is supplied. + */ + prev?: string; +}; + +/** + * Key-value pair of a property to sort by, and a sort direction. + */ +type MetadataSortingOptions = + | keyof Omit + | ({ [K in keyof Omit]?: 'asc' | 'desc' | null } & { + [key: `custom.${string}`]: 'asc' | 'desc' | null; + }); + +type RelationSortingOptions = { + [K in keyof Omit as `${O}.${string & K}`]: 'asc' | 'desc' | null; +}; + +/** + * Key-value pair of a property to sort by, and a sort direction. + */ +type MembershipsSortingOptions2 = + | keyof RelationSortingOptions + | keyof RelationSortingOptions + | (RelationSortingOptions & + RelationSortingOptions & { + [key: `channel.custom.${string}`]: 'asc' | 'desc' | null; + [key: `space.custom.${string}`]: 'asc' | 'desc' | null; + }); + +/** + * Key-value pair of a property to sort by, and a sort direction. + */ +type MembershipsSortingOptions = + | 'channel.id' + | 'channel.name' + | 'channel.description' + | 'channel.updated' + | 'space.id' + | 'space.name' + | 'space.description' + | 'space.updated' + | 'updated' + | { + /** + * Sort results by channel's `id` in ascending (`asc`) or descending (`desc`) order. + * + * Specify `null` for default sorting direction (ascending). + */ + 'channel.id'?: 'asc' | 'desc' | null; + + /** + * Sort results by channel's `name` in ascending (`asc`) or descending (`desc`) order. + * + * Specify `null` for default sorting direction (ascending). + */ + 'channel.name'?: 'asc' | 'desc' | null; + + /** + * Sort results by channel's `description` in ascending (`asc`) or descending (`desc`) order. + * + * Specify `null` for default sorting direction (ascending). + */ + 'channel.description'?: 'asc' | 'desc' | null; + + /** + * Sort results by channel's `update` in ascending (`asc`) or descending (`desc`) order. + * + * Specify `null` for default sorting direction (ascending). + */ + 'channel.updated'?: 'asc' | 'desc' | null; + + /** + * Sort results by channel's `id` in ascending (`asc`) or descending (`desc`) order. + * + * Specify `null` for default sorting direction (ascending). + * + * @deprecated Use `channel.id` instead. + */ + 'space.id'?: 'asc' | 'desc' | null; + + /** + * Sort results by channel's `name` in ascending (`asc`) or descending (`desc`) order. + * + * Specify `null` for default sorting direction (ascending). + * + * @deprecated Use `channel.name` instead. + */ + 'space.name'?: 'asc' | 'desc' | null; + + /** + * Sort results by channel's `description` in ascending (`asc`) or descending (`desc`) order. + * + * Specify `null` for default sorting direction (ascending). + * + * @deprecated Use `channel.name` instead. + */ + 'space.description'?: 'asc' | 'desc' | null; + + /** + * Sort results by channel's `update` in ascending (`asc`) or descending (`desc`) order. + * + * Specify `null` for default sorting direction (ascending). + * + * @deprecated Use `channel.updated` instead. + */ + 'space.updated'?: 'asc' | 'desc' | null; + + /** + * Sort results by `updated` in ascending (`asc`) or descending (`desc`) order. + * + * Specify `null` for default sorting direction (ascending). + */ + updated?: 'asc' | 'desc' | null; + }; + +/** + * Key-value pair of a property to sort by, and a sort direction. + */ +type MembersSortingOptions = + | 'uuid.id' + | 'uuid.name' + | 'uuid.updated' + | 'user.id' + | 'user.name' + | 'user.updated' + | 'updated' + | { + /** + * Sort results by user's `id` in ascending (`asc`) or descending (`desc`) order. + * + * Specify `null` for default sorting direction (ascending). + */ + 'uuid.id'?: 'asc' | 'desc' | null; + + /** + * Sort results by user's `name` in ascending (`asc`) or descending (`desc`) order. + * + * Specify `null` for default sorting direction (ascending). + */ + 'uuid.name'?: 'asc' | 'desc' | null; + + /** + * Sort results by user's `update` in ascending (`asc`) or descending (`desc`) order. + * + * Specify `null` for default sorting direction (ascending). + */ + 'uuid.updated'?: 'asc' | 'desc' | null; + + /** + * Sort results by user's `id` in ascending (`asc`) or descending (`desc`) order. + * + * Specify `null` for default sorting direction (ascending). + * + * @deprecated Use `uuid.id` instead. + */ + 'user.id'?: 'asc' | 'desc' | null; + + /** + * Sort results by user's `name` in ascending (`asc`) or descending (`desc`) order. + * + * Specify `null` for default sorting direction (ascending). + * + * @deprecated Use `uuid.name` instead. + */ + 'user.name'?: 'asc' | 'desc' | null; + + /** + * Sort results by user's `update` in ascending (`asc`) or descending (`desc`) order. + * + * Specify `null` for default sorting direction (ascending). + * + * @deprecated Use `uuid.updated` instead. + */ + 'user.updated'?: 'asc' | 'desc' | null; + + /** + * Sort results by `updated` in ascending (`asc`) or descending (`desc`) order. + * + * Specify `null` for default sorting direction (ascending). + */ + updated?: 'asc' | 'desc' | null; + }; + +// -------------------------------------------------------- +// --------------------- Common API ----------------------- +// -------------------------------------------------------- + +/** + * Fetch All UUID or Channel Metadata request parameters. + */ +export type GetAllMetadataParameters = PagedRequestParameters< + IncludeOptions, + MetadataSortingOptions +>; + +// -------------------------------------------------------- +// ---------------------- UUID API ------------------------ +// -------------------------------------------------------- + +/** + * Type which describes own UUID metadata object fields. + */ +type UUIDMetadataFields = { + /** + * Display name for the user. + */ + name?: string; + + /** + * The user's email address. + */ + email?: string; + + /** + * User's identifier in an external system. + */ + externalId?: string; + + /** + * The URL of the user's profile picture. + */ + profileUrl?: string; + + /** + * User's object type information. + */ + type?: string; + + /** + * User's object status. + */ + status?: string; +}; + +/** + * Updated UUID metadata object. + * + * Type represents updated UUID metadata object which will be pushed to the PubNub service. + */ +type UUIDMetadata = ObjectParameters & Partial; + +/** + * Received UUID metadata object. + * + * Type represents UUID metadata retrieved from the PubNub service. + */ +export type UUIDMetadataObject = ObjectData & PartialNullable; + +/** + * Response with fetched page of UUID metadata objects. + */ +export type GetAllUUIDMetadataResponse = PagedResponse>; + +/** + * Fetch UUID Metadata request parameters. + */ +export type GetUUIDMetadataParameters = { + /** + * Unique user identifier. + * + * **Important:** If not supplied then current user's uuid is used. + * + * @default Current `uuid`. + */ + uuid?: string; + + /** + * Unique user identifier. + * + * **Important:** If not supplied then current user's uuid is used. + * + * @default Current `userId`. + * + * @deprecated Use `getUUIDMetadata()` method instead. + */ + userId?: string; + + /** + * Fields which can be additionally included into response. + */ + include?: Omit; +}; + +/** + * Response with requested UUID metadata object. + */ +export type GetUUIDMetadataResponse = ObjectResponse>; + +/** + * Update UUID Metadata request parameters. + */ +export type SetUUIDMetadataParameters = { + /** + * Unique user identifier. + * + * **Important:** If not supplied then current user's uuid is used. + * + * @default Current `uuid`. + */ + uuid?: string; + + /** + * Unique user identifier. + * + * **Important:** If not supplied then current user's uuid is used. + * + * @default Current `userId`. + * + * @deprecated Use `setUUIDMetadata()` method instead. + */ + userId?: string; + + /** + * Metadata, which should be associated with UUID. + */ + data: UUIDMetadata; + + /** + * Fields which can be additionally included into response. + */ + include?: Omit; +}; + +/** + * Response with result of the UUID metadata object update. + */ +export type SetUUIDMetadataResponse = ObjectResponse>; + +/** + * Remove UUID Metadata request parameters. + */ +export type RemoveUUIDMetadataParameters = { + /** + * Unique user identifier. + * + * **Important:** If not supplied then current user's uuid is used. + * + * @default Current `uuid`. + */ + uuid?: string; + + /** + * Unique user identifier. + * + * **Important:** If not supplied then current user's uuid is used. + * + * @default Current `userId`. + * + * @deprecated Use `removeUUIDMetadata()` method instead. + */ + userId?: string; +}; + +/** + * Response with result of the UUID metadata removal. + */ +export type RemoveUUIDMetadataResponse = ObjectResponse>; + +// -------------------------------------------------------- +// --------------------- Channel API ---------------------- +// -------------------------------------------------------- + +/** + * Type which describes own Channel metadata object fields. + */ +type ChannelMetadataFields = { + /** + * Name of a channel. + */ + name?: string; + + /** + * Description of a channel. + */ + description?: string; + + /** + * Channel's object type information. + */ + type?: string; + + /** + * Channel's object status. + */ + status?: string; +}; + +/** + * Updated channel metadata object. + * + * Type represents updated channel metadata object which will be pushed to the PubNub service. + */ +type ChannelMetadata = ObjectParameters & Partial; + +/** + * Received channel metadata object. + * + * Type represents chanel metadata retrieved from the PubNub service. + */ +export type ChannelMetadataObject = ObjectData & + PartialNullable; + +/** + * Response with fetched page of channel metadata objects. + */ +export type GetAllChannelMetadataResponse = PagedResponse>; + +/** + * Fetch Channel Metadata request parameters. + */ +export type GetChannelMetadataParameters = { + /** + * Channel name. + */ + channel: string; + + /** + * Space identifier. + * + * @deprecated Use `getChannelMetadata()` method instead. + */ + spaceId?: string; + + /** + * Fields which can be additionally included into response. + */ + include?: Omit; +}; + +/** + * Response with requested channel metadata object. + */ +export type GetChannelMetadataResponse = ObjectResponse>; + +/** + * Update Channel Metadata request parameters. + */ +export type SetChannelMetadataParameters = { + /** + * Channel name. + */ + channel: string; + + /** + * Space identifier. + * + * @deprecated Use `setChannelMetadata()` method instead. + */ + spaceId?: string; + + /** + * Metadata, which should be associated with UUID. + */ + data: ChannelMetadata; + + /** + * Fields which can be additionally included into response. + */ + include?: Omit; +}; + +/** + * Response with result of the channel metadata object update. + */ +export type SetChannelMetadataResponse = ObjectResponse>; + +/** + * Remove Channel Metadata request parameters. + */ +export type RemoveChannelMetadataParameters = { + /** + * Channel name. + */ + channel: string; + + /** + * Space identifier. + * + * @deprecated Use `removeChannelMetadata()` method instead. + */ + spaceId?: string; +}; + +/** + * Response with result of the channel metadata removal. + */ +export type RemoveChannelMetadataResponse = ObjectResponse>; + +// -------------------------------------------------------- +// ------------------ Memberships API --------------------- +// -------------------------------------------------------- + +/** + * Related channel metadata object. + * + * Type represents chanel metadata which has been used to create membership relation with UUID. + */ +type MembershipsObject = Omit< + ObjectData, + 'id' +> & { + channel: ChannelMetadataObject | { id: string }; +}; + +/** + * Response with fetched page of UUID membership objects. + */ +type MembershipsResponse = PagedResponse< + MembershipsObject +>; + +/** + * Fetch Memberships request parameters. + */ +export type GetMembershipsParameters = PagedRequestParameters & { + /** + * Unique user identifier. + * + * **Important:** If not supplied then current user's uuid is used. + * + * @default Current `uuid`. + */ + uuid?: string; + + /** + * Unique user identifier. + * + * **Important:** If not supplied then current user's uuid is used. + * + * @default Current `uuidId`. + * + * @deprecated Use `uuid` field instead. + */ + userId?: string; +}; + +/** + * Response with requested channel memberships information. + */ +export type GetMembershipsResponse< + MembershipCustom extends CustomData, + ChannelCustom extends CustomData, +> = MembershipsResponse; + +/** + * Update Memberships request parameters. + */ +export type SetMembershipsParameters = PagedRequestParameters< + Omit, + MembershipsSortingOptions +> & { + /** + * Unique user identifier. + * + * **Important:** If not supplied then current user's uuid is used. + * + * @default Current `uuid`. + */ + uuid?: string; + + /** + * Unique user identifier. + * + * **Important:** If not supplied then current user's uuid is used. + * + * @default Current `userId`. + * + * @deprecated Use `uuid` field instead. + */ + userId?: string; + + /** + * List of channels with which UUID membership should be established. + */ + channels: Array>; + + /** + * List of channels with which UUID membership should be established. + * + * @deprecated Use `channels` field instead. + */ + spaces?: Array< + | string + | (Omit, 'id'> & { + /** + * Unique Space object identifier. + */ + spaceId: string; + }) + >; +}; + +/** + * Response with requested channel memberships information change. + */ +export type SetMembershipsResponse< + MembershipCustom extends CustomData, + ChannelCustom extends CustomData, +> = MembershipsResponse; + +/** + * Remove Memberships request parameters. + */ +export type RemoveMembershipsParameters = PagedRequestParameters< + MembershipsIncludeOptions, + MembershipsSortingOptions +> & { + /** + * Unique user identifier. + * + * **Important:** If not supplied then current user's uuid is used. + * + * @default Current `uuid`. + */ + uuid?: string; + + /** + * Unique user identifier. + * + * **Important:** If not supplied then current user's uuid is used. + * + * @default Current `userId`. + * + * @deprecated Use {@link uuid} field instead. + */ + userId?: string; + + /** + * List of channels for which membership which UUID should be removed. + */ + channels: string[]; + + /** + * List of space names for which membership which UUID should be removed. + * + * @deprecated Use {@link channels} field instead. + */ + spaceIds?: string[]; +}; + +/** + * Response with remaining memberships. + */ +export type RemoveMembershipsResponse< + MembershipCustom extends CustomData, + ChannelCustom extends CustomData, +> = MembershipsResponse; + +// -------------------------------------------------------- +// -------------------- Members API ----------------------- +// -------------------------------------------------------- + +/** + * Related UUID metadata object. + * + * Type represents UUID metadata which has been used to when added members to the channel. + */ +type MembersObject = Omit< + ObjectData, + 'id' +> & { + uuid: UUIDMetadataObject | { id: string }; +}; + +/** + * Response with fetched page of channel member objects. + */ +type MembersResponse = PagedResponse< + MembersObject +>; + +/** + * Fetch Members request parameters. + */ +export type GetMembersParameters = PagedRequestParameters & { + /** + * Channel name. + */ + channel: string; + + /** + * Space identifier. + * + * @deprecated Use `channel` field instead. + */ + spaceId?: string; +}; + +/** + * Response with requested channel memberships information. + */ +export type GetMembersResponse = MembersResponse< + MembersCustom, + UUIDCustom +>; + +/** + * Update Members request parameters. + */ +export type SetChannelMembersParameters = PagedRequestParameters< + Omit, + MembersSortingOptions +> & { + /** + * Channel name. + */ + channel: string; + + /** + * Space identifier. + * + * @deprecated Use `channel` field instead. + */ + spaceId?: string; + + /** + * List of UUIDs which should be added as `channel` members. + */ + uuids: Array>; + + /** + * List of UUIDs which should be added as `channel` members. + * + * @deprecated Use `uuids` field instead. + */ + users?: Array< + | string + | (Omit, 'id'> & { + /** + * Unique User object identifier. + */ + userId: string; + }) + >; +}; + +/** + * Response with requested channel members information change. + */ +export type SetMembersResponse = MembersResponse< + MemberCustom, + UUIDCustom +>; +/** + * Remove Members request parameters. + */ +export type RemoveMembersParameters = PagedRequestParameters & { + /** + * Channel name. + */ + channel: string; + + /** + * Space identifier. + * + * @deprecated Use {@link channel} field instead. + */ + spaceId?: string; + + /** + * List of UUIDs which should be removed from the `channel` members list. + * removed. + */ + uuids: string[]; + + /** + * List of user identifiers which should be removed from the `channel` members list. + * removed. + * + * @deprecated Use {@link uuids} field instead. + */ + userIds?: string[]; +}; + +/** + * Response with remaining members. + */ +export type RemoveMembersResponse = MembersResponse< + MemberCustom, + UUIDCustom +>; + +// region Deprecated +/** + * Related User metadata object. + * + * Type represents User metadata which has been used to when added members to the Space. + */ +type UserMembersObject = Omit< + ObjectData, + 'id' +> & { + user: UUIDMetadataObject | { id: string }; +}; + +/** + * Response with fetched page of Space member objects. + */ +export type UserMembersResponse = PagedResponse< + UserMembersObject +>; + +type SpaceMembershipObject = Omit< + ObjectData, + 'id' +> & { + space: ChannelMetadataObject | { id: string }; +}; + +/** + * Response with fetched page of User membership objects. + */ +export type SpaceMembershipsResponse< + MembershipCustom extends CustomData, + ChannelCustom extends CustomData, +> = PagedResponse>; +// endregion diff --git a/src/core/types/api/channel-groups.ts b/src/core/types/api/channel-groups.ts new file mode 100644 index 000000000..79ea23091 --- /dev/null +++ b/src/core/types/api/channel-groups.ts @@ -0,0 +1,64 @@ +/** + * Add or remove Channels to the channel group request parameters. + */ +export type ManageChannelGroupChannelsParameters = { + /** + * Name of the channel group for which channels list should be changed. + */ + channelGroup: string; + + /** + * List of channels to be added or removed. + */ + channels: string[]; +}; + +/** + * Channel group channels list manage response. + */ +export type ManageChannelGroupChannelsResponse = Record; + +/** + * Response with result of the all channel groups list. + */ +export type ListAllChannelGroupsResponse = { + /** + * All channel groups with channels. + */ + groups: string[]; +}; + +/** + * List Channel Group Channels request parameters. + */ +export type ListChannelGroupChannelsParameters = { + /** + * Name of the channel group for which list of channels should be retrieved. + */ + channelGroup: string; +}; + +/** + * Response with result of the list channel group channels. + */ +export type ListChannelGroupChannelsResponse = { + /** + * List of the channels registered withing specified channel group. + */ + channels: string[]; +}; + +/** + * Delete Channel Group request parameters. + */ +export type DeleteChannelGroupParameters = { + /** + * Name of the channel group which should be removed. + */ + channelGroup: string; +}; + +/** + * Delete channel group response. + */ +export type DeleteChannelGroupResponse = Record; diff --git a/src/core/types/api/file-sharing.ts b/src/core/types/api/file-sharing.ts new file mode 100644 index 000000000..90200f69a --- /dev/null +++ b/src/core/types/api/file-sharing.ts @@ -0,0 +1,454 @@ +/** + * File Sharing REST API module. + */ + +import { PubNubFileInterface } from '../file'; +import { Payload } from './index'; + +// -------------------------------------------------------- +// ----------------------- Common ------------------------- +// -------------------------------------------------------- +// region Common + +/** + * Shared file object. + */ +export type SharedFile = { + /** + * Name with which file has been stored. + */ + name: string; + + /** + * Unique service-assigned file identifier. + */ + id: string; + + /** + * Shared file size. + */ + size: number; + + /** + * ISO 8601 time string when file has been shared. + */ + created: string; +}; +// endregion + +// -------------------------------------------------------- +// --------------------- List Files ----------------------- +// -------------------------------------------------------- +// region List Files + +/** + * List Files request parameters. + */ +export type ListFilesParameters = { + /** + * Name of channel for which list of files should be requested. + */ + channel: string; + + /** + * How many entries return with single response. + */ + limit?: number; + + /** + * Next files list page token. + */ + next?: string; +}; + +/** + * List Files request response. + */ +export type ListFilesResponse = { + /** + * Files list fetch result status code. + */ + status: number; + + /** + * List of fetched file objects. + */ + data: SharedFile[]; + + /** + * Next files list page token. + */ + next: string; + + /** + * Number of retrieved files. + */ + count: number; +}; +// endregion + +// -------------------------------------------------------- +// --------------------- Send File ------------------------ +// -------------------------------------------------------- +// region Send File + +/** + * Send File request parameters. + */ +export type SendFileParameters = Omit & { + /** + * Channel to send the file to. + */ + channel: string; + + /** + * File to send. + */ + file: FileParameters; +}; + +/** + * Send File request response. + */ +export type SendFileResponse = PublishFileMessageResponse & { + /** + * Send file request processing status code. + */ + status: number; + + /** + * Actual file name under which file has been stored. + * + * File name and unique {@link id} can be used to download file from the channel later. + * + * **Important:** Actual file name may be different from the one which has been used during file + * upload. + */ + name: string; + + /** + * Unique file identifier. + * + * Unique file identifier and it's {@link name} can be used to download file from the channel + * later. + */ + id: string; +}; + +/** + * Upload File request parameters. + */ +export type UploadFileParameters = { + /** + * Unique file identifier. + * + * Unique file identifier, and it's {@link fileName} can be used to download file from the channel + * later. + */ + fileId: string; + + /** + * Actual file name under which file has been stored. + * + * File name and unique {@link fileId} can be used to download file from the channel later. + * + * **Note:** Actual file name may be different from the one which has been used during file + * upload. + */ + fileName: string; + + /** + * File which should be uploaded. + */ + file: PubNubFileInterface; + + /** + * Pre-signed file upload Url. + */ + uploadUrl: string; + + /** + * An array of form fields to be used in the pre-signed POST request. + * + * **Important:** Form data fields should be passed in exact same order as received from + * the PubNub service. + */ + formFields: { + /** + * Form data field name. + */ + name: string; + + /** + * Form data field value. + */ + value: string; + }[]; +}; + +/** + * Upload File request response. + */ +export type UploadFileResponse = { + /** + * Upload File request processing status code. + */ + status: number; + + /** + * Service processing result response. + */ + message: Payload; +}; +// endregion + +// -------------------------------------------------------- +// -------------- Generate File Upload Url ---------------- +// -------------------------------------------------------- +// region Generate File Upload Url + +/** + * Generate File Upload URL request parameters. + */ +export type GenerateFileUploadUrlParameters = { + /** + * Name of channel to which file should be uploaded. + */ + channel: string; + + /** + * Actual name of the file which should be uploaded. + */ + name: string; +}; + +/** + * Generation File Upload URL request response. + */ +export type GenerateFileUploadUrlResponse = { + /** + * Unique file identifier. + * + * Unique file identifier, and it's {@link name} can be used to download file from the channel + * later. + */ + id: string; + + /** + * Actual file name under which file has been stored. + * + * File name and unique {@link id} can be used to download file from the channel later. + * + * **Note:** Actual file name may be different from the one which has been used during file + * upload. + */ + name: string; + + /** + * Pre-signed URL for file upload. + */ + url: string; + + /** + * An array of form fields to be used in the pre-signed POST request. + * + * **Important:** Form data fields should be passed in exact same order as received from + * the PubNub service. + */ + formFields: { + /** + * Form data field name. + */ + name: string; + + /** + * Form data field value. + */ + value: string; + }[]; +}; +// endregion + +// -------------------------------------------------------- +// ---------------- Publish File Message ------------------ +// -------------------------------------------------------- +// region Publish File Message + +/** + * Publish File Message request parameters. + */ +export type PublishFileMessageParameters = { + /** + * Name of channel to which file has been sent. + */ + channel: string; + + /** + * File annotation message. + */ + message?: Payload; + + /** + * Custom file and message encryption key. + * + * @deprecated Use {@link Configuration#cryptoModule|cryptoModule} configured for PubNub client + * instance or encrypt file prior {@link PubNub#sendFile|sendFile} method call. + */ + cipherKey?: string; + + /** + * Unique file identifier. + * + * Unique file identifier, and it's {@link fileName} can be used to download file from the channel + * later. + */ + fileId: string; + + /** + * Actual file name under which file has been stored. + * + * File name and unique {@link fileId} can be used to download file from the channel later. + * + * **Note:** Actual file name may be different from the one which has been used during file + * upload. + */ + fileName: string; + + /** + * Whether published file messages should be stored in the channel's history. + * + * **Note:** If `storeInHistory` not specified, then the history configuration on the key is + * used. + * + * @default `true` + */ + storeInHistory?: boolean; + + /** + * How long the message should be stored in the channel's history. + * + * **Note:** If not specified, defaults to the key set's retention value. + * + * @default `0` + */ + ttl?: number; + + /** + * Metadata, which should be associated with published file. + * + * Associated metadata can be utilized by message filtering feature. + */ + meta?: Payload; +}; + +/** + * Publish File Message request response. + */ +export type PublishFileMessageResponse = { + /** + * High-precision time when published file message has been received by the PubNub service. + */ + timetoken: string; +}; +// endregion + +// -------------------------------------------------------- +// -------------------- Download File --------------------- +// -------------------------------------------------------- +// region Download File +/** + * Download File request parameters. + */ +export type DownloadFileParameters = FileUrlParameters & { + /** + * Custom file and message encryption key. + * + * @deprecated Use {@link Configuration#cryptoModule|cryptoModule} configured for PubNub client + * instance or encrypt file prior {@link PubNub#sendFile|sendFile} method call. + */ + cipherKey?: string; +}; +// endregion + +// -------------------------------------------------------- +// ------------- Generate File Download Url --------------- +// -------------------------------------------------------- +// region Generate File Download Url + +/** + * Generate File download Url request parameters. + */ +export type FileUrlParameters = { + /** + * Name of channel where file has been sent. + */ + channel: string; + + /** + * Unique file identifier. + * + * Unique file identifier and it's {@link name} can be used to download file from the channel + * later. + */ + id: string; + + /** + * Actual file name under which file has been stored. + * + * File name and unique {@link id} can be used to download file from the channel later. + * + * **Important:** Actual file name may be different from the one which has been used during file + * upload. + */ + name: string; +}; + +/** + * Generate File Download Url response. + */ +export type FileUrlResponse = string; +// endregion + +// -------------------------------------------------------- +// --------------------- Delete File ---------------------- +// -------------------------------------------------------- +// region Delete File + +/** + * Delete File request parameters. + */ +export type DeleteFileParameters = { + /** + * Name of channel where file has been sent. + */ + channel: string; + + /** + * Unique file identifier. + * + * Unique file identifier and it's {@link name} can be used to download file from the channel + * later. + */ + id: string; + + /** + * Actual file name under which file has been stored. + * + * File name and unique {@link id} can be used to download file from the channel later. + * + * **Important:** Actual file name may be different from the one which has been used during file + * upload. + */ + name: string; +}; + +/** + * Delete File request response. + */ +export type DeleteFileResponse = { + /** + * Delete File request processing status code. + */ + status: number; +}; +// endregion diff --git a/src/core/types/api/history.ts b/src/core/types/api/history.ts new file mode 100644 index 000000000..6bea6b7eb --- /dev/null +++ b/src/core/types/api/history.ts @@ -0,0 +1,475 @@ +import { Payload } from './index'; + +// -------------------------------------------------------- +// --------------------- Get History ---------------------- +// -------------------------------------------------------- +// region Get History + +/** + * Get history request parameters. + */ +export type GetHistoryParameters = { + /** + * Channel to return history messages from. + */ + channel: string; + + /** + * Specifies the number of historical messages to return. + * + * **Note:** Maximum `100` messages can be returned in single response. + * + * @default `100` + */ + count?: number; + + /** + * Whether message `meta` information should be fetched or not. + * + * @default `false` + */ + includeMeta?: boolean; + + /** + * Timetoken delimiting the `start` of `time` slice (exclusive) to pull messages from. + */ + start?: string; + + /** + * Timetoken delimiting the `end` of `time` slice (inclusive) to pull messages from. + */ + end?: string; + + /** + * Whether timeline should traverse in reverse starting with the oldest message first or not. + * + * If both `start` and `end` arguments are provided, `reverse` is ignored and messages are + * returned starting with the newest message. + */ + reverse?: boolean; + + /** + * Whether message timetokens should be stringified or not. + * + * @default `false` + */ + stringifiedTimeToken?: boolean; +}; + +/** + * Get history response. + */ +export type GetHistoryResponse = { + /** + * List of previously published messages. + */ + messages: { + /** + * Message payload (decrypted). + */ + entry: Payload; + + /** + * When message has been received by PubNub service. + */ + timetoken: string | number; + + /** + * Additional data which has been published along with message to be used with real-time + * events filter expression. + */ + meta?: Payload; + + /** + * Message decryption error (if attempt has been done). + */ + error?: string; + }[]; + + /** + * Received messages timeline start. + */ + startTimeToken: string | number; + + /** + * Received messages timeline end. + */ + endTimeToken: string | number; +}; +// endregion + +// -------------------------------------------------------- +// -------------------- Fetch Messages -------------------- +// -------------------------------------------------------- +// region Fetch Messages + +/** + * PubNub-defined message type. + * + * Types of messages which can be retrieved with fetch messages REST API. + */ +export enum PubNubMessageType { + /** + * Regular message. + */ + Message = -1, + + /** + * File message. + */ + Files = 4, +} + +/** + * Per-message actions information. + */ +export type Actions = { + /** + * Message action type. + */ + [t: string]: { + /** + * Message action value. + */ + [v: string]: { + /** + * Unique identifier of the user which reacted on message. + */ + uuid: string; + + /** + * High-precision PubNub timetoken with time when {@link uuid} reacted on message. + */ + actionTimetoken: string; + }; + }; +}; + +/** + * Additional message actions fetch information. + */ +export type MoreActions = { + /** + * Prepared fetch messages with actions REST API URL. + */ + url: string; + + /** + * Next page time offset. + */ + start: string; + + /** + * Number of messages to retrieve with next page. + */ + max: number; +}; + +/** + * Common content of the fetched message. + */ +type BaseFetchedMessage = { + /** + * Name of channel for which message has been retrieved. + */ + channel: string; + + /** + * When message has been received by PubNub service. + */ + timetoken: string | number; + + /** + * Message publisher unique identifier. + */ + uuid?: string; + + /** + * Additional data which has been published along with message to be used with real-time + * events filter expression. + */ + meta?: Payload; + + /** + * Message decryption error (if attempt has been done). + */ + error?: string; +}; + +/** + * Regular message published to the channel. + */ +export type RegularMessage = BaseFetchedMessage & { + /** + * Message payload (decrypted). + */ + message: Payload; + + /** + * PubNub-defined message type. + */ + messageType?: PubNubMessageType.Message; +}; + +/** + * File message published to the channel. + */ +export type FileMessage = BaseFetchedMessage & { + /** + * Message payload (decrypted). + */ + message: { + /** + * File annotation message. + */ + message?: Payload; + + /** + * File information. + */ + file: { + /** + * Unique file identifier. + */ + id: string; + + /** + * Name with which file has been stored. + */ + name: string; + + /** + * File's content mime-type. + */ + 'mime-type': string; + + /** + * Stored file size. + */ + size: number; + + /** + * Pre-computed file download Url. + */ + url: string; + }; + }; + + /** + * PubNub-defined message type. + */ + messageType?: PubNubMessageType.Files; +}; + +/** + * Fetched message entry in channel messages list. + */ +export type FetchedMessage = RegularMessage | FileMessage; + +/** + * Fetched with actions message entry in channel messages list. + */ +export type FetchedMessageWithActions = FetchedMessage & { + /** + * List of message reactions. + */ + actions?: Actions; + /** + * List of message reactions. + * + * @deprecated Use {@link actions} field instead. + */ + data?: Actions; +}; + +/** + * Fetch messages request parameters. + */ +export type FetchMessagesParameters = { + /** + * Specifies channels to return history messages from. + * + * **Note:** Maximum of `500` channels are allowed. + */ + channels: string[]; + + /** + * Specifies the number of historical messages to return per channel. + * + * **Note:** Default is `100` per single channel and `25` per multiple channels or per + * single channel if {@link includeMessageActions} is used. + * + * @default `100` or `25` + */ + count?: number; + + /** + * Whether message type should be returned with each history message or not. + * + * @default `true` + */ + includeMessageType?: boolean; + + /** + * Whether publisher `uuid` should be returned with each history message or not. + * + * @default `true` + */ + includeUUID?: boolean; + + /** + * Whether publisher `uuid` should be returned with each history message or not. + * + * @deprecated Use {@link includeUUID} property instead. + */ + includeUuid?: boolean; + + /** + * Whether message `meta` information should be fetched or not. + * + * @default `false` + */ + includeMeta?: boolean; + + /** + * Whether message-added message actions should be fetched or not. + * + * If used, the limit of messages retrieved will be `25` per single channel. + * + * Each message can have a maximum of `25000` actions attached to it. Consider the example of + * querying for 10 messages. The first five messages have 5000 actions attached to each of + * them. The API will return the first 5 messages and all their 25000 actions. The response + * will also include a `more` link to get the remaining 5 messages. + * + * **Important:** Truncation will happen if the number of actions on the messages returned + * is > 25000. + * + * @default `false` + * + * @throws Exception if API is called with more than one channel. + */ + includeMessageActions?: boolean; + + /** + * Timetoken delimiting the `start` of `time` slice (exclusive) to pull messages from. + */ + start?: string; + + /** + * Timetoken delimiting the `end` of `time` slice (inclusive) to pull messages from. + */ + end?: string; + + /** + * Whether message timetokens should be stringified or not. + * + * @default `false` + */ + stringifiedTimeToken?: boolean; +}; + +/** + * Fetch messages response. + */ +export type FetchMessagesForChannelsResponse = { + /** + * List of previously published messages per requested channel. + */ + channels: { + [p: string]: FetchedMessage[]; + }; +}; + +/** + * Fetch messages with reactions response. + */ +export type FetchMessagesWithActionsResponse = { + channels: { + [p: string]: FetchedMessageWithActions[]; + }; + + /** + * Additional message actions fetch information. + */ + more: MoreActions; +}; + +/** + * Fetch messages response. + */ +export type FetchMessagesResponse = FetchMessagesForChannelsResponse | FetchMessagesWithActionsResponse; +// endregion + +// -------------------------------------------------------- +// ------------------- Messages Count --------------------- +// -------------------------------------------------------- +// region Messages Count + +/** + * Message count request parameters. + */ +export type MessageCountParameters = { + /** + * The channels to fetch the message count. + */ + channels: string[]; + + /** + * List of timetokens, in order of the {@link channels} list. + * + * Specify a single timetoken to apply it to all channels. Otherwise, the list of timetokens + * must be the same length as the list of {@link channels}, or the function returns an error + * flag. + */ + channelTimetokens?: string[]; + + /** + * High-precision PubNub timetoken starting from which number of messages should be counted. + * + * Same timetoken will be used to count messages for each passed {@link channels}. + * + * @deprecated Use {@link channelTimetokens} field instead. + */ + timetoken?: string; +}; +/** + * Message count response. + */ +export type MessageCountResponse = { + /** + * Map of channel names to the number of counted messages. + */ + channels: Record; +}; +// endregion + +// -------------------------------------------------------- +// ------------------- Delete Messages -------------------- +// -------------------------------------------------------- +// region Delete Messages + +/** + * Delete messages from channel parameters. + */ +export type DeleteMessagesParameters = { + /** + * Specifies channel messages to be deleted from history. + */ + channel: string; + + /** + * Timetoken delimiting the start of time slice (exclusive) to delete messages from. + */ + start?: string; + + /** + * Timetoken delimiting the end of time slice (inclusive) to delete messages from. + */ + end?: string; +}; + +/** + * Delete messages from channel response. + */ +export type DeleteMessagesResponse = Record; +// endregion diff --git a/src/core/types/api/index.ts b/src/core/types/api/index.ts new file mode 100644 index 000000000..dd3a51e1f --- /dev/null +++ b/src/core/types/api/index.ts @@ -0,0 +1,145 @@ +// PubNub client API common types. + +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import StatusCategory from '../../constants/categories'; + +/** + * PubNub account keyset. + */ +export type KeySet = { + /** + * Specifies the `subscribeKey` to be used for subscribing to a channel and message publishing. + */ + subscribeKey: string; + + /** + * Specifies the `publishKey` to be used for publishing messages to a channel. + */ + publishKey?: string; + + /** + * Specifies the `secretKey` to be used for request signatures computation. + */ + secretKey?: string; +}; + +/** + * REST API request processing function. + */ +export type SendRequestFunction = ( + request: AbstractRequest, + callback?: ResultCallback, +) => Promise; + +/** + * Endpoint call completion block with result. + * + * **Note:** Endpoints which return consumable data use this callback. + */ +export type ResultCallback = (status: Status, response: ResponseType | null) => void; + +/** + * Endpoint acknowledgment completion block. + * + * **Note:** Endpoints which return only acknowledgment or error status use this callback. + */ +export type StatusCallback = (status: Status) => void; + +/** + * REST API endpoint processing status. + * + * **Note:** Used as {@link ResultCallback} and {@link StatusCallback} callbacks first argument type and + * {@link PubNubError} instance `status` field value type. + */ +export type Status = { + /** + * Whether status represent error or not. + */ + error: boolean; + /** + * API call status category. + */ + category: StatusCategory; + + /** + * Type of REST API endpoint which reported status. + */ + operation?: RequestOperation; + + /** + * REST API response status code. + */ + statusCode: number; + + /** + * Error data provided by REST API. + */ + errorData?: Error | Payload; + + /** + * Additional status information. + */ + [p: string]: Payload | Error | undefined; +}; + +/** + * Real-time PubNub client status change event. + */ +export type StatusEvent = { + /** + * API call status category. + */ + category: StatusCategory; + + /** + * Type of REST API endpoint which reported status. + */ + operation?: RequestOperation; + + /** + * Information about error. + */ + error?: string | boolean; + + /** + * List of channels for which status update announced. + */ + affectedChannels?: string[]; + + /** + * List of currently subscribed channels. + * + * List of channels from which PubNub client receives real-time updates. + */ + subscribedChannels?: string[]; + + /** + * List of channel groups for which status update announced. + */ + affectedChannelGroups?: string[]; + + /** + * High-precision timetoken which has been used with previous subscription loop. + */ + lastTimetoken?: number | string; + + /** + * High-precision timetoken which is used for current subscription loop. + */ + currentTimetoken?: number | string; +}; + +/** + * {@link TransportRequest} query parameter type. + */ +export type Query = Record; + +/** + * General payload type. + * + * Type should be used for: + * * generic messages and signals content, + * * published message metadata. + */ +export type Payload = string | number | boolean | { [key: string]: Payload | null } | Payload[]; diff --git a/src/core/types/api/message-action.ts b/src/core/types/api/message-action.ts new file mode 100644 index 000000000..125d3a3e0 --- /dev/null +++ b/src/core/types/api/message-action.ts @@ -0,0 +1,175 @@ +/** + * Message reaction object type. + */ +export type MessageAction = { + /** + * What feature this message action represents. + */ + type: string; + + /** + * Value which should be stored along with message action. + */ + value: string; + + /** + * Unique identifier of the user which added message action. + */ + uuid: string; + + /** + * Timetoken of when message reaction has been added. + * + * **Note:** This token required when it will be required to remove raction. + */ + actionTimetoken: string; + + /** + * Timetoken of message to which `action` has been added. + */ + messageTimetoken: string; +}; + +/** + * More message actions fetch information. + */ +export type MoreMessageActions = { + /** + * Prepared REST API url to fetch next page with message actions. + */ + url: string; + + /** + * Message action timetoken denoting the start of the range requested with next page. + * + * **Note:** Return values will be less than {@link start}. + */ + start: string; + + /** + * Message action timetoken denoting the end of the range requested with next page. + * + * **Note:** Return values will be greater than or equal to {@link end}. + */ + end: string; + /** + * Number of message actions to return in next response. + */ + limit: number; +}; + +/** + * Add Message Action request parameters. + */ +export type AddMessageActionParameters = { + /** + * Name of channel which stores the message for which {@link action} should be added. + */ + channel: string; + + /** + * Timetoken of message for which {@link action} should be added. + */ + messageTimetoken: string; + + /** + * Message `action` information. + */ + action: { + /** + * What feature this message action represents. + */ + type: string; + + /** + * Value which should be stored along with message action. + */ + value: string; + }; +}; + +/** + * Response with added message action object. + */ +export type AddMessageActionResponse = { data: MessageAction }; + +/** + * Get Message Actions request parameters. + */ +export type GetMessageActionsParameters = { + /** + * Name of channel from which list of messages `actions` should be retrieved. + */ + channel: string; + + /** + * Message action timetoken denoting the start of the range requested. + * + * **Note:** Return values will be less than {@link start}. + */ + start?: string; + + /** + * Message action timetoken denoting the end of the range requested. + * + * **Note:** Return values will be greater than or equal to {@link end}. + */ + end?: string; + + /** + * Number of message actions to return in response. + */ + limit?: number; +}; + +/** + * Response with message actions in specific `channel`. + */ +export type GetMessageActionsResponse = { + /** + * Retrieved list of message actions. + */ + data: MessageAction[]; + + /** + * Received message actions time frame start. + */ + start: string | null; + + /** + * Received message actions time frame end. + */ + end: string | null; + + /** + * More message actions fetch information. + */ + more?: MoreMessageActions; +}; + +/** + * Remove Message Action request parameters. + */ +export type RemoveMessageActionParameters = { + /** + * Name of channel which store message for which `action` should be removed. + */ + channel: string; + + /** + * Timetoken of message for which `action` should be removed. + */ + messageTimetoken: string; + + /** + * Action addition timetoken. + */ + actionTimetoken: string; +}; + +/** + * Response with message remove result. + */ +export type RemoveMessageActionResponse = { + data: Record; +}; diff --git a/src/core/types/api/presence.ts b/src/core/types/api/presence.ts new file mode 100644 index 000000000..16d9e2f33 --- /dev/null +++ b/src/core/types/api/presence.ts @@ -0,0 +1,250 @@ +import { Payload } from './index'; + +// region Get Presence State +/** + * Associated presence state fetch parameters. + */ +export type GetPresenceStateParameters = { + /** + * The subscriber uuid to get the current state. + * + * @default `current uuid` + */ + uuid?: string; + + /** + * List of channels for which state associated with {@link uuid} should be retrieved. + * + * **Important:** Either {@link channels} or {@link channelGroups} should be provided; + */ + channels?: string[]; + + /** + * List of channel groups for which state associated with {@link uuid} should be retrieved. + * + * **Important:** Either {@link channels} or {@link channelGroups} should be provided; + */ + channelGroups?: string[]; +}; + +/** + * Associated presence state fetch response. + */ +export type GetPresenceStateResponse = { + /** + * Channels map to state which `uuid` has associated with them. + */ + channels: Record; +}; +// endregion + +// region Set Presence State +/** + * Associate presence state parameters. + */ +export type SetPresenceStateParameters = { + /** + * List of channels for which state should be associated with {@link uuid}. + */ + channels?: string[]; + + /** + * List of channel groups for which state should be associated with {@link uuid}. + */ + channelGroups?: string[]; + + /** + * State which should be associated with `uuid` on provided list of {@link channels} and {@link channelGroups}. + */ + state: Payload; +}; + +/** + * Associate presence state parameters using heartbeat. + */ +export type SetPresenceStateWithHeartbeatParameters = { + /** + * List of channels for which state should be associated with {@link uuid}. + */ + channels?: string[]; + + /** + * State which should be associated with `uuid` on provided list of {@link channels}. + */ + state: Payload; + + /** + * Whether `presence/heartbeat` REST API should be used to manage state or not. + * + * @default `false` + */ + withHeartbeat: boolean; +}; + +/** + * Associate presence state response. + */ +export type SetPresenceStateResponse = { + /** + * State which has been associated with `uuid` on provided list of channels and groups. + */ + state: Payload; +}; +// endregion + +// region Heartbeat announce +/** + * Announce heartbeat parameters. + */ +export type PresenceHeartbeatParameters = { + /** + * How long the server will consider the client alive for presence.The value is in seconds. + */ + heartbeat: number; + + /** + * List of channels for which heartbeat should be announced for {@link uuid}. + */ + channels?: string[]; + + /** + * List of channel groups for which heartbeat should be announced for {@link uuid}. + */ + channelGroups?: string[]; + + /** + * State which should be associated with `uuid` on provided list of {@link channels} and {@link channelGroups}. + */ + state?: Payload; +}; + +/** + * Announce heartbeat response. + */ +export type PresenceHeartbeatResponse = Record; +// endregion + +// region Get Presence State +/** + * Presence leave parameters. + */ +export type PresenceLeaveParameters = { + /** + * List of channels for which `uuid` should be marked as `offline`. + */ + channels?: string[]; + + /** + /** + * List of channel groups for which `uuid` should be marked as `offline`. + */ + channelGroups?: string[]; +}; + +/** + * Presence leave response. + */ +export type PresenceLeaveResponse = Record; +// endregion + +// region Here now +/** + * Channel / channel group presence fetch parameters.. + */ +export type HereNowParameters = { + /** + * List of channels for which presence should be retrieved. + */ + channels?: string[]; + + /** + * List of channel groups for which presence should be retrieved. + */ + channelGroups?: string[]; + + /** + * Whether `uuid` information should be included in response or not. + * + * **Note:** Only occupancy information will be returned if both {@link includeUUIDs} and {@link includeState} is + * set to `false`. + * + * @default `true` + */ + includeUUIDs?: boolean; + + /** + * Whether state associated with `uuid` should be included in response or not. + * + * @default `false`. + */ + includeState?: boolean; + + /** + * Additional query parameters. + */ + queryParameters?: Record; +}; + +/** + * `uuid` where now response. + */ +export type HereNowResponse = { + /** + * Total number of channels for which presence information received. + */ + totalChannels: number; + + /** + * Total occupancy for all retrieved channels. + */ + totalOccupancy: number; + + /** + * List of channels to which `uuid` currently subscribed. + */ + channels: { + [p: string]: { + /** + * List of received channel subscribers. + * + * **Note:** Field is missing if `uuid` and `state` not included. + */ + occupants: { uuid: string; state?: Payload | null }[]; + + /** + * Name of channel for which presence information retrieved. + */ + name: string; + + /** + * Total number of active subscribers in single channel. + */ + occupancy: number; + }; + }; +}; +// endregion + +// region Where now +/** + * `uuid` where now parameters. + */ +export type WhereNowParameters = { + /** + * The subscriber uuid to get the current state. + * + * @default `current uuid` + */ + uuid?: string; +}; + +/** + * `uuid` where now response. + */ +export type WhereNowResponse = { + /** + * Channels map to state which `uuid` has associated with them. + */ + channels: string[]; +}; +// endregion diff --git a/src/core/types/api/push-notifications.ts b/src/core/types/api/push-notifications.ts new file mode 100644 index 000000000..8dd0dadcf --- /dev/null +++ b/src/core/types/api/push-notifications.ts @@ -0,0 +1,53 @@ +/** + * Type of Push Notifications gateway which should be used with Push Notifications REST API. + */ +type PushGateway = 'apns2' | 'gcm'; + +/** + * Basic information required by Push Notifications REST API about device. + */ +type DevicePush = { + /** + * Device ID for which list of registered channel push notifications will be changed. + */ + device: string; + + /** + * Push Notifications gateway to use. + * + * **Important:** Depends from the source of `device` token and can be `apns2` (for token + * provided during device registration using Apple's framework) or `gcm` (when used Firebase + * or similar framework to receive token). + */ + pushGateway: PushGateway; +}; + +/** + * Register and unregister push notifications for device request parameters. + */ +export type ManageDeviceChannelsParameters = { + /** + * List of channels to be added or removed. + */ + channels: string[]; +} & DevicePush; + +/** + * List Device Channels request parameters. + */ +export type ListDeviceChannelsParameters = DevicePush; + +/** + * Response with result of the list device channels. + */ +export type ListDeviceChannelsResponse = { + /** + * List of the channels for which `device` will receive push notifications. + */ + channels: string[]; +}; + +/** + * Delete Push Notification for device request parameters. + */ +export type DeleteDeviceParameters = DevicePush; diff --git a/src/core/types/api/push.ts b/src/core/types/api/push.ts new file mode 100644 index 000000000..f4fe04edf --- /dev/null +++ b/src/core/types/api/push.ts @@ -0,0 +1,156 @@ +/** + * Common managed channels push notification parameters. + */ +type ManagedDeviceChannels = { + /** + * Channels to register or unregister with mobile push notifications. + */ + channels: string[]; + + /** + * The device ID to associate with mobile push notifications. + */ + device: string; + + /** + * Starting channel for pagination. + * + * **Note:** Use the last channel from the previous page request. + */ + start?: string; + + /** + * Number of channels to return for pagination. + * + * **Note:** maximum of 1000 tokens at a time. + * + * @default `500` + */ + count?: number; +}; + +// region List channels +/** + * List all FCM device push notification enabled channels parameters. + */ +type ListFCMDeviceChannelsParameters = Omit; + +/** + * List all APNS device push notification enabled channels parameters. + * + * @deprecated Use `APNS2`-based endpoints. + */ +type ListAPNSDeviceChannelsParameters = Omit; + +/** + * List all APNS2 device push notification enabled channels parameters. + */ +type ListAPNS2DeviceChannelsParameters = Omit; + +/** + * List all device push notification enabled channels parameters. + */ +export type ListDeviceChannelsParameters = + | ListFCMDeviceChannelsParameters + | ListAPNSDeviceChannelsParameters + | ListAPNS2DeviceChannelsParameters; + +/** + * List all device push notification enabled channels response. + */ +export type ListDeviceChannelsResponse = { + /** + * List of channels registered for device push notifications. + */ + channels: string[]; +}; +// endregion + +// region Add / Remove channels +/** + * Manage FCM device push notification enabled channels parameters. + */ +type ManageFCMDeviceChannelsParameters = ManagedDeviceChannels & { + /** + * Push Notifications gateway type. + */ + pushGateway: 'gcm'; +}; + +/** + * Manage APNS device push notification enabled channels parameters. + * + * @deprecated Use `APNS2`-based endpoints. + */ +type ManageAPNSDeviceChannelsParameters = ManagedDeviceChannels & { + /** + * Push Notifications gateway type. + */ + pushGateway: 'apns'; +}; + +/** + * Manage APNS2 device push notification enabled channels parameters. + */ +type ManageAPNS2DeviceChannelsParameters = ManagedDeviceChannels & { + /** + * Push Notifications gateway type. + */ + pushGateway: 'apns2'; + + /** + * Environment within which device should manage list of channels with enabled notifications. + */ + environment?: 'development' | 'production'; + + /** + * Notifications topic name (usually it is bundle identifier of application for Apple platform). + */ + topic: string; +}; + +/** + * Manage device push notification enabled channels parameters. + */ +export type ManageDeviceChannelsParameters = + | ManageFCMDeviceChannelsParameters + | ManageAPNSDeviceChannelsParameters + | ManageAPNS2DeviceChannelsParameters; + +/** + * Manage device push notification enabled channels response. + */ +export type ManageDeviceChannelsResponse = Record; +// endregion + +// region Remove device +/** + * Remove all FCM device push notification enabled channels parameters. + */ +type RemoveFCMDeviceParameters = Omit; + +/** + * Manage APNS device push notification enabled channels parameters. + * + * @deprecated Use `APNS2`-based endpoints. + */ +type RemoveAPNSDeviceParameters = Omit; + +/** + * Manage APNS2 device push notification enabled channels parameters. + */ +type RemoveAPNS2DeviceParameters = Omit; + +/** + * Remove all device push notification enabled channels parameters. + */ +export type RemoveDeviceParameters = + | RemoveFCMDeviceParameters + | RemoveAPNSDeviceParameters + | RemoveAPNS2DeviceParameters; + +/** + * Remove all device push notification enabled channels response. + */ +export type RemoveDeviceResponse = Record; +// endregion diff --git a/src/core/types/api/subscription.ts b/src/core/types/api/subscription.ts new file mode 100644 index 000000000..5cdab91fe --- /dev/null +++ b/src/core/types/api/subscription.ts @@ -0,0 +1,371 @@ +import { + RequestParameters as SubscribeRequestParameters, + VSPMembershipObjectData, + AppContextObjectData, + MessageActionData, + PubNubEventType, + SpaceObjectData, + UserObjectData, + PresenceData, + FileData, +} from '../../endpoints/subscribe'; +import { AbortSignal } from '../../components/abort_signal'; +import { Payload } from './index'; + +// -------------------------------------------------------- +// --------------------- Event types ---------------------- +// -------------------------------------------------------- +// region Even types + +/** + * Time cursor. + * + * Cursor used by subscription loop to identify point in time after which updates will be + * delivered. + */ +export type SubscriptionCursor = { + /** + * PubNub high-precision timestamp. + * + * Aside of specifying exact time of receiving data / event this token used to catchup / + * follow on real-time updates. + */ + timetoken: string | number; + + /** + * Data center region for which `timetoken` has been generated. + */ + region?: number; +}; + +/** + * Common real-time event. + */ +type Event = { + /** + * Channel to which real-time event has been sent. + */ + channel: string; + + /** + * Actual subscription at which real-time event has been received. + * + * PubNub client provide various ways to subscribe to the real-time stream: channel groups, + * wildcard subscription, and spaces. + * + * **Note:** Value will be `null` if it is the same as {@link channel}. + */ + subscription: string | null; + + /** + * High-precision PubNub timetoken with time when event has been received by PubNub services. + */ + timetoken: string; +}; + +/** + * Common legacy real-time event for backward compatibility. + */ +type LegacyEvent = Event & { + /** + * Channel to which real-time event has been sent. + * + * @deprecated Use {@link channel} field instead. + */ + actualChannel?: string | null; + + /** + * Actual subscription at which real-time event has been received. + * + * @deprecated Use {@link subscription} field instead. + */ + subscribedChannel?: string; +}; + +// region Presence event +/** + * Presence change real-time event. + */ +export type Presence = LegacyEvent & PresenceData; + +/** + * Extended presence real-time event. + * + * Type extended for listener manager support. + */ +type PresenceEvent = { + type: PubNubEventType.Presence; + data: Presence; +}; +// endregion + +// region Data publish event +/** + * Common published data information. + */ +type PublishedData = { + /** + * Unique identifier of the user which sent data. + */ + publisher?: string; + + /** + * Additional user-provided metadata which can be used with real-time filtering expression. + */ + userMetadata?: { [p: string]: Payload }; + + /** + * Sent data. + */ + message: Payload; +}; + +/** + * Real-time message event. + */ +export type Message = LegacyEvent & + PublishedData & { + /** + * Decryption error message in case of failure. + */ + error?: string; + }; + +/** + * Extended real-time message event. + * + * Type extended for listener manager support. + */ +type MessageEvent = { + type: PubNubEventType.Message; + data: Message; +}; + +/** + * Real-time signal event. + */ +export type Signal = Event & PublishedData; + +/** + * Extended real-time signal event. + * + * Type extended for listener manager support. + */ +type SignalEvent = { + type: PubNubEventType.Signal; + data: Signal; +}; +// endregion + +// region Message action event + +/** + * Message action real-time event. + */ +export type MessageAction = Event & + Omit & { + /** + * Unique identifier of the user which added message reaction. + * + * @deprecated Use `data.uuid` field instead. + */ + publisher?: string; + + data: MessageActionData['data'] & { + /** + * Unique identifier of the user which added message reaction. + */ + uuid: string; + }; + }; + +/** + * Extended message action real-time event. + * + * Type extended for listener manager support. + */ +type MessageActionEvent = { + type: PubNubEventType.MessageAction; + data: MessageAction; +}; +// endregion + +// region App Context event +/** + * App Context Object change real-time event. + */ +export type AppContextObject = Event & { + /** + * Information about App Context object for which event received. + */ + message: AppContextObjectData; +}; + +/** + * `User` App Context Object change real-time event. + */ +export type UserAppContextObject = Omit & { + /** + * Space to which real-time event has been sent. + */ + spaceId: string; + + /** + * Information about User Object for which event received. + */ + message: UserObjectData; +}; + +/** + * `Space` App Context Object change real-time event. + */ +export type SpaceAppContextObject = Omit & { + /** + * Space to which real-time event has been sent. + */ + spaceId: string; + + /** + * Information about `Space` Object for which event received. + */ + message: SpaceObjectData; +}; + +/** + * VSP `Membership` App Context Object change real-time event. + */ +export type VSPMembershipAppContextObject = Omit & { + /** + * Space to which real-time event has been sent. + */ + spaceId: string; + + /** + * Information about `Membership` Object for which event received. + */ + message: VSPMembershipObjectData; +}; + +/** + * Extended App Context Object change real-time event. + * + * Type extended for listener manager support. + */ +type AppContextEvent = { + type: PubNubEventType.AppContext; + data: AppContextObject; +}; +// endregion + +// region File event +/** + * File real-time event. + */ +export type File = Event & + Omit & + Omit & { + /** + * Message which has been associated with uploaded file. + */ + message?: Payload; + + /** + * Information about uploaded file. + */ + file?: FileData['file'] & { + /** + * File download url. + */ + url: string; + }; + + /** + * Decryption error message in case of failure. + */ + error?: string; + }; + +/** + * Extended File real-time event. + * + * Type extended for listener manager support. + */ +type FileEvent = { + type: PubNubEventType.Files; + data: File; +}; +// endregion + +// -------------------------------------------------------- +// -------------------- Request types --------------------- +// -------------------------------------------------------- + +/** + * Cancelable subscribe request parameters. + */ +export type CancelableSubscribeParameters = Omit< + SubscribeRequestParameters, + 'crypto' | 'timeout' | 'keySet' | 'getFileUrl' +> & { + /** + * Long-poll request termination signal. + */ + abortSignal: AbortSignal; +}; + +/** + * Subscribe request parameters. + */ +export type SubscribeParameters = { + /** + * List of channels from which real-time events should be delivered. + * + * @default `,` if {@link channelGroups} is set. + */ + channels?: string[]; + + /** + * List of channel groups from which real-time events should be retrieved. + */ + channelGroups?: string[]; + + /** + * Next subscription loop timetoken. + */ + timetoken?: string | number; + + /** + * Whether should subscribe to channels / groups presence announcements or not. + * + * @default `false` + */ + withPresence?: boolean; + + // region Deprecated + /** + * Presence information which should be associated with `userId`. + * + * `state` information will be associated with `userId` on channels mentioned as keys in + * this object. + * + * @deprecated Use set state methods to specify associated user's data instead of passing to + * subscribe. + */ + state?: Record; + + /** + * Whether should subscribe to channels / groups presence announcements or not. + * + * @default `false` + */ + withHeartbeats?: boolean; + // endregion +}; + +/** + * Service success response. + */ +export type SubscriptionResponse = { + cursor: SubscriptionCursor; + messages: (PresenceEvent | MessageEvent | SignalEvent | MessageActionEvent | AppContextEvent | FileEvent)[]; +}; diff --git a/src/core/types/file.ts b/src/core/types/file.ts new file mode 100644 index 000000000..0423b5151 --- /dev/null +++ b/src/core/types/file.ts @@ -0,0 +1,120 @@ +/** + * {@link PubNub} File object interface module. + */ + +/** + * Base file constructor parameters. + * + * Minimum set of parameters which can be p + */ +export type PubNubBasicFileParameters = { + data: string | ArrayBuffer; + name: string; + mimeType?: string; +}; + +/** + * Platform-agnostic {@link PubNub} File object. + * + * Interface describes share of {@link PubNub} File which is required by {@link PubNub} core to + * perform required actions. + */ +export interface PubNubFileInterface { + /** + * Actual file name. + */ + name: string; + + /** + * File mime-type. + */ + mimeType?: string; + + /** + * File content length. + */ + contentLength?: number; + + /** + * Convert {@link PubNub} file object content to {@link ArrayBuffer}. + * + * @returns Asynchronous results of conversion to the {@link ArrayBuffer}. + * + * @throws Error if provided {@link PubNub} File object content is not supported for this + * operation. + */ + toArrayBuffer(): Promise; + + /** + * Convert {@link PubNub} File object content to file `Uri`. + * + * @returns Asynchronous results of conversion to file `Uri`. + * + * @throws Error if provided {@link PubNub} File object content is not supported for this + * operation. + */ + toFileUri(): Promise>; +} + +/** + * {@link PubNub} File object class interface. + */ +export interface PubNubFileConstructor { + /** + * Whether {@link Blob} data supported by platform or not. + */ + supportsBlob: boolean; + + /** + * Whether {@link File} data supported by platform or not. + */ + supportsFile: boolean; + + /** + * Whether {@link Buffer} data supported by platform or not. + */ + supportsBuffer: boolean; + + /** + * Whether {@link Stream} data supported by platform or not. + */ + supportsStream: boolean; + + /** + * Whether {@link String} data supported by platform or not. + */ + supportsString: boolean; + + /** + * Whether {@link ArrayBuffer} supported by platform or not. + */ + supportsArrayBuffer: boolean; + + /** + * Whether {@link PubNub} File object encryption supported or not. + */ + supportsEncryptFile: boolean; + + /** + * Whether `File Uri` data supported by platform or not. + */ + supportsFileUri: boolean; + + /** + * {@link PubNub} File object constructor. + * + * @param file - File instantiation parameters (can be raw data or structured object). + * + * @returns Constructed platform-specific {@link PubNub} File object. + */ + create(file: ConstructorParameters): File; + + /** + * {@link PubNub} File object constructor. + * + * @param file - File instantiation parameters (can be raw data or structured object). + * + * @returns Constructed platform-specific {@link PubNub} File object. + */ + new (file: ConstructorParameters): File; +} diff --git a/src/core/types/transport-request.ts b/src/core/types/transport-request.ts new file mode 100644 index 000000000..22ea0c521 --- /dev/null +++ b/src/core/types/transport-request.ts @@ -0,0 +1,110 @@ +import { PubNubFileInterface } from './file'; +import { Query } from './api'; + +/** + * Enum representing possible transport methods for HTTP requests. + * + * @enum {number} + */ +export enum TransportMethod { + /** + * Request will be sent using `GET` method. + */ + GET = 'GET', + /** + * Request will be sent using `POST` method. + */ + POST = 'POST', + /** + * Request will be sent using `PATCH` method. + */ + PATCH = 'PATCH', + /** + * Request will be sent using `DELETE` method. + */ + DELETE = 'DELETE', + + /** + * Local request. + * + * Request won't be sent to the service and probably used to compute URL. + */ + LOCAL = 'LOCAL', +} + +/** + * Request cancellation controller. + */ +export type CancellationController = { + /** + * Request cancellation / abort function. + */ + abort: () => void; +}; + +/** + * This object represents a request to be sent to the PubNub API. + * + * This struct represents a request to be sent to the PubNub API. It is used by the transport + * provider which implements {@link Transport} interface. + * + * All fields are representing certain parts of the request that can be used to prepare one. + */ +export type TransportRequest = { + /** + * Remote host name. + */ + origin?: string; + + /** + * Remote resource path. + */ + path: string; + + /** + * Query parameters to be sent with the request. + */ + queryParameters?: Query; + + /** + * Transport request HTTP method. + */ + method: TransportMethod; + + /** + * Headers to be sent with the request. + */ + headers?: Record; + + /** + * Multipart form data fields. + * + * **Important:** `Content-Type` header should be sent the {@link body} data type when + * `multipart/form-data` should request should be sent. + */ + formData?: Record[]; + + /** + * Body to be sent with the request. + */ + body?: ArrayBuffer | PubNubFileInterface | string; + + /** + * For how long request should wait response from the server. + * + * @default `10` seconds. + */ + timeout: number; + + /** + * Whether request can be cancelled or not. + * + * @default `false`. + */ + cancellable: boolean; + + /** + * Unique request identifier. + */ + identifier: string; +}; diff --git a/src/core/types/transport-response.ts b/src/core/types/transport-response.ts new file mode 100644 index 000000000..22dc20ef4 --- /dev/null +++ b/src/core/types/transport-response.ts @@ -0,0 +1,26 @@ +/** + * Represents a transport response from a service. + */ +export type TransportResponse = { + /** + * Full remote resource URL used to retrieve response. + */ + url: string; + + /** + * Service response status code. + */ + status: number; + + /** + * Service response headers. + * + * **Important:** Header names are in lowercase. + */ + headers: Record; + + /** + * Service response body. + */ + body?: ArrayBuffer; +}; diff --git a/src/core/utils.js b/src/core/utils.js deleted file mode 100644 index 668845dd6..000000000 --- a/src/core/utils.js +++ /dev/null @@ -1,71 +0,0 @@ -function objectToList(o) { - const l = []; - Object.keys(o).forEach((key) => l.push(key)); - return l; -} - -function encodeString(input) { - return encodeURIComponent(input).replace(/[!~*'()]/g, (x) => `%${x.charCodeAt(0).toString(16).toUpperCase()}`); -} - -function objectToListSorted(o) { - return objectToList(o).sort(); -} - -function signPamFromParams(params) { - const l = objectToListSorted(params); - return l.map((paramKey) => `${paramKey}=${encodeString(params[paramKey])}`).join('&'); -} - -function endsWith(searchString, suffix) { - return searchString.indexOf(suffix, this.length - suffix.length) !== -1; -} - -function createPromise() { - let successResolve; - let failureResolve; - const promise = new Promise((fulfill, reject) => { - successResolve = fulfill; - failureResolve = reject; - }); - - return { promise, reject: failureResolve, fulfill: successResolve }; -} - -function stringToArrayBuffer(str) { - var buf = new ArrayBuffer(str.length * 2); - var bufView = new Uint16Array(buf); - for (var i = 0, strLen = str.length; i < strLen; i++) { - bufView[i] = str.charCodeAt(i); - } - return buf; -} - -function removeSingleOccurance(source, elementsToRemove) { - let removed = Object.fromEntries(elementsToRemove.map((prop) => [prop, false])); - - return source.filter((e) => { - if (elementsToRemove.includes(e) && !removed[e]) { - removed[e] = true; - return false; - } - return true; - }); -} - -function findUniqueCommonElements(a, b) { - return [...a].filter( - (value) => - b.includes(value) && a.indexOf(value) === a.lastIndexOf(value) && b.indexOf(value) === b.lastIndexOf(value), - ); -} - -module.exports = { - signPamFromParams, - endsWith, - createPromise, - encodeString, - stringToArrayBuffer, - removeSingleOccurance, - findUniqueCommonElements, -}; diff --git a/src/core/utils.ts b/src/core/utils.ts new file mode 100644 index 000000000..dc65d95b4 --- /dev/null +++ b/src/core/utils.ts @@ -0,0 +1,65 @@ +import { Query } from './types/api'; + +/** + * Percent-encode input string. + * + * **Note:** Encode content in accordance of the `PubNub` service requirements. + * + * @param input - Source string or number for encoding. + * + * @returns Percent-encoded string. + */ +export const encodeString = (input: string | number) => { + return encodeURIComponent(input).replace(/[!~*'()]/g, (x) => `%${x.charCodeAt(0).toString(16).toUpperCase()}`); +}; + +/** + * Percent-encode list of names (channels). + * + * @param names - List of names which should be encoded. + * + * @param [defaultString] - String which should be used in case if {@link names} is empty. + * + * @returns String which contains encoded names joined by non-encoded `,`. + */ +export const encodeNames = (names: string[], defaultString?: string) => { + const encodedNames = names.map((name) => encodeString(name)); + return encodedNames.length ? encodedNames.join(',') : defaultString ?? ''; +}; + +export const removeSingleOccurance = (source: string[], elementsToRemove: string[]) => { + const removed = Object.fromEntries(elementsToRemove.map((prop) => [prop, false])); + + return source.filter((e) => { + if (elementsToRemove.includes(e) && !removed[e]) { + removed[e] = true; + return false; + } + return true; + }); +}; + +export const findUniqueCommonElements = (a: string[], b: string[]) => { + return [...a].filter( + (value) => + b.includes(value) && a.indexOf(value) === a.lastIndexOf(value) && b.indexOf(value) === b.lastIndexOf(value), + ); +}; + +/** + * Transform query key / value pairs to the string. + * + * @param query - Key / value pairs of the request query parameters. + * + * @returns Stringified query key / value pairs. + */ +export const queryStringFromObject = (query: Query) => { + return Object.keys(query) + .map((key) => { + const queryValue = query[key]; + if (!Array.isArray(queryValue)) return `${key}=${encodeString(queryValue)}`; + + return queryValue.map((value) => `${key}=${encodeString(value)}`).join('&'); + }) + .join('&'); +}; diff --git a/src/crypto/modules/NodeCryptoModule/ICryptor.ts b/src/crypto/modules/NodeCryptoModule/ICryptor.ts index 5e73cee31..63860b300 100644 --- a/src/crypto/modules/NodeCryptoModule/ICryptor.ts +++ b/src/crypto/modules/NodeCryptoModule/ICryptor.ts @@ -1,19 +1,106 @@ +/** + * Cryptor module. + */ + +/** + * Data encrypted by {@link CryptoModule}. + */ export type EncryptedDataType = { + /** + * Encrypted data. + */ data: Buffer | string; + + /** + * Used cryptor's metadata. + */ metadata: Buffer | null; }; +/** + * {@link Readable} stream encrypted by {@link CryptoModule}. + */ export type EncryptedStream = { + /** + * Stream with encrypted content. + */ stream: NodeJS.ReadableStream; + + /** + * Length of encrypted data in {@link Readable} stream. + */ metadataLength: number; + + /** + * Used cryptor's metadata. + */ metadata?: Buffer | undefined; }; +/** + * Cryptor algorithm interface. + */ export interface ICryptor { + /** + * Cryptor unique identifier. + * + * @returns Cryptor identifier. + */ get identifier(): string; + + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + + // region Encryption + /** + * Encrypt provided source data. + * + * @param data - Source data for encryption. + * + * @returns Encrypted data object. + * + * @throws Error if unknown data type has been passed. + */ encrypt(data: BufferSource | string): EncryptedDataType; - decrypt(data: EncryptedDataType): ArrayBuffer; + /** + * Encrypt provided source {@link Readable} stream. + * + * @param stream - Stream for encryption. + * + * @returns Encrypted stream object. + * + * @throws Error if unknown data type has been passed. + */ encryptStream(stream: NodeJS.ReadableStream): Promise; - decryptStream(encryptedStream: EncryptedStream): Promise; + // endregion + + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + + // region Decryption + /** + * Decrypt provided encrypted data object. + * + * @param data - Encrypted data object for decryption. + * + * @returns Decrypted data. + * + * @throws Error if unknown data type has been passed. + */ + decrypt(data: EncryptedDataType): ArrayBuffer; + + /** + * Decrypt provided encrypted stream object. + * + * @param stream - Encrypted stream object for decryption. + * + * @returns Decrypted data as {@link Readable} stream. + * + * @throws Error if unknown data type has been passed. + */ + decryptStream(stream: EncryptedStream): Promise; + // endregion } diff --git a/src/crypto/modules/NodeCryptoModule/ILegacyCryptor.ts b/src/crypto/modules/NodeCryptoModule/ILegacyCryptor.ts index 9a63aa455..8fd6ae953 100644 --- a/src/crypto/modules/NodeCryptoModule/ILegacyCryptor.ts +++ b/src/crypto/modules/NodeCryptoModule/ILegacyCryptor.ts @@ -1,26 +1,84 @@ +/** + * Legacy cryptor module. + */ + +import PubNubFile, { PubNubFileParameters } from '../../../file/modules/node'; +import { PubNubFileConstructor } from '../../../core/types/file'; +import { Payload } from '../../../core/types/api'; import { EncryptedDataType } from './ICryptor'; -export type PubNubFileType = { - stream: NodeJS.ReadStream; - data: NodeJS.ReadStream | Buffer; - name: string; - mimeType: string; - contentLength: number; +/** + * Legacy cryptor algorithm interface. + */ +export interface ILegacyCryptor { + /** + * Cryptor unique identifier. + */ + get identifier(): string; + + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- - create(config: any): PubNubFileType; + // region Encryption + /** + * Encrypt provided source data. + * + * @param data - Source data for encryption. + * + * @returns Encrypted data object. + * + * @throws Error if unknown data type has been passed. + */ + encrypt(data: string): EncryptedDataType; - toBuffer(): Buffer; - toArrayBuffer(): ArrayBuffer; - toString(): string; - toStream(): NodeJS.ReadStream; -}; + /** + * Encrypt provided source {@link PubNub} File object. + * + * @param file - Source {@link PubNub} File object for encryption. + * @param File - Class constructor for {@link PubNub} File object. + * + * @returns Encrypted data as {@link PubNub} File object. + * + * @throws Error if file is empty or contains unsupported data type. + * @throws Error if cipher key not set. + */ + encryptFile( + file: PubNubFile, + File: PubNubFileConstructor, + ): Promise; + // endregion -export interface ILegacyCryptor { - get identifier(): string; + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- - encrypt(data: string | ArrayBuffer): EncryptedDataType; - decrypt(data: EncryptedDataType): BufferSource | string; + // region Decryption + /** + * Decrypt provided encrypted data object. + * + * @param data - Encrypted data object for decryption. + * + * @returns Decrypted data. + * + * @throws Error if unknown data type has been passed. + */ + decrypt(data: EncryptedDataType): Payload | null; - encryptFile(file: T, File: T): Promise; - decryptFile(file: T, File: T): Promise; + /** + * Decrypt provided encrypted {@link PubNub} File object. + * + * @param file - Encrypted {@link PubNub} File object for decryption. + * @param File - Class constructor for {@link PubNub} File object. + * + * @returns Decrypted data as {@link PubNub} File object. + * + * @throws Error if file is empty or contains unsupported data type. + * @throws Error if cipher key not set. + */ + decryptFile( + file: PubNubFile, + File: PubNubFileConstructor, + ): Promise; + // endregion } diff --git a/src/crypto/modules/NodeCryptoModule/aesCbcCryptor.ts b/src/crypto/modules/NodeCryptoModule/aesCbcCryptor.ts index 68cfb89a6..024b4e188 100644 --- a/src/crypto/modules/NodeCryptoModule/aesCbcCryptor.ts +++ b/src/crypto/modules/NodeCryptoModule/aesCbcCryptor.ts @@ -1,39 +1,50 @@ -import { PassThrough } from 'stream'; +/** + * AES-CBC cryptor module. + */ + import { createCipheriv, createDecipheriv, createHash, randomBytes } from 'crypto'; +import { PassThrough } from 'stream'; + import { ICryptor, EncryptedDataType, EncryptedStream } from './ICryptor'; +/** + * AES-CBC cryptor. + * + * AES-CBC cryptor with enhanced cipher strength. + */ export default class AesCbcCryptor implements ICryptor { + /** + * Cryptor block size. + */ static BLOCK_SIZE = 16; - cipherKey: string; - constructor(configuration: { cipherKey: string }) { - this.cipherKey = configuration.cipherKey; - } + /** + * {@link string|String} to {@link ArrayBuffer} response decoder. + */ + static encoder = new TextEncoder(); - get algo() { - return 'aes-256-cbc'; - } + /** + * Data encryption / decryption cipher key. + */ + cipherKey: string; - get identifier() { - return 'ACRH'; + constructor({ cipherKey }: { cipherKey: string }) { + this.cipherKey = cipherKey; } - getIv() { - return randomBytes(AesCbcCryptor.BLOCK_SIZE); - } + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + // region Encryption - getKey() { - const sha = createHash('sha256'); - sha.update(Buffer.from(this.cipherKey, 'utf8')); - return Buffer.from(sha.digest()); - } - - encrypt(data: ArrayBuffer | string) { + encrypt(data: ArrayBuffer | string): EncryptedDataType { const iv = this.getIv(); const key = this.getKey(); - const plainData = typeof data === 'string' ? new TextEncoder().encode(data) : data; + const plainData = typeof data === 'string' ? AesCbcCryptor.encoder.encode(data) : data; const bPlain = Buffer.from(plainData); - if (bPlain.byteLength === 0) throw new Error('encryption error. empty content'); + + if (bPlain.byteLength === 0) throw new Error('Encryption error: empty content'); + const aes = createCipheriv(this.algo, key, iv); return { @@ -42,37 +53,53 @@ export default class AesCbcCryptor implements ICryptor { }; } - decrypt(encryptedData: EncryptedDataType) { - const data = - typeof encryptedData.data === 'string' ? new TextEncoder().encode(encryptedData.data) : encryptedData.data; - if (data.byteLength <= 0) throw new Error('decryption error: empty content'); - const aes = createDecipheriv(this.algo, this.getKey(), encryptedData.metadata); - return Uint8Array.from(Buffer.concat([aes.update(data), aes.final()])).buffer; - } - async encryptStream(stream: NodeJS.ReadableStream) { + if (!stream.readable) throw new Error('Encryption error: empty stream'); + const output = new PassThrough(); const bIv = this.getIv(); - if (stream.readable === false) throw new Error('encryption error. empty stream'); const aes = createCipheriv(this.algo, this.getKey(), bIv); stream.pipe(aes).pipe(output); + return { stream: output, metadata: bIv, metadataLength: AesCbcCryptor.BLOCK_SIZE, }; } + // endregion + + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + // region Decryption + + decrypt(input: EncryptedDataType) { + const data = typeof input.data === 'string' ? new TextEncoder().encode(input.data) : input.data; + + if (data.byteLength <= 0) throw new Error('Decryption error: empty content'); + const aes = createDecipheriv(this.algo, this.getKey(), input.metadata!); + const decryptedDataBuffer = Buffer.concat([aes.update(data), aes.final()]); + + return decryptedDataBuffer.buffer.slice( + decryptedDataBuffer.byteOffset, + decryptedDataBuffer.byteOffset + decryptedDataBuffer.length, + ); + } - async decryptStream(encryptedStream: EncryptedStream) { + async decryptStream(stream: EncryptedStream) { const decryptedStream = new PassThrough(); let bIv = Buffer.alloc(0); - let aes: any = null; + let aes: ReturnType | null = null; + const onReadable = () => { - let data = encryptedStream.stream.read(); + let data = stream.stream.read(); + while (data !== null) { if (data) { const bChunk = Buffer.from(data); - const sliceLen = encryptedStream.metadataLength - bIv.byteLength; + const sliceLen = stream.metadataLength - bIv.byteLength; + if (bChunk.byteLength < sliceLen) { bIv = Buffer.concat([bIv, bChunk]); } else { @@ -82,16 +109,55 @@ export default class AesCbcCryptor implements ICryptor { aes.write(bChunk.slice(sliceLen)); } } - data = encryptedStream.stream.read(); + data = stream.stream.read(); } }; - encryptedStream.stream.on('readable', onReadable); - encryptedStream.stream.on('end', () => { - if (aes) { - aes.end(); - } + stream.stream.on('readable', onReadable); + stream.stream.on('end', () => { + if (aes) aes.end(); decryptedStream.end(); }); + return decryptedStream; } + // endregion + + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + // region Helpers + + get identifier() { + return 'ACRH'; + } + + /** + * Cryptor algorithm. + * + * @returns Cryptor module algorithm. + */ + private get algo() { + return 'aes-256-cbc'; + } + + /** + * Generate random initialization vector. + * + * @returns Random initialization vector. + */ + private getIv() { + return randomBytes(AesCbcCryptor.BLOCK_SIZE); + } + + /** + * Convert cipher key to the {@link Buffer}. + * + * @returns SHA256 encoded cipher key {@link Buffer}. + */ + private getKey() { + const sha = createHash('sha256'); + sha.update(Buffer.from(this.cipherKey, 'utf8')); + return Buffer.from(sha.digest()); + } + // endregion } diff --git a/src/crypto/modules/NodeCryptoModule/legacyCryptor.ts b/src/crypto/modules/NodeCryptoModule/legacyCryptor.ts index c8a28fc6b..4aa44e4e4 100644 --- a/src/crypto/modules/NodeCryptoModule/legacyCryptor.ts +++ b/src/crypto/modules/NodeCryptoModule/legacyCryptor.ts @@ -1,41 +1,88 @@ +/** + * Legacy cryptor module. + */ + +import PubNubFile, { PubNubFileParameters } from '../../../file/modules/node'; +import { CryptorConfiguration } from '../../../core/interfaces/crypto-module'; import Crypto from '../../../core/components/cryptography/index'; +import { PubNubFileConstructor } from '../../../core/types/file'; import { encode } from '../../../core/components/base64_codec'; -import FileCryptor from '../node'; +import { PubNubError } from '../../../errors/pubnub-error'; +import { ILegacyCryptor } from './ILegacyCryptor'; import { EncryptedDataType } from './ICryptor'; -import { ILegacyCryptor, PubNubFileType } from './ILegacyCryptor'; +import FileCryptor from '../node'; -export default class LegacyCryptor implements ILegacyCryptor { +/** + * Legacy cryptor. + */ +export default class LegacyCryptor implements ILegacyCryptor { + /** + * Legacy cryptor configuration. + */ config; - cryptor; + /** + * Configured file cryptor. + */ fileCryptor; - constructor(config: any) { + /** + * Configured legacy cryptor. + */ + cryptor; + + constructor(config: CryptorConfiguration) { this.config = config; - this.cryptor = new Crypto({ config }); + this.cryptor = new Crypto({ ...config }); this.fileCryptor = new FileCryptor(); } - get identifier() { - return ''; - } - encrypt(data: string) { - if (data.length === 0) throw new Error('encryption error. empty content'); + + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + // region Encryption + + encrypt(data: string): EncryptedDataType { + if (data.length === 0) throw new Error('Encryption error: empty content'); + return { data: this.cryptor.encrypt(data), metadata: null, }; } + async encryptFile(file: PubNubFile, File: PubNubFileConstructor) { + if (!this.config.cipherKey) throw new PubNubError('File encryption error: cipher key not set.'); + + return this.fileCryptor.encryptFile(this.config.cipherKey, file, File); + } + // endregion + + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + // region Decryption + decrypt(encryptedData: EncryptedDataType) { const data = typeof encryptedData.data === 'string' ? encryptedData.data : encode(encryptedData.data); + return this.cryptor.decrypt(data); } - async encryptFile(file: PubNubFileType, File: PubNubFileType) { - return this.fileCryptor.encryptFile(this.config.cipherKey, file, File); - } + async decryptFile(file: PubNubFile, File: PubNubFileConstructor) { + if (!this.config.cipherKey) throw new PubNubError('File decryption error: cipher key not set.'); - async decryptFile(file: PubNubFileType, File: PubNubFileType) { return this.fileCryptor.decryptFile(this.config.cipherKey, file, File); } + // endregion + + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + // region Helpers + + get identifier() { + return ''; + } + // endregion } diff --git a/src/crypto/modules/NodeCryptoModule/nodeCryptoModule.ts b/src/crypto/modules/NodeCryptoModule/nodeCryptoModule.ts index a1d218946..a98176b5d 100644 --- a/src/crypto/modules/NodeCryptoModule/nodeCryptoModule.ts +++ b/src/crypto/modules/NodeCryptoModule/nodeCryptoModule.ts @@ -1,123 +1,147 @@ +/** + * Node.js crypto module. + */ + import { Readable, PassThrough } from 'stream'; +import { Buffer } from 'buffer'; + +import { AbstractCryptoModule, CryptorConfiguration } from '../../../core/interfaces/crypto-module'; +import PubNubFile, { PubNubFileParameters } from '../../../file/modules/node'; +import { PubNubFileConstructor } from '../../../core/types/file'; import { decode } from '../../../core/components/base64_codec'; -import LegacyCryptor from './legacyCryptor'; +import { PubNubError } from '../../../errors/pubnub-error'; +import { EncryptedDataType, ICryptor } from './ICryptor'; +import { ILegacyCryptor } from './ILegacyCryptor'; import AesCbcCryptor from './aesCbcCryptor'; -import { ICryptor } from './ICryptor'; -import { ILegacyCryptor, PubNubFileType } from './ILegacyCryptor'; +import LegacyCryptor from './legacyCryptor'; +/** + * Re-export bundled cryptors. + */ export { LegacyCryptor, AesCbcCryptor }; -type CryptorType = ICryptor | ILegacyCryptor; - -type CryptoModuleConfiguration = { - default: CryptorType; - cryptors?: Array; -}; - -export class CryptoModule { +/** + * Crypto module cryptors interface. + */ +type CryptorType = ICryptor | ILegacyCryptor; + +/** + * CryptoModule for Node.js platform. + */ +export class CryptoModule extends AbstractCryptoModule { + /** + * {@link LegacyCryptor|Legacy} cryptor identifier. + */ static LEGACY_IDENTIFIER = ''; - defaultCryptor: CryptorType; - cryptors: Array; + // -------------------------------------------------------- + // --------------- Convenience functions ------------------ + // ------------------------------------------------------- + // region Convenience functions - constructor(cryptoModuleConfiguration: CryptoModuleConfiguration) { - this.defaultCryptor = cryptoModuleConfiguration.default; - this.cryptors = cryptoModuleConfiguration.cryptors ?? []; - } + static legacyCryptoModule(config: CryptorConfiguration) { + if (!config.cipherKey) throw new PubNubError('Crypto module error: cipher key not set.'); - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore: type detection issue with old Config type assignment - static legacyCryptoModule(config) { return new this({ default: new LegacyCryptor({ - cipherKey: config.cipherKey, + ...config, useRandomIVs: config.useRandomIVs ?? true, }), cryptors: [new AesCbcCryptor({ cipherKey: config.cipherKey })], }); } - static aesCbcCryptoModule(config: any) { + static aesCbcCryptoModule(config: CryptorConfiguration) { + if (!config.cipherKey) throw new PubNubError('Crypto module error: cipher key not set.'); + return new this({ default: new AesCbcCryptor({ cipherKey: config.cipherKey }), cryptors: [ new LegacyCryptor({ - cipherKey: config.cipherKey, + ...config, useRandomIVs: config.useRandomIVs ?? true, }), ], }); } + + /** + * Construct crypto module with `cryptor` as default for data encryption and decryption. + * + * @param defaultCryptor - Default cryptor for data encryption and decryption. + * + * @returns Crypto module with pre-configured default cryptor. + */ static withDefaultCryptor(defaultCryptor: CryptorType) { return new this({ default: defaultCryptor }); } + // endregion - private getAllCryptors() { - return [this.defaultCryptor, ...this.cryptors]; - } - - private getLegacyCryptor() { - return this.getAllCryptors().find((c) => c.identifier === ''); - } + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + // region Encryption encrypt(data: ArrayBuffer | string) { - const encrypted = this.defaultCryptor.encrypt(data); + // Encrypt data. + const encrypted = + data instanceof ArrayBuffer && this.defaultCryptor.identifier === CryptoModule.LEGACY_IDENTIFIER + ? (this.defaultCryptor as ILegacyCryptor).encrypt(CryptoModule.decoder.decode(data)) + : (this.defaultCryptor as ICryptor).encrypt(data); + if (!encrypted.metadata) return encrypted.data; - const header = CryptorHeader.from(this.defaultCryptor.identifier, encrypted.metadata); + const headerData = this.getHeaderData(encrypted)!; - const headerData = new Uint8Array(header!.length); - let pos = 0; - headerData.set(header!.data, pos); - pos = header!.length - encrypted.metadata.length; - headerData.set(encrypted.metadata, pos); - return Buffer.concat([headerData, Buffer.from(encrypted.data)]); - } + // Write encrypted data payload content. + const encryptedData = + typeof encrypted.data === 'string' + ? CryptoModule.encoder.encode(encrypted.data).buffer + : encrypted.data.buffer.slice(encrypted.data.byteOffset, encrypted.data.byteOffset + encrypted.data.length); - decrypt(data: ArrayBuffer | string) { - const encryptedData = Buffer.from(typeof data === 'string' ? decode(data) : data); - const header = CryptorHeader.tryParse(encryptedData); - const cryptor = this.getCryptor(header); - const metadata = - header.length > 0 - ? encryptedData.slice(header.length - (header as CryptorHeaderV1).metadataLength, header.length) - : null; - if (encryptedData.slice(header.length).byteLength <= 0) throw new Error('decryption error. empty content'); - return cryptor!.decrypt({ - data: encryptedData.slice(header.length), - metadata: metadata, - }); + return this.concatArrayBuffer(headerData, encryptedData); } - async encryptFile(file: PubNubFileType, File: PubNubFileType) { + async encryptFile(file: PubNubFile, File: PubNubFileConstructor) { /** * Files handled differently in case of Legacy cryptor. - * (as long as we support legacy need to check on intsance type) + * (as long as we support legacy need to check on instance type) */ if (this.defaultCryptor.identifier === CryptorHeader.LEGACY_IDENTIFIER) - return (this.defaultCryptor as ILegacyCryptor).encryptFile(file, File); + return (this.defaultCryptor as ILegacyCryptor).encryptFile(file, File); + if (file.data instanceof Buffer) { + const encryptedData = this.encrypt(file.data); + return File.create({ name: file.name, mimeType: 'application/octet-stream', - data: Buffer.from(this.encrypt(file.data!) as Buffer), + data: Buffer.from( + typeof encryptedData === 'string' ? CryptoModule.encoder.encode(encryptedData) : encryptedData, + ), }); } + if (file.data instanceof Readable) { - if (file.contentLength === 0) throw new Error('encryption error. empty content'); + if (!file.contentLength || file.contentLength === 0) throw new Error('Encryption error: empty content'); + const encryptedStream = await (this.defaultCryptor as ICryptor).encryptStream(file.data); const header = CryptorHeader.from(this.defaultCryptor.identifier, encryptedStream.metadata!); const payload = new Uint8Array(header!.length); let pos = 0; payload.set(header!.data, pos); pos += header!.length; + if (encryptedStream.metadata) { - pos -= encryptedStream.metadata.length; - payload.set(encryptedStream.metadata, pos); + const metadata = new Uint8Array(encryptedStream.metadata); + pos -= encryptedStream.metadata.byteLength; + payload.set(metadata, pos); } + const output = new PassThrough(); output.write(payload); encryptedStream.stream.pipe(output); + return File.create({ name: file.name, mimeType: 'application/octet-stream', @@ -125,172 +149,307 @@ export class CryptoModule { }); } } + // endregion + + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + // region Decryption - async decryptFile(file: PubNubFileType, File: PubNubFileType) { - if (file?.data instanceof Buffer) { - const header = CryptorHeader.tryParse(file.data); + decrypt(data: ArrayBuffer | string) { + const encryptedData = Buffer.from(typeof data === 'string' ? decode(data) : data); + const header = CryptorHeader.tryParse( + encryptedData.buffer.slice(encryptedData.byteOffset, encryptedData.byteOffset + encryptedData.length), + ); + const cryptor = this.getCryptor(header); + const metadata = + header.length > 0 + ? encryptedData.slice(header.length - (header as CryptorHeaderV1).metadataLength, header.length) + : null; + + if (encryptedData.slice(header.length).byteLength <= 0) throw new Error('Decryption error: empty content'); + + return cryptor!.decrypt({ + data: encryptedData.slice(header.length), + metadata: metadata, + }); + } + + async decryptFile( + file: PubNubFile, + File: PubNubFileConstructor, + ): Promise { + if (file.data && file.data instanceof Buffer) { + const header = CryptorHeader.tryParse( + file.data.buffer.slice(file.data.byteOffset, file.data.byteOffset + file.data.length), + ); const cryptor = this.getCryptor(header); /** - * If It's legacyone then redirect it. + * If It's legacy one then redirect it. * (as long as we support legacy need to check on instance type) */ if (cryptor?.identifier === CryptoModule.LEGACY_IDENTIFIER) - return (cryptor as ILegacyCryptor).decryptFile(file, File); + return (cryptor as ILegacyCryptor).decryptFile(file, File); + return File.create({ name: file.name, - data: Buffer.from(this.decrypt(file?.data) as ArrayBuffer), + data: Buffer.from(this.decrypt(file.data) as ArrayBuffer), }); } - if (file.data instanceof Readable) { + if (file.data && file.data instanceof Readable) { const stream = file.data; return new Promise((resolve) => { stream.on('readable', () => resolve(this.onStreamReadable(stream, file, File))); }); } } + // endregion + + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + // region Helpers + + /** + * Retrieve registered legacy cryptor. + * + * @returns Previously registered {@link ILegacyCryptor|legacy} cryptor. + * + * @throws Error if legacy cryptor not registered. + */ + private getLegacyCryptor(): ILegacyCryptor | undefined { + return this.getCryptorFromId(CryptoModule.LEGACY_IDENTIFIER) as ILegacyCryptor; + } + + /** + * Retrieve registered cryptor by its identifier. + * + * @param id - Unique cryptor identifier. + * + * @returns Registered cryptor with specified identifier. + * + * @throws Error if cryptor with specified {@link id} can't be found. + */ + private getCryptorFromId(id: string) { + const cryptor = this.getAllCryptors().find((cryptor) => id === cryptor.identifier); + if (cryptor) return cryptor; + + throw new Error('Unknown cryptor error'); + } + + /** + * Retrieve cryptor by its identifier. + * + * @param header - Header with cryptor-defined data or raw cryptor identifier. + * + * @returns Cryptor which correspond to provided {@link header}. + */ + private getCryptor(header: CryptorHeader | string) { + if (typeof header === 'string') { + const cryptor = this.getAllCryptors().find((c) => c.identifier === header); + if (cryptor) return cryptor; + + throw new Error('Unknown cryptor error'); + } else if (header instanceof CryptorHeaderV1) { + return this.getCryptorFromId(header.identifier); + } + } + + /** + * Create cryptor header data. + * + * @param encrypted - Encryption data object as source for header data. + * + * @returns Binary representation of the cryptor header data. + */ + private getHeaderData(encrypted: EncryptedDataType) { + if (!encrypted.metadata) return; + const header = CryptorHeader.from(this.defaultCryptor.identifier, encrypted.metadata); + const headerData = new Uint8Array(header!.length); + let pos = 0; + headerData.set(header!.data, pos); + pos += header!.length - encrypted.metadata.byteLength; + headerData.set(new Uint8Array(encrypted.metadata), pos); - private async onStreamReadable(stream: NodeJS.ReadableStream, file: PubNubFileType, File: PubNubFileType) { + return headerData.buffer; + } + + /** + * Merge two {@link ArrayBuffer} instances. + * + * @param ab1 - First {@link ArrayBuffer}. + * @param ab2 - Second {@link ArrayBuffer}. + * + * @returns Merged data as {@link ArrayBuffer}. + */ + private concatArrayBuffer(ab1: ArrayBuffer, ab2: ArrayBuffer): ArrayBuffer { + const tmp = new Uint8Array(ab1.byteLength + ab2.byteLength); + + tmp.set(new Uint8Array(ab1), 0); + tmp.set(new Uint8Array(ab2), ab1.byteLength); + + return tmp.buffer; + } + + /** + * {@link Readable} stream event handler. + * + * @param stream - Stream which can be used to read data for decryption. + * @param file - File object which has been created with {@link stream}. + * @param File - Class constructor for {@link PubNub} File object. + * + * @returns Decrypted data as {@link PubNub} File object. + * + * @throws Error if file is empty or contains unsupported data type. + */ + private async onStreamReadable( + stream: NodeJS.ReadableStream, + file: PubNubFile, + File: PubNubFileConstructor, + ) { stream.removeAllListeners('readable'); const magicBytes = stream.read(4); + if (!CryptorHeader.isSentinel(magicBytes as Buffer)) { - if (magicBytes === null) throw new Error('decryption error. empty content'); + if (magicBytes === null) throw new Error('Decryption error: empty content'); stream.unshift(magicBytes); + return this.decryptLegacyFileStream(stream, file, File); } + const versionByte = stream.read(1); CryptorHeader.validateVersion(versionByte[0] as number); const identifier = stream.read(4); const cryptor = this.getCryptorFromId(CryptorHeader.tryGetIdentifier(identifier as Buffer)); const headerSize = CryptorHeader.tryGetMetadataSizeFromStream(stream); - if (file.contentLength <= CryptorHeader.MIN_HEADER_LEGTH + headerSize) - throw new Error('decryption error. empty content'); + + if (!file.contentLength || file.contentLength <= CryptorHeader.MIN_HEADER_LENGTH + headerSize) + throw new Error('Decryption error: empty content'); + return File.create({ name: file.name, mimeType: 'application/octet-stream', - stream: await (cryptor as ICryptor).decryptStream({ stream: stream, metadataLength: headerSize as number }), + stream: (await (cryptor as ICryptor).decryptStream({ + stream: stream, + metadataLength: headerSize as number, + })) as Readable, }); } - private async decryptLegacyFileStream(stream: NodeJS.ReadableStream, file: PubNubFileType, File: PubNubFileType) { - if (file.contentLength <= 16) throw new Error('decryption error: empty content'); + /** + * Decrypt {@link Readable} stream using legacy cryptor. + * + * @param stream - Stream which can be used to read data for decryption. + * @param file - File object which has been created with {@link stream}. + * @param File - Class constructor for {@link PubNub} File object. + * + * @returns Decrypted data as {@link PubNub} File object. + * + * @throws Error if file is empty or contains unsupported data type. + */ + private async decryptLegacyFileStream( + stream: NodeJS.ReadableStream, + file: PubNubFile, + File: PubNubFileConstructor, + ) { + if (!file.contentLength || file.contentLength <= 16) throw new Error('Decryption error: empty content'); + const cryptor = this.getLegacyCryptor(); + if (cryptor) { - return (cryptor as ILegacyCryptor).decryptFile( + return cryptor.decryptFile( File.create({ name: file.name, - stream: stream, + stream: stream as Readable, }), File, ); - } else { - throw new Error('unknown cryptor error'); - } - } - - private getCryptor(header: CryptorHeader) { - if (header === '') { - const cryptor = this.getAllCryptors().find((c) => c.identifier === ''); - if (cryptor) return cryptor; - throw new Error('unknown cryptor error'); - } else if (header instanceof CryptorHeaderV1) { - return this.getCryptorFromId(header.identifier); - } - } - - private getCryptorFromId(id: string) { - const cryptor = this.getAllCryptors().find((c) => id === c.identifier); - if (cryptor) { - return cryptor; - } - throw new Error('unknown cryptor error'); + } else throw new Error('unknown cryptor error'); } + // endregion } -// CryptorHeader Utility +/** + * CryptorHeader Utility + */ class CryptorHeader { + static decoder = new TextDecoder(); static SENTINEL = 'PNED'; static LEGACY_IDENTIFIER = ''; static IDENTIFIER_LENGTH = 4; static VERSION = 1; static MAX_VERSION = 1; - static MIN_HEADER_LEGTH = 10; + static MIN_HEADER_LENGTH = 10; - static from(id: string, metadata: Buffer) { + static from(id: string, metadata: ArrayBuffer) { if (id === CryptorHeader.LEGACY_IDENTIFIER) return; - return new CryptorHeaderV1(id, metadata.length); + return new CryptorHeaderV1(id, metadata.byteLength); } - static isSentinel(bytes: Buffer) { - if (bytes && bytes.byteLength >= 4) { - if (bytes.toString('utf8') == CryptorHeader.SENTINEL) return true; - } + static isSentinel(bytes: ArrayBuffer) { + return bytes && bytes.byteLength >= 4 && CryptorHeader.decoder.decode(bytes) == CryptorHeader.SENTINEL; } static validateVersion(data: number) { - if (data && data > CryptorHeader.MAX_VERSION) throw new Error('decryption error. invalid header version'); + if (data && data > CryptorHeader.MAX_VERSION) throw new Error('Decryption error: invalid header version'); return data; } - static tryGetIdentifier(data: Buffer) { - if (data.byteLength < 4) { - throw new Error('unknown cryptor error. decryption failed'); - } else { - return data.toString('utf8'); - } + static tryGetIdentifier(data: ArrayBuffer) { + if (data.byteLength < 4) throw new Error('Decryption error: unknown cryptor error'); + else return CryptorHeader.decoder.decode(data); } static tryGetMetadataSizeFromStream(stream: NodeJS.ReadableStream) { const sizeBuf = stream.read(1); - if (sizeBuf && (sizeBuf[0] as number) < 255) { - return sizeBuf[0] as number; - } + + if (sizeBuf && (sizeBuf[0] as number) < 255) return sizeBuf[0] as number; if ((sizeBuf[0] as number) === 255) { const nextBuf = stream.read(2); + if (nextBuf.length >= 2) { return new Uint16Array([nextBuf[0] as number, nextBuf[1] as number]).reduce((acc, val) => (acc << 8) + val, 0); } } - throw new Error('decryption error. Invalid metadata size'); + + throw new Error('Decryption error: invalid metadata size'); } - static tryParse(encryptedData: Buffer) { - let sentinel: any = ''; + + static tryParse(encryptedData: ArrayBuffer) { + const encryptedDataView = new DataView(encryptedData); + let sentinel: ArrayBuffer; let version = null; - if (encryptedData.length >= 4) { + if (encryptedData.byteLength >= 4) { sentinel = encryptedData.slice(0, 4); - if (sentinel.toString('utf8') !== CryptorHeader.SENTINEL) return ''; + if (!this.isSentinel(sentinel)) return CryptoModule.LEGACY_IDENTIFIER; } - if (encryptedData.length >= 5) { - version = encryptedData[4]; - } else { - throw new Error('decryption error. invalid header version'); - } + if (encryptedData.byteLength >= 5) version = encryptedDataView.getInt8(4); + else throw new Error('Decryption error: invalid header version'); if (version > CryptorHeader.MAX_VERSION) throw new Error('unknown cryptor error'); - let identifier: Buffer; + let identifier: ArrayBuffer; let pos = 5 + CryptorHeader.IDENTIFIER_LENGTH; - if (encryptedData.length >= pos) { - identifier = encryptedData.slice(5, pos); - } else { - throw new Error('decryption error. invalid crypto identifier'); - } + if (encryptedData.byteLength >= pos) identifier = encryptedData.slice(5, pos); + else throw new Error('Decryption error: invalid crypto identifier'); + let metadataLength = null; - if (encryptedData.length >= pos + 1) { - metadataLength = encryptedData[pos]; - } else { - throw new Error('decryption error. invalid metadata length'); - } + if (encryptedData.byteLength >= pos + 1) metadataLength = encryptedDataView.getInt8(pos); + else throw new Error('Decryption error: invalid metadata length'); + pos += 1; - if (metadataLength === 255 && encryptedData.length >= pos + 2) { + if (metadataLength === 255 && encryptedData.byteLength >= pos + 2) { metadataLength = new Uint16Array(encryptedData.slice(pos, pos + 2)).reduce((acc, val) => (acc << 8) + val, 0); - pos += 2; } - return new CryptorHeaderV1(identifier.toString('utf8'), metadataLength); + + return new CryptorHeaderV1(CryptorHeader.decoder.decode(identifier), metadataLength); } } -// v1 CryptorHeader +/** + * Cryptor header (v1). + */ class CryptorHeaderV1 { _identifier; _metadataLength; @@ -337,14 +496,15 @@ class CryptorHeaderV1 { pos += CryptorHeader.SENTINEL.length; header[pos] = this.version; pos++; + if (this.identifier) header.set(Buffer.from(this.identifier), pos); - pos += CryptorHeader.IDENTIFIER_LENGTH; + const metadataLength = this.metadataLength; - if (metadataLength < 255) { - header[pos] = metadataLength; - } else { - header.set([255, metadataLength >> 8, metadataLength & 0xff], pos); - } + pos += CryptorHeader.IDENTIFIER_LENGTH; + + if (metadataLength < 255) header[pos] = metadataLength; + else header.set([255, metadataLength >> 8, metadataLength & 0xff], pos); + return header; } } diff --git a/src/crypto/modules/WebCryptoModule/ICryptor.ts b/src/crypto/modules/WebCryptoModule/ICryptor.ts index b15709c75..aa6080ce9 100644 --- a/src/crypto/modules/WebCryptoModule/ICryptor.ts +++ b/src/crypto/modules/WebCryptoModule/ICryptor.ts @@ -1,13 +1,86 @@ +/** + * Cryptor module. + */ + +/** + * Data encrypted by {@link CryptoModule}. + */ export type EncryptedDataType = { - data: ArrayBuffer; + /** + * Encrypted data. + */ + data: ArrayBuffer | string; + + /** + * Used cryptor's metadata. + */ metadata: ArrayBuffer | null; }; +/** + * Cryptor algorithm interface. + */ export interface ICryptor { + /** + * Cryptor unique identifier. + * + * @returns Cryptor identifier. + */ get identifier(): string; + + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + + // region Encryption + /** + * Encrypt provided source data. + * + * @param data - Source data for encryption. + * + * @returns Encrypted data object. + * + * @throws Error if unknown data type has been passed. + */ encrypt(data: ArrayBuffer | string): EncryptedDataType; - decrypt(data: EncryptedDataType): ArrayBuffer; + /** + * Encrypt provided source {@link ArrayBuffer}. + * + * @param data - Source {@link ArrayBuffer} for encryption. + * + * @returns Encrypted data object. + * + * @throws Error if unknown data type has been passed. + */ encryptFileData(data: ArrayBuffer): Promise; - decryptFileData(data: EncryptedDataType): Promise; + // endregion + + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + + // region Decryption + /** + * Decrypt provided encrypted data object. + * + * @param data - Encrypted data object for decryption. + * + * @returns Decrypted data. + * + * @throws Error if unknown data type has been passed. + */ + decrypt(data: EncryptedDataType): ArrayBuffer; + + /** + * Decrypt provided encrypted {@link ArrayBuffer} File object. + * + * @param file - Encrypted {@link ArrayBuffer} for decryption. + * + * @returns Decrypted data as {@link ArrayBuffer}. + * + * @throws Error if unknown data type has been passed. + */ + decryptFileData(file: EncryptedDataType): Promise; + // endregion } diff --git a/src/crypto/modules/WebCryptoModule/ILegacyCryptor.ts b/src/crypto/modules/WebCryptoModule/ILegacyCryptor.ts index c9ae022c0..a0afa95e5 100644 --- a/src/crypto/modules/WebCryptoModule/ILegacyCryptor.ts +++ b/src/crypto/modules/WebCryptoModule/ILegacyCryptor.ts @@ -1,24 +1,86 @@ +/** + * Legacy cryptor module. + */ + +import { PubNubFile, PubNubFileParameters } from '../../../file/modules/web'; +import { PubNubFileConstructor } from '../../../core/types/file'; +import { Payload } from '../../../core/types/api'; import { EncryptedDataType } from './ICryptor'; -export type PubNubFileType = { - data: File | Blob; - name: string; - mimeType: string; +/** + * Legacy cryptor algorithm interface. + */ +export interface ILegacyCryptor { + /** + * Cryptor unique identifier. + * + * @returns Cryptor identifier. + */ + get identifier(): string; + + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- - create(config: any): PubNubFileType; + // region Encryption + /** + * Encrypt provided source data. + * + * @param data - Source data for encryption. + * + * @returns Encrypted data object. + * + * @throws Error if unknown data type has been passed. + */ + encrypt(data: ArrayBuffer | string): EncryptedDataType; - toArrayBuffer(): ArrayBuffer; - toBlob(): Blob; - toString(): string; - toFile(): File; -}; + /** + * Encrypt provided source {@link PubNub} File object. + * + * @param file - Source {@link PubNub} File object for encryption. + * @param File - Class constructor for {@link PubNub} File object. + * + * @returns Encrypted data as {@link PubNub} File object. + * + * @throws Error if file is empty or contains unsupported data type. + * @throws Error if cipher key not set. + */ + encryptFile( + file: PubNubFile, + File: PubNubFileConstructor, + ): Promise; + // endregion -export interface ILegacyCryptor { - get identifier(): string; + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- - encrypt(data: ArrayBuffer | string): EncryptedDataType; - decrypt(data: EncryptedDataType): ArrayBuffer | string; + // region Decryption + /** + * Decrypt provided encrypted data object. + * + * @param data - Encrypted data object for decryption. + * + * @returns Decrypted data. + * + * @throws Error if unknown data type has been passed. + */ + decrypt(data: EncryptedDataType): Payload | null; - encryptFile(file: T, File: T): Promise; - decryptFile(file: T, File: T): Promise; + /** + * Decrypt provided encrypted {@link PubNub} File object. + * + * @param file - Encrypted {@link PubNub} File object for decryption. + * @param File - Class constructor for {@link PubNub} File object. + * + * @returns Decrypted data as {@link PubNub} File object. + * + * @throws Error if file is empty or contains unsupported data type. + * @throws Error if cipher key not set. + */ + decryptFile( + file: PubNubFile, + File: PubNubFileConstructor, + ): Promise; + // endregion } diff --git a/src/crypto/modules/WebCryptoModule/aesCbcCryptor.ts b/src/crypto/modules/WebCryptoModule/aesCbcCryptor.ts index 78bda2175..6aed65a1b 100644 --- a/src/crypto/modules/WebCryptoModule/aesCbcCryptor.ts +++ b/src/crypto/modules/WebCryptoModule/aesCbcCryptor.ts @@ -1,44 +1,58 @@ -import { ICryptor, EncryptedDataType } from './ICryptor'; +/** + * AES-CBC cryptor module. + */ + import cryptoJS from '../../../core/components/cryptography/hmac-sha256'; import { decode } from '../../../core/components/base64_codec'; +import { ICryptor, EncryptedDataType } from './ICryptor'; +/** + * AES-CBC cryptor. + * + * AES-CBC cryptor with enhanced cipher strength. + */ export default class AesCbcCryptor implements ICryptor { + /** + * Cryptor block size. + */ static BLOCK_SIZE = 16; + + /** + * {@link string|String} to {@link ArrayBuffer} response decoder. + */ static encoder = new TextEncoder(); + + /** + * {@link ArrayBuffer} to {@link string} decoder. + */ static decoder = new TextDecoder(); + /** + * Data encryption / decryption cipher key. + */ cipherKey: string; + + /* eslint-disable @typescript-eslint/no-explicit-any */ encryptedKey: any; + /* eslint-disable @typescript-eslint/no-explicit-any */ CryptoJS: any; - constructor(configuration: { cipherKey: string }) { - this.cipherKey = configuration.cipherKey; + constructor({ cipherKey }: { cipherKey: string }) { + this.cipherKey = cipherKey; this.CryptoJS = cryptoJS; - this.encryptedKey = this.CryptoJS.SHA256(this.cipherKey); + this.encryptedKey = this.CryptoJS.SHA256(cipherKey); } - get algo() { - return 'AES-CBC'; - } + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + // region Encryption - get identifier() { - return 'ACRH'; - } - - private getIv() { - return crypto.getRandomValues(new Uint8Array(AesCbcCryptor.BLOCK_SIZE)); - } - - private async getKey() { - const bKey = AesCbcCryptor.encoder.encode(this.cipherKey); - const abHash = await crypto.subtle.digest('SHA-256', bKey.buffer); - return crypto.subtle.importKey('raw', abHash, this.algo, true, ['encrypt', 'decrypt']); - } - - encrypt(data: ArrayBuffer | string) { + encrypt(data: ArrayBuffer | string): EncryptedDataType { const stringData = typeof data === 'string' ? data : AesCbcCryptor.decoder.decode(data); if (stringData.length === 0) throw new Error('encryption error. empty content'); const abIv = this.getIv(); + return { metadata: abIv, data: decode( @@ -50,9 +64,28 @@ export default class AesCbcCryptor implements ICryptor { }; } + async encryptFileData(data: ArrayBuffer): Promise { + const key = await this.getKey(); + const iv = this.getIv(); + return { + data: await crypto.subtle.encrypt({ name: this.algo, iv: iv }, key, data), + metadata: iv, + }; + } + // endregion + + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + // region Decryption + decrypt(encryptedData: EncryptedDataType) { + if (typeof encryptedData.data === 'string') + throw new Error('Decryption error: data for decryption should be ArrayBuffed.'); + const iv = this.bufferToWordArray(new Uint8ClampedArray(encryptedData.metadata!)); const data = this.bufferToWordArray(new Uint8ClampedArray(encryptedData.data)); + return AesCbcCryptor.encoder.encode( this.CryptoJS.AES.decrypt({ ciphertext: data }, this.encryptedKey, { iv, @@ -61,26 +94,69 @@ export default class AesCbcCryptor implements ICryptor { ).buffer; } - async encryptFileData(data: ArrayBuffer): Promise { - const key = await this.getKey(); - const iv = this.getIv(); - return { - data: await crypto.subtle.encrypt({ name: this.algo, iv: iv }, key, data), - metadata: iv, - }; - } - async decryptFileData(encryptedData: EncryptedDataType): Promise { + if (typeof encryptedData.data === 'string') + throw new Error('Decryption error: data for decryption should be ArrayBuffed.'); + const key = await this.getKey(); return crypto.subtle.decrypt({ name: this.algo, iv: encryptedData.metadata! }, key, encryptedData.data); } + // endregion + + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + // region Helpers + + get identifier() { + return 'ACRH'; + } - private bufferToWordArray(b: any) { - const wa: any[] = []; + /** + * Cryptor algorithm. + * + * @returns Cryptor module algorithm. + */ + private get algo() { + return 'AES-CBC'; + } + + /** + * Generate random initialization vector. + * + * @returns Random initialization vector. + */ + + private getIv() { + return crypto.getRandomValues(new Uint8Array(AesCbcCryptor.BLOCK_SIZE)); + } + + /** + * Convert cipher key to the {@link Buffer}. + * + * @returns SHA256 encoded cipher key {@link Buffer}. + */ + private async getKey() { + const bKey = AesCbcCryptor.encoder.encode(this.cipherKey); + const abHash = await crypto.subtle.digest('SHA-256', bKey.buffer); + return crypto.subtle.importKey('raw', abHash, this.algo, true, ['encrypt', 'decrypt']); + } + + /** + * Convert bytes array to words array. + * + * @param b - Bytes array (buffer) which should be converted. + * + * @returns Word sized array. + */ + private bufferToWordArray(b: string | any[] | Uint8Array | Uint8ClampedArray) { + const wa: number[] = []; let i; + for (i = 0; i < b.length; i += 1) { wa[(i / 4) | 0] |= b[i] << (24 - 8 * i); } + return this.CryptoJS.lib.WordArray.create(wa, b.length); } } diff --git a/src/crypto/modules/WebCryptoModule/legacyCryptor.ts b/src/crypto/modules/WebCryptoModule/legacyCryptor.ts index db4b96bed..3f0a07704 100644 --- a/src/crypto/modules/WebCryptoModule/legacyCryptor.ts +++ b/src/crypto/modules/WebCryptoModule/legacyCryptor.ts @@ -1,46 +1,98 @@ +/** + * Legacy cryptor module. + */ + +import { CryptorConfiguration } from '../../../core/interfaces/crypto-module'; +import { PubNubFile, PubNubFileParameters } from '../../../file/modules/web'; import Crypto from '../../../core/components/cryptography/index'; -import FileCryptor from '../web'; -import { EncryptedDataType } from './ICryptor'; -import { ILegacyCryptor, PubNubFileType } from './ILegacyCryptor'; +import { PubNubFileConstructor } from '../../../core/types/file'; import { encode } from '../../../core/components/base64_codec'; +import { PubNubError } from '../../../errors/pubnub-error'; +import { ILegacyCryptor } from './ILegacyCryptor'; +import { EncryptedDataType } from './ICryptor'; +import FileCryptor from '../web'; + +/** + * Legacy cryptor. + */ +export default class LegacyCryptor implements ILegacyCryptor { + /** + * `string` to {@link ArrayBuffer} response decoder. + */ + static encoder = new TextEncoder(); + + /** + * {@link ArrayBuffer} to {@link string} decoder. + */ + static decoder = new TextDecoder(); -export default class LegacyCryptor implements ILegacyCryptor { + /** + * Legacy cryptor configuration. + */ config; - cryptor; + /** + * Configured file cryptor. + */ fileCryptor; - constructor(config: any) { + /** + * Configured legacy cryptor. + */ + cryptor; + + constructor(config: CryptorConfiguration) { this.config = config; - this.cryptor = new Crypto({ config }); + this.cryptor = new Crypto({ ...config }); this.fileCryptor = new FileCryptor(); } - get identifier() { - return ''; - } + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + // region Encryption + encrypt(data: ArrayBuffer | string) { - const stringData = typeof data === 'string' ? data : new TextDecoder().decode(data); + const stringData = typeof data === 'string' ? data : LegacyCryptor.decoder.decode(data); + return { data: this.cryptor.encrypt(stringData), metadata: null, }; } + async encryptFile(file: PubNubFile, File: PubNubFileConstructor) { + if (!this.config.cipherKey) throw new PubNubError('File encryption error: cipher key not set.'); + + return this.fileCryptor.encryptFile(this.config?.cipherKey, file, File); + } + // endregion + + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + // region Decryption + decrypt(encryptedData: EncryptedDataType) { const data = typeof encryptedData.data === 'string' ? encryptedData.data : encode(encryptedData.data); + return this.cryptor.decrypt(data); } - async encryptFile(file: PubNubFileType, File: PubNubFileType) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - //@ts-ignore: can not detect cipherKey from old Config - return this.fileCryptor.encryptFile(this.config?.cipherKey, file, File); - } + async decryptFile(file: PubNubFile, File: PubNubFileConstructor) { + if (!this.config.cipherKey) throw new PubNubError('File encryption error: cipher key not set.'); - async decryptFile(file: PubNubFileType, File: PubNubFileType) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - //@ts-ignore: can not detect cipherKey from old Config return this.fileCryptor.decryptFile(this.config.cipherKey, file, File); } + // endregion + + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + // region Helpers + + get identifier() { + return ''; + } + // endregion } diff --git a/src/crypto/modules/WebCryptoModule/webCryptoModule.ts b/src/crypto/modules/WebCryptoModule/webCryptoModule.ts index 5b5217dad..b58b615c2 100644 --- a/src/crypto/modules/WebCryptoModule/webCryptoModule.ts +++ b/src/crypto/modules/WebCryptoModule/webCryptoModule.ts @@ -1,69 +1,125 @@ -import LegacyCryptor from './legacyCryptor'; -import AesCbcCryptor from './aesCbcCryptor'; -import { EncryptedDataType, ICryptor } from './ICryptor'; -import { ILegacyCryptor, PubNubFileType } from './ILegacyCryptor'; +/** + * Browser crypto module. + */ + +import { AbstractCryptoModule, CryptorConfiguration } from '../../../core/interfaces/crypto-module'; +import { PubNubFile, PubNubFileParameters } from '../../../file/modules/web'; +import { PubNubFileConstructor } from '../../../core/types/file'; import { decode } from '../../../core/components/base64_codec'; +import { PubNubError } from '../../../errors/pubnub-error'; +import { EncryptedDataType, ICryptor } from './ICryptor'; +import { ILegacyCryptor } from './ILegacyCryptor'; +import AesCbcCryptor from './aesCbcCryptor'; +import LegacyCryptor from './legacyCryptor'; +/** + * Re-export bundled cryptors. + */ export { LegacyCryptor, AesCbcCryptor }; -type CryptorType = ICryptor | ILegacyCryptor; - -type CryptoModuleConfiguration = { - default: CryptorType; - cryptors?: Array; -}; - -export class CryptoModule { +/** + * Crypto module cryptors interface. + */ +type CryptorType = ICryptor | ILegacyCryptor; + +/** + * CryptoModule for browser platform. + */ +export class WebCryptoModule extends AbstractCryptoModule { + /** + * {@link LegacyCryptor|Legacy} cryptor identifier. + */ static LEGACY_IDENTIFIER = ''; - static encoder = new TextEncoder(); - static decoder = new TextDecoder(); - defaultCryptor: CryptorType; - cryptors: Array; - constructor(cryptoModuleConfiguration: CryptoModuleConfiguration) { - this.defaultCryptor = cryptoModuleConfiguration.default; - this.cryptors = cryptoModuleConfiguration.cryptors ?? []; - } + // -------------------------------------------------------- + // --------------- Convenience functions ------------------ + // ------------------------------------------------------- + // region Convenience functions - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - //@ts-ignore: type detection issue with old Config type assignment - static legacyCryptoModule(config) { - return new this({ + static legacyCryptoModule(config: CryptorConfiguration) { + if (!config.cipherKey) throw new PubNubError('Crypto module error: cipher key not set.'); + + return new WebCryptoModule({ default: new LegacyCryptor({ - cipherKey: config.cipherKey, + ...config, useRandomIVs: config.useRandomIVs ?? true, }), cryptors: [new AesCbcCryptor({ cipherKey: config.cipherKey })], }); } - static aesCbcCryptoModule(config: any) { - return new this({ + static aesCbcCryptoModule(config: CryptorConfiguration) { + if (!config.cipherKey) throw new PubNubError('Crypto module error: cipher key not set.'); + + return new WebCryptoModule({ default: new AesCbcCryptor({ cipherKey: config.cipherKey }), cryptors: [ new LegacyCryptor({ - cipherKey: config.cipherKey, + ...config, useRandomIVs: config.useRandomIVs ?? true, }), ], }); } + /** + * Construct crypto module with `cryptor` as default for data encryption and decryption. + * + * @param defaultCryptor - Default cryptor for data encryption and decryption. + * + * @returns Crypto module with pre-configured default cryptor. + */ static withDefaultCryptor(defaultCryptor: CryptorType) { return new this({ default: defaultCryptor }); } + // endregion - private getAllCryptors() { - return [this.defaultCryptor, ...this.cryptors]; - } + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + // region Encryption encrypt(data: ArrayBuffer | string) { - const encrypted = (this.defaultCryptor as ICryptor).encrypt(data); + // Encrypt data. + const encrypted = + data instanceof ArrayBuffer && this.defaultCryptor.identifier === WebCryptoModule.LEGACY_IDENTIFIER + ? (this.defaultCryptor as ILegacyCryptor).encrypt(WebCryptoModule.decoder.decode(data)) + : (this.defaultCryptor as ICryptor).encrypt(data); + if (!encrypted.metadata) return encrypted.data; + else if (typeof encrypted.data === 'string') + throw new Error('Encryption error: encrypted data should be ArrayBuffed.'); + const headerData = this.getHeaderData(encrypted); + return this.concatArrayBuffer(headerData!, encrypted.data); } + async encryptFile(file: PubNubFile, File: PubNubFileConstructor) { + /** + * Files handled differently in case of Legacy cryptor. + * (as long as we support legacy need to check on instance type) + */ + if (this.defaultCryptor.identifier === CryptorHeader.LEGACY_IDENTIFIER) + return (this.defaultCryptor as ILegacyCryptor).encryptFile(file, File); + + const fileData = await this.getFileData(file); + const encrypted = await (this.defaultCryptor as ICryptor).encryptFileData(fileData); + if (typeof encrypted.data === 'string') throw new Error('Encryption error: encrypted data should be ArrayBuffed.'); + + return File.create({ + name: file.name, + mimeType: 'application/octet-stream', + data: this.concatArrayBuffer(this.getHeaderData(encrypted)!, encrypted.data), + }); + } + // endregion + + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + // region Decryption + decrypt(data: ArrayBuffer | string) { const encryptedData = typeof data === 'string' ? decode(data) : data; const header = CryptorHeader.tryParse(encryptedData); @@ -72,34 +128,29 @@ export class CryptoModule { header.length > 0 ? encryptedData.slice(header.length - (header as CryptorHeaderV1).metadataLength, header.length) : null; - if (encryptedData.slice(header.length).byteLength <= 0) throw new Error('decryption error. empty content'); + + if (encryptedData.slice(header.length).byteLength <= 0) throw new Error('Decryption error: empty content'); + return cryptor!.decrypt({ data: encryptedData.slice(header.length), metadata: metadata, }); } - async encryptFile(file: PubNubFileType, File: PubNubFileType) { - if (this.defaultCryptor.identifier === CryptorHeader.LEGACY_IDENTIFIER) - return (this.defaultCryptor as ILegacyCryptor).encryptFile(file, File); - const fileData = await this.getFileData(file.data); - const encrypted = await (this.defaultCryptor as ICryptor).encryptFileData(fileData); - return File.create({ - name: file.name, - mimeType: 'application/octet-stream', - data: this.concatArrayBuffer(this.getHeaderData(encrypted)!, encrypted.data), - }); - } - - async decryptFile(file: PubNubFileType, File: PubNubFileType) { + async decryptFile(file: PubNubFile, File: PubNubFileConstructor) { const data = await file.data.arrayBuffer(); const header = CryptorHeader.tryParse(data); const cryptor = this.getCryptor(header); - if (cryptor?.identifier === CryptoModule.LEGACY_IDENTIFIER) { - return (cryptor as ILegacyCryptor).decryptFile(file, File); - } + /** + * Files handled differently in case of Legacy cryptor. + * (as long as we support legacy need to check on instance type) + */ + if (cryptor?.identifier === CryptorHeader.LEGACY_IDENTIFIER) + return (cryptor as ILegacyCryptor).decryptFile(file, File); + const fileData = await this.getFileData(data); const metadata = fileData.slice(header.length - (header as CryptorHeaderV1).metadataLength, header.length); + return File.create({ name: file.name, data: await (this.defaultCryptor as ICryptor).decryptFileData({ @@ -108,34 +159,54 @@ export class CryptoModule { }), }); } + // endregion + + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + // region Helpers + + /** + * Retrieve registered cryptor by its identifier. + * + * @param id - Unique cryptor identifier. + * + * @returns Registered cryptor with specified identifier. + * + * @throws Error if cryptor with specified {@link id} can't be found. + */ + private getCryptorFromId(id: string) { + const cryptor = this.getAllCryptors().find((cryptor) => id === cryptor.identifier); + if (cryptor) return cryptor; - private getCryptor(header: string | CryptorHeaderV1) { - if (header === '') { - const cryptor = this.getAllCryptors().find((c) => c.identifier === ''); + throw Error('Unknown cryptor error'); + } + + /** + * Retrieve cryptor by its identifier. + * + * @param header - Header with cryptor-defined data or raw cryptor identifier. + * + * @returns Cryptor which correspond to provided {@link header}. + */ + private getCryptor(header: CryptorHeader | string) { + if (typeof header === 'string') { + const cryptor = this.getAllCryptors().find((cryptor) => cryptor.identifier === header); if (cryptor) return cryptor; - throw new Error('unknown cryptor error'); + + throw new Error('Unknown cryptor error'); } else if (header instanceof CryptorHeaderV1) { return this.getCryptorFromId(header.identifier); } } - private getCryptorFromId(id: string) { - const cryptor = this.getAllCryptors().find((c) => id === c.identifier); - if (cryptor) { - return cryptor; - } - throw Error('unknown cryptor error'); - } - - private concatArrayBuffer(ab1: ArrayBuffer, ab2: ArrayBuffer) { - const tmp = new Uint8Array(ab1.byteLength + ab2.byteLength); - - tmp.set(new Uint8Array(ab1), 0); - tmp.set(new Uint8Array(ab2), ab1.byteLength); - - return tmp.buffer; - } - + /** + * Create cryptor header data. + * + * @param encrypted - Encryption data object as source for header data. + * + * @returns Binary representation of the cryptor header data. + */ private getHeaderData(encrypted: EncryptedDataType) { if (!encrypted.metadata) return; const header = CryptorHeader.from(this.defaultCryptor.identifier, encrypted.metadata); @@ -147,24 +218,43 @@ export class CryptoModule { return headerData.buffer; } - private async getFileData(input: any) { - if (input instanceof Blob) { - const fileData = await input.arrayBuffer(); - return fileData; - } - if (input instanceof ArrayBuffer) { - return input; - } - if (typeof input === 'string') { - return CryptoModule.encoder.encode(input); - } + /** + * Merge two {@link ArrayBuffer} instances. + * + * @param ab1 - First {@link ArrayBuffer}. + * @param ab2 - Second {@link ArrayBuffer}. + * + * @returns Merged data as {@link ArrayBuffer}. + */ + private concatArrayBuffer(ab1: ArrayBuffer, ab2: ArrayBuffer): ArrayBuffer { + const tmp = new Uint8Array(ab1.byteLength + ab2.byteLength); + + tmp.set(new Uint8Array(ab1), 0); + tmp.set(new Uint8Array(ab2), ab1.byteLength); + + return tmp.buffer; + } + + /** + * Retrieve file content. + * + * @param file - Content of the {@link PubNub} File object. + * + * @returns Normalized file {@link data} as {@link ArrayBuffer}; + */ + private async getFileData(file: PubNubFile | ArrayBuffer) { + if (file instanceof ArrayBuffer) return file; + else if (file instanceof PubNubFile) return file.toArrayBuffer(); + throw new Error( 'Cannot decrypt/encrypt file. In browsers file encrypt/decrypt supported for string, ArrayBuffer or Blob', ); } } -// CryptorHeader Utility +/** + * CryptorHeader Utility + */ class CryptorHeader { static SENTINEL = 'PNED'; static LEGACY_IDENTIFIER = ''; @@ -180,37 +270,33 @@ class CryptorHeader { static tryParse(data: ArrayBuffer) { const encryptedData = new Uint8Array(data); - let sentinel: any = ''; + let sentinel: Uint8Array; let version = null; + if (encryptedData.byteLength >= 4) { sentinel = encryptedData.slice(0, 4); - if (this.decoder.decode(sentinel) !== CryptorHeader.SENTINEL) return ''; + if (this.decoder.decode(sentinel) !== CryptorHeader.SENTINEL) return WebCryptoModule.LEGACY_IDENTIFIER; } - if (encryptedData.byteLength >= 5) { - version = (encryptedData as Uint8Array)[4] as number; - } else { - throw new Error('decryption error. invalid header version'); - } - if (version > CryptorHeader.MAX_VERSION) throw new Error('unknown cryptor error'); - let identifier: any = ''; + if (encryptedData.byteLength >= 5) version = (encryptedData as Uint8Array)[4] as number; + else throw new Error('Decryption error: invalid header version'); + + if (version > CryptorHeader.MAX_VERSION) throw new Error('Decryption error: Unknown cryptor error'); + + let identifier: Uint8Array; let pos = 5 + CryptorHeader.IDENTIFIER_LENGTH; - if (encryptedData.byteLength >= pos) { - identifier = encryptedData.slice(5, pos); - } else { - throw new Error('decryption error. invalid crypto identifier'); - } + if (encryptedData.byteLength >= pos) identifier = encryptedData.slice(5, pos); + else throw new Error('Decryption error: invalid crypto identifier'); + let metadataLength = null; - if (encryptedData.byteLength >= pos + 1) { - metadataLength = (encryptedData as Uint8Array)[pos]; - } else { - throw new Error('decryption error. invalid metadata length'); - } + if (encryptedData.byteLength >= pos + 1) metadataLength = (encryptedData as Uint8Array)[pos]; + else throw new Error('Decryption error: invalid metadata length'); + pos += 1; if (metadataLength === 255 && encryptedData.byteLength >= pos + 2) { metadataLength = new Uint16Array(encryptedData.slice(pos, pos + 2)).reduce((acc, val) => (acc << 8) + val, 0); - pos += 2; } + return new CryptorHeaderV1(this.decoder.decode(identifier), metadataLength); } } @@ -266,14 +352,15 @@ class CryptorHeaderV1 { pos += CryptorHeader.SENTINEL.length; header[pos] = this.version; pos++; + if (this.identifier) header.set(encoder.encode(this.identifier), pos); - pos += CryptorHeader.IDENTIFIER_LENGTH; + const metadataLength = this.metadataLength; - if (metadataLength < 255) { - header[pos] = metadataLength; - } else { - header.set([255, metadataLength >> 8, metadataLength & 0xff], pos); - } + pos += CryptorHeader.IDENTIFIER_LENGTH; + + if (metadataLength < 255) header[pos] = metadataLength; + else header.set([255, metadataLength >> 8, metadataLength & 0xff], pos); + return header; } } diff --git a/src/crypto/modules/node.js b/src/crypto/modules/node.js deleted file mode 100644 index 11055962c..000000000 --- a/src/crypto/modules/node.js +++ /dev/null @@ -1,191 +0,0 @@ -/** */ -import { Readable, PassThrough, Transform } from 'stream'; -import { createCipheriv, createDecipheriv, createHash, randomBytes } from 'crypto'; - -export default class NodeCryptography { - static IV_LENGTH = 16; - - get algo() { - return 'aes-256-cbc'; - } - - async encrypt(key, input) { - const bKey = this.getKey(key); - if (input instanceof Buffer) { - return this.encryptBuffer(bKey, input); - } - if (input instanceof Readable) { - return this.encryptStream(bKey, input); - } - if (typeof input === 'string') { - return this.encryptString(bKey, input); - } - throw new Error('Unsupported input format'); - } - - async decrypt(key, input) { - const bKey = this.getKey(key); - if (input instanceof Buffer) { - return this.decryptBuffer(bKey, input); - } - if (input instanceof Readable) { - return this.decryptStream(bKey, input); - } - if (typeof input === 'string') { - return this.decryptString(bKey, input); - } - throw new Error('Unsupported input format'); - } - - async encryptFile(key, file, File) { - const bKey = this.getKey(key); - - if (file.data instanceof Buffer) { - if (file.data.byteLength <= 0) throw new Error('encryption error. empty content'); - return File.create({ - name: file.name, - mimeType: 'application/octet-stream', - data: await this.encryptBuffer(bKey, file.data), - }); - } - if (file.data instanceof Readable) { - if (file.contentLength === 0) throw new Error('encryption error. empty content'); - return File.create({ - name: file.name, - mimeType: 'application/octet-stream', - stream: await this.encryptStream(bKey, file.data), - }); - } - throw new Error('Cannot encrypt this file. In Node.js file encryption supports only string, Buffer or Stream.'); - } - - async decryptFile(key, file, File) { - const bKey = this.getKey(key); - - if (file.data instanceof Buffer) { - return File.create({ - name: file.name, - data: await this.decryptBuffer(bKey, file.data), - }); - } - if (file.data instanceof Readable) { - return File.create({ - name: file.name, - stream: await this.decryptStream(bKey, file.data), - }); - } - throw new Error('Cannot decrypt this file. In Node.js file decryption supports only string, Buffer or Stream.'); - } - - getKey(key) { - const sha = createHash('sha256'); - - sha.update(Buffer.from(key, 'utf8')); - - return Buffer.from(sha.digest('hex').slice(0, 32), 'utf8'); - } - - getIv() { - return randomBytes(NodeCryptography.IV_LENGTH); - } - - encryptString(key, plaintext) { - const bIv = this.getIv(); - - const bPlaintext = Buffer.from(plaintext); - - const aes = createCipheriv(this.algo, key, bIv); - - return Buffer.concat([bIv, aes.update(bPlaintext), aes.final()]).toString('utf8'); - } - - decryptString(key, sCiphertext) { - const ciphertext = Buffer.from(sCiphertext); - const bIv = ciphertext.slice(0, NodeCryptography.IV_LENGTH); - const bCiphertext = ciphertext.slice(NodeCryptography.IV_LENGTH); - - const aes = createDecipheriv(this.algo, key, bIv); - - return Buffer.concat([aes.update(bCiphertext), aes.final()]).toString('utf8'); - } - - encryptBuffer(key, plaintext) { - const bIv = this.getIv(); - - const aes = createCipheriv(this.algo, key, bIv); - - return Buffer.concat([bIv, aes.update(plaintext), aes.final()]); - } - - decryptBuffer(key, ciphertext) { - const bIv = ciphertext.slice(0, NodeCryptography.IV_LENGTH); - const bCiphertext = ciphertext.slice(NodeCryptography.IV_LENGTH); - if (bCiphertext.byteLength <= 0) throw new Error('decryption error: empty content'); - const aes = createDecipheriv(this.algo, key, bIv); - - return Buffer.concat([aes.update(bCiphertext), aes.final()]); - } - - async encryptStream(key, stream) { - const bIv = this.getIv(); - const aes = createCipheriv('aes-256-cbc', key, bIv).setAutoPadding(true); - let inited = false; - return stream.pipe(aes).pipe( - new Transform({ - transform(chunk, _, cb) { - if (!inited) { - inited = true; - this.push(Buffer.concat([bIv, chunk])); - } else { - this.push(chunk); - } - cb(); - }, - }), - ); - } - - decryptStream(key, stream) { - const output = new PassThrough(); - - let bIv = Buffer.alloc(0); - let aes = null; - - const getIv = () => { - let data = stream.read(); - - while (data !== null) { - if (data) { - const bChunk = Buffer.from(data); - const sliceLen = NodeCryptography.IV_LENGTH - bIv.byteLength; - - if (bChunk.byteLength < sliceLen) { - bIv = Buffer.concat([bIv, bChunk]); - } else { - bIv = Buffer.concat([bIv, bChunk.slice(0, sliceLen)]); - - aes = createDecipheriv(this.algo, key, bIv); - - aes.pipe(output); - - aes.write(bChunk.slice(sliceLen)); - } - } - - data = stream.read(); - } - }; - - stream.on('readable', getIv); - - stream.on('end', () => { - if (aes) { - aes.end(); - } - - output.end(); - }); - - return output; - } -} diff --git a/src/crypto/modules/node.ts b/src/crypto/modules/node.ts new file mode 100644 index 000000000..e0eacbd77 --- /dev/null +++ b/src/crypto/modules/node.ts @@ -0,0 +1,300 @@ +/** + * Legacy Node.js cryptography module. + */ + +import { createCipheriv, createDecipheriv, createHash, randomBytes } from 'crypto'; +import { Readable, PassThrough, Transform } from 'stream'; +import { Buffer } from 'buffer'; + +import PubNubFile, { PubNubFileParameters } from '../../file/modules/node'; +import { Cryptography } from '../../core/interfaces/cryptography'; +import { PubNubFileConstructor } from '../../core/types/file'; + +/** + * Legacy cryptography implementation for Node.js-based {@link PubNub} client. + */ +export default class NodeCryptography implements Cryptography { + /** + * Random initialization vector size. + */ + static IV_LENGTH = 16; + + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + // region Encryption + + public async encrypt( + key: string, + input: string | ArrayBuffer | Buffer | Readable, + ): Promise { + const bKey = this.getKey(key); + + if (input instanceof Buffer) return this.encryptBuffer(bKey, input); + if (input instanceof Readable) return this.encryptStream(bKey, input); + if (typeof input === 'string') return this.encryptString(bKey, input); + + throw new Error('Encryption error: unsupported input format'); + } + + /** + * Encrypt provided source {@link Buffer} using specific encryption {@link key}. + * + * @param key - Data encryption key.
**Note:** Same key should be used to `decrypt` {@link Buffer}. + * @param buffer - Source {@link Buffer} for encryption. + * + * @returns Encrypted data as {@link Buffer} object. + */ + private encryptBuffer(key: Buffer, buffer: Buffer) { + const bIv = this.getIv(); + const aes = createCipheriv(this.algo, key, bIv); + + return Buffer.concat([bIv, aes.update(buffer), aes.final()]); + } + + /** + * Encrypt provided source {@link Readable} stream using specific encryption {@link key}. + * + * @param key - Data encryption key.
**Note:** Same key should be used to `decrypt` {@link Readable} stream. + * @param stream - Source {@link Readable} stream for encryption. + * + * @returns Encrypted data as {@link Transform} object. + */ + private async encryptStream(key: Buffer, stream: Readable) { + const bIv = this.getIv(); + const aes = createCipheriv(this.algo, key, bIv).setAutoPadding(true); + let initiated = false; + + return stream.pipe(aes).pipe( + new Transform({ + transform(chunk, _, cb) { + if (!initiated) { + initiated = true; + this.push(Buffer.concat([bIv, chunk])); + } else this.push(chunk); + + cb(); + }, + }), + ); + } + + /** + * Encrypt provided source {@link string} using specific encryption {@link key}. + * + * @param key - Data encryption key.
**Note:** Same key should be used to `decrypt` {@link string}. + * @param text - Source {@link string} for encryption. + * + * @returns Encrypted data as byte {@link string}. + */ + private encryptString(key: Buffer, text: string) { + const bIv = this.getIv(); + const bPlaintext = Buffer.from(text); + const aes = createCipheriv(this.algo, key, bIv); + + return Buffer.concat([bIv, aes.update(bPlaintext), aes.final()]).toString('utf8'); + } + + public async encryptFile( + key: string, + file: PubNubFile, + File: PubNubFileConstructor, + ) { + const bKey = this.getKey(key); + + /** + * Buffer type check also covers `string` which converted to the `Buffer` during file object creation. + */ + if (file.data instanceof Buffer) { + if (file.data.byteLength <= 0) throw new Error('Encryption error: empty content.'); + + return File.create({ + name: file.name, + mimeType: file.mimeType, + data: this.encryptBuffer(bKey, file.data), + }); + } + + if (file.data instanceof Readable) { + if (!file.contentLength || file.contentLength === 0) throw new Error('Encryption error: empty content.'); + + return File.create({ + name: file.name, + mimeType: file.mimeType, + stream: await this.encryptStream(bKey, file.data), + }); + } + + throw new Error('Cannot encrypt this file. In Node.js file encryption supports only string, Buffer or Stream.'); + } + // endregion + + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + // region Decryption + + public async decrypt(key: string, input: string | ArrayBuffer | Buffer | Readable) { + const bKey = this.getKey(key); + if (input instanceof ArrayBuffer) { + const decryptedBuffer = this.decryptBuffer(bKey, Buffer.from(input)); + + return decryptedBuffer.buffer.slice( + decryptedBuffer.byteOffset, + decryptedBuffer.byteOffset + decryptedBuffer.length, + ); + } + if (input instanceof Buffer) return this.decryptBuffer(bKey, input); + if (input instanceof Readable) return this.decryptStream(bKey, input); + if (typeof input === 'string') return this.decryptString(bKey, input); + + throw new Error('Decryption error: unsupported input format'); + } + + /** + * Decrypt provided encrypted {@link Buffer} using specific decryption {@link key}. + * + * @param key - Data decryption key.
**Note:** Should be the same as used to `encrypt` {@link Buffer}. + * @param buffer - Encrypted {@link Buffer} for decryption. + * + * @returns Decrypted data as {@link Buffer} object. + */ + private decryptBuffer(key: Buffer, buffer: Buffer) { + const bIv = buffer.slice(0, NodeCryptography.IV_LENGTH); + const bCiphertext = buffer.slice(NodeCryptography.IV_LENGTH); + + if (bCiphertext.byteLength <= 0) throw new Error('Decryption error: empty content'); + + const aes = createDecipheriv(this.algo, key, bIv); + + return Buffer.concat([aes.update(bCiphertext), aes.final()]); + } + + /** + * Decrypt provided encrypted {@link Readable} stream using specific decryption {@link key}. + * + * @param key - Data decryption key.
**Note:** Should be the same as used to `encrypt` {@link Readable} stream. + * @param stream - Encrypted {@link Readable} stream for decryption. + * + * @returns Decrypted data as {@link Readable} object. + */ + private decryptStream(key: Buffer, stream: Readable) { + let aes: ReturnType | null = null; + const output = new PassThrough(); + let bIv = Buffer.alloc(0); + + const getIv = () => { + let data = stream.read(); + + while (data !== null) { + if (data) { + const bChunk = Buffer.from(data); + const sliceLen = NodeCryptography.IV_LENGTH - bIv.byteLength; + + if (bChunk.byteLength < sliceLen) bIv = Buffer.concat([bIv, bChunk]); + else { + bIv = Buffer.concat([bIv, bChunk.slice(0, sliceLen)]); + aes = createDecipheriv(this.algo, key, bIv); + aes.pipe(output); + aes.write(bChunk.slice(sliceLen)); + } + } + + data = stream.read(); + } + }; + + stream.on('readable', getIv); + stream.on('end', () => { + if (aes) aes.end(); + output.end(); + }); + + return output; + } + + /** + * Decrypt provided encrypted {@link string} using specific decryption {@link key}. + * + * @param key - Data decryption key.
**Note:** Should be the same as used to `encrypt` {@link string}. + * @param text - Encrypted {@link string} for decryption. + * + * @returns Decrypted data as byte {@link string}. + */ + private decryptString(key: Buffer, text: string) { + const ciphertext = Buffer.from(text); + const bIv = ciphertext.slice(0, NodeCryptography.IV_LENGTH); + const bCiphertext = ciphertext.slice(NodeCryptography.IV_LENGTH); + const aes = createDecipheriv(this.algo, key, bIv); + + return Buffer.concat([aes.update(bCiphertext), aes.final()]).toString('utf8'); + } + + public async decryptFile( + key: string, + file: PubNubFile, + File: PubNubFileConstructor, + ) { + const bKey = this.getKey(key); + + /** + * Buffer type check also covers `string` which converted to the `Buffer` during file object creation. + */ + if (file.data instanceof Buffer) { + return File.create({ + name: file.name, + mimeType: file.mimeType, + data: this.decryptBuffer(bKey, file.data), + }); + } + + if (file.data instanceof Readable) { + return File.create({ + name: file.name, + mimeType: file.mimeType, + stream: this.decryptStream(bKey, file.data), + }); + } + + throw new Error('Cannot decrypt this file. In Node.js file decryption supports only string, Buffer or Stream.'); + } + // endregion + + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + + // region Helpers + /** + * Cryptography algorithm. + * + * @returns Cryptography module algorithm. + */ + private get algo() { + return 'aes-256-cbc'; + } + + /** + * Convert cipher key to the {@link Buffer}. + * + * @param key - String cipher key. + * + * @returns SHA256 HEX encoded cipher key {@link Buffer}. + */ + private getKey(key: string) { + const sha = createHash('sha256'); + sha.update(Buffer.from(key, 'utf8')); + + return Buffer.from(sha.digest('hex').slice(0, 32), 'utf8'); + } + + /** + * Generate random initialization vector. + * + * @returns Random initialization vector. + */ + private getIv() { + return randomBytes(NodeCryptography.IV_LENGTH); + } + // endregion +} diff --git a/src/crypto/modules/web.js b/src/crypto/modules/web.js deleted file mode 100644 index 20e1a274b..000000000 --- a/src/crypto/modules/web.js +++ /dev/null @@ -1,117 +0,0 @@ -/* global crypto */ - -function concatArrayBuffer(ab1, ab2) { - const tmp = new Uint8Array(ab1.byteLength + ab2.byteLength); - - tmp.set(new Uint8Array(ab1), 0); - tmp.set(new Uint8Array(ab2), ab1.byteLength); - - return tmp.buffer; -} - -export default class WebCryptography { - static IV_LENGTH = 16; - static encoder = new TextEncoder(); - static decoder = new TextDecoder(); - - get algo() { - return 'aes-256-cbc'; - } - - async encrypt(key, input) { - const cKey = await this.getKey(key); - - if (input instanceof ArrayBuffer) { - return this.encryptArrayBuffer(cKey, input); - } - if (typeof input === 'string') { - return this.encryptString(cKey, input); - } - throw new Error('Cannot encrypt this file. In browsers file encryption supports only string or ArrayBuffer'); - } - - async decrypt(key, input) { - const cKey = await this.getKey(key); - if (input instanceof ArrayBuffer) { - return this.decryptArrayBuffer(cKey, input); - } - if (typeof input === 'string') { - return this.decryptString(cKey, input); - } - throw new Error('Cannot decrypt this file. In browsers file decryption supports only string or ArrayBuffer'); - } - - async encryptFile(key, file, File) { - if (file.data.byteLength <= 0) throw new Error('encryption error. empty content'); - const bKey = await this.getKey(key); - - const abPlaindata = await file.data.arrayBuffer(); - - const abCipherdata = await this.encryptArrayBuffer(bKey, abPlaindata); - - return File.create({ - name: file.name, - mimeType: 'application/octet-stream', - data: abCipherdata, - }); - } - - async decryptFile(key, file, File) { - const bKey = await this.getKey(key); - - const abCipherdata = await file.data.arrayBuffer(); - const abPlaindata = await this.decryptArrayBuffer(bKey, abCipherdata); - - return File.create({ - name: file.name, - data: abPlaindata, - }); - } - - async getKey(key) { - const digest = await crypto.subtle.digest('SHA-256', WebCryptography.encoder.encode(key)); - const hashHex = Array.from(new Uint8Array(digest)) - .map((b) => b.toString(16).padStart(2, '0')) - .join(''); - const abKey = WebCryptography.encoder.encode(hashHex.slice(0, 32)).buffer; - return crypto.subtle.importKey('raw', abKey, 'AES-CBC', true, ['encrypt', 'decrypt']); - } - - async encryptArrayBuffer(key, plaintext) { - const abIv = crypto.getRandomValues(new Uint8Array(16)); - - return concatArrayBuffer(abIv.buffer, await crypto.subtle.encrypt({ name: 'AES-CBC', iv: abIv }, key, plaintext)); - } - - async decryptArrayBuffer(key, ciphertext) { - const abIv = ciphertext.slice(0, 16); - if (ciphertext.slice(WebCryptography.IV_LENGTH).byteLength <= 0) throw new Error('decryption error: empty content'); - const data = await crypto.subtle.decrypt( - { name: 'AES-CBC', iv: abIv }, - key, - ciphertext.slice(WebCryptography.IV_LENGTH), - ); - return data; - } - - async encryptString(key, plaintext) { - const abIv = crypto.getRandomValues(new Uint8Array(16)); - - const abPlaintext = WebCryptography.encoder.encode(plaintext).buffer; - const abPayload = await crypto.subtle.encrypt({ name: 'AES-CBC', iv: abIv }, key, abPlaintext); - - const ciphertext = concatArrayBuffer(abIv.buffer, abPayload); - - return WebCryptography.decoder.decode(ciphertext); - } - - async decryptString(key, ciphertext) { - const abCiphertext = WebCryptography.encoder.encode(ciphertext).buffer; - const abIv = abCiphertext.slice(0, 16); - const abPayload = abCiphertext.slice(16); - - const abPlaintext = await crypto.subtle.decrypt({ name: 'AES-CBC', iv: abIv }, key, abPayload); - - return WebCryptography.decoder.decode(abPlaintext); - } -} diff --git a/src/crypto/modules/web.ts b/src/crypto/modules/web.ts new file mode 100644 index 000000000..e971fab6f --- /dev/null +++ b/src/crypto/modules/web.ts @@ -0,0 +1,233 @@ +/* global crypto */ +/** + * Legacy browser cryptography module. + */ + +import { PubNubFile, PubNubFileParameters } from '../../file/modules/web'; +import { Cryptography } from '../../core/interfaces/cryptography'; +import { PubNubFileConstructor } from '../../core/types/file'; + +function concatArrayBuffer(ab1: ArrayBuffer, ab2: ArrayBuffer) { + const tmp = new Uint8Array(ab1.byteLength + ab2.byteLength); + + tmp.set(new Uint8Array(ab1), 0); + tmp.set(new Uint8Array(ab2), ab1.byteLength); + + return tmp.buffer; +} + +/** + * Legacy cryptography implementation for browser-based {@link PubNub} client. + */ +export default class WebCryptography implements Cryptography { + /** + * Random initialization vector size. + */ + static IV_LENGTH = 16; + + /** + * {@link string|String} to {@link ArrayBuffer} response decoder. + */ + static encoder = new TextEncoder(); + + /** + * {@link ArrayBuffer} to {@link string} decoder. + */ + static decoder = new TextDecoder(); + + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + + // region Encryption + /** + * Encrypt provided source data using specific encryption {@link key}. + * + * @param key - Data encryption key.
**Note:** Same key should be used to `decrypt` data. + * @param input - Source data for encryption. + * + * @returns Encrypted data as object or stream (depending on from source data type). + * + * @throws Error if unknown data type has been passed. + */ + public async encrypt(key: string, input: ArrayBuffer | string) { + if (!(input instanceof ArrayBuffer) && typeof input !== 'string') + throw new Error('Cannot encrypt this file. In browsers file encryption supports only string or ArrayBuffer'); + + const cKey = await this.getKey(key); + + return input instanceof ArrayBuffer ? this.encryptArrayBuffer(cKey, input) : this.encryptString(cKey, input); + } + + /** + * Encrypt provided source {@link Buffer} using specific encryption {@link ArrayBuffer}. + * + * @param key - Data encryption key.
**Note:** Same key should be used to `decrypt` {@link ArrayBuffer}. + * @param buffer - Source {@link ArrayBuffer} for encryption. + * + * @returns Encrypted data as {@link ArrayBuffer} object. + */ + private async encryptArrayBuffer(key: CryptoKey, buffer: ArrayBuffer) { + const abIv = crypto.getRandomValues(new Uint8Array(16)); + + return concatArrayBuffer(abIv.buffer, await crypto.subtle.encrypt({ name: 'AES-CBC', iv: abIv }, key, buffer)); + } + + /** + * Encrypt provided source {@link string} using specific encryption {@link key}. + * + * @param key - Data encryption key.
**Note:** Same key should be used to `decrypt` {@link string}. + * @param text - Source {@link string} for encryption. + * + * @returns Encrypted data as byte {@link string}. + */ + private async encryptString(key: CryptoKey, text: string) { + const abIv = crypto.getRandomValues(new Uint8Array(16)); + + const abPlaintext = WebCryptography.encoder.encode(text).buffer; + const abPayload = await crypto.subtle.encrypt({ name: 'AES-CBC', iv: abIv }, key, abPlaintext); + + const ciphertext = concatArrayBuffer(abIv.buffer, abPayload); + + return WebCryptography.decoder.decode(ciphertext); + } + + /** + * Encrypt provided {@link PubNub} File object using specific encryption {@link key}. + * + * @param key - Key for {@link PubNub} File object encryption.
**Note:** Same key should be + * used to `decrypt` data. + * @param file - Source {@link PubNub} File object for encryption. + * @param File - Class constructor for {@link PubNub} File object. + * + * @returns Encrypted data as {@link PubNub} File object. + * + * @throws Error if file is empty or contains unsupported data type. + */ + public async encryptFile( + key: string, + file: PubNubFile, + File: PubNubFileConstructor, + ) { + if ((file.contentLength ?? 0) <= 0) throw new Error('encryption error. empty content'); + const bKey = await this.getKey(key); + const abPlaindata = await file.toArrayBuffer(); + const abCipherdata = await this.encryptArrayBuffer(bKey, abPlaindata); + + return File.create({ + name: file.name, + mimeType: file.mimeType ?? 'application/octet-stream', + data: abCipherdata, + }); + } + // endregion + + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + + // region Decryption + /** + * Decrypt provided encrypted data using specific decryption {@link key}. + * + * @param key - Data decryption key.
**Note:** Should be the same as used to `encrypt` data. + * @param input - Encrypted data for decryption. + * + * @returns Decrypted data as object or stream (depending on from encrypted data type). + * + * @throws Error if unknown data type has been passed. + */ + public async decrypt(key: string, input: ArrayBuffer | string) { + if (!(input instanceof ArrayBuffer) && typeof input !== 'string') + throw new Error('Cannot decrypt this file. In browsers file decryption supports only string or ArrayBuffer'); + + const cKey = await this.getKey(key); + + return input instanceof ArrayBuffer ? this.decryptArrayBuffer(cKey, input) : this.decryptString(cKey, input); + } + + /** + * Decrypt provided encrypted {@link ArrayBuffer} using specific decryption {@link key}. + * + * @param key - Data decryption key.
**Note:** Should be the same as used to `encrypt` {@link ArrayBuffer}. + * @param buffer - Encrypted {@link ArrayBuffer} for decryption. + * + * @returns Decrypted data as {@link ArrayBuffer} object. + */ + private async decryptArrayBuffer(key: CryptoKey, buffer: ArrayBuffer) { + const abIv = buffer.slice(0, 16); + if (buffer.slice(WebCryptography.IV_LENGTH).byteLength <= 0) throw new Error('decryption error: empty content'); + + return await crypto.subtle.decrypt({ name: 'AES-CBC', iv: abIv }, key, buffer.slice(WebCryptography.IV_LENGTH)); + } + + /** + * Decrypt provided encrypted {@link string} using specific decryption {@link key}. + * + * @param key - Data decryption key.
**Note:** Should be the same as used to `encrypt` {@link string}. + * @param text - Encrypted {@link string} for decryption. + * + * @returns Decrypted data as byte {@link string}. + */ + private async decryptString(key: CryptoKey, text: string) { + const abCiphertext = WebCryptography.encoder.encode(text).buffer; + const abIv = abCiphertext.slice(0, 16); + const abPayload = abCiphertext.slice(16); + const abPlaintext = await crypto.subtle.decrypt({ name: 'AES-CBC', iv: abIv }, key, abPayload); + + return WebCryptography.decoder.decode(abPlaintext); + } + + /** + * Decrypt provided {@link PubNub} File object using specific decryption {@link key}. + * + * @param key - Key for {@link PubNub} File object decryption.
**Note:** Should be the same + * as used to `encrypt` data. + * @param file - Encrypted {@link PubNub} File object for decryption. + * @param File - Class constructor for {@link PubNub} File object. + * + * @returns Decrypted data as {@link PubNub} File object. + * + * @throws Error if file is empty or contains unsupported data type. + */ + public async decryptFile( + key: string, + file: PubNubFile, + File: PubNubFileConstructor, + ) { + const bKey = await this.getKey(key); + + const abCipherdata = await file.toArrayBuffer(); + const abPlaindata = await this.decryptArrayBuffer(bKey, abCipherdata); + + return File.create({ + name: file.name, + mimeType: file.mimeType, + data: abPlaindata, + }); + } + // endregion + + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + + // region Helpers + /** + * Convert cipher key to the {@link Buffer}. + * + * @param key - String cipher key. + * + * @returns SHA256 HEX encoded cipher key {@link CryptoKey}. + */ + private async getKey(key: string) { + const digest = await crypto.subtle.digest('SHA-256', WebCryptography.encoder.encode(key)); + const hashHex = Array.from(new Uint8Array(digest)) + .map((b) => b.toString(16).padStart(2, '0')) + .join(''); + const abKey = WebCryptography.encoder.encode(hashHex.slice(0, 32)).buffer; + + return crypto.subtle.importKey('raw', abKey, 'AES-CBC', true, ['encrypt', 'decrypt']); + } + // endregion +} diff --git a/src/entities/Channel.ts b/src/entities/Channel.ts index e3ad72904..5e09713a0 100644 --- a/src/entities/Channel.ts +++ b/src/entities/Channel.ts @@ -1,17 +1,19 @@ +import type { PubNubCore as PubNub } from '../core/pubnub-common'; +import EventEmitter from '../core/components/eventEmitter'; +import { SubscriptionOptions } from './commonTypes'; import { Subscription } from './Subscription'; -import { SubscriptionOptions, EventEmitter } from './commonTypes'; -import type PubNub from '../core/pubnub-common'; export class Channel { - private name: string; - private eventEmitter: EventEmitter; - private pubnub: PubNub; + private readonly name: string; - constructor(channelName: string, eventEmitter: EventEmitter, pubnub: PubNub) { + constructor( + channelName: string, + private readonly eventEmitter: EventEmitter, + private readonly pubnub: PubNub, + ) { this.name = channelName; - this.eventEmitter = eventEmitter; - this.pubnub = pubnub; } + subscription(subscriptionOptions?: SubscriptionOptions) { return new Subscription({ channels: subscriptionOptions?.receivePresenceEvents ? [this.name, `${this.name}-pnpres`] : [this.name], diff --git a/src/entities/ChannelGroup.ts b/src/entities/ChannelGroup.ts index f668e79c9..ff6671ba8 100644 --- a/src/entities/ChannelGroup.ts +++ b/src/entities/ChannelGroup.ts @@ -1,17 +1,19 @@ +import type { PubNubCore as PubNub } from '../core/pubnub-common'; +import EventEmitter from '../core/components/eventEmitter'; +import { SubscriptionOptions } from './commonTypes'; import { Subscription } from './Subscription'; -import { SubscriptionOptions, EventEmitter } from './commonTypes'; -import type PubNub from '../core/pubnub-common'; export class ChannelGroup { - private name: string; - private eventEmitter: EventEmitter; - private pubnub: PubNub; + private readonly name: string; - constructor(channelGroup: string, eventEmitter: EventEmitter, pubnub: PubNub) { + constructor( + channelGroup: string, + private readonly eventEmitter: EventEmitter, + private readonly pubnub: PubNub, + ) { this.name = channelGroup; - this.eventEmitter = eventEmitter; - this.pubnub = pubnub; } + subscription(subscriptionOptions?: SubscriptionOptions) { return new Subscription({ channels: [], diff --git a/src/entities/ChannelMetadata.ts b/src/entities/ChannelMetadata.ts index 78020d988..a06bfffa1 100644 --- a/src/entities/ChannelMetadata.ts +++ b/src/entities/ChannelMetadata.ts @@ -1,17 +1,15 @@ +import type { PubNubCore as PubNub } from '../core/pubnub-common'; +import EventEmitter from '../core/components/eventEmitter'; +import { SubscriptionOptions } from './commonTypes'; import { Subscription } from './Subscription'; -import { SubscriptionOptions, EventEmitter } from './commonTypes'; -import type PubNub from '../core/pubnub-common'; export class ChannelMetadata { - private id: string; - private eventEmitter: EventEmitter; - private pubnub: PubNub; + constructor( + private readonly id: string, + private readonly eventEmitter: EventEmitter, + private readonly pubnub: PubNub, + ) {} - constructor(id: string, eventEmitter: EventEmitter, pubnub: PubNub) { - this.id = id; - this.eventEmitter = eventEmitter; - this.pubnub = pubnub; - } subscription(subscriptionOptions?: SubscriptionOptions) { return new Subscription({ channels: [this.id], diff --git a/src/entities/SubscribeCapable.ts b/src/entities/SubscribeCapable.ts index 93d2e7ebf..b6cdcc84d 100644 --- a/src/entities/SubscribeCapable.ts +++ b/src/entities/SubscribeCapable.ts @@ -1,13 +1,15 @@ -import { EventEmitter, Listener, SubscriptionOptions } from './commonTypes'; -import PubNubType from 'pubnub'; -import type PubNub from '../core/pubnub-common'; +import type { PubNubCore as PubNub } from '../core/pubnub-common'; +import { Listener } from '../core/components/listener_manager'; +import * as Subscription from '../core/types/api/subscription'; +import EventEmitter from '../core/components/eventEmitter'; +import { SubscriptionOptions } from './commonTypes'; export abstract class SubscribeCapable { protected abstract channelNames: string[]; protected abstract groupNames: string[]; protected abstract listener: Listener; protected abstract eventEmitter: EventEmitter; - protected abstract pubnub: PubNub; + protected abstract pubnub: PubNub; protected abstract options?: SubscriptionOptions; subscribe() { @@ -24,27 +26,27 @@ export abstract class SubscribeCapable { }); } - set onMessage(onMessagelistener: (messageEvent: PubNubType.MessageEvent) => void) { - this.listener.message = onMessagelistener; + set onMessage(onMessageListener: (messageEvent: Subscription.Message) => void) { + this.listener.message = onMessageListener; } - set onPresence(onPresencelistener: (presenceEvent: PubNubType.PresenceEvent) => void) { - this.listener.presence = onPresencelistener; + set onPresence(onPresenceListener: (presenceEvent: Subscription.Presence) => void) { + this.listener.presence = onPresenceListener; } - set onSignal(onSignalListener: (signalEvent: PubNubType.SignalEvent) => void) { + set onSignal(onSignalListener: (signalEvent: Subscription.Signal) => void) { this.listener.signal = onSignalListener; } - set onObjects(onObjectsListener: (objectsEvent: PubNubType.ObjectsEvent) => void) { + set onObjects(onObjectsListener: (objectsEvent: Subscription.AppContextObject) => void) { this.listener.objects = onObjectsListener; } - set onMessageAction(messageActionEventListener: (messageActionEvent: PubNubType.MessageActionEvent) => void) { + set onMessageAction(messageActionEventListener: (messageActionEvent: Subscription.MessageAction) => void) { this.listener.messageAction = messageActionEventListener; } - set onFile(fileEventListener: (fileEvent: PubNubType.FileEvent) => void) { + set onFile(fileEventListener: (fileEvent: Subscription.File) => void) { this.listener.file = fileEventListener; } diff --git a/src/entities/Subscription.ts b/src/entities/Subscription.ts index 6e2a17aa3..2002313e5 100644 --- a/src/entities/Subscription.ts +++ b/src/entities/Subscription.ts @@ -1,13 +1,15 @@ -import { SubscriptionSet } from './SubscriptionSet'; -import { SubscriptionOptions, EventEmitter, Listener } from './commonTypes'; -import type PubNub from '../core/pubnub-common'; +import type { PubNubCore as PubNub } from '../core/pubnub-common'; +import { Listener } from '../core/components/listener_manager'; +import EventEmitter from '../core/components/eventEmitter'; import { SubscribeCapable } from './SubscribeCapable'; +import { SubscriptionOptions } from './commonTypes'; +import { SubscriptionSet } from './SubscriptionSet'; export class Subscription extends SubscribeCapable { protected channelNames: string[] = []; protected groupNames: string[] = []; protected options?: SubscriptionOptions; - protected pubnub: PubNub; + protected pubnub: PubNub; protected eventEmitter: EventEmitter; protected listener: Listener; @@ -22,7 +24,7 @@ export class Subscription extends SubscribeCapable { channelGroups: string[]; subscriptionOptions?: SubscriptionOptions; eventEmitter: EventEmitter; - pubnub: PubNub; + pubnub: PubNub; }) { super(); this.channelNames = channels; diff --git a/src/entities/SubscriptionSet.ts b/src/entities/SubscriptionSet.ts index d824e682b..970ff7754 100644 --- a/src/entities/SubscriptionSet.ts +++ b/src/entities/SubscriptionSet.ts @@ -1,13 +1,15 @@ -import { Subscription } from './Subscription'; -import { SubscriptionOptions, EventEmitter, Listener } from './commonTypes'; -import type PubNub from '../core/pubnub-common'; +import type { PubNubCore as PubNub } from '../core/pubnub-common'; +import { Listener } from '../core/components/listener_manager'; +import EventEmitter from '../core/components/eventEmitter'; import { SubscribeCapable } from './SubscribeCapable'; +import { SubscriptionOptions } from './commonTypes'; +import { Subscription } from './Subscription'; export class SubscriptionSet extends SubscribeCapable { protected channelNames: string[] = []; protected groupNames: string[] = []; - protected options: SubscriptionOptions; - protected pubnub: PubNub; + protected options?: SubscriptionOptions; + protected pubnub: PubNub; protected eventEmitter: EventEmitter; protected subscriptionList: Subscription[] = []; protected listener: Listener; @@ -19,11 +21,11 @@ export class SubscriptionSet extends SubscribeCapable { eventEmitter, pubnub, }: { - channels: string[]; - channelGroups: string[]; - subscriptionOptions: SubscriptionOptions; + channels?: string[]; + channelGroups?: string[]; + subscriptionOptions?: SubscriptionOptions; eventEmitter: EventEmitter; - pubnub: PubNub; + pubnub: PubNub; }) { super(); this.options = subscriptionOptions; diff --git a/src/entities/UserMetadata.ts b/src/entities/UserMetadata.ts index 3364374f0..abc11abac 100644 --- a/src/entities/UserMetadata.ts +++ b/src/entities/UserMetadata.ts @@ -1,17 +1,15 @@ +import type { PubNubCore as PubNub } from '../core/pubnub-common'; +import EventEmitter from '../core/components/eventEmitter'; +import { SubscriptionOptions } from './commonTypes'; import { Subscription } from './Subscription'; -import { SubscriptionOptions, EventEmitter } from './commonTypes'; -import type PubNub from '../core/pubnub-common'; export class UserMetadata { - private id: string; - private eventEmitter: EventEmitter; - private pubnub: PubNub; + constructor( + private readonly id: string, + private readonly eventEmitter: EventEmitter, + private readonly pubnub: PubNub, + ) {} - constructor(id: string, eventEmitter: EventEmitter, pubnub: PubNub) { - this.id = id; - this.eventEmitter = eventEmitter; - this.pubnub = pubnub; - } subscription(subscriptionOptions?: SubscriptionOptions) { return new Subscription({ channels: [this.id], diff --git a/src/entities/commonTypes.ts b/src/entities/commonTypes.ts index 496d5047d..cd30c0c61 100644 --- a/src/entities/commonTypes.ts +++ b/src/entities/commonTypes.ts @@ -1,31 +1,4 @@ -import PubNub from 'pubnub'; - export type SubscriptionOptions = { cursor?: { timetoken?: string; region?: number }; receivePresenceEvents?: boolean; }; - -export type EventEmitter = { - emitEvent(e: Event): void; - addListener(l: Listener, channels?: string[], groups?: string[]): void; - removeListener(listener: Listener, channels?: string[], groups?: string[]): void; - removeAllListeners(): void; -}; - -export type Listener = { - message?(m: PubNub.MessageEvent): void; - presence?(p: PubNub.PresenceEvent): void; - signal?(s: PubNub.SignalEvent): void; - objects?(o: PubNub.ObjectsEvent): void; - messageAction?(ma: PubNub.MessageActionEvent): void; - file?(f: PubNub.FileEvent): void; - status?(s: PubNub.StatusEvent): void; -}; - -type Event = - | PubNub.MessageEvent - | PubNub.PresenceEvent - | PubNub.SignalEvent - | PubNub.ObjectsEvent - | PubNub.MessageActionEvent - | PubNub.FileEvent; diff --git a/src/errors/pubnub-api-error.ts b/src/errors/pubnub-api-error.ts new file mode 100644 index 000000000..793deb1bb --- /dev/null +++ b/src/errors/pubnub-api-error.ts @@ -0,0 +1,194 @@ +/** + * REST API endpoint use error module. + */ + +import { TransportResponse } from '../core/types/transport-response'; +import RequestOperation from '../core/constants/operations'; +import StatusCategory from '../core/constants/categories'; +import { Payload, Status } from '../core/types/api'; +import { PubNubError } from './pubnub-error'; + +/** + * PubNub REST API call error. + */ +export class PubNubAPIError extends Error { + /** + * Construct API from known error object or {@link PubNub} service error response. + * + * @param errorOrResponse - `Error` or service error response object from which error information + * should be extracted. + * @param data - Preprocessed service error response. + * + * @returns `PubNubAPIError` object with known error category and additional information (if + * available). + */ + static create(errorOrResponse: Error | TransportResponse, data?: ArrayBuffer): PubNubAPIError { + if (errorOrResponse instanceof Error) return PubNubAPIError.createFromError(errorOrResponse); + else return PubNubAPIError.createFromServiceResponse(errorOrResponse, data); + } + + /** + * Create API error instance from other error object. + * + * @param error - `Error` object provided by network provider (mostly) or other {@link PubNub} client components. + * + * @returns `PubNubAPIError` object with known error category and additional information (if + * available). + */ + private static createFromError(error: unknown): PubNubAPIError { + let category: StatusCategory = StatusCategory.PNUnknownCategory; + let message = 'Unknown error'; + let errorName = 'Error'; + + if (!error) return new PubNubAPIError(message, category, 0); + else if (error instanceof PubNubAPIError) return error; + + if (error instanceof Error) { + message = error.message; + errorName = error.name; + } + + if (errorName === 'AbortError' || message.indexOf('Aborted') !== -1) { + category = StatusCategory.PNCancelledCategory; + message = 'Request cancelled'; + } else if (message.indexOf('timeout') !== -1) { + category = StatusCategory.PNTimeoutCategory; + message = 'Request timeout'; + } else if (message.indexOf('network') !== -1) { + category = StatusCategory.PNNetworkIssuesCategory; + message = 'Network issues'; + } else if (errorName === 'TypeError') { + category = StatusCategory.PNBadRequestCategory; + } else if (errorName === 'FetchError') { + const errorCode = (error as Record).code; + + if (['ECONNREFUSED', 'ENETUNREACH', 'ENOTFOUND', 'ECONNRESET', 'EAI_AGAIN'].includes(errorCode)) + category = StatusCategory.PNNetworkIssuesCategory; + if (errorCode === 'ECONNREFUSED') message = 'Connection refused'; + else if (errorCode === 'ENETUNREACH') message = 'Network not reachable'; + else if (errorCode === 'ENOTFOUND') message = 'Server not found'; + else if (errorCode === 'ECONNRESET') message = 'Connection reset by peer'; + else if (errorCode === 'EAI_AGAIN') message = 'Name resolution error'; + else if (errorCode === 'ETIMEDOUT') { + category = StatusCategory.PNTimeoutCategory; + message = 'Request timeout'; + } else message = `Unknown system error: ${error}`; + } else if (message === 'Request timeout') category = StatusCategory.PNTimeoutCategory; + + return new PubNubAPIError(message, category, 0, error as Error); + } + + /** + * Construct API from known {@link PubNub} service error response. + * + * @param response - Service error response object from which error information should be + * extracted. + * @param data - Preprocessed service error response. + * + * @returns `PubNubAPIError` object with known error category and additional information (if + * available). + */ + private static createFromServiceResponse(response: TransportResponse, data?: ArrayBuffer): PubNubAPIError { + let category: StatusCategory = StatusCategory.PNUnknownCategory; + let errorData: Error | Payload | undefined; + let message = 'Unknown error'; + let { status } = response; + data ??= response.body; + + if (status === 402) message = 'Not available for used key set. Contact support@pubnub.com'; + else if (status === 400) { + category = StatusCategory.PNBadRequestCategory; + message = 'Bad request'; + } else if (status === 403) { + category = StatusCategory.PNAccessDeniedCategory; + message = 'Access denied'; + } + + // Try to get more information about error from service response. + if (data && data.byteLength > 0) { + const decoded = new TextDecoder().decode(data); + + if ( + response.headers['content-type']!.indexOf('text/javascript') !== -1 || + response.headers['content-type']!.indexOf('application/json') !== -1 + ) { + try { + const errorResponse: Payload = JSON.parse(decoded); + + if (typeof errorResponse === 'object' && !Array.isArray(errorResponse)) { + if ( + 'error' in errorResponse && + (errorResponse.error === 1 || errorResponse.error === true) && + 'status' in errorResponse && + typeof errorResponse.status === 'number' && + 'message' in errorResponse && + 'service' in errorResponse + ) { + errorData = errorResponse; + status = errorResponse.status; + } else errorData = errorResponse; + + if ('error' in errorResponse && errorResponse.error instanceof Error) errorData = errorResponse.error; + } + } catch (_) { + errorData = decoded; + } + } else if (response.headers['content-type']!.indexOf('xml') !== -1) { + const reason = /(.*)<\/Message>/gi.exec(decoded); + message = reason ? `Upload to bucket failed: ${reason[1]}` : 'Upload to bucket failed.'; + } else { + errorData = decoded; + } + } + + return new PubNubAPIError(message, category, status, errorData); + } + + /** + * Construct PubNub endpoint error. + * + * @param message - Short API call error description. + * @param category - Error category. + * @param statusCode - Response HTTP status code. + * @param errorData - Error information. + */ + constructor( + message: string, + public readonly category: StatusCategory, + public readonly statusCode: number, + public readonly errorData?: Error | Payload, + ) { + super(message); + + this.name = 'PubNubAPIError'; + } + + /** + * Convert API error object to API callback status object. + * + * @param operation - Request operation during which error happened. + * + * @returns Pre-formatted API callback status object. + */ + public toStatus(operation: RequestOperation): Status { + return { + error: true, + category: this.category, + operation, + statusCode: this.statusCode, + errorData: this.errorData, + }; + } + + /** + * Convert API error object to PubNub client error object. + * + * @param operation - Request operation during which error happened. + * @param message - Custom error message. + * + * @returns Client-facing pre-formatted endpoint call error. + */ + public toPubNubError(operation: RequestOperation, message?: string): PubNubError { + return new PubNubError(message ?? this.message, this.toStatus(operation)); + } +} diff --git a/src/errors/pubnub-error.ts b/src/errors/pubnub-error.ts new file mode 100644 index 000000000..435352aa8 --- /dev/null +++ b/src/errors/pubnub-error.ts @@ -0,0 +1,30 @@ +import { Status } from '../core/types/api'; +import StatusCategory from '../core/constants/categories'; + +export class PubNubError extends Error { + constructor( + message: string, + public status?: Status, + ) { + super(message); + this.name = 'PubNubError'; + this.message = message; + + Object.setPrototypeOf(this, new.target.prototype); + } +} + +function createError(errorPayload: { message: string; statusCode?: number }): Status { + errorPayload.statusCode ??= 0; + + return { + ...errorPayload, + statusCode: errorPayload.statusCode!, + category: StatusCategory.PNValidationErrorCategory, + error: true, + }; +} + +export function createValidationError(message: string, statusCode?: number) { + return createError({ message, ...(statusCode !== undefined ? { statusCode } : {}) }); +} diff --git a/src/event-engine/core/handler.ts b/src/event-engine/core/handler.ts index 041eba17b..338a922f9 100644 --- a/src/event-engine/core/handler.ts +++ b/src/event-engine/core/handler.ts @@ -1,7 +1,10 @@ import { AbortSignal } from '../../core/components/abort_signal'; export abstract class Handler { - constructor(protected payload: Payload, protected readonly dependencies: Dependencies) {} + constructor( + protected payload: Payload, + protected readonly dependencies: Dependencies, + ) {} abstract start(): void; abstract cancel(): void; diff --git a/src/event-engine/core/retryPolicy.ts b/src/event-engine/core/retryPolicy.ts index a1692ca75..ebc515ad9 100644 --- a/src/event-engine/core/retryPolicy.ts +++ b/src/event-engine/core/retryPolicy.ts @@ -1,18 +1,24 @@ +import { PubNubError } from '../../errors/pubnub-error'; + export class RetryPolicy { - static LinearRetryPolicy(configuration: LinearRetryPolicyConfiguration) { + static LinearRetryPolicy( + configuration: LinearRetryPolicyConfiguration, + ): RequestRetryPolicy & LinearRetryPolicyConfiguration { return { delay: configuration.delay, maximumRetry: configuration.maximumRetry, + /* eslint-disable @typescript-eslint/no-explicit-any */ shouldRetry(error: any, attempt: number) { if (error?.status?.statusCode === 403) { return false; } return this.maximumRetry > attempt; }, - getDelay(_: number, reason: any) { + getDelay(_, reason) { const delay = reason.retryAfter ?? this.delay; return (delay + Math.random()) * 1000; }, + /* eslint-disable @typescript-eslint/no-explicit-any */ getGiveupReason(error: any, attempt: number) { if (this.maximumRetry <= attempt) { return 'retry attempts exhaused.'; @@ -22,40 +28,94 @@ export class RetryPolicy { } return 'unknown error'; }, + validate() { + if (this.maximumRetry > 10) throw new Error('Maximum retry for linear retry policy can not be more than 10'); + }, }; } - static ExponentialRetryPolicy(configuration: ExponentialRetryPolicyConfiguration) { + static ExponentialRetryPolicy( + configuration: ExponentialRetryPolicyConfiguration, + ): RequestRetryPolicy & ExponentialRetryPolicyConfiguration { return { minimumDelay: configuration.minimumDelay, maximumDelay: configuration.maximumDelay, maximumRetry: configuration.maximumRetry, - shouldRetry(error: any, attempt: number) { - if (error?.status?.statusCode === 403) { + shouldRetry(reason, attempt) { + if (reason?.status?.statusCode === 403) { return false; } return this.maximumRetry > attempt; }, - getDelay(attempt: number, reason: any) { + getDelay(attempt, reason) { const delay = reason.retryAfter ?? Math.min(Math.pow(2, attempt), this.maximumDelay); return (delay + Math.random()) * 1000; }, - getGiveupReason(error: any, attempt: number) { + getGiveupReason(reason, attempt) { if (this.maximumRetry <= attempt) { - return 'retry attempts exhaused.'; + return 'retry attempts exhausted.'; } - if (error?.status?.statusCode === 403) { + if (reason?.status?.statusCode === 403) { return 'forbidden operation.'; } return 'unknown error'; }, + + validate() { + if (this.minimumDelay < 2) throw new Error('Minimum delay can not be set less than 2 seconds for retry'); + else if (this.maximumDelay) throw new Error('Maximum delay can not be set more than 150 seconds for retry'); + else if (this.maximumRetry > 6) + throw new Error('Maximum retry for exponential retry policy can not be more than 6'); + }, }; } } +export type RequestRetryPolicy = { + /** + * Check whether failed request can be retried. + * + * @param reason - Request processing failure reason. + * @param attempt - Number of consequent failure. + * + * @returns `true` if another request retry attempt can be done. + */ + shouldRetry(reason: PubNubError & { retryAfter?: number }, attempt: number): boolean; + + /** + * Computed delay for next request retry attempt. + * + * @param attempt - Number of consequent failure. + * @param reason - Request processing failure reason. + * + * @returns Delay before next request retry attempt in milliseconds. + */ + getDelay(attempt: number, reason: PubNubError & { retryAfter?: number }): number; + + /** + * Identify reason why another retry attempt can't be made. + * + * @param reason - Request processing failure reason. + * @param attempt - Number of consequent failure. + * + * @returns Give up reason. + */ + getGiveupReason(reason: PubNubError & { retryAfter?: number }, attempt: number): string; + + /** + * Validate retry policy parameters. + * + * @throws Error if `minimum` delay is smaller than 2 seconds for `exponential` retry policy. + * @throws Error if `maximum` delay is larger than 150 seconds for `exponential` retry policy. + * @throws Error if `maximumRetry` attempts is larger than 6 for `exponential` retry policy. + * @throws Error if `maximumRetry` attempts is larger than 10 for `linear` retry policy. + */ + validate(): void; +}; + export type LinearRetryPolicyConfiguration = { delay: number; maximumRetry: number; diff --git a/src/event-engine/core/types.ts b/src/event-engine/core/types.ts index e5c6f7f2b..a10f31336 100644 --- a/src/event-engine/core/types.ts +++ b/src/event-engine/core/types.ts @@ -1,7 +1,5 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { State } from './state'; - export type Event = { type: T; payload: P }; export type Invocation = { type: T; payload: P; managed: boolean }; diff --git a/src/event-engine/dispatcher.ts b/src/event-engine/dispatcher.ts index 3054d5ee2..5d9c7c064 100644 --- a/src/event-engine/dispatcher.ts +++ b/src/event-engine/dispatcher.ts @@ -1,21 +1,27 @@ -import { PubNubError } from '../core/components/endpoint'; +import { PrivateClientConfiguration } from '../core/interfaces/configuration'; +import * as Subscription from '../core/types/api/subscription'; +import { PubNubError } from '../errors/pubnub-error'; import { asyncHandler, Dispatcher, Engine } from './core'; import * as effects from './effects'; import * as events from './events'; +import { Payload, StatusEvent } from '../core/types/api'; +import StatusCategory from '../core/constants/categories'; export type Dependencies = { - handshake: any; - receiveMessages: any; - join: any; - leave: any; - leaveAll: any; - presenceState: any; - config: any; + handshake: (parameters: Subscription.CancelableSubscribeParameters) => Promise; + receiveMessages: ( + parameters: Subscription.CancelableSubscribeParameters, + ) => Promise; + join?: (parameters: { channels?: string[]; groups?: string[] }) => void; + leave?: (parameters: { channels?: string[]; groups?: string[] }) => void; + leaveAll?: () => void; + presenceState: Record; + config: PrivateClientConfiguration; delay: (milliseconds: number) => Promise; - emitMessages: (events: any[]) => void; - emitStatus: (status: any) => void; + emitMessages: (events: Subscription.SubscriptionResponse['messages']) => void; + emitStatus: (status: StatusEvent) => void; }; export class EventEngineDispatcher extends Dispatcher { @@ -37,11 +43,8 @@ export class EventEngineDispatcher extends Dispatcher ({ channels, @@ -10,12 +11,15 @@ export const handshake = createManagedEffect('HANDSHAKE', (channels: string[], g export const receiveMessages = createManagedEffect( 'RECEIVE_MESSAGES', - (channels: string[], groups: string[], cursor: Cursor) => ({ channels, groups, cursor }), + (channels: string[], groups: string[], cursor: Subscription.SubscriptionCursor) => ({ channels, groups, cursor }), ); -export const emitMessages = createEffect('EMIT_MESSAGES', (events: any[]) => events); +export const emitMessages = createEffect( + 'EMIT_MESSAGES', + (events: Subscription.SubscriptionResponse['messages']) => events, +); -export const emitStatus = createEffect('EMIT_STATUS', (status: any) => status); +export const emitStatus = createEffect('EMIT_STATUS', (status: StatusEvent) => status); export const receiveReconnect = createManagedEffect( 'RECEIVE_RECONNECT', diff --git a/src/event-engine/events.ts b/src/event-engine/events.ts index c0341d8f0..70fa68b3b 100644 --- a/src/event-engine/events.ts +++ b/src/event-engine/events.ts @@ -1,5 +1,5 @@ -import { PubNubError } from '../core/components/endpoint'; -import { Cursor } from '../models/Cursor'; +import * as Subscription from '../core/types/api/subscription'; +import { PubNubError } from '../errors/pubnub-error'; import { createEvent, MapOf } from './core'; export const subscriptionChange = createEvent('SUBSCRIPTION_CHANGED', (channels: string[], groups: string[]) => ({ @@ -9,7 +9,7 @@ export const subscriptionChange = createEvent('SUBSCRIPTION_CHANGED', (channels: export const restore = createEvent( 'SUBSCRIPTION_RESTORED', - (channels: string[], groups: string[], timetoken: string, region?: number) => ({ + (channels: string[], groups: string[], timetoken: string | number, region?: number) => ({ channels, groups, cursor: { @@ -19,25 +19,34 @@ export const restore = createEvent( }), ); -export const handshakeSuccess = createEvent('HANDSHAKE_SUCCESS', (cursor: Cursor) => cursor); +export const handshakeSuccess = createEvent('HANDSHAKE_SUCCESS', (cursor: Subscription.SubscriptionCursor) => cursor); export const handshakeFailure = createEvent('HANDSHAKE_FAILURE', (error: PubNubError) => error); -export const handshakeReconnectSuccess = createEvent('HANDSHAKE_RECONNECT_SUCCESS', (cursor: Cursor) => ({ - cursor, -})); +export const handshakeReconnectSuccess = createEvent( + 'HANDSHAKE_RECONNECT_SUCCESS', + (cursor: Subscription.SubscriptionCursor) => ({ + cursor, + }), +); export const handshakeReconnectFailure = createEvent('HANDSHAKE_RECONNECT_FAILURE', (error: PubNubError) => error); export const handshakeReconnectGiveup = createEvent('HANDSHAKE_RECONNECT_GIVEUP', (error: PubNubError) => error); -export const receiveSuccess = createEvent('RECEIVE_SUCCESS', (cursor: Cursor, events: any[]) => ({ - cursor, - events, -})); +export const receiveSuccess = createEvent( + 'RECEIVE_SUCCESS', + (cursor: Subscription.SubscriptionCursor, events: Subscription.SubscriptionResponse['messages']) => ({ + cursor, + events, + }), +); export const receiveFailure = createEvent('RECEIVE_FAILURE', (error: PubNubError) => error); -export const receiveReconnectSuccess = createEvent('RECEIVE_RECONNECT_SUCCESS', (cursor: Cursor, events: any[]) => ({ - cursor, - events, -})); +export const receiveReconnectSuccess = createEvent( + 'RECEIVE_RECONNECT_SUCCESS', + (cursor: Subscription.SubscriptionCursor, events: Subscription.SubscriptionResponse['messages']) => ({ + cursor, + events, + }), +); export const receiveReconnectFailure = createEvent('RECEIVE_RECONNECT_FAILURE', (error: PubNubError) => error); export const receiveReconnectGiveup = createEvent('RECEIVING_RECONNECT_GIVEUP', (error: PubNubError) => error); export const disconnect = createEvent('DISCONNECT', () => ({})); diff --git a/src/event-engine/index.ts b/src/event-engine/index.ts index 5e948e769..871d78c7e 100644 --- a/src/event-engine/index.ts +++ b/src/event-engine/index.ts @@ -15,7 +15,7 @@ export class EventEngine { return this.engine; } - private _unsubscribeEngine!: () => void; + private readonly _unsubscribeEngine!: () => void; constructor(dependencies: Dependencies) { this.dependencies = dependencies; @@ -41,11 +41,12 @@ export class EventEngine { }: { channels?: string[]; channelGroups?: string[]; - timetoken?: string; + timetoken?: string | number; withPresence?: boolean; }): void { this.channels = [...this.channels, ...(channels ?? [])]; this.groups = [...this.groups, ...(channelGroups ?? [])]; + if (withPresence) { this.channels.map((c) => this.channels.push(`${c}-pnpres`)); this.groups.map((g) => this.groups.push(`${g}-pnpres`)); @@ -79,6 +80,7 @@ export class EventEngine { ...channels, ...channels.map((c) => `${c}-pnpres`), ]); + const filteredGroups = utils.removeSingleOccurance(this.groups, [ ...channelGroups, ...channelGroups.map((c) => `${c}-pnpres`), @@ -116,7 +118,9 @@ export class EventEngine { this.groups = []; if (this.dependencies.presenceState) { - this.dependencies.presenceState = {}; + Object.keys(this.dependencies.presenceState).forEach((objectName) => { + delete this.dependencies.presenceState[objectName]; + }); } this.engine.transition(events.subscriptionChange(this.channels.slice(0), this.groups.slice(0))); if (this.dependencies.leaveAll) { @@ -136,11 +140,11 @@ export class EventEngine { } getSubscribedChannels(): string[] { - return Array.from(new Set(this.channels)); + return Array.from(new Set(this.channels.slice(0))); } getSubscribedChannelGroups(): string[] { - return Array.from(new Set(this.groups)); + return Array.from(new Set(this.groups.slice(0))); } dispose(): void { diff --git a/src/event-engine/presence/dispatcher.ts b/src/event-engine/presence/dispatcher.ts index 39c455362..f2dfa0571 100644 --- a/src/event-engine/presence/dispatcher.ts +++ b/src/event-engine/presence/dispatcher.ts @@ -1,18 +1,26 @@ -import { PubNubError } from '../../core/components/endpoint'; +import { PrivateClientConfiguration } from '../../core/interfaces/configuration'; import { asyncHandler, Dispatcher, Engine } from '../core'; import PNOperations from '../../core/constants/operations'; +import * as Presence from '../../core/types/api/presence'; +import { PubNubError } from '../../errors/pubnub-error'; +import { Payload, ResultCallback } from '../../core/types/api'; import * as effects from './effects'; import * as events from './events'; +import StatusCategory from '../../core/constants/categories'; export type Dependencies = { - heartbeat: any; - leave: any; + heartbeat: ( + parameters: Presence.PresenceHeartbeatParameters, + callback?: ResultCallback, + ) => Promise; + leave: (parameters: Presence.PresenceLeaveParameters) => void; heartbeatDelay: () => Promise; retryDelay: (milliseconds: number) => Promise; - config: any; - presenceState: any; + config: PrivateClientConfiguration; + presenceState: Record; + /* eslint-disable @typescript-eslint/no-explicit-any */ emitStatus: (status: any) => void; }; @@ -28,10 +36,12 @@ export class PresenceEventEngineDispatcher extends Dispatcher { if (!config.suppressLeaveEvents) { try { - const result = await leave({ + leave({ channels: payload.channels, channelGroups: payload.groups, }); @@ -70,21 +80,21 @@ export class PresenceEventEngineDispatcher extends Dispatcher { if (config.retryConfiguration && config.retryConfiguration.shouldRetry(payload.reason, payload.attempts)) { abortSignal.throwIfAborted(); + await retryDelay(config.retryConfiguration.getDelay(payload.attempts, payload.reason)); + abortSignal.throwIfAborted(); try { const result = await heartbeat({ channels: payload.channels, channelGroups: payload.groups, ...(config.maintainPresenceState && { state: presenceState }), + heartbeat: config.presenceTimeout!, }); return engine.transition(events.heartbeatSuccess(200)); } catch (e) { - if (e instanceof Error && e.message === 'Aborted') { - return; - } - if (e instanceof PubNubError) { + if (e.status && e.status.category == StatusCategory.PNCancelledCategory) return; return engine.transition(events.heartbeatFailure(e)); } } diff --git a/src/event-engine/presence/effects.ts b/src/event-engine/presence/effects.ts index e60579f5f..0eddde4d5 100644 --- a/src/event-engine/presence/effects.ts +++ b/src/event-engine/presence/effects.ts @@ -1,5 +1,6 @@ import { createEffect, createManagedEffect, MapOf } from '../core'; import { HeartbeatReconnectingStateContext } from './states/heartbeat_reconnecting'; +import { Status } from '../../core/types/api'; export const heartbeat = createEffect('HEARTBEAT', (channels: string[], groups: string[]) => ({ channels, @@ -11,6 +12,7 @@ export const leave = createEffect('LEAVE', (channels: string[], groups: string[] groups, })); +/* eslint-disable @typescript-eslint/no-explicit-any */ export const emitStatus = createEffect('EMIT_STATUS', (status: any) => status); export const wait = createManagedEffect('WAIT', () => ({})); diff --git a/src/event-engine/presence/events.ts b/src/event-engine/presence/events.ts index d25642967..9607a44d7 100644 --- a/src/event-engine/presence/events.ts +++ b/src/event-engine/presence/events.ts @@ -1,4 +1,4 @@ -import { PubNubError } from '../../core/components/endpoint'; +import { PubNubError } from '../../errors/pubnub-error'; import { createEvent, MapOf } from '../core'; export const reconnect = createEvent('RECONNECT', () => ({})); diff --git a/src/event-engine/presence/presence.ts b/src/event-engine/presence/presence.ts index 05cb03500..768fbed1e 100644 --- a/src/event-engine/presence/presence.ts +++ b/src/event-engine/presence/presence.ts @@ -8,7 +8,6 @@ import { HeartbeatInactiveState } from './states/heartbeat_inactive'; export class PresenceEventEngine { private engine: Engine = new Engine(); private dispatcher: Dispatcher; - private dependencies: any; get _engine() { return this.engine; @@ -16,9 +15,8 @@ export class PresenceEventEngine { private _unsubscribeEngine!: () => void; - constructor(dependencies: Dependencies) { + constructor(private dependencies: Dependencies) { this.dispatcher = new PresenceEventEngineDispatcher(this.engine, dependencies); - this.dependencies = dependencies; this._unsubscribeEngine = this.engine.subscribe((change) => { if (change.type === 'invocationDispatched') { diff --git a/src/event-engine/presence/states/heartbeat_reconnecting.ts b/src/event-engine/presence/states/heartbeat_reconnecting.ts index 099a05e4d..a665004ab 100644 --- a/src/event-engine/presence/states/heartbeat_reconnecting.ts +++ b/src/event-engine/presence/states/heartbeat_reconnecting.ts @@ -1,5 +1,5 @@ +import { PubNubError } from '../../../errors/pubnub-error'; import { State } from '../../core/state'; -import { PubNubError } from '../../../core/components/endpoint'; import { Events, disconnect, diff --git a/src/event-engine/states/handshake_failed.ts b/src/event-engine/states/handshake_failed.ts index dd86cd552..7b86933a4 100644 --- a/src/event-engine/states/handshake_failed.ts +++ b/src/event-engine/states/handshake_failed.ts @@ -1,15 +1,15 @@ import { State } from '../core/state'; import { Effects } from '../effects'; import { Events, reconnect, restore, subscriptionChange, unsubscribeAll } from '../events'; -import { PubNubError } from '../../core/components/endpoint'; +import { PubNubError } from '../../errors/pubnub-error'; import { HandshakingState } from './handshaking'; import { UnsubscribedState } from './unsubscribed'; -import { Cursor } from '../../models/Cursor'; +import * as Subscription from '../../core/types/api/subscription'; export type HandshakeFailedStateContext = { channels: string[]; groups: string[]; - cursor?: Cursor; + cursor?: Subscription.SubscriptionCursor; reason: PubNubError; }; diff --git a/src/event-engine/states/handshake_reconnecting.ts b/src/event-engine/states/handshake_reconnecting.ts index 75a2fe6d3..6c82a348d 100644 --- a/src/event-engine/states/handshake_reconnecting.ts +++ b/src/event-engine/states/handshake_reconnecting.ts @@ -1,4 +1,4 @@ -import { PubNubError } from '../../core/components/endpoint'; +import { PubNubError } from '../../errors/pubnub-error'; import { State } from '../core/state'; import { Effects, emitStatus, handshakeReconnect } from '../effects'; import { @@ -17,12 +17,12 @@ import { HandshakingState } from './handshaking'; import { ReceivingState } from './receiving'; import { UnsubscribedState } from './unsubscribed'; import categoryConstants from '../../core/constants/categories'; -import { Cursor } from '../../models/Cursor'; +import * as Subscription from '../../core/types/api/subscription'; export type HandshakeReconnectingStateContext = { channels: string[]; groups: string[]; - cursor?: Cursor; + cursor?: Subscription.SubscriptionCursor; attempts: number; reason: PubNubError; diff --git a/src/event-engine/states/handshake_stopped.ts b/src/event-engine/states/handshake_stopped.ts index 133451f93..e7040c417 100644 --- a/src/event-engine/states/handshake_stopped.ts +++ b/src/event-engine/states/handshake_stopped.ts @@ -1,14 +1,14 @@ -import { Cursor } from '../../models/Cursor'; import { State } from '../core/state'; import { Effects } from '../effects'; import { Events, reconnect, restore, subscriptionChange, unsubscribeAll } from '../events'; import { HandshakingState } from './handshaking'; import { UnsubscribedState } from './unsubscribed'; +import * as Subscription from '../../core/types/api/subscription'; type HandshakeStoppedStateContext = { channels: string[]; groups: string[]; - cursor?: Cursor; + cursor?: Subscription.SubscriptionCursor; }; export const HandshakeStoppedState = new State('HANDSHAKE_STOPPED'); diff --git a/src/event-engine/states/handshaking.ts b/src/event-engine/states/handshaking.ts index 14ea66adc..c2dcdb7b5 100644 --- a/src/event-engine/states/handshaking.ts +++ b/src/event-engine/states/handshaking.ts @@ -14,12 +14,12 @@ import { HandshakeStoppedState } from './handshake_stopped'; import { ReceivingState } from './receiving'; import { UnsubscribedState } from './unsubscribed'; import categoryConstants from '../../core/constants/categories'; -import { Cursor } from '../../models/Cursor'; +import * as Subscription from '../../core/types/api/subscription'; export type HandshakingStateContext = { channels: string[]; groups: string[]; - cursor?: Cursor; + cursor?: Subscription.SubscriptionCursor; }; export const HandshakingState = new State('HANDSHAKING'); diff --git a/src/event-engine/states/receive_failed.ts b/src/event-engine/states/receive_failed.ts index 91de8e787..5b3db90be 100644 --- a/src/event-engine/states/receive_failed.ts +++ b/src/event-engine/states/receive_failed.ts @@ -1,15 +1,15 @@ import { State } from '../core/state'; -import { Cursor } from '../../models/Cursor'; import { Effects } from '../effects'; import { Events, reconnect, restore, subscriptionChange, unsubscribeAll } from '../events'; -import { PubNubError } from '../../core/components/endpoint'; +import { PubNubError } from '../../errors/pubnub-error'; import { HandshakingState } from './handshaking'; import { UnsubscribedState } from './unsubscribed'; +import * as Subscription from '../../core/types/api/subscription'; export type ReceiveFailedStateContext = { channels: string[]; groups: string[]; - cursor: Cursor; + cursor: Subscription.SubscriptionCursor; reason: PubNubError; }; diff --git a/src/event-engine/states/receive_reconnecting.ts b/src/event-engine/states/receive_reconnecting.ts index 69b550558..133a44bfe 100644 --- a/src/event-engine/states/receive_reconnecting.ts +++ b/src/event-engine/states/receive_reconnecting.ts @@ -1,5 +1,4 @@ -import { PubNubError } from '../../core/components/endpoint'; -import { Cursor } from '../../models/Cursor'; +import { PubNubError } from '../../errors/pubnub-error'; import { State } from '../core/state'; import { Effects, emitMessages, receiveReconnect, emitStatus } from '../effects'; import { @@ -17,11 +16,12 @@ import { ReceiveFailedState } from './receive_failed'; import { ReceiveStoppedState } from './receive_stopped'; import { UnsubscribedState } from './unsubscribed'; import categoryConstants from '../../core/constants/categories'; +import * as Subscription from '../../core/types/api/subscription'; export type ReceiveReconnectingStateContext = { channels: string[]; groups: string[]; - cursor: Cursor; + cursor: Subscription.SubscriptionCursor; attempts: number; reason: PubNubError; diff --git a/src/event-engine/states/receive_stopped.ts b/src/event-engine/states/receive_stopped.ts index 20993b80f..49027d275 100644 --- a/src/event-engine/states/receive_stopped.ts +++ b/src/event-engine/states/receive_stopped.ts @@ -1,14 +1,14 @@ -import { Cursor } from '../../models/Cursor'; import { State } from '../core/state'; import { Effects } from '../effects'; import { Events, reconnect, restore, subscriptionChange, unsubscribeAll } from '../events'; import { HandshakingState } from './handshaking'; import { UnsubscribedState } from './unsubscribed'; +import * as Subscription from '../../core/types/api/subscription'; type ReceiveStoppedStateContext = { channels: string[]; groups: string[]; - cursor: Cursor; + cursor: Subscription.SubscriptionCursor; }; export const ReceiveStoppedState = new State('RECEIVE_STOPPED'); diff --git a/src/event-engine/states/receiving.ts b/src/event-engine/states/receiving.ts index e7789debc..7219f0bf3 100644 --- a/src/event-engine/states/receiving.ts +++ b/src/event-engine/states/receiving.ts @@ -1,5 +1,4 @@ import { State } from '../core/state'; -import { Cursor } from '../../models/Cursor'; import { Effects, emitMessages, emitStatus, receiveMessages } from '../effects'; import { disconnect, @@ -14,11 +13,12 @@ import { UnsubscribedState } from './unsubscribed'; import { ReceiveReconnectingState } from './receive_reconnecting'; import { ReceiveStoppedState } from './receive_stopped'; import categoryConstants from '../../core/constants/categories'; +import * as Subscription from '../../core/types/api/subscription'; export type ReceivingStateContext = { channels: string[]; groups: string[]; - cursor: Cursor; + cursor: Subscription.SubscriptionCursor; }; export const ReceivingState = new State('RECEIVING'); diff --git a/src/file/index.js b/src/file/index.js deleted file mode 100644 index 0975b9062..000000000 --- a/src/file/index.js +++ /dev/null @@ -1 +0,0 @@ -/** */ diff --git a/src/file/modules/node.js b/src/file/modules/node.js deleted file mode 100644 index 9b51c6e27..000000000 --- a/src/file/modules/node.js +++ /dev/null @@ -1,136 +0,0 @@ -import { Readable, PassThrough } from 'stream'; -import fs from 'fs'; -import { basename } from 'path'; - -const PubNubFile = class PubNubFile { - static supportsBlob = false; - - static supportsFile = false; - - static supportsBuffer = typeof Buffer !== 'undefined'; - - static supportsStream = true; - - static supportsString = true; - - static supportsArrayBuffer = false; - - static supportsEncryptFile = true; - - static supportsFileUri = false; - - data; - - name; - - mimeType; - - contentLength; - - static create(config) { - return new this(config); - } - - constructor({ stream, data, encoding, name, mimeType }) { - if (stream instanceof Readable) { - this.data = stream; - - if (stream instanceof fs.ReadStream) { - // $FlowFixMe: incomplete flow node definitions - this.name = basename(stream.path); - this.contentLength = fs.statSync(stream.path).size; - } - } else if (data instanceof Buffer) { - this.data = Buffer.from(data); - } else if (typeof data === 'string') { - // $FlowFixMe: incomplete flow node definitions - this.data = Buffer.from(data, encoding ?? 'utf8'); - } - - if (name) { - this.name = basename(name); - } - - if (mimeType) { - this.mimeType = mimeType; - } - - if (this.data === undefined) { - throw new Error("Couldn't construct a file out of supplied options."); - } - - if (this.name === undefined) { - throw new Error("Couldn't guess filename out of the options. Please provide one."); - } - } - - toBuffer() { - if (this.data instanceof Buffer) { - return Promise.resolve(Buffer.from(this.data)); - } - - if (this.data instanceof Readable) { - const stream = this.data; - return new Promise((resolve, reject) => { - const chunks = []; - - stream.on('data', (chunk) => chunks.push(chunk)); - stream.once('error', reject); - stream.once('end', () => { - resolve(Buffer.concat(chunks)); - }); - }); - } - - if (typeof this.data === 'string') { - return Promise.resolve(Buffer.from(this.data)); - } - - throw new Error("Can't cast to 'buffer'."); - } - - async toArrayBuffer() { - throw new Error('This feature is only supported in browser environments.'); - } - - async toString(encoding = 'utf8') { - const buffer = await this.toBuffer(); - - return buffer.toString(encoding); - } - - async toStream() { - if (!(this.data instanceof Readable)) { - const input = this.data; - - return new Readable({ - read() { - this.push(Buffer.from(input)); - this.push(null); - }, - }); - } - - const stream = new PassThrough(); - - if (this.data instanceof Readable) { - this.data.pipe(stream); - } - - return stream; - } - - async toFile() { - throw new Error('This feature is only supported in browser environments.'); - } - - async toFileUri() { - throw new Error('This feature is only supported in react native environments.'); - } - - async toBlob() { - throw new Error('This feature is only supported in browser environments.'); - } -}; - -export default PubNubFile; diff --git a/src/file/modules/node.ts b/src/file/modules/node.ts new file mode 100644 index 000000000..ae2fde560 --- /dev/null +++ b/src/file/modules/node.ts @@ -0,0 +1,257 @@ +/** + * Node.js {@link PubNub} File object module. + */ + +import { Readable, PassThrough } from 'stream'; +import { Buffer } from 'buffer'; +import { basename } from 'path'; +import fs from 'fs'; + +import { PubNubFileInterface } from '../../core/types/file'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- + +// region Types +/** + * PubNub File instance creation parameters. + */ +export type PubNubFileParameters = { + /** + * Readable stream represents file object content. + */ + stream?: Readable; + + /** + * Buffer or string represents file object content. + */ + data?: Buffer | ArrayBuffer | string; + + /** + * String {@link PubNubFileParameters#data|data} encoding. + * + * @default `utf8` + */ + encoding?: StringEncoding; + + /** + * File object name. + */ + name: string; + + /** + * File object content type. + */ + mimeType?: string; +}; +// endregion + +/** + * Node.js implementation for {@link PubNub} File object. + * + * **Important:** Class should implement constructor and class fields from {@link PubNubFileConstructor}. + */ +export default class PubNubFile implements PubNubFileInterface { + // region Class properties + /** + * Whether {@link Blob} data supported by platform or not. + */ + static supportsBlob = false; + + /** + * Whether {@link File} data supported by platform or not. + */ + static supportsFile = false; + + /** + * Whether {@link Buffer} data supported by platform or not. + */ + static supportsBuffer = true; + + /** + * Whether {@link Stream} data supported by platform or not. + */ + static supportsStream = true; + + /** + * Whether {@link String} data supported by platform or not. + */ + static supportsString = true; + + /** + * Whether {@link ArrayBuffer} supported by platform or not. + */ + static supportsArrayBuffer = true; + + /** + * Whether {@link PubNub} File object encryption supported or not. + */ + static supportsEncryptFile = true; + + /** + * Whether `File Uri` data supported by platform or not. + */ + static supportsFileUri = false; + // endregion + + // region Instance properties + /** + * File object content source. + */ + readonly data: Readable | Buffer; + + /** + * File object content length. + */ + contentLength?: number; + + /** + * File object content type. + */ + mimeType: string; + + /** + * File object name. + */ + name: string; + // endregion + + static create(file: PubNubFileParameters) { + return new PubNubFile(file); + } + + constructor(file: PubNubFileParameters) { + const { stream, data, encoding, name, mimeType } = file; + let fileData: Readable | Buffer | undefined; + let contentLength: number | undefined; + let fileMimeType: string | undefined; + let fileName: string | undefined; + + if (stream && stream instanceof Readable) { + fileData = stream; + + if (stream instanceof fs.ReadStream) { + const streamFilePath = stream.path instanceof Buffer ? new TextDecoder().decode(stream.path) : stream.path; + fileName = basename(streamFilePath); + contentLength = fs.statSync(streamFilePath).size; + } + } else if (data instanceof Buffer) { + contentLength = data.length; + // Copy content of the source Buffer. + fileData = Buffer.alloc(contentLength!); + data.copy(fileData); + } else if (data instanceof ArrayBuffer) { + contentLength = data.byteLength; + fileData = Buffer.from(data); + } else if (typeof data === 'string') { + fileData = Buffer.from(data, encoding ?? 'utf8'); + contentLength = fileData.length; + } + + if (contentLength) this.contentLength = contentLength; + if (mimeType) fileMimeType = mimeType; + else fileMimeType = 'application/octet-stream'; + if (name) fileName = basename(name); + + if (fileData === undefined) throw new Error("Couldn't construct a file out of supplied options."); + if (fileName === undefined) throw new Error("Couldn't guess filename out of the options. Please provide one."); + + this.mimeType = fileMimeType; + this.data = fileData; + this.name = fileName; + } + + /** + * Convert {@link PubNub} File object content to {@link Buffer}. + * + * @returns Asynchronous results of conversion to the {@link Buffer}. + */ + async toBuffer(): Promise { + if (this.data instanceof Buffer) return this.data; + + const stream = this.data; + return new Promise((resolve, reject) => { + const chunks: Uint8Array[] = []; + + stream.on('data', (chunk) => { + chunks.push(chunk); + }); + stream.on('end', () => { + resolve(Buffer.concat(chunks)); + }); + + // Handle any errors during streaming + stream.on('error', (error) => reject(error)); + }); + } + + /** + * Convert {@link PubNub} File object content to {@link ArrayBuffer}. + * + * @returns Asynchronous results of conversion to the {@link ArrayBuffer}. + */ + async toArrayBuffer(): Promise { + return this.toBuffer().then((buffer) => buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.length)); + } + + /** + * Convert {@link PubNub} File object content to {@link string}. + * + * @returns Asynchronous results of conversion to the {@link string}. + */ + async toString(encoding: BufferEncoding = 'utf8'): Promise { + return this.toBuffer().then((buffer) => buffer.toString(encoding)); + } + + /** + * Convert {@link PubNub} File object content to {@link Readable} stream. + * + * @returns Asynchronous results of conversion to the {@link Readable} stream. + */ + async toStream() { + if (this.data instanceof Readable) { + const stream = new PassThrough(); + this.data.pipe(stream); + + return stream; + } + + return this.toBuffer().then( + (buffer) => + new Readable({ + read() { + this.push(buffer); + this.push(null); + }, + }), + ); + } + + /** + * Convert {@link PubNub} File object content to {@link File}. + * + * @throws Error because {@link File} not available in Node.js environment. + */ + async toFile() { + throw new Error('This feature is only supported in browser environments.'); + } + + /** + * Convert {@link PubNub} File object content to file `Uri`. + * + * @throws Error because file `Uri` not available in Node.js environment. + */ + async toFileUri(): Promise> { + throw new Error('This feature is only supported in React Native environments.'); + } + + /** + * Convert {@link PubNub} File object content to {@link Blob}. + * + * @throws Error because {@link Blob} not available in Node.js environment. + */ + async toBlob() { + throw new Error('This feature is only supported in browser environments.'); + } +} diff --git a/src/file/modules/react-native.js b/src/file/modules/react-native.js deleted file mode 100644 index 4d9921862..000000000 --- a/src/file/modules/react-native.js +++ /dev/null @@ -1,167 +0,0 @@ -/* global File, FileReader */ - -import { IFile, FileClass } from '..'; - -const PubNubFile = class PubNubFile { - static supportsFile = typeof File !== 'undefined'; - - static supportsBlob = typeof Blob !== 'undefined'; - - static supportsArrayBuffer = typeof ArrayBuffer !== 'undefined'; - - static supportsBuffer = false; - - static supportsStream = false; - - static supportsString = true; - - static supportsEncryptFile = false; - - static supportsFileUri = true; - - static create(config) { - return new this(config); - } - - data; - - name; - - mimeType; - - constructor(config) { - if (config instanceof File) { - this.data = config; - - this.name = this.data.name; - this.mimeType = this.data.type; - } else if (config.uri) { - // uri upload for react native - this.data = { - uri: config.uri, - name: config.name, - type: config.mimeType, - }; - - this.name = config.name; - - if (config.mimeType) { - this.mimeType = config.mimeType; - } - } else if (config.data) { - this.data = config.data; - this.name = config.name; - - if (config.mimeType) { - this.mimeType = config.mimeType; - } - } else { - throw new Error("Couldn't construct a file out of supplied options. URI or file data required."); - } - - if (this.data === undefined) { - throw new Error("Couldn't construct a file out of supplied options."); - } - - if (this.name === undefined) { - throw new Error("Couldn't guess filename out of the options. Please provide one."); - } - } - - async toBuffer() { - throw new Error('This feature is only supported in Node.js environments.'); - } - - async toStream() { - throw new Error('This feature is only supported in Node.js environments.'); - } - - async toBlob() { - if (this.data && this.data.uri) { - throw new Error('This file contains a file URI and does not contain the file contents.'); - } else if (this.data instanceof File) { - return this.data; - } else { - // data must be a fetch response - return this.data.blob(); - } - } - - async toArrayBuffer() { - if (this.data && this.data.uri) { - throw new Error('This file contains a file URI and does not contain the file contents.'); - } else if (this.data instanceof File) { - return new Promise((resolve, reject) => { - const reader = new FileReader(); - - reader.addEventListener('load', () => { - if (reader.result instanceof ArrayBuffer) { - return resolve(reader.result); - } - }); - - reader.addEventListener('error', () => { - reject(reader.error); - }); - - reader.readAsArrayBuffer(this.data); - }); - } else { - // data must be a fetch response - let result; - - try { - result = await this.data.arrayBuffer(); - } catch (e) { - throw new Error(`Unable to support toArrayBuffer in ReactNative environment: ${e}`); - } - - return result; - } - } - - async toString() { - if (this.data && this.data.uri) { - return JSON.stringify(this.data); - } - if (this.data instanceof File) { - return new Promise((resolve, reject) => { - const reader = new FileReader(); - - reader.addEventListener('load', () => { - if (typeof reader.result === 'string') { - return resolve(reader.result); - } - }); - - reader.addEventListener('error', () => { - reject(reader.error); - }); - - reader.readAsBinaryString(this.data); - }); - } - // data must be a fetch response - return this.data.text(); - } - - async toFile() { - if (this.data.uri) { - throw new Error('This file contains a file URI and does not contain the file contents.'); - } else if (this.data instanceof File) { - return this.data; - } else { - // data must be a fetch response - return this.data.blob(); - } - } - - async toFileUri() { - if (this.data && this.data.uri) { - return this.data; - } - throw new Error('This file does not contain a file URI'); - } -}; - -export default PubNubFile; diff --git a/src/file/modules/react-native.ts b/src/file/modules/react-native.ts new file mode 100644 index 000000000..7c036a76e --- /dev/null +++ b/src/file/modules/react-native.ts @@ -0,0 +1,265 @@ +/* global File, FileReader */ +/** + * React Native {@link PubNub} File object module. + */ + +import { PubNubFileInterface } from '../../core/types/file'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- + +// region Types +/** + * File path-based file. + */ +type FileUri = { uri: string; name: string; mimeType?: string }; + +/** + * Asynchronously fetched file content. + */ +type ReadableFile = { arrayBuffer: () => Promise; blob: () => Promise; text: () => Promise }; + +/** + * PubNub File instance creation parameters. + */ +export type PubNubFileParameters = + | File + | FileUri + | ReadableFile + | { data: string | Blob | ArrayBuffer | ArrayBufferView; name: string; mimeType?: string }; +// endregion + +export class PubNubFile implements PubNubFileInterface { + // region Class properties + /** + * Whether {@link Blob} data supported by platform or not. + */ + static supportsBlob = typeof Blob !== 'undefined'; + + /** + * Whether {@link File} data supported by platform or not. + */ + static supportsFile = typeof File !== 'undefined'; + + /** + * Whether {@link Buffer} data supported by platform or not. + */ + static supportsBuffer = false; + + /** + * Whether {@link Stream} data supported by platform or not. + */ + static supportsStream = false; + + /** + * Whether {@link String} data supported by platform or not. + */ + static supportsString = true; + + /** + * Whether {@link ArrayBuffer} supported by platform or not. + */ + static supportsArrayBuffer = true; + + /** + * Whether {@link PubNub} File object encryption supported or not. + */ + static supportsEncryptFile = false; + + /** + * Whether `File Uri` data supported by platform or not. + */ + static supportsFileUri = true; + // endregion + + // region Instance properties + /** + * File object content source. + */ + readonly data: File | FileUri | ReadableFile; + + /** + * File object content length. + */ + contentLength?: number; + + /** + * File object content type. + */ + mimeType: string; + + /** + * File object name. + */ + name: string; + // endregion + + static create(file: PubNubFileParameters) { + return new PubNubFile(file); + } + + constructor(file: PubNubFileParameters) { + let fileData: PubNubFile['data'] | undefined; + let contentLength: number | undefined; + let fileMimeType: string | undefined; + let fileName: string | undefined; + + if (file instanceof File) { + fileData = file; + + fileName = file.name; + fileMimeType = file.type; + contentLength = file.size; + } else if ('data' in file) { + const contents = file.data; + + fileMimeType = file.mimeType; + fileName = file.name; + fileData = new File([contents], fileName, { type: fileMimeType }); + contentLength = fileData.size; + } else if ('uri' in file) { + fileMimeType = file.mimeType; + fileName = file.name; + fileData = { + uri: file.uri, + name: file.name, + type: file.mimeType!, + }; + } else throw new Error("Couldn't construct a file out of supplied options. URI or file data required."); + + if (fileData === undefined) throw new Error("Couldn't construct a file out of supplied options."); + if (fileName === undefined) throw new Error("Couldn't guess filename out of the options. Please provide one."); + + if (contentLength) this.contentLength = contentLength; + this.mimeType = fileMimeType!; + this.data = fileData; + this.name = fileName; + } + + /** + * Convert {@link PubNub} File object content to {@link Buffer}. + * + * @throws Error because {@link Buffer} not available in React Native environment. + */ + async toBuffer() { + throw new Error('This feature is only supported in Node.js environments.'); + } + + /** + * Convert {@link PubNub} File object content to {@link ArrayBuffer}. + * + * @returns Asynchronous results of conversion to the {@link ArrayBuffer}. + * + * @throws Error if provided {@link PubNub} File object content is not supported for this + * operation. + */ + async toArrayBuffer(): Promise { + if (this.data && this.data instanceof File) { + const data = this.data; + + return new Promise((resolve, reject) => { + const reader = new FileReader(); + + reader.addEventListener('load', () => { + if (reader.result instanceof ArrayBuffer) return resolve(reader.result); + }); + reader.addEventListener('error', () => reject(reader.error)); + reader.readAsArrayBuffer(data); + }); + } else if (this.data && 'uri' in this.data) { + throw new Error('This file contains a file URI and does not contain the file contents.'); + } else if (this.data) { + let result: ArrayBuffer | undefined; + + try { + result = await this.data.arrayBuffer(); + } catch (error) { + throw new Error(`Unable to support toArrayBuffer in ReactNative environment: ${error}`); + } + + return result; + } + + throw new Error('Unable convert provided file content type to ArrayBuffer'); + } + + /** + * Convert {@link PubNub} File object content to {@link string}. + * + * @returns Asynchronous results of conversion to the {@link string}. + */ + async toString(): Promise { + if (this.data && 'uri' in this.data) return JSON.stringify(this.data); + else if (this.data && this.data instanceof File) { + const data = this.data; + + return new Promise((resolve, reject) => { + const reader = new FileReader(); + + reader.addEventListener('load', () => { + if (typeof reader.result === 'string') return resolve(reader.result); + }); + reader.addEventListener('error', () => reject(reader.error)); + reader.readAsBinaryString(data); + }); + } + + return this.data.text(); + } + + /** + * Convert {@link PubNub} File object content to {@link Readable} stream. + * + * @throws Error because {@link Readable} stream not available in React Native environment. + */ + async toStream() { + throw new Error('This feature is only supported in Node.js environments.'); + } + + /** + * Convert {@link PubNub} File object content to {@link File}. + * + * @returns Asynchronous results of conversion to the {@link File}. + * + * @throws Error if provided {@link PubNub} File object content is not supported for this + * operation. + */ + async toFile() { + if (this.data instanceof File) return this.data; + else if ('uri' in this.data) + throw new Error('This file contains a file URI and does not contain the file contents.'); + else return this.data.blob(); + } + + /** + * Convert {@link PubNub} File object content to file `Uri`. + * + * @returns Asynchronous results of conversion to file `Uri`. + * + * @throws Error if provided {@link PubNub} File object content is not supported for this + * operation. + */ + async toFileUri() { + if (this.data && 'uri' in this.data) return this.data; + + throw new Error('This file does not contain a file URI'); + } + + /** + * Convert {@link PubNub} File object content to {@link Blob}. + * + * @returns Asynchronous results of conversion to the {@link Blob}. + * + * @throws Error if provided {@link PubNub} File object content is not supported for this + * operation. + */ + async toBlob() { + if (this.data instanceof File) return this.data; + else if (this.data && 'uri' in this.data) + throw new Error('This file contains a file URI and does not contain the file contents.'); + else return this.data.blob(); + } +} + +export default PubNubFile; diff --git a/src/file/modules/web.js b/src/file/modules/web.js deleted file mode 100644 index 0f741a619..000000000 --- a/src/file/modules/web.js +++ /dev/null @@ -1,116 +0,0 @@ -/* global File, FileReader */ - -import { IFile, FileClass } from '..'; - -const PubNubFile = class PubNubFile { - static supportsFile = typeof File !== 'undefined'; - - static supportsBlob = typeof Blob !== 'undefined'; - - static supportsArrayBuffer = typeof ArrayBuffer !== 'undefined'; - - static supportsBuffer = false; - - static supportsStream = false; - - static supportsString = true; - - static supportsEncryptFile = true; - - static supportsFileUri = false; - - static create(config) { - return new this(config); - } - - data; - - name; - - mimeType; - - constructor(config) { - if (config instanceof File) { - this.data = config; - - this.name = this.data.name; - this.mimeType = this.data.type; - } else if (config.data) { - const contents = config.data; - - this.data = new File([contents], config.name, { type: config.mimeType }); - - this.name = config.name; - - if (config.mimeType) { - this.mimeType = config.mimeType; - } - } - - if (this.data === undefined) { - throw new Error("Couldn't construct a file out of supplied options."); - } - - if (this.name === undefined) { - throw new Error("Couldn't guess filename out of the options. Please provide one."); - } - } - - async toBuffer() { - throw new Error('This feature is only supported in Node.js environments.'); - } - - async toStream() { - throw new Error('This feature is only supported in Node.js environments.'); - } - - async toFileUri() { - throw new Error('This feature is only supported in react native environments.'); - } - - async toBlob() { - return this.data; - } - - async toArrayBuffer() { - return new Promise((resolve, reject) => { - const reader = new FileReader(); - - reader.addEventListener('load', () => { - if (reader.result instanceof ArrayBuffer) { - return resolve(reader.result); - } - }); - - reader.addEventListener('error', () => { - reject(reader.error); - }); - - reader.readAsArrayBuffer(this.data); - }); - } - - async toString() { - return new Promise((resolve, reject) => { - const reader = new FileReader(); - - reader.addEventListener('load', () => { - if (typeof reader.result === 'string') { - return resolve(reader.result); - } - }); - - reader.addEventListener('error', () => { - reject(reader.error); - }); - - reader.readAsBinaryString(this.data); - }); - } - - async toFile() { - return this.data; - } -}; - -export default PubNubFile; diff --git a/src/file/modules/web.ts b/src/file/modules/web.ts new file mode 100644 index 000000000..b3a5e13ed --- /dev/null +++ b/src/file/modules/web.ts @@ -0,0 +1,209 @@ +/* global File, FileReader */ +/** + * Browser {@link PubNub} File object module. + */ + +import { PubNubFileInterface } from '../../core/types/file'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- + +// region Types +/** + * PubNub File instance creation parameters. + */ +export type PubNubFileParameters = + | File + | { data: string | Blob | ArrayBuffer | ArrayBufferView; name: string; mimeType?: string }; +// endregion + +/** + * Web implementation for {@link PubNub} File object. + * + * **Important:** Class should implement constructor and class fields from {@link PubNubFileConstructor}. + */ +export class PubNubFile implements PubNubFileInterface { + // region Class properties + /** + * Whether {@link Blob} data supported by platform or not. + */ + static supportsBlob = typeof Blob !== 'undefined'; + + /** + * Whether {@link File} data supported by platform or not. + */ + static supportsFile = typeof File !== 'undefined'; + + /** + * Whether {@link Buffer} data supported by platform or not. + */ + static supportsBuffer = false; + + /** + * Whether {@link Stream} data supported by platform or not. + */ + static supportsStream = false; + + /** + * Whether {@link String} data supported by platform or not. + */ + static supportsString = true; + + /** + * Whether {@link ArrayBuffer} supported by platform or not. + */ + static supportsArrayBuffer = true; + + /** + * Whether {@link PubNub} File object encryption supported or not. + */ + static supportsEncryptFile = true; + + /** + * Whether `File Uri` data supported by platform or not. + */ + static supportsFileUri = false; + // endregion + + // region Instance properties + /** + * File object content source. + */ + readonly data: File; + + /** + * File object content length. + */ + contentLength?: number; + + /** + * File object content type. + */ + mimeType: string; + + /** + * File object name. + */ + name: string; + // endregion + + static create(file: PubNubFileParameters) { + return new PubNubFile(file); + } + + constructor(file: PubNubFileParameters) { + let contentLength: number | undefined; + let fileMimeType: string | undefined; + let fileName: string | undefined; + let fileData: File | undefined; + + if (file instanceof File) { + fileData = file; + + fileName = file.name; + fileMimeType = file.type; + contentLength = file.size; + } else if ('data' in file) { + const contents = file.data; + + fileMimeType = file.mimeType; + fileName = file.name; + fileData = new File([contents], fileName, { type: fileMimeType }); + contentLength = fileData.size; + } + + if (fileData === undefined) throw new Error("Couldn't construct a file out of supplied options."); + if (fileName === undefined) throw new Error("Couldn't guess filename out of the options. Please provide one."); + + if (contentLength) this.contentLength = contentLength; + this.mimeType = fileMimeType!; + this.data = fileData; + this.name = fileName; + } + + /** + * Convert {@link PubNub} File object content to {@link Buffer}. + * + * @throws Error because {@link Buffer} not available in browser environment. + */ + async toBuffer() { + throw new Error('This feature is only supported in Node.js environments.'); + } + + /** + * Convert {@link PubNub} File object content to {@link ArrayBuffer}. + * + * @returns Asynchronous results of conversion to the {@link ArrayBuffer}. + */ + async toArrayBuffer(): Promise { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + + reader.addEventListener('load', () => { + if (reader.result instanceof ArrayBuffer) return resolve(reader.result); + }); + reader.addEventListener('error', () => reject(reader.error)); + reader.readAsArrayBuffer(this.data); + }); + } + + /** + * Convert {@link PubNub} File object content to {@link string}. + * + * @returns Asynchronous results of conversion to the {@link string}. + */ + async toString(): Promise { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + + reader.addEventListener('load', () => { + if (typeof reader.result === 'string') { + return resolve(reader.result); + } + }); + + reader.addEventListener('error', () => { + reject(reader.error); + }); + + reader.readAsBinaryString(this.data); + }); + } + + /** + * Convert {@link PubNub} File object content to {@link Readable} stream. + * + * @throws Error because {@link Readable} stream not available in browser environment. + */ + async toStream() { + throw new Error('This feature is only supported in Node.js environments.'); + } + + /** + * Convert {@link PubNub} File object content to {@link File}. + * + * @returns Asynchronous results of conversion to the {@link File}. + */ + async toFile() { + return this.data; + } + + /** + * Convert {@link PubNub} File object content to file `Uri`. + * + * @throws Error because file `Uri` not available in browser environment. + */ + async toFileUri(): Promise> { + throw new Error('This feature is only supported in React Native environments.'); + } + + /** + * Convert {@link PubNub} File object content to {@link Blob}. + * + * @returns Asynchronous results of conversion to the {@link Blob}. + */ + async toBlob() { + return this.data; + } +} diff --git a/src/networking/index.js b/src/networking/index.js deleted file mode 100644 index 74d666294..000000000 --- a/src/networking/index.js +++ /dev/null @@ -1,135 +0,0 @@ -/* */ - -import Config from '../core/components/config'; -import categoryConstants from '../core/constants/categories'; - -export default class { - _modules; - - _config; - - _currentSubDomain; - - _standardOrigin; - - _subscribeOrigin; - - _requestTimeout; - - _coreParams; /* items that must be passed with each request. */ - - constructor(modules) { - this._modules = {}; - - Object.keys(modules).forEach((key) => { - this._modules[key] = modules[key].bind(this); - }); - } - - init(config) { - this._config = config; - - if (Array.isArray(this._config.origin)) { - this._currentSubDomain = Math.floor(Math.random() * this._config.origin.length); - } else { - this._currentSubDomain = 0; - } - - this._coreParams = {}; - - // create initial origins - this.shiftStandardOrigin(); - } - - nextOrigin() { - const protocol = this._config.secure ? 'https://' : 'http://'; - - if (typeof this._config.origin === 'string') { - return `${protocol}${this._config.origin}`; - } - - this._currentSubDomain += 1; - - if (this._currentSubDomain >= this._config.origin.length) { - this._currentSubDomain = 0; - } - - const origin = this._config.origin[this._currentSubDomain]; - - return `${protocol}${origin}`; - } - - hasModule(name) { - return name in this._modules; - } - - // origin operations - shiftStandardOrigin() { - this._standardOrigin = this.nextOrigin(); - - return this._standardOrigin; - } - - getStandardOrigin() { - return this._standardOrigin; - } - - POSTFILE(url, fields, file) { - return this._modules.postfile(url, fields, file); - } - - GETFILE(params, endpoint, callback) { - return this._modules.getfile(params, endpoint, callback); - } - - POST(params, body, endpoint, callback) { - return this._modules.post(params, body, endpoint, callback); - } - - PATCH(params, body, endpoint, callback) { - return this._modules.patch(params, body, endpoint, callback); - } - - GET(params, endpoint, callback) { - return this._modules.get(params, endpoint, callback); - } - - DELETE(params, endpoint, callback) { - return this._modules.del(params, endpoint, callback); - } - - _detectErrorCategory(err) { - if (err.code === 'ENOTFOUND') { - return categoryConstants.PNNetworkIssuesCategory; - } - if (err.code === 'ECONNREFUSED') { - return categoryConstants.PNNetworkIssuesCategory; - } - if (err.code === 'ECONNRESET') { - return categoryConstants.PNNetworkIssuesCategory; - } - if (err.code === 'EAI_AGAIN') { - return categoryConstants.PNNetworkIssuesCategory; - } - - if (err.status === 0 || (err.hasOwnProperty('status') && typeof err.status === 'undefined')) { - return categoryConstants.PNNetworkIssuesCategory; - } - if (err.timeout) return categoryConstants.PNTimeoutCategory; - - if (err.code === 'ETIMEDOUT') { - return categoryConstants.PNNetworkIssuesCategory; - } - - if (err.response) { - if (err.response.badRequest) { - return categoryConstants.PNBadRequestCategory; - } - if (err.response.forbidden) { - return categoryConstants.PNAccessDeniedCategory; - } - } - - return categoryConstants.PNUnknownCategory; - } -} diff --git a/src/networking/modules/nativescript.js b/src/networking/modules/nativescript.js deleted file mode 100644 index b86fe7719..000000000 --- a/src/networking/modules/nativescript.js +++ /dev/null @@ -1,85 +0,0 @@ -/* */ - -import { request as HttpRequest } from 'http'; -import { buildUrl } from '../utils'; - -function log(url, qs, res) { - const _pickLogger = () => { - if (console && console.log) return console; // eslint-disable-line no-console - return console; - }; - - const start = new Date().getTime(); - const timestamp = new Date().toISOString(); - const logger = _pickLogger(); - logger.log('<<<<<'); // eslint-disable-line no-console - logger.log(`[${timestamp}]`, '\n', url, '\n', qs); // eslint-disable-line no-console - logger.log('-----'); // eslint-disable-line no-console - - const now = new Date().getTime(); - const elapsed = now - start; - const timestampDone = new Date().toISOString(); - - logger.log('>>>>>>'); // eslint-disable-line no-console - logger.log(`[${timestampDone} / ${elapsed}]`, '\n', url, '\n', qs, '\n', res); // eslint-disable-line no-console - logger.log('-----'); // eslint-disable-line no-console -} - -function xdr(method, url, params, body, endpoint, callback) { - const status = {}; - status.operation = endpoint.operation; - - const httpConfig = { - method, - url: buildUrl(url, params), - timeout: endpoint.timeout, - content: body, - }; - - // $FlowFixMe - return HttpRequest(httpConfig) - .then((response) => { - status.error = false; - - if (response.statusCode) { - status.statusCode = response.statusCode; - } - - return response.content.toJSON(); - }) - .then((response) => { - const resp = response; - - if (this._config.logVerbosity) { - log(url, params, resp); - } - - callback(status, resp); - }) - .catch((e) => { - status.error = true; - status.errorData = e; - status.category = this._detectErrorCategory(e); - callback(status, null); - }); -} - -export function get(params, endpoint, callback) { - const url = this.getStandardOrigin() + endpoint.url; - return xdr.call(this, 'GET', url, params, '', endpoint, callback); -} - -export function post(params, body, endpoint, callback) { - const url = this.getStandardOrigin() + endpoint.url; - return xdr.call(this, 'POST', url, params, body, endpoint, callback); -} - -export function patch(params, body, endpoint, callback) { - const url = this.getStandardOrigin() + endpoint.url; - return xdr.call(this, 'PATCH', url, params, body, endpoint, callback); -} - -export function del(params, endpoint, callback) { - const url = this.getStandardOrigin() + endpoint.url; - return xdr.call(this, 'DELETE', url, params, '', endpoint, callback); -} diff --git a/src/networking/modules/node.js b/src/networking/modules/node.js deleted file mode 100644 index b5d272044..000000000 --- a/src/networking/modules/node.js +++ /dev/null @@ -1,27 +0,0 @@ -import superagent from 'superagent'; -import AgentKeepAlive from 'agentkeepalive'; -import superagentProxy from '../proxyAgent'; - -let keepAliveAgent = null; -let keepAliveSecureAgent = null; - -superagentProxy(superagent); - -export function proxy(superagentConstruct) { - return superagentConstruct.proxy(this._config.proxy); -} - -export function keepAlive(superagentConstruct) { - let agent = this._config.secure ? keepAliveSecureAgent : keepAliveAgent; - if (agent === null) { - const AgentClass = this._config.secure ? AgentKeepAlive.HttpsAgent : AgentKeepAlive; - agent = new AgentClass(this._config.keepAliveSettings); - if (this._config.secure) { - keepAliveSecureAgent = agent; - } else { - keepAliveAgent = agent; - } - } - - return superagentConstruct.agent(agent); -} diff --git a/src/networking/modules/react_native.js b/src/networking/modules/react_native.js deleted file mode 100644 index 40cd28f83..000000000 --- a/src/networking/modules/react_native.js +++ /dev/null @@ -1,119 +0,0 @@ -/* */ -/* global FormData */ -/* global fetch */ - -import { EndpointDefinition, StatusAnnouncement } from '../../core/flow_interfaces'; -import { postfile as postfilewebnode } from './web-node'; - -async function postfileuri(url, fields, fileInput) { - const formData = new FormData(); - - fields.forEach(({ key, value }) => { - formData.append(key, value); - }); - - formData.append('file', fileInput); - - const result = await fetch(url, { - method: 'POST', - body: formData, - }); - - return result; -} - -export async function postfile(url, fields, fileInput) { - if (!fileInput.uri) { - return postfilewebnode(url, fields, fileInput); - } - return postfileuri(url, fields, fileInput); -} - -export function getfile(params, endpoint, callback) { - let url = this.getStandardOrigin() + endpoint.url; - - if (params && Object.keys(params).length > 0) { - const searchParams = new URLSearchParams(params); - - if (endpoint.url.indexOf('?') > -1) { - url += '&'; - } else { - url += '?'; - } - - url += searchParams.toString(); - } - - const fetchResult = fetch(url, { method: 'GET', headers: endpoint.headers }); - - fetchResult.then(async (resp) => { - let parsedResponse; - const status = {}; - status.error = false; - status.operation = endpoint.operation; - - if (resp && resp.status) { - status.statusCode = resp.status; - } - - if (endpoint.ignoreBody) { - parsedResponse = { - headers: resp.headers, - redirects: [], - response: resp, - }; - } else { - try { - parsedResponse = JSON.parse(await resp.text()); - } catch (e) { - status.errorData = resp; - status.error = true; - return callback(status, null); - } - } - - if ( - parsedResponse.error && - parsedResponse.error === 1 && - parsedResponse.status && - parsedResponse.message && - parsedResponse.service - ) { - status.errorData = parsedResponse; - status.statusCode = parsedResponse.status; - status.error = true; - status.category = this._detectErrorCategory(status); - return callback(status, null); - } - if (parsedResponse.error && parsedResponse.error.message) { - status.errorData = parsedResponse.error; - } - - // returning the entire response in order to use response methods for - // reading the body in react native because the response.body - // is a ReadableStream which doesn't seem to be reliable on ios and android - return callback(status, { response: { body: resp } }); - }); - - fetchResult.catch((err) => { - const status = {}; - status.error = true; - status.operation = endpoint.operation; - - if (err.response && err.response.text && !this._config.logVerbosity) { - try { - status.errorData = JSON.parse(err.response.text); - } catch (e) { - status.errorData = err; - } - } else { - status.errorData = err; - } - - status.category = this._detectErrorCategory(err); - - return callback(status, null); - }); - - return fetchResult; -} diff --git a/src/networking/modules/titanium.js b/src/networking/modules/titanium.js deleted file mode 100644 index af496373d..000000000 --- a/src/networking/modules/titanium.js +++ /dev/null @@ -1,107 +0,0 @@ -/* */ -/* global XMLHttpRequest, Ti */ - -import { buildUrl } from '../utils'; - -function log(url, qs, res) { - const _pickLogger = () => { - if (Ti && Ti.API && Ti.API.log) return Ti.API; - return console; - }; - - const start = new Date().getTime(); - const timestamp = new Date().toISOString(); - const logger = _pickLogger(); - logger.log('<<<<<'); // eslint-disable-line no-console - logger.log(`[${timestamp}]`, '\n', url, '\n', qs); // eslint-disable-line no-console - logger.log('-----'); // eslint-disable-line no-console - - const now = new Date().getTime(); - const elapsed = now - start; - const timestampDone = new Date().toISOString(); - - logger.log('>>>>>>'); // eslint-disable-line no-console - logger.log(`[${timestampDone} / ${elapsed}]`, '\n', url, '\n', qs, '\n', res); // eslint-disable-line no-console - logger.log('-----'); -} - -function getHttpClient() { - if (Ti.Platform.osname === 'mobileweb') { - return new XMLHttpRequest(); - } - return Ti.Network.createHTTPClient(); -} - -function keepAlive(xhr) { - if (Ti.Platform.osname !== 'mobileweb' && this._config.keepAlive) { - xhr.enableKeepAlive = true; - } -} - -function xdr(xhr, method, url, params, body, endpoint, callback) { - const status = {}; - status.operation = endpoint.operation; - - xhr.open(method, buildUrl(url, params), true); - - keepAlive.call(this, xhr); - - xhr.onload = () => { - status.error = false; - - if (xhr.status) { - status.statusCode = xhr.status; - } - - const resp = JSON.parse(xhr.responseText); - - if (this._config.logVerbosity) { - log(url, params, xhr.responseText); - } - - return callback(status, resp); - }; - - xhr.onerror = (e) => { - status.error = true; - status.errorData = e.error; - status.category = this._detectErrorCategory(e.error); - return callback(status, null); - }; - - xhr.timeout = Ti.Platform.osname === 'android' ? 2147483647 : Infinity; - - xhr.send(body); -} - -export function get(params, endpoint, callback) { - const xhr = getHttpClient(); - - const url = this.getStandardOrigin() + endpoint.url; - - return xdr.call(this, xhr, 'GET', url, params, {}, endpoint, callback); -} - -export function post(params, body, endpoint, callback) { - const xhr = getHttpClient(); - - const url = this.getStandardOrigin() + endpoint.url; - - return xdr.call(this, xhr, 'POST', url, params, JSON.parse(body), endpoint, callback); -} - -export function patch(params, body, endpoint, callback) { - const xhr = getHttpClient(); - - const url = this.getStandardOrigin() + endpoint.url; - - return xdr.call(this, xhr, 'PATCH', url, params, JSON.parse(body), endpoint, callback); -} - -export function del(params, endpoint, callback) { - const xhr = getHttpClient(); - - const url = this.getStandardOrigin() + endpoint.url; - - return xdr.call(this, xhr, 'DELETE', url, params, {}, endpoint, callback); -} diff --git a/src/networking/modules/web-node.js b/src/networking/modules/web-node.js deleted file mode 100644 index ce80930a1..000000000 --- a/src/networking/modules/web-node.js +++ /dev/null @@ -1,196 +0,0 @@ -/* */ -/* global window */ - -import superagent from 'superagent'; -import categories from '../../core/constants/categories'; - -function log(req) { - const _pickLogger = () => { - if (console && console.log) return console; // eslint-disable-line no-console - if (window && window.console && window.console.log) return window.console; - return console; - }; - - const start = new Date().getTime(); - const timestamp = new Date().toISOString(); - const logger = _pickLogger(); - logger.log('<<<<<'); - logger.log(`[${timestamp}]`, '\n', req.url, '\n', req.qs); - logger.log('-----'); - - req.on('response', (res) => { - const now = new Date().getTime(); - const elapsed = now - start; - const timestampDone = new Date().toISOString(); - - logger.log('>>>>>>'); - - logger.log(`[${timestampDone} / ${elapsed}]`, '\n', req.url, '\n', req.qs, '\n', res.text); - logger.log('-----'); - }); -} - -function xdr(superagentConstruct, endpoint, callback) { - if (this._config.logVerbosity) { - superagentConstruct = superagentConstruct.use(log); - } - - if (this._config.proxy && this._modules.proxy) { - superagentConstruct = this._modules.proxy.call(this, superagentConstruct); - } - - if (this._config.keepAlive && this._modules.keepAlive) { - superagentConstruct = this._modules.keepAlive(superagentConstruct); - } - - let sc = superagentConstruct; - - if (endpoint.abortSignal) { - const unsubscribe = endpoint.abortSignal.subscribe(() => { - sc.abort(); - unsubscribe(); - }); - } - - if (endpoint.forceBuffered === true) { - if (typeof Blob === 'undefined') { - sc = sc.buffer().responseType('arraybuffer'); - } else { - sc = sc.responseType('arraybuffer'); - } - } else if (endpoint.forceBuffered === false) { - sc = sc.buffer(false); - } - - sc = sc.timeout(endpoint.timeout); - - sc.on('abort', () => { - return callback( - { - category: categories.PNUnknownCategory, - error: true, - operation: endpoint.operation, - errorData: new Error('Aborted'), - }, - null, - ); - }); - - sc.end((err, resp) => { - let parsedResponse; - const status = {}; - status.error = err !== null; - status.operation = endpoint.operation; - - if (resp && resp.status) { - status.statusCode = resp.status; - } - - if (err) { - if (err.response && err.response.text && !this._config.logVerbosity) { - try { - status.errorData = JSON.parse(err.response.text); - } catch (e) { - status.errorData = err; - } - } else { - status.errorData = err; - } - status.category = this._detectErrorCategory(err); - return callback(status, null); - } - - if (endpoint.ignoreBody) { - parsedResponse = { - headers: resp.headers, - redirects: resp.redirects, - response: resp, - }; - } else { - try { - parsedResponse = JSON.parse(resp.text); - } catch (e) { - status.errorData = resp; - status.error = true; - return callback(status, null); - } - } - - if ( - parsedResponse.error && - parsedResponse.error === 1 && - parsedResponse.status && - parsedResponse.message && - parsedResponse.service - ) { - status.errorData = parsedResponse; - status.statusCode = parsedResponse.status; - status.error = true; - status.category = this._detectErrorCategory(status); - return callback(status, null); - } - if (parsedResponse.error && parsedResponse.error.message) { - status.errorData = parsedResponse.error; - } - - return callback(status, parsedResponse); - }); - - return sc; -} - -export async function postfile(url, fields, fileInput) { - let agent = superagent.post(url); - - fields.forEach(({ key, value }) => { - agent = agent.field(key, value); - }); - - agent.attach('file', fileInput, { contentType: 'application/octet-stream' }); - - const result = await agent; - - return result; -} - -export function getfile(params, endpoint, callback) { - const superagentConstruct = superagent - .get(this.getStandardOrigin() + endpoint.url) - .set(endpoint.headers) - .query(params); - return xdr.call(this, superagentConstruct, endpoint, callback); -} - -export function get(params, endpoint, callback) { - const superagentConstruct = superagent - .get(this.getStandardOrigin() + endpoint.url) - .set(endpoint.headers) - .query(params); - return xdr.call(this, superagentConstruct, endpoint, callback); -} - -export function post(params, body, endpoint, callback) { - const superagentConstruct = superagent - .post(this.getStandardOrigin() + endpoint.url) - .query(params) - .set(endpoint.headers) - .send(body); - return xdr.call(this, superagentConstruct, endpoint, callback); -} - -export function patch(params, body, endpoint, callback) { - const superagentConstruct = superagent - .patch(this.getStandardOrigin() + endpoint.url) - .query(params) - .set(endpoint.headers) - .send(body); - return xdr.call(this, superagentConstruct, endpoint, callback); -} - -export function del(params, endpoint, callback) { - const superagentConstruct = superagent - .delete(this.getStandardOrigin() + endpoint.url) - .set(endpoint.headers) - .query(params); - return xdr.call(this, superagentConstruct, endpoint, callback); -} diff --git a/src/networking/proxyAgent.js b/src/networking/proxyAgent.js deleted file mode 100644 index ebee260ea..000000000 --- a/src/networking/proxyAgent.js +++ /dev/null @@ -1,15 +0,0 @@ -import { ProxyAgent } from 'proxy-agent'; - -export default function (superagent) { - var Request = superagent.Request; - Request.prototype.proxy = proxy; - return superagent; -} - -function proxy(proxyConfiguration) { - var agent = new ProxyAgent(proxyConfiguration); - - if (agent) this.agent(agent); - - return this; -} diff --git a/src/networking/utils.js b/src/networking/utils.js deleted file mode 100644 index 0d1733599..000000000 --- a/src/networking/utils.js +++ /dev/null @@ -1,29 +0,0 @@ -/* */ - -export function encodedKeyValuePair(pairs, key, value) { - if (value != null) { - if (Array.isArray(value)) { - value.forEach((item) => { - encodedKeyValuePair(pairs, key, item); - }); - } else if (typeof value === 'object') { - Object.keys(value).forEach((subkey) => { - encodedKeyValuePair(pairs, `${key}[${subkey}]`, value[subkey]); - }); - } else { - pairs.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`); - } - } else if (value === null) { - pairs.push(encodeURIComponent(`${encodeURIComponent(key)}`)); - } -} - -export function buildUrl(url, params) { - const pairs = []; - - Object.keys(params).forEach((key) => { - encodedKeyValuePair(pairs, key, params[key]); - }); - - return `${url}?${pairs.join('&')}`; -} diff --git a/src/node/configuration.ts b/src/node/configuration.ts new file mode 100644 index 000000000..a3c5d2b99 --- /dev/null +++ b/src/node/configuration.ts @@ -0,0 +1,94 @@ +/** + * Node.js specific {@link PubNub} client configuration module. + */ + +import { + UserConfiguration, + ExtendedConfiguration, + setDefaults as setBaseDefaults, +} from '../core/interfaces/configuration'; +import { CryptoModule } from '../crypto/modules/NodeCryptoModule/nodeCryptoModule'; +import { TransportKeepAlive } from '../core/interfaces/transport'; +import { Payload } from '../core/types/api'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- + +// region Defaults +/** + * Whether PubNub client should try utilize existing TCP connection for new requests or not. + */ +const KEEP_ALIVE = false; +// endregion + +/** + * NodeJS platform PubNub client configuration. + */ +export type PubNubConfiguration = UserConfiguration & { + /** + * Set a custom parameters for setting your connection `keepAlive` if this is set to `true`. + */ + keepAliveSettings?: TransportKeepAlive; + + /** + * The cryptography module used for encryption and decryption of messages and files. Takes the + * {@link cipherKey} and {@link useRandomIVs} parameters as arguments. + * + * For more information, refer to the + * {@link /docs/sdks/javascript/api-reference/configuration#cryptomodule|cryptoModule} section. + * + * @default `not set` + */ + cryptoModule?: CryptoModule; + + // region Deprecated parameters + /** + * If passed, will encrypt the payloads. + * + * @deprecated Pass it to {@link cryptoModule} instead. + */ + cipherKey?: string; + + /** + * When `true` the initialization vector (IV) is random for all requests (not just for file + * upload). + * When `false` the IV is hard-coded for all requests except for file upload. + * + * @default `true` + * + * @deprecated Pass it to {@link cryptoModule} instead. + */ + useRandomIVs?: boolean; + + /** + * Custom data encryption method. + * + * @deprecated Instead use {@link cryptoModule} for data encryption. + */ + customEncrypt?: (data: string | Payload) => string; + + /** + * Custom data decryption method. + * + * @deprecated Instead use {@link cryptoModule} for data decryption. + */ + customDecrypt?: (data: string) => string; + // endregion +}; + +/** + * Apply configuration default values. + * + * @param configuration - User-provided configuration. + * + * @returns Extended {@link PubNub} client configuration object pre-filled with default values. + */ +export const setDefaults = (configuration: PubNubConfiguration): PubNubConfiguration & ExtendedConfiguration => { + return { + // Set base configuration defaults. + ...setBaseDefaults(configuration), + // Set platform-specific options. + keepAlive: configuration.keepAlive ?? KEEP_ALIVE, + }; +}; diff --git a/src/node/index.ts b/src/node/index.ts index c95b77ae3..a3ac1273b 100755 --- a/src/node/index.ts +++ b/src/node/index.ts @@ -1,48 +1,107 @@ +import { ProxyAgentOptions } from 'proxy-agent'; import CborReader from 'cbor-sync'; -import PubNubCore from '../core/pubnub-common'; -import Networking from '../networking'; -import Cbor from '../cbor/common'; -import { decode } from '../core/components/base64_codec'; -import { del, get, patch, post, getfile, postfile } from '../networking/modules/web-node'; -import { keepAlive, proxy } from '../networking/modules/node'; +import { Readable } from 'stream'; +import { Buffer } from 'buffer'; -import NodeCryptography from '../crypto/modules/node'; -import PubNubFile from '../file/modules/node'; import { CryptoModule, LegacyCryptor, AesCbcCryptor } from '../crypto/modules/NodeCryptoModule/nodeCryptoModule'; +import PubNubFile, { PubNubFileParameters } from '../file/modules/node'; +import { CryptorConfiguration } from '../core/interfaces/crypto-module'; +import { makeConfiguration } from '../core/components/configuration'; +import { PubNubConfiguration, setDefaults } from './configuration'; +import { TokenManager } from '../core/components/token_manager'; +import { NodeTransport } from '../transport/node-transport'; +import { PubNubMiddleware } from '../transport/middleware'; +import { PubNubFileConstructor } from '../core/types/file'; +import { decode } from '../core/components/base64_codec'; +import NodeCryptography from '../crypto/modules/node'; +import Crypto from '../core/components/cryptography'; +import { PubNubError } from '../errors/pubnub-error'; +import { PubNubCore } from '../core/pubnub-common'; +import Cbor from '../cbor/common'; -export = class extends PubNubCore { +/** + * PubNub client for Node.js platform. + */ +export = class PubNub extends PubNubCore { + /** + * Data encryption / decryption module constructor. + */ static CryptoModule = CryptoModule; - constructor(setup: any) { - setup.cbor = new Cbor((buffer: ArrayBuffer) => CborReader.decode(Buffer.from(buffer)), decode); - setup.networking = new Networking({ - keepAlive, - del, - get, - post, - patch, - proxy, - getfile, - postfile, + + /** + * PubNub File constructor. + */ + public File: PubNubFileConstructor = PubNubFile; + + /** + * Actual underlying transport provider. + */ + private nodeTransport: NodeTransport; + + constructor(configuration: PubNubConfiguration) { + const configurationCopy = setDefaults(configuration); + const platformConfiguration = { ...configurationCopy, sdkFamily: 'Nodejs', PubNubFile }; + + // Prepare full client configuration. + const clientConfiguration = makeConfiguration( + platformConfiguration, + (cryptoConfiguration: CryptorConfiguration) => { + if (!cryptoConfiguration.cipherKey) return undefined; + + return new CryptoModule({ + default: new LegacyCryptor({ ...cryptoConfiguration }), + cryptors: [new AesCbcCryptor({ cipherKey: cryptoConfiguration.cipherKey })], + }); + }, + ); + + // Prepare Token manager. + const tokenManager = new TokenManager( + new Cbor((buffer: ArrayBuffer) => CborReader.decode(Buffer.from(buffer)), decode), + ); + + // Legacy crypto (legacy data encryption / decryption and request signature support). + const crypto = new Crypto({ + secretKey: clientConfiguration.secretKey, + cipherKey: clientConfiguration.getCipherKey(), + useRandomIVs: clientConfiguration.getUseRandomIVs(), + customEncrypt: clientConfiguration.getCustomEncrypt(), + customDecrypt: clientConfiguration.getCustomDecrypt(), + }); + + // Setup transport provider. + const transport = new NodeTransport(configuration.keepAlive, configuration.keepAliveSettings); + const transportMiddleware = new PubNubMiddleware({ + clientConfiguration, + tokenManager, + transport, + shaHMAC: crypto?.HMACSHA256.bind(crypto), + }); + + super({ + configuration: clientConfiguration, + transport: transportMiddleware, + cryptography: new NodeCryptography(), + tokenManager, + crypto, }); - setup.sdkFamily = 'Nodejs'; - - setup.PubNubFile = PubNubFile; - setup.cryptography = new NodeCryptography(); - - setup.initCryptoModule = (cryptoConfiguration: any) => { - return new CryptoModule({ - default: new LegacyCryptor({ - cipherKey: cryptoConfiguration.cipherKey, - useRandomIVs: cryptoConfiguration.useRandomIVs, - }), - cryptors: [new AesCbcCryptor({ cipherKey: cryptoConfiguration.cipherKey })], - }); - }; - - if (!('ssl' in setup)) { - setup.ssl = true; - } - - super(setup); + + this.nodeTransport = transport; + } + + /** + * Update request proxy configuration. + * + * @param configuration - Updated request proxy configuration. + * + * @throws An error if {@link PubNub} client already configured to use `keepAlive`. + * `keepAlive` and `proxy` can't be used simultaneously. + */ + public setProxy(configuration?: ProxyAgentOptions) { + if (configuration && (this._configuration.keepAlive ?? false)) + throw new PubNubError("Can't set 'proxy' because already configured for 'keepAlive'"); + + this.nodeTransport.setProxy(configuration); + this.reconnect(); } }; diff --git a/src/react_native/configuration.ts b/src/react_native/configuration.ts new file mode 100644 index 000000000..1cbfae42f --- /dev/null +++ b/src/react_native/configuration.ts @@ -0,0 +1,19 @@ +import { + setDefaults as setBaseDefaults, + ExtendedConfiguration, + UserConfiguration, +} from '../core/interfaces/configuration'; + +/** + * React Native platform PubNub client configuration. + */ +export type PubNubConfiguration = UserConfiguration; + +/** + * Apply configuration default values. + * + * @param configuration - User-provided configuration. + */ +export const setDefaults = (configuration: PubNubConfiguration): PubNubConfiguration & ExtendedConfiguration => { + return setBaseDefaults(configuration); +}; diff --git a/src/react_native/index.js b/src/react_native/index.js deleted file mode 100644 index 921477ec3..000000000 --- a/src/react_native/index.js +++ /dev/null @@ -1,35 +0,0 @@ -import CborReader from 'cbor-js'; -import { Buffer } from 'buffer'; -import PubNubCore from '../core/pubnub-common'; -import Networking from '../networking'; -import { decode } from '../core/components/base64_codec'; -import { stringifyBufferKeys } from '../core/components/stringify_buffer_keys'; -import Cbor from '../cbor/common'; -import { del, get, post, patch } from '../networking/modules/web-node'; -import { getfile, postfile } from '../networking/modules/react_native'; - -import PubNubFile from '../file/modules/react-native'; -import { stringifyBufferKeys } from '../web'; - -global.Buffer = global.Buffer || Buffer; - -export default class extends PubNubCore { - constructor(setup) { - setup.cbor = new Cbor((arrayBuffer) => stringifyBufferKeys(CborReader.decode(arrayBuffer)), decode); - - setup.PubNubFile = PubNubFile; - - setup.networking = new Networking({ - del, - get, - post, - patch, - getfile, - postfile, - }); - setup.sdkFamily = 'ReactNative'; - setup.ssl = true; - - super(setup); - } -} diff --git a/src/react_native/index.ts b/src/react_native/index.ts new file mode 100644 index 000000000..07bd18331 --- /dev/null +++ b/src/react_native/index.ts @@ -0,0 +1,67 @@ +import { TextEncoder, TextDecoder } from 'text-encoding'; +import 'react-native-url-polyfill/auto'; +import CborReader from 'cbor-js'; +import { Buffer } from 'buffer'; + +import { WebReactNativeTransport } from '../transport/web-react-native-transport'; +import { stringifyBufferKeys } from '../core/components/stringify_buffer_keys'; +import { makeConfiguration } from '../core/components/configuration'; +import { PubNubFileParameters } from '../file/modules/react-native'; +import { TokenManager } from '../core/components/token_manager'; +import { PubNubMiddleware } from '../transport/middleware'; +import { decode } from '../core/components/base64_codec'; +import PubNubFile from '../file/modules/react-native'; +import { PubNubConfiguration } from './configuration'; +import Crypto from '../core/components/cryptography'; +import { PubNubCore } from '../core/pubnub-common'; +import { setDefaults } from './configuration'; +import Cbor from '../cbor/common'; + +// Polyfill global environment +global.TextEncoder = global.TextEncoder || TextEncoder; +global.TextDecoder = global.TextDecoder || TextDecoder; +global.Buffer = global.Buffer || Buffer; + +/** + * PubNub client for React Native platform. + */ +export default class PubNub extends PubNubCore { + constructor(configuration: PubNubConfiguration) { + const configurationCopy = setDefaults(configuration); + const platformConfiguration = { ...configurationCopy, sdkFamily: 'ReactNative', PubNubFile }; + + // Prepare full client configuration. + const clientConfiguration = makeConfiguration(platformConfiguration); + + // Prepare Token manager. + const tokenManager = new TokenManager( + new Cbor((arrayBuffer: ArrayBuffer) => stringifyBufferKeys(CborReader.decode(arrayBuffer)), decode), + ); + + // Legacy crypto (legacy data encryption / decryption and request signature support). + let crypto: Crypto | undefined; + if (clientConfiguration.getCipherKey() || clientConfiguration.secretKey) { + crypto = new Crypto({ + secretKey: clientConfiguration.secretKey, + cipherKey: clientConfiguration.getCipherKey(), + useRandomIVs: clientConfiguration.getUseRandomIVs(), + customEncrypt: clientConfiguration.getCustomEncrypt(), + customDecrypt: clientConfiguration.getCustomDecrypt(), + }); + } + + // Setup transport layer. + const transportMiddleware = new PubNubMiddleware({ + clientConfiguration, + tokenManager, + transport: new WebReactNativeTransport(clientConfiguration.keepAlive, clientConfiguration.logVerbosity!), + }); + + super({ + configuration: clientConfiguration, + transport: transportMiddleware, + tokenManager, + crypto, + }); + } +} diff --git a/src/titanium/configuration.ts b/src/titanium/configuration.ts new file mode 100644 index 000000000..4cf016114 --- /dev/null +++ b/src/titanium/configuration.ts @@ -0,0 +1,43 @@ +import { + setDefaults as setBaseDefaults, + ExtendedConfiguration, + UserConfiguration, +} from '../core/interfaces/configuration'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Whether PubNub client should try to utilize existing TCP connection for new requests or not. + */ +const KEEP_ALIVE = true; +// endregion + +/** + * Titanium platform PubNub client configuration. + */ +export type PubNubConfiguration = UserConfiguration & { + /** + * If set to `true`, SDK will use the same TCP connection for each HTTP request, instead of + * opening a new one for each new request. + * + * @default `true` + */ + keepAlive?: boolean; +}; + +/** + * Apply configuration default values. + * + * @param configuration - User-provided configuration. + */ +export const setDefaults = (configuration: PubNubConfiguration): PubNubConfiguration & ExtendedConfiguration => { + return { + // Set base configuration defaults. + ...setBaseDefaults(configuration), + // Set platform-specific options. + keepAlive: configuration.keepAlive ?? KEEP_ALIVE, + }; +}; diff --git a/src/titanium/index.js b/src/titanium/index.js deleted file mode 100644 index 88c350f96..000000000 --- a/src/titanium/index.js +++ /dev/null @@ -1,22 +0,0 @@ -import CborReader from 'cbor-sync'; -import PubNubCore from '../core/pubnub-common'; -import Networking from '../networking'; -import Cbor from '../cbor/common'; -import { del, get, post, patch } from '../networking/modules/titanium'; - -class PubNub extends PubNubCore { - constructor(setup) { - setup.cbor = new Cbor(CborReader.decode, (base64String) => Buffer.from(base64String, 'base64')); - setup.sdkFamily = 'TitaniumSDK'; - setup.networking = new Networking({ - del, - get, - post, - patch, - }); - - super(setup); - } -} - -export { PubNub as default }; diff --git a/src/titanium/index.ts b/src/titanium/index.ts new file mode 100644 index 000000000..36b890d91 --- /dev/null +++ b/src/titanium/index.ts @@ -0,0 +1,42 @@ +import CborReader from 'cbor-sync'; + +import { makeConfiguration } from '../core/components/configuration'; +import { TitaniumTransport } from '../transport/titanium-transport'; +import { PubNubConfiguration, setDefaults } from './configuration'; +import { TokenManager } from '../core/components/token_manager'; +import { PubNubMiddleware } from '../transport/middleware'; +import { PubNubCore } from '../core/pubnub-common'; +import Cbor from '../cbor/common'; + +/** + * PubNub client for Titanium. + */ +export class PubNub extends PubNubCore { + constructor(configuration: PubNubConfiguration) { + const configurationCopy = setDefaults(configuration); + const platformConfiguration = { ...configurationCopy, sdkFamily: 'TitaniumSDK' }; + + // Prepare full client configuration. + const clientConfiguration = makeConfiguration(platformConfiguration); + + // Prepare Token manager. + const tokenManager = new TokenManager( + new Cbor(CborReader.decode, (base64String: string) => Buffer.from(base64String, 'base64')), + ); + + // Setup transport layer. + const transportMiddleware = new PubNubMiddleware({ + clientConfiguration, + tokenManager, + transport: new TitaniumTransport(clientConfiguration.keepAlive, clientConfiguration.logVerbosity), + }); + + super({ + configuration: clientConfiguration, + transport: transportMiddleware, + tokenManager, + }); + } +} + +export { PubNub as default }; diff --git a/src/transport/middleware.ts b/src/transport/middleware.ts new file mode 100644 index 000000000..dacbd336f --- /dev/null +++ b/src/transport/middleware.ts @@ -0,0 +1,177 @@ +import { TransportMethod, TransportRequest } from '../core/types/transport-request'; +import { PrivateClientConfiguration } from '../core/interfaces/configuration'; +import { TokenManager } from '../core/components/token_manager'; +import { Transport } from '../core/interfaces/transport'; +import { encodeString } from '../core/utils'; +import { Query } from '../core/types/api'; + +/** + * Transport middleware configuration options. + */ +type PubNubMiddlewareConfiguration = { + /** + * Private client configuration. + */ + clientConfiguration: PrivateClientConfiguration; + + /** + * REST API endpoints access tokens manager. + */ + tokenManager: TokenManager; + + /** + * HMAC-SHA256 hash generator from provided `data`. + */ + shaHMAC?: (data: string) => string; + + /** + * Platform-specific transport for requests processing. + */ + transport: Transport; +}; + +export class RequestSignature { + private static textDecoder = new TextDecoder('utf-8'); + constructor( + private publishKey: string, + private secretKey: string, + private hasher: (input: string, secret: string) => string, + ) {} + + /** + * Compute request signature. + * + * @param req - Request which will be used to compute signature. + * @returns {string} `v2` request signature. + */ + public signature(req: TransportRequest): string { + const method = req.path.startsWith('/publish') ? TransportMethod.GET : req.method; + + let signatureInput = `${method}\n${this.publishKey}\n${req.path}\n${this.queryParameters(req.queryParameters!)}\n`; + if (method === TransportMethod.POST || method === TransportMethod.PATCH) { + const body = req.body; + let payload: string | undefined; + + if (body && body instanceof ArrayBuffer) { + payload = RequestSignature.textDecoder.decode(body); + } else if (body && typeof body !== 'object') { + payload = body; + } + + if (payload) signatureInput += payload; + } + + return `v2.${this.hasher(signatureInput, this.secretKey)}` + .replace(/\+/g, '-') + .replace(/\//g, '_') + .replace(/=+$/, ''); + } + + /** + * Prepare request query parameters for signature. + * + * @param query - Key / value pair of the request query parameters. + * @private + */ + private queryParameters(query: Query) { + return Object.keys(query) + .sort() + .map((key) => { + const queryValue = query[key]; + if (!Array.isArray(queryValue)) return `${key}=${encodeString(queryValue)}`; + + return queryValue + .sort() + .map((value) => `${key}=${encodeString(value)}`) + .join('&'); + }) + .join('&'); + } +} + +export class PubNubMiddleware implements Transport { + /** + * Request signature generator. + */ + signatureGenerator?: RequestSignature; + + constructor(private configuration: PubNubMiddlewareConfiguration) { + const { + clientConfiguration: { keySet }, + shaHMAC, + } = configuration; + + if (keySet.secretKey && shaHMAC) + this.signatureGenerator = new RequestSignature(keySet.publishKey!, keySet.secretKey, shaHMAC); + } + + makeSendable(req: TransportRequest) { + return this.configuration.transport.makeSendable(this.request(req)); + } + + request(req: TransportRequest): TransportRequest { + const { clientConfiguration } = this.configuration; + + // Get request patched by transport provider. + req = this.configuration.transport.request(req); + if (!req.queryParameters) req.queryParameters = {}; + + // Modify request with required information. + if (clientConfiguration.useInstanceId) req.queryParameters['instanceid'] = clientConfiguration.instanceId!; + if (!req.queryParameters['uuid']) req.queryParameters['uuid'] = clientConfiguration.userId!; + if (clientConfiguration.useRequestId) req.queryParameters['requestid'] = req.identifier; + req.queryParameters['pnsdk'] = this.generatePNSDK(); + req.origin ??= clientConfiguration.origin as string; + + // Authenticate request if required. + this.authenticateRequest(req); + + // Sign request if it is required. + this.signRequest(req); + + return req; + } + + private authenticateRequest(req: TransportRequest) { + // Access management endpoints doesn't need authentication (signature required instead). + if (req.path.startsWith('/v2/auth/') || req.path.startsWith('/v3/pam/') || req.path.startsWith('/time')) return; + + const { clientConfiguration, tokenManager } = this.configuration; + const accessKey = tokenManager.getToken() ?? clientConfiguration.authKey; + if (accessKey) req.queryParameters!['auth'] = accessKey; + } + + /** + * Compute and append request signature. + * + * @param req - Transport request with information which should be used to generate signature. + */ + private signRequest(req: TransportRequest) { + if (!this.signatureGenerator || req.path.startsWith('/time')) return; + + req.queryParameters!['timestamp'] = String(Math.floor(new Date().getTime() / 1000)); + req.queryParameters!['signature'] = this.signatureGenerator.signature(req); + } + + /** + * Compose `pnsdk` query parameter. + * + * SDK provides ability to set custom name or append vendor information to the `pnsdk` query + * parameter. + * + * @returns Finalized `pnsdk` query parameter value. + */ + private generatePNSDK() { + const { clientConfiguration } = this.configuration; + if (clientConfiguration.sdkName) return clientConfiguration.sdkName; + + let base = `PubNub-JS-${clientConfiguration.sdkFamily}`; + if (clientConfiguration.partnerId) base += `-${clientConfiguration.partnerId}`; + base += `/${clientConfiguration.getVersion()}`; + + const pnsdkSuffix = clientConfiguration._getPnsdkSuffix(' '); + if (pnsdkSuffix.length > 0) base += pnsdkSuffix; + + return base; + } +} diff --git a/src/transport/node-transport.ts b/src/transport/node-transport.ts new file mode 100644 index 000000000..ed6de5a44 --- /dev/null +++ b/src/transport/node-transport.ts @@ -0,0 +1,218 @@ +import fetch, { Request, Response, RequestInit } from 'node-fetch'; +import { ProxyAgent, ProxyAgentOptions } from 'proxy-agent'; +import { Agent as HttpsAgent } from 'https'; +import { Agent as HttpAgent } from 'http'; +import FormData from 'form-data'; +import { Buffer } from 'buffer'; + +import { CancellationController, TransportRequest } from '../core/types/transport-request'; +import { Transport, TransportKeepAlive } from '../core/interfaces/transport'; +import { TransportResponse } from '../core/types/transport-response'; +import { PubNubAPIError } from '../errors/pubnub-api-error'; +import { PubNubFileInterface } from '../core/types/file'; +import { queryStringFromObject } from '../core/utils'; + +/** + * Class representing a fetch-based Node.js transport provider. + */ +export class NodeTransport implements Transport { + /** + * Service {@link ArrayBuffer} response decoder. + */ + protected static decoder = new TextDecoder(); + + /** + * Request proxy configuration. + */ + private proxyConfiguration?: ProxyAgentOptions; + + private proxyAgent?: ProxyAgent; + private httpsAgent?: HttpsAgent; + private httpAgent?: HttpAgent; + + /** + * Creates a new `fetch`-based transport instance. + * + * @param keepAlive - Indicates whether keep-alive should be enabled. + * @param [keepAliveSettings] - Optional settings for keep-alive. + * @param [logVerbosity] - Whether verbose logging enabled or not. + * + * @returns Transport for performing network requests. + */ + constructor( + private readonly keepAlive: boolean = false, + private readonly keepAliveSettings: TransportKeepAlive = { timeout: 30000 }, + private readonly logVerbosity: boolean = false, + ) {} + + /** + * Update request proxy configuration. + * + * @param configuration - New proxy configuration. + */ + public setProxy(configuration?: ProxyAgentOptions) { + this.proxyConfiguration = configuration; + } + + makeSendable(req: TransportRequest): [Promise, CancellationController | undefined] { + let controller: CancellationController | undefined = undefined; + let abortController: AbortController | undefined; + + if (req.cancellable) { + abortController = new AbortController(); + controller = { + // Storing controller inside to prolong object lifetime. + abortController, + abort: () => abortController?.abort(), + } as CancellationController; + } + + return [ + this.requestFromTransportRequest(req).then((request) => { + const start = new Date().getTime(); + + this.logRequestProcessProgress(request); + + return fetch(request, { + signal: abortController?.signal, + timeout: req.timeout * 1000, + } as RequestInit) + .then((response): Promise<[Response, ArrayBuffer]> | [Response, ArrayBuffer] => + response.arrayBuffer().then((arrayBuffer) => [response, arrayBuffer]), + ) + .then((response) => { + const responseBody = response[1].byteLength > 0 ? response[1] : undefined; + const { status, headers: requestHeaders } = response[0]; + const headers: Record = {}; + + // Copy Headers object content into plain Record. + requestHeaders.forEach((value, key) => (headers[key] = value.toLowerCase())); + + const transportResponse: TransportResponse = { + status, + url: request.url, + headers, + body: responseBody, + }; + + if (status >= 400) throw PubNubAPIError.create(transportResponse); + + this.logRequestProcessProgress(request, new Date().getTime() - start, responseBody); + + return transportResponse; + }) + .catch((error) => { + throw PubNubAPIError.create(error); + }); + }), + controller, + ]; + } + + request(req: TransportRequest): TransportRequest { + return req; + } + + /** + * Creates a Request object from a given {@link TransportRequest} object. + * + * @param req - The {@link TransportRequest} object containing request information. + * + * @returns Request object generated from the {@link TransportRequest} object. + */ + private async requestFromTransportRequest(req: TransportRequest): Promise { + let headers: Record | undefined = req.headers; + let body: string | ArrayBuffer | FormData | undefined; + let path = req.path; + + // Create multipart request body. + if (req.formData && req.formData.length > 0) { + // Reset query parameters to conform to signed URL + req.queryParameters = {}; + + const file = req.body as PubNubFileInterface; + const fileData = await file.toArrayBuffer(); + const formData = new FormData(); + for (const { key, value } of req.formData) formData.append(key, value); + + formData.append('file', Buffer.from(fileData), { contentType: 'application/octet-stream', filename: file.name }); + body = formData; + + headers = formData.getHeaders(headers ?? {}); + } + // Handle regular body payload (if passed). + else if (req.body && (typeof req.body === 'string' || req.body instanceof ArrayBuffer)) body = req.body; + + if (req.queryParameters && Object.keys(req.queryParameters).length !== 0) + path = `${path}?${queryStringFromObject(req.queryParameters)}`; + + return new Request(`${req.origin!}${path}`, { + agent: this.agentForTransportRequest(req), + method: req.method, + headers, + redirect: 'follow', + body, + } as RequestInit); + } + + /** + * Determines and returns the appropriate agent for a given transport request. + * + * If keep alive is not requested, returns undefined. + * + * @param req - The transport request object. + * + * @returns {HttpAgent | HttpsAgent | undefined} - The appropriate agent for the request, or + * undefined if keep alive or proxy not requested. + */ + private agentForTransportRequest(req: TransportRequest): HttpAgent | HttpsAgent | undefined { + // Don't configure any agents if keep alive not requested. + if (!this.keepAlive && !this.proxyConfiguration) return undefined; + + // Create proxy agent (if possible). + if (this.proxyConfiguration) + return this.proxyAgent ? this.proxyAgent : (this.proxyAgent = new ProxyAgent(this.proxyConfiguration)); + + // Create keep alive agent. + const useSecureAgent = req.origin!.startsWith('https:'); + + if (useSecureAgent && this.httpsAgent === undefined) + this.httpsAgent = new HttpsAgent({ keepAlive: true, ...this.keepAliveSettings }); + else if (!useSecureAgent && this.httpAgent === undefined) { + this.httpAgent = new HttpAgent({ keepAlive: true, ...this.keepAliveSettings }); + } + + return useSecureAgent ? this.httpsAgent : this.httpAgent; + } + + /** + * Log out request processing progress and result. + * + * @param request - Platform-specific request object. + * @param [elapsed] - How many times passed since request processing started. + * @param [body] - Service response (if available). + */ + protected logRequestProcessProgress(request: Request, elapsed?: number, body?: ArrayBuffer) { + if (!this.logVerbosity) return; + + const { protocol, host, pathname, search } = new URL(request.url); + const timestamp = new Date().toISOString(); + + if (!elapsed) { + console.log('<<<<<'); + console.log(`[${timestamp}]`, `\n${protocol}//${host}${pathname}`, `\n${search}`); + console.log('-----'); + } else { + const stringifiedBody = body ? NodeTransport.decoder.decode(body) : undefined; + + console.log('>>>>>>'); + console.log( + `[${timestamp} / ${elapsed}]`, + `\n${protocol}//${host}${pathname}`, + `\n${search}`, + `\n${stringifiedBody}`, + ); + console.log('-----'); + } + } +} diff --git a/src/transport/service-worker/subscription-service-worker-middleware.ts b/src/transport/service-worker/subscription-service-worker-middleware.ts new file mode 100644 index 000000000..7e03303e1 --- /dev/null +++ b/src/transport/service-worker/subscription-service-worker-middleware.ts @@ -0,0 +1,304 @@ +/** + * Subscription Service Worker transport middleware module. + * + * Middleware optimize subscription feature requests utilizing `Subscription Service Worker` if available and not + * disabled by user. + */ + +import { CancellationController, TransportRequest } from '../../core/types/transport-request'; +import * as PubNubSubscriptionServiceWorker from './subscription-service-worker'; +import { TransportResponse } from '../../core/types/transport-response'; +import { Transport } from '../../core/interfaces/transport'; +import { PubNubAPIError } from '../../errors/pubnub-api-error'; +import StatusCategory from '../../core/constants/categories'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +type PubNubMiddlewareConfiguration = { + /** + * Unique PubNub SDK client identifier. + */ + clientIdentifier: string; + + /** + * Subscribe REST API access key. + */ + subscriptionKey: string; + + /** + * Current PubNub client version. + */ + sdkVersion: string; + + /** + * Whether verbose logging enabled or not. + */ + logVerbosity: boolean; + + /** + * Platform-specific transport for requests processing. + */ + transport: Transport; +}; + +// endregion + +/** + * Subscription Service Worker transport middleware. + */ +export class SubscriptionServiceWorkerMiddleware implements Transport { + /** + * Scheduled requests result handling callback. + */ + callbacks?: Map void; reject: (value: Error) => void }>; + + /** + * Subscription service worker. + * + * **Note:** Web PubNub SDK Transport provider adjustment for explicit subscription feature support. + */ + serviceWorkerRegistration?: ServiceWorkerRegistration; + + /** + * Queue of events for service worker. + * + * Keep list of events which should be sent to the worker after its activation. + */ + serviceWorkerEventsQueue: PubNubSubscriptionServiceWorker.ClientEvent[]; + + constructor(private readonly configuration: PubNubMiddlewareConfiguration) { + this.serviceWorkerEventsQueue = []; + this.callbacks = new Map(); + + this.setupServiceWorker(); + } + + makeSendable(req: TransportRequest): [Promise, CancellationController | undefined] { + // Use default request flow for non-subscribe / presence leave requests. + if (!req.path.startsWith('/v2/subscribe') && !req.path.endsWith('/leave')) + return this.configuration.transport.makeSendable(req); + + let controller: CancellationController | undefined; + const sendRequestEvent: PubNubSubscriptionServiceWorker.SendRequestEvent = { + type: 'send-request', + clientIdentifier: this.configuration.clientIdentifier, + subscriptionKey: this.configuration.subscriptionKey, + logVerbosity: this.configuration.logVerbosity, + request: req, + }; + + if (req.cancellable) { + controller = { + abort: () => { + const cancelRequest: PubNubSubscriptionServiceWorker.CancelRequestEvent = { + type: 'cancel-request', + clientIdentifier: this.configuration.clientIdentifier, + subscriptionKey: this.configuration.subscriptionKey, + logVerbosity: this.configuration.logVerbosity, + identifier: req.identifier, + }; + + // Cancel active request with specified identifier. + this.scheduleEventPost(cancelRequest); + }, + }; + } + + return [ + new Promise((resolve, reject) => { + // Associate Promise resolution / reject with request identifier for future usage in + // `onmessage` handler block to return results. + this.callbacks!.set(req.identifier, { resolve, reject }); + + // Trigger request processing by Service Worker. + this.scheduleEventPost(sendRequestEvent); + }), + controller, + ]; + } + + request(req: TransportRequest): TransportRequest { + return req; + } + + /** + * Schedule {@link event} publish to the service worker. + * + * Service worker may not be ready for events processing and this method build queue for the time when worker will be + * ready. + * + * @param event - Event payload for service worker. + * @param outOfOrder - Whether event should be processed first then enqueued queue. + */ + private scheduleEventPost(event: PubNubSubscriptionServiceWorker.ClientEvent, outOfOrder: boolean = false) { + // Trigger request processing by Web Worker. + const serviceWorker = this.serviceWorker; + if (serviceWorker) serviceWorker.postMessage(event); + else { + if (outOfOrder) this.serviceWorkerEventsQueue.splice(0, 0, event); + else this.serviceWorkerEventsQueue.push(event); + } + } + + /** + * Dequeue and post events from the queue to the service worker. + */ + private flushScheduledEvents(): void { + // Trigger request processing by Web Worker. + const serviceWorker = this.serviceWorker; + if (!serviceWorker || this.serviceWorkerEventsQueue.length === 0) return; + + // Clean up from cancelled events. + const outdatedEvents: PubNubSubscriptionServiceWorker.ClientEvent[] = []; + for (let i = 0; i < this.serviceWorkerEventsQueue.length; i++) { + const event = this.serviceWorkerEventsQueue[i]; + + // Check whether found request cancel event to search for request send event it cancels. + if (event.type !== 'cancel-request' || i === 0) continue; + + for (let j = 0; j < i; j++) { + const otherEvent = this.serviceWorkerEventsQueue[j]; + if (otherEvent.type !== 'send-request') continue; + + // Collect outdated events if identifiers match. + if (otherEvent.request.identifier === event.identifier) { + outdatedEvents.push(event, otherEvent); + break; + } + } + } + + // Actualizing events queue. + this.serviceWorkerEventsQueue = this.serviceWorkerEventsQueue.filter((event) => !outdatedEvents.includes(event)); + this.serviceWorkerEventsQueue.forEach((event) => serviceWorker.postMessage(event)); + this.serviceWorkerEventsQueue = []; + } + + /** + * Subscription service worker. + * + * @returns Service worker which has been registered by the PubNub SDK. + */ + private get serviceWorker() { + return this.serviceWorkerRegistration ? this.serviceWorkerRegistration.active : null; + } + + private setupServiceWorker(): void { + if (!('serviceWorker' in navigator)) return; + const serviceWorkerContainer = navigator.serviceWorker as ServiceWorkerContainer; + serviceWorkerContainer + .register(`SERVICE_WORKER_CDN/SERVICE_WORKER_FILE_PLACEHOLDER`, { + scope: `/pubnub-${this.configuration.sdkVersion}`, + }) + .then((registration) => { + this.serviceWorkerRegistration = registration; + + // Flush any pending service worker events. + if (registration.active) this.flushScheduledEvents(); + + /** + * Listening for service worker code update. + * + * It is possible that one of the tabs will open with newer SDK version and Subscription Service Worker + * will be re-installed - in this case we need to "rehydrate" it. + * + * After re-installation of new service worker it will lose all accumulated state and client need to + * re-introduce itself and its state. + */ + this.serviceWorkerRegistration.addEventListener('updatefound', () => { + if (!this.serviceWorkerRegistration) return; + + // New service installing right now. + const serviceWorker = this.serviceWorkerRegistration.installing!; + + const stateChangeListener = () => { + // Flush any pending service worker events. + if (serviceWorker.state === 'activated') { + // Flush any pending service worker events. + this.flushScheduledEvents(); + } else if (serviceWorker.state === 'redundant') { + // Clean up listener from deprecated service worker version. + serviceWorker.removeEventListener('statechange', stateChangeListener); + } + }; + + serviceWorker.addEventListener('statechange', stateChangeListener); + }); + }); + + serviceWorkerContainer.addEventListener('message', (event) => this.handleServiceWorkerEvent(event)); + } + + private handleServiceWorkerEvent(event: MessageEvent) { + const { data } = event; + + // Ignoring updates not related to this instance. + if (data.clientIdentifier !== this.configuration.clientIdentifier) return; + + if (data.type === 'request-progress-start' || data.type === 'request-progress-end') { + this.logRequestProgress(data); + } else if (data.type === 'request-process-success' || data.type === 'request-process-error') { + const { resolve, reject } = this.callbacks!.get(data.identifier)!; + + if (data.type === 'request-process-success') { + resolve({ + status: data.response.status, + url: data.url, + headers: data.response.headers, + body: data.response.body, + }); + } else { + let category: StatusCategory = StatusCategory.PNUnknownCategory; + let message = 'Unknown error'; + + // Handle client-side issues (if any). + if (data.error) { + if (data.error.type === 'NETWORK_ISSUE') category = StatusCategory.PNNetworkIssuesCategory; + else if (data.error.type === 'TIMEOUT') category = StatusCategory.PNTimeoutCategory; + else if (data.error.type === 'ABORTED') category = StatusCategory.PNCancelledCategory; + message = `${data.error.message} (${data.identifier})`; + } + // Handle service error response. + else if (data.response) { + return reject( + PubNubAPIError.create( + { + url: data.url, + headers: data.response.headers, + body: data.response.body, + status: data.response.status, + }, + data.response.body, + ), + ); + } + + reject(new PubNubAPIError(message, category, 0, new Error(message))); + } + } + } + + /** + * Print request progress information. + * + * @param information - Request progress information from Web Worker. + */ + private logRequestProgress(information: PubNubSubscriptionServiceWorker.RequestSendingProgress) { + if (information.type === 'request-progress-start') { + console.log('<<<<<'); + console.log(`[${information.timestamp}] ${information.url}\n${JSON.stringify(information.query ?? {})}`); + console.log('-----'); + } else { + console.log('>>>>>>'); + console.log( + `[${information.timestamp} / ${information.duration}] ${information.url}\n${JSON.stringify( + information.query ?? {}, + )}\n${information.response}`, + ); + console.log('-----'); + } + } +} diff --git a/src/transport/service-worker/subscription-service-worker.ts b/src/transport/service-worker/subscription-service-worker.ts new file mode 100644 index 000000000..970ded65a --- /dev/null +++ b/src/transport/service-worker/subscription-service-worker.ts @@ -0,0 +1,1390 @@ +/// +/** + * Subscription Service Worker Transport provider. + * + * Service worker provides support for PubNub subscription feature to give better user experience across + * multiple opened pages. + */ + +import { TransportRequest } from '../../core/types/transport-request'; +import uuidGenerator from '../../core/components/uuid'; +import { Payload, Query } from '../../core/types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types +// region Client-side + +/** + * Basic information for client and request group identification. + */ +type BasicEvent = { + /** + * Unique PubNub SDK client identifier for which setup is done. + */ + clientIdentifier: string; + + /** + * Subscribe REST API access key. + */ + subscriptionKey: string; + + /** + * Whether verbose logging enabled or not. + */ + logVerbosity: boolean; +}; + +/** + * Send HTTP request event. + * + * Request from Web Worker to schedule {@link Request} using provided {@link SendRequestSignal#request|request} data. + */ +export type SendRequestEvent = BasicEvent & { + type: 'send-request'; + + /** + * Instruction to construct actual {@link Request}. + */ + request: TransportRequest; +}; + +/** + * Cancel HTTP request event. + */ +export type CancelRequestEvent = BasicEvent & { + type: 'cancel-request'; + + /** + * Identifier of request which should be cancelled. + */ + identifier: string; +}; + +/** + * List of known events from the PubNub Core. + */ +export type ClientEvent = SendRequestEvent | CancelRequestEvent; +// endregion + +// region Service Worker +/** + * {@link Request} processing start event. + * + * This event will be sent if {@link logVerbosity} set to `true` when worker will receive + * {@link SendRequestEvent}. + */ +export type RequestSendingStart = { + type: 'request-progress-start'; + + /** + * Receiving PubNub client unique identifier. + */ + clientIdentifier: string; + + /** + * Url of request which has been sent. + */ + url: string; + + /** + * Key / value pairs of request which has been sent. + */ + query?: Query; + + /** + * When request processing started. + */ + timestamp: string; +}; +/** + * {@link Request} processing completion event. + * + * This event will be sent if {@link logVerbosity} set to `true` when worker will receive + * response from service or error. + */ +export type RequestSendingEnd = { + type: 'request-progress-end'; + + /** + * Receiving PubNub client unique identifier. + */ + clientIdentifier: string; + + /** + * Url of request which has been sent. + */ + url: string; + + /** + * Key / value pairs of request which has been sent. + */ + query?: Query; + + /** + * Stringified service response (if `Content-Type` allows it). + */ + response: string | undefined; + + /** + * How long it took to perform request. + */ + duration: number; + + /** + * When request processing ended. + */ + timestamp: string; +}; + +/** + * Request processing progress. + */ +export type RequestSendingProgress = RequestSendingStart | RequestSendingEnd; + +/** + * Request processing error. + * + * Object may include either service error response or client-side processing error object. + */ +export type RequestSendingError = { + type: 'request-process-error'; + + /** + * Receiving PubNub client unique identifier. + */ + clientIdentifier: string; + + /** + * Failed request identifier. + */ + identifier: string; + + /** + * Url which has been used to perform request. + */ + url: string; + + /** + * Service error response. + */ + response?: RequestSendingSuccess['response']; + + /** + * Client side request processing error. + */ + error?: { + /** + * Name of error object which has been received. + */ + name: string; + + /** + * Available client-side errors. + */ + type: 'NETWORK_ISSUE' | 'ABORTED' | 'TIMEOUT'; + + /** + * Triggered error message. + */ + message: string; + }; +}; + +/** + * Request processing success. + */ +export type RequestSendingSuccess = { + type: 'request-process-success'; + + /** + * Receiving PubNub client unique identifier. + */ + clientIdentifier: string; + + /** + * Processed request identifier. + */ + identifier: string; + + /** + * Url which has been used to perform request. + */ + url: string; + + /** + * Service success response. + */ + response: { + /** + * Received {@link RequestSendingSuccess#response.body|body} content type. + */ + contentType: string; + + /** + * Received {@link RequestSendingSuccess#response.body|body} content length. + */ + contentLength: number; + + /** + * Response headers key / value pairs. + */ + headers: Record; + + /** + * Response status code. + */ + status: number; + + /** + * Service response. + */ + body?: ArrayBuffer; + }; +}; + +/** + * Request processing results. + */ +export type RequestSendingResult = RequestSendingError | RequestSendingSuccess; + +/** + * List of known events from the PubNub Subscription Service Worker. + */ +export type ServiceWorkerEvent = RequestSendingProgress | RequestSendingResult; + +/** + * PubNub client state representation in Service Worker. + */ +type PubNubClientState = { + /** + * Unique PubNub client identifier. + */ + clientIdentifier: string; + + /** + * Subscribe REST API access key. + */ + subscriptionKey: string; + + /** + * Unique identifier of the user currently configured for the PubNub client. + */ + userId: string; + + /** + * Authorization key or access token which is used to access provided list of + * {@link subscription.channels|channels} and {@link subscription.channelGroups|channelGroups}. + */ + authKey?: string; + + /** + * Whether verbose logging enabled or not. + */ + logVerbosity: boolean; + + /** + * Current subscription session information. + * + * **Note:** Information updated each time when PubNub client instance schedule `subscribe` or + * `unsubscribe` requests. + */ + subscription: { + /** + * Subscription REST API uri path. + * + * **Note:** Keeping it for faster check whether client state should be updated or not. + */ + path: string; + + /** + * Channel groups list representation from request query parameters. + * + * **Note:** Keeping it for faster check whether client state should be updated or not. + */ + channelGroupQuery: string; + + /** + * List of channels used in current subscription session. + */ + channels: string[]; + + /** + * List of channel groups used in current subscription session. + */ + channelGroups: string[]; + + /** + * Timetoken which used has been used with previous subscription session loop. + */ + previousTimetoken: string; + + /** + * Timetoken which used in current subscription session loop. + */ + timetoken: string; + + /** + * List of channel and / or channel group names for which state has been assigned. + * + * Information used during client information update to identify entries which should be removed. + */ + objectsWithState: string[]; + + /** + * Subscribe request which has been emitted by PubNub client. + * + * Value will be reset when current request processing completed or client "disconnected" (not interested in + * real-time updates). + */ + request?: TransportRequest; + + /** + * Identifier of subscribe request which has been actually sent by Service Worker. + * + * **Note:** Value not set if client not interested in any real-time updates. + */ + serviceRequestId?: string; + + /** + * Real-time events filtering expression. + */ + filterExpression?: string; + }; +}; +// endregion +// endregion + +// -------------------------------------------------------- +// ------------------- Service Worker --------------------- +// -------------------------------------------------------- +// region Service Worker + +declare const self: ServiceWorkerGlobalScope; + +// region State +/** + * Service `ArrayBuffer` response decoder. + */ +const decoder = new TextDecoder(); + +/** + * Map of identifiers, scheduled by the Service Worker, to their abort controllers. + * + * **Note:** Because of message-based nature of interaction it will be impossible to pass actual {@link AbortController} + * to the transport provider code. + */ +const abortControllers: Map = new Map(); + +/** + * Map of PubNub client identifiers to their state in the current Service Worker. + */ +const pubNubClients: Record = {}; + +/** + * Per-subscription key list of PubNub client state. + */ +const pubNubClientsBySubscriptionKey: { [subscriptionKey: string]: PubNubClientState[] | undefined } = {}; + +/** + * Per-subscription key presence state associated with unique user identifiers with which {@link pubNubClients|clients} + * scheduled subscription request. + */ +const presenceState: { + [subscriptionKey: string]: + | { + [userId: string]: Record | undefined; + } + | undefined; +} = {}; + +/** + * Per-subscription key map of client identifiers to the Service Worker {@link Client} identifier. + * + * Service Worker {@link Client} represent pages at which PubNub clients registered Service Workers. + */ +const serviceWorkerClients: { + [subscriptionKey: string]: { [clientId: string]: string | undefined } | undefined; +} = {}; + +/** + * List of ongoing subscription requests. + * + * **Node:** Identifiers differ from request identifiers received in {@link SendRequestEvent} object. + */ +const serviceRequests: { + [requestId: string]: { + /** + * Unique active request identifier. + */ + requestId: string; + + /** + * Timetoken which is used for subscription loop. + */ + timetoken: string; + + /** + * List of channels used in current subscription session. + */ + channels: string[]; + + /** + * List of channel groups used in current subscription session. + */ + channelGroups: string[]; + }; +} = {}; +// endregion + +// -------------------------------------------------------- +// ------------------- Event Handlers --------------------- +// -------------------------------------------------------- +// region Event Handlers + +/** + * Listen for Service Worker activation. + */ +self.addEventListener('activate', (event) => { + event.waitUntil(self.clients.claim()); +}); + +/** + * Listen for events from the client. + */ +self.addEventListener('message', (event) => { + // Ignoring requests sent from other service workers. + if (!validateEventPayload(event)) return; + + const data = event.data as ClientEvent; + + if (data.type === 'send-request') { + if (data.request.path.startsWith('/v2/subscribe')) { + registerClientIfRequired(event); + handleSendSubscribeRequestEvent(data); + } else { + if (!pubNubClients[data.clientIdentifier]) registerClientIfRequired(event); + handleSendLeaveRequestEvent(event); + } + } else if (data.type === 'cancel-request') handleCancelRequestEvent(data); +}); + +/** + * Handle client request to send subscription request. + * + * @param event - Subscription event details. + */ +const handleSendSubscribeRequestEvent = (event: SendRequestEvent) => { + const requestOrId = subscribeTransportRequestFromEvent(event); + const client = pubNubClients[event.clientIdentifier]; + + if (client) notifyRequestProcessing('start', [client], new Date().toISOString()); + + if (typeof requestOrId === 'string') { + if (client) { + // Updating client timetoken information. + client.subscription.previousTimetoken = client.subscription.timetoken; + client.subscription.timetoken = serviceRequests[requestOrId].timetoken; + client.subscription.serviceRequestId = requestOrId; + } + return; + } + + if (event.request.cancellable) abortControllers.set(requestOrId.identifier, new AbortController()); + + sendRequest( + requestOrId, + () => clientsForRequest(requestOrId.identifier), + (clients, response) => { + // Notify each PubNub client which awaited for response. + notifyRequestProcessingResult(clients, response); + + // Clean up scheduled request and client references to it. + markRequestCompleted(clients, requestOrId.identifier); + }, + (clients, error) => { + // Notify each PubNub client which awaited for response. + notifyRequestProcessingResult(clients, null, requestOrId, requestProcessingError(error)); + + // Clean up scheduled request and client references to it. + markRequestCompleted(clients, requestOrId.identifier); + }, + ); +}; + +/** + * Handle client request to leave request. + * + * @param event - Leave event details. + */ +const handleSendLeaveRequestEvent = (event: ExtendableMessageEvent) => { + const data = event.data as SendRequestEvent; + const request = leaveTransportRequestFromEvent(data); + const client = pubNubClients[data.clientIdentifier]; + + if (!client) return; + if (!request) { + const body = new TextEncoder().encode('{"status": 200, "action": "leave", "message": "OK", "service":"Presence"}'); + const headers = new Headers({ 'Content-Type': 'text/javascript; charset="UTF-8"', 'Content-Length': '74' }); + const response = new Response(body, { status: 200, headers }); + const result = requestProcessingSuccess([response, body]); + result.url = `${data.request.origin}${data.request.path}`; + result.clientIdentifier = data.clientIdentifier; + result.identifier = data.request.identifier; + + publishClientEvent((event.source! as Client).id, result).then((sent) => { + if (sent) invalidateClient(client.subscriptionKey, client.clientIdentifier, client.userId); + }); + return; + } + + sendRequest( + request, + () => [client], + (clients, response) => { + // Notify each PubNub client which awaited for response. + notifyRequestProcessingResult(clients, response, data.request); + }, + (clients, error) => { + // Notify each PubNub client which awaited for response. + notifyRequestProcessingResult(clients, null, data.request, requestProcessingError(error)); + }, + ); +}; + +/** + * Handle cancel request event. + * + * Try cancel request if there is no other observers. + * + * @param event - Request cancellation event details. + */ +const handleCancelRequestEvent = (event: CancelRequestEvent) => { + const client = pubNubClients[event.clientIdentifier]; + const serviceRequestId = client ? client.subscription.serviceRequestId : undefined; + if (!client || !serviceRequestId) return; + + // Unset awaited requests. + delete client.subscription.serviceRequestId; + delete client.subscription.request; + + if (clientsForRequest(serviceRequestId).length === 0) { + const controller = abortControllers.get(serviceRequestId); + abortControllers.delete(serviceRequestId); + + // Clean up scheduled requests. + delete serviceRequests[serviceRequestId]; + + // Abort request if possible. + if (controller) controller.abort(); + } +}; +// endregion + +// -------------------------------------------------------- +// ------------------------ Common ------------------------ +// -------------------------------------------------------- +// region Common + +/** + * Process transport request. + * + * @param request - Transport request with required information for {@link Request} creation. + * @param getClients - Request completion PubNub client observers getter. + * @param success - Request success completion handler. + * @param failure - Request failure handler. + */ +const sendRequest = ( + request: TransportRequest, + getClients: () => PubNubClientState[], + success: (clients: PubNubClientState[], response: [Response, ArrayBuffer]) => void, + failure: (clients: PubNubClientState[], error: unknown) => void, +) => { + (async () => { + // Request progress support. + const start = new Date().getTime(); + + Promise.race([ + fetch(requestFromTransportRequest(request), { + signal: abortControllers.get(request.identifier)?.signal, + keepalive: true, + }), + requestTimeoutTimer(request.identifier, request.timeout), + ]) + .then((response): Promise<[Response, ArrayBuffer]> | [Response, ArrayBuffer] => + response.arrayBuffer().then((buffer) => [response, buffer]), + ) + .then((response) => { + const responseBody = response[1].byteLength > 0 ? response[1] : undefined; + + const clients = getClients(); + if (clients.length === 0) return; + + notifyRequestProcessing( + 'end', + clients, + new Date().toISOString(), + request, + responseBody, + response[0].headers.get('Content-Type'), + new Date().getTime() - start, + ); + + success(clients, response); + }) + .catch((error) => { + const clients = getClients(); + if (clients.length === 0) return; + + failure(clients, error); + }); + })(); +}; + +/** + * Create request timeout timer. + * + * **Note:** Native Fetch API doesn't support `timeout` out-of-box and {@link Promise} used to emulate it. + * + * @param requestId - Unique identifier of request which will time out after {@link requestTimeout} seconds. + * @param requestTimeout - Number of seconds after which request with specified identifier will time out. + * + * @returns Promise which rejects after time out will fire. + */ +const requestTimeoutTimer = (requestId: string, requestTimeout: number) => + new Promise((_, reject) => { + const timeoutId = setTimeout(() => { + // Clean up. + abortControllers.delete(requestId); + clearTimeout(timeoutId); + + reject(new Error('Request timeout')); + }, requestTimeout * 1000); + }); + +/** + * Retrieve list of PubNub clients which is pending for service worker request completion. + * + * @param identifier - Identifier of the subscription request which has been scheduled by the Service Worker. + * + * @returns List of PubNub client state objects for Service Worker. + */ +const clientsForRequest = (identifier: string) => { + return Object.values(pubNubClients).filter( + (client): client is PubNubClientState => + client !== undefined && client.subscription.serviceRequestId === identifier, + ); +}; + +/** + * Clean up PubNub client states from ongoing request. + * + * Reset requested and scheduled request information to make PubNub client "free" for neext requests. + * + * @param clients - List of PubNub clients which awaited for scheduled request completion. + * @param requestId - Unique subscribe request identifier for which {@link clients} has been provided. + */ +const markRequestCompleted = (clients: PubNubClientState[], requestId: string) => { + delete serviceRequests[requestId]; + + clients.forEach((client) => { + delete client.subscription.request; + delete client.subscription.serviceRequestId; + }); +}; + +/** + * Creates a Request object from a given {@link TransportRequest} object. + * + * @param req - The {@link TransportRequest} object containing request information. + * + * @returns `Request` object generated from the {@link TransportRequest} object or `undefined` if no request + * should be sent. + */ +const requestFromTransportRequest = (req: TransportRequest): Request => { + let headers: Record | undefined = undefined; + const queryParameters = req.queryParameters; + let path = req.path; + + if (req.headers) { + headers = {}; + for (const [key, value] of Object.entries(req.headers)) headers[key] = value; + } + + if (queryParameters && Object.keys(queryParameters).length !== 0) + path = `${path}?${queryStringFromObject(queryParameters)}`; + + return new Request(`${req.origin!}${path}`, { + method: req.method, + headers, + redirect: 'follow', + }); +}; + +/** + * Construct transport request from send subscription request event. + * + * Update transport request to aggregate channels and groups if possible. + * + * @param event - Client's send subscription event request. + * + * @returns Final transport request or identifier from active request which will provide response to required + * channels and groups. + */ +const subscribeTransportRequestFromEvent = (event: SendRequestEvent): TransportRequest | string => { + const client = pubNubClients[event.clientIdentifier]!; + const clients = clientsForSendSubscribeRequestEvent(client.subscription.previousTimetoken, event); + const serviceRequestId = uuidGenerator.createUUID(); + const request = { ...event.request }; + + if (clients.length > 1) { + const activeRequestId = activeSubscriptionForEvent(clients, event); + + // Return identifier of the ongoing request. + if (activeRequestId) return activeRequestId; + + const state = (presenceState[client.subscriptionKey] ?? {})[client.userId]; + const aggregatedState: Record = {}; + const channelGroups = new Set(client.subscription.channelGroups); + const channels = new Set(client.subscription.channels); + + if (state && client.subscription.objectsWithState.length) { + client.subscription.objectsWithState.forEach((name) => { + const objectState = state[name]; + if (objectState) aggregatedState[name] = objectState; + }); + } + + for (const client of clients) { + const { subscription } = client!; + // Skip clients which already have active subscription request. + if (subscription.serviceRequestId) continue; + + subscription.channelGroups.forEach(channelGroups.add, channelGroups); + subscription.channels.forEach(channels.add, channels); + + // Set awaited service worker request identifier. + subscription.serviceRequestId = serviceRequestId; + + if (!state) continue; + + subscription.objectsWithState.forEach((name) => { + const objectState = state[name]; + + if (objectState && !aggregatedState[name]) aggregatedState[name] = objectState; + }); + } + + const serviceRequest = (serviceRequests[serviceRequestId] ??= { + requestId: serviceRequestId, + timetoken: (request.queryParameters!.tt as string) ?? '0', + channelGroups: [], + channels: [], + }); + + // Update request channels list (if required). + if (channels.size) { + serviceRequest.channels = Array.from(channels).sort(); + const pathComponents = request.path.split('/'); + pathComponents[4] = serviceRequest.channels.join(','); + request.path = pathComponents.join('/'); + } + + // Update request channel groups list (if required). + if (channelGroups.size) { + serviceRequest.channelGroups = Array.from(channelGroups).sort(); + request.queryParameters!['channel-group'] = serviceRequest.channelGroups.join(','); + } + + // Update request `state` (if required). + if (Object.keys(aggregatedState).length) request.queryParameters!['state'] = JSON.stringify(aggregatedState); + } else { + serviceRequests[serviceRequestId] = { + requestId: serviceRequestId, + timetoken: (request.queryParameters!.tt as string) ?? '0', + channelGroups: client.subscription.channelGroups, + channels: client.subscription.channels, + }; + } + + client.subscription.serviceRequestId = serviceRequestId; + request.identifier = serviceRequestId; + + return request; +}; + +/** + * Construct transport request from send leave request event. + * + * Filter out channels and groups, which is still in use by other PubNub client instances from leave request. + * + * @param event - Client's send leave event request. + * + * @returns Final transport request or `undefined` in case if there is no channels and groups for which request can be + * done. + */ +const leaveTransportRequestFromEvent = (event: SendRequestEvent): TransportRequest | undefined => { + const client = pubNubClients[event.clientIdentifier]; + const clients = clientsForSendLeaveRequestEvent(event); + let channelGroups = channelGroupsFromRequest(event.request); + let channels = channelsFromRequest(event.request); + const request = { ...event.request }; + + if (client) { + const { subscription } = client; + if (channels.length) subscription.channels = subscription.channels.filter((channel) => !channels.includes(channel)); + if (channelGroups.length) { + subscription.channelGroups = subscription.channelGroups.filter((group) => !channelGroups.includes(group)); + } + } + + // Filter out channels and groups which is still in use by the other PubNub client instances. + for (const client of clients) { + if (client.clientIdentifier === event.clientIdentifier) continue; + if (channels.length) channels = channels.filter((channel) => !client.subscription.channels.includes(channel)); + if (channelGroups.length) + channelGroups = channelGroups.filter((group) => !client.subscription.channelGroups.includes(group)); + } + + if (channels.length === 0 && channelGroups.length === 0) return undefined; + + // Update request channels list (if required). + if (channels.length) { + const pathComponents = request.path.split('/'); + pathComponents[4] = channels.join(','); + request.path = pathComponents.join('/'); + } + + // Update request channel groups list (if required). + if (channelGroups.length) request.queryParameters!['channel-group'] = channelGroups.join(','); + + return request; +}; + +/** + * Send event to all service worker clients. + * + * @param identifier - Service Worker receiving {@link Client} identifier. + * @param event - Service worker event object. + */ +const publishClientEvent = (identifier: string, event: ServiceWorkerEvent) => { + return self.clients.get(identifier).then((client) => { + if (!client) return false; + + client.postMessage(event); + return true; + }); +}; + +/** + * Send request processing update. + * + * @param type - Type of processing event. + * @param clients - List of PubNub clients which should be notified about request progress. + * @param timestamp - Date and time when request processing update happened. + * @param [request] - Processed request information. + * @param [responseBody] - PubNub service response. + * @param [contentType] - PubNub service response content type. + * @param [duration] - How long it took to complete request. + */ +const notifyRequestProcessing = ( + type: 'start' | 'end', + clients: PubNubClientState[], + timestamp: string, + request?: TransportRequest, + responseBody?: ArrayBuffer, + contentType?: string | null, + duration?: number, +) => { + if (clients.length === 0) return; + + const clientIds = serviceWorkerClients[clients[0].subscriptionKey] ?? {}; + let event: RequestSendingProgress; + + if (type === 'start') { + event = { + type: 'request-progress-start', + clientIdentifier: '', + url: '', + timestamp, + }; + } else { + let response: string | undefined; + if ( + responseBody && + contentType && + (contentType.indexOf('text/javascript') !== -1 || + contentType.indexOf('application/json') !== -1 || + contentType.indexOf('text/plain') !== -1 || + contentType.indexOf('text/html') !== -1) + ) { + response = decoder.decode(responseBody); + } + + event = { + type: 'request-progress-end', + clientIdentifier: '', + url: '', + response, + timestamp, + duration: duration!, + }; + } + + clients.forEach((client) => { + const serviceWorkerClientId = clientIds[client.clientIdentifier]; + const { request: clientRequest } = client.subscription; + const decidedRequest = clientRequest ?? request; + + if (client.logVerbosity && serviceWorkerClientId && decidedRequest) { + publishClientEvent(serviceWorkerClientId, { + ...event, + clientIdentifier: client.clientIdentifier, + url: `${decidedRequest.origin}${decidedRequest.path}`, + query: decidedRequest.queryParameters, + }).then((sent) => { + if (sent) invalidateClient(client.subscriptionKey, client.clientIdentifier, client.userId); + }); + } + }); +}; + +/** + * Send request processing result event. + * + * @param clients - List of PubNub clients which should be notified about request result. + * @param [response] - PubNub service response. + * @param [request] - Processed request information. + * @param [result] - Explicit request processing result which should be notified. + */ +const notifyRequestProcessingResult = ( + clients: PubNubClientState[], + response: [Response, ArrayBuffer] | null, + request?: TransportRequest, + result?: RequestSendingResult, +) => { + if (clients.length === 0) return; + if (!result && !response) return; + + const clientIds = serviceWorkerClients[clients[0].subscriptionKey] ?? {}; + + if (!result && response) { + result = + response[0].status >= 400 + ? // Treat 4xx and 5xx status codes as errors. + requestProcessingError(undefined, response) + : requestProcessingSuccess(response); + } + + clients.forEach((client) => { + const serviceWorkerClientId = clientIds[client.clientIdentifier]; + const { request: clientRequest } = client.subscription; + const decidedRequest = clientRequest ?? request; + + if (serviceWorkerClientId && decidedRequest) { + publishClientEvent(serviceWorkerClientId, { + ...result!, + clientIdentifier: client.clientIdentifier, + identifier: decidedRequest.identifier, + url: `${decidedRequest.origin}${decidedRequest.path}`, + }).then((sent) => { + if (sent) invalidateClient(client.subscriptionKey, client.clientIdentifier, client.userId); + }); + } + }); +}; + +/** + * Create processing success event from service response. + * + * **Note:** The rest of information like `clientIdentifier`,`identifier`, and `url` will be added later for each + * specific PubNub client state. + * + * @param res - Service response for used REST API endpoint along with response body. + * + * @returns Request processing success event object. + */ +const requestProcessingSuccess = (res: [Response, ArrayBuffer]): RequestSendingSuccess => { + const [response, body] = res; + const responseBody = body.byteLength > 0 ? body : undefined; + const contentLength = parseInt(response.headers.get('Content-Length') ?? '0', 10); + const contentType = response.headers.get('Content-Type')!; + const headers: Record = {}; + + // Copy Headers object content into plain Record. + response.headers.forEach((value, key) => (headers[key] = value.toLowerCase())); + + return { + type: 'request-process-success', + clientIdentifier: '', + identifier: '', + url: '', + response: { + contentLength, + contentType, + headers, + status: response.status, + body: responseBody, + }, + }; +}; + +/** + * Create processing error event from service response. + * + * **Note:** The rest of information like `clientIdentifier`,`identifier`, and `url` will be added later for each + * specific PubNub client state. + * + * @param [error] - Client-side request processing error (for example network issues). + * @param [res] - Service error response (for example permissions error or malformed + * payload) along with service body. + * + * @returns Request processing error event object. + */ +const requestProcessingError = (error?: unknown, res?: [Response, ArrayBuffer]): RequestSendingError => { + // User service response as error information source. + if (res) { + return { + ...requestProcessingSuccess(res), + type: 'request-process-error', + }; + } + + let type: NonNullable['type'] = 'NETWORK_ISSUE'; + let message = 'Unknown error'; + let name = 'Error'; + + if (error && error instanceof Error) { + message = error.message; + name = error.name; + } + + if (name === 'AbortError') { + message = 'Request aborted'; + type = 'ABORTED'; + } else if (message === 'Request timeout') type = 'TIMEOUT'; + + return { + type: 'request-process-error', + clientIdentifier: '', + identifier: '', + url: '', + error: { name, type, message }, + }; +}; +// endregion + +// -------------------------------------------------------- +// ----------------------- Helpers ------------------------ +// -------------------------------------------------------- +// region Helpers + +/** + * Register client if it didn't use Service Worker before. + * + * The registration process updates the Service Worker state with information about channels and groups in which + * particular PubNub clients are interested, and uses this information when another subscribe request is made to build + * shared requests. + * + * @param event - Base information about PubNub client instance and Service Worker {@link Client}. + */ +const registerClientIfRequired = (event: ExtendableMessageEvent) => { + const information = event.data as SendRequestEvent; + const { clientIdentifier } = information; + const query = information.request.queryParameters!; + + let client = pubNubClients[clientIdentifier]; + + if (!client) { + const isPresenceLeave = !information.request.path.startsWith('/v2/subscribe'); + const channelGroupQuery = !isPresenceLeave ? ((query!['channel-group'] ?? '') as string) : ''; + const state = !isPresenceLeave ? ((query.state ?? '') as string) : ''; + + client = pubNubClients[clientIdentifier] = { + clientIdentifier, + subscriptionKey: information.subscriptionKey, + userId: query.uuid as string, + authKey: (query.auth ?? '') as string, + logVerbosity: information.logVerbosity, + subscription: { + path: !isPresenceLeave ? information.request.path : '', + channelGroupQuery: !isPresenceLeave ? channelGroupQuery : '', + channels: !isPresenceLeave ? channelsFromRequest(information.request) : [], + channelGroups: !isPresenceLeave ? channelGroupsFromRequest(information.request) : [], + previousTimetoken: !isPresenceLeave ? ((query.tt ?? '0') as string) : '0', + timetoken: !isPresenceLeave ? ((query.tt ?? '0') as string) : '0', + request: !isPresenceLeave ? information.request : undefined, + objectsWithState: [], + filterExpression: !isPresenceLeave ? ((query['filter-expr'] ?? '') as string) : undefined, + }, + }; + + if (!isPresenceLeave && state.length > 0) { + const parsedState = JSON.parse(state) as Record; + const userState = ((presenceState[client.subscriptionKey] ??= {})[client.userId] ??= {}); + + Object.entries(parsedState).forEach(([objectName, value]) => (userState[objectName] = value)); + client.subscription.objectsWithState = Object.keys(parsedState); + } + + // Map registered PubNub client to its subscription key. + const clientsBySubscriptionKey = (pubNubClientsBySubscriptionKey[information.subscriptionKey] ??= []); + if (clientsBySubscriptionKey.every((entry) => entry.clientIdentifier !== clientIdentifier)) + clientsBySubscriptionKey.push(client); + + // Binding PubNub client to the page (Service Worker Client). + (serviceWorkerClients[information.subscriptionKey] ??= {})[clientIdentifier] = (event.source! as Client).id; + } else { + const channelGroupQuery = (query!['channel-group'] ?? '') as string; + const state = (query.state ?? '') as string; + client.subscription.filterExpression = (query['filter-expr'] ?? '') as string; + client.subscription.previousTimetoken = client.subscription.timetoken; + client.subscription.timetoken = (query.tt ?? '0') as string; + client.subscription.request = information.request; + client.authKey = (query.auth ?? '') as string; + client.userId = query.uuid as string; + + if (client.subscription.path !== information.request.path) { + client.subscription.path = information.request.path; + client.subscription.channels = channelsFromRequest(information.request); + } + + if (client.subscription.channelGroupQuery !== channelGroupQuery) { + client.subscription.channelGroupQuery = channelGroupQuery; + client.subscription.channelGroups = channelGroupsFromRequest(information.request); + } + + if (state.length > 0) { + const parsedState = JSON.parse(state) as Record; + const userState = ((presenceState[client.subscriptionKey] ??= {})[client.userId] ??= {}); + Object.entries(parsedState).forEach(([objectName, value]) => (userState[objectName] = value)); + + // Clean up state for objects where presence state has been reset. + for (const objectName of client.subscription.objectsWithState) + if (!parsedState[objectName]) delete userState[objectName]; + client.subscription.objectsWithState = Object.keys(parsedState); + } + // Handle potential presence state reset. + else if (client.subscription.objectsWithState.length) { + const userState = ((presenceState[client.subscriptionKey] ??= {})[client.userId] ??= {}); + + for (const objectName of client.subscription.objectsWithState) delete userState[objectName]; + client.subscription.objectsWithState = []; + } + } +}; + +/** + * Clean up resources used by registered PubNub client instance. + * + * @param subscriptionKey - Subscription key which has been used by the + * invalidated instance. + * @param clientId - Unique PubNub client identifier. + * @param userId - Unique identifier of the user used by PubNub client instance. + */ +const invalidateClient = (subscriptionKey: string, clientId: string, userId: string) => { + delete pubNubClients[clientId]; + let clients = pubNubClientsBySubscriptionKey[subscriptionKey]; + + if (clients) { + // Clean up linkage between client and subscription key. + clients = clients.filter((client) => client.clientIdentifier !== clientId); + if (clients.length > 0) pubNubClientsBySubscriptionKey[subscriptionKey] = clients; + else delete pubNubClientsBySubscriptionKey[subscriptionKey]; + + // Clean up presence state information if not in use anymore. + if (clients.length === 0) delete presenceState[subscriptionKey]; + + // Clean up service workers client linkage to PubNub clients. + if (clients.length > 0) { + const workerClients = serviceWorkerClients[subscriptionKey]; + if (workerClients) { + delete workerClients[clientId]; + + if (Object.keys(workerClients).length === 0) delete serviceWorkerClients[subscriptionKey]; + } + } else delete serviceWorkerClients[subscriptionKey]; + } +}; + +/** + * Validate received event payload. + */ +const validateEventPayload = (event: ExtendableMessageEvent): boolean => { + if (!event.source || !(event.source instanceof Client)) return false; + const data = event.data as ClientEvent; + + const { clientIdentifier, subscriptionKey, logVerbosity } = data as ClientEvent; + if (logVerbosity === undefined || typeof logVerbosity !== 'boolean') return false; + if (!clientIdentifier || typeof clientIdentifier !== 'string') return false; + + return !(!subscriptionKey || typeof subscriptionKey !== 'string'); +}; + +/** + * Search for active subscription for one of the passed {@link serviceWorkerClients}. + * + * @param activeClients - List of suitable registered PubNub clients. + * @param event - Send Subscriber Request event data. + * + * @returns Unique identifier of the active request which will receive real-time updates for channels and groups + * requested in received subscription request or `undefined` if none of active (or not scheduled) request can be used. + */ +const activeSubscriptionForEvent = ( + activeClients: PubNubClientState[], + event: SendRequestEvent, +): string | undefined => { + const query = event.request.queryParameters!; + const channelGroupQuery = (query['channel-group'] ?? '') as string; + const requestPath = event.request.path; + let channelGroups: string[] | undefined; + let channels: string[] | undefined; + + for (const client of activeClients) { + const { subscription } = client; + // Skip PubNub clients which doesn't await for subscription response. + if (!subscription.serviceRequestId) continue; + + if (subscription.path === requestPath && subscription.channelGroupQuery === channelGroupQuery) { + return subscription.serviceRequestId; + } else { + const scheduledRequest = serviceRequests[subscription.serviceRequestId]; + if (!channelGroups) channelGroups = channelGroupsFromRequest(event.request); + if (!channels) channels = channelsFromRequest(event.request); + + // Checking whether all required channels and groups are handled already by active request or not. + if (channels.length && !includesStrings(scheduledRequest.channels, channels)) continue; + if (channelGroups.length && !includesStrings(scheduledRequest.channelGroups, channelGroups)) continue; + + return subscription.serviceRequestId; + } + } + + return undefined; +}; + +/** + * Find PubNub client states with configuration compatible with the one in request. + * + * Method allow to find information about all PubNub client instances which use same: + * - subscription key + * - `userId` + * - `auth` key + * - `filter expression` + * - `timetoken` (compare should be done against previous timetoken of the client which requested new subscribe). + * + * @param timetoken - Previous timetoken used by the PubNub client which requested to send new subscription request + * (it will be the same as 'current' timetoken of the other PubNub clients). + * @param event - Send subscribe request event information. + * + * @returns List of PubNub client states which works from other pages for the same user. + */ +const clientsForSendSubscribeRequestEvent = (timetoken: string, event: SendRequestEvent) => { + const query = event.request.queryParameters!; + const filterExpression = (query['filter-expr'] ?? '') as string; + const authKey = (query.auth ?? '') as string; + const userId = query.uuid! as string; + + return (pubNubClientsBySubscriptionKey[event.subscriptionKey] ?? []).filter( + (client) => + client.userId === userId && + client.authKey === authKey && + client.subscription.filterExpression === filterExpression && + (timetoken === '0' || + client.subscription.previousTimetoken === '0' || + client.subscription.previousTimetoken === timetoken), + ); +}; + +/** + * Find PubNub client states with configuration compatible with the one in request. + * + * Method allow to find information about all PubNub client instances which use same: + * - subscription key + * - `userId` + * - `auth` key + * + * @param event - Send leave request event information. + * + * @returns List of PubNub client states which works from other pages for the same user. + */ +const clientsForSendLeaveRequestEvent = (event: SendRequestEvent) => { + const query = event.request.queryParameters!; + const authKey = (query.auth ?? '') as string; + const userId = query.uuid! as string; + + return (pubNubClientsBySubscriptionKey[event.subscriptionKey] ?? []).filter( + (client) => client.userId === userId && client.authKey === authKey, + ); +}; + +/** + * Extract list of channels from request URI path. + * + * @param request - Transport request which should provide `path` for parsing. + * + * @returns List of channel names (not percent-decoded) for which `subscribe` or `leave` has been called. + */ +const channelsFromRequest = (request: TransportRequest): string[] => { + const channels = request.path.split('/')[request.path.startsWith('/v2/subscribe/') ? 4 : 6]; + return channels === ',' ? [] : channels.split(',').filter((name) => name.length > 0); +}; + +/** + * Extract list of channel groups from request query. + * + * @param request - Transport request which should provide `query` for parsing. + * + * @returns List of channel group names (not percent-decoded) for which `subscribe` or `leave` has been called. + */ +const channelGroupsFromRequest = (request: TransportRequest): string[] => { + const group = (request.queryParameters!['channel-group'] ?? '') as string; + return group.length === 0 ? [] : group.split(',').filter((name) => name.length > 0); +}; + +/** + * Check whether {@link main} array contains all entries from {@link sub} array. + * + * @param main - Main array with which `intersection` with {@link sub} should be checked. + * @param sub - Sub-array whose values should be checked in {@link main}. + * + * @returns `true` if all entries from {@link sub} is present in {@link main}. + */ +const includesStrings = (main: string[], sub: string[]) => { + const set = new Set(main); + return sub.every(set.has, set); +}; + +/** + * Stringify request query key / value pairs. + * + * @param query - Request query object. + * + * @returns Stringified query object. + */ +const queryStringFromObject = (query: Query) => { + return Object.keys(query) + .map((key) => { + const queryValue = query[key]; + if (!Array.isArray(queryValue)) return `${key}=${encodeString(queryValue)}`; + + return queryValue.map((value) => `${key}=${encodeString(value)}`).join('&'); + }) + .join('&'); +}; + +/** + * Percent-encode input string. + * + * **Note:** Encode content in accordance of the `PubNub` service requirements. + * + * @param input - Source string or number for encoding. + * + * @returns Percent-encoded string. + */ +const encodeString = (input: string | number) => { + return encodeURIComponent(input).replace(/[!~*'()]/g, (x) => `%${x.charCodeAt(0).toString(16).toUpperCase()}`); +}; +// endregion +// endregion diff --git a/src/transport/titanium-transport.ts b/src/transport/titanium-transport.ts new file mode 100644 index 000000000..8836dbcec --- /dev/null +++ b/src/transport/titanium-transport.ts @@ -0,0 +1,173 @@ +/** global Ti */ + +/** + * Titanium Transport provider module. + */ + +import { CancellationController, TransportRequest } from '../core/types/transport-request'; +import { TransportResponse } from '../core/types/transport-response'; +import { PubNubAPIError } from '../errors/pubnub-api-error'; +import { Transport } from '../core/interfaces/transport'; +import { queryStringFromObject } from '../core/utils'; + +/** + * Class representing a {@link Ti.Network.HTTPClient|HTTPClient}-based Titanium transport provider. + */ +export class TitaniumTransport implements Transport { + /** + * Service {@link ArrayBuffer} response decoder. + */ + protected static decoder = new TextDecoder(); + + /** + * Create a new `Ti.Network.HTTPClient`-based transport instance. + * + * @param keepAlive - Indicates whether keep-alive should be enabled. + * @param [logVerbosity] - Whether verbose logging enabled or not. + * + * @returns Transport for performing network requests. + */ + constructor( + private readonly keepAlive: boolean = false, + private readonly logVerbosity: boolean = false, + ) {} + + makeSendable(req: TransportRequest): [Promise, CancellationController | undefined] { + const [xhr, url, body] = this.requestFromTransportRequest(req); + let controller: CancellationController | undefined; + let aborted = false; + + if (req.cancellable) { + controller = { + abort: () => { + aborted = true; + xhr.abort(); + }, + }; + } + + return [ + new Promise((resolve, reject) => { + const start = new Date().getTime(); + + this.logRequestProcessProgress(url); + + xhr.onload = () => { + const response = this.transportResponseFromXHR(url, xhr); + + this.logRequestProcessProgress(url, new Date().getTime() - start, response.body); + resolve(response); + }; + + xhr.onerror = () => { + const elapsed = new Date().getTime() - start; + let body: ArrayBuffer | undefined; + let error: PubNubAPIError; + + if (aborted) { + error = PubNubAPIError.create(new Error('Aborted')); + } else if (xhr.timeout >= elapsed - 100) { + error = PubNubAPIError.create(new Error('Request timeout')); + } else if (xhr.status === 0) { + error = PubNubAPIError.create(new Error('Request failed because of network issues')); + } else { + const response = this.transportResponseFromXHR(url, xhr); + error = PubNubAPIError.create(response); + body = response.body; + } + + this.logRequestProcessProgress(url, elapsed, body); + + reject(error); + }; + + xhr.send(body); + }), + controller, + ]; + } + + request(req: TransportRequest): TransportRequest { + return req; + } + + /** + * Creates a Request object from a given {@link TransportRequest} object. + * + * @param request - The {@link TransportRequest} object containing request information. + * + * @returns Request object generated from the {@link TransportRequest} object. + */ + private requestFromTransportRequest( + request: TransportRequest, + ): [Ti.Network.HTTPClient, string, string | ArrayBuffer | undefined] { + const xhr = Ti.Network.createHTTPClient({ timeout: request.timeout * 1000, enableKeepAlive: this.keepAlive }); + let body: string | ArrayBuffer | undefined; + let path = request.path; + + if (request.queryParameters && Object.keys(request.queryParameters).length !== 0) + path = `${path}?${queryStringFromObject(request.queryParameters)}`; + const url = `${request.origin!}${path}`; + + // Initiate XHR request. + xhr.open(request.method, url, true); + + // Append HTTP headers (if required). + for (const [key, value] of Object.entries(request.headers ?? {})) xhr.setRequestHeader(key, value); + + if (request.body && (typeof request.body === 'string' || request.body instanceof ArrayBuffer)) body = request.body; + + return [xhr, url, body]; + } + + /** + * Create service response from {@link Ti.Network.HTTPClient|HTTPClient} processing result. + * + * @param url - Used endpoint url. + * @param xhr - `HTTPClient` which has been used to make a request. + * + * @returns Pre-processed transport response. + */ + private transportResponseFromXHR(url: string, xhr: Ti.Network.HTTPClient): TransportResponse { + const allHeaders = xhr.getAllResponseHeaders().split('\n'); + const headers: Record = {}; + + for (const header of allHeaders) { + const [key, value] = header.trim().split(':'); + if (key && value) headers[key.toLowerCase()] = value.trim(); + } + + return { status: xhr.status, url, headers, body: xhr.responseData.toArrayBuffer() }; + } + + /** + * Log out request processing progress and result. + * + * @param url - Endpoint Url used by {@link Ti.Network.HTTPClient|HTTPClient}. + * @param [elapsed] - How many times passed since request processing started. + * @param [body] - Service response (if available). + */ + private logRequestProcessProgress(url: string, elapsed?: number, body?: ArrayBuffer) { + if (!this.logVerbosity) return; + + const { protocol, host, pathname, search } = new URL(url); + const timestamp = new Date().toISOString(); + + if (!elapsed) { + Ti.API.info('<<<<<'); + Ti.API.info([`[${timestamp}]`, `\n${protocol}//${host}${pathname}`, `\n${search}`]); + Ti.API.info('-----'); + } else { + const stringifiedBody = body ? TitaniumTransport.decoder.decode(body) : undefined; + + Ti.API.info('>>>>>>'); + Ti.API.info([ + `[${timestamp} / ${elapsed}]`, + `\n${protocol}//${host}${pathname}`, + `\n${search}`, + `\n${stringifiedBody}`, + ]); + Ti.API.info('-----'); + } + } +} diff --git a/src/transport/web-react-native-transport.ts b/src/transport/web-react-native-transport.ts new file mode 100644 index 000000000..39b8dc686 --- /dev/null +++ b/src/transport/web-react-native-transport.ts @@ -0,0 +1,172 @@ +/** + * Common browser and React Native Transport provider module. + */ + +import { CancellationController, TransportRequest } from '../core/types/transport-request'; +import { TransportResponse } from '../core/types/transport-response'; +import { PubNubAPIError } from '../errors/pubnub-api-error'; +import { Transport } from '../core/interfaces/transport'; +import { PubNubFileInterface } from '../core/types/file'; +import { queryStringFromObject } from '../core/utils'; + +/** + * Class representing a `fetch`-based browser and React Native transport provider. + */ +export class WebReactNativeTransport implements Transport { + /** + * Service {@link ArrayBuffer} response decoder. + */ + protected static decoder = new TextDecoder(); + + constructor( + private keepAlive: boolean = false, + private readonly logVerbosity: boolean, + ) {} + + makeSendable(req: TransportRequest): [Promise, CancellationController | undefined] { + let controller: CancellationController | undefined; + let abortController: AbortController | undefined; + + if (req.cancellable) { + abortController = new AbortController(); + controller = { + // Storing controller inside to prolong object lifetime. + abortController, + abort: () => abortController?.abort(), + } as CancellationController; + } + + return [ + this.requestFromTransportRequest(req).then((request) => { + const start = new Date().getTime(); + + this.logRequestProcessProgress(request); + + /** + * Setup request timeout promise. + * + * **Note:** Native Fetch API doesn't support `timeout` out-of-box. + */ + const requestTimeout = new Promise((_, reject) => { + const timeoutId = setTimeout(() => { + // Clean up. + clearTimeout(timeoutId); + + reject(new Error('Request timeout')); + }, req.timeout * 1000); + }); + + return Promise.race([fetch(request, { signal: abortController?.signal }), requestTimeout]) + .then((response): Promise<[Response, ArrayBuffer]> | [Response, ArrayBuffer] => + response.arrayBuffer().then((arrayBuffer) => [response, arrayBuffer]), + ) + .then((response) => { + const responseBody = response[1].byteLength > 0 ? response[1] : undefined; + const { status, headers: requestHeaders } = response[0]; + const headers: Record = {}; + + // Copy Headers object content into plain Record. + requestHeaders.forEach((value, key) => (headers[key] = value.toLowerCase())); + + const transportResponse: TransportResponse = { + status, + url: request.url, + headers, + body: responseBody, + }; + + if (status >= 400) throw PubNubAPIError.create(transportResponse); + + this.logRequestProcessProgress(request, new Date().getTime() - start, responseBody); + + return transportResponse; + }) + .catch((error) => { + throw PubNubAPIError.create(error); + }); + }), + controller, + ]; + } + + request(req: TransportRequest): TransportRequest { + return req; + } + + /** + * Creates a Request object from a given {@link TransportRequest} object. + * + * @param req - The {@link TransportRequest} object containing request information. + * + * @returns Request object generated from the {@link TransportRequest} object. + */ + private async requestFromTransportRequest(req: TransportRequest): Promise { + let body: string | ArrayBuffer | FormData | undefined; + let path = req.path; + + // Create multipart request body. + if (req.formData && req.formData.length > 0) { + // Reset query parameters to conform to signed URL + req.queryParameters = {}; + + const file = req.body as PubNubFileInterface; + const formData = new FormData(); + for (const { key, value } of req.formData) formData.append(key, value); + try { + const fileData = await file.toArrayBuffer(); + formData.append('file', new Blob([fileData], { type: 'application/octet-stream' }), file.name); + } catch (_) { + try { + const fileData = await file.toFileUri(); + // @ts-expect-error React Native File Uri support. + formData.append('file', fileData, file.name); + } catch (_) {} + } + + body = formData; + } + // Handle regular body payload (if passed). + else if (req.body && (typeof req.body === 'string' || req.body instanceof ArrayBuffer)) body = req.body; + + if (req.queryParameters && Object.keys(req.queryParameters).length !== 0) + path = `${path}?${queryStringFromObject(req.queryParameters)}`; + + return new Request(`${req.origin!}${path}`, { + method: req.method, + headers: req.headers, + redirect: 'follow', + body, + }); + } + + /** + * Log out request processing progress and result. + * + * @param request - Platform-specific + * @param [elapsed] - How many seconds passed since request processing started. + * @param [body] - Service response (if available). + */ + protected logRequestProcessProgress(request: Request, elapsed?: number, body?: ArrayBuffer) { + if (!this.logVerbosity) return; + + const { protocol, host, pathname, search } = new URL(request.url); + const timestamp = new Date().toISOString(); + + if (!elapsed) { + console.log('<<<<<'); + console.log(`[${timestamp}]`, `\n${protocol}//${host}${pathname}`, `\n${search}`); + console.log('-----'); + } else { + const stringifiedBody = body ? WebReactNativeTransport.decoder.decode(body) : undefined; + + console.log('>>>>>>'); + console.log( + `[${timestamp} / ${elapsed}]`, + `\n${protocol}//${host}${pathname}`, + `\n${search}`, + `\n${stringifiedBody}`, + ); + console.log('-----'); + } + } +} diff --git a/src/web/components/configuration.ts b/src/web/components/configuration.ts new file mode 100644 index 000000000..583c0361b --- /dev/null +++ b/src/web/components/configuration.ts @@ -0,0 +1,80 @@ +import { + UserConfiguration, + ExtendedConfiguration, + setDefaults as setBaseDefaults, +} from '../../core/interfaces/configuration'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Whether PubNub client should update its state using browser's reachability events or not. + * + * If the browser fails to detect the network changes from Wi-Fi to LAN and vice versa, or you get + * reconnection issues, set the flag to `false`. This allows the SDK reconnection logic to take over. + */ +const LISTEN_TO_BROWSER_NETWORK_EVENTS = true; + +/** + * Whether PubNub client should spawn `Subscription` service worker for better user presence + * experience or not. + */ +const ENABLE_SERVICE_WORKER = false; + +/** + * Whether PubNub client should try to utilize existing TCP connection for new requests or not. + */ +const KEEP_ALIVE = true; +// endregion + +/** + * Browser platform PubNub client configuration. + */ +export type PubNubConfiguration = UserConfiguration & { + /** + * If the browser fails to detect the network changes from Wi-Fi to LAN and vice versa, or you + * get reconnection issues, set the flag to `false`. This allows the SDK reconnection logic to + * take over. + * + * @default `true` + */ + listenToBrowserNetworkEvents?: boolean; + + /** + * Whether PubNub client should spawn `Subscription` service worker for better user presence + * experience or not. + * + * @default `true` (if supported) + */ + enableServiceWorker?: boolean; + + /** + * If set to `true`, SDK will use the same TCP connection for each HTTP request, instead of + * opening a new one for each new request. + * + * @default `true` + */ + keepAlive?: boolean; +}; + +/** + * Apply configuration default values. + * + * @param configuration - User-provided configuration. + */ +export const setDefaults = (configuration: PubNubConfiguration): PubNubConfiguration & ExtendedConfiguration => { + // Force disable service workers if environment doesn't support them. + if ((configuration.enableServiceWorker ?? ENABLE_SERVICE_WORKER) && !('serviceWorker' in navigator)) + configuration.enableServiceWorker = false; + + return { + // Set base configuration defaults. + ...setBaseDefaults(configuration), + // Set platform-specific options. + listenToBrowserNetworkEvents: configuration.listenToBrowserNetworkEvents ?? LISTEN_TO_BROWSER_NETWORK_EVENTS, + enableServiceWorker: configuration.enableServiceWorker ?? ENABLE_SERVICE_WORKER, + keepAlive: configuration.keepAlive ?? KEEP_ALIVE, + }; +}; diff --git a/src/web/index.js b/src/web/index.js deleted file mode 100644 index 24008da2e..000000000 --- a/src/web/index.js +++ /dev/null @@ -1,67 +0,0 @@ -/* eslint no-bitwise: ["error", { "allow": ["~", "&", ">>"] }] */ -/* global navigator, window */ - -import CborReader from 'cbor-js'; -import PubNubCore from '../core/pubnub-common'; -import Networking from '../networking'; -import { decode } from '../core/components/base64_codec'; -import { stringifyBufferKeys } from '../core/components/stringify_buffer_keys'; -import Cbor from '../cbor/common'; -import { del, get, post, patch, getfile, postfile } from '../networking/modules/web-node'; - -import WebCryptography from '../crypto/modules/web'; -import PubNubFile from '../file/modules/web'; -import { CryptoModule, LegacyCryptor, AesCbcCryptor } from '../crypto/modules/WebCryptoModule/webCryptoModule'; - -function sendBeacon(url) { - if (navigator && navigator.sendBeacon) { - navigator.sendBeacon(url); - } else { - return false; - } -} - -export default class extends PubNubCore { - static CryptoModule = CryptoModule; - constructor(setup) { - // extract config. - const { listenToBrowserNetworkEvents = true } = setup; - setup.sdkFamily = 'Web'; - setup.networking = new Networking({ - del, - get, - post, - patch, - sendBeacon, - getfile, - postfile, - }); - setup.cbor = new Cbor((arrayBuffer) => stringifyBufferKeys(CborReader.decode(arrayBuffer)), decode); - - setup.PubNubFile = PubNubFile; - setup.cryptography = new WebCryptography(); - - setup.initCryptoModule = (cryptoConfiguration) => { - return new CryptoModule({ - default: new LegacyCryptor({ - cipherKey: cryptoConfiguration.cipherKey, - useRandomIVs: cryptoConfiguration.useRandomIVs, - }), - cryptors: [new AesCbcCryptor({ cipherKey: cryptoConfiguration.cipherKey })], - }); - }; - - super(setup); - - if (listenToBrowserNetworkEvents) { - // mount network events. - window.addEventListener('offline', () => { - this.networkDownDetected(); - }); - - window.addEventListener('online', () => { - this.networkUpDetected(); - }); - } - } -} diff --git a/src/web/index.ts b/src/web/index.ts new file mode 100644 index 000000000..3d3c5f05c --- /dev/null +++ b/src/web/index.ts @@ -0,0 +1,119 @@ +/* eslint no-bitwise: ["error", { "allow": ["~", "&", ">>"] }] */ +/* global navigator */ + +import CborReader from 'cbor-js'; + +// eslint-disable-next-line max-len +import { SubscriptionServiceWorkerMiddleware } from '../transport/service-worker/subscription-service-worker-middleware'; +import { AesCbcCryptor, LegacyCryptor, WebCryptoModule } from '../crypto/modules/WebCryptoModule/webCryptoModule'; +import { WebReactNativeTransport } from '../transport/web-react-native-transport'; +import { stringifyBufferKeys } from '../core/components/stringify_buffer_keys'; +import { PubNubConfiguration, setDefaults } from './components/configuration'; +import { CryptorConfiguration } from '../core/interfaces/crypto-module'; +import { PubNubFile, PubNubFileParameters } from '../file/modules/web'; +import { makeConfiguration } from '../core/components/configuration'; +import { TokenManager } from '../core/components/token_manager'; +import { PubNubMiddleware } from '../transport/middleware'; +import { decode } from '../core/components/base64_codec'; +import { Transport } from '../core/interfaces/transport'; +import Crypto from '../core/components/cryptography'; +import WebCryptography from '../crypto/modules/web'; +import { PubNubCore } from '../core/pubnub-common'; +import Cbor from '../cbor/common'; + +/** + * PubNub client for browser platform. + */ +export default class PubNub extends PubNubCore { + /** + * Data encryption / decryption module constructor. + */ + static CryptoModule = WebCryptoModule; + + constructor(configuration: PubNubConfiguration) { + const configurationCopy = setDefaults(configuration); + const platformConfiguration = { ...configurationCopy, sdkFamily: 'Web', PubNubFile }; + + // Prepare full client configuration. + const clientConfiguration = makeConfiguration( + platformConfiguration, + (cryptoConfiguration: CryptorConfiguration) => { + if (!cryptoConfiguration.cipherKey) return undefined; + + return new WebCryptoModule({ + default: new LegacyCryptor({ ...cryptoConfiguration }), + cryptors: [new AesCbcCryptor({ cipherKey: cryptoConfiguration.cipherKey })], + }); + }, + ); + + // Prepare Token manager. + const tokenManager = new TokenManager( + new Cbor((arrayBuffer: ArrayBuffer) => stringifyBufferKeys(CborReader.decode(arrayBuffer)), decode), + ); + + // Legacy crypto (legacy data encryption / decryption and request signature support). + let crypto: Crypto | undefined; + if (clientConfiguration.getCipherKey() || clientConfiguration.secretKey) { + crypto = new Crypto({ + secretKey: clientConfiguration.secretKey, + cipherKey: clientConfiguration.getCipherKey(), + useRandomIVs: clientConfiguration.getUseRandomIVs(), + customEncrypt: clientConfiguration.getCustomEncrypt(), + customDecrypt: clientConfiguration.getCustomDecrypt(), + }); + } + + // Setup transport provider. + let transport: Transport = new WebReactNativeTransport( + clientConfiguration.keepAlive, + clientConfiguration.logVerbosity!, + ); + if (configurationCopy.enableServiceWorker) { + // Inject subscription service worker into transport provider stack. + transport = new SubscriptionServiceWorkerMiddleware({ + clientIdentifier: clientConfiguration._instanceId, + subscriptionKey: clientConfiguration.subscribeKey, + sdkVersion: clientConfiguration.getVersion(), + logVerbosity: clientConfiguration.logVerbosity!, + transport, + }); + } + + const transportMiddleware = new PubNubMiddleware({ + clientConfiguration, + tokenManager, + transport, + }); + + super({ + configuration: clientConfiguration, + transport: transportMiddleware, + cryptography: new WebCryptography(), + tokenManager, + crypto, + }); + + if (configuration.listenToBrowserNetworkEvents ?? true) { + window.addEventListener('offline', () => { + this.networkDownDetected(); + }); + + window.addEventListener('online', () => { + this.networkUpDetected(); + }); + } + } + + private networkDownDetected() { + this.listenerManager.announceNetworkDown(); + + if (this._configuration.restore) this.disconnect(); + else this.destroy(true); + } + + private networkUpDetected() { + this.listenerManager.announceNetworkUp(); + this.reconnect(); + } +} diff --git a/test/contract/definitions/auth.ts b/test/contract/definitions/auth.ts index a91dd2731..41c44627d 100644 --- a/test/contract/definitions/auth.ts +++ b/test/contract/definitions/auth.ts @@ -19,7 +19,10 @@ class AuthSteps { private token?: string; - constructor(private manager: PubNubManager, private keyset: AccessManagerKeyset) {} + constructor( + private manager: PubNubManager, + private keyset: AccessManagerKeyset, + ) {} @when('I publish a message using that auth token with channel {string}') public publishMessage() { diff --git a/test/contract/definitions/event-engine.ts b/test/contract/definitions/event-engine.ts index 34eed878f..ef02e4925 100644 --- a/test/contract/definitions/event-engine.ts +++ b/test/contract/definitions/event-engine.ts @@ -36,7 +36,10 @@ class EventEngineSteps { private changelog: Change[] = []; private configuration: any = {}; - constructor(private manager: PubNubManager, private keyset: DemoKeyset) {} + constructor( + private manager: PubNubManager, + private keyset: DemoKeyset, + ) {} private async testDelay(time: number) { return new Promise((resolve) => setTimeout(resolve, time * 1000)); @@ -114,7 +117,7 @@ class EventEngineSteps { @then('I observe the following Events and Invocations of the Presence EE:') async thenIObservePresenceEE(dataTable: DataTable) { const expectedChangelog = dataTable.hashes(); - const actualChangelog = []; + const actualChangelog: { type: string; name: string }[] = []; for (const entry of this.changelog) { if (entry.type === 'eventReceived') { actualChangelog.push({ type: 'event', name: entry.event.type }); @@ -170,10 +173,10 @@ class EventEngineSteps { this.messagePromise = new Promise((resolveMessage) => { this.pubnub?.addListener({ message(messageEvent) { - resolveMessage(messageEvent); + setTimeout(() => resolveMessage(messageEvent), 100); }, status(statusEvent) { - resolveStatus(statusEvent); + setTimeout(() => resolveStatus(statusEvent), 100); }, }); @@ -182,16 +185,16 @@ class EventEngineSteps { }); } - @when('I subscribe with timetoken {int}') + @when(/I subscribe with timetoken (\d*)/) async whenISubscribeWithTimetoken(timetoken: number) { this.statusPromise = new Promise((resolveStatus) => { this.messagePromise = new Promise((resolveMessage) => { this.pubnub?.addListener({ message(messageEvent) { - resolveMessage(messageEvent); + setTimeout(() => resolveMessage(messageEvent), 100); }, status(statusEvent) { - resolveStatus(statusEvent); + setTimeout(() => resolveStatus(statusEvent), 100); }, }); @@ -225,7 +228,7 @@ class EventEngineSteps { thenIObserve(dataTable: DataTable) { const expectedChangelog = dataTable.hashes(); - const actualChangelog = []; + const actualChangelog: { type: string; name: string }[] = []; for (const entry of this.changelog) { if (entry.type === 'eventReceived') { actualChangelog.push({ type: 'event', name: entry.event.type }); @@ -242,7 +245,7 @@ class EventEngineSteps { @then("I don't observe any Events and Invocations of the Presence EE") noeventInvocations() { - const actualChangelog = []; + const actualChangelog: { type: string; name: string }[] = []; for (const entry of this.changelog) { if (entry.type === 'eventReceived') { actualChangelog.push({ type: 'event', name: entry.event.type }); @@ -258,7 +261,9 @@ class EventEngineSteps { @after() dispose() { - (this.pubnub as any).removeAllListeners(); - (this.pubnub as any).eventEngine.dispose(); + if (this.pubnub) { + (this.pubnub as any).removeAllListeners(); + (this.pubnub as any).eventEngine.dispose(); + } } } diff --git a/test/contract/definitions/grant.ts b/test/contract/definitions/grant.ts index dc4cf9365..a0a655f0f 100644 --- a/test/contract/definitions/grant.ts +++ b/test/contract/definitions/grant.ts @@ -26,7 +26,10 @@ class GrantTokenSteps { private resourceName?: string; private resourceType?: ResourceType; - constructor(private manager: PubNubManager, private keyset: AccessManagerKeyset) {} + constructor( + private manager: PubNubManager, + private keyset: AccessManagerKeyset, + ) {} @given('the authorized UUID {string}') public givenAuthorizedUUID(authorizedUUID: string) { diff --git a/test/contract/shared/keysets.ts b/test/contract/shared/keysets.ts index bcdbd5840..fe38c4cff 100644 --- a/test/contract/shared/keysets.ts +++ b/test/contract/shared/keysets.ts @@ -1,9 +1,9 @@ import { Keyset } from './pubnub'; export class AccessManagerKeyset implements Keyset { - publishKey = process.env.PUBLISH_KEY_ACCESS || 'pub-key'; - subscribeKey = process.env.SUBSCRIBE_KEY_ACCESS || 'sub-key'; - secretKey = process.env.SECRET_KEY_ACCESS || 'secret-key'; + subscribeKey = process.env.PAM_SUBSCRIBE_KEY || 'sub-key'; + secretKey = process.env.PAM_SECRET_KEY || 'secret-key'; + publishKey = process.env.PAM_PUBLISH_KEY || 'pub-key'; } export class DemoKeyset implements Keyset { diff --git a/test/contract/shared/pubnub.ts b/test/contract/shared/pubnub.ts index d8d46ad8e..1c0fdbee0 100644 --- a/test/contract/shared/pubnub.ts +++ b/test/contract/shared/pubnub.ts @@ -1,5 +1,4 @@ -import type PubNubType from 'pubnub'; -import PubNub from '../../../lib/node/index.js'; +import PubNubCore from '../../../lib/node/index.js'; export interface Keyset { subscribeKey?: string; @@ -35,8 +34,8 @@ const defaultConfig: Config = { export class PubNubManager { getInstance(config: Config = {}) { - return new (PubNub as any)({ ...defaultConfig, ...config }); + return new (PubNubCore as any)({ ...defaultConfig, ...config }); } } -export type PubNub = PubNubType; +export type PubNub = PubNubCore; diff --git a/test/contract/tsconfig.json b/test/contract/tsconfig.json index 88f3844ab..80e527d98 100644 --- a/test/contract/tsconfig.json +++ b/test/contract/tsconfig.json @@ -1,15 +1,20 @@ { "compilerOptions": { - "module": "commonjs", - "moduleResolution": "node", + "module": "CommonJS", + "moduleResolution": "Node", "resolveJsonModule": true, "experimentalDecorators": true, - "target": "es5", + "emitDecoratorMetadata": true, + "noStrictGenericChecks": true, + "target": "es6", "sourceMap": true, "esModuleInterop": true, "strict": true, "allowJs": true, - "noEmit": true + "noEmit": true, + "noImplicitAny": false }, - "exclude": ["../../lib"] + "exclude": [ + "../../lib" + ] } diff --git a/test/dist/objectsv2.test.js b/test/dist/objectsv2.test.ts similarity index 75% rename from test/dist/objectsv2.test.js rename to test/dist/objectsv2.test.ts index 9b8346a2a..dec3002af 100644 --- a/test/dist/objectsv2.test.js +++ b/test/dist/objectsv2.test.ts @@ -1,36 +1,41 @@ /** */ -import util from 'util' -import PubNub from '../../src/node' +import chaiAsPromised from 'chai-as-promised'; +import chai, { expect } from 'chai'; +import chaiNock from 'chai-nock'; +import assert from 'assert'; -describe('Objects V2 system tests', () => { - const SUBSCRIBE_KEY = 'sub-c-d86a1698-889e-11ea-b883-d2d532c9a1bf'; - const PUBLISH_KEY = 'pub-c-5397272a-7664-4b57-bc91-944977fb3f25'; +import { Listener } from '../../src/core/components/listener_manager'; +import PubNub from '../../src/node'; + +chai.use(chaiAsPromised); +chai.use(chaiNock); +describe('Objects V2 system tests', () => { const TEST_PREFIX = 'objectsV2tests'; const UUID = `${TEST_PREFIX}-main`; const UUID_1 = `${TEST_PREFIX}-uuid-1`; const CHANNEL_1 = `${TEST_PREFIX}-channel-1`; - let pubnub ; + let pubnub: PubNub; const events = []; - const listener = { + const listener: Listener = { objects: (event) => { events.push(event); - } + }, }; before(() => { pubnub = new PubNub({ - subscribeKey: SUBSCRIBE_KEY, - publishKey: PUBLISH_KEY, + subscribeKey: process.env.SUBSCRIBE_KEY || 'demo', + publishKey: process.env.PUBLISH_KEY || 'demo', uuid: UUID, // logVerbosity: true }); - pubnub.subscribe({ channels: [UUID_1] }) + pubnub.subscribe({ channels: [UUID_1] }); pubnub.addListener(listener); }); @@ -58,8 +63,7 @@ describe('Objects V2 system tests', () => { }); it('should get all uuids', async () => { - const result = await pubnub.objects.getAllUUIDMetadata({ include: { totalCount: true }}); - + const result = await pubnub.objects.getAllUUIDMetadata({ include: { totalCount: true } }); expect(result.status).to.equal(200); expect(result.data[0].name).to.equal(USER_NAME); @@ -70,8 +74,8 @@ describe('Objects V2 system tests', () => { channel: CHANNEL_1, data: { name: CHANNEL_NAME, - custom: { foo: true } - } + custom: { foo: true }, + }, }); expect(result.status).to.equal(200); @@ -104,7 +108,7 @@ describe('Objects V2 system tests', () => { it('should get channel members', async () => { const result = await pubnub.objects.getChannelMembers({ channel: CHANNEL_1, - include: { customFields: true } + include: { customFields: true }, }); expect(result.status).to.equal(200); @@ -118,20 +122,20 @@ describe('Objects V2 system tests', () => { customFields: true, customChannelFields: true, channelFields: true, - } + }, }); expect(result.status).to.equal(200); - expect(result.data[0]?.custom?.myData).to.equal(42); - expect(result.data[0]?.channel?.name).to.equal(CHANNEL_NAME); - expect(result.data[0]?.channel?.custom?.foo).to.be.true; + expect(result.data[0].custom?.myData).to.equal(42); + assert('name' in result.data[0].channel); + expect(result.data[0].channel?.name).to.equal(CHANNEL_NAME); + expect(result.data[0].channel?.custom?.foo).to.be.true; }); it('should remove memberships', async () => { - const result = pubnub.objects.removeMemberships({ uuid: UUID_1, channels: [CHANNEL_1] }, (status, result) => { - expect(result.status).to.equal(200); - }); - }) + const result = await pubnub.objects.removeMemberships({ uuid: UUID_1, channels: [CHANNEL_1] }); + expect(result.status).to.equal(200); + }); it('should remove uuid', async () => { const result = await pubnub.objects.removeUUIDMetadata({ uuid: UUID_1 }); diff --git a/test/dist/react-native.test.js b/test/dist/react-native.test.js index 949168e22..ac9da0d05 100644 --- a/test/dist/react-native.test.js +++ b/test/dist/react-native.test.js @@ -31,9 +31,13 @@ describe('#distribution test (rkt-native)', function () { it('should have to subscribe a channel', (done) => { pubnub.addListener({ status: (st) => { - expect(st.operation).to.be.equal('PNSubscribeOperation'); - pubnub.unsubscribeAll() - done(); + try { + expect(st.operation).to.be.equal('PNSubscribeOperation'); + pubnub.unsubscribeAll() + done(); + } catch (error) { + done(error); + } } }); pubnub.subscribe({channels: [myChannel1]}); @@ -47,10 +51,14 @@ describe('#distribution test (rkt-native)', function () { } }, message: (m) => { - expect(m.channel).to.be.equal(myChannel2); - expect(m.message.text).to.be.equal('hello React-Native SDK'); - pubnub.unsubscribeAll() - done(); + try { + expect(m.channel).to.be.equal(myChannel2); + expect(m.message.text).to.be.equal('hello React-Native SDK'); + pubnub.unsubscribeAll() + done(); + } catch (error) { + done(error); + } } }); pubnub.subscribe({channels: [myChannel2]}); @@ -58,17 +66,25 @@ describe('#distribution test (rkt-native)', function () { it('should have to set state', (done) => { pubnub.setState({ channels: [myChannel1], state: { hello: 'there' } }, (status, response) => { - expect(status.error).to.be.equal(false); - expect(response.state.hello).to.be.equal('there'); - done(); + try { + expect(status.error).to.be.equal(false); + expect(response.state.hello).to.be.equal("there"); + done(); + } catch (error) { + done(error); + } }); }); it('should have to get the time', (done) => { pubnub.time((status) => { - expect(status.operation).to.be.equal('PNTimeOperation'); - expect(status.statusCode).to.be.equal(200); - done(); + try { + expect(status.operation).to.be.equal("PNTimeOperation"); + expect(status.statusCode).to.be.equal(200); + done(); + } catch (error) { + done(error); + } }); }); @@ -80,8 +96,12 @@ describe('#distribution test (rkt-native)', function () { count: 1, reverse: false }, function(status, response) { - expect(response.messages).to.have.length(1); - done(); + try { + expect(response.messages).to.have.length(1); + done(); + } catch (error) { + done(error); + } }); }, 3000); }); diff --git a/test/dist/web-titanium.test.js b/test/dist/web-titanium.test.js index 00d1a8e59..862a4bf68 100644 --- a/test/dist/web-titanium.test.js +++ b/test/dist/web-titanium.test.js @@ -13,9 +13,12 @@ var myChannel2 = 'mychannel2' + channelSuffix; var myChanneGroup1 = 'myChannelGroup1' + channelSuffix; describe('#distribution test (titanium)', function () { - before(function () { - pubnub = new PubNub({ subscribeKey: 'demo', publishKey: 'demo', uuid: 'myUUID' }); + pubnub = new PubNub({ + subscribeKey: 'demo', + publishKey: 'demo', + uuid: 'myUUID', + }); }); after(function () { @@ -25,13 +28,17 @@ describe('#distribution test (titanium)', function () { it('should have to subscribe a channel', function (done) { listener = { status: function (st) { - expect(st.operation).to.be.equal('PNSubscribeOperation'); - done(); - } + try { + expect(st.operation).to.be.equal("PNSubscribeOperation"); + done(); + } catch (error) { + done(error); + } + }, }; pubnub.addListener(listener); - pubnub.subscribe({channels: [myChannel1]}); + pubnub.subscribe({ channels: [myChannel1] }); }); it('should have to receive message from a channel', function (done) { @@ -41,43 +48,64 @@ describe('#distribution test (titanium)', function () { listener = pubnub.addListener({ message: function (m) { - expect(m.channel).to.be.equal(myChannel2); - expect(m.message.text).to.be.equal('hello Titanium SDK'); - done(); - } + try { + expect(m.channel).to.be.equal(myChannel2); + expect(m.message.text).to.be.equal("hello Titanium SDK"); + done(); + } catch (error) { + done(error); + } + }, }); - pubnub.subscribe({channels: [myChannel2]}); - pubnub.publish({ channel: myChannel2, message: { text: 'hello Titanium SDK' }}); + pubnub.subscribe({ channels: [myChannel2] }); + setTimeout(function () { + pubnub.publish({ channel: myChannel2, message: { text: 'hello Titanium SDK' } }); + }, 1000); }); it('should have to set state', function (done) { pubnub.setState({ channels: [myChannel1], state: { hello: 'there' } }, function (status, response) { - expect(status.error).to.be.equal(false); - expect(response.state.hello).to.be.equal('there'); - done(); + try { + expect(status.error).to.be.equal(false); + expect(response.state.hello).to.be.equal("there"); + done(); + } catch (error) { + done(error); + } }); }); it('should have to get the time', function (done) { pubnub.time(function (status) { - expect(status.operation).to.be.equal('PNTimeOperation'); - expect(status.statusCode).to.be.equal(200); - done(); + try { + expect(status.operation).to.be.equal("PNTimeOperation"); + expect(status.statusCode).to.be.equal(200); + done(); + } catch (error) { + done(error); + } }); }); it('should have to get the last message', function (done) { // add delay to ensure publish completes setTimeout(function () { - pubnub.history({ - channel: myChannel2, - count: 1, - reverse: false - }, function(status, response) { - expect(response.messages).to.have.length(1); - done(); - }); + pubnub.history( + { + channel: myChannel2, + count: 1, + reverse: false, + }, + function (status, response) { + try { + expect(response.messages).to.have.length(1); + done(); + } catch (error) { + done(error); + } + }, + ); }, 3000); }); @@ -111,10 +139,14 @@ describe('#distribution test (titanium)', function () { // }); it('should have to change the UUID', function (done) { - pubnub.setUUID("CustomUUID"); + pubnub.setUUID('CustomUUID'); - expect(pubnub.getUUID()).to.be.equal("CustomUUID"); - done(); + try { + expect(pubnub.getUUID()).to.be.equal("CustomUUID"); + done(); + } catch (error) { + done(error); + } }); it('should have to unsubscribe', function (done) { @@ -126,15 +158,19 @@ describe('#distribution test (titanium)', function () { pubnub.addListener({ status: function (st) { - expect(st.operation).to.be.equal('PNUnsubscribeOperation'); - - if (!finished) { - // prevent calling done twice - finished = true; - done(); + try { + expect(st.operation).to.be.equal("PNUnsubscribeOperation"); + + if (!finished) { + // prevent calling done twice + finished = true; + done(); + } + } catch (error) { + done(error); } - } + }, }); - pubnub.unsubscribe({channels: [myChannel1]}); + pubnub.unsubscribe({ channels: [myChannel1] }); }); -}); \ No newline at end of file +}); diff --git a/test/feature/file_upload.node.test.js b/test/feature/file_upload.node.test.ts similarity index 71% rename from test/feature/file_upload.node.test.js rename to test/feature/file_upload.node.test.ts index e8a6c3c4e..85cdeb29f 100644 --- a/test/feature/file_upload.node.test.js +++ b/test/feature/file_upload.node.test.ts @@ -1,16 +1,17 @@ /** */ -import util from 'util'; -import { Readable } from 'stream'; +import chaiAsPromised from 'chai-as-promised'; +import chai, { expect } from 'chai'; +import chaiNock from 'chai-nock'; +import assert from 'assert'; +import fs from 'fs'; import PubNub from '../../src/node'; -import fs from 'fs'; +chai.use(chaiAsPromised); +chai.use(chaiNock); describe('File Upload API v1 tests', () => { - const SUBSCRIBE_KEY = 'demo'; - const PUBLISH_KEY = 'demo'; - const ORIGIN = undefined; const TEST_PREFIX = 'javascript-fileUploadApiV1-tests'; @@ -21,12 +22,12 @@ describe('File Upload API v1 tests', () => { const FILE_1 = `${TEST_PREFIX}-file-1`; - let pubnub; + let pubnub: PubNub; describe('with encryption', () => { pubnub = new PubNub({ - subscribeKey: SUBSCRIBE_KEY, - publishKey: PUBLISH_KEY, + subscribeKey: process.env.SUBSCRIBE_KEY || 'demo', + publishKey: process.env.PUBLISH_KEY || 'demo', uuid: UUID, origin: ORIGIN, cipherKey: 'abcdef', @@ -38,8 +39,8 @@ describe('File Upload API v1 tests', () => { describe('without encryption', () => { pubnub = new PubNub({ - subscribeKey: SUBSCRIBE_KEY, - publishKey: PUBLISH_KEY, + subscribeKey: process.env.SUBSCRIBE_KEY || 'demo', + publishKey: process.env.PUBLISH_KEY || 'demo', origin: ORIGIN, uuid: UUID, }); @@ -47,7 +48,7 @@ describe('File Upload API v1 tests', () => { runTests(pubnub); }); - function runTests(pubnub) { + function runTests(pubnub: PubNub) { it('should export File class in PubNub instance', async () => { expect(pubnub.File).to.exist; }); @@ -100,8 +101,8 @@ describe('File Upload API v1 tests', () => { expect(output.toString('utf8')).to.equal(testContent); }).timeout(10000); - let fileId; - let fileName; + let fileId: string; + let fileName: string; it('should handle strings', (done) => { const testContent = `Hello world! ${new Date().toLocaleString()}`; @@ -112,9 +113,15 @@ describe('File Upload API v1 tests', () => { file: { data: testContent, name: 'someFile.txt', mimeType: 'text/plain' }, }, (err, result) => { - expect(err).to.be.null; + try { + expect(err.error).to.be.false; - expect(result.name).to.equal('someFile.txt'); + assert(result !== null); + expect(result.name).to.equal('someFile.txt'); + } catch (error) { + done(error); + return; + } pubnub.downloadFile( { @@ -126,14 +133,19 @@ describe('File Upload API v1 tests', () => { fileId = result.id; fileName = result.name; + assert(file !== null); const output = file.toString('utf8').then((output) => { - expect(output).to.equal(testContent); + try { + expect(output).to.equal(testContent); - done(); + done(); + } catch (error) { + done(error); + } }); - } + }, ); - } + }, ); }).timeout(10000); @@ -156,32 +168,42 @@ describe('File Upload API v1 tests', () => { { channel: CHANNEL_1, file: { data: testContent, name: 'someFile.txt', mimeType: 'text/plain' }, - cipherKey: 'cipherKey' + cipherKey: 'cipherKey', }, (err, result) => { - expect(err).to.be.null; + try { + expect(err.error).to.be.false; - expect(result.name).to.equal('someFile.txt'); + assert(result !== null); + expect(result.name).to.equal('someFile.txt'); + } catch (error) { + done(error); + } pubnub.downloadFile( { channel: CHANNEL_1, - id: result.id, - name: result.name, - cipherKey: 'cipherKey' + id: result!.id, + name: result!.name, + cipherKey: 'cipherKey', }, (err2, file) => { - fileId = result.id; - fileName = result.name; + fileId = result!.id; + fileName = result!.name; + assert(file !== null); const output = file.toString('utf8').then((output) => { - expect(output).to.equal(testContent); + try { + expect(output).to.equal(testContent); - done(); + done(); + } catch (error) { + done(error); + } }); - } + }, ); - } + }, ); }).timeout(10000); } diff --git a/test/feature/file_upload.web.test.js b/test/feature/file_upload.web.test.js index daa68d336..4802981a3 100644 --- a/test/feature/file_upload.web.test.js +++ b/test/feature/file_upload.web.test.js @@ -13,9 +13,6 @@ function urlToFile(url, filename, mimeType) { } describe('test', () => { - const SUBSCRIBE_KEY = 'demo-36'; - const PUBLISH_KEY = 'demo-36'; - const TEST_PREFIX = 'javascript-fileUploadApiV1-tests'; const UUID = `${TEST_PREFIX}-main`; const UUID_1 = `${TEST_PREFIX}-uuid-1`; @@ -24,7 +21,7 @@ describe('test', () => { const FILE_1 = `${TEST_PREFIX}-file-1`; - let pubnub ; + let pubnub; after(() => { pubnub.unsubscribeAll(); @@ -33,8 +30,8 @@ describe('test', () => { describe('with encryption', () => { pubnub = new PubNub({ - subscribeKey: SUBSCRIBE_KEY, - publishKey: PUBLISH_KEY, + subscribeKey: process.env.SUBSCRIBE_KEY || 'demo', + publishKey: process.env.PUBLISH_KEY || 'demo', uuid: UUID, cipherKey: 'abcdef', }); @@ -44,8 +41,8 @@ describe('test', () => { describe('without encryption', () => { pubnub = new PubNub({ - subscribeKey: SUBSCRIBE_KEY, - publishKey: PUBLISH_KEY, + subscribeKey: process.env.SUBSCRIBE_KEY || 'demo', + publishKey: process.env.PUBLISH_KEY || 'demo', uuid: UUID, }); @@ -166,7 +163,7 @@ describe('test', () => { const result = await pubnub.sendFile({ channel: CHANNEL_1, file: { data: testContent, name: 'someFile.txt', mimeType: 'text/plain' }, - cipherKey: 'cipherKey' + cipherKey: 'cipherKey', }); expect(result.name).to.equal('someFile.txt'); @@ -175,7 +172,7 @@ describe('test', () => { channel: CHANNEL_1, id: result.id, name: result.name, - cipherKey: 'cipherKey' + cipherKey: 'cipherKey', }); fileId = result.id; diff --git a/test/integration/components/config.test.js b/test/integration/components/config.test.ts similarity index 86% rename from test/integration/components/config.test.js rename to test/integration/components/config.test.ts index a639494a3..fcdbc6c3b 100644 --- a/test/integration/components/config.test.js +++ b/test/integration/components/config.test.ts @@ -7,11 +7,11 @@ import PubNub from '../../../src/node/index'; describe('components/config', () => { describe('AuthKey parameter', () => { it('get/set', () => { - let pubnub = new PubNub({ + const pubnub = new PubNub({ subscribeKey: 'mySubKey', publishKey: 'myPublishKey', authKey: 'authKey1', - uuid: 'myUUID', + userId: 'myUUID', }); assert.equal(pubnub.getAuthKey(), 'authKey1'); pubnub.setAuthKey('authKey2'); @@ -21,7 +21,7 @@ describe('components/config', () => { describe('uuid Parameter', () => { it('throws when not provided value', () => { - let config = { + const config = { subscribeKey: 'mySubKey', publishKey: 'myPublishKey', authKey: 'authKey1', @@ -32,7 +32,7 @@ describe('components/config', () => { }); it('get/set', () => { - let pubnub = new PubNub({ + const pubnub = new PubNub({ subscribeKey: 'mySubKey', publishKey: 'myPublishKey', uuid: 'uuid1', @@ -43,7 +43,7 @@ describe('components/config', () => { }); it('get/set userId', () => { - let pubnub = new PubNub({ + const pubnub = new PubNub({ subscribeKey: 'mySubKey', publishKey: 'myPublishKey', userId: 'userId1', @@ -54,7 +54,7 @@ describe('components/config', () => { }); it('throws when both userId and uuid are provided', () => { - let config = { subscribeKey: 'demo', publishKey: 'demo', uuid: 'myUuid', userId: 'myUserId' }; + const config = { subscribeKey: 'demo', publishKey: 'demo', uuid: 'myUuid', userId: 'myUserId' }; assert.throws(() => { new PubNub(config); @@ -62,7 +62,7 @@ describe('components/config', () => { }); it('throws when invalid value provided', () => { - let config = { + const config = { subscribeKey: 'mySubKey', publishKey: 'myPublishKey', uuid: ' ', @@ -73,7 +73,7 @@ describe('components/config', () => { }); it('setUUID throws while trying to set invalid uuid', () => { - let pubnub = new PubNub({ + const pubnub = new PubNub({ subscribeKey: 'mySubKey', publishKey: 'myPublishKey', uuid: 'myUUID', diff --git a/test/integration/components/crypto.test.js b/test/integration/components/crypto.test.ts similarity index 83% rename from test/integration/components/crypto.test.js rename to test/integration/components/crypto.test.ts index b425c55ff..d7373805c 100644 --- a/test/integration/components/crypto.test.js +++ b/test/integration/components/crypto.test.ts @@ -1,4 +1,5 @@ /** */ +import { expect } from 'chai'; import PubNub from '../../../src/node'; @@ -8,7 +9,7 @@ describe('components/crypto useRandomIVs', () => { publishKey: 'demo-36', useRandomIVs: true, cipherKey: 'abcdef', - uuid: 'myUUID' + uuid: 'myUUID', }); it('should be able to encrypt and decrypt a message', () => { @@ -21,19 +22,19 @@ describe('components/crypto useRandomIVs', () => { const decrypted = pubnub.decrypt(ciphertext); - expect(decrypted).to.deep.equal(data); + expect(decrypted).to.deep.equal(data, JSON.stringify(decrypted)); }); it('should be able to encrypt and decrypt a message with CryptoModule', () => { - const pubnub = new PubNub({ - subscribeKey: 'demo-36', - publishKey: 'demo-36', - useRandomIVs: true, - cryptoModule: PubNub.CryptoModule.aesCbcCryptoModule({ - cipherKey: 'abcd' - }), - uuid: 'myUUID', - }); + const pubnub = new PubNub({ + subscribeKey: 'demo-36', + publishKey: 'demo-36', + useRandomIVs: true, + cryptoModule: PubNub.CryptoModule.aesCbcCryptoModule({ + cipherKey: 'abcd', + }), + uuid: 'myUUID', + }); const data = { message: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', diff --git a/test/integration/components/listeners.test.js b/test/integration/components/listeners.test.ts similarity index 61% rename from test/integration/components/listeners.test.js rename to test/integration/components/listeners.test.ts index ef54a7d5b..d576d728a 100644 --- a/test/integration/components/listeners.test.js +++ b/test/integration/components/listeners.test.ts @@ -1,10 +1,11 @@ +import { expect } from 'chai'; import nock from 'nock'; -import _ from 'underscore'; -import utils from '../../utils'; +import * as Subscription from '../../../src/core/types/api/subscription'; import PubNub from '../../../src/node/index'; +import utils from '../../utils'; -let pubnub; +let pubnub: PubNub; describe('#listeners', () => { before(() => { @@ -20,14 +21,16 @@ describe('#listeners', () => { pubnub = new PubNub({ subscribeKey: 'mySubKey', publishKey: 'myPublishKey', + origin: 'ps.pndsn.com', uuid: 'myUUID', + // @ts-expect-error Force override default value. + useRequestId: false, enableEventEngine: true, autoNetworkDetection: false, }); }); afterEach(() => { - pubnub.stop(); pubnub.destroy(); }); @@ -39,27 +42,21 @@ describe('#listeners', () => { pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', ee: '', - state: '{}', tt: 0, }) - .reply(200, '{"t":{"t":"3","r":1},"m":[]}'); + .reply(200, '{"t":{"t":"3","r":1},"m":[]}', { 'content-type': 'text/javascript' }); utils .createNock() .get('/v2/subscribe/mySubKey/ch1/0') - .query({ - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - ee: '', - tt: '3', - tr: 1, - }) + .query((object) => object.tt === '3') .reply( 200, '{"t":{"t":"10","r":1},"m":[{"a":"3","f":514,"i":"demo","p":{"t":"17069673079697201","r":33},"k":"demo","c":"ch1","d":{"message":"My message!"}}]}', + { 'content-type': 'text/javascript' }, ); - var channel = pubnub.channel('ch1'); - var subscription = channel.subscription(); - var messagePromise = new Promise((resolveMessage) => + const channel = pubnub.channel('ch1'); + const subscription = channel.subscription(); + const messagePromise = new Promise((resolveMessage) => subscription.addListener({ message: (m) => resolveMessage(m), }), @@ -68,21 +65,21 @@ describe('#listeners', () => { const actual = await messagePromise; expect(JSON.stringify(actual.message)).to.equal('{"message":"My message!"}'); }); + it('should subscribed to channel and presence channels', async () => { utils .createNock() - .get('/v2/subscribe/mySubKey/ch1%2Cch1-pnpres/0') + .get('/v2/subscribe/mySubKey/ch1,ch1-pnpres/0') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', ee: '', - state: '{}', tt: 0, }) - .reply(200, '{"t":{"t":"3","r":1},"m":[]}'); + .reply(200, '{"t":{"t":"3","r":1},"m":[]}', { 'content-type': 'text/javascript' }); utils .createNock() - .get('/v2/subscribe/mySubKey/ch1%2Cch1-pnpres/0') + .get('/v2/subscribe/mySubKey/ch1,ch1-pnpres/0') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -93,11 +90,13 @@ describe('#listeners', () => { .reply( 200, '{"t":{"t":"10","r":1},"m":[{"a":"3","f":514,"i":"demo","p":{"t":"17069673079697201","r":33},"k":"demo","c":"ch1","d":{"message":"My message!"}}]}', + { 'content-type': 'text/javascript' }, ); + nock.enableNetConnect(); const channel = pubnub.channel('ch1'); const subscription = channel.subscription({ receivePresenceEvents: true }); - const messagePromise = new Promise((resolveMessage) => + const messagePromise = new Promise((resolveMessage) => subscription.addListener({ message: (m) => resolveMessage(m), }), @@ -110,18 +109,17 @@ describe('#listeners', () => { it('should work with subscriptionSet', async () => { utils .createNock() - .get('/v2/subscribe/mySubKey/ch1%2Cch2/0') + .get('/v2/subscribe/mySubKey/ch1,ch2/0') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', ee: '', - state: '{}', tt: 0, }) - .reply(200, '{"t":{"t":"3","r":1},"m":[]}'); + .reply(200, '{"t":{"t":"3","r":1},"m":[]}', { 'content-type': 'text/javascript' }); utils .createNock() - .get('/v2/subscribe/mySubKey/ch1%2Cch2/0') + .get('/v2/subscribe/mySubKey/ch1,ch2/0') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -132,12 +130,13 @@ describe('#listeners', () => { .reply( 200, '{"t":{"t":"10","r":1},"m":[{"a":"3","f":514,"i":"demo","p":{"t":"17069673079697201","r":33},"k":"demo","c":"ch1","d":{"message":"My message!"}}]}', + { 'content-type': 'text/javascript' }, ); const channel = pubnub.channel('ch1'); const subscription = channel.subscription(); const subscriptionSet = subscription.addSubscription(pubnub.channel('ch2').subscription()); - const messagePromise = new Promise((resolveMessage) => + const messagePromise = new Promise((resolveMessage) => subscriptionSet.addListener({ message: (m) => resolveMessage(m), }), @@ -150,18 +149,17 @@ describe('#listeners', () => { it('should able to create subscriptionSet', async () => { utils .createNock() - .get('/v2/subscribe/mySubKey/ch1%2Cch2/0') + .get('/v2/subscribe/mySubKey/ch1,ch2/0') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', ee: '', - state: '{}', tt: 0, }) - .reply(200, '{"t":{"t":"3","r":1},"m":[]}'); + .reply(200, '{"t":{"t":"3","r":1},"m":[]}', { 'content-type': 'text/javascript' }); utils .createNock() - .get('/v2/subscribe/mySubKey/ch1%2Cch2/0') + .get('/v2/subscribe/mySubKey/ch1,ch2/0') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -172,11 +170,12 @@ describe('#listeners', () => { .reply( 200, '{"t":{"t":"10","r":1},"m":[{"a":"3","f":514,"i":"demo","p":{"t":"17069673079697201","r":33},"k":"demo","c":"ch1","d":{"message":"My message!"}}]}', + { 'content-type': 'text/javascript' }, ); const subscriptionSet = pubnub.subscriptionSet({ channels: ['ch1', 'ch2'] }); - const messagePromise = new Promise((resolveMessage) => + const messagePromise = new Promise((resolveMessage) => subscriptionSet.addListener({ message: (m) => resolveMessage(m), }), @@ -189,18 +188,17 @@ describe('#listeners', () => { it('subscriptionSet works with add/remove with set', async () => { utils .createNock() - .get('/v2/subscribe/mySubKey/ch3%2Cch4/0') + .get('/v2/subscribe/mySubKey/ch3,ch4/0') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', ee: '', - state: '{}', tt: 0, }) - .reply(200, '{"t":{"t":"3","r":1},"m":[]}'); + .reply(200, '{"t":{"t":"3","r":1},"m":[]}', { 'content-type': 'text/javascript' }); utils .createNock() - .get('/v2/subscribe/mySubKey/ch3%2Cch4/0') + .get('/v2/subscribe/mySubKey/ch3,ch4/0') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -211,6 +209,7 @@ describe('#listeners', () => { .reply( 200, '{"t":{"t":"10","r":1},"m":[{"a":"3","f":514,"i":"demo","p":{"t":"17069673079697201","r":33},"k":"demo","c":"ch3","d":{"message":"My message!"}}]}', + { 'content-type': 'text/javascript' }, ); const subscriptionSetCh34 = pubnub.subscriptionSet({ channels: ['ch3', 'ch4'] }); @@ -223,7 +222,7 @@ describe('#listeners', () => { subscriptionSetCh34.addSubscriptionSet(subscriptionSetCh12); subscriptionSetCh34.removeSubscriptionSet(subscriptionSetCh12); - const messagePromise = new Promise((resolveMessage) => + const messagePromise = new Promise((resolveMessage) => subscriptionSetCh34.addListener({ message: (m) => resolveMessage(m), }), @@ -232,21 +231,21 @@ describe('#listeners', () => { const actual = await messagePromise; expect(JSON.stringify(actual.message)).to.equal('{"message":"My message!"}'); }); + it('listener should route presence event to registered handler', async () => { utils .createNock() - .get('/v2/subscribe/mySubKey/ch1%2Cch1-pnpres/0') + .get('/v2/subscribe/mySubKey/ch1,ch1-pnpres/0') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', ee: '', - state: '{}', tt: 0, }) - .reply(200, '{"t":{"t":"3","r":1},"m":[]}'); + .reply(200, '{"t":{"t":"3","r":1},"m":[]}', { 'content-type': 'text/javascript' }); utils .createNock() - .get('/v2/subscribe/mySubKey/ch1%2Cch1-pnpres/0') + .get('/v2/subscribe/mySubKey/ch1,ch1-pnpres/0') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -257,19 +256,21 @@ describe('#listeners', () => { .reply( 200, '{"t":{"t":"17070458535164862","r":31},"m":[{"a":"0","f":0,"p":{"t":"17070458535164862","r":31},"k":"mySubKey","c":"ch1-pnpres","u":{"pn_action":"join","pn_uuid":"dartClient","pn_timestamp":1707045853,"pn_precise_timestamp":1707045853513,"pn_occupancy":2,"pn_ispresence":1,"pn_channel":"ch1"},"d":{"action":"join","uuid":"p2","timestamp":1707045853,"precise_timestamp":1707045853513,"occupancy":2},"b":"ch1-pnpres"}]}', + { 'content-type': 'text/javascript' }, ); const channel = pubnub.channel('ch1'); const subscription = channel.subscription({ receivePresenceEvents: true }); - const presencePromise = new Promise((resolvePresence) => + const presencePromise = new Promise((resolvePresence) => subscription.addListener({ presence: (p) => resolvePresence(p), }), ); subscription.subscribe(); const actual = await presencePromise; - expect(actual.action).to.equal('join'); - expect(actual.occupancy).to.equal(2); + if (actual.action === 'join') { + expect(actual.occupancy).to.equal(2); + } else throw new Error('Unexpected presence event'); }); it('add/remove listener should work on subscription', async () => { @@ -280,10 +281,9 @@ describe('#listeners', () => { pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', ee: '', - state: '{}', tt: 0, }) - .reply(200, '{"t":{"t":"3","r":1},"m":[]}'); + .reply(200, '{"t":{"t":"3","r":1},"m":[]}', { 'content-type': 'text/javascript' }); utils .createNock() .get('/v2/subscribe/mySubKey/ch1/0') @@ -297,13 +297,14 @@ describe('#listeners', () => { .reply( 200, '{"t":{"t":"10","r":1},"m":[{"a":"3","f":514,"i":"demo","p":{"t":"17069673079697201","r":33},"k":"demo","c":"ch1","d":{"message":"My message!"}}]}', + { 'content-type': 'text/javascript' }, ); - const messages = []; + const messages: Subscription.Message[] = []; const channel = pubnub.channel('ch1'); const subscription = channel.subscription(); - const listener = { message: (m) => messages.push(m) }; + const listener = { message: (m: Subscription.Message) => messages.push(m) }; subscription.addListener(listener); - const messagePromise = new Promise((resolveMessage) => + const messagePromise = new Promise((resolveMessage) => subscription.addListener({ message: (m) => resolveMessage(m), }), @@ -318,19 +319,18 @@ describe('#listeners', () => { it('should work with channel groups and their presence', async () => { utils .createNock() - .get('/v2/subscribe/mySubKey/%2C/0') + .get('/v2/subscribe/mySubKey/,/0') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', ee: '', - state: '{}', tt: 0, 'channel-group': 'cg1,cg1-pnpres', }) - .reply(200, '{"t":{"t":"3","r":1},"m":[]}'); + .reply(200, '{"t":{"t":"3","r":1},"m":[]}', { 'content-type': 'text/javascript' }); utils .createNock() - .get('/v2/subscribe/mySubKey/%2C/0') + .get('/v2/subscribe/mySubKey/,/0') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -342,10 +342,11 @@ describe('#listeners', () => { .reply( 200, '{"t":{"t":"17070655215847224","r":33},"m":[{"a":"0","f":0,"i":"cl1","p":{"t":"17070655215847224","r":31},"k":"mySubKey","c":"ch1","d":{"message":"My message!"},"b":"cg1"}]}', + { 'content-type': 'text/javascript' }, ); - var channelGroup = pubnub.channelGroup('cg1'); - var subscription = channelGroup.subscription({ receivePresenceEvents: true }); - var messagePromise = new Promise((resolveMessage) => + const channelGroup = pubnub.channelGroup('cg1'); + const subscription = channelGroup.subscription({ receivePresenceEvents: true }); + const messagePromise = new Promise((resolveMessage) => subscription.addListener({ message: (m) => resolveMessage(m), }), @@ -363,10 +364,9 @@ describe('#listeners', () => { pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', ee: '', - state: '{}', tt: 0, }) - .reply(200, '{"t":{"t":"3","r":1},"m":[]}'); + .reply(200, '{"t":{"t":"3","r":1},"m":[]}', { 'content-type': 'text/javascript' }); utils .createNock() .get('/v2/subscribe/mySubKey/ch1/0') @@ -380,24 +380,20 @@ describe('#listeners', () => { .reply( 200, '{"t":{"t":"10","r":1},"m":[{"a":"3","f":514,"i":"demo","p":{"t":"17069673079697201","r":33},"k":"demo","c":"ch1","d":{"message":"My message!"}}]}', + { 'content-type': 'text/javascript' }, ); utils .createNock() .get('/v2/subscribe/mySubKey/ch1/0') - .query({ - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - ee: '', - tt: '10', - tr: 1, - }) + .query((object) => object.tt === '10') .reply( 200, '{"t":{"t":"10","r":1},"m":[{"a":"3","f":514,"i":"demo","p":{"t":"17069673079697201","r":33},"k":"demo","c":"ch1","d":{"message":"My message!"}}]}', + { 'content-type': 'text/javascript' }, ); utils .createNock() - .get('/v2/subscribe/mySubKey/ch1%2Cch2/0') + .get('/v2/subscribe/mySubKey/ch1,ch2/0') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -408,10 +404,11 @@ describe('#listeners', () => { .reply( 200, '{"t":{"t":"10","r":1},"m":[{"a":"3","f":514,"i":"demo","p":{"t":"17069673079697201","r":33},"k":"demo","c":"ch1","d":{"message":"My message!"}}]}', + { 'content-type': 'text/javascript' }, ); utils .createNock() - .get('/v2/subscribe/mySubKey/ch1%2Cch2%2Cch3/0') + .get('/v2/subscribe/mySubKey/ch1,ch2,ch3/0') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -422,10 +419,11 @@ describe('#listeners', () => { .reply( 200, '{"t":{"t":"10","r":1},"m":[{"a":"3","f":514,"i":"demo","p":{"t":"17069673079697201","r":33},"k":"demo","c":"ch1","d":{"message":"My message!"}}]}', + { 'content-type': 'text/javascript' }, ); utils .createNock() - .get('/v2/subscribe/mySubKey/ch2%2Cch3/0') + .get('/v2/subscribe/mySubKey/ch2,ch3/0') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -436,39 +434,38 @@ describe('#listeners', () => { .reply( 200, '{"t":{"t":"12","r":1},"m":[{"a":"3","f":514,"i":"demo","p":{"t":"17069673079697201","r":33},"k":"demo","c":"ch2","d":{"ch2":"My message!"}}]}', + { 'content-type': 'text/javascript' }, ); - const messages = []; + const messages: Subscription.Message[] = []; const channel = pubnub.channel('ch1'); const subscription = channel.subscription(); - const listener = { message: (m) => messages.push(m) }; + const listener = { message: (m: Subscription.Message) => messages.push(m) }; subscription.addListener(listener); - const messagePromise = new Promise((resolveMessage) => + const messagePromise = new Promise((resolveMessage) => subscription.addListener({ message: (m) => resolveMessage(m), }), ); subscription.removeListener(listener); subscription.subscribe(); - expect(pubnub.getSubscribedChannels()).to.deep.equal(['ch1']); const actual = await messagePromise; expect(JSON.stringify(actual.message)).to.equal('{"message":"My message!"}'); expect(messages.length).to.equal(0); - const subscriptionCh2 = pubnub.channel('ch2').subscription(); subscriptionCh2.subscribe(); - expect(pubnub.getSubscribedChannels()).to.deep.equal(['ch1', 'ch2']); - const subscriptionCh3 = pubnub.channel('ch3').subscription(); const subscriptionSetCh23 = subscriptionCh3.addSubscription(pubnub.channel('ch2').subscription()); + const messagePromiseChannel2 = new Promise((resolveMessage) => + subscriptionSetCh23.addListener({ + message: (m) => resolveMessage(m), + }), + ); subscriptionSetCh23.subscribe(); - expect(pubnub.getSubscribedChannels()).to.deep.equal(['ch1', 'ch2', 'ch3']); - subscription.unsubscribe(); - expect(pubnub.getSubscribedChannels()).to.deep.equal(['ch2', 'ch3']); - subscriptionCh2.unsubscribe(); - expect(pubnub.getSubscribedChannels()).to.deep.equal(['ch2', 'ch3']); + const actualChannel2MessageAfterOneUnsubCh2 = await messagePromiseChannel2; pubnub.destroy(); + expect(JSON.stringify(actualChannel2MessageAfterOneUnsubCh2.message)).to.equal('{"ch2":"My message!"}'); }); it('should work with event type specific listener registraction', async () => { @@ -479,10 +476,9 @@ describe('#listeners', () => { pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', ee: '', - state: '{}', tt: 0, }) - .reply(200, '{"t":{"t":"3","r":1},"m":[]}'); + .reply(200, '{"t":{"t":"3","r":1},"m":[]}', { 'content-type': 'text/javascript' }); utils .createNock() .get('/v2/subscribe/mySubKey/ch1/0') @@ -496,30 +492,32 @@ describe('#listeners', () => { .reply( 200, '{"t":{"t":"10","r":1},"m":[{"a":"3","f":514,"i":"demo","p":{"t":"17069673079697201","r":33},"k":"demo","c":"ch1","d":{"message":"My message!"}}]}', + { 'content-type': 'text/javascript' }, ); - var channel = pubnub.channel('ch1'); - var subscription = channel.subscription(); - var messagePromise = new Promise((resolveMessage) => (subscription.onMessage = (m) => resolveMessage(m))); + const channel = pubnub.channel('ch1'); + const subscription = channel.subscription(); + const messagePromise = new Promise( + (resolveMessage) => (subscription.onMessage = (m) => resolveMessage(m)), + ); subscription.subscribe(); const actual = await messagePromise; expect(JSON.stringify(actual.message)).to.equal('{"message":"My message!"}'); }); - it('with presence should work with event type specific listener registraction', async () => { + it('with presence should work with event type specific listener registration', async () => { utils .createNock() - .get('/v2/subscribe/mySubKey/ch1%2Cch1-pnpres/0') + .get('/v2/subscribe/mySubKey/ch1,ch1-pnpres/0') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', ee: '', - state: '{}', tt: 0, }) - .reply(200, '{"t":{"t":"3","r":1},"m":[]}'); + .reply(200, '{"t":{"t":"3","r":1},"m":[]}', { 'content-type': 'text/javascript' }); utils .createNock() - .get('/v2/subscribe/mySubKey/ch1%2Cch1-pnpres/0') + .get('/v2/subscribe/mySubKey/ch1,ch1-pnpres/0') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -530,137 +528,26 @@ describe('#listeners', () => { .reply( 200, '{"t":{"t":"10","r":1},"m":[{"a":"4","f":0,"p":{"t":"8","r":2},"k":"subKey","c":"ch1-pnpres","d":{"action": "join", "timestamp": 1461451222, "uuid": "testid", "occupancy": 1},"b":"ch1-pnpres"}]}', + { 'content-type': 'text/javascript' }, ); const channel = pubnub.channel('ch1'); const subscription = channel.subscription({ receivePresenceEvents: true }); - const presencePromise = new Promise( + const presencePromise = new Promise( (resolvePresenceEvent) => (subscription.onPresence = (p) => resolvePresenceEvent(p)), ); subscription.subscribe(); const actual = await presencePromise; - expect(JSON.stringify(actual)).to.equal( - '{"channel":"ch1","subscription":null,"action":"join","timetoken":"8","occupancy":1,"uuid":"testid","timestamp":1461451222,"actualChannel":null,"subscribedChannel":"ch1-pnpres"}', - ); - }); - - it('should work with objects data - membership', async () => { - utils - .createNock() - .get('/v2/subscribe/mySubKey/ch1/0') - .query({ - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - ee: '', - state: '{}', - tt: 0, - }) - .reply(200, '{"t":{"t":"3","r":1},"m":[]}'); - utils - .createNock() - .get('/v2/subscribe/mySubKey/ch1/0') - .query({ - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - ee: '', - tt: '3', - tr: 1, - }) - .reply( - 200, - `{"t":{"t":"17087917617921775","r":31},"m":[{"a":"0","f":0,"e":2,"p":{"t":"17087917617921775","r":31},"k":"mySubKey","c":"ch1","d":{"source":"objects","version":"2.0","event":"set","type":"membership","data":{"channel":{"id":"c1"},"eTag":"AZO/t53al7m8fw","updated":"2024-02-24T16:22:41.786844939Z","uuid":{"id":"userIdTest"}}},"b":"ch1"}]}`, - ); - var channel = pubnub.channel('ch1'); - var subscription = channel.subscription(); - var membershipPromise = new Promise((resolveObjects) => - subscription.addListener({ - objects: (objectsEvent) => resolveObjects(objectsEvent), - }), - ); - subscription.subscribe(); - const actual = await membershipPromise; - expect(JSON.stringify(actual)).to.equal( - `{"channel":"ch1","subscription":null,"timetoken":"17087917617921775","message":{"event":"set","type":"membership","data":{"channel":{"id":"c1"},"eTag":"AZO/t53al7m8fw","updated":"2024-02-24T16:22:41.786844939Z","uuid":{"id":"userIdTest"}}}}`, - ); - }); - - it('should work with objects data - channel', async () => { - utils - .createNock() - .get('/v2/subscribe/mySubKey/ch1/0') - .query({ - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - ee: '', - state: '{}', - tt: 0, - }) - .reply(200, '{"t":{"t":"3","r":1},"m":[]}'); - utils - .createNock() - .get('/v2/subscribe/mySubKey/ch1/0') - .query({ - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - ee: '', - tt: '3', - tr: 1, - }) - .reply( - 200, - `{"t":{"t":"17087625097482155","r":33},"m":[{"a":"0","f":0,"e":2,"p":{"t":"17087625097482155","r":33},"k":"mySubKey","c":"ch1","d":{"source":"objects","version":"2.0","event":"set","type":"channel","data":{"custom":{"occupancy":1},"eTag":"125aasww","id":"user-1","updated":"2024-02-24T08:15:09.744661Z"}},"b":"ch1"}]}`, - ); - var channel = pubnub.channel('ch1'); - var subscription = channel.subscription(); - var objectsEventPromise = new Promise((resolveObjects) => - subscription.addListener({ - objects: (objectsEvent) => resolveObjects(objectsEvent), - }), - ); - subscription.subscribe(); - const actual = await objectsEventPromise; - expect(JSON.stringify(actual)).to.equal( - '{"channel":"ch1","subscription":null,"timetoken":"17087625097482155","message":{"event":"set","type":"channel","data":{"custom":{"occupancy":1},"eTag":"125aasww","id":"user-1","updated":"2024-02-24T08:15:09.744661Z"}}}', - ); - }); - - it('should work with message actions', async () => { - utils - .createNock() - .get('/v2/subscribe/mySubKey/ch1/0') - .query({ - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - ee: '', - state: '{}', - tt: 0, - }) - .reply(200, '{"t":{"t":"3","r":1},"m":[]}'); - utils - .createNock() - .get('/v2/subscribe/mySubKey/ch1/0') - .query({ - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - ee: '', - tt: '3', - tr: 1, - }) - .reply( - 200, - `{"t":{"t":"17087942541729876","r":31},"m":[{"a":"0","f":0,"e":3,"i":"userIdTest","p":{"t":"17087942541729876","r":31},"k":"mySubKey","c":"ch1","d":{"source":"actions","version":"1.0","data":{"messageTimetoken":"17087942466262824","type":"reaction","value":"smiley","actionTimetoken":"17087942541639760"},"event":"added"},"b":"ch1"}]}`, - ); - var channel = pubnub.channel('ch1'); - var subscription = channel.subscription(); - var messageActionPromise = new Promise((resolveMessageActionEvent) => - subscription.addListener({ - messageAction: (messageActionEvent) => resolveMessageActionEvent(messageActionEvent), - }), - ); - subscription.subscribe(); - const actual = await messageActionPromise; - expect(JSON.stringify(actual)).to.equal( - '{"channel":"ch1","subscription":null,"timetoken":"17087942541729876","publisher":"userIdTest","data":{"messageTimetoken":"17087942466262824","actionTimetoken":"17087942541639760","type":"reaction","uuid":"userIdTest","value":"smiley"},"event":"added"}', - ); + expect(actual).to.deep.equal({ + channel: 'ch1', + subscription: 'ch1-pnpres', + action: 'join', + occupancy: 1, + uuid: 'testid', + timestamp: 1461451222, + actualChannel: 'ch1', + subscribedChannel: 'ch1-pnpres', + timetoken: '8', + }); }); }); diff --git a/test/integration/components/networking.test.js b/test/integration/components/networking.test.ts similarity index 54% rename from test/integration/components/networking.test.js rename to test/integration/components/networking.test.ts index 3713d3995..bf27209d1 100644 --- a/test/integration/components/networking.test.js +++ b/test/integration/components/networking.test.ts @@ -3,14 +3,16 @@ import assert from 'assert'; import nock from 'nock'; -import utils from '../../utils'; -import PubNub from '../../../src/node/index'; + +// @ts-expect-error Loading package information. import packageJSON from '../../../package.json'; +import PubNub from '../../../src/node/index'; +import utils from '../../utils'; describe('#components/networking', () => { - let pubnub; - let pubnubPartner; - let pubnubSDKName; + let pubnub: PubNub; + let pubnubPartner: PubNub; + let pubnubSDKName: PubNub; before(() => { nock.disableNetConnect(); @@ -26,17 +28,23 @@ describe('#components/networking', () => { subscribeKey: 'mySubKey', publishKey: 'myPublishKey', uuid: 'myUUID', + // @ts-expect-error Force override default value. + useRequestId: false, }); pubnubPartner = new PubNub({ subscribeKey: 'mySubKey', publishKey: 'myPublishKey', uuid: 'myUUID', partnerId: 'alligator', + // @ts-expect-error Force override default value. + useRequestId: false, }); pubnubSDKName = new PubNub({ subscribeKey: 'mySubKey', publishKey: 'myPublishKey', uuid: 'myUUID', + // @ts-expect-error Force override default value. + useRequestId: false, sdkName: 'custom-sdk/1.0.0', }); }); @@ -50,12 +58,16 @@ describe('#components/networking', () => { uuid: 'myUUID', pnsdk: `PubNub-JS-Nodejs-alligator/${packageJSON.version}`, }) - .reply(200, [14570763868573725]); + .reply(200, ['14570763868573725'], { 'content-type': 'text/javascript' }); pubnubPartner.time((status) => { - assert.equal(status.error, false); - assert.equal(status.statusCode, 200); - done(); + try { + assert.equal(status.error, false); + assert.equal(status.statusCode, 200); + done(); + } catch (error) { + done(error); + } }); }); }); @@ -66,12 +78,16 @@ describe('#components/networking', () => { .createNock() .get('/time/0') .query({ uuid: 'myUUID', pnsdk: 'custom-sdk/1.0.0' }) - .reply(200, [14570763868573725]); + .reply(200, ['14570763868573725'], { 'content-type': 'text/javascript' }); pubnubSDKName.time((status) => { - assert.equal(status.error, false); - assert.equal(status.statusCode, 200); - done(); + try { + assert.equal(status.error, false); + assert.equal(status.statusCode, 200); + done(); + } catch (error) { + done(error); + } }); }); }); @@ -82,12 +98,16 @@ describe('#components/networking', () => { .createNock() .get('/time/0') .query(true) - .reply(200, [14570763868573725]); + .reply(200, ['14570763868573725'], { 'content-type': 'text/javascript' }); pubnub.time((status) => { - assert.equal(status.error, false); - assert.equal(status.statusCode, 200); - done(); + try { + assert.equal(status.error, false); + assert.equal(status.statusCode, 200); + done(); + } catch (error) { + done(error); + } }); }); @@ -96,13 +116,17 @@ describe('#components/networking', () => { .createNock() .get('/time/0') .query(true) - .reply(403, [14570763868573725]); + .reply(403, ['14570763868573725'], { 'content-type': 'text/javascript' }); pubnub.time((status) => { - assert.equal(status.error, true); - assert.equal(status.statusCode, 403); - assert.equal(status.category, 'PNAccessDeniedCategory'); - done(); + try { + assert.equal(status.error, true); + assert.equal(status.statusCode, 403); + assert.equal(status.category, 'PNAccessDeniedCategory'); + done(); + } catch (error) { + done(error); + } }); }); @@ -111,13 +135,17 @@ describe('#components/networking', () => { .createNock() .get('/time/0') .query(true) - .reply(400, [14570763868573725]); + .reply(400, ['14570763868573725'], { 'content-type': 'text/javascript' }); pubnub.time((status) => { - assert.equal(status.error, true); - assert.equal(status.statusCode, 400); - assert.equal(status.category, 'PNBadRequestCategory'); - done(); + try { + assert.equal(status.error, true); + assert.equal(status.statusCode, 400); + assert.equal(status.category, 'PNBadRequestCategory'); + done(); + } catch (error) { + done(error); + } }); }); }); diff --git a/test/integration/components/reconnection_manager.test.js b/test/integration/components/reconnection_manager.test.js deleted file mode 100644 index 632f565b8..000000000 --- a/test/integration/components/reconnection_manager.test.js +++ /dev/null @@ -1,128 +0,0 @@ -/* global describe, beforeEach, it, before, afterEach, after */ -/* eslint no-console: 0 */ - -import assert from 'assert'; -import sinon from 'sinon'; -import nock from 'nock'; -import _ from 'underscore'; - -import utils from '../../utils'; -import PubNub from '../../../src/node/index'; - -describe('#components/reconnection_manger', () => { - let pubnub; - let clock; - - before(() => { - nock.disableNetConnect(); - }); - - after(() => { - nock.enableNetConnect(); - }); - - beforeEach(() => { - nock.cleanAll(); - pubnub = new PubNub({ - subscribeKey: 'mySubKey', - publishKey: 'myPublishKey', - uuid: 'myUUID', - heartbeatInterval: 149, - }); - clock = sinon.useFakeTimers(); - }); - - afterEach(() => { - pubnub.stop(); - clock.restore(); - }); - - it('reports when the network is unreachable', (done) => { - utils - .createNock() - .get('/v2/subscribe/mySubKey/ch1%2Cch2%2Cch1-pnpres%2Cch2-pnpres/0') - .query(true) - .replyWithError({ message: 'Network unavailable', code: 'ENOTFOUND' }); - - utils - .createNock() - .get('/v2/presence/sub-key/mySubKey/channel/ch1%2Cch2/heartbeat') - .query(true) - .replyWithError({ message: 'Network unavailable', code: 'ENOTFOUND' }); - - pubnub.addListener({ - status(statusPayload) { - if (statusPayload.operation !== 'PNSubscribeOperation') return; - let statusWithoutError = _.omit(statusPayload, 'errorData'); - assert.deepEqual( - { - category: 'PNNetworkIssuesCategory', - error: true, - operation: 'PNSubscribeOperation', - }, - statusWithoutError, - ); - done(); - }, - }); - - pubnub.subscribe({ channels: ['ch1', 'ch2'], withPresence: true }); - }); - - it('begins polling and reports reconnects when subscribe is again successful', (done) => { - utils - .createNock() - .get('/v2/subscribe/mySubKey/ch1%2Cch2%2Cch1-pnpres%2Cch2-pnpres/0') - .query(true) - .replyWithError({ message: 'Network unavailable', code: 'ENOTFOUND' }); - - utils - .createNock() - .get('/v2/presence/sub-key/mySubKey/channel/ch1%2Cch2/heartbeat') - .query(true) - .replyWithError({ message: 'Network unavailable', code: 'ENOTFOUND' }); - - utils.createNock().get('/time/0').query(true).reply(200, [14570763868573725]); - - pubnub.addListener({ - status(statusPayload) { - if (statusPayload.category === 'PNNetworkIssuesCategory') { - utils - .createNock() - .get('/v2/subscribe/mySubKey/ch1%2Cch2%2Cch1-pnpres%2Cch2-pnpres/0') - .query(true) - .reply( - 200, - '{"t":{"t":"14607577960932487","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Enter Message Here"},"b":"coolChan-bnel"}]}', - ); - - utils - .createNock() - .get('/v2/presence/sub-key/mySubKey/channel/ch1%2Cch2/heartbeat') - .query(true) - .reply(200, '{"status": 200, "message": "OK", "service": "Presence"}'); - - // Advance the clock so that _performTimeLoop() executes - clock.tick(3500); - } else if (statusPayload.category === 'PNReconnectedCategory') { - assert.deepEqual( - { - category: 'PNReconnectedCategory', - operation: 'PNSubscribeOperation', - currentTimetoken: 0, - lastTimetoken: 0, - }, - statusPayload, - ); - done(); - } - }, - }); - - pubnub.subscribe({ - channels: ['ch1', 'ch2'], - withPresence: true, - withHeathbeats: true, - }); - }); -}); diff --git a/test/integration/components/reconnection_manager.test.ts b/test/integration/components/reconnection_manager.test.ts new file mode 100644 index 000000000..d2afe707a --- /dev/null +++ b/test/integration/components/reconnection_manager.test.ts @@ -0,0 +1,164 @@ +/* global describe, beforeEach, it, before, afterEach, after */ +/* eslint no-console: 0 */ + +import assert from 'assert'; +import _ from 'underscore'; +import sinon from 'sinon'; +import nock from 'nock'; + +import PubNub from '../../../src/node/index'; +import utils from '../../utils'; + +describe('#components/reconnection_manger', () => { + let clock: sinon.SinonFakeTimers; + let pubnub: PubNub; + + before(() => { + nock.disableNetConnect(); + }); + + after(() => { + nock.enableNetConnect(); + }); + + beforeEach(() => { + nock.cleanAll(); + pubnub = new PubNub({ + subscribeKey: 'mySubKey', + publishKey: 'myPublishKey', + origin: 'ps.pndsn.com', + uuid: 'myUUID', + // @ts-expect-error Force override default value. + useRequestId: false, + heartbeatInterval: 149, + }); + clock = sinon.useFakeTimers(); + }); + + afterEach(() => { + pubnub.destroy(); + clock.restore(); + }); + + it('reports when the network is unreachable', (done) => { + utils + .createNock() + .get('/v2/subscribe/mySubKey/ch1,ch1-pnpres,ch2,ch2-pnpres/0') + .query(true) + .replyWithError({ message: 'Network unavailable', code: 'ENOTFOUND' }); + + utils + .createNock() + .get('/v2/presence/sub-key/mySubKey/channel/ch1,ch2/heartbeat') + .query(true) + .replyWithError({ message: 'Network unavailable', code: 'ENOTFOUND' }); + + pubnub.addListener({ + status(statusPayload) { + if (statusPayload.operation !== PubNub.OPERATIONS.PNSubscribeOperation) return; + let statusWithoutError = _.omit(statusPayload, ['errorData', 'statusCode']); + try { + assert.deepEqual( + { + category: PubNub.CATEGORIES.PNNetworkIssuesCategory, + error: true, + operation: PubNub.OPERATIONS.PNSubscribeOperation + }, + statusWithoutError + ); + + utils + .createNock() + .get("/v2/presence/sub-key/mySubKey/channel/ch1,ch2/leave") + .query(true) + .reply(200, "{\"status\": 200, \"message\": \"OK\", \"service\": \"Presence\"}", { + "content-type": "text/javascript" + }); + + done(); + } catch (error) { + done(error); + } + }, + }); + + pubnub.subscribe({ channels: ['ch1', 'ch2'], withPresence: true }); + }); + + it('begins polling and reports reconnects when subscribe is again successful', (done) => { + utils + .createNock() + .get('/v2/subscribe/mySubKey/ch1,ch1-pnpres,ch2,ch2-pnpres/0') + .query(true) + .replyWithError({ message: 'Network unavailable', code: 'ENOTFOUND' }); + + utils + .createNock() + .get('/v2/presence/sub-key/mySubKey/channel/ch1,ch2/heartbeat') + .query(true) + .replyWithError({ message: 'Network unavailable', code: 'ENOTFOUND' }); + + utils + .createNock() + .get('/time/0') + .query(true) + .reply(200, [14570763868573725], { 'content-type': 'text/javascript' }); + + pubnub.addListener({ + status(statusPayload) { + if (statusPayload.category === PubNub.CATEGORIES.PNNetworkIssuesCategory) { + utils + .createNock() + .get('/v2/subscribe/mySubKey/ch1,ch1-pnpres,ch2,ch2-pnpres/0') + .query(true) + .reply( + 200, + '{"t":{"t":"14607577960932487","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Enter Message Here"},"b":"coolChan-bnel"}]}', + { 'content-type': 'text/javascript' }, + ); + + utils + .createNock() + .get('/v2/presence/sub-key/mySubKey/channel/ch1,ch2/heartbeat') + .query(true) + .reply(200, '{"status": 200, "message": "OK", "service": "Presence"}', { + 'content-type': 'text/javascript', + }); + + // Advance the clock so that _performTimeLoop() executes + clock.tick(3500); + } else if (statusPayload.category === PubNub.CATEGORIES.PNReconnectedCategory) { + try { + assert.deepEqual( + { + category: PubNub.CATEGORIES.PNReconnectedCategory, + operation: PubNub.OPERATIONS.PNSubscribeOperation, + currentTimetoken: 0, + lastTimetoken: 0 + }, + statusPayload + ); + + utils + .createNock() + .get("/v2/presence/sub-key/mySubKey/channel/ch1,ch2/leave") + .query(true) + .reply(200, "{\"status\": 200, \"message\": \"OK\", \"service\": \"Presence\"}", { + "content-type": "text/javascript" + }); + + done(); + } catch (error) { + done(error); + } + } + }, + }); + + pubnub.subscribe({ + channels: ['ch1', 'ch2'], + withPresence: true, + withHeartbeats: true, + }); + }); +}); diff --git a/test/integration/components/subscription_manager.test.js b/test/integration/components/subscription_manager.test.ts similarity index 55% rename from test/integration/components/subscription_manager.test.js rename to test/integration/components/subscription_manager.test.ts index dfc871aaf..3a8ebb9c1 100644 --- a/test/integration/components/subscription_manager.test.js +++ b/test/integration/components/subscription_manager.test.ts @@ -2,17 +2,17 @@ /* eslint no-console: 0 */ import assert from 'assert'; -import nock from 'nock'; import _ from 'underscore'; +import nock from 'nock'; -import utils from '../../utils'; import PubNub from '../../../src/node/index'; +import utils from '../../utils'; describe('#components/subscription_manager', () => { - let pubnub; - let pubnubWithPassingHeartbeats; - let pubnubWithLimitedQueue; - let pubnubWithCrypto; + let pubnub: PubNub; + let pubnubWithPassingHeartbeats: PubNub; + let pubnubWithLimitedQueue: PubNub; + let pubnubWithCrypto: PubNub; before(() => { nock.disableNetConnect(); @@ -27,22 +27,31 @@ describe('#components/subscription_manager', () => { pubnub = new PubNub({ subscribeKey: 'mySubKey', publishKey: 'myPublishKey', + origin: 'ps.pndsn.com', uuid: 'myUUID', + // @ts-expect-error Force override default value. + useRequestId: false, autoNetworkDetection: false, heartbeatInterval: 149, }); pubnubWithPassingHeartbeats = new PubNub({ subscribeKey: 'mySubKey', publishKey: 'myPublishKey', + origin: 'ps.pndsn.com', uuid: 'myUUID', + // @ts-expect-error: This configuration option normally is hidden. announceSuccessfulHeartbeats: true, + useRequestId: false, autoNetworkDetection: false, heartbeatInterval: 149, }); pubnubWithLimitedQueue = new PubNub({ subscribeKey: 'mySubKey', publishKey: 'myPublishKey', + origin: 'ps.pndsn.com', uuid: 'myUUID', + // @ts-expect-error Force override default value. + useRequestId: false, requestMessageCountThreshold: 1, autoNetworkDetection: false, heartbeatInterval: 149, @@ -50,7 +59,10 @@ describe('#components/subscription_manager', () => { pubnubWithCrypto = new PubNub({ subscribeKey: 'mySubKey', publishKey: 'myPublishKey', + origin: 'ps.pndsn.com', uuid: 'myUUID', + // @ts-expect-error Force override default value. + useRequestId: false, cryptoModule: PubNub.CryptoModule.aesCbcCryptoModule({ cipherKey: 'cipherKey' }), }); }); @@ -64,7 +76,7 @@ describe('#components/subscription_manager', () => { it('passes the correct message information', (done) => { const scope1 = utils .createNock() - .get('/v2/subscribe/mySubKey/ch1%2Cch2%2Cch1-pnpres%2Cch2-pnpres/0') + .get('/v2/subscribe/mySubKey/ch1,ch1-pnpres,ch2,ch2-pnpres/0') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -72,12 +84,13 @@ describe('#components/subscription_manager', () => { }) .reply( 200, - '{"t":{"t":"3","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1}, "i": "client1", "k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Message"},"b":"coolChan-bnel"}]}' + '{"t":{"t":"3","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1}, "i": "client1", "k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Message"},"b":"coolChan-bnel"}]}', + { 'content-type': 'text/javascript' }, ); const scope2 = utils .createNock() - .get('/v2/subscribe/mySubKey/ch1%2Cch2%2Cch1-pnpres%2Cch2-pnpres/0') + .get('/v2/subscribe/mySubKey/ch1,ch1-pnpres,ch2,ch2-pnpres/0') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -87,12 +100,13 @@ describe('#components/subscription_manager', () => { }) .reply( 200, - '{"t":{"t":"10","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1},"i": "client2", "k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Message3"},"b":"coolChan-bnel"}]}' + '{"t":{"t":"10","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1},"i": "client2", "k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Message3"},"b":"coolChan-bnel"}]}', + { 'content-type': 'text/javascript' }, ); const scope3 = utils .createNock() - .get('/v2/subscribe/mySubKey/ch1%2Cch2%2Cch1-pnpres%2Cch2-pnpres/0') + .get('/v2/subscribe/mySubKey/ch1,ch1-pnpres,ch2,ch2-pnpres/0') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -102,8 +116,14 @@ describe('#components/subscription_manager', () => { }) .reply( 200, - '{"t":{"t":"20","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1},"i": "client3", "k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Message10"},"b":"coolChan-bnel", "u": {"cool": "meta"}}]}' + '{"t":{"t":"20","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1},"i": "client3", "k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Message10"},"b":"coolChan-bnel", "u": {"cool": "meta"}}]}', + { 'content-type': 'text/javascript' }, ); + utils + .createNock() + .get(/heartbeat$/) + .query(true) + .reply(200, '{"status": 200,"message":"OK","service":"Presence"}', { 'content-type': 'text/javascript' }); let incomingPayloads = []; @@ -112,48 +132,53 @@ describe('#components/subscription_manager', () => { incomingPayloads.push(messagePayload); if (incomingPayloads.length === 3) { - assert.equal(scope1.isDone(), true); - assert.equal(scope2.isDone(), true); - assert.equal(scope3.isDone(), true); - assert.deepEqual(incomingPayloads, [ - { - actualChannel: 'coolChannel', - message: { - text: 'Message', + try { + assert.equal(scope1.isDone(), true); + assert.equal(scope2.isDone(), true); + assert.equal(scope3.isDone(), true); + assert.deepEqual(incomingPayloads, [ + { + actualChannel: "coolChannel", + message: { + text: "Message" + }, + subscribedChannel: "coolChan-bnel", + channel: "coolChannel", + subscription: "coolChan-bnel", + timetoken: "14607577960925503", + publisher: "client1" }, - subscribedChannel: 'coolChan-bnel', - channel: 'coolChannel', - subscription: 'coolChan-bnel', - timetoken: '14607577960925503', - publisher: 'client1', - }, - { - actualChannel: 'coolChannel', - message: { - text: 'Message3', + { + actualChannel: "coolChannel", + message: { + text: "Message3" + }, + subscribedChannel: "coolChan-bnel", + channel: "coolChannel", + subscription: "coolChan-bnel", + timetoken: "14607577960925503", + publisher: "client2" }, - subscribedChannel: 'coolChan-bnel', - channel: 'coolChannel', - subscription: 'coolChan-bnel', - timetoken: '14607577960925503', - publisher: 'client2', - }, - { - actualChannel: 'coolChannel', - message: { - text: 'Message10', - }, - userMetadata: { - cool: 'meta', - }, - subscribedChannel: 'coolChan-bnel', - channel: 'coolChannel', - subscription: 'coolChan-bnel', - timetoken: '14607577960925503', - publisher: 'client3', - }, - ]); - done(); + { + actualChannel: "coolChannel", + message: { + text: "Message10" + }, + userMetadata: { + cool: "meta" + }, + subscribedChannel: "coolChan-bnel", + channel: "coolChannel", + subscription: "coolChan-bnel", + timetoken: "14607577960925503", + publisher: "client3" + } + ]); + + done(); + } catch (error) { + done(error); + } } }, }); @@ -164,7 +189,7 @@ describe('#components/subscription_manager', () => { it('passes the correct presence information', (done) => { const scope = utils .createNock() - .get('/v2/subscribe/mySubKey/ch1%2Cch2%2Cch1-pnpres%2Cch2-pnpres/0') + .get('/v2/subscribe/mySubKey/ch1,ch1-pnpres,ch2,ch2-pnpres/0') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -172,28 +197,32 @@ describe('#components/subscription_manager', () => { }) .reply( 200, - '{"t":{"t":"14614512228786519","r":1},"m":[{"a":"4","f":0,"p":{"t":"14614512228418349","r":2},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel-pnpres","d":{"action": "join", "timestamp": 1461451222, "uuid": "4a6d5df7-e301-4e73-a7b7-6af9ab484eb0", "occupancy": 1},"b":"coolChannel-pnpres"}]}' + '{"t":{"t":"14614512228786519","r":1},"m":[{"a":"4","f":0,"p":{"t":"14614512228418349","r":2},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel-pnpres","d":{"action": "join", "timestamp": 1461451222, "uuid": "4a6d5df7-e301-4e73-a7b7-6af9ab484eb0", "occupancy": 1},"b":"coolChannel-pnpres"}]}', + { 'content-type': 'text/javascript' }, ); pubnub.addListener({ presence(presencePayload) { - assert.equal(scope.isDone(), true); - assert.deepEqual( - { - channel: 'coolChannel', - subscription: null, - actualChannel: null, - occupancy: 1, - subscribedChannel: 'coolChannel-pnpres', - timestamp: 1461451222, - timetoken: '14614512228418349', - uuid: '4a6d5df7-e301-4e73-a7b7-6af9ab484eb0', - action: 'join', - state: undefined, - }, - presencePayload - ); - done(); + try { + assert.equal(scope.isDone(), true); + assert.deepEqual( + { + channel: "coolChannel", + subscription: "coolChannel-pnpres", + actualChannel: "coolChannel", + occupancy: 1, + subscribedChannel: "coolChannel-pnpres", + timestamp: 1461451222, + timetoken: "14614512228418349", + uuid: "4a6d5df7-e301-4e73-a7b7-6af9ab484eb0", + action: "join" + }, + presencePayload + ); + done(); + } catch (error) { + done(error); + } }, }); @@ -201,9 +230,10 @@ describe('#components/subscription_manager', () => { }); it('Unknown category status returned when user trigger TypeError in subscription handler', (done) => { - const scope1 = utils + let callDone = false; + utils .createNock() - .get('/v2/subscribe/mySubKey/ch1%2Cch1-pnpres/0') + .get('/v2/subscribe/mySubKey/ch1,ch1-pnpres/0') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -211,48 +241,67 @@ describe('#components/subscription_manager', () => { }) .reply( 200, - '{"t":{"t":"3","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1}, "i": "client1", "k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"ch1","d":{"text":"Message"},"b":"ch1"}]}' + '{"t":{"t":"6","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1}, "i": "client1", "k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"ch1","d":{"text":"Message"},"b":"ch1"}]}', + { 'content-type': 'text/javascript' }, ); - const scope2 = utils + utils .createNock() .get(/heartbeat$/) .query(true) - .reply(200, '{"status": 200,"message":"OK","service":"Presence"}'); - const scope3 = utils + .reply(200, '{"status": 200,"message":"OK","service":"Presence"}', { 'content-type': 'text/javascript' }); + utils .createNock() .get(/leave$/) .query(true) - .reply(200, '{"status": 200,"message":"OK","action":"leave","service":"Presence"}'); - const scope4 = utils + .reply(200, '{"status": 200,"message":"OK","action":"leave","service":"Presence"}', { + 'content-type': 'text/javascript', + }); + utils .createNock() .get('/publish/myPublishKey/mySubKey/0/ch1/0/%7B%22such%22%3A%22object%22%7D') .query(true) - .reply(200, '[1,"Sent","14647523059145592"]'); + .reply(200, '[1,"Sent","14647523059145592"]', { 'content-type': 'text/javascript' }); + + utils + .createNock() + .get('/v2/subscribe/mySubKey/ch1,ch1-pnpres/0') + .query({ + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + uuid: 'myUUID', + heartbeat: 300, + tt: 6, + }) + .reply(200, '{"t":{"t":"9","r":1},"m":[]}', { 'content-type': 'text/javascript' }); pubnub.addListener({ - message(message) { + message(_) { + // @ts-expect-error Intentional exception. null.test; }, status(status) { - if (status.category === "PNUnknownCategory") { - assert.equal(status.errorData instanceof Error, true); - done(); - } else if (status.category === "PNConnectedCategory") { - pubnub.publish( - { message: { such: 'object' }, channel: 'ch1' }, - (status, response) => { } - ); + if (status.category === PubNub.CATEGORIES.PNUnknownCategory && 'statusCode' in status) { + try { + assert.equal(status.errorData instanceof Error, true); + if (!callDone) { + callDone = true; + done(); + } + } catch (error) { + done(error); + } + } else if (status.category === PubNub.CATEGORIES.PNConnectedCategory) { + pubnub.publish({ message: { such: 'object' }, channel: 'ch1' }, () => {}); } - } + }, }); pubnub.subscribe({ channels: ['ch1'], withPresence: true }); }); it('passes the correct presence information when state is changed', (done) => { - const scope = utils + const scope1 = utils .createNock() - .get('/v2/subscribe/mySubKey/ch1%2Cch2%2Cch1-pnpres%2Cch2-pnpres/0') + .get('/v2/subscribe/mySubKey/ch1,ch1-pnpres,ch2,ch2-pnpres/0') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -260,30 +309,46 @@ describe('#components/subscription_manager', () => { }) .reply( 200, - '{"t":{"t":"14637536741734954","r":1},"m":[{"a":"4","f":512,"p":{"t":"14637536740940378","r":1},"k":"demo-36","c":"ch10-pnpres","d":{"action": "join", "timestamp": 1463753674, "uuid": "24c9bb19-1fcd-4c40-a6f1-522a8a1329ef", "occupancy": 3},"b":"ch10-pnpres"},{"a":"4","f":512,"p":{"t":"14637536741726901","r":1},"k":"demo-36","c":"ch10-pnpres","d":{"action": "state-change", "timestamp": 1463753674, "data": {"state": "cool"}, "uuid": "24c9bb19-1fcd-4c40-a6f1-522a8a1329ef", "occupancy": 3},"b":"ch10-pnpres"}]}' + '{"t":{"t":"14637536741734954","r":1},"m":[{"a":"4","f":512,"p":{"t":"14637536740940378","r":1},"k":"demo-36","c":"ch10-pnpres","d":{"action": "join", "timestamp": 1463753674, "uuid": "24c9bb19-1fcd-4c40-a6f1-522a8a1329ef", "occupancy": 3},"b":"ch10-pnpres"},{"a":"4","f":512,"p":{"t":"14637536741726901","r":1},"k":"demo-36","c":"ch10-pnpres","d":{"action": "state-change", "timestamp": 1463753674, "data": {"state": "cool"}, "uuid": "24c9bb19-1fcd-4c40-a6f1-522a8a1329ef", "occupancy": 3},"b":"ch10-pnpres"}]}', + { 'content-type': 'text/javascript' }, ); + utils + .createNock() + .get(/heartbeat$/) + .query(true) + .reply(200, '{"status": 200,"message":"OK","service":"Presence"}'); + utils + .createNock() + .get('/v2/subscribe/mySubKey/ch1,ch1-pnpres,ch2,ch2-pnpres/0') + .query({ + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + uuid: 'myUUID', + heartbeat: 300, + tt: '14637536741734954', + }) + .reply(200, '{"t":{"t":"9","r":1},"m":[]}', { 'content-type': 'text/javascript' }); pubnub.addListener({ presence(presencePayload) { if (presencePayload.action !== 'state-change') return; - - assert.equal(scope.isDone(), true); - assert.deepEqual( - { - channel: 'ch10', - subscription: null, - actualChannel: null, + try { + assert.equal(scope1.isDone(), true); + assert.deepEqual(presencePayload, { + channel: "ch10", + subscription: "ch10-pnpres", + actualChannel: "ch10", occupancy: 3, - subscribedChannel: 'ch10-pnpres', + subscribedChannel: "ch10-pnpres", timestamp: 1463753674, - timetoken: '14637536741726901', - uuid: '24c9bb19-1fcd-4c40-a6f1-522a8a1329ef', - action: 'state-change', - state: { state: 'cool' }, - }, - presencePayload - ); - done(); + timetoken: "14637536741726901", + uuid: "24c9bb19-1fcd-4c40-a6f1-522a8a1329ef", + action: "state-change", + state: { state: "cool" } + }); + done(); + } catch (error) { + done(error); + } }, }); @@ -291,23 +356,34 @@ describe('#components/subscription_manager', () => { }); it('reports when heartbeats failed', (done) => { + utils + .createNock() + .get('/v2/subscribe/mySubKey/ch1,ch1-pnpres,ch2,ch2-pnpres/0') + .query({ + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + uuid: 'myUUID', + heartbeat: 300, + }) + .reply(200, '{"t":{"t":"3","r":1},"m":[]}', { 'content-type': 'text/javascript' }); + pubnub.addListener({ status(statusPayload) { - if ( - statusPayload.operation !== PubNub.OPERATIONS.PNHeartbeatOperation - ) { - return; + if (statusPayload.operation !== PubNub.OPERATIONS.PNHeartbeatOperation) return; + + let statusWithoutError = _.omit(statusPayload, 'errorData', 'statusCode'); + try { + assert.deepEqual( + { + category: PubNub.CATEGORIES.PNUnknownCategory, + error: true, + operation: PubNub.OPERATIONS.PNHeartbeatOperation + }, + statusWithoutError + ); + done(); + } catch (error) { + done(error); } - let statusWithoutError = _.omit(statusPayload, 'errorData'); - assert.deepEqual( - { - category: 'PNUnknownCategory', - error: true, - operation: 'PNHeartbeatOperation', - }, - statusWithoutError - ); - done(); }, }); @@ -321,34 +397,35 @@ describe('#components/subscription_manager', () => { it('reports when heartbeats fail with error code', (done) => { const scope = utils .createNock() - .get('/v2/presence/sub-key/mySubKey/channel/ch1%2Cch2/heartbeat') + .get('/v2/presence/sub-key/mySubKey/channel/ch1,ch2/heartbeat') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', heartbeat: 300, state: '{}', }) - .reply(400, '{"status": 400, "message": "OK", "service": "Presence"}'); + .reply(400, '{"status": 400, "message": "OK", "service": "Presence"}', { 'content-type': 'text/javascript' }); pubnub.addListener({ status(statusPayload) { - if ( - statusPayload.operation !== PubNub.OPERATIONS.PNHeartbeatOperation - ) { - return; - } + if (statusPayload.operation !== PubNub.OPERATIONS.PNHeartbeatOperation) return; + let statusWithoutError = _.omit(statusPayload, 'errorData'); - assert.equal(scope.isDone(), true); - assert.deepEqual( - { - category: 'PNBadRequestCategory', - error: true, - operation: 'PNHeartbeatOperation', - statusCode: 400, - }, - statusWithoutError - ); - done(); + try { + assert.equal(scope.isDone(), true); + assert.deepEqual( + { + category: PubNub.CATEGORIES.PNBadRequestCategory, + error: true, + operation: PubNub.OPERATIONS.PNHeartbeatOperation, + statusCode: 400 + }, + statusWithoutError + ); + done(); + } catch (error) { + done(error); + } }, }); @@ -362,33 +439,34 @@ describe('#components/subscription_manager', () => { it('reports when heartbeats pass', (done) => { const scope = utils .createNock() - .get('/v2/presence/sub-key/mySubKey/channel/ch1%2Cch2/heartbeat') + .get('/v2/presence/sub-key/mySubKey/channel/ch1,ch2/heartbeat') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', heartbeat: 300, state: '{}', }) - .reply(200, '{"status": 200, "message": "OK", "service": "Presence"}'); + .reply(200, '{"status": 200, "message": "OK", "service": "Presence"}', { 'content-type': 'text/javascript' }); pubnubWithPassingHeartbeats.addListener({ status(statusPayload) { - if ( - statusPayload.operation !== PubNub.OPERATIONS.PNHeartbeatOperation - ) { - return; - } + if (statusPayload.operation !== PubNub.OPERATIONS.PNHeartbeatOperation) return; - assert.equal(scope.isDone(), true); - assert.deepEqual( - { - error: false, - operation: 'PNHeartbeatOperation', - statusCode: 200, - }, - statusPayload - ); - done(); + try { + assert.equal(scope.isDone(), true); + assert.deepEqual( + { + error: false, + operation: PubNub.OPERATIONS.PNHeartbeatOperation, + category: PubNub.CATEGORIES.PNAcknowledgmentCategory, + statusCode: 200 + }, + statusPayload + ); + done(); + } catch (error) { + done(error); + } }, }); @@ -402,33 +480,34 @@ describe('#components/subscription_manager', () => { it('reports when heartbeats pass with heartbeatChannels', (done) => { const scope = utils .createNock() - .get('/v2/presence/sub-key/mySubKey/channel/ch1%2Cch2/heartbeat') + .get('/v2/presence/sub-key/mySubKey/channel/ch1,ch2/heartbeat') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', heartbeat: 300, state: '{}', }) - .reply(200, '{"status": 200, "message": "OK", "service": "Presence"}'); + .reply(200, '{"status": 200, "message": "OK", "service": "Presence"}', { 'content-type': 'text/javascript' }); pubnubWithPassingHeartbeats.addListener({ status(statusPayload) { - if ( - statusPayload.operation !== PubNub.OPERATIONS.PNHeartbeatOperation - ) { - return; - } + if (statusPayload.operation !== PubNub.OPERATIONS.PNHeartbeatOperation) return; - assert.equal(scope.isDone(), true); - assert.deepEqual( - { - error: false, - operation: 'PNHeartbeatOperation', - statusCode: 200, - }, - statusPayload - ); - done(); + try { + assert.equal(scope.isDone(), true); + assert.deepEqual( + { + error: false, + operation: PubNub.OPERATIONS.PNHeartbeatOperation, + category: PubNub.CATEGORIES.PNAcknowledgmentCategory, + statusCode: 200 + }, + statusPayload + ); + done(); + } catch (error) { + done(error); + } }, }); @@ -441,7 +520,7 @@ describe('#components/subscription_manager', () => { it('reports when heartbeats pass with heartbeatChannelGroups', (done) => { const scope = utils .createNock() - .get('/v2/presence/sub-key/mySubKey/channel/%2C/heartbeat') + .get('/v2/presence/sub-key/mySubKey/channel/,/heartbeat') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -449,26 +528,27 @@ describe('#components/subscription_manager', () => { state: '{}', 'channel-group': 'cg1', }) - .reply(200, '{"status": 200, "message": "OK", "service": "Presence"}'); + .reply(200, '{"status": 200, "message": "OK", "service": "Presence"}', { 'content-type': 'text/javascript' }); pubnubWithPassingHeartbeats.addListener({ status(statusPayload) { - if ( - statusPayload.operation !== PubNub.OPERATIONS.PNHeartbeatOperation - ) { - return; - } + if (statusPayload.operation !== PubNub.OPERATIONS.PNHeartbeatOperation) return; - assert.equal(scope.isDone(), true); - assert.deepEqual( - { - error: false, - operation: 'PNHeartbeatOperation', - statusCode: 200, - }, - statusPayload - ); - done(); + try { + assert.equal(scope.isDone(), true); + assert.deepEqual( + { + error: false, + operation: PubNub.OPERATIONS.PNHeartbeatOperation, + category: PubNub.CATEGORIES.PNAcknowledgmentCategory, + statusCode: 200 + }, + statusPayload + ); + done(); + } catch (error) { + done(error); + } }, }); @@ -481,7 +561,7 @@ describe('#components/subscription_manager', () => { it('reports when the queue is beyond set threshold', (done) => { const scope = utils .createNock() - .get('/v2/subscribe/mySubKey/ch1%2Cch2%2Cch1-pnpres%2Cch2-pnpres/0') + .get('/v2/subscribe/mySubKey/ch1,ch1-pnpres,ch2,ch2-pnpres/0') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -489,28 +569,32 @@ describe('#components/subscription_manager', () => { }) .reply( 200, - '{"t":{"t":"14614512228786519","r":1},"m":[{"a":"4","f":0,"p":{"t":"14614512228418349","r":2},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel-pnpres","d":{"action": "join", "timestamp": 1461451222, "uuid": "4a6d5df7-e301-4e73-a7b7-6af9ab484eb0", "occupancy": 1},"b":"coolChannel-pnpres"}]}' + '{"t":{"t":"3","r":1},"m":[{"a":"4","f":0,"p":{"t":"14614512228418349","r":2},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel-pnpres","d":{"action": "join", "timestamp": 1461451222, "uuid": "4a6d5df7-e301-4e73-a7b7-6af9ab484eb0", "occupancy": 1},"b":"coolChannel-pnpres"}]}', + { 'content-type': 'text/javascript' }, ); + utils + .createNock() + .get('/v2/subscribe/mySubKey/ch1,ch1-pnpres,ch2,ch2-pnpres/0') + .query({ + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + uuid: 'myUUID', + heartbeat: 300, + tt: 3, + }) + .reply(200, '{"t":{"t":"3","r":1},"m":[]}', { 'content-type': 'text/javascript' }); pubnubWithLimitedQueue.addListener({ status(statusPayload) { - if ( - statusPayload.category !== - PubNub.CATEGORIES.PNRequestMessageCountExceededCategory - ) { - return; - } + if (statusPayload.category !== PubNub.CATEGORIES.PNRequestMessageCountExceededCategory) return; - assert.equal(scope.isDone(), true); - assert.equal( - statusPayload.category, - PubNub.CATEGORIES.PNRequestMessageCountExceededCategory - ); - assert.equal( - statusPayload.operation, - PubNub.OPERATIONS.PNSubscribeOperation - ); - done(); + try { + assert.equal(scope.isDone(), true); + assert.equal(statusPayload.category, PubNub.CATEGORIES.PNRequestMessageCountExceededCategory); + assert.equal(statusPayload.operation, PubNub.OPERATIONS.PNSubscribeOperation); + done(); + } catch (error) { + done(error); + } }, }); @@ -521,12 +605,13 @@ describe('#components/subscription_manager', () => { }); it('supports deduping on duplicates', (done) => { + // @ts-expect-error: This configuration option normally is hidden. pubnub._config.dedupeOnSubscribe = true; let messageCount = 0; utils .createNock() - .get('/v2/subscribe/mySubKey/ch1%2Cch2%2Cch1-pnpres%2Cch2-pnpres/0') + .get('/v2/subscribe/mySubKey/ch1,ch1-pnpres,ch2,ch2-pnpres/0') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -534,12 +619,13 @@ describe('#components/subscription_manager', () => { }) .reply( 200, - '{"t":{"t":"3","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1}, "i": "client1", "k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Message"},"b":"coolChan-bnel"}]}' + '{"t":{"t":"3","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1}, "i": "client1", "k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Message"},"b":"coolChan-bnel"}]}', + { 'content-type': 'text/javascript' }, ); utils .createNock() - .get('/v2/subscribe/mySubKey/ch1%2Cch2%2Cch1-pnpres%2Cch2-pnpres/0') + .get('/v2/subscribe/mySubKey/ch1,ch1-pnpres,ch2,ch2-pnpres/0') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -549,7 +635,8 @@ describe('#components/subscription_manager', () => { }) .reply( 200, - '{"t":{"t":"14607577960932487","r":1},"m":[{"a":"4","f":0,"i":"Publisher-A","p":{"t":"14607577960925503","r":1},"o":{"t":"14737141991877032","r":2},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Message"},"b":"coolChannel"},{"a":"4","f":0,"i":"Publisher-A","p":{"t":"14607577960925503","r":1},"o":{"t":"14737141991877032","r":2},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Message"},"b":"coolChannel"}]}' + '{"t":{"t":"14607577960932487","r":1},"m":[{"a":"4","f":0,"i":"Publisher-A","p":{"t":"14607577960925503","r":1},"o":{"t":"14737141991877032","r":2},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Message"},"b":"coolChannel"},{"a":"4","f":0,"i":"Publisher-A","p":{"t":"14607577960925503","r":1},"o":{"t":"14737141991877032","r":2},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Message"},"b":"coolChannel"}]}', + { 'content-type': 'text/javascript' }, ); pubnub.addListener({ @@ -563,7 +650,7 @@ describe('#components/subscription_manager', () => { setTimeout(() => { if (messageCount === 1) { done(); - } + } else done(new Error(`Received unexpected number of messages: ${messageCount} (expected: 1)`)); }, 250); }); @@ -572,7 +659,7 @@ describe('#components/subscription_manager', () => { utils .createNock() - .get('/v2/subscribe/mySubKey/ch1%2Cch2%2Cch1-pnpres%2Cch2-pnpres/0') + .get('/v2/subscribe/mySubKey/ch1,ch1-pnpres,ch2,ch2-pnpres/0') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -580,12 +667,13 @@ describe('#components/subscription_manager', () => { }) .reply( 200, - '{"t":{"t":"3","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1}, "i": "client1", "k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Message"},"b":"coolChan-bnel"}]}' + '{"t":{"t":"3","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1}, "i": "client1", "k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Message"},"b":"coolChan-bnel"}]}', + { 'content-type': 'text/javascript' }, ); utils .createNock() - .get('/v2/subscribe/mySubKey/ch1%2Cch2%2Cch1-pnpres%2Cch2-pnpres/0') + .get('/v2/subscribe/mySubKey/ch1,ch1-pnpres,ch2,ch2-pnpres/0') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -595,7 +683,8 @@ describe('#components/subscription_manager', () => { }) .reply( 200, - '{"t":{"t":"14607577960932487","r":1},"m":[{"a":"4","f":0,"i":"Publisher-A","p":{"t":"14607577960925503","r":1},"o":{"t":"14737141991877032","r":2},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Message"},"b":"coolChannel"},{"a":"4","f":0,"i":"Publisher-A","p":{"t":"14607577960925503","r":1},"o":{"t":"14737141991877032","r":2},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Message"},"b":"coolChannel"}]}' + '{"t":{"t":"14607577960932487","r":1},"m":[{"a":"4","f":0,"i":"Publisher-A","p":{"t":"14607577960925503","r":1},"o":{"t":"14737141991877032","r":2},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Message"},"b":"coolChannel"},{"a":"4","f":0,"i":"Publisher-A","p":{"t":"14607577960925503","r":1},"o":{"t":"14737141991877032","r":2},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Message"},"b":"coolChannel"}]}', + { 'content-type': 'text/javascript' }, ); pubnub.addListener({ @@ -609,18 +698,20 @@ describe('#components/subscription_manager', () => { setTimeout(() => { if (messageCount === 3) { done(); - } + } else done(new Error(`Received unexpected number of messages: ${messageCount} (expected: 3)`)); }, 250); }); it('supports deduping on shallow queue', (done) => { + // @ts-expect-error: This configuration option normally is hidden. pubnub._config.dedupeOnSubscribe = true; + // @ts-expect-error: This configuration option normally is hidden. pubnub._config.maximumCacheSize = 1; let messageCount = 0; utils .createNock() - .get('/v2/subscribe/mySubKey/ch1%2Cch2%2Cch1-pnpres%2Cch2-pnpres/0') + .get('/v2/subscribe/mySubKey/ch1,ch1-pnpres,ch2,ch2-pnpres/0') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -628,12 +719,13 @@ describe('#components/subscription_manager', () => { }) .reply( 200, - '{"t":{"t":"3","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1}, "i": "client1", "k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Message"},"b":"coolChan-bnel"}]}' + '{"t":{"t":"3","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1}, "i": "client1", "k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Message"},"b":"coolChan-bnel"}]}', + { 'content-type': 'text/javascript' }, ); utils .createNock() - .get('/v2/subscribe/mySubKey/ch1%2Cch2%2Cch1-pnpres%2Cch2-pnpres/0') + .get('/v2/subscribe/mySubKey/ch1,ch1-pnpres,ch2,ch2-pnpres/0') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -643,7 +735,8 @@ describe('#components/subscription_manager', () => { }) .reply( 200, - '{"t":{"t":"14607577960932487","r":1},"m":[{"a":"4","f":0,"i":"Publisher-A","p":{"t":"14607577960925503","r":1},"o":{"t":"14737141991877032","r":2},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Message1"},"b":"coolChannel"},{"a":"4","f":0,"i":"Publisher-A","p":{"t":"14607577960925503","r":1},"o":{"t":"14737141991877032","r":2},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Message2"},"b":"coolChannel"}, {"a":"4","f":0,"i":"Publisher-A","p":{"t":"14607577960925503","r":1},"o":{"t":"14737141991877032","r":2},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Message1"},"b":"coolChannel"}]}' + '{"t":{"t":"14607577960932487","r":1},"m":[{"a":"4","f":0,"i":"Publisher-A","p":{"t":"14607577960925503","r":1},"o":{"t":"14737141991877032","r":2},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Message1"},"b":"coolChannel"},{"a":"4","f":0,"i":"Publisher-A","p":{"t":"14607577960925503","r":1},"o":{"t":"14737141991877032","r":2},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Message2"},"b":"coolChannel"}, {"a":"4","f":0,"i":"Publisher-A","p":{"t":"14607577960925503","r":1},"o":{"t":"14737141991877032","r":2},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Message1"},"b":"coolChannel"}]}', + { 'content-type': 'text/javascript' }, ); pubnub.addListener({ @@ -657,10 +750,10 @@ describe('#components/subscription_manager', () => { setTimeout(() => { if (messageCount === 4) { done(); - } + } else done(new Error(`Received unexpected number of messages: ${messageCount} (expected: 4)`)); }, 250); }); - + it('handles unencrypted message when cryptoModule is configured', (done) => { const scope = utils .createNock() @@ -673,6 +766,7 @@ describe('#components/subscription_manager', () => { .reply( 200, '{"t":{"t":"3","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1}, "i": "client1", "k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":"hello","b":"coolChan-bnel"}]}', + { 'content-type': 'text/javascript' }, ); let incomingPayloads = []; @@ -681,20 +775,24 @@ describe('#components/subscription_manager', () => { message(messagePayload) { incomingPayloads.push(messagePayload); if (incomingPayloads.length === 1) { - assert.equal(scope.isDone(), true); - assert.deepEqual(incomingPayloads, [ - { - actualChannel: 'coolChannel', - message: 'hello', - subscribedChannel: 'coolChan-bnel', - channel: 'coolChannel', - subscription: 'coolChan-bnel', - timetoken: '14607577960925503', - publisher: 'client1', - error: 'Error while decrypting message content: decryption error. invalid header version', - }, - ]); - done(); + try { + assert.equal(scope.isDone(), true); + assert.deepEqual(incomingPayloads, [ + { + actualChannel: "coolChannel", + message: "hello", + subscribedChannel: "coolChan-bnel", + channel: "coolChannel", + subscription: "coolChan-bnel", + timetoken: "14607577960925503", + publisher: "client1", + error: "Error while decrypting message content: Decryption error: invalid header version" + } + ]); + done(); + } catch (error) { + done(error); + } } }, }); @@ -715,6 +813,7 @@ describe('#components/subscription_manager', () => { .reply( 200, '{"t":{"t":"3","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1}, "i": "client1", "k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":"hello","b":"coolChan-bnel"}]}', + { 'content-type': 'text/javascript' }, ); let incomingPayloads = []; @@ -723,20 +822,24 @@ describe('#components/subscription_manager', () => { message(messagePayload) { incomingPayloads.push(messagePayload); if (incomingPayloads.length === 1) { - assert.equal(scope.isDone(), true); - assert.deepEqual(incomingPayloads, [ - { - actualChannel: 'coolChannel', - message: 'hello', - subscribedChannel: 'coolChan-bnel', - channel: 'coolChannel', - subscription: 'coolChan-bnel', - timetoken: '14607577960925503', - publisher: 'client1', - error: 'Error while decrypting message content: decryption error. invalid header version', - }, - ]); - done(); + try { + assert.equal(scope.isDone(), true); + assert.deepEqual(incomingPayloads, [ + { + actualChannel: "coolChannel", + message: "hello", + subscribedChannel: "coolChan-bnel", + channel: "coolChannel", + subscription: "coolChan-bnel", + timetoken: "14607577960925503", + publisher: "client1", + error: "Error while decrypting message content: Decryption error: invalid header version" + } + ]); + done(); + } catch (error) { + done(error); + } } }, }); @@ -756,6 +859,7 @@ describe('#components/subscription_manager', () => { .reply( 200, '{"t":{"t":"3","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1}, "i": "client1", "k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":"UE5FRAFBQ1JIEIocqA6BfaybN/3U0WJRam0v3bPwfAXezgeCeGp+MztQ","b":"coolChan-bnel"}]}', + { 'content-type': 'text/javascript' }, ); let incomingPayloads = []; @@ -764,19 +868,23 @@ describe('#components/subscription_manager', () => { message(messagePayload) { incomingPayloads.push(messagePayload); if (incomingPayloads.length === 1) { - assert.equal(scope.isDone(), true); - assert.deepEqual(incomingPayloads, [ - { - actualChannel: 'coolChannel', - message: 'hello', - subscribedChannel: 'coolChan-bnel', - channel: 'coolChannel', - subscription: 'coolChan-bnel', - timetoken: '14607577960925503', - publisher: 'client1', - }, - ]); - done(); + try { + assert.equal(scope.isDone(), true); + assert.deepEqual(incomingPayloads, [ + { + actualChannel: "coolChannel", + message: "hello", + subscribedChannel: "coolChan-bnel", + channel: "coolChannel", + subscription: "coolChan-bnel", + timetoken: "14607577960925503", + publisher: "client1" + } + ]); + done(); + } catch (error) { + done(error); + } } }, }); diff --git a/test/integration/components/token_manager.test.js b/test/integration/components/token_manager.test.ts similarity index 60% rename from test/integration/components/token_manager.test.js rename to test/integration/components/token_manager.test.ts index 3dd26f60c..99751afa4 100644 --- a/test/integration/components/token_manager.test.js +++ b/test/integration/components/token_manager.test.ts @@ -2,16 +2,19 @@ /* eslint no-console: 0 */ import assert from 'assert'; + import PubNub from '../../../src/node/index'; describe('#components/token_manager', () => { - let pubnub; + let pubnub: PubNub; beforeEach(() => { pubnub = new PubNub({ subscribeKey: 'mySubKey', publishKey: 'myPublishKey', - uuid: 'myUUID' + uuid: 'myUUID', + // @ts-expect-error Force override default value. + useRequestId: false, }); }); @@ -23,8 +26,9 @@ describe('#components/token_manager', () => { }); it('contains correct permissions', () => { - let tokenWithAll = 'p0F2AkF0GmEK-4NDdHRsGDxDcmVzpURjaGFuoWhjaGFubmVsMQFDZ3JwoWZncm91cDEBQ3VzcqBDc3BjoER1dWlkoWV1c2VyMQFDcGF0pURjaGFuoWIuKgFDZ3JwoWIuKgFDdXNyoENzcGOgRHV1aWShYi4qAURtZXRhoENzaWdYII5bQpWLi6Z-l5jbShWxZ7QL6o8Dz6_vxluhxrMGzQCN'; - let permissions = pubnub.parseToken(tokenWithAll); + let tokenWithAll = + 'p0F2AkF0GmEK-4NDdHRsGDxDcmVzpURjaGFuoWhjaGFubmVsMQFDZ3JwoWZncm91cDEBQ3VzcqBDc3BjoER1dWlkoWV1c2VyMQFDcGF0pURjaGFuoWIuKgFDZ3JwoWIuKgFDdXNyoENzcGOgRHV1aWShYi4qAURtZXRhoENzaWdYII5bQpWLi6Z-l5jbShWxZ7QL6o8Dz6_vxluhxrMGzQCN'; + let permissions = pubnub.parseToken(tokenWithAll)!; assert(permissions.version === 2); assert(permissions.timestamp === 1628109699); @@ -32,6 +36,7 @@ describe('#components/token_manager', () => { assert(permissions.meta === undefined); assert(permissions.signature instanceof Buffer); + assert(permissions.resources !== undefined); assert(typeof permissions.resources === 'object'); assert(typeof permissions.resources.uuids === 'object'); assert(typeof permissions.resources.channels === 'object'); @@ -42,19 +47,26 @@ describe('#components/token_manager', () => { assert(typeof permissions.patterns.channels === 'object'); assert(typeof permissions.patterns.groups === 'object'); + assert(permissions.resources.uuids.user1 !== undefined); assert(permissions.resources.uuids.user1.read === true); + assert(permissions.resources.channels.channel1 !== undefined); assert(permissions.resources.channels.channel1.read === true); + assert(permissions.resources.groups.group1 !== undefined); assert(permissions.resources.groups.group1.read === true); + assert(permissions.patterns.uuids['.*'] !== undefined); assert(permissions.patterns.uuids['.*'].read === true); + assert(permissions.patterns.channels['.*'] !== undefined); assert(permissions.patterns.channels['.*'].read === true); + assert(permissions.patterns.groups['.*'] !== undefined); assert(permissions.patterns.groups['.*'].read === true); }); }); describe('supports token update', () => { it('support get and set token', () => { - let token = 'p0F2AkF0GmEK8NZDdHRsGDxDcmVzpURjaGFuoENncnCgQ3VzcqBDc3BjoER1dWlkoWV1c2VyMRhoQ3BhdKVEY2hhbqBDZ3JwoEN1c3KgQ3NwY6BEdXVpZKBEbWV0YaBDc2lnWCB6sYaT3ZbNVV6TBxDKGvdOk6TSQRMoRZir4cwoN9-_dA=='; + let token = + 'p0F2AkF0GmEK8NZDdHRsGDxDcmVzpURjaGFuoENncnCgQ3VzcqBDc3BjoER1dWlkoWV1c2VyMRhoQ3BhdKVEY2hhbqBDZ3JwoEN1c3KgQ3NwY6BEdXVpZKBEbWV0YaBDc2lnWCB6sYaT3ZbNVV6TBxDKGvdOk6TSQRMoRZir4cwoN9-_dA=='; // has uuid id 'user1' pubnub.setToken(token); @@ -65,8 +77,10 @@ describe('#components/token_manager', () => { }); it('adding new token replaces previous', () => { - let token = 'p0F2AkF0GmEK8NZDdHRsGDxDcmVzpURjaGFuoENncnCgQ3VzcqBDc3BjoER1dWlkoWV1c2VyMRhoQ3BhdKVEY2hhbqBDZ3JwoEN1c3KgQ3NwY6BEdXVpZKBEbWV0YaBDc2lnWCB6sYaT3ZbNVV6TBxDKGvdOk6TSQRMoRZir4cwoN9-_dA=='; - let token2 = 'p0F2AkF0GmEK8LFDdHRsGDxDcmVzpURjaGFuoENncnCgQ3VzcqBDc3BjoER1dWlkoWV1c2VyMhhoQ3BhdKVEY2hhbqBDZ3JwoEN1c3KgQ3NwY6BEdXVpZKBEbWV0YaBDc2lnWCDq63hdreA9JbHVnHLDJuHzK-AWSdcVFZKG0nse79JMZw=='; + let token = + 'p0F2AkF0GmEK8NZDdHRsGDxDcmVzpURjaGFuoENncnCgQ3VzcqBDc3BjoER1dWlkoWV1c2VyMRhoQ3BhdKVEY2hhbqBDZ3JwoEN1c3KgQ3NwY6BEdXVpZKBEbWV0YaBDc2lnWCB6sYaT3ZbNVV6TBxDKGvdOk6TSQRMoRZir4cwoN9-_dA=='; + let token2 = + 'p0F2AkF0GmEK8LFDdHRsGDxDcmVzpURjaGFuoENncnCgQ3VzcqBDc3BjoER1dWlkoWV1c2VyMhhoQ3BhdKVEY2hhbqBDZ3JwoEN1c3KgQ3NwY6BEdXVpZKBEbWV0YaBDc2lnWCDq63hdreA9JbHVnHLDJuHzK-AWSdcVFZKG0nse79JMZw=='; // has uuid id 'uuid1' pubnub.setToken(token); diff --git a/test/integration/endpoints/access.test.js b/test/integration/endpoints/access.test.ts similarity index 53% rename from test/integration/endpoints/access.test.js rename to test/integration/endpoints/access.test.ts index b98e4ff8d..75f40c5f6 100644 --- a/test/integration/endpoints/access.test.js +++ b/test/integration/endpoints/access.test.ts @@ -2,21 +2,19 @@ /* eslint no-console: 0 */ import assert from 'assert'; -import nock from 'nock'; import sinon from 'sinon'; +import nock from 'nock'; -import utils from '../../utils'; import PubNub from '../../../src/node/index'; +import utils from '../../utils'; describe('access endpoints', () => { - let pubnub; - let clock; + let clock: sinon.SinonFakeTimers; + let pubnub: PubNub; before(() => { nock.disableNetConnect(); - clock = sinon.useFakeTimers( - new Date(Date.UTC(2011, 9, 1, 0, 0, 0)).getTime() - ); + clock = sinon.useFakeTimers(new Date(Date.UTC(2011, 9, 1, 0, 0, 0)).getTime()); }); after(() => { @@ -30,6 +28,9 @@ describe('access endpoints', () => { subscribeKey: 'mySubscribeKey', publishKey: 'myPublishKey', secretKey: 'mySecretKey', + origin: 'ps.pndsn.com', + // @ts-expect-error Remove request identifier to match with hardcoded test signature + useRequestId: false, uuid: 'myUUID', }); pubnub._config.getVersion = () => 'suchJavascript'; @@ -49,26 +50,31 @@ describe('access endpoints', () => { }) .reply( 200, - '{"message":"Success","payload":{"level":"channel-group+auth","subscribe_key":"mySubscribeKey","channel-group":"cg2","auths":{"key1":{"r":1,"m":1,"w":1,"d":1}}},"service":"Access Manager","status":200}' + '{"message":"Success","payload":{"level":"channel-group+auth","subscribe_key":"mySubscribeKey","channel-group":"cg2","auths":{"key1":{"r":1,"m":1,"w":1,"d":1}}},"service":"Access Manager","status":200}', + { 'content-type': 'text/javascript' }, ); pubnub.audit({ channel: 'ch1' }, (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response, { - level: 'channel-group+auth', - subscribe_key: 'mySubscribeKey', - 'channel-group': 'cg2', - auths: { - key1: { - r: 1, - m: 1, - w: 1, - d: 1, - }, - }, - }); - assert.equal(scope.isDone(), true); - done(); + try { + assert.equal(status.error, false); + assert.deepEqual(response, { + level: "channel-group+auth", + subscribe_key: "mySubscribeKey", + "channel-group": "cg2", + auths: { + key1: { + r: 1, + m: 1, + w: 1, + d: 1 + } + } + }); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } }); }); @@ -85,26 +91,31 @@ describe('access endpoints', () => { }) .reply( 200, - '{"message":"Success","payload":{"level":"channel-group+auth","subscribe_key":"mySubscribeKey","channel-group":"cg2","auths":{"key1":{"r":1,"m":1,"w":1,"d":1}}},"service":"Access Manager","status":200}' + '{"message":"Success","payload":{"level":"channel-group+auth","subscribe_key":"mySubscribeKey","channel-group":"cg2","auths":{"key1":{"r":1,"m":1,"w":1,"d":1}}},"service":"Access Manager","status":200}', + { 'content-type': 'text/javascript' }, ); pubnub.audit({ channelGroup: 'cg1' }, (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response, { - level: 'channel-group+auth', - subscribe_key: 'mySubscribeKey', - 'channel-group': 'cg2', - auths: { - key1: { - r: 1, - m: 1, - w: 1, - d: 1, - }, - }, - }); - assert.equal(scope.isDone(), true); - done(); + try { + assert.equal(status.error, false); + assert.deepEqual(response, { + level: "channel-group+auth", + subscribe_key: "mySubscribeKey", + "channel-group": "cg2", + auths: { + key1: { + r: 1, + m: 1, + w: 1, + d: 1 + } + } + }); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } }); }); @@ -121,26 +132,31 @@ describe('access endpoints', () => { }) .reply( 200, - '{"message":"Success","payload":{"level":"channel-group+auth","subscribe_key":"mySubscribeKey","channel-group":"cg2","auths":{"key1":{"r":1,"m":1,"w":1,"d":1}}},"service":"Access Manager","status":200}' + '{"message":"Success","payload":{"level":"channel-group+auth","subscribe_key":"mySubscribeKey","channel-group":"cg2","auths":{"key1":{"r":1,"m":1,"w":1,"d":1}}},"service":"Access Manager","status":200}', + { 'content-type': 'text/javascript' }, ); pubnub.audit({ authKeys: ['key1', 'key2'] }, (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response, { - level: 'channel-group+auth', - subscribe_key: 'mySubscribeKey', - 'channel-group': 'cg2', - auths: { - key1: { - r: 1, - m: 1, - w: 1, - d: 1, - }, - }, - }); - assert.equal(scope.isDone(), true); - done(); + try { + assert.equal(status.error, false); + assert.deepEqual(response, { + level: "channel-group+auth", + subscribe_key: "mySubscribeKey", + "channel-group": "cg2", + auths: { + key1: { + r: 1, + m: 1, + w: 1, + d: 1 + } + } + }); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } }); }); }); @@ -163,21 +179,23 @@ describe('access endpoints', () => { d: 0, g: 0, j: 0, - u: 0 + u: 0, }) .reply( 200, - '{"message":"Success","payload":{"level":"channel-group+auth","subscribe_key":"mySubscribeKey","channel-group":"cg2","auths":{"key1":{"r":0,"m":0,"w":0,"d":0}}},"service":"Access Manager","status":200}' + '{"message":"Success","payload":{"level":"channel-group+auth","subscribe_key":"mySubscribeKey","channel-group":"cg2","auths":{"key1":{"r":0,"m":0,"w":0,"d":0}}},"service":"Access Manager","status":200}', + { 'content-type': 'text/javascript' }, ); - pubnub.grant( - { channels: ['ch1', 'ch2'], authKeys: ['key1', 'key2'] }, - (status) => { + pubnub.grant({ channels: ['ch1', 'ch2'], authKeys: ['key1', 'key2'] }, (status) => { + try { assert.equal(status.error, false); assert.equal(scope.isDone(), true); done(); + } catch (error) { + done(error); } - ); + }); }); it('issues the correct RESTful request for channels groups', (done) => { @@ -197,11 +215,12 @@ describe('access endpoints', () => { d: 0, g: 0, j: 0, - u: 0 + u: 0, }) .reply( 200, - '{"message":"Success","payload":{"level":"channel-group+auth","subscribe_key":"mySubscribeKey","channel-group":"cg2","auths":{"key1":{"r":1,"m":1,"w":1,"d":1}}},"service":"Access Manager","status":200}' + '{"message":"Success","payload":{"level":"channel-group+auth","subscribe_key":"mySubscribeKey","channel-group":"cg2","auths":{"key1":{"r":1,"m":1,"w":1,"d":1}}},"service":"Access Manager","status":200}', + { 'content-type': 'text/javascript' }, ); pubnub.grant( @@ -212,10 +231,14 @@ describe('access endpoints', () => { write: true, }, (status) => { - assert.equal(status.error, false); - assert.equal(scope.isDone(), true); - done(); - } + try { + assert.equal(status.error, false); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }, ); }); @@ -237,11 +260,12 @@ describe('access endpoints', () => { ttl: 1337, g: 0, j: 0, - u: 0 + u: 0, }) .reply( 200, - '{"message":"Success","payload":{"level":"channel-group+auth","subscribe_key":"mySubscribeKey","channel-group":"cg2","auths":{"key1":{"r":1,"m":0,"w":1,"d":0}}},"service":"Access Manager","status":200}' + '{"message":"Success","payload":{"level":"channel-group+auth","subscribe_key":"mySubscribeKey","channel-group":"cg2","auths":{"key1":{"r":1,"m":0,"w":1,"d":0}}},"service":"Access Manager","status":200}', + { 'content-type': 'text/javascript' }, ); pubnub.grant( @@ -253,10 +277,14 @@ describe('access endpoints', () => { ttl: 1337, }, (status) => { - assert.equal(status.error, false); - assert.equal(scope.isDone(), true); - done(); - } + try { + assert.equal(status.error, false); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }, ); }); @@ -277,26 +305,27 @@ describe('access endpoints', () => { d: 1, g: 1, j: 0, - u: 1 + u: 1, }) .reply( 200, - '{"message":"Success","payload":{"level":"uuid","subscribe_key":"mySubscribeKey","target-uuid":"uuid-1,uuid-2","auths":{"key1":{"r":0,"m":0,"w":0,"d":0}}},"service":"Access Manager","status":200}' + '{"message":"Success","payload":{"level":"uuid","subscribe_key":"mySubscribeKey","target-uuid":"uuid-1,uuid-2","auths":{"key1":{"r":0,"m":0,"w":0,"d":0}}},"service":"Access Manager","status":200}', + { 'content-type': 'text/javascript' }, ); pubnub.grant( - { uuids: ['uuid-1', 'uuid-2'], - authKeys: ['key1', 'key2'], - get: true, - update: true, - delete: true}, + { uuids: ['uuid-1', 'uuid-2'], authKeys: ['key1', 'key2'], get: true, update: true, delete: true }, (status) => { - assert.equal(status.error, false); - assert.equal(scope.isDone(), true); - done(); - } + try { + assert.equal(status.error, false); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }, ); - }); + }); it('issues the correct RESTful request for uuids w/ ttl', (done) => { const scope = utils .createNock() @@ -315,11 +344,12 @@ describe('access endpoints', () => { ttl: 1337, g: 1, j: 0, - u: 1 + u: 1, }) .reply( 200, - '{"message":"Success","payload":{"level":"uuid","subscribe_key":"mySubscribeKey","target-uuid":"uuid-1,uuid-2","auths":{"key1":{"r":0,"m":0,"w":0,"d":1,"j":0,"g":1,"u":1}}},"service":"Access Manager","status":200}' + '{"message":"Success","payload":{"level":"uuid","subscribe_key":"mySubscribeKey","target-uuid":"uuid-1,uuid-2","auths":{"key1":{"r":0,"m":0,"w":0,"d":1,"j":0,"g":1,"u":1}}},"service":"Access Manager","status":200}', + { 'content-type': 'text/javascript' }, ); pubnub.grant( @@ -332,139 +362,163 @@ describe('access endpoints', () => { ttl: 1337, }, (status) => { - assert.equal(status.error, false); - assert.equal(scope.isDone(), true); - done(); - } + try { + assert.equal(status.error, false); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }, ); }); - describe('##validation', () => { - it('channelGroups and uuids in single request', (done) => { - const scope = utils - .createNock() - .get('/v2/auth/grant/sub-key/mySubscribeKey') - .query({ - timestamp: 1317427200, - 'channel-group': 'cg1,cg2', - 'target-uuid': 'uuid-1, uuid-2', - auth: 'key1,key2', - uuid: 'myUUID', - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - signature: 'v2.zneRpaqzdxJPegBrJHWMzj-mD8QVBxqh8Zl15N7n2d4', - r: 1, - w: 1, - m: 0, - d: 0, - ttl: 1337, - g: 0, - j: 0, - u: 0 - }) - .reply( - 200, - '{"message":"Success","payload":{"level":"channel-group+auth","subscribe_key":"mySubscribeKey","channel-group":"cg2","auths":{"key1":{"r":1,"m":0,"w":1,"d":0}}},"service":"Access Manager","status":200}' - ); - pubnub.grant( - { - channelGroups: ['cg1', 'cg2'], - uuids: ['uuid-1', 'uuid-2'], - authKeys: ['key1', 'key2'], - read: true, - write: true, - ttl: 1337, - } - ).catch((error) => { - assert.equal(scope.isDone(), false); - assert.equal(error.status.message, 'Both channel/channelgroup and uuid cannot be used in the same request'); - done(); + describe('##validation', () => { + it('channelGroups and uuids in single request', (done) => { + const scope = utils + .createNock() + .get('/v2/auth/grant/sub-key/mySubscribeKey') + .query({ + timestamp: 1317427200, + 'channel-group': 'cg1,cg2', + 'target-uuid': 'uuid-1, uuid-2', + auth: 'key1,key2', + uuid: 'myUUID', + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + signature: 'v2.zneRpaqzdxJPegBrJHWMzj-mD8QVBxqh8Zl15N7n2d4', + r: 1, + w: 1, + m: 0, + d: 0, + ttl: 1337, + g: 0, + j: 0, + u: 0, + }) + .reply( + 200, + '{"message":"Success","payload":{"level":"channel-group+auth","subscribe_key":"mySubscribeKey","channel-group":"cg2","auths":{"key1":{"r":1,"m":0,"w":1,"d":0}}},"service":"Access Manager","status":200}', + { 'content-type': 'text/javascript' }, + ); + + pubnub + .grant({ + channelGroups: ['cg1', 'cg2'], + uuids: ['uuid-1', 'uuid-2'], + authKeys: ['key1', 'key2'], + read: true, + write: true, + ttl: 1337, + }) + .catch((error) => { + try { + assert.equal(scope.isDone(), false); + assert.equal( + error.status.message, + "Both channel/channel group and uuid cannot be used in the same request" + ); + done(); + } catch (error) { + done(error); + } + }); }); - }); - it('channels and uuids in single request', (done) => { - const scope = utils - .createNock() - .get('/v2/auth/grant/sub-key/mySubscribeKey') - .query({ - timestamp: 1317427200, - 'channel': 'ch1,ch2', - 'target-uuid': 'uuid-1, uuid-2', - auth: 'key1,key2', - uuid: 'myUUID', - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - signature: 'v2.zneRpaqzdxJPegBrJHWMzj-mD8QVBxqh8Zl15N7n2d4', - r: 1, - w: 1, - m: 0, - d: 0, - ttl: 1337, - g: 0, - j: 0, - u: 0 - }) - .reply( - 200, - '{"message":"Success","payload":{"level":"channel-group+auth","subscribe_key":"mySubscribeKey","channel-group":"cg2","auths":{"key1":{"r":1,"m":0,"w":1,"d":0}}},"service":"Access Manager","status":200}' - ); - pubnub.grant( - { - channels: ['ch1', 'ch2'], - uuids: ['uuid-1', 'uuid-2'], - authKeys: ['key1', 'key2'], - read: true, - write: true, - ttl: 1337, - } - ).catch((error) => { - assert.equal(scope.isDone(), false); - assert.equal(error.status.message, 'Both channel/channelgroup and uuid cannot be used in the same request'); - done(); + it('channels and uuids in single request', (done) => { + const scope = utils + .createNock() + .get('/v2/auth/grant/sub-key/mySubscribeKey') + .query({ + timestamp: 1317427200, + channel: 'ch1,ch2', + 'target-uuid': 'uuid-1, uuid-2', + auth: 'key1,key2', + uuid: 'myUUID', + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + signature: 'v2.zneRpaqzdxJPegBrJHWMzj-mD8QVBxqh8Zl15N7n2d4', + r: 1, + w: 1, + m: 0, + d: 0, + ttl: 1337, + g: 0, + j: 0, + u: 0, + }) + .reply( + 200, + '{"message":"Success","payload":{"level":"channel-group+auth","subscribe_key":"mySubscribeKey","channel-group":"cg2","auths":{"key1":{"r":1,"m":0,"w":1,"d":0}}},"service":"Access Manager","status":200}', + { 'content-type': 'text/javascript' }, + ); + pubnub + .grant({ + channels: ['ch1', 'ch2'], + uuids: ['uuid-1', 'uuid-2'], + authKeys: ['key1', 'key2'], + read: true, + write: true, + ttl: 1337, + }) + .catch((error) => { + try { + assert.equal(scope.isDone(), false); + assert.equal( + error.status.message, + "Both channel/channel group and uuid cannot be used in the same request" + ); + done(); + } catch (error) { + done(error); + } + }); }); - }); - it('uuids and empty authKeys', (done) => { - const scope = utils - .createNock() - .get('/v2/auth/grant/sub-key/mySubscribeKey') - .query({ - timestamp: 1317427200, - 'target-uuid': 'uuid-1, uuid-2', - uuid: 'myUUID', - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - signature: 'v2.zneRpaqzdxJPegBrJHWMzj-mD8QVBxqh8Zl15N7n2d4', - r: 1, - w: 1, - m: 0, - d: 0, - ttl: 1337, - g: 0, - j: 0, - u: 0 - }) - .reply( - 200, - '{"message":"Success","payload":{"level":"uuid","subscribe_key":"mySubscribeKey","channel-group":"cg2","auths":{"key1":{"r":1,"m":0,"w":1,"d":0}}},"service":"Access Manager","status":200}' - ); - pubnub.grant( - { - uuids: ['uuid-1', 'uuid-2'], - read: true, - write: true, - ttl: 1337, - } - ).catch((error) => { - assert.equal(scope.isDone(), false); - assert.equal(error.status.message, 'authKeys are required for grant request on uuids'); - done(); + it('uuids and empty authKeys', (done) => { + const scope = utils + .createNock() + .get('/v2/auth/grant/sub-key/mySubscribeKey') + .query({ + timestamp: 1317427200, + 'target-uuid': 'uuid-1,uuid-2', + uuid: 'myUUID', + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + signature: 'v2.zneRpaqzdxJPegBrJHWMzj-mD8QVBxqh8Zl15N7n2d4', + r: 1, + w: 1, + m: 0, + d: 0, + ttl: 1337, + g: 0, + j: 0, + u: 0, + }) + .reply( + 200, + '{"message":"Success","payload":{"level":"uuid","subscribe_key":"mySubscribeKey","channel-group":"cg2","auths":{"key1":{"r":1,"m":0,"w":1,"d":0}}},"service":"Access Manager","status":200}', + { 'content-type': 'text/javascript' }, + ); + pubnub + .grant({ + uuids: ['uuid-1', 'uuid-2'], + read: true, + write: true, + ttl: 1337, + }) + .catch((error) => { + try { + assert.equal(scope.isDone(), false); + assert.equal(error.status.message, "authKeys are required for grant request on uuids"); + done(); + } catch (error) { + done(error); + } + }); }); }); - - }); - }); }); describe('access endpoints telemetry', () => { - let pubnub; + let pubnub: PubNub; before(() => { nock.disableNetConnect(); @@ -481,6 +535,8 @@ describe('access endpoints telemetry', () => { publishKey: 'myPublishKey', secretKey: 'mySecretKey', uuid: 'myUUID', + // @ts-expect-error Force override default value. + useRequestId: false, }); pubnub._config.getVersion = () => 'suchJavascript'; }); @@ -493,18 +549,19 @@ describe('access endpoints telemetry', () => { const average = Math.floor(countedDelays.reduce((acc, delay) => acc + delay, 0) / countedDelays.length); const leeway = 50; - utils.runAPIWithResponseDelays(scope, - 200, - '{"message":"Success","payload":{"level":"channel-group+auth","subscribe_key":"mySubscribeKey","channel-group":"cg2","auths":{"key1":{"r":1,"m":1,"w":1,"d":1}}},"service":"Access Manager","status":200}', - delays, - (completion) => { - pubnub.audit( - { channel: 'ch1' }, - () => { completion(); } - ); - }) + utils + .runAPIWithResponseDelays( + scope, + 200, + '{"message":"Success","payload":{"level":"channel-group+auth","subscribe_key":"mySubscribeKey","channel-group":"cg2","auths":{"key1":{"r":1,"m":1,"w":1,"d":1}}},"service":"Access Manager","status":200}', + delays, + (completion) => { + pubnub.audit({ channel: 'ch1' }, () => { + completion(); + }); + }, + ) .then((lastRequest) => { - utils.verifyRequestTelemetry(lastRequest.path, 'l_pam', average, leeway); done(); }); }).timeout(20000); @@ -518,18 +575,19 @@ describe('access endpoints telemetry', () => { const average = Math.floor(countedDelays.reduce((acc, delay) => acc + delay, 0) / countedDelays.length); const leeway = 50; - utils.runAPIWithResponseDelays(scope, - 200, - '{"message":"Success","payload":{"level":"channel-group+auth","subscribe_key":"mySubscribeKey","channel-group":"cg2","auths":{"key1":{"r":1,"m":1,"w":1,"d":1}}},"service":"Access Manager","status":200}', - delays, - (completion) => { - pubnub.grant( - { channels: ['ch1', 'ch2'], authKeys: ['key1', 'key2'] }, - () => { completion(); } - ); - }) + utils + .runAPIWithResponseDelays( + scope, + 200, + '{"message":"Success","payload":{"level":"channel-group+auth","subscribe_key":"mySubscribeKey","channel-group":"cg2","auths":{"key1":{"r":1,"m":1,"w":1,"d":1}}},"service":"Access Manager","status":200}', + delays, + (completion) => { + pubnub.grant({ channels: ['ch1', 'ch2'], authKeys: ['key1', 'key2'] }, () => { + completion(); + }); + }, + ) .then((lastRequest) => { - utils.verifyRequestTelemetry(lastRequest.path, 'l_pam', average, leeway); done(); }); }).timeout(20000); diff --git a/test/integration/endpoints/channel_groups.test.js b/test/integration/endpoints/channel_groups.test.js deleted file mode 100644 index dec7ee82a..000000000 --- a/test/integration/endpoints/channel_groups.test.js +++ /dev/null @@ -1,265 +0,0 @@ -/* global describe, beforeEach, it, before, after */ -/* eslint no-console: 0 */ - -import assert from 'assert'; -import nock from 'nock'; -import utils from '../../utils'; -import PubNub from '../../../src/node/index'; - -describe('channel group endpoints', () => { - let pubnub; - - before(() => { - nock.disableNetConnect(); - }); - - after(() => { - nock.enableNetConnect(); - }); - - beforeEach(() => { - nock.cleanAll(); - pubnub = new PubNub({ - subscribeKey: 'mySubKey', - publishKey: 'myPublishKey', - uuid: 'myUUID', - }); - }); - - describe('adding channels to channel group', () => { - it('supports addition of multiple channels', (done) => { - const scope = utils - .createNock() - .get('/v1/channel-registration/sub-key/mySubKey/channel-group/cg1') - .query({ - add: 'a,b', - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - }) - .reply( - 200, - '{"status": 200, "message": "OK", "payload": {} , "service": "ChannelGroups"}' - ); - - pubnub.channelGroups.addChannels( - { channels: ['a', 'b'], channelGroup: 'cg1' }, - (status) => { - assert.equal(status.error, false); - assert.equal(scope.isDone(), true); - done(); - } - ); - }); - - it('should add channels add API telemetry information', (done) => { - let scope = utils.createNock().get('/v1/channel-registration/sub-key/mySubKey/channel-group/cg1').query(true); - const delays = [100, 200, 300, 400]; - const countedDelays = delays.slice(0, delays.length - 1); - const average = Math.floor(countedDelays.reduce((acc, delay) => acc + delay, 0) / countedDelays.length); - const leeway = 50; - - utils.runAPIWithResponseDelays(scope, - 200, - '{"status": 200, "message": "OK", "payload": {} , "service": "ChannelGroups"}', - delays, - (completion) => { - pubnub.channelGroups.addChannels( - { channels: ['a', 'b'], channelGroup: 'cg1' }, - () => { completion(); } - ); - }) - .then((lastRequest) => { - utils.verifyRequestTelemetry(lastRequest.path, 'l_cg', average, leeway); - done(); - }); - }).timeout(60000); - }); - - describe('removal of channel group', () => { - it('supports deletion of group', (done) => { - const scope = utils - .createNock() - .get( - '/v1/channel-registration/sub-key/mySubKey/channel-group/cg1/remove' - ) - .query({ - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - }) - .reply( - 200, - '{"status": 200, "message": "OK", "payload": {} , "service": "ChannelGroups"}' - ); - - pubnub.channelGroups.deleteGroup({ channelGroup: 'cg1' }, (status) => { - assert.equal(status.error, false); - assert.equal(scope.isDone(), true); - done(); - }); - }); - - it('should add channel group remove API telemetry information', (done) => { - let scope = utils.createNock().get('/v1/channel-registration/sub-key/mySubKey/channel-group/cg1/remove').query(true); - const delays = [100, 200, 300, 400]; - const countedDelays = delays.slice(0, delays.length - 1); - const average = Math.floor(countedDelays.reduce((acc, delay) => acc + delay, 0) / countedDelays.length); - const leeway = 50; - - utils.runAPIWithResponseDelays(scope, - 200, - '{"status": 200, "message": "OK", "payload": {} , "service": "ChannelGroups"}', - delays, - (completion) => { - pubnub.channelGroups.deleteGroup( - { channelGroup: 'cg1' }, - () => { completion(); } - ); - }) - .then((lastRequest) => { - utils.verifyRequestTelemetry(lastRequest.path, 'l_cg', average, leeway); - done(); - }); - }).timeout(60000); - }); - - describe('listing of channel groups', () => { - it('returns a list of all channel groups', (done) => { - const scope = utils - .createNock() - .get('/v1/channel-registration/sub-key/mySubKey/channel-group') - .query({ - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - }) - .reply( - 200, - '{"status": 200, "message": "OK", "payload": {"groups": ["a","b"]}, "service": "ChannelGroups"}' - ); - - pubnub.channelGroups.listGroups((status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.groups, ['a', 'b']); - assert.equal(scope.isDone(), true); - done(); - }); - }); - - it('should add channel groups list API telemetry information', (done) => { - let scope = utils.createNock().get('/v1/channel-registration/sub-key/mySubKey/channel-group').query(true); - const delays = [100, 200, 300, 400]; - const countedDelays = delays.slice(0, delays.length - 1); - const average = Math.floor(countedDelays.reduce((acc, delay) => acc + delay, 0) / countedDelays.length); - const leeway = 50; - - utils.runAPIWithResponseDelays(scope, - 200, - '{"status": 200, "message": "OK", "payload": {"groups": ["a","b"]}, "service": "ChannelGroups"}', - delays, - (completion) => { - pubnub.channelGroups.listGroups(() => { completion(); }); - }) - .then((lastRequest) => { - utils.verifyRequestTelemetry(lastRequest.path, 'l_cg', average, leeway); - done(); - }); - }).timeout(60000); - }); - - describe('listing of channels inside channel group', () => { - it('returns a list of all channel groups', (done) => { - const scope = utils - .createNock() - .get('/v1/channel-registration/sub-key/mySubKey/channel-group/cg1') - .query({ - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - }) - .reply( - 200, - '{"status": 200, "message": "OK", "payload": {"channels": ["a","b"]}, "service": "ChannelGroups"}' - ); - - pubnub.channelGroups.listChannels( - { channelGroup: 'cg1' }, - (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.channels, ['a', 'b']); - assert.equal(scope.isDone(), true); - done(); - } - ); - }); - - it('should add channel group channels list API telemetry information', (done) => { - let scope = utils.createNock().get('/v1/channel-registration/sub-key/mySubKey/channel-group/cg1').query(true); - const delays = [100, 200, 300, 400]; - const countedDelays = delays.slice(0, delays.length - 1); - const average = Math.floor(countedDelays.reduce((acc, delay) => acc + delay, 0) / countedDelays.length); - const leeway = 50; - - utils.runAPIWithResponseDelays(scope, - 200, - '{"status": 200, "message": "OK", "payload": {"channels": ["a","b"]}, "service": "ChannelGroups"}', - delays, - (completion) => { - pubnub.channelGroups.listChannels( - { channelGroup: 'cg1' }, - () => { completion(); } - ); - }) - .then((lastRequest) => { - utils.verifyRequestTelemetry(lastRequest.path, 'l_cg', average, leeway); - done(); - }); - }).timeout(60000); - }); - - describe('deletion of channels from channel group', () => { - it('works as expected', (done) => { - const scope = utils - .createNock() - .get('/v1/channel-registration/sub-key/mySubKey/channel-group/cg1') - .query({ - remove: 'a,b', - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - }) - .reply( - 200, - '{"status": 200, "message": "OK", "payload": {} , "service": "ChannelGroups"}' - ); - - pubnub.channelGroups.removeChannels( - { channels: ['a', 'b'], channelGroup: 'cg1' }, - (status) => { - assert.equal(status.error, false); - assert.equal(scope.isDone(), true); - done(); - } - ); - }); - - it('should add channels remove API telemetry information', (done) => { - let scope = utils.createNock().get('/v1/channel-registration/sub-key/mySubKey/channel-group/cg1').query(true); - const delays = [100, 200, 300, 400]; - const countedDelays = delays.slice(0, delays.length - 1); - const average = Math.floor(countedDelays.reduce((acc, delay) => acc + delay, 0) / countedDelays.length); - const leeway = 50; - - utils.runAPIWithResponseDelays(scope, - 200, - '{"status": 200, "message": "OK", "payload": {} , "service": "ChannelGroups"}', - delays, - (completion) => { - pubnub.channelGroups.removeChannels( - { channels: ['a', 'b'], channelGroup: 'cg1' }, - () => { completion(); } - ); - }) - .then((lastRequest) => { - utils.verifyRequestTelemetry(lastRequest.path, 'l_cg', average, leeway); - done(); - }); - }).timeout(60000); - }); -}); diff --git a/test/integration/endpoints/channel_groups.test.ts b/test/integration/endpoints/channel_groups.test.ts new file mode 100644 index 000000000..abe20a179 --- /dev/null +++ b/test/integration/endpoints/channel_groups.test.ts @@ -0,0 +1,167 @@ +/* global describe, beforeEach, it, before, after */ +/* eslint no-console: 0 */ + +import assert from 'assert'; +import nock from 'nock'; + +import PubNub from '../../../src/node/index'; +import utils from '../../utils'; + + +describe('channel group endpoints', () => { + let pubnub: PubNub; + + before(() => { + nock.disableNetConnect(); + }); + + after(() => { + nock.enableNetConnect(); + }); + + beforeEach(() => { + nock.cleanAll(); + pubnub = new PubNub({ + subscribeKey: 'mySubKey', + publishKey: 'myPublishKey', + uuid: 'myUUID', + // @ts-expect-error Force override default value. + useRequestId: false, + }); + }); + + describe('adding channels to channel group', () => { + it('supports addition of multiple channels', (done) => { + const scope = utils + .createNock() + .get('/v1/channel-registration/sub-key/mySubKey/channel-group/cg1') + .query({ + add: 'a,b', + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + uuid: 'myUUID', + }) + .reply(200, '{"status": 200, "message": "OK", "payload": {} , "service": "ChannelGroups"}', { + 'content-type': 'text/javascript', + }); + + pubnub.channelGroups.addChannels({ channels: ['a', 'b'], channelGroup: 'cg1' }, (status) => { + try { + assert.equal(status.error, false); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }); + }); + }); + + describe('removal of channel group', () => { + it('supports deletion of group', (done) => { + const scope = utils + .createNock() + .get('/v1/channel-registration/sub-key/mySubKey/channel-group/cg1/remove') + .query({ + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + uuid: 'myUUID', + }) + .reply(200, '{"status": 200, "message": "OK", "payload": {} , "service": "ChannelGroups"}', { + 'content-type': 'text/javascript', + }); + + pubnub.channelGroups.deleteGroup({ channelGroup: 'cg1' }, (status) => { + try { + assert.equal(status.error, false); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }); + }); + }); + + describe('listing of channel groups', () => { + it('returns a list of all channel groups', (done) => { + const scope = utils + .createNock() + .get('/v1/channel-registration/sub-key/mySubKey/channel-group') + .query({ + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + uuid: 'myUUID', + }) + .reply(200, '{"status": 200, "message": "OK", "payload": {"groups": ["a","b"]}, "service": "ChannelGroups"}', { + 'content-type': 'text/javascript', + }); + + pubnub.channelGroups.listGroups((status, response) => { + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.groups, ["a", "b"]); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }); + }); + }); + + describe('listing of channels inside channel group', () => { + it('returns a list of all channel groups', (done) => { + const scope = utils + .createNock() + .get('/v1/channel-registration/sub-key/mySubKey/channel-group/cg1') + .query({ + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + uuid: 'myUUID', + }) + .reply( + 200, + '{"status": 200, "message": "OK", "payload": {"channels": ["a","b"]}, "service": "ChannelGroups"}', + { + 'content-type': 'text/javascript', + }, + ); + + pubnub.channelGroups.listChannels({ channelGroup: 'cg1' }, (status, response) => { + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.channels, ["a", "b"]); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }); + }); + }); + + describe('deletion of channels from channel group', () => { + it('works as expected', (done) => { + const scope = utils + .createNock() + .get('/v1/channel-registration/sub-key/mySubKey/channel-group/cg1') + .query({ + remove: 'a,b', + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + uuid: 'myUUID', + }) + .reply(200, '{"status": 200, "message": "OK", "payload": {} , "service": "ChannelGroups"}', { + 'content-type': 'text/javascript', + }); + + pubnub.channelGroups.removeChannels({ channels: ['a', 'b'], channelGroup: 'cg1' }, (status) => { + try { + assert.equal(status.error, false); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }); + }); + }); +}); diff --git a/test/integration/endpoints/fetch_messages.test.js b/test/integration/endpoints/fetch_messages.test.js deleted file mode 100644 index 9ca8fb9df..000000000 --- a/test/integration/endpoints/fetch_messages.test.js +++ /dev/null @@ -1,606 +0,0 @@ -/* global describe, beforeEach, afterEach, it, after */ -/* eslint no-console: 0 */ - -import assert from 'assert'; -import nock from 'nock'; -import utils from '../../utils'; -import PubNub from '../../../src/node/index'; - -function publishMessagesToChannel(client, count, channel, completion) { - let publishCompleted = 0; - let messages = []; - - const publish = (messageIdx) => { - let payload = { message: { messageIdx: [channel, messageIdx].join(': '), time: Date.now() }, channel }; - - if (messageIdx % 2 === 0) { - payload.meta = { time: payload.message.time }; - } - - client.publish(payload, (status, response) => { - publishCompleted += 1; - - if (!status.error) { - messages.push({ message: payload.message, timetoken: response.timetoken }); - messages = messages.sort((left, right) => left.timetoken - right.timetoken); - } else { - console.error('Publish did fail:', status); - } - - if (publishCompleted < count) { - publish(publishCompleted); - } else if (publishCompleted === count) { - completion(messages); - } - }); - }; - - publish(publishCompleted); -} - -function addActionsInChannel(client, count, messageTimetokens, channel, completion) { - const types = ['reaction', 'receipt', 'custom']; - const values = [ - PubNub.generateUUID(), - PubNub.generateUUID(), - PubNub.generateUUID(), - PubNub.generateUUID(), - PubNub.generateUUID(), - PubNub.generateUUID(), - PubNub.generateUUID(), - PubNub.generateUUID(), - PubNub.generateUUID(), - PubNub.generateUUID(), - ]; - let actionsToAdd = []; - let actionsAdded = 0; - let actions = []; - - for (let messageIdx = 0; messageIdx < messageTimetokens.length; messageIdx += 1) { - const messageTimetoken = messageTimetokens[messageIdx]; - - for (let messageActionIdx = 0; messageActionIdx < count; messageActionIdx += 1) { - /** @type MessageAction */ - const action = { type: types[(messageActionIdx + 1) % 3], value: values[(messageActionIdx + 1) % 10] }; - - actionsToAdd.push({ messageTimetoken, action }); - } - } - - const addAction = (actionIdx) => { - const { messageTimetoken, action } = actionsToAdd[actionIdx]; - - client.addMessageAction({ channel, messageTimetoken, action }, (status, response) => { - actionsAdded += 1; - - if (!status.error) { - actions.push(response.data); - actions = actions.sort((left, right) => left.actionTimetoken - right.actionTimetoken); - } else { - console.error('Action add did fail:', status); - } - - if (actionsAdded < actionsToAdd.length) { - addAction(actionsAdded); - } else if (actionsAdded === actionsToAdd.length) { - completion(actions); - } - }); - }; - - addAction(actionsAdded); -} - -describe('fetch messages endpoints', () => { - const subscribeKey = process.env.SUBSCRIBE_KEY || 'demo'; - const publishKey = process.env.PUBLISH_KEY || 'demo'; - let pubnub; - - after(() => { - nock.enableNetConnect(); - }); - - afterEach(() => { - nock.enableNetConnect(); - pubnub.removeAllListeners(); - pubnub.unsubscribeAll(); - pubnub.stop(); - }); - - beforeEach(() => { - nock.cleanAll(); - pubnub = new PubNub({ - subscribeKey, - publishKey, - uuid: 'myUUID', - useRandomIVs: false - }); - }); - - it('supports payload', (done) => { - nock.disableNetConnect(); - const scope = utils - .createNock() - .get(`/v3/history/sub-key/${subscribeKey}/channel/ch1%2Cch2`) - .query({ - max: '10', - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - include_uuid: 'true', - include_message_type: 'true', - }) - .reply( - 200, - '{ "channels": { "ch1": [{"message":{"text":"hey1"},"timetoken":"11"}, {"message":{"text":"hey2"},"timetoken":"12"}], "ch2": [{"message":{"text":"hey3"},"timetoken":"21"}, {"message":{"text":"hey2"},"timetoken":"22"}] } }' - ); - - pubnub.fetchMessages({ channels: ['ch1', 'ch2'], count: 10 }, (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response, { - channels: { - ch1: [ - { - channel: 'ch1', - message: { - text: 'hey1', - }, - timetoken: '11', - messageType: undefined, - uuid: undefined, - }, - { - channel: 'ch1', - message: { - text: 'hey2', - }, - timetoken: '12', - messageType: undefined, - uuid: undefined, - }, - ], - ch2: [ - { - channel: 'ch2', - message: { - text: 'hey3', - }, - timetoken: '21', - messageType: undefined, - uuid: undefined, - }, - { - channel: 'ch2', - message: { - text: 'hey2', - }, - timetoken: '22', - messageType: undefined, - uuid: undefined, - }, - ], - }, - }); - assert.equal(scope.isDone(), true); - done(); - }); - }); - - it('supports encrypted payload', (done) => { - nock.disableNetConnect(); - const scope = utils - .createNock() - .get(`/v3/history/sub-key/${subscribeKey}/channel/ch1%2Cch2`) - .query({ - max: '10', - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - include_uuid: 'true', - include_message_type: 'true', - }) - .reply( - 200, - '{ "channels": { "ch1": [{"message":"zFJeF9BVABL80GUiQEBjLg==","timetoken":"11"}, {"message":"zFJeF9BVABL80GUiQEBjLg==","timetoken":"12"}], "ch2": [{"message":"HIq4MTi9nk/KEYlHOKpMCaH78ZXppGynDHrgY9nAd3s=","timetoken":"21"}, {"message":"HIq4MTi9nk/KEYlHOKpMCaH78ZXppGynDHrgY9nAd3s=","timetoken":"22"}] } }' - ); - - pubnub.setCipherKey('cipherKey'); - pubnub.fetchMessages({ channels: ['ch1', 'ch2'], count: 10 }, (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response, { - channels: { - ch1: [ - { - channel: 'ch1', - message: { - text: 'hey', - }, - timetoken: '11', - messageType: undefined, - uuid: undefined, - }, - { - channel: 'ch1', - message: { - text: 'hey', - }, - timetoken: '12', - messageType: undefined, - uuid: undefined, - }, - ], - ch2: [ - { - channel: 'ch2', - message: { - text2: 'hey2', - }, - timetoken: '21', - messageType: undefined, - uuid: undefined, - }, - { - channel: 'ch2', - message: { - text2: 'hey2', - }, - timetoken: '22', - messageType: undefined, - uuid: undefined, - }, - ], - }, - }); - assert.equal(scope.isDone(), true); - done(); - }); - }); - - it('supports metadata', (done) => { - const channel = PubNub.generateUUID(); - const expectedMessagesCount = 10; - - publishMessagesToChannel(pubnub, expectedMessagesCount, channel, (messages) => { - pubnub.fetchMessages({ channels: [channel], count: 25, includeMeta: true }, (status, response) => { - const channelMessages = response.channels[channel]; - - assert.deepEqual(channelMessages[0].meta, { time: messages[0].message.time }); - assert(!channelMessages[1].meta); - done(); - }); - }); - }).timeout(60000); - - it('throws when requested actions for multiple channels', () => { - let errorCatched = false; - - try { - pubnub.fetchMessages({ channels: ['channelA', 'channelB'], includeMessageActions: true }, () => {}); - } catch (error) { - assert.equal( - error.message, - 'History can return actions data for a single channel only. Either pass a single channel or disable the includeMessageActions flag.' - ); - errorCatched = true; - } - - assert(errorCatched); - }); - - it("supports actions (stored as 'data' field)", (done) => { - const channel = PubNub.generateUUID(); - const expectedMessagesCount = 2; - const expectedActionsCount = 4; - - publishMessagesToChannel(pubnub, expectedMessagesCount, channel, (messages) => { - const messageTimetokens = messages.map((message) => message.timetoken); - - addActionsInChannel(pubnub, expectedActionsCount, messageTimetokens, channel, (actions) => { - setTimeout(() => { - pubnub.fetchMessages({ channels: [channel], includeMessageActions: true }, (status, response) => { - assert.equal(status.error, false); - const fetchedMessages = response.channels[channel]; - const actionsByType = fetchedMessages[0].data; - let historyActionsCount = 0; - - Object.keys(actionsByType).forEach((actionType) => { - Object.keys(actionsByType[actionType]).forEach((actionValue) => { - let actionFound = false; - historyActionsCount += 1; - - actions.forEach((action) => { - if (action.value === actionValue) { - actionFound = true; - } - }); - - assert.equal(actionFound, true); - }); - }); - - assert.equal(historyActionsCount, expectedActionsCount); - assert.equal(fetchedMessages[0].timetoken, messageTimetokens[0]); - assert.equal( - fetchedMessages[fetchedMessages.length - 1].timetoken, - messageTimetokens[messageTimetokens.length - 1] - ); - - done(); - }); - }, 2000); - }); - }); - }).timeout(60000); - - it("supports actions (stored as 'actions' field)", (done) => { - const channel = PubNub.generateUUID(); - const expectedMessagesCount = 2; - const expectedActionsCount = 4; - - publishMessagesToChannel(pubnub, expectedMessagesCount, channel, (messages) => { - const messageTimetokens = messages.map((message) => message.timetoken); - - addActionsInChannel(pubnub, expectedActionsCount, messageTimetokens, channel, (actions) => { - setTimeout(() => { - pubnub.fetchMessages({ channels: [channel], includeMessageActions: true }, (status, response) => { - assert.equal(status.error, false); - const fetchedMessages = response.channels[channel]; - const actionsByType = fetchedMessages[0].actions; - let historyActionsCount = 0; - - Object.keys(actionsByType).forEach((actionType) => { - Object.keys(actionsByType[actionType]).forEach((actionValue) => { - let actionFound = false; - historyActionsCount += 1; - - actions.forEach((action) => { - if (action.value === actionValue) { - actionFound = true; - } - }); - - assert.equal(actionFound, true); - }); - }); - - assert.equal(historyActionsCount, expectedActionsCount); - assert.equal(fetchedMessages[0].timetoken, messageTimetokens[0]); - assert.equal( - fetchedMessages[fetchedMessages.length - 1].timetoken, - messageTimetokens[messageTimetokens.length - 1] - ); - - done(); - }); - }, 2000); - }); - }); - }).timeout(60000); - - it('should add fetch messages API telemetry information', (done) => { - nock.disableNetConnect(); - let scope = utils.createNock().get(`/v3/history/sub-key/${subscribeKey}/channel/ch1%2Cch2`).query(true); - const delays = [100, 200, 300, 400]; - const countedDelays = delays.slice(0, delays.length - 1); - const average = Math.floor(countedDelays.reduce((acc, delay) => acc + delay, 0) / countedDelays.length); - const leeway = 50; - - utils - .runAPIWithResponseDelays( - scope, - 200, - '{ "channels": { "ch1": [{"message":{"text":"hey1"},"timetoken":"11"}, {"message":{"text":"hey2"},"timetoken":"12"}], "ch2": [{"message":{"text":"hey3"},"timetoken":"21"}, {"message":{"text":"hey2"},"timetoken":"22"}] } }', - delays, - (completion) => { - pubnub.fetchMessages({ channels: ['ch1', 'ch2'], count: 10 }, () => { - completion(); - }); - } - ) - .then((lastRequest) => { - utils.verifyRequestTelemetry(lastRequest.path, 'l_hist', average, leeway); - done(); - }); - }).timeout(60000); - - it('should return "more" field when server sends it', (done) => { - nock.disableNetConnect(); - const scope = utils - .createNock() - .get(`/v3/history-with-actions/sub-key/${subscribeKey}/channel/ch1`) - .query({ - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - max: '25', - include_uuid: 'true', - include_message_type: 'true' - }) - .reply( - 200, - '{"status":200,"error":false,"error_message":"","channels":{"demo-channel":[{"message":"Hi","timetoken":15610547826970040,"actions":{"receipt":{"read":[{"uuid":"user-7","actionTimetoken":15610547826970044}]}}},{"message":"Hello","timetoken":15610547826970000,"actions":{"reaction":{"smiley_face":[{"uuid":"user-456","actionTimetoken":15610547826970050}]}}}]},"more":{"url":"/v3/history-with-actions/sub-key/s/channel/c?start=15610547826970000&max=98","start":"15610547826970000","max":98}}' - ); - pubnub.fetchMessages({ channels: ['ch1'], includeMessageActions: true}, (status, response) => { - assert.equal(status.error, false); - assert.equal(response.more.url, '/v3/history-with-actions/sub-key/s/channel/c?start=15610547826970000&max=98'); - assert.equal(response.more.start, '15610547826970000'); - assert.equal(response.more.max, 98); - done(); - }); - }); - it('should request 100 messages when count not provided with single channel', (done) => { - nock.disableNetConnect(); - const scope = utils - .createNock() - .get(`/v3/history/sub-key/${subscribeKey}/channel/ch1`) - .query({ - max: '100', - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - include_uuid: 'true', - include_message_type: 'true', - }) - .reply( - 200, - '{ "error": false, "error_message": "", "channels": { "ch1": [ { "message_type": null, "message": "hello world", "timetoken": "16048329933709932", "uuid": "test-uuid"} ] } }' - ); - pubnub.fetchMessages({ channels: ['ch1'] }, (status, response) => { - assert.equal(status.error, false); - done(); - }); - }); - - it('should request 25 messages when count not provided with multiple channels', (done) => { - nock.disableNetConnect(); - const scope = utils - .createNock() - .get(`/v3/history/sub-key/${subscribeKey}/channel/ch1%2Cch2`) - .query({ - max: '25', - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - include_uuid: 'true', - include_message_type: 'true', - }) - .reply( - 200, - '{ "error": false, "error_message": "", "channels": { "ch1": [ { "message_type": null, "message": "hello world", "timetoken": "16048329933709932", "uuid": "test-uuid"} ] } }' - ); - pubnub.fetchMessages({ channels: ['ch1', 'ch2'] }, (status, response) => { - assert.equal(status.error, false); - done(); - }); - }); - - it('should request 25 messages when count not provided for history-with-actions', (done) => { - nock.disableNetConnect(); - const scope = utils - .createNock() - .get(`/v3/history-with-actions/sub-key/${subscribeKey}/channel/ch1`) - .query({ - max: '25', - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - include_uuid: 'true', - include_message_type: 'true' - }) - .reply( - 200, - '{ "error": false, "error_message": "", "channels": { "ch1": [ { "message_type": null, "message": "hello world", "timetoken": "16048329933709932", "uuid": "test-uuid"} ] } }' - ); - pubnub.fetchMessages({ channels: ['ch1'], includeMessageActions: true}, (status, response) => { - assert.equal(status.error, false); - done(); - }); - }); - - it('should request provided number of messages when count is specified for history-with-actions', (done) => { - nock.disableNetConnect(); - const scope = utils - .createNock() - .get(`/v3/history-with-actions/sub-key/${subscribeKey}/channel/ch1`) - .query({ - max: '10', - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - include_uuid: 'true', - include_message_type: 'true' - }) - .reply( - 200, - '{ "error": false, "error_message": "", "channels": { "ch1": [ { "message_type": null, "message": "hello world", "timetoken": "16048329933709932", "uuid": "test-uuid"} ] } }' - ); - pubnub.fetchMessages({ channels: ['ch1'], includeMessageActions: true, count: 10}, (status, response) => { - assert.equal(status.error, false); - done(); - }); - }); - - it('should request provided number of messages when count is specified for batch history with single channel', (done) => { - nock.disableNetConnect(); - const scope = utils - .createNock() - .get(`/v3/history/sub-key/${subscribeKey}/channel/ch1`) - .query({ - max: '10', - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - include_uuid: 'true', - include_message_type: 'true' - }) - .reply( - 200, - '{ "error": false, "error_message": "", "channels": { "ch1": [ { "message_type": null, "message": "hello world", "timetoken": "16048329933709932", "uuid": "test-uuid"} ] } }' - ); - pubnub.fetchMessages({ channels: ['ch1'], count: 10}, (status, response) => { - assert.equal(status.error, false); - done(); - }); - }); - - it('should request provided number of messages when count is specified for batch history with multiple channels', (done) => { - nock.disableNetConnect(); - const scope = utils - .createNock() - .get(`/v3/history/sub-key/${subscribeKey}/channel/ch1%2Cch2`) - .query({ - max: '10', - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - include_uuid: 'true', - include_message_type: 'true' - }) - .reply( - 200, - '{ "error": false, "error_message": "", "channels": { "ch1": [ { "message_type": null, "message": "hello world", "timetoken": "16048329933709932", "uuid": "test-uuid"} ] } }' - ); - pubnub.fetchMessages({ channels: ['ch1', 'ch2'], count: 10}, (status, response) => { - assert.equal(status.error, false); - done(); - }); - }); - - it('handles unencrypted payload when cryptomodule configured', (done) => { - nock.disableNetConnect(); - const scope = utils - .createNock() - .get(`/v3/history/sub-key/${subscribeKey}/channel/ch1`) - .query({ - max: '10', - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - include_uuid: 'true', - include_message_type: 'true', - }) - .reply( - 200, - '{ "channels": { "ch1": [{"message":"hello","timetoken":"11"}, {"message":"hey","timetoken":"12"}] } }', - ); - - pubnub.setCipherKey('cipherKey'); - pubnub.fetchMessages({ channels: ['ch1'], count: 10 }, (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response, { - channels: { - ch1: [ - { - channel: 'ch1', - message: 'hello', - timetoken: '11', - messageType: undefined, - uuid: undefined, - error: 'Error while decrypting message content: decryption error. invalid header version', - }, - { - channel: 'ch1', - message: 'hey', - timetoken: '12', - messageType: undefined, - uuid: undefined, - error: 'Error while decrypting message content: decryption error. invalid header version', - }, - ], - }, - }); - assert.equal(scope.isDone(), true); - done(); - }); - }); -}); diff --git a/test/integration/endpoints/fetch_messages.test.ts b/test/integration/endpoints/fetch_messages.test.ts new file mode 100644 index 000000000..7b328a630 --- /dev/null +++ b/test/integration/endpoints/fetch_messages.test.ts @@ -0,0 +1,709 @@ +/* global describe, beforeEach, afterEach, it, after */ +/* eslint no-console: 0 */ + +import assert from 'assert'; +import nock from 'nock'; + +import * as MessageActions from '../../../src/core/types/api/message-action'; +import { Payload } from '../../../src/core/types/api'; +import PubNub from '../../../src/node/index'; +import utils from '../../utils'; +import { PubNubError } from '../../../src/errors/pubnub-error'; + +/** + * Published test message shape. + */ +type TestMessage = { messageIdx: string; time: number }; + +/** + * Prepare messages history. + * + * @param client - PubNub client instance which will be used to publish messages. + * @param count - How many messages should be published. + * @param channel - Name of the channel into which messages should be published. + * @param completion - Messages set publish completion function. + */ +function publishMessagesToChannel( + client: PubNub, + count: number, + channel: string, + completion: (published: { message: TestMessage; timetoken: string }[]) => void, +) { + let messages: { message: TestMessage; timetoken: string }[] = []; + let publishCompleted = 0; + + const publish = (messageIdx: number) => { + let payload: { channel: string; message: TestMessage; meta?: Payload } = { + message: { messageIdx: [channel, messageIdx].join(': '), time: Date.now() }, + channel, + }; + + if (messageIdx % 2 === 0) payload.meta = { time: payload.message.time }; + + client.publish(payload, (status, response) => { + publishCompleted += 1; + + if (!status.error && response) { + messages.push({ message: payload.message, timetoken: response.timetoken }); + messages = messages.sort((left, right) => parseInt(left.timetoken, 10) - parseInt(right.timetoken, 10)); + } else { + console.error('Publish did fail:', status); + } + + if (publishCompleted < count) { + publish(publishCompleted); + } else if (publishCompleted === count) { + completion(messages); + } + }); + }; + + publish(publishCompleted); +} + +/** + * Attach message actions to the previously published messages. + * + * @param client - PubNub client instance which should be used to add message action to the message. + * @param count - How many message actions should be added to each referenced message. + * @param messageTimetokens - List of referenced messages' timetokens. + * @param channel - Name of the channel where referenced messages has been published. + * @param completion - Message actions addition completion function. + */ +function addActionsInChannel( + client: PubNub, + count: number, + messageTimetokens: string[], + channel: string, + completion: (added: MessageActions.MessageAction[]) => void, +) { + const types = ['reaction', 'receipt', 'custom']; + const values = [ + PubNub.generateUUID(), + PubNub.generateUUID(), + PubNub.generateUUID(), + PubNub.generateUUID(), + PubNub.generateUUID(), + PubNub.generateUUID(), + PubNub.generateUUID(), + PubNub.generateUUID(), + PubNub.generateUUID(), + PubNub.generateUUID(), + ]; + let actions: MessageActions.MessageAction[] = []; + let actionsToAdd: { + messageTimetoken: string; + action: Pick; + }[] = []; + let actionsAdded = 0; + + for (let messageIdx = 0; messageIdx < messageTimetokens.length; messageIdx += 1) { + const messageTimetoken = messageTimetokens[messageIdx]; + + for (let messageActionIdx = 0; messageActionIdx < count; messageActionIdx += 1) { + const action = { type: types[(messageActionIdx + 1) % 3], value: values[(messageActionIdx + 1) % 10] }; + + actionsToAdd.push({ messageTimetoken, action }); + } + } + + /** + * Attach set of message actions. + * + * @param actionIdx - Index of currently adding message action. + */ + const addAction = (actionIdx: number) => { + const { messageTimetoken, action } = actionsToAdd[actionIdx]; + + client.addMessageAction({ channel, messageTimetoken, action }, (status, response) => { + actionsAdded += 1; + + if (!status.error && response) { + actions.push(response.data); + actions = actions.sort( + (left, right) => parseInt(left.actionTimetoken, 10) - parseInt(right.actionTimetoken, 10), + ); + } else { + console.error('Action add did fail:', status); + } + + if (actionsAdded < actionsToAdd.length) { + addAction(actionsAdded); + } else if (actionsAdded === actionsToAdd.length) { + completion(actions); + } + }); + }; + + addAction(actionsAdded); +} + +describe('fetch messages endpoints', () => { + const subscribeKey = process.env.SUBSCRIBE_KEY || 'demo'; + const publishKey = process.env.PUBLISH_KEY || 'demo'; + let pubnub: PubNub; + + after(() => { + nock.enableNetConnect(); + }); + + afterEach(() => { + nock.enableNetConnect(); + pubnub.removeAllListeners(); + pubnub.unsubscribeAll(); + pubnub.stop(); + }); + + beforeEach(() => { + nock.cleanAll(); + pubnub = new PubNub({ + subscribeKey, + publishKey, + uuid: 'myUUID', + // @ts-expect-error Force override default value. + useRequestId: false, + useRandomIVs: false, + }); + }); + + it('supports payload', (done) => { + nock.disableNetConnect(); + const scope = utils + .createNock() + .get(`/v3/history/sub-key/${subscribeKey}/channel/ch1,ch2`) + .query({ + max: '10', + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + uuid: 'myUUID', + include_uuid: 'true', + include_message_type: 'true', + }) + .reply( + 200, + '{ "channels": { "ch1": [{"message":{"text":"hey1"},"timetoken":"11"}, {"message":{"text":"hey2"},"timetoken":"12"}], "ch2": [{"message":{"text":"hey3"},"timetoken":"21"}, {"message":{"text":"hey2"},"timetoken":"22"}] } }', + { 'content-type': 'text/javascript' }, + ); + + pubnub.fetchMessages({ channels: ['ch1', 'ch2'], count: 10 }, (status, response) => { + try { + assert.equal(status.error, false); + assert.deepEqual(response, { + channels: { + ch1: [ + { + channel: 'ch1', + message: { + text: 'hey1', + }, + timetoken: '11', + messageType: undefined, + uuid: undefined, + }, + { + channel: 'ch1', + message: { + text: 'hey2', + }, + timetoken: '12', + messageType: undefined, + uuid: undefined, + }, + ], + ch2: [ + { + channel: 'ch2', + message: { + text: 'hey3', + }, + timetoken: '21', + messageType: undefined, + uuid: undefined, + }, + { + channel: 'ch2', + message: { + text: 'hey2', + }, + timetoken: '22', + messageType: undefined, + uuid: undefined, + }, + ], + }, + }); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }); + }); + + it('supports encrypted payload', (done) => { + nock.disableNetConnect(); + const scope = utils + .createNock() + .get(`/v3/history/sub-key/${subscribeKey}/channel/ch1,ch2`) + .query({ + max: '10', + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + uuid: 'myUUID', + include_uuid: 'true', + include_message_type: 'true', + }) + .reply( + 200, + '{ "channels": { "ch1": [{"message":"zFJeF9BVABL80GUiQEBjLg==","timetoken":"11"}, {"message":"zFJeF9BVABL80GUiQEBjLg==","timetoken":"12"}], "ch2": [{"message":"HIq4MTi9nk/KEYlHOKpMCaH78ZXppGynDHrgY9nAd3s=","timetoken":"21"}, {"message":"HIq4MTi9nk/KEYlHOKpMCaH78ZXppGynDHrgY9nAd3s=","timetoken":"22"}] } }', + { 'content-type': 'text/javascript' }, + ); + + pubnub.setCipherKey('cipherKey'); + pubnub.fetchMessages({ channels: ['ch1', 'ch2'], count: 10 }, (status, response) => { + try { + assert.equal(status.error, false); + assert.deepEqual(response, { + channels: { + ch1: [ + { + channel: 'ch1', + message: { + text: 'hey', + }, + timetoken: '11', + messageType: undefined, + uuid: undefined, + }, + { + channel: 'ch1', + message: { + text: 'hey', + }, + timetoken: '12', + messageType: undefined, + uuid: undefined, + }, + ], + ch2: [ + { + channel: 'ch2', + message: { + text2: 'hey2', + }, + timetoken: '21', + messageType: undefined, + uuid: undefined, + }, + { + channel: 'ch2', + message: { + text2: 'hey2', + }, + timetoken: '22', + messageType: undefined, + uuid: undefined, + }, + ], + }, + }); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }); + }); + + it('supports metadata', (done) => { + const channel = PubNub.generateUUID(); + const expectedMessagesCount = 10; + + publishMessagesToChannel(pubnub, expectedMessagesCount, channel, (messages) => { + pubnub.fetchMessages({ channels: [channel], count: 25, includeMeta: true }, (_, response) => { + try { + assert(response !== null); + const channelMessages = response.channels[channel]; + + assert.deepEqual(channelMessages[0].meta, { time: messages[0].message.time }); + assert(!channelMessages[1].meta); + done(); + } catch (error) { + done(error); + } + }); + }); + }).timeout(60000); + + it('throws when requested actions for multiple channels', async () => { + let errorCatched = false; + + try { + await pubnub.fetchMessages({ channels: ['channelA', 'channelB'], includeMessageActions: true }); + } catch (error) { + assert(error instanceof PubNubError); + assert.equal( + error.status!.message, + 'History can return actions data for a single channel only. Either pass a single channel or disable the includeMessageActions flag.', + ); + errorCatched = true; + } + + assert(errorCatched); + }); + + it("supports actions (stored as 'data' field)", (done) => { + const channel = PubNub.generateUUID(); + const expectedMessagesCount = 2; + const expectedActionsCount = 4; + + publishMessagesToChannel(pubnub, expectedMessagesCount, channel, (messages) => { + const messageTimetokens = messages.map((message) => message.timetoken); + + addActionsInChannel(pubnub, expectedActionsCount, messageTimetokens, channel, (actions) => { + setTimeout(() => { + pubnub.fetchMessages({ channels: [channel], includeMessageActions: true }, (status, response) => { + try { + assert.equal(status.error, false); + assert(response !== null); + const fetchedMessages = response.channels[channel]; + // TypeScript types system now requires to figure out type of object before using it. + assert('actions' in fetchedMessages[0]); + const actionsByType = fetchedMessages[0].data ?? {}; + let historyActionsCount = 0; + + Object.keys(actionsByType).forEach((actionType) => { + Object.keys(actionsByType[actionType]).forEach((actionValue) => { + let actionFound = false; + historyActionsCount += 1; + + actions.forEach((action) => { + if (action.value === actionValue) actionFound = true; + }); + + assert.equal(actionFound, true); + }); + }); + + assert.equal(historyActionsCount, expectedActionsCount); + assert.equal(fetchedMessages[0].timetoken, messageTimetokens[0]); + assert.equal( + fetchedMessages[fetchedMessages.length - 1].timetoken, + messageTimetokens[messageTimetokens.length - 1], + ); + + done(); + } catch (error) { + done(error); + } + }); + }, 2000); + }); + }); + }).timeout(60000); + + it("supports actions (stored as 'actions' field)", (done) => { + const channel = PubNub.generateUUID(); + const expectedMessagesCount = 2; + const expectedActionsCount = 4; + + publishMessagesToChannel(pubnub, expectedMessagesCount, channel, (messages) => { + const messageTimetokens = messages.map((message) => message.timetoken); + + addActionsInChannel(pubnub, expectedActionsCount, messageTimetokens, channel, (actions) => { + setTimeout(() => { + pubnub.fetchMessages({ channels: [channel], includeMessageActions: true }, (status, response) => { + try { + assert.equal(status.error, false); + assert(response !== null); + const fetchedMessages = response.channels[channel]; + // TypeScript types system now requires to figure out type of object before using it. + assert('actions' in fetchedMessages[0]); + const actionsByType = fetchedMessages[0].actions ?? {}; + let historyActionsCount = 0; + + Object.keys(actionsByType).forEach((actionType) => { + Object.keys(actionsByType[actionType]).forEach((actionValue) => { + let actionFound = false; + historyActionsCount += 1; + + actions.forEach((action) => { + if (action.value === actionValue) { + actionFound = true; + } + }); + + assert.equal(actionFound, true); + }); + }); + + assert.equal(historyActionsCount, expectedActionsCount); + assert.equal(fetchedMessages[0].timetoken, messageTimetokens[0]); + assert.equal( + fetchedMessages[fetchedMessages.length - 1].timetoken, + messageTimetokens[messageTimetokens.length - 1], + ); + + done(); + } catch (error) { + done(error); + } + }); + }, 2000); + }); + }); + }).timeout(60000); + + it('should return "more" field when server sends it', (done) => { + nock.disableNetConnect(); + const scope = utils + .createNock() + .get(`/v3/history-with-actions/sub-key/${subscribeKey}/channel/ch1`) + .query({ + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + uuid: 'myUUID', + max: '25', + include_uuid: 'true', + include_message_type: 'true', + }) + .reply( + 200, + '{"status":200,"error":false,"error_message":"","channels":{"demo-channel":[{"message":"Hi","timetoken":15610547826970040,"actions":{"receipt":{"read":[{"uuid":"user-7","actionTimetoken":15610547826970044}]}}},{"message":"Hello","timetoken":15610547826970000,"actions":{"reaction":{"smiley_face":[{"uuid":"user-456","actionTimetoken":15610547826970050}]}}}]},"more":{"url":"/v3/history-with-actions/sub-key/s/channel/c?start=15610547826970000&max=98","start":"15610547826970000","max":98}}', + { 'content-type': 'text/javascript' }, + ); + + pubnub.fetchMessages({ channels: ['ch1'], includeMessageActions: true }, (status, response) => { + try { + assert.equal(scope.isDone(), true); + assert.equal(status.error, false); + assert(response !== null); + // TypeScript types system now requires to figure out type of object before using it. + assert('more' in response); + assert.equal(response.more.url, '/v3/history-with-actions/sub-key/s/channel/c?start=15610547826970000&max=98'); + assert.equal(response.more.start, '15610547826970000'); + assert.equal(response.more.max, 98); + done(); + } catch (error) { + done(error); + } + }); + }); + + it('should request 100 messages when count not provided with single channel', (done) => { + nock.disableNetConnect(); + const scope = utils + .createNock() + .get(`/v3/history/sub-key/${subscribeKey}/channel/ch1`) + .query({ + max: '100', + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + uuid: 'myUUID', + include_uuid: 'true', + include_message_type: 'true', + }) + .reply( + 200, + '{ "error": false, "error_message": "", "channels": { "ch1": [ { "message_type": null, "message": "hello world", "timetoken": "16048329933709932", "uuid": "test-uuid"} ] } }', + { 'content-type': 'text/javascript' }, + ); + pubnub.fetchMessages({ channels: ['ch1'] }, (status) => { + try { + assert.equal(scope.isDone(), true); + assert.equal(status.error, false); + done(); + } catch (error) { + done(error); + } + }); + }); + + it('should request 25 messages when count not provided with multiple channels', (done) => { + nock.disableNetConnect(); + const scope = utils + .createNock() + .get(`/v3/history/sub-key/${subscribeKey}/channel/ch1,ch2`) + .query({ + max: '25', + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + uuid: 'myUUID', + include_uuid: 'true', + include_message_type: 'true', + }) + .reply( + 200, + '{ "error": false, "error_message": "", "channels": { "ch1": [ { "message_type": null, "message": "hello world", "timetoken": "16048329933709932", "uuid": "test-uuid"} ] } }', + { 'content-type': 'text/javascript' }, + ); + pubnub.fetchMessages({ channels: ['ch1', 'ch2'] }, (status) => { + try { + assert.equal(scope.isDone(), true); + assert.equal(status.error, false); + done(); + } catch (error) { + done(error); + } + }); + }); + + it('should request 25 messages when count not provided for history-with-actions', (done) => { + nock.disableNetConnect(); + const scope = utils + .createNock() + .get(`/v3/history-with-actions/sub-key/${subscribeKey}/channel/ch1`) + .query({ + max: '25', + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + uuid: 'myUUID', + include_uuid: 'true', + include_message_type: 'true', + }) + .reply( + 200, + '{ "error": false, "error_message": "", "channels": { "ch1": [ { "message_type": null, "message": "hello world", "timetoken": "16048329933709932", "uuid": "test-uuid"} ] } }', + { 'content-type': 'text/javascript' }, + ); + pubnub.fetchMessages({ channels: ['ch1'], includeMessageActions: true }, (status) => { + try { + assert.equal(scope.isDone(), true); + assert.equal(status.error, false); + done(); + } catch (error) { + done(error); + } + }); + }); + + it('should request provided number of messages when count is specified for history-with-actions', (done) => { + nock.disableNetConnect(); + const scope = utils + .createNock() + .get(`/v3/history-with-actions/sub-key/${subscribeKey}/channel/ch1`) + .query({ + max: '10', + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + uuid: 'myUUID', + include_uuid: 'true', + include_message_type: 'true', + }) + .reply( + 200, + '{ "error": false, "error_message": "", "channels": { "ch1": [ { "message_type": null, "message": "hello world", "timetoken": "16048329933709932", "uuid": "test-uuid"} ] } }', + { 'content-type': 'text/javascript' }, + ); + pubnub.fetchMessages({ channels: ['ch1'], includeMessageActions: true, count: 10 }, (status) => { + try { + assert.equal(scope.isDone(), true); + assert.equal(status.error, false); + done(); + } catch (error) { + done(error); + } + }); + }); + + it('should request provided number of messages when count is specified for batch history with single channel', (done) => { + nock.disableNetConnect(); + const scope = utils + .createNock() + .get(`/v3/history/sub-key/${subscribeKey}/channel/ch1`) + .query({ + max: '10', + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + uuid: 'myUUID', + include_uuid: 'true', + include_message_type: 'true', + }) + .reply( + 200, + '{ "error": false, "error_message": "", "channels": { "ch1": [ { "message_type": null, "message": "hello world", "timetoken": "16048329933709932", "uuid": "test-uuid"} ] } }', + { 'content-type': 'text/javascript' }, + ); + pubnub.fetchMessages({ channels: ['ch1'], count: 10 }, (status) => { + try { + assert.equal(scope.isDone(), true); + assert.equal(status.error, false); + done(); + } catch (error) { + done(error); + } + }); + }); + + it('should request provided number of messages when count is specified for batch history with multiple channels', (done) => { + nock.disableNetConnect(); + const scope = utils + .createNock() + .get(`/v3/history/sub-key/${subscribeKey}/channel/ch1,ch2`) + .query({ + max: '10', + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + uuid: 'myUUID', + include_uuid: 'true', + include_message_type: 'true', + }) + .reply( + 200, + '{ "error": false, "error_message": "", "channels": { "ch1": [ { "message_type": null, "message": "hello world", "timetoken": "16048329933709932", "uuid": "test-uuid"} ] } }', + { 'content-type': 'text/javascript' }, + ); + pubnub.fetchMessages({ channels: ['ch1', 'ch2'], count: 10 }, (status) => { + try { + assert.equal(scope.isDone(), true); + assert.equal(status.error, false); + done(); + } catch (error) { + done(error); + } + }); + }); + + it('handles unencrypted payload when cryptomodule configured', (done) => { + nock.disableNetConnect(); + const scope = utils + .createNock() + .get(`/v3/history/sub-key/${subscribeKey}/channel/ch1`) + .query({ + max: '10', + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + uuid: 'myUUID', + include_uuid: 'true', + include_message_type: 'true', + }) + .reply( + 200, + '{ "channels": { "ch1": [{"message":"hello","timetoken":"11"}, {"message":"hey","timetoken":"12"}] } }', + { 'content-type': 'text/javascript' }, + ); + + pubnub.setCipherKey('cipherKey'); + pubnub.fetchMessages({ channels: ['ch1'], count: 10 }, (status, response) => { + try { + assert.equal(status.error, false); + assert.deepEqual(response, { + channels: { + ch1: [ + { + channel: 'ch1', + message: 'hello', + timetoken: '11', + messageType: undefined, + uuid: undefined, + error: 'Error while decrypting message content: Decryption error: invalid header version', + }, + { + channel: 'ch1', + message: 'hey', + timetoken: '12', + messageType: undefined, + uuid: undefined, + error: 'Error while decrypting message content: Decryption error: invalid header version', + }, + ], + }, + }); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }); + }); +}); diff --git a/test/integration/endpoints/get_file_url.test.js b/test/integration/endpoints/get_file_url.test.ts similarity index 66% rename from test/integration/endpoints/get_file_url.test.js rename to test/integration/endpoints/get_file_url.test.ts index e6a6607a3..a0d8c0a0b 100644 --- a/test/integration/endpoints/get_file_url.test.js +++ b/test/integration/endpoints/get_file_url.test.ts @@ -2,6 +2,7 @@ /* eslint no-console: 0 */ import assert from 'assert'; + import PubNub from '../../../src/node/index'; describe('getFileUrl', () => { @@ -10,12 +11,15 @@ describe('getFileUrl', () => { subscribeKey: 'demo', publishKey: 'demo', uuid: 'myUUID', - origin: 'example.com' + // @ts-expect-error Force override default value. + useRequestId: false, + origin: 'example.com', }); const url = pubnub.getFileUrl({ channel: 'channel', id: 'id', name: 'name' }); + // @ts-expect-error Access to the `sdkFamily` required for test purpose. const pnsdk = `PubNub-JS-${pubnub._config.sdkFamily}%2F${pubnub._config.getVersion()}`; - + assert.equal(url, `https://example.com/v1/files/demo/channels/channel/files/id/name?uuid=myUUID&pnsdk=${pnsdk}`); }); @@ -24,14 +28,19 @@ describe('getFileUrl', () => { subscribeKey: 'demo', publishKey: 'demo', uuid: 'myUUID', - origin: ['test1.example.com', 'test2.example.com'] + // @ts-expect-error Force override default value. + useRequestId: false, + origin: ['test1.example.com', 'test2.example.com'], }); const url = pubnub.getFileUrl({ channel: 'channel', id: 'id', name: 'name' }); + // @ts-expect-error Access to the `sdkFamily` required for test purpose. const pnsdk = `PubNub-JS-${pubnub._config.sdkFamily}%2F${pubnub._config.getVersion()}`; - - assert(url === `https://test1.example.com/v1/files/demo/channels/channel/files/id/name?uuid=myUUID&pnsdk=${pnsdk}` - || url === `https://test2.example.com/v1/files/demo/channels/channel/files/id/name?uuid=myUUID&pnsdk=${pnsdk}`); + + assert( + url === `https://test1.example.com/v1/files/demo/channels/channel/files/id/name?uuid=myUUID&pnsdk=${pnsdk}` || + url === `https://test2.example.com/v1/files/demo/channels/channel/files/id/name?uuid=myUUID&pnsdk=${pnsdk}`, + ); }); it('constructs proper url when token is set', () => { @@ -39,12 +48,15 @@ describe('getFileUrl', () => { subscribeKey: 'demo', publishKey: 'demo', uuid: 'myUUID', + // @ts-expect-error Force override default value. + useRequestId: false, origin: 'example.com', }); pubnub.setToken('tokenString'); const url = pubnub.getFileUrl({ channel: 'channel', id: 'id', name: 'name' }); + // @ts-expect-error Access to the `sdkFamily` required for test purpose. const pnsdk = `PubNub-JS-${pubnub._config.sdkFamily}%2F${pubnub._config.getVersion()}`; assert.equal( diff --git a/test/integration/endpoints/grant_token.test.js b/test/integration/endpoints/grant_token.test.ts similarity index 62% rename from test/integration/endpoints/grant_token.test.js rename to test/integration/endpoints/grant_token.test.ts index 61e163ad0..0ae467d84 100644 --- a/test/integration/endpoints/grant_token.test.js +++ b/test/integration/endpoints/grant_token.test.ts @@ -3,11 +3,12 @@ import nock from 'nock'; import sinon from 'sinon'; import utils from '../../utils'; import PubNub from '../../../src/node/index'; +import { PubNubError } from '../../../src/errors/pubnub-error'; describe('grant token endpoint', () => { - let originalVersionFunction = null; - let pubnub; - let clock; + let originalVersionFunction: (() => string) | null = null; + let clock: sinon.SinonFakeTimers; + let pubnub: PubNub; before(() => { nock.disableNetConnect(); @@ -17,7 +18,7 @@ describe('grant token endpoint', () => { after(() => { clock.restore(); nock.enableNetConnect(); - pubnub._config.getVersion = originalVersionFunction; + pubnub._config.getVersion = originalVersionFunction!; }); beforeEach(() => { @@ -27,15 +28,15 @@ describe('grant token endpoint', () => { publishKey: 'myPublishKey', secretKey: 'mySecretKey', uuid: 'myUUID', + // @ts-expect-error Force override default value. + useRequestId: false, autoNetworkDetection: false, }); - pubnub._config.getVersion = () => 'testVersion'; - if (originalVersionFunction === null) { originalVersionFunction = pubnub._config.getVersion; pubnub._config.getVersion = () => 'testVersion'; - } + } else pubnub._config.getVersion = () => 'testVersion'; }); describe('#grantToken', () => { @@ -62,9 +63,13 @@ describe('grant token endpoint', () => { ttl: 1440, }) .catch((err) => { - assert.equal(scope.isDone(), false); - assert.equal(err.status.message, 'Missing either Resources or Patterns.'); - done(); + try { + assert.equal(scope.isDone(), false); + assert.equal(err.status.message, "Missing values for either Resources or Patterns"); + done(); + } catch (error) { + done(error); + } }); }); @@ -95,9 +100,13 @@ describe('grant token endpoint', () => { }, }) .catch((err) => { - assert.equal(scope.isDone(), false); - assert.equal(err.status.message, 'Missing values for either Resources or Patterns.'); - done(); + try { + assert.equal(scope.isDone(), false); + assert.equal(err.status.message, "Missing values for either Resources or Patterns"); + done(); + } catch (error) { + done(error); + } }); }); @@ -128,9 +137,13 @@ describe('grant token endpoint', () => { }, }) .catch((err) => { - assert.equal(scope.isDone(), false); - assert.equal(err.status.message, 'Missing values for either Resources or Patterns.'); - done(); + try { + assert.equal(scope.isDone(), false); + assert.equal(err.status.message, "Missing values for either Resources or Patterns"); + done(); + } catch (error) { + done(error); + } }); }); @@ -139,6 +152,7 @@ describe('grant token endpoint', () => { await pubnub.grantToken({ ttl: 1440, resources: { + // @ts-expect-error It is not allowed to mix in VSP and new permissions type. users: { user1: { read: true } }, }, patterns: { @@ -146,8 +160,9 @@ describe('grant token endpoint', () => { }, }); } catch (e) { + assert(e instanceof PubNubError); assert.strictEqual( - e.status.message, + e.status!.message, // eslint-disable-next-line max-len 'Cannot mix `users`, `spaces` and `authorizedUserId` with `uuids`, `channels`, `groups` and `authorized_uuid`', ); @@ -179,13 +194,16 @@ describe('grant token endpoint', () => { await pubnub.grantToken({ ttl: 1440, resources: { + // @ts-expect-error Intentianally using VSP types. users: { user1: { read: true } }, }, patterns: { + // @ts-expect-error Intentianally using VSP types. users: { '.*': { read: true } }, }, }); } catch (e) { + assert(e instanceof PubNubError); console.log(e.status); } @@ -194,81 +212,3 @@ describe('grant token endpoint', () => { }); }); }); - -describe('grant token endpoint telemetry', () => { - let originalVersionFunction = null; - let pubnub; - - before(() => { - nock.disableNetConnect(); - }); - - after(() => { - nock.enableNetConnect(); - pubnub._config.getVersion = originalVersionFunction; - }); - - beforeEach(() => { - nock.cleanAll(); - pubnub = new PubNub({ - subscribeKey: 'mySubscribeKey', - publishKey: 'myPublishKey', - secretKey: 'mySecretKey', - uuid: 'myUUID', - autoNetworkDetection: false, - }); - - if (originalVersionFunction === null) { - originalVersionFunction = pubnub._config.getVersion; - pubnub._config.getVersion = () => 'testVersion'; - } - }); - - describe('#grantToken', () => { - it('should add PAM grant token API telemetry information', (done) => { - let scope = utils - .createNock() - .post( - '/v3/pam/mySubscribeKey/grant', - '{"ttl":1440,"permissions":{"resources":{"channels":{},"groups":{},"uuids":{"user1":1},"users":{},"spaces":{}},"patterns":{"channels":{},"groups":{},"uuids":{".*":1},"users":{},"spaces":{}},"meta":{}}}', - ) - .query(true); - const delays = [100, 200, 300, 400]; - const countedDelays = delays.slice(0, delays.length - 1); - const average = Math.floor(countedDelays.reduce((acc, delay) => acc + delay, 0) / countedDelays.length); - const leeway = 50; - - utils - .runAPIWithResponseDelays( - scope, - 200, - { message: 'Success', data: { token: 'token' } }, - delays, - (completion) => { - pubnub.grantToken( - { - ttl: 1440, - resources: { - channels: {}, - groups: {}, - uuids: { user1: { read: true } }, - }, - patterns: { - channels: {}, - groups: {}, - uuids: { '.*': { read: true } }, - }, - }, - () => { - completion(); - }, - ); - }, - ) - .then((lastRequest) => { - utils.verifyRequestTelemetry(lastRequest.path, 'l_pamv3', average, leeway); - done(); - }); - }).timeout(60000); - }); -}); diff --git a/test/integration/endpoints/history.test.js b/test/integration/endpoints/history.test.ts similarity index 51% rename from test/integration/endpoints/history.test.js rename to test/integration/endpoints/history.test.ts index 34897b3c4..d2d55a111 100644 --- a/test/integration/endpoints/history.test.js +++ b/test/integration/endpoints/history.test.ts @@ -3,26 +3,47 @@ import assert from 'assert'; import nock from 'nock'; -import utils from '../../utils'; + +import { Payload } from '../../../src/core/types/api'; import PubNub from '../../../src/node/index'; +import utils from '../../utils'; -function publishMessagesToChannel(client, count, channel, completion) { +/** + * Published test message shape. + */ +type TestMessage = { messageIdx: string; time: number }; + +/** + * Prepare messages history. + * + * @param client - PubNub client instance which will be used to publish messages. + * @param count - How many messages should be published. + * @param channel - Name of the channel into which messages should be published. + * @param completion - Messages set publish completion function. + */ +function publishMessagesToChannel( + client: PubNub, + count: number, + channel: string, + completion: (published: { message: TestMessage; timetoken: string }[]) => void, +) { + let messages: { message: TestMessage; timetoken: string }[] = []; let publishCompleted = 0; - let messages = []; - const publish = (messageIdx) => { - let payload = { message: { messageIdx: [channel, messageIdx].join(': '), time: Date.now() }, channel }; + const publish = (messageIdx: number) => { + let payload: { channel: string; message: TestMessage; meta?: Payload } = { + message: { messageIdx: [channel, messageIdx].join(': '), time: Date.now() }, + channel, + }; - if (messageIdx % 2 === 0) { - payload.meta = { time: payload.message.time }; - } + if (messageIdx % 2 === 0) payload.meta = { time: payload.message.time }; client.publish(payload, (status, response) => { publishCompleted += 1; - if (!status.error) { + if (!status.error && response) { messages.push({ message: payload.message, timetoken: response.timetoken }); - messages = messages.sort((left, right) => left.timetoken - right.timetoken); + messages = messages.sort((left, right) => parseInt(left.timetoken, 10) - parseInt(right.timetoken, 10)); } else { console.error('Publish did fail:', status); } @@ -41,7 +62,7 @@ function publishMessagesToChannel(client, count, channel, completion) { describe('history endpoints', () => { const subscribeKey = process.env.SUBSCRIBE_KEY || 'demo'; const publishKey = process.env.PUBLISH_KEY || 'demo'; - let pubnub; + let pubnub: PubNub; after(() => { nock.enableNetConnect(); @@ -60,6 +81,8 @@ describe('history endpoints', () => { subscribeKey, publishKey, uuid: 'myUUID', + // @ts-expect-error Force override default value. + useRequestId: false, useRandomIVs: false, }); }); @@ -79,18 +102,24 @@ describe('history endpoints', () => { .reply( 200, '[[{"message":{"text":"hey"},"timetoken":"14648503433058358"},{"message":{"text2":"hey2"},"timetoken":"14648503433058359"}],"14648503433058358","14649346364851578"]', + { 'content-type': 'text/javascript' }, ); pubnub.history({ channel: 'ch1', stringifiedTimeToken: true }, (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.startTimeToken, '14648503433058358'); - assert.deepEqual(response.endTimeToken, '14649346364851578'); - assert.deepEqual(response.messages, [ - { timetoken: '14648503433058358', entry: { text: 'hey' } }, - { timetoken: '14648503433058359', entry: { text2: 'hey2' } }, - ]); - assert.equal(scope.isDone(), true); - done(); + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.startTimeToken, "14648503433058358"); + assert.deepEqual(response.endTimeToken, "14649346364851578"); + assert.deepEqual(response.messages, [ + { timetoken: "14648503433058358", entry: { text: "hey" } }, + { timetoken: "14648503433058359", entry: { text2: "hey2" } } + ]); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } }); }); @@ -109,19 +138,25 @@ describe('history endpoints', () => { .reply( 200, '[[{"message":"zFJeF9BVABL80GUiQEBjLg==","timetoken":"14649369736959785"},{"message":"HIq4MTi9nk/KEYlHOKpMCaH78ZXppGynDHrgY9nAd3s=","timetoken":"14649369766426772"}],"14649369736959785","14649369766426772"]', + { 'content-type': 'text/javascript' }, ); pubnub.setCipherKey('cipherKey'); pubnub.history({ channel: 'ch1', stringifiedTimeToken: true }, (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.startTimeToken, '14649369736959785'); - assert.deepEqual(response.endTimeToken, '14649369766426772'); - assert.deepEqual(response.messages, [ - { timetoken: '14649369736959785', entry: { text: 'hey' } }, - { timetoken: '14649369766426772', entry: { text2: 'hey2' } }, - ]); - assert.equal(scope.isDone(), true); - done(); + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.startTimeToken, "14649369736959785"); + assert.deepEqual(response.endTimeToken, "14649369766426772"); + assert.deepEqual(response.messages, [ + { timetoken: "14649369736959785", entry: { text: "hey" } }, + { timetoken: "14649369766426772", entry: { text2: "hey2" } } + ]); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } }); }); @@ -130,40 +165,19 @@ describe('history endpoints', () => { const expectedMessagesCount = 10; publishMessagesToChannel(pubnub, expectedMessagesCount, channel, (messages) => { - pubnub.history({ channel, includeMeta: true }, (status, response) => { - assert.deepEqual(response.messages[0].meta, { time: messages[0].message.time }); - assert(!response.messages[1].meta); - done(); + pubnub.history({ channel, includeMeta: true }, (_, response) => { + try { + assert(response !== null); + assert.deepEqual(response.messages[0].meta, { time: messages[0].message.time }); + assert(!response.messages[1].meta); + done(); + } catch (error) { + done(error); + } }); }); }).timeout(60000); - it('should add history API telemetry information', (done) => { - nock.disableNetConnect(); - let scope = utils.createNock().get(`/v2/history/sub-key/${subscribeKey}/channel/ch1`).query(true); - const delays = [100, 200, 300, 400]; - const countedDelays = delays.slice(0, delays.length - 1); - const average = Math.floor(countedDelays.reduce((acc, delay) => acc + delay, 0) / countedDelays.length); - const leeway = 50; - - utils - .runAPIWithResponseDelays( - scope, - 200, - '[[{"message":{"text":"hey"},"timetoken":"14648503433058358"},{"message":{"text2":"hey2"},"timetoken":"14648503433058359"}],"14648503433058358","14649346364851578"]', - delays, - (completion) => { - pubnub.history({ channel: 'ch1', stringifiedTimeToken: true }, () => { - completion(); - }); - }, - ) - .then((lastRequest) => { - utils.verifyRequestTelemetry(lastRequest.path, 'l_hist', average, leeway); - done(); - }); - }).timeout(60000); - it('handles unencrypted payload with cryptoModule', (done) => { nock.disableNetConnect(); const scope = utils @@ -179,22 +193,28 @@ describe('history endpoints', () => { .reply( 200, '[[{"message":"zFJeF9BVABL80GUiQEBjLg==","timetoken":"14648503433058358"},{"message":"hello","timetoken":"14648503433058359"}],"14648503433058358","14649346364851578"]', + { 'content-type': 'text/javascript' }, ); pubnub.setCipherKey('cipherKey'); pubnub.history({ channel: 'ch1', stringifiedTimeToken: true }, (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.startTimeToken, '14648503433058358'); - assert.deepEqual(response.endTimeToken, '14649346364851578'); - assert.deepEqual(response.messages, [ - { timetoken: '14648503433058358', entry: { text: 'hey' } }, - { - timetoken: '14648503433058359', - entry: 'hello', - error: 'Error while decrypting message content: decryption error. invalid header version', - }, - ]); - assert.equal(scope.isDone(), true); - done(); + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.startTimeToken, "14648503433058358"); + assert.deepEqual(response.endTimeToken, "14649346364851578"); + assert.deepEqual(response.messages, [ + { timetoken: "14648503433058358", entry: { text: "hey" } }, + { + timetoken: "14648503433058359", + entry: "hello", + error: "Error while decrypting message content: Decryption error: invalid header version" + } + ]); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } }); }); }); diff --git a/test/integration/endpoints/message_actions.test.js b/test/integration/endpoints/message_actions.test.js deleted file mode 100644 index 8b8725c66..000000000 --- a/test/integration/endpoints/message_actions.test.js +++ /dev/null @@ -1,612 +0,0 @@ -/* global describe, beforeEach, afterEach, it, after */ -/* eslint no-console: 0 */ - -import assert from 'assert'; -import nock from 'nock'; -import PubNub from '../../../src/node/index'; -import utils from '../../utils'; - - -function publishMessages(client , count , channel , completion ) { - let publishCompleted = 0; - let timetokens = []; - - const publish = (messageIdx) => { - const message = { messageIdx, time: Date.now() }; - - client.publish( - { message, channel }, - (status, response) => { - publishCompleted += 1; - - if (!status.error) { - timetokens.push(response.timetoken); - } else { - console.error('Publish did fail:', status); - } - - if (publishCompleted < count) { - publish(publishCompleted); - } else if (publishCompleted === count) { - completion(timetokens.sort((left, right) => left - right)); - } - } - ); - }; - - publish(publishCompleted); -} - -function addActions(client , count , messageTimetokens , channel , completion ) { - const types = ['reaction', 'receipt', 'custom']; - const values = [ - PubNub.generateUUID(), PubNub.generateUUID(), PubNub.generateUUID(), PubNub.generateUUID(), PubNub.generateUUID(), - PubNub.generateUUID(), PubNub.generateUUID(), PubNub.generateUUID(), PubNub.generateUUID(), PubNub.generateUUID() - ]; - let actionsToAdd = []; - let actionsAdded = 0; - let timetokens = []; - - for (let messageIdx = 0; messageIdx < messageTimetokens.length; messageIdx += 1) { - const messageTimetoken = messageTimetokens[messageIdx]; - - for (let messageActionIdx = 0; messageActionIdx < count; messageActionIdx += 1) { - /** @type MessageAction */ - const action = { type: types[(messageActionIdx + 1) % 3], value: values[(messageActionIdx + 1) % 10] }; - - actionsToAdd.push({ messageTimetoken, action }); - } - } - - const addAction = (actionIdx) => { - const { messageTimetoken, action } = actionsToAdd[actionIdx]; - - client.addMessageAction( - { channel, messageTimetoken, action }, - (status, response) => { - actionsAdded += 1; - - if (!status.error) { - timetokens.push(response.data.actionTimetoken); - } else { - console.error('Action add did fail:', action, '\n', status); - } - - if (actionsAdded < actionsToAdd.length) { - addAction(actionsAdded); - } else if (actionsAdded === actionsToAdd.length) { - completion(timetokens.sort((left, right) => left - right)); - } - } - ); - }; - - addAction(actionsAdded); -} - - -describe('message actions endpoints', () => { - const subscribeKey = process.env.SUBSCRIBE_KEY || 'demo'; - const publishKey = process.env.PUBLISH_KEY || 'demo'; - let pubnub; - - after(() => { - nock.enableNetConnect(); - }); - - afterEach(() => { - nock.enableNetConnect(); - pubnub.removeAllListeners(); - pubnub.unsubscribeAll(); - pubnub.stop(); - }); - - beforeEach(() => { - nock.cleanAll(); - pubnub = new PubNub({ - subscribeKey, - publishKey, - uuid: 'myUUID', - authKey: 'myAuthKey', - }); - }); - - describe('addMessageAction', () => { - describe('##validation', () => { - it('fails if \'action\' is missing', (done) => { - nock.disableNetConnect(); - const scope = utils - .createNock() - .post(`/v1/message-actions/${subscribeKey}/channel/test-channel/message/1234567890`) - .reply(200, {}); - - pubnub.addMessageAction({ - channel: 'test-channel', - messageTimetoken: '1234567890', - }) - .catch((err) => { - assert.equal(scope.isDone(), false); - assert.equal(err.status.message, 'Missing Action'); - done(); - }); - }); - - it('fails if \'type\' is missing', (done) => { - nock.disableNetConnect(); - const scope = utils - .createNock() - .post(`/v1/message-actions/${subscribeKey}/channel/test-channel/message/1234567890`) - .reply(200, {}); - const action = { value: 'test value' }; - - pubnub.addMessageAction({ - channel: 'test-channel', - messageTimetoken: '1234567890', - action, - }) - .catch((err) => { - assert.equal(scope.isDone(), false); - assert.equal(err.status.message, 'Missing Action.type'); - done(); - }); - }); - - it('fails if \'type\' is too long', (done) => { - nock.disableNetConnect(); - const scope = utils - .createNock() - .post(`/v1/message-actions/${subscribeKey}/channel/test-channel/message/1234567890`) - .reply(200, {}); - const action = { type: PubNub.generateUUID(), value: 'test value' }; - - pubnub.addMessageAction({ - channel: 'test-channel', - messageTimetoken: '1234567890', - action, - }) - .catch((err) => { - assert.equal(scope.isDone(), false); - assert.equal(err.status.message, 'Action.type value exceed maximum length of 15'); - done(); - }); - }); - - it('fails if \'value\' is missing', (done) => { - nock.disableNetConnect(); - const scope = utils - .createNock() - .post(`/v1/message-actions/${subscribeKey}/channel/test-channel/message/1234567890`) - .reply(200, {}); - const action = { type: 'custom' }; - - pubnub.addMessageAction({ - channel: 'test-channel', - messageTimetoken: '1234567890', - action, - }) - .catch((err) => { - assert.equal(scope.isDone(), false); - assert.equal(err.status.message, 'Missing Action.value'); - done(); - }); - }); - - it('fails if \'messageTimetoken\' is missing', (done) => { - nock.disableNetConnect(); - const scope = utils - .createNock() - .post(`/v1/message-actions/${subscribeKey}/channel/test-channel/message/`) - .reply(200, {}); - const action = { type: 'custom', value: 'test value' }; - - pubnub.addMessageAction({ - channel: 'test-channel', - action, - }) - .catch((err) => { - assert.equal(scope.isDone(), false); - assert.equal(err.status.message, 'Missing message timetoken'); - done(); - }); - }); - - it('fails if \'channel\' is missing', (done) => { - nock.disableNetConnect(); - const scope = utils - .createNock() - .post(`/v1/message-actions/${subscribeKey}/channel/test-channel/message/1234567890`) - .reply(200, {}); - const action = { type: 'custom', value: 'test value' }; - - pubnub.addMessageAction({ - messageTimetoken: '1234567890', - action, - }) - .catch((err) => { - assert.equal(scope.isDone(), false); - assert.equal(err.status.message, 'Missing message channel'); - done(); - }); - }); - }); - - it('add message action', (done) => { - /** @type MessageAction */ - const messageAction = { type: 'custom', value: PubNub.generateUUID() }; - const channel = PubNub.generateUUID(); - - publishMessages(pubnub, 1, channel, (timetokens) => { - pubnub.addMessageAction( - { channel, messageTimetoken: timetokens[0], action: messageAction }, - (status, response) => { - assert.equal(status.error, false); - assert.equal(response.data.type, messageAction.type); - assert.equal(response.data.value, messageAction.value); - assert.equal(response.data.uuid, pubnub.getUUID()); - assert.equal(response.data.messageTimetoken, timetokens[0]); - assert(response.data.actionTimetoken); - - done(); - } - ); - }); - }).timeout(60000); - - it('add message action with encoded channel', (done) => { - /** @type MessageAction */ - const messageAction = { type: 'custom', value: PubNub.generateUUID() }; - const channel = `${PubNub.generateUUID()}#1`; - - publishMessages(pubnub, 1, channel, (timetokens) => { - pubnub.addMessageAction( - { channel, messageTimetoken: timetokens[0], action: messageAction }, - (status, response) => { - assert.equal(status.error, false); - assert.equal(response.data.type, messageAction.type); - assert.equal(response.data.value, messageAction.value); - assert.equal(response.data.uuid, pubnub.getUUID()); - assert.equal(response.data.messageTimetoken, timetokens[0]); - assert(response.data.actionTimetoken); - - done(); - } - ); - }); - }).timeout(60000); - - it('add message action and 207 status code', (done) => { - nock.disableNetConnect(); - const scope = utils - .createNock() - .post(`/v1/message-actions/${subscribeKey}/channel/test-channel/message/1234567890`) - .query({ - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - auth: 'myAuthKey' - }) - .reply(207, { - status: 207, - data: { - type: 'reaction', - value: 'smiley_face', - uuid: 'user-456', - actionTimetoken: '15610547826970050', - messageTimetoken: '15610547826969050' - }, - error: { - message: 'Stored but failed to publish message action.', - source: 'actions' - } - }); - - pubnub.addMessageAction( - { channel: 'test-channel', messageTimetoken: '1234567890', action: { type: 'custom', value: 'test' } }, - (status) => { - assert.equal(scope.isDone(), true); - assert.equal(status.statusCode, 207); - assert(status.errorData.message); - - done(); - } - ); - }); - - it('add message action should trigger event', (done) => { - /** @type MessageAction */ - const messageAction = { type: 'custom', value: PubNub.generateUUID() }; - const channel = PubNub.generateUUID(); - let messageTimetoken = null; - - pubnub.addListener({ - status: (status) => { - if (status.category === 'PNConnectedCategory') { - pubnub.publish( - { channel, message: { hello: 'test' }, sendByPost: true }, - (publishStatus, response) => { - messageTimetoken = response.timetoken; - - pubnub.addMessageAction( - { channel, messageTimetoken, action: messageAction } - ); - } - ); - } - }, - messageAction: (messageActionEvent) => { - assert(messageActionEvent.data); - assert.equal(messageActionEvent.data.type, messageAction.type); - assert.equal(messageActionEvent.data.value, messageAction.value); - assert.equal(messageActionEvent.data.uuid, pubnub.getUUID()); - assert.equal(messageActionEvent.data.messageTimetoken, messageTimetoken); - assert(messageActionEvent.data.actionTimetoken); - assert.equal(messageActionEvent.event, 'added'); - pubnub.unsubscribeAll() - - done(); - } - }); - - pubnub.subscribe({ channels: [channel] }); - }).timeout(60000); - }); - - describe('removeMessageAction', () => { - describe('##validation', () => { - it('fails if \'messageTimetoken\' is missing', (done) => { - nock.disableNetConnect(); - const scope = utils - .createNock() - .delete(`/v1/message-actions/${subscribeKey}/channel/test-channel/message/1234567890/action/12345678901`) - .reply(200, {}); - - pubnub.removeMessageAction({ - channel: 'test-channel', - actionTimetoken: '1234567890', - }) - .catch((err) => { - assert.equal(scope.isDone(), false); - assert.equal(err.status.message, 'Missing message timetoken'); - - done(); - }); - }); - - it('fails if \'actionTimetoken\' is missing', (done) => { - nock.disableNetConnect(); - const scope = utils - .createNock() - .delete(`/v1/message-actions/${subscribeKey}/channel/test-channel/message/1234567890/action/12345678901`) - .reply(200, {}); - - pubnub.removeMessageAction({ - channel: 'test-channel', - messageTimetoken: '1234567890', - }) - .catch((err) => { - assert.equal(scope.isDone(), false); - assert.equal(err.status.message, 'Missing action timetoken'); - - done(); - }); - }); - - it('fails if \'channel\' is missing', (done) => { - nock.disableNetConnect(); - const scope = utils - .createNock() - .delete(`/v1/message-actions/${subscribeKey}/channel/test-channel/message/1234567890/action/12345678901`) - .reply(200, {}); - - pubnub.removeMessageAction({ - messageTimetoken: '1234567890', - actionTimetoken: '12345678901', - }) - .catch((err) => { - assert.equal(scope.isDone(), false); - assert.equal(err.status.message, 'Missing message channel'); - - done(); - }); - }); - }); - - it('remove message action', (done) => { - const channel = PubNub.generateUUID(); - - publishMessages(pubnub, 1, channel, (messageTimetokens) => { - addActions(pubnub, 1, messageTimetokens, channel, (actionTimetokens) => { - pubnub.getMessageActions({ channel }, (status, response) => { - assert.equal(status.error, false); - assert.equal(response.data.length, actionTimetokens.length); - - pubnub.removeMessageAction( - { channel, actionTimetoken: actionTimetokens[0], messageTimetoken: messageTimetokens[0] }, - (removeMessageStatus) => { - assert.equal(removeMessageStatus.error, false); - - setTimeout(() => { - pubnub.getMessageActions({ channel }, (getMessagesStatus, getMessagesResponse) => { - assert.equal(getMessagesStatus.error, false); - assert.equal(getMessagesResponse.data.length, 0); - - done(); - }); - }, 2000); - } - ); - }); - }); - }); - }).timeout(60000); - - it('remove message action with encoded channel', (done) => { - const channel = `${PubNub.generateUUID()}#1`; - - publishMessages(pubnub, 1, channel, (messageTimetokens) => { - addActions(pubnub, 1, messageTimetokens, channel, (actionTimetokens) => { - pubnub.getMessageActions({ channel }, (status, response) => { - assert.equal(status.error, false); - assert.equal(response.data.length, actionTimetokens.length); - - pubnub.removeMessageAction( - { channel, actionTimetoken: actionTimetokens[0], messageTimetoken: messageTimetokens[0] }, - (removeMessageStatus) => { - assert.equal(removeMessageStatus.error, false); - - setTimeout(() => { - pubnub.getMessageActions({ channel }, (getMessagesStatus, getMessagesResponse) => { - assert.equal(getMessagesStatus.error, false); - assert.equal(getMessagesResponse.data.length, 0); - - done(); - }); - }, 2000); - } - ); - }); - }); - }); - }).timeout(60000); - - it('remove message action should trigger event', (done) => { - const channel = PubNub.generateUUID(); - - publishMessages(pubnub, 1, channel, (messageTimetokens) => { - addActions(pubnub, 1, messageTimetokens, channel, (actionTimetokens) => { - pubnub.addListener({ - status: (status) => { - if (status.category === 'PNConnectedCategory') { - pubnub.removeMessageAction( - { channel, actionTimetoken: actionTimetokens[0], messageTimetoken: messageTimetokens[0] }, - (removeMessagesStatus) => { - assert.equal(removeMessagesStatus.error, false); - } - ); - } - }, - messageAction: (messageActionEvent) => { - assert(messageActionEvent.data); - assert.equal(messageActionEvent.data.uuid, pubnub.getUUID()); - assert.equal(messageActionEvent.data.messageTimetoken, messageTimetokens[0]); - assert.equal(messageActionEvent.data.actionTimetoken, actionTimetokens[0]); - assert.equal(messageActionEvent.event, 'removed'); - pubnub.unsubscribeAll() - - done(); - } - }); - - pubnub.subscribe({ channels: [channel] }); - }); - }); - }).timeout(60000); - }); - - describe('getMessageAction', () => { - describe('##validation', () => { - it('fails if \'channel\' is missing', (done) => { - nock.disableNetConnect(); - const scope = utils - .createNock() - .get(`/v1/message-actions/${subscribeKey}/channel/test-channel`) - .reply(200, {}); - - pubnub.getMessageActions({}).catch((err) => { - assert.equal(scope.isDone(), false); - assert.equal(err.status.message, 'Missing message channel'); - - done(); - }); - }); - }); - - it('fetch message actions', (done) => { - const channel = PubNub.generateUUID(); - - publishMessages(pubnub, 2, channel, (messageTimetokens) => { - addActions(pubnub, 3, messageTimetokens, channel, (actionTimetokens) => { - const lastPublishedActionTimetoken = actionTimetokens[actionTimetokens.length - 1]; - const firstPublishedActionTimetoken = actionTimetokens[0]; - - pubnub.getMessageActions({ channel }, (status, response) => { - assert.equal(status.error, false); - const firstFetchedActionTimetoken = response.data[0].actionTimetoken; - const lastFetchedActionTimetoken = response.data[response.data.length - 1].actionTimetoken; - assert.equal(firstFetchedActionTimetoken, firstPublishedActionTimetoken); - assert.equal(lastFetchedActionTimetoken, lastPublishedActionTimetoken); - assert.equal(response.data.length, actionTimetokens.length); - assert.equal(response.start, firstPublishedActionTimetoken); - assert.equal(response.end, lastPublishedActionTimetoken); - - done(); - }); - }); - }); - }).timeout(60000); - - it('fetch message actions with encoded channel', (done) => { - const channel = `${PubNub.generateUUID()}#1`; - - publishMessages(pubnub, 2, channel, (messageTimetokens) => { - addActions(pubnub, 3, messageTimetokens, channel, (actionTimetokens) => { - const lastPublishedActionTimetoken = actionTimetokens[actionTimetokens.length - 1]; - const firstPublishedActionTimetoken = actionTimetokens[0]; - - pubnub.getMessageActions({ channel }, (status, response) => { - assert.equal(status.error, false); - const firstFetchedActionTimetoken = response.data[0].actionTimetoken; - const lastFetchedActionTimetoken = response.data[response.data.length - 1].actionTimetoken; - assert.equal(firstFetchedActionTimetoken, firstPublishedActionTimetoken); - assert.equal(lastFetchedActionTimetoken, lastPublishedActionTimetoken); - assert.equal(response.data.length, actionTimetokens.length); - assert.equal(response.start, firstPublishedActionTimetoken); - assert.equal(response.end, lastPublishedActionTimetoken); - - done(); - }); - }); - }); - }).timeout(60000); - - it('fetch next message actions page', (done) => { - const channel = PubNub.generateUUID(); - - publishMessages(pubnub, 2, channel, (messageTimetokens) => { - addActions(pubnub, 5, messageTimetokens, channel, (actionTimetokens) => { - const lastPublishedActionTimetoken = actionTimetokens[actionTimetokens.length - 1]; - const halfSize = Math.floor(actionTimetokens.length * 0.5); - const firstPublishedActionTimetoken = actionTimetokens[0]; - const middleMinusOnePublishedActionTimetoken = actionTimetokens[halfSize - 1]; - const middlePublishedActionTimetoken = actionTimetokens[halfSize]; - - pubnub.getMessageActions({ channel, limit: halfSize }, (status, response) => { - assert.equal(status.error, false); - let firstFetchedActionTimetoken = response.data[0].actionTimetoken; - let lastFetchedActionTimetoken = response.data[response.data.length - 1].actionTimetoken; - assert.equal(firstFetchedActionTimetoken, middlePublishedActionTimetoken); - assert.equal(lastFetchedActionTimetoken, lastPublishedActionTimetoken); - assert.equal(response.data.length, halfSize); - assert.equal(response.start, middlePublishedActionTimetoken); - assert.equal(response.end, lastPublishedActionTimetoken); - - pubnub.getMessageActions( - { channel, start: middlePublishedActionTimetoken, limit: halfSize }, - (getMessageActionsStatus, getMessageActionsResponse) => { - assert.equal(getMessageActionsStatus.error, false); - firstFetchedActionTimetoken = getMessageActionsResponse.data[0].actionTimetoken; - lastFetchedActionTimetoken = getMessageActionsResponse.data[getMessageActionsResponse.data.length - 1].actionTimetoken; - assert.equal(firstFetchedActionTimetoken, firstPublishedActionTimetoken); - assert.equal(lastFetchedActionTimetoken, middleMinusOnePublishedActionTimetoken); - assert.equal(getMessageActionsResponse.data.length, halfSize); - assert.equal(getMessageActionsResponse.start, firstPublishedActionTimetoken); - assert.equal(getMessageActionsResponse.end, middleMinusOnePublishedActionTimetoken); - - done(); - } - ); - }); - }); - }); - }).timeout(60000); - }); -}); diff --git a/test/integration/endpoints/message_actions.test.ts b/test/integration/endpoints/message_actions.test.ts new file mode 100644 index 000000000..ab3bcf4a9 --- /dev/null +++ b/test/integration/endpoints/message_actions.test.ts @@ -0,0 +1,752 @@ +/* global describe, beforeEach, afterEach, it, after */ +/* eslint no-console: 0 */ + +import assert from 'assert'; +import nock from 'nock'; + +import * as MessageActions from '../../../src/core/types/api/message-action'; +import PubNub from '../../../src/node/index'; +import utils from '../../utils'; + +/** + * Message action object. + */ +type MessageAction = MessageActions.AddMessageActionParameters['action']; + +/** + * Prepare messages history. + * + * @param client - PubNub client instance which will be used to publish messages. + * @param count - How many messages should be published. + * @param channel - Name of the channel into which messages should be published. + * @param completion - Messages set publish completion function. + */ +function publishMessages(client: PubNub, count: number, channel: string, completion: (timetokens: string[]) => void) { + let publishCompleted = 0; + let timetokens: string[] = []; + + const publish = (messageIdx: number) => { + const message = { messageIdx, time: Date.now() }; + + client.publish({ message, channel }, (status, response) => { + publishCompleted += 1; + + if (!status.error && response) { + timetokens.push(response.timetoken); + } else { + console.error('Publish did fail:', status); + } + + if (publishCompleted < count) { + publish(publishCompleted); + } else if (publishCompleted === count) { + completion(timetokens.sort((left, right) => parseInt(left, 10) - parseInt(right, 10))); + } + }); + }; + + publish(publishCompleted); +} + +/** + * Attach message actions to the previously published messages. + * + * @param client - PubNub client instance which should be used to add message action to the message. + * @param count - How many message actions should be added to each referenced message. + * @param messageTimetokens - List of referenced messages' timetokens. + * @param channel - Name of the channel where referenced messages has been published. + * @param completion - Message actions addition completion function. + */ +function addActions( + client: PubNub, + count: number, + messageTimetokens: string[], + channel: string, + completion: (timetokens: string[]) => void, +) { + const types = ['reaction', 'receipt', 'custom']; + const values = [ + PubNub.generateUUID(), + PubNub.generateUUID(), + PubNub.generateUUID(), + PubNub.generateUUID(), + PubNub.generateUUID(), + PubNub.generateUUID(), + PubNub.generateUUID(), + PubNub.generateUUID(), + PubNub.generateUUID(), + PubNub.generateUUID(), + ]; + let actionsToAdd: { messageTimetoken: string; action: MessageAction }[] = []; + let timetokens: string[] = []; + let actionsAdded = 0; + + for (let messageIdx = 0; messageIdx < messageTimetokens.length; messageIdx += 1) { + const messageTimetoken = messageTimetokens[messageIdx]; + + for (let messageActionIdx = 0; messageActionIdx < count; messageActionIdx += 1) { + const action: MessageAction = { + type: types[(messageActionIdx + 1) % 3], + value: values[(messageActionIdx + 1) % 10], + }; + + actionsToAdd.push({ messageTimetoken, action }); + } + } + + /** + * Attach set of message actions. + * + * @param actionIdx - Index of currently adding message action. + */ + const addAction = (actionIdx: number) => { + const { messageTimetoken, action } = actionsToAdd[actionIdx]; + + client.addMessageAction({ channel, messageTimetoken, action }, (status, response) => { + actionsAdded += 1; + + if (!status.error && response) { + timetokens.push(response.data.actionTimetoken); + } else { + console.error('Action add did fail:', action, '\n', status); + } + + if (actionsAdded < actionsToAdd.length) { + addAction(actionsAdded); + } else if (actionsAdded === actionsToAdd.length) { + completion(timetokens.sort((left, right) => parseInt(left, 10) - parseInt(right, 10))); + } + }); + }; + + addAction(actionsAdded); +} + +describe('message actions endpoints', () => { + const subscribeKey = process.env.SUBSCRIBE_KEY || 'demo'; + const publishKey = process.env.PUBLISH_KEY || 'demo'; + let pubnub: PubNub; + + after(() => { + nock.enableNetConnect(); + }); + + afterEach(() => { + nock.enableNetConnect(); + pubnub.removeAllListeners(); + pubnub.unsubscribeAll(); + pubnub.stop(); + }); + + beforeEach(() => { + nock.cleanAll(); + pubnub = new PubNub({ + subscribeKey, + publishKey, + uuid: 'myUUID', + authKey: 'myAuthKey', + // @ts-expect-error Force override default value. + useRequestId: false, + }); + }); + + describe('addMessageAction', () => { + describe('##validation', () => { + it("fails if 'action' is missing", (done) => { + nock.disableNetConnect(); + const scope = utils + .createNock() + .post(`/v1/message-actions/${subscribeKey}/channel/test-channel/message/1234567890`) + .reply(200, {}); + + pubnub + // @ts-expect-error Intentionally don't include `action`. + .addMessageAction({ + channel: 'test-channel', + messageTimetoken: '1234567890', + }) + .catch((err) => { + try { + assert.equal(scope.isDone(), false); + assert.equal(err.status.message, "Missing Action"); + done(); + } catch (error) { + done(error); + } + }); + }); + + it("fails if 'type' is missing", (done) => { + nock.disableNetConnect(); + const scope = utils + .createNock() + .post(`/v1/message-actions/${subscribeKey}/channel/test-channel/message/1234567890`) + .reply(200, {}); + const action = { value: 'test value' }; + + pubnub + .addMessageAction({ + channel: 'test-channel', + messageTimetoken: '1234567890', + // @ts-expect-error Intentionally don't include `type` field into `action`. + action, + }) + .catch((err) => { + try { + assert.equal(scope.isDone(), false); + assert.equal(err.status.message, "Missing Action.type"); + done(); + } catch (error) { + done(error); + } + }); + }); + + it("fails if 'type' is too long", (done) => { + nock.disableNetConnect(); + const scope = utils + .createNock() + .post(`/v1/message-actions/${subscribeKey}/channel/test-channel/message/1234567890`) + .reply(200, {}); + const action: MessageAction = { type: PubNub.generateUUID(), value: 'test value' }; + + pubnub + .addMessageAction({ + channel: 'test-channel', + messageTimetoken: '1234567890', + action, + }) + .catch((err) => { + try { + assert.equal(scope.isDone(), false); + assert.equal(err.status.message, "Action.type value exceed maximum length of 15"); + done(); + } catch (error) { + done(error); + } + }); + }); + + it("fails if 'value' is missing", (done) => { + nock.disableNetConnect(); + const scope = utils + .createNock() + .post(`/v1/message-actions/${subscribeKey}/channel/test-channel/message/1234567890`) + .reply(200, {}); + const action = { type: 'custom' }; + + pubnub + .addMessageAction({ + channel: 'test-channel', + messageTimetoken: '1234567890', + // @ts-expect-error Intentionally don't include `value` field into `action`. + action, + }) + .catch((err) => { + try { + assert.equal(scope.isDone(), false); + assert.equal(err.status.message, "Missing Action.value"); + done(); + } catch (error) { + done(error); + } + }); + }); + + it("fails if 'messageTimetoken' is missing", (done) => { + nock.disableNetConnect(); + const scope = utils + .createNock() + .post(`/v1/message-actions/${subscribeKey}/channel/test-channel/message/`) + .reply(200, {}); + const action: MessageAction = { type: 'custom', value: 'test value' }; + + pubnub + // @ts-expect-error Intentionally don't include `messageTimetoken`. + .addMessageAction({ + channel: 'test-channel', + action, + }) + .catch((err) => { + try { + assert.equal(scope.isDone(), false); + assert.equal(err.status.message, "Missing message timetoken"); + done(); + } catch (error) { + done(error); + } + }); + }); + + it("fails if 'channel' is missing", (done) => { + nock.disableNetConnect(); + const scope = utils + .createNock() + .post(`/v1/message-actions/${subscribeKey}/channel/test-channel/message/1234567890`) + .reply(200, {}); + const action: MessageAction = { type: 'custom', value: 'test value' }; + + pubnub + // @ts-expect-error Intentionally don't include `channel`. + .addMessageAction({ + messageTimetoken: '1234567890', + action, + }) + .catch((err) => { + try { + assert.equal(scope.isDone(), false); + assert.equal(err.status.message, "Missing message channel"); + done(); + } catch (error) { + done(error); + } + }); + }); + }); + + it('add message action', (done) => { + const messageAction: MessageAction = { type: 'custom', value: PubNub.generateUUID() }; + const channel = PubNub.generateUUID(); + + publishMessages(pubnub, 1, channel, (timetokens) => { + pubnub.addMessageAction( + { channel, messageTimetoken: timetokens[0], action: messageAction }, + (status, response) => { + try { + assert.equal(status.error, false); + assert(response !== null); + assert.equal(response.data.type, messageAction.type); + assert.equal(response.data.value, messageAction.value); + assert.equal(response.data.uuid, pubnub.getUUID()); + assert.equal(response.data.messageTimetoken, timetokens[0]); + assert(response.data.actionTimetoken); + + done(); + } catch (error) { + done(error); + } + }, + ); + }); + }).timeout(60000); + + it('add message action with encoded channel', (done) => { + const messageAction: MessageAction = { type: 'custom', value: PubNub.generateUUID() }; + const channel = `${PubNub.generateUUID()}#1`; + + publishMessages(pubnub, 1, channel, (timetokens) => { + pubnub.addMessageAction( + { channel, messageTimetoken: timetokens[0], action: messageAction }, + (status, response) => { + try { + assert.equal(status.error, false); + assert(response !== null); + assert.equal(response.data.type, messageAction.type); + assert.equal(response.data.value, messageAction.value); + assert.equal(response.data.uuid, pubnub.getUUID()); + assert.equal(response.data.messageTimetoken, timetokens[0]); + assert(response.data.actionTimetoken); + + done(); + } catch (error) { + done(error); + } + }, + ); + }); + }).timeout(60000); + + it('add message action and 207 status code', (done) => { + nock.disableNetConnect(); + const scope = utils + .createNock() + .post(`/v1/message-actions/${subscribeKey}/channel/test-channel/message/1234567890`) + .query({ + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + uuid: 'myUUID', + auth: 'myAuthKey', + }) + .reply(207, { + status: 207, + data: { + type: 'reaction', + value: 'smiley_face', + uuid: 'user-456', + actionTimetoken: '15610547826970050', + messageTimetoken: '15610547826969050', + }, + error: { + message: 'Stored but failed to publish message action.', + source: 'actions', + }, + }); + + pubnub.addMessageAction( + { channel: 'test-channel', messageTimetoken: '1234567890', action: { type: 'custom', value: 'test' } }, + (status) => { + try { + assert.equal(scope.isDone(), true); + assert.equal(status.statusCode, 207); + + // @ts-expect-error `errorData` may contain a dictionary (Payload) with an arbitrary set of fields. + assert(status.errorData!.message); + + done(); + } catch (error) { + done(error); + } + }, + ); + }); + + it('add message action should trigger event', (done) => { + const messageAction: MessageAction = { type: 'custom', value: PubNub.generateUUID() }; + const channel = PubNub.generateUUID(); + let messageTimetoken: string | null = null; + + pubnub.addListener({ + status: (status) => { + if (status.category === 'PNConnectedCategory') { + pubnub.publish({ channel, message: { hello: 'test' }, sendByPost: true }, (publishStatus, response) => { + assert(response !== null); + messageTimetoken = response.timetoken; + + pubnub.addMessageAction({ channel, messageTimetoken, action: messageAction }); + }); + } + }, + messageAction: (messageActionEvent) => { + try { + assert(messageActionEvent.data); + assert.equal(messageActionEvent.data.type, messageAction.type); + assert.equal(messageActionEvent.data.value, messageAction.value); + assert.equal(messageActionEvent.data.uuid, pubnub.getUUID()); + assert.equal(messageActionEvent.data.messageTimetoken, messageTimetoken); + assert(messageActionEvent.data.actionTimetoken); + assert.equal(messageActionEvent.event, "added"); + pubnub.unsubscribeAll(); + + done(); + } catch (error) { + done(error); + } + }, + }); + + pubnub.subscribe({ channels: [channel] }); + }).timeout(60000); + }); + + describe('removeMessageAction', () => { + describe('##validation', () => { + it("fails if 'messageTimetoken' is missing", (done) => { + nock.disableNetConnect(); + const scope = utils + .createNock() + .delete(`/v1/message-actions/${subscribeKey}/channel/test-channel/message/1234567890/action/12345678901`) + .reply(200, {}); + + pubnub + // @ts-expect-error Intentionally don't include `messageTimetoken`. + .removeMessageAction({ + channel: 'test-channel', + actionTimetoken: '1234567890', + }) + .catch((err) => { + try { + assert.equal(scope.isDone(), false); + assert.equal(err.status.message, "Missing message timetoken"); + + done(); + } catch (error) { + done(error); + } + }); + }); + + it("fails if 'actionTimetoken' is missing", (done) => { + nock.disableNetConnect(); + const scope = utils + .createNock() + .delete(`/v1/message-actions/${subscribeKey}/channel/test-channel/message/1234567890/action/12345678901`) + .reply(200, {}); + + pubnub + // @ts-expect-error Intentionally don't include `actionTimetoken`. + .removeMessageAction({ + channel: 'test-channel', + messageTimetoken: '1234567890', + }) + .catch((err) => { + try { + assert.equal(scope.isDone(), false); + assert.equal(err.status.message, "Missing action timetoken"); + + done(); + } catch (error) { + done(error); + } + }); + }); + + it("fails if 'channel' is missing", (done) => { + nock.disableNetConnect(); + const scope = utils + .createNock() + .delete(`/v1/message-actions/${subscribeKey}/channel/test-channel/message/1234567890/action/12345678901`) + .reply(200, {}); + + pubnub + // @ts-expect-error Intentionally don't include `channel`. + .removeMessageAction({ + messageTimetoken: '1234567890', + actionTimetoken: '12345678901', + }) + .catch((err) => { + try { + assert.equal(scope.isDone(), false); + assert.equal(err.status.message, "Missing message action channel"); + + done(); + } catch (error) { + done(error); + } + }); + }); + }); + + it('remove message action', (done) => { + const channel = PubNub.generateUUID(); + + publishMessages(pubnub, 1, channel, (messageTimetokens) => { + addActions(pubnub, 1, messageTimetokens, channel, (actionTimetokens) => { + pubnub.getMessageActions({ channel }, (status, response) => { + assert.equal(status.error, false); + assert(response !== null); + assert.equal(response.data.length, actionTimetokens.length); + + pubnub.removeMessageAction( + { channel, actionTimetoken: actionTimetokens[0], messageTimetoken: messageTimetokens[0] }, + (removeMessageStatus) => { + assert.equal(removeMessageStatus.error, false); + + setTimeout(() => { + pubnub.getMessageActions({ channel }, (getMessagesStatus, getMessagesResponse) => { + try { + assert.equal(getMessagesStatus.error, false); + assert(getMessagesResponse !== null); + assert.equal(getMessagesResponse.data.length, 0); + + done(); + } catch (error) { + done(error); + } + }); + }, 2000); + }, + ); + }); + }); + }); + }).timeout(60000); + + it('remove message action with encoded channel', (done) => { + const channel = `${PubNub.generateUUID()}#1`; + + publishMessages(pubnub, 1, channel, (messageTimetokens) => { + addActions(pubnub, 1, messageTimetokens, channel, (actionTimetokens) => { + pubnub.getMessageActions({ channel }, (status, response) => { + assert.equal(status.error, false); + assert(response !== null); + assert.equal(response.data.length, actionTimetokens.length); + + pubnub.removeMessageAction( + { channel, actionTimetoken: actionTimetokens[0], messageTimetoken: messageTimetokens[0] }, + (removeMessageStatus) => { + assert.equal(removeMessageStatus.error, false); + + setTimeout(() => { + pubnub.getMessageActions({ channel }, (getMessagesStatus, getMessagesResponse) => { + try { + assert.equal(getMessagesStatus.error, false); + assert(getMessagesResponse !== null); + assert.equal(getMessagesResponse.data.length, 0); + + done(); + } catch (error) { + done(error); + } + }); + }, 2000); + }, + ); + }); + }); + }); + }).timeout(60000); + + it('remove message action should trigger event', (done) => { + const channel = PubNub.generateUUID(); + + publishMessages(pubnub, 1, channel, (messageTimetokens) => { + addActions(pubnub, 1, messageTimetokens, channel, (actionTimetokens) => { + pubnub.addListener({ + status: (status) => { + if (status.category === 'PNConnectedCategory') { + pubnub.removeMessageAction( + { channel, actionTimetoken: actionTimetokens[0], messageTimetoken: messageTimetokens[0] }, + (removeMessagesStatus) => { + assert.equal(removeMessagesStatus.error, false); + }, + ); + } + }, + messageAction: (messageActionEvent) => { + try { + assert(messageActionEvent.data); + assert.equal(messageActionEvent.data.uuid, pubnub.getUUID()); + assert.equal(messageActionEvent.data.messageTimetoken, messageTimetokens[0]); + assert.equal(messageActionEvent.data.actionTimetoken, actionTimetokens[0]); + assert.equal(messageActionEvent.event, "removed"); + pubnub.unsubscribeAll(); + + done(); + } catch (error) { + done(error); + } + }, + }); + + pubnub.subscribe({ channels: [channel] }); + }); + }); + }).timeout(60000); + }); + + describe('getMessageAction', () => { + describe('##validation', () => { + it("fails if 'channel' is missing", (done) => { + nock.disableNetConnect(); + const scope = utils.createNock().get(`/v1/message-actions/${subscribeKey}/channel/test-channel`).reply(200, {}); + + // @ts-expect-error Intentionally don't include `channel`. + pubnub.getMessageActions({}).catch((err) => { + try { + assert.equal(scope.isDone(), false); + assert.equal(err.status.message, "Missing message channel"); + + done(); + } catch (error) { + done(error); + } + }); + }); + }); + + it('fetch message actions', (done) => { + const channel = PubNub.generateUUID(); + + publishMessages(pubnub, 2, channel, (messageTimetokens) => { + addActions(pubnub, 3, messageTimetokens, channel, (actionTimetokens) => { + const lastPublishedActionTimetoken = actionTimetokens[actionTimetokens.length - 1]; + const firstPublishedActionTimetoken = actionTimetokens[0]; + + pubnub.getMessageActions({ channel }, (status, response) => { + try { + assert.equal(status.error, false); + assert(response !== null); + const firstFetchedActionTimetoken = response.data[0].actionTimetoken; + const lastFetchedActionTimetoken = response.data[response.data.length - 1].actionTimetoken; + assert.equal(firstFetchedActionTimetoken, firstPublishedActionTimetoken); + assert.equal(lastFetchedActionTimetoken, lastPublishedActionTimetoken); + assert.equal(response.data.length, actionTimetokens.length); + assert.equal(response.start, firstPublishedActionTimetoken); + assert.equal(response.end, lastPublishedActionTimetoken); + + done(); + } catch (error) { + done(error); + } + }); + }); + }); + }).timeout(60000); + + it('fetch message actions with encoded channel', (done) => { + const channel = `${PubNub.generateUUID()}#1`; + + publishMessages(pubnub, 2, channel, (messageTimetokens) => { + addActions(pubnub, 3, messageTimetokens, channel, (actionTimetokens) => { + const lastPublishedActionTimetoken = actionTimetokens[actionTimetokens.length - 1]; + const firstPublishedActionTimetoken = actionTimetokens[0]; + + pubnub.getMessageActions({ channel }, (status, response) => { + try { + assert.equal(status.error, false); + assert(response !== null); + const firstFetchedActionTimetoken = response.data[0].actionTimetoken; + const lastFetchedActionTimetoken = response.data[response.data.length - 1].actionTimetoken; + assert.equal(firstFetchedActionTimetoken, firstPublishedActionTimetoken); + assert.equal(lastFetchedActionTimetoken, lastPublishedActionTimetoken); + assert.equal(response.data.length, actionTimetokens.length); + assert.equal(response.start, firstPublishedActionTimetoken); + assert.equal(response.end, lastPublishedActionTimetoken); + + done(); + } catch (error) { + done(error); + } + }); + }); + }); + }).timeout(60000); + + it('fetch next message actions page', (done) => { + const channel = PubNub.generateUUID(); + + publishMessages(pubnub, 2, channel, (messageTimetokens) => { + addActions(pubnub, 5, messageTimetokens, channel, (actionTimetokens) => { + const lastPublishedActionTimetoken = actionTimetokens[actionTimetokens.length - 1]; + const halfSize = Math.floor(actionTimetokens.length * 0.5); + const firstPublishedActionTimetoken = actionTimetokens[0]; + const middleMinusOnePublishedActionTimetoken = actionTimetokens[halfSize - 1]; + const middlePublishedActionTimetoken = actionTimetokens[halfSize]; + + pubnub.getMessageActions({ channel, limit: halfSize }, (status, response) => { + assert.equal(status.error, false); + assert(response !== null); + let firstFetchedActionTimetoken = response.data[0].actionTimetoken; + let lastFetchedActionTimetoken = response.data[response.data.length - 1].actionTimetoken; + assert.equal(firstFetchedActionTimetoken, middlePublishedActionTimetoken); + assert.equal(lastFetchedActionTimetoken, lastPublishedActionTimetoken); + assert.equal(response.data.length, halfSize); + assert.equal(response.start, middlePublishedActionTimetoken); + assert.equal(response.end, lastPublishedActionTimetoken); + + pubnub.getMessageActions( + { channel, start: middlePublishedActionTimetoken, limit: halfSize }, + (getMessageActionsStatus, getMessageActionsResponse) => { + try { + assert.equal(getMessageActionsStatus.error, false); + assert(getMessageActionsResponse !== null); + firstFetchedActionTimetoken = getMessageActionsResponse.data[0].actionTimetoken; + lastFetchedActionTimetoken = + getMessageActionsResponse.data[getMessageActionsResponse.data.length - 1].actionTimetoken; + assert.equal(firstFetchedActionTimetoken, firstPublishedActionTimetoken); + assert.equal(lastFetchedActionTimetoken, middleMinusOnePublishedActionTimetoken); + assert.equal(getMessageActionsResponse.data.length, halfSize); + assert.equal(getMessageActionsResponse.start, firstPublishedActionTimetoken); + assert.equal(getMessageActionsResponse.end, middleMinusOnePublishedActionTimetoken); + + done(); + } catch (error) { + done(error); + } + }, + ); + }); + }); + }); + }).timeout(60000); + }); +}); diff --git a/test/integration/endpoints/message_counts.test.js b/test/integration/endpoints/message_counts.test.js deleted file mode 100644 index 3d8af1e59..000000000 --- a/test/integration/endpoints/message_counts.test.js +++ /dev/null @@ -1,187 +0,0 @@ -/* global describe, beforeEach, it, before, after */ -/* eslint no-console: 0 */ - -import assert from 'assert'; -import nock from 'nock'; -import utils from '../../utils'; -import PubNub from '../../../src/node/index'; - -describe('message counts', () => { - let pubnub; - - before(() => { - nock.disableNetConnect(); - }); - - after(() => { - nock.enableNetConnect(); - }); - - beforeEach(() => { - nock.cleanAll(); - pubnub = new PubNub({ - subscribeKey: 'mySubKey', - publishKey: 'myPublishKey', - uuid: 'myUUID', - }); - }); - - it('get history with messages for a channel', (done) => { - const scope = utils - .createNock() - .get('/v3/history/sub-key/mySubKey/message-counts/ch1') - .query({ - timetoken: 15495750401727535, - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - }) - .reply( - 200, - '{"status": 200, "error": false, "error_message": "", "channels": {"ch1":0}}' - ); - - pubnub.messageCounts( - { channels: ['ch1'], timetoken: 15495750401727535 }, - (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.channels, { ch1: 0 }); - assert.equal(scope.isDone(), true); - done(); - } - ); - }); - - it('get history with messages for multiple channels using timetoken', (done) => { - const scope = utils - .createNock() - .get('/v3/history/sub-key/mySubKey/message-counts/ch1%2Cch2%2Cch3') - .query({ - timetoken: 15495750401727535, - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - }) - .reply( - 200, - '{"status": 200, "error": false, "error_message": "", "channels": {"ch1":0,"ch2":0,"ch3":0}}' - ); - - pubnub.messageCounts( - { channels: ['ch1', 'ch2', 'ch3'], timetoken: 15495750401727535 }, - (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.channels, { ch1: 0, ch2: 0, ch3: 0 }); - assert.equal(scope.isDone(), true); - done(); - } - ); - }); - - it('get history with messages for a channel using channelTimetokens', (done) => { - const scope = utils - .createNock() - .get('/v3/history/sub-key/mySubKey/message-counts/ch1') - .query({ - timetoken: '15495750401727535', - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - }) - .reply( - 200, - '{"status": 200, "error": false, "error_message": "", "channels": {"ch1":2}}' - ); - - pubnub.messageCounts( - { channels: ['ch1'], channelTimetokens: ['15495750401727535'] }, - (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.channels, { ch1: 2 }); - assert.equal(scope.isDone(), true); - done(); - } - ); - }); - - it('get history with messages for multiple channels using channelTimetokens', (done) => { - const scope = utils - .createNock() - .get('/v3/history/sub-key/mySubKey/message-counts/ch1%2Cch2%2Cch3') - .query({ - timetoken: '15495750401727535', - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - }) - .reply( - 200, - '{"status": 200, "error": false, "error_message": "", "channels": {"ch1":0,"ch2":3,"ch3":0}}' - ); - - pubnub.messageCounts( - { - channels: ['ch1', 'ch2', 'ch3'], - channelTimetokens: ['15495750401727535'], - }, - (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.channels, { ch1: 0, ch2: 3, ch3: 0 }); - assert.equal(scope.isDone(), true); - done(); - } - ); - }); - - it('get history with messages for multiple channels using multiple channelTimetokens', (done) => { - const scope = utils - .createNock() - .get('/v3/history/sub-key/mySubKey/message-counts/ch1%2Cch2%2Cch3') - .query({ - channelsTimetoken: - '15495750401727535,15495750401727536,15495750401727537', - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - }) - .reply( - 200, - '{"status": 200, "error": false, "error_message": "", "channels": {"ch1":0,"ch2":0,"ch3":4}}' - ); - - pubnub.messageCounts( - { - channels: ['ch1', 'ch2', 'ch3'], - channelTimetokens: [ - '15495750401727535', - '15495750401727536', - '15495750401727537', - ], - }, - (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.channels, { ch1: 0, ch2: 0, ch3: 4 }); - assert.equal(scope.isDone(), true); - done(); - } - ); - }); - - it('should add message count API telemetry information', (done) => { - let scope = utils.createNock().get('/v3/history/sub-key/mySubKey/message-counts/ch1').query(true); - const delays = [100, 200, 300, 400]; - const countedDelays = delays.slice(0, delays.length - 1); - const average = Math.floor(countedDelays.reduce((acc, delay) => acc + delay, 0) / countedDelays.length); - const leeway = 50; - - utils.runAPIWithResponseDelays(scope, - 200, - '{"status": 200, "error": false, "error_message": "", "channels": {"ch1":0}}', - delays, - (completion) => { - pubnub.messageCounts( - { channels: ['ch1'], timetoken: 15495750401727535 }, - () => { completion(); } - ); - }) - .then((lastRequest) => { - utils.verifyRequestTelemetry(lastRequest.path, 'l_hist', average, leeway); - done(); - }); - }).timeout(60000); -}); diff --git a/test/integration/endpoints/message_counts.test.ts b/test/integration/endpoints/message_counts.test.ts new file mode 100644 index 000000000..19f66d255 --- /dev/null +++ b/test/integration/endpoints/message_counts.test.ts @@ -0,0 +1,173 @@ +/* global describe, beforeEach, it, before, after */ +/* eslint no-console: 0 */ + +import assert from 'assert'; +import nock from 'nock'; + +import PubNub from '../../../src/node/index'; +import utils from '../../utils'; + +describe('message counts', () => { + let pubnub: PubNub; + + before(() => { + nock.disableNetConnect(); + }); + + after(() => { + nock.enableNetConnect(); + }); + + beforeEach(() => { + nock.cleanAll(); + pubnub = new PubNub({ + subscribeKey: 'mySubKey', + publishKey: 'myPublishKey', + uuid: 'myUUID', + // @ts-expect-error Force override default value. + useRequestId: false, + }); + }); + + it('get history with messages for a channel', (done) => { + const scope = utils + .createNock() + .get('/v3/history/sub-key/mySubKey/message-counts/ch1') + .query({ + timetoken: '15495750401727535', + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + uuid: 'myUUID', + }) + .reply(200, '{"status": 200, "error": false, "error_message": "", "channels": {"ch1":0}}', { + 'content-type': 'text/javascript', + }); + + pubnub.messageCounts({ channels: ['ch1'], timetoken: '15495750401727535' }, (status, response) => { + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.channels, { ch1: 0 }); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }); + }); + + it('get history with messages for multiple channels using timetoken', (done) => { + const scope = utils + .createNock() + .get('/v3/history/sub-key/mySubKey/message-counts/ch1,ch2,ch3') + .query({ + timetoken: '15495750401727535', + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + uuid: 'myUUID', + }) + .reply(200, '{"status": 200, "error": false, "error_message": "", "channels": {"ch1":0,"ch2":0,"ch3":0}}', { + 'content-type': 'text/javascript', + }); + + pubnub.messageCounts({ channels: ['ch1', 'ch2', 'ch3'], timetoken: '15495750401727535' }, (status, response) => { + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.channels, { ch1: 0, ch2: 0, ch3: 0 }); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }); + }); + + it('get history with messages for a channel using channelTimetokens', (done) => { + const scope = utils + .createNock() + .get('/v3/history/sub-key/mySubKey/message-counts/ch1') + .query({ + timetoken: '15495750401727535', + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + uuid: 'myUUID', + }) + .reply(200, '{"status": 200, "error": false, "error_message": "", "channels": {"ch1":2}}', { + 'content-type': 'text/javascript', + }); + + pubnub.messageCounts({ channels: ['ch1'], channelTimetokens: ['15495750401727535'] }, (status, response) => { + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.channels, { ch1: 2 }); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }); + }); + + it('get history with messages for multiple channels using channelTimetokens', (done) => { + const scope = utils + .createNock() + .get('/v3/history/sub-key/mySubKey/message-counts/ch1,ch2,ch3') + .query({ + timetoken: '15495750401727535', + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + uuid: 'myUUID', + }) + .reply(200, '{"status": 200, "error": false, "error_message": "", "channels": {"ch1":0,"ch2":3,"ch3":0}}', { + 'content-type': 'text/javascript', + }); + + pubnub.messageCounts( + { + channels: ['ch1', 'ch2', 'ch3'], + channelTimetokens: ['15495750401727535'], + }, + (status, response) => { + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.channels, { ch1: 0, ch2: 3, ch3: 0 }); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }, + ); + }); + + it('get history with messages for multiple channels using multiple channelTimetokens', (done) => { + const scope = utils + .createNock() + .get('/v3/history/sub-key/mySubKey/message-counts/ch1,ch2,ch3') + .query({ + channelsTimetoken: '15495750401727535,15495750401727536,15495750401727537', + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + uuid: 'myUUID', + }) + .reply(200, '{"status": 200, "error": false, "error_message": "", "channels": {"ch1":0,"ch2":0,"ch3":4}}', { + 'content-type': 'text/javascript', + }); + + pubnub.messageCounts( + { + channels: ['ch1', 'ch2', 'ch3'], + channelTimetokens: ['15495750401727535', '15495750401727536', '15495750401727537'], + }, + (status, response) => { + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.channels, { ch1: 0, ch2: 0, ch3: 4 }); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }, + ); + }); +}); diff --git a/test/integration/endpoints/objects/channel.test.js b/test/integration/endpoints/objects/channel.test.ts similarity index 92% rename from test/integration/endpoints/objects/channel.test.js rename to test/integration/endpoints/objects/channel.test.ts index d343c9b4f..1bd25182a 100644 --- a/test/integration/endpoints/objects/channel.test.js +++ b/test/integration/endpoints/objects/channel.test.ts @@ -1,17 +1,18 @@ +import { expect } from 'chai'; import nock from 'nock'; -import utils from '../../../utils'; -import PubNub from '../../../../src/node/index'; -import { asResponse, allChannels, channel1 } from './fixtures'; +import { asResponse, allChannels, channel1 } from './fixtures.js'; +import PubNub from '../../../../src/node/index'; +import utils from '../../../utils'; describe('objects channel', () => { - const SUBSCRIBE_KEY = 'mySubKey'; const PUBLISH_KEY = 'myPublishKey'; - const UUID = 'myUUID'; + const SUBSCRIBE_KEY = 'mySubKey'; const AUTH_KEY = 'myAuthKey'; + const UUID = 'myUUID'; - let pubnub; - let PNSDK; + let pubnub: PubNub; + let PNSDK: string; before(() => { nock.disableNetConnect(); @@ -27,6 +28,8 @@ describe('objects channel', () => { subscribeKey: SUBSCRIBE_KEY, publishKey: PUBLISH_KEY, uuid: UUID, + // @ts-expect-error Force override default value. + useRequestId: false, authKey: AUTH_KEY, }); PNSDK = `PubNub-JS-Nodejs/${pubnub.getVersion()}`; @@ -75,9 +78,6 @@ describe('objects channel', () => { await expect(resultP).to.eventually.deep.equal({ status: 200, data: allChannels.map(asResponse), - next: undefined, - prev: undefined, - totalCount: undefined, }); }); }); @@ -135,7 +135,7 @@ describe('objects channel', () => { }); it('should reject if channel is empty', async () => { - // $FlowFixMe This is intentional to suppress Flow error + // @ts-expect-error Intentionally don't include `channel`. const resultP = pubnub.objects.getChannelMetadata(); await expect(resultP).to.be.rejected; @@ -195,8 +195,8 @@ describe('objects channel', () => { }); it('should reject if data is missing', async () => { - // $FlowFixMe This is intentional to suppress Flow error - const resultP = pubnub.objects.setChannelMetadata(); + // @ts-expect-error Intentionally don't include `data`. + const resultP = pubnub.objects.setChannelMetadata({ channel: 'test' }); await expect(resultP).to.be.rejected; }); @@ -248,8 +248,8 @@ describe('objects channel', () => { }); }); - it('should reject if uuid is missing', async () => { - // $FlowFixMe This is intentional to suppress Flow error + it('should reject if channel is missing', async () => { + // @ts-expect-error Intentionally don't include `channel`. const resultP = pubnub.objects.removeChannelMetadata(); await expect(resultP).to.be.rejected; diff --git a/test/integration/endpoints/objects/fixtures.js b/test/integration/endpoints/objects/fixtures.ts similarity index 92% rename from test/integration/endpoints/objects/fixtures.js rename to test/integration/endpoints/objects/fixtures.ts index e534a2e26..b07091260 100644 --- a/test/integration/endpoints/objects/fixtures.js +++ b/test/integration/endpoints/objects/fixtures.ts @@ -1,6 +1,6 @@ /** */ -export const asResponse = (fixture ) => ({ +export const asResponse = (fixture: Record) => ({ ...fixture.data, update: fixture.updated, eTag: fixture.eTag, diff --git a/test/integration/endpoints/objects/membership.test.js b/test/integration/endpoints/objects/membership.test.ts similarity index 84% rename from test/integration/endpoints/objects/membership.test.js rename to test/integration/endpoints/objects/membership.test.ts index 304422089..626f66659 100644 --- a/test/integration/endpoints/objects/membership.test.js +++ b/test/integration/endpoints/objects/membership.test.ts @@ -1,8 +1,9 @@ /** */ import nock from 'nock'; -import utils from '../../../utils'; + import PubNub from '../../../../src/node/index'; +import utils from '../../../utils'; // import {} from './fixtures'; @@ -12,8 +13,8 @@ describe('objects membership', () => { const UUID = 'myUUID'; const AUTH_KEY = 'myAuthKey'; - let pubnub ; - let PNSDK ; + let pubnub: PubNub; + let PNSDK: string; before(() => { nock.disableNetConnect(); @@ -29,6 +30,8 @@ describe('objects membership', () => { subscribeKey: SUBSCRIBE_KEY, publishKey: PUBLISH_KEY, uuid: UUID, + // @ts-expect-error Force override default value. + useRequestId: false, authKey: AUTH_KEY, }); PNSDK = `PubNub-JS-Nodejs/${pubnub.getVersion()}`; diff --git a/test/integration/endpoints/objects/uuid.test.js b/test/integration/endpoints/objects/uuid.test.ts similarity index 95% rename from test/integration/endpoints/objects/uuid.test.js rename to test/integration/endpoints/objects/uuid.test.ts index 19215af50..e51a9a765 100644 --- a/test/integration/endpoints/objects/uuid.test.js +++ b/test/integration/endpoints/objects/uuid.test.ts @@ -1,17 +1,18 @@ +import { expect } from 'chai'; import nock from 'nock'; -import utils from '../../../utils'; -import PubNub from '../../../../src/node/index'; import { asResponse, allUsers, user1 } from './fixtures'; +import PubNub from '../../../../src/node/index'; +import utils from '../../../utils'; describe('objects UUID', () => { - const SUBSCRIBE_KEY = 'mySubKey'; const PUBLISH_KEY = 'myPublishKey'; - const UUID = 'myUUID'; + const SUBSCRIBE_KEY = 'mySubKey'; const AUTH_KEY = 'myAuthKey'; + const UUID = 'myUUID'; - let pubnub; - let PNSDK; + let pubnub: PubNub; + let PNSDK: string; before(() => { nock.disableNetConnect(); @@ -27,6 +28,8 @@ describe('objects UUID', () => { subscribeKey: SUBSCRIBE_KEY, publishKey: PUBLISH_KEY, uuid: UUID, + // @ts-expect-error Force override default value. + useRequestId: false, authKey: AUTH_KEY, }); PNSDK = `PubNub-JS-Nodejs/${pubnub.getVersion()}`; @@ -55,9 +58,6 @@ describe('objects UUID', () => { await expect(resultP).to.eventually.deep.equal({ status: 200, data: allUsers.map(asResponse), - prev: undefined, - next: undefined, - totalCount: undefined, }); }); @@ -249,7 +249,7 @@ describe('objects UUID', () => { }); it('should reject if data is missing', async () => { - // $FlowFixMe This is intentional to suppress Flow error + // @ts-expect-error Intentionally don't include `data`. const resultP = pubnub.objects.setUUIDMetadata(); await expect(resultP).to.be.rejected; @@ -321,12 +321,5 @@ describe('objects UUID', () => { data: {}, }); }); - - it('should reject if uuid is missing', async () => { - // $FlowFixMe This is intentional to suppress Flow error - const resultP = pubnub.objects.removeUUIDMetadata(); - - await expect(resultP).to.be.rejected; - }); }); }); diff --git a/test/integration/endpoints/presence.test.js b/test/integration/endpoints/presence.test.ts similarity index 54% rename from test/integration/endpoints/presence.test.js rename to test/integration/endpoints/presence.test.ts index 53ac17efe..139e7a726 100644 --- a/test/integration/endpoints/presence.test.js +++ b/test/integration/endpoints/presence.test.ts @@ -2,12 +2,12 @@ import assert from 'assert'; import nock from 'nock'; -import utils from '../../utils'; + import PubNub from '../../../src/node/index'; +import utils from '../../utils'; describe('presence endpoints', () => { - let pubnubOther; - let pubnub; + let pubnub: PubNub; before(() => { nock.disableNetConnect(); @@ -23,6 +23,8 @@ describe('presence endpoints', () => { subscribeKey: 'mySubscribeKey', publishKey: 'myPublishKey', uuid: 'myUUID', + // @ts-expect-error Force override default value. + useRequestId: false, }); }); @@ -35,13 +37,20 @@ describe('presence endpoints', () => { pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', }) - .reply(200, '{"status": 200, "message": "OK", "payload": {"channels": ["a","b"]}, "service": "Presence"}'); + .reply(200, '{"status": 200, "message": "OK", "payload": {"channels": ["a","b"]}, "service": "Presence"}', { + 'content-type': 'text/javascript', + }); pubnub.whereNow({}, (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.channels, ['a', 'b']); - assert.equal(scope.isDone(), true); - done(); + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.channels, ["a", "b"]); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } }); }); @@ -53,19 +62,28 @@ describe('presence endpoints', () => { pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID#1', }) - .reply(200, '{"status": 200, "message": "OK", "payload": {"channels": ["a","b"]}, "service": "Presence"}'); + .reply(200, '{"status": 200, "message": "OK", "payload": {"channels": ["a","b"]}, "service": "Presence"}', { + 'content-type': 'text/javascript', + }); const pubnubClient = new PubNub({ subscribeKey: 'mySubscribeKey', publishKey: 'myPublishKey', uuid: 'myUUID#1', + // @ts-expect-error Force override default value. + useRequestId: false, }); pubnubClient.whereNow({}, (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.channels, ['a', 'b']); - assert.equal(scope.isDone(), true); - done(); + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.channels, ["a", "b"]); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } }); }); @@ -77,13 +95,20 @@ describe('presence endpoints', () => { pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', }) - .reply(200, '{"status": 200, "message": "OK", "payload": {"channels": ["a","b"]}, "service": "Presence"}'); + .reply(200, '{"status": 200, "message": "OK", "payload": {"channels": ["a","b"]}, "service": "Presence"}', { + 'content-type': 'text/javascript', + }); pubnub.whereNow({ uuid: 'otherUUID' }, (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.channels, ['a', 'b']); - assert.equal(scope.isDone(), true); - done(); + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.channels, ["a", "b"]); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } }); }); @@ -95,40 +120,22 @@ describe('presence endpoints', () => { pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', }) - .reply(200, '{"status": 200, "message": "OK", "service": "Presence"}'); + .reply(200, '{"status": 200, "message": "OK", "service": "Presence"}', { + 'content-type': 'text/javascript', + }); pubnub.whereNow({ uuid: '' }, (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.channels, []); - assert.equal(scope.isDone(), true); - done(); + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.channels, []); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } }); }); - - it('should add where now API telemetry information', (done) => { - let scope = utils.createNock().get('/v2/presence/sub-key/mySubscribeKey/uuid/myUUID').query(true); - const delays = [100, 200, 300, 400]; - const countedDelays = delays.slice(0, delays.length - 1); - const average = Math.floor(countedDelays.reduce((acc, delay) => acc + delay, 0) / countedDelays.length); - const leeway = 50; - - utils - .runAPIWithResponseDelays( - scope, - 200, - '{"status": 200, "message": "OK", "payload": {"channels": ["a","b"]}, "service": "Presence"}', - delays, - (completion) => { - pubnub.whereNow({}, () => { - completion(); - }); - }, - ) - .then((lastRequest) => { - utils.verifyRequestTelemetry(lastRequest.path, 'l_pres', average, leeway); - done(); - }); - }).timeout(60000); }); describe('#setState', () => { @@ -144,13 +151,19 @@ describe('presence endpoints', () => { .reply( 200, '{ "status": 200, "message": "OK", "payload": { "age" : 20, "status" : "online"}, "service": "Presence"}', + { 'content-type': 'text/javascript' }, ); pubnub.setState({ channels: ['testChannel'], state: { new: 'state' } }, (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.state, { age: 20, status: 'online' }); - assert.equal(scope.isDone(), true); - done(); + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.state, { age: 20, status: "online" }); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } }); }); @@ -166,26 +179,35 @@ describe('presence endpoints', () => { .reply( 200, '{ "status": 200, "message": "OK", "payload": { "age" : 20, "status" : "online"}, "service": "Presence"}', + { 'content-type': 'text/javascript' }, ); const pubnubClient = new PubNub({ subscribeKey: 'mySubscribeKey', publishKey: 'myPublishKey', uuid: 'myUUID#1', + // @ts-expect-error Force override default value. + useRequestId: false, }); pubnubClient.setState({ channels: ['testChannel#1'], state: { new: 'state' } }, (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.state, { age: 20, status: 'online' }); - assert.equal(scope.isDone(), true); - done(); + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.state, { age: 20, status: "online" }); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } }); }); it('sets presence data for multiple channels', (done) => { const scope = utils .createNock() - .get('/v2/presence/sub-key/mySubscribeKey/channel/ch1%2Cch2/uuid/myUUID/data') + .get('/v2/presence/sub-key/mySubscribeKey/channel/ch1,ch2/uuid/myUUID/data') + .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -194,23 +216,29 @@ describe('presence endpoints', () => { .reply( 200, '{ "status": 200, "message": "OK", "payload": { "ch1": { "age" : 20, "status" : "online"}, "ch2": { "age": 100, "status": "offline" } }, "service": "Presence"}', + { 'content-type': 'text/javascript' }, ); pubnub.setState({ channels: ['ch1', 'ch2'], state: { new: 'state' } }, (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.state, { - ch1: { age: 20, status: 'online' }, - ch2: { age: 100, status: 'offline' }, - }); - assert.equal(scope.isDone(), true); - done(); + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.state, { + ch1: { age: 20, status: "online" }, + ch2: { age: 100, status: "offline" } + }); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } }); }); it('sets state for multiple channels / channel groups', (done) => { const scope = utils .createNock() - .get('/v2/presence/sub-key/mySubscribeKey/channel/ch1%2Cch2/uuid/myUUID/data') + .get('/v2/presence/sub-key/mySubscribeKey/channel/ch1,ch2/uuid/myUUID/data') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -220,6 +248,7 @@ describe('presence endpoints', () => { .reply( 200, '{ "status": 200, "message": "OK", "payload": { "age" : 20, "status" : "online"}, "service": "Presence"}', + { 'content-type': 'text/javascript' }, ); pubnub.setState( @@ -229,41 +258,18 @@ describe('presence endpoints', () => { state: { new: 'state' }, }, (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.state, { age: 20, status: 'online' }); - assert.equal(scope.isDone(), true); - done(); + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.state, { age: 20, status: "online" }); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } }, ); }); - - it('should add set state API telemetry information', (done) => { - let scope = utils - .createNock() - .get('/v2/presence/sub-key/mySubscribeKey/channel/testChannel/uuid/myUUID/data') - .query(true); - const delays = [100, 200, 300, 400]; - const countedDelays = delays.slice(0, delays.length - 1); - const average = Math.floor(countedDelays.reduce((acc, delay) => acc + delay, 0) / countedDelays.length); - const leeway = 50; - - utils - .runAPIWithResponseDelays( - scope, - 200, - '{ "status": 200, "message": "OK", "payload": { "age" : 20, "status" : "online"}, "service": "Presence"}', - delays, - (completion) => { - pubnub.setState({ channels: ['testChannel'], state: { new: 'state' } }, () => { - completion(); - }); - }, - ) - .then((lastRequest) => { - utils.verifyRequestTelemetry(lastRequest.path, 'l_pres', average, leeway); - done(); - }); - }).timeout(60000); }); describe('#getState', () => { @@ -278,15 +284,21 @@ describe('presence endpoints', () => { .reply( 200, '{ "status": 200, "message": "OK", "payload": { "age" : 20, "status" : "online"}, "service": "Presence"}', + { 'content-type': 'text/javascript' }, ); pubnub.getState({ channels: ['testChannel'] }, (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.channels, { - testChannel: { age: 20, status: 'online' }, - }); - assert.equal(scope.isDone(), true); - done(); + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.channels, { + testChannel: { age: 20, status: "online" } + }); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } }); }); @@ -301,22 +313,28 @@ describe('presence endpoints', () => { .reply( 200, '{ "status": 200, "message": "OK", "payload": { "age" : 20, "status" : "online"}, "service": "Presence"}', + { 'content-type': 'text/javascript' }, ); pubnub.getState({ uuid: 'otherUUID', channels: ['testChannel'] }, (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.channels, { - testChannel: { age: 20, status: 'online' }, - }); - assert.equal(scope.isDone(), true); - done(); + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.channels, { + testChannel: { age: 20, status: "online" } + }); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } }); }); it('returns the requested for multiple channels', (done) => { const scope = utils .createNock() - .get('/v2/presence/sub-key/mySubscribeKey/channel/ch1%2Cch2/uuid/myUUID') + .get('/v2/presence/sub-key/mySubscribeKey/channel/ch1,ch2/uuid/myUUID') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -324,23 +342,29 @@ describe('presence endpoints', () => { .reply( 200, '{ "status": 200, "message": "OK", "payload": { "ch1": { "age" : 20, "status" : "online"}, "ch2": { "age": 100, "status": "offline" } }, "service": "Presence"}', + { 'content-type': 'text/javascript' }, ); pubnub.getState({ channels: ['ch1', 'ch2'] }, (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.channels, { - ch1: { age: 20, status: 'online' }, - ch2: { age: 100, status: 'offline' }, - }); - assert.equal(scope.isDone(), true); - done(); + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.channels, { + ch1: { age: 20, status: "online" }, + ch2: { age: 100, status: "offline" } + }); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } }); }); it('returns the requested for multiple channels', (done) => { const scope = utils .createNock() - .get('/v2/presence/sub-key/mySubscribeKey/channel/ch1%2Cch2/uuid/myUUID') + .get('/v2/presence/sub-key/mySubscribeKey/channel/ch1,ch2/uuid/myUUID') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -349,46 +373,24 @@ describe('presence endpoints', () => { .reply( 200, '{ "status": 200, "message": "OK", "payload": { "ch1": { "age" : 20, "status" : "online"}, "ch2": { "age": 100, "status": "offline" } }, "service": "Presence"}', + { 'content-type': 'text/javascript' }, ); pubnub.getState({ channels: ['ch1', 'ch2'], channelGroups: ['cg1', 'cg2'] }, (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.channels, { - ch1: { age: 20, status: 'online' }, - ch2: { age: 100, status: 'offline' }, - }); - assert.equal(scope.isDone(), true); - done(); + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.channels, { + ch1: { age: 20, status: "online" }, + ch2: { age: 100, status: "offline" } + }); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } }); }); - - it('should add get state API telemetry information', (done) => { - let scope = utils - .createNock() - .get('/v2/presence/sub-key/mySubscribeKey/channel/testChannel/uuid/myUUID') - .query(true); - const delays = [100, 200, 300, 400]; - const countedDelays = delays.slice(0, delays.length - 1); - const average = Math.floor(countedDelays.reduce((acc, delay) => acc + delay, 0) / countedDelays.length); - const leeway = 50; - - utils - .runAPIWithResponseDelays( - scope, - 200, - '{ "status": 200, "message": "OK", "payload": { "age" : 20, "status" : "online"}, "service": "Presence"}', - delays, - (completion) => { - pubnub.getState({ channels: ['testChannel'] }, () => { - completion(); - }); - }, - ) - .then((lastRequest) => { - utils.verifyRequestTelemetry(lastRequest.path, 'l_pres', average, leeway); - done(); - }); - }).timeout(60000); }); describe('#hereNow', () => { @@ -403,24 +405,30 @@ describe('presence endpoints', () => { .reply( 200, '{"status": 200, "message": "OK", "uuids": ["a3ffd012-a3b9-478c-8705-64089f24d71e"], "occupancy": 1, "service": "Presence"}', + { 'content-type': 'text/javascript' }, ); pubnub.hereNow({ channels: ['game1'] }, (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.channels, { - game1: { - name: 'game1', - occupancy: 1, - occupants: [ - { - state: null, - uuid: 'a3ffd012-a3b9-478c-8705-64089f24d71e', - }, - ], - }, - }); - assert.equal(scope.isDone(), true); - done(); + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.channels, { + game1: { + name: "game1", + occupancy: 1, + occupants: [ + { + state: null, + uuid: "a3ffd012-a3b9-478c-8705-64089f24d71e" + } + ] + } + }); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } }); }); @@ -432,26 +440,33 @@ describe('presence endpoints', () => { pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', }) - .reply(200, '{"status": 200, "message": "OK", "occupancy": 1, "service": "Presence"}'); + .reply(200, '{"status": 200, "message": "OK", "occupancy": 1, "service": "Presence"}', { + 'content-type': 'text/javascript', + }); pubnub.hereNow({ channels: ['game1'] }, (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.channels, { - game1: { - name: 'game1', - occupancy: 1, - occupants: [], - }, - }); - assert.equal(scope.isDone(), true); - done(); + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.channels, { + game1: { + name: "game1", + occupancy: 1, + occupants: [] + } + }); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } }); }); it('returns response for multiple channels', (done) => { const scope = utils .createNock() - .get('/v2/presence/sub-key/mySubscribeKey/channel/ch1%2Cch2') + .get('/v2/presence/sub-key/mySubscribeKey/channel/ch1,ch2') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -459,31 +474,37 @@ describe('presence endpoints', () => { .reply( 200, '{"status": 200, "message": "OK", "payload": {"channels": {"game1": {"uuids": ["a3ffd012-a3b9-478c-8705-64089f24d71e"], "occupancy": 1}}, "total_channels": 1, "total_occupancy": 1}, "service": "Presence"}', + { 'content-type': 'text/javascript' }, ); pubnub.hereNow({ channels: ['ch1', 'ch2'] }, (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.channels, { - game1: { - name: 'game1', - occupancy: 1, - occupants: [ - { - state: null, - uuid: 'a3ffd012-a3b9-478c-8705-64089f24d71e', - }, - ], - }, - }); - assert.equal(scope.isDone(), true); - done(); + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.channels, { + game1: { + name: "game1", + occupancy: 1, + occupants: [ + { + state: null, + uuid: "a3ffd012-a3b9-478c-8705-64089f24d71e" + } + ] + } + }); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } }); }); it('returns response for multiple channel with state', (done) => { const scope = utils .createNock() - .get('/v2/presence/sub-key/mySubscribeKey/channel/ch1%2Cch2') + .get('/v2/presence/sub-key/mySubscribeKey/channel/ch1,ch2') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -492,45 +513,48 @@ describe('presence endpoints', () => { .reply( 200, '{"status":200,"message":"OK","payload":{"total_occupancy":3,"total_channels":2,"channels":{"ch1":{"occupancy":1,"uuids":[{"uuid":"user1"}]},"ch2":{"occupancy":2,"uuids":[{"uuid":"user1"},{"uuid":"user3"}]}}},"service":"Presence"}', + { 'content-type': 'text/javascript' }, ); pubnub.hereNow({ channels: ['ch1', 'ch2'], includeState: true }, (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.channels, { - ch1: { - name: 'ch1', - occupancy: 1, - occupants: [ - { - state: undefined, - uuid: 'user1', - }, - ], - }, - ch2: { - name: 'ch2', - occupancy: 2, - occupants: [ - { - state: undefined, - uuid: 'user1', - }, - { - state: undefined, - uuid: 'user3', - }, - ], - }, - }); - assert.equal(scope.isDone(), true); - done(); + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.channels, { + ch1: { + name: "ch1", + occupancy: 1, + occupants: [ + { + uuid: "user1" + } + ] + }, + ch2: { + name: "ch2", + occupancy: 2, + occupants: [ + { + uuid: "user1" + }, + { + uuid: "user3" + } + ] + } + }); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } }); }); it('returns response for multiple channel here now without UUIDS', (done) => { const scope = utils .createNock() - .get('/v2/presence/sub-key/mySubscribeKey/channel/ch1%2Cch2') + .get('/v2/presence/sub-key/mySubscribeKey/channel/ch1,ch2') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -539,31 +563,37 @@ describe('presence endpoints', () => { .reply( 200, '{"status":200,"message":"OK","payload":{"total_occupancy":3,"total_channels":2,"channels":{"ch1":{"occupancy":1,"uuids":[{"uuid":"user1"}]},"ch2":{"occupancy":2,"uuids":[{"uuid":"user1"},{"uuid":"user3"}]}}},"service":"Presence"}', + { 'content-type': 'text/javascript' }, ); pubnub.hereNow({ channels: ['ch1', 'ch2'], includeUUIDs: false }, (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.channels, { - ch1: { - name: 'ch1', - occupancy: 1, - occupants: [], - }, - ch2: { - name: 'ch2', - occupancy: 2, - occupants: [], - }, - }); - assert.equal(scope.isDone(), true); - done(); + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.channels, { + ch1: { + name: "ch1", + occupancy: 1, + occupants: [] + }, + ch2: { + name: "ch2", + occupancy: 2, + occupants: [] + } + }); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } }); }); it('returns response for channel group', (done) => { const scope = utils .createNock() - .get('/v2/presence/sub-key/mySubscribeKey/channel/%2C') + .get('/v2/presence/sub-key/mySubscribeKey/channel/,') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -572,24 +602,30 @@ describe('presence endpoints', () => { .reply( 200, ' {"status": 200, "message": "OK", "payload": {"channels": {"ch1": {"uuids": ["a581c974-e2f9-4088-9cc8-9632708e012d"], "occupancy": 1}}, "total_channels": 1, "total_occupancy": 1}, "service": "Presence"}', + { 'content-type': 'text/javascript' }, ); pubnub.hereNow({ channelGroups: ['cg1'] }, (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.channels, { - ch1: { - name: 'ch1', - occupancy: 1, - occupants: [ - { - state: null, - uuid: 'a581c974-e2f9-4088-9cc8-9632708e012d', - }, - ], - }, - }); - assert.equal(scope.isDone(), true); - done(); + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.channels, { + ch1: { + name: "ch1", + occupancy: 1, + occupants: [ + { + state: null, + uuid: "a581c974-e2f9-4088-9cc8-9632708e012d" + } + ] + } + }); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } }); }); @@ -604,34 +640,40 @@ describe('presence endpoints', () => { .reply( 200, '{"status": 200, "message": "OK", "payload": {"channels": {"ch10": {"uuids": ["2c3b136e-dc9e-4e97-939c-752dbb47acbd"], "occupancy": 1}, "bot_object": {"uuids": ["fb49e109-756f-483e-92dc-d966d73a119d"], "occupancy": 1}}, "total_channels": 2, "total_occupancy": 2}, "service": "Presence"}', + { 'content-type': 'text/javascript' }, ); pubnub.hereNow({}, (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.channels, { - bot_object: { - name: 'bot_object', - occupancy: 1, - occupants: [ - { - state: null, - uuid: 'fb49e109-756f-483e-92dc-d966d73a119d', - }, - ], - }, - ch10: { - name: 'ch10', - occupancy: 1, - occupants: [ - { - state: null, - uuid: '2c3b136e-dc9e-4e97-939c-752dbb47acbd', - }, - ], - }, - }); - assert.equal(scope.isDone(), true); - done(); + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.channels, { + bot_object: { + name: "bot_object", + occupancy: 1, + occupants: [ + { + state: null, + uuid: "fb49e109-756f-483e-92dc-d966d73a119d" + } + ] + }, + ch10: { + name: "ch10", + occupancy: 1, + occupants: [ + { + state: null, + uuid: "2c3b136e-dc9e-4e97-939c-752dbb47acbd" + } + ] + } + }); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } }); }); @@ -647,24 +689,30 @@ describe('presence endpoints', () => { .reply( 200, '{"status": 200, "message": "OK", "payload": {"channels": {"ch10": {"occupancy": 1}, "bot_object": {"occupancy": 1}}, "total_channels": 2, "total_occupancy": 2}, "service": "Presence"}', + { 'content-type': 'text/javascript' }, ); pubnub.hereNow({ includeUUIDs: false }, (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.channels, { - bot_object: { - name: 'bot_object', - occupancy: 1, - occupants: [], - }, - ch10: { - name: 'ch10', - occupancy: 1, - occupants: [], - }, - }); - assert.equal(scope.isDone(), true); - done(); + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.channels, { + bot_object: { + name: "bot_object", + occupancy: 1, + occupants: [] + }, + ch10: { + name: "ch10", + occupancy: 1, + occupants: [] + } + }); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } }); }); @@ -677,12 +725,18 @@ describe('presence endpoints', () => { uuid: 'myUUID', disable_uuids: 1, }) - .reply(200, '{"status": 503, "message": "Service Unavailable", "error": 1, "service": "Presence"}'); + .reply(200, '{"status": 503, "message": "Service Unavailable", "error": 1, "service": "Presence"}', { + 'content-type': 'text/javascript', + }); pubnub.hereNow({ includeUUIDs: false }, (status) => { - assert.equal(status.error, true); - assert.equal(scope.isDone(), true); - done(); + try { + assert.equal(status.error, true); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } }); }); @@ -697,14 +751,24 @@ describe('presence endpoints', () => { .reply( 200, '{"status": 402, "error": 1, "message": "This feature is not turned on for this account. Contact support@pubnub.com to activate this feature.", "service": "Presence"}', + { + 'content-type': 'text/javascript', + }, ); + let expected = - 'You have tried to perform a Global Here Now operation, your keyset configuration does not support that. Please provide a channel, or enable the Global Here Now feature from the Portal.'; - pubnub.hereNow({ channles: [] }, (status) => { - assert.equal(status.error, true); - assert.equal(status.errorData.message, expected); - assert.equal(scope.isDone(), true); - done(); + 'This feature is not turned on for this account. Contact support@pubnub.com to activate this feature.'; + pubnub.hereNow({ channels: [] }, (status) => { + try { + assert.equal(status.error, true); + assert(status.errorData); + // @ts-expect-error `errorData` may contain a dictionary (Payload) with an arbitrary set of fields. + assert.equal(status.errorData.message, expected); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } }); }); @@ -720,50 +784,31 @@ describe('presence endpoints', () => { .reply( 200, '{"status": 200, "message": "OK", "uuids": ["a3ffd012-a3b9-478c-8705-64089f24d71e"], "occupancy": 1, "service": "Presence"}', + { 'content-type': 'text/javascript' }, ); pubnub.hereNow({ channels: ['game1'], queryParameters: { test: 'param' } }, (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.channels, { - game1: { - name: 'game1', - occupancy: 1, - occupants: [ - { - state: null, - uuid: 'a3ffd012-a3b9-478c-8705-64089f24d71e', - }, - ], - }, - }); - assert.equal(scope.isDone(), true); - done(); + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.channels, { + game1: { + name: "game1", + occupancy: 1, + occupants: [ + { + state: null, + uuid: "a3ffd012-a3b9-478c-8705-64089f24d71e" + } + ] + } + }); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } }); }); - - it('should add here now API telemetry information', (done) => { - let scope = utils.createNock().get('/v2/presence/sub-key/mySubscribeKey/channel/game1').query(true); - const delays = [100, 200, 300, 400]; - const countedDelays = delays.slice(0, delays.length - 1); - const average = Math.floor(countedDelays.reduce((acc, delay) => acc + delay, 0) / countedDelays.length); - const leeway = 50; - - utils - .runAPIWithResponseDelays( - scope, - 200, - '{"status": 200, "message": "OK", "uuids": ["a3ffd012-a3b9-478c-8705-64089f24d71e"], "occupancy": 1, "service": "Presence"}', - delays, - (completion) => { - pubnub.hereNow({ channels: ['game1'] }, () => { - completion(); - }); - }, - ) - .then((lastRequest) => { - utils.verifyRequestTelemetry(lastRequest.path, 'l_pres', average, leeway); - done(); - }); - }).timeout(60000); }); }); diff --git a/test/integration/endpoints/publish.test.js b/test/integration/endpoints/publish.test.js deleted file mode 100644 index 8b2138846..000000000 --- a/test/integration/endpoints/publish.test.js +++ /dev/null @@ -1,300 +0,0 @@ -/* global describe, beforeEach, it, before, after */ -/* eslint no-console: 0 */ - -import assert from 'assert'; -import nock from 'nock'; -import utils from '../../utils'; -import PubNub from '../../../src/node/index'; - -describe('publish endpoints', () => { - let pubnub; - - before(() => { - nock.disableNetConnect(); - }); - - after(() => { - nock.enableNetConnect(); - }); - - beforeEach(() => { - nock.cleanAll(); - pubnub = new PubNub({ - subscribeKey: 'mySubKey', - publishKey: 'myPublishKey', - uuid: 'myUUID', - authKey: 'myAuthKey', - useRandomIVs: false - }); - }); - - describe('##validation', () => { - it('fails if channel is missing', (done) => { - const scope = utils - .createNock() - .get('/publish/*') - .reply(200, '[1,"Sent","14647523059145592"]'); - - pubnub.publish({ message: { such: 'object' } }).catch((err) => { - assert.equal(scope.isDone(), false); - assert.equal(err.status.message, 'Missing Channel'); - done(); - }); - }); - }); - - it('publishes a complex object via GET', (done) => { - const scope = utils - .createNock() - .get( - '/publish/myPublishKey/mySubKey/0/ch1/0/%7B%22such%22%3A%22object%22%7D' - ) - .query({ - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - auth: 'myAuthKey', - }) - .reply(200, '[1,"Sent","14647523059145592"]'); - - pubnub.publish( - { message: { such: 'object' }, channel: 'ch1' }, - (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.timetoken, 14647523059145592); - assert.equal(scope.isDone(), true); - done(); - } - ); - }); - - it('publishes without replication via GET', (done) => { - const scope = utils - .createNock() - .get( - '/publish/myPublishKey/mySubKey/0/ch1/0/%7B%22such%22%3A%22object%22%7D' - ) - .query({ - norep: true, - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - auth: 'myAuthKey', - }) - .reply(200, '[1,"Sent","14647523059145592"]'); - - pubnub.publish( - { message: { such: 'object' }, channel: 'ch1', replicate: false }, - (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.timetoken, 14647523059145592); - assert.equal(scope.isDone(), true); - done(); - } - ); - }); - - it('publishes a complex object via GET with encryption', (done) => { - const scope = utils - .createNock() - .get( - '/publish/myPublishKey/mySubKey/0/ch1/0/%22toDEeIZkmIyoiLpSojGu7n3%2B2t1rn7%2FDsrEZ1r8JKR4%3D%22' - ) - .query({ - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - auth: 'myAuthKey', - }) - .reply(200, '[1,"Sent","14647523059145592"]'); - - pubnub.setCipherKey('myCipherKey'); - - pubnub.publish( - { message: { such: 'object' }, channel: 'ch1' }, - (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.timetoken, 14647523059145592); - assert.equal(scope.isDone(), true); - done(); - } - ); - }); - - it('supports ttl param', (done) => { - const scope = utils - .createNock() - .get( - '/publish/myPublishKey/mySubKey/0/ch1/0/%22toDEeIZkmIyoiLpSojGu7n3%2B2t1rn7%2FDsrEZ1r8JKR4%3D%22' - ) - .query({ - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - auth: 'myAuthKey', - ttl: '10', - }) - .reply(200, '[1,"Sent","14647523059145592"]'); - - pubnub.setCipherKey('myCipherKey'); - pubnub.publish( - { message: { such: 'object' }, channel: 'ch1', ttl: 10 }, - (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.timetoken, 14647523059145592); - assert.equal(scope.isDone(), true); - done(); - } - ); - }); - - it('supports storeInHistory=0', (done) => { - const scope = utils - .createNock() - .get( - '/publish/myPublishKey/mySubKey/0/ch1/0/%22toDEeIZkmIyoiLpSojGu7n3%2B2t1rn7%2FDsrEZ1r8JKR4%3D%22' - ) - .query({ - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - auth: 'myAuthKey', - store: '0', - }) - .reply(200, '[1,"Sent","14647523059145592"]'); - - pubnub.setCipherKey('myCipherKey'); - - pubnub.publish( - { message: { such: 'object' }, channel: 'ch1', storeInHistory: false }, - (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.timetoken, 14647523059145592); - assert.equal(scope.isDone(), true); - done(); - } - ); - }); - - it('supports storeInHistory=1', (done) => { - const scope = utils - .createNock() - .get( - '/publish/myPublishKey/mySubKey/0/ch1/0/%22toDEeIZkmIyoiLpSojGu7n3%2B2t1rn7%2FDsrEZ1r8JKR4%3D%22' - ) - .query({ - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - auth: 'myAuthKey', - store: '1', - }) - .reply(200, '[1,"Sent","14647523059145592"]'); - - pubnub.setCipherKey('myCipherKey'); - - pubnub.publish( - { message: { such: 'object' }, channel: 'ch1', storeInHistory: true }, - (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.timetoken, 14647523059145592); - assert.equal(scope.isDone(), true); - done(); - } - ); - }); - - it('publishes a complex object via POST', (done) => { - const scope = utils - .createNock() - .post('/publish/myPublishKey/mySubKey/0/ch1/0', '{"such":"object"}') - .query({ - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - auth: 'myAuthKey', - }) - .reply(200, '[1,"Sent","14647523059145592"]'); - - pubnub.publish( - { message: { such: 'object' }, channel: 'ch1', sendByPost: true }, - (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.timetoken, 14647523059145592); - assert.equal(scope.isDone(), true); - done(); - } - ); - }); - - it('publishes a complex object via POST with encryption', (done) => { - const scope = utils - .createNock() - .post( - '/publish/myPublishKey/mySubKey/0/ch1/0', - '"toDEeIZkmIyoiLpSojGu7n3+2t1rn7/DsrEZ1r8JKR4="' - ) - .query({ - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - auth: 'myAuthKey', - }) - .reply(200, '[1,"Sent","14647523059145592"]'); - - pubnub.setCipherKey('myCipherKey'); - - pubnub.publish( - { message: { such: 'object' }, channel: 'ch1', sendByPost: true }, - (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.timetoken, 14647523059145592); - assert.equal(scope.isDone(), true); - done(); - } - ); - }); - - it('should add publish API telemetry information', (done) => { - let scope = utils.createNock().get('/publish/myPublishKey/mySubKey/0/ch1/0/%7B%22such%22%3A%22object%22%7D').query(true); - const delays = [100, 200, 300, 400]; - const countedDelays = delays.slice(0, delays.length - 1); - const average = Math.floor(countedDelays.reduce((acc, delay) => acc + delay, 0) / countedDelays.length); - const leeway = 50; - - utils.runAPIWithResponseDelays(scope, - 200, - '[1,"Sent","14647523059145592"]', - delays, - (completion) => { - pubnub.publish( - { message: { such: 'object' }, channel: 'ch1' }, - () => { completion(); } - ); - }) - .then((lastRequest) => { - utils.verifyRequestTelemetry(lastRequest.path, 'l_pub', average, leeway); - done(); - }); - }).timeout(60000); - - describe('#fire', () => { - it('publishes a complex object via GET', (done) => { - const scope = utils - .createNock() - .get( - '/publish/myPublishKey/mySubKey/0/ch1/0/%7B%22such%22%3A%22object%22%7D' - ) - .query({ - norep: true, - store: 0, - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - uuid: 'myUUID', - auth: 'myAuthKey', - }) - .reply(200, '[1,"Sent","14647523059145592"]'); - - pubnub.fire( - { message: { such: 'object' }, channel: 'ch1' }, - (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.timetoken, 14647523059145592); - assert.equal(scope.isDone(), true); - done(); - } - ); - }); - }); -}); diff --git a/test/integration/endpoints/publish.test.ts b/test/integration/endpoints/publish.test.ts new file mode 100644 index 000000000..cc113b55b --- /dev/null +++ b/test/integration/endpoints/publish.test.ts @@ -0,0 +1,286 @@ +/* global describe, beforeEach, it, before, after */ +/* eslint no-console: 0 */ + +import assert from 'assert'; +import nock from 'nock'; + +import PubNub from '../../../src/node/index'; +import utils from '../../utils'; + +describe('publish endpoints', () => { + let pubnub: PubNub; + + before(() => { + nock.disableNetConnect(); + }); + + after(() => { + nock.enableNetConnect(); + }); + + beforeEach(() => { + nock.cleanAll(); + pubnub = new PubNub({ + subscribeKey: 'mySubKey', + publishKey: 'myPublishKey', + uuid: 'myUUID', + authKey: 'myAuthKey', + // @ts-expect-error Force override default value. + useRequestId: false, + useRandomIVs: false, + }); + }); + + describe('##validation', () => { + it('fails if channel is missing', (done) => { + const scope = utils + .createNock() + .get('/publish/*') + .reply(200, '[1,"Sent","14647523059145592"]', { 'content-type': 'text/javascript' }); + + // @ts-expect-error Intentionally don't include `channel`. + pubnub.publish({ message: { such: 'object' } }).catch((err) => { + try { + assert.equal(scope.isDone(), false); + assert.equal(err.status.message, "Missing 'channel'"); + done(); + } catch (error) { + done(error); + } + }); + }); + }); + + it('publishes a complex object via GET', (done) => { + const scope = utils + .createNock() + .get('/publish/myPublishKey/mySubKey/0/ch1/0/%7B%22such%22%3A%22object%22%7D') + .query({ + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + uuid: 'myUUID', + auth: 'myAuthKey', + }) + .reply(200, '[1,"Sent","14647523059145592"]', { 'content-type': 'text/javascript' }); + + pubnub.publish({ message: { such: 'object' }, channel: 'ch1' }, (status, response) => { + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.timetoken, "14647523059145592"); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }); + }); + + it('publishes without replication via GET', (done) => { + const scope = utils + .createNock() + .get('/publish/myPublishKey/mySubKey/0/ch1/0/%7B%22such%22%3A%22object%22%7D') + .query({ + norep: true, + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + uuid: 'myUUID', + auth: 'myAuthKey', + }) + .reply(200, '[1,"Sent","14647523059145592"]', { 'content-type': 'text/javascript' }); + + pubnub.publish({ message: { such: 'object' }, channel: 'ch1', replicate: false }, (status, response) => { + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.timetoken, "14647523059145592"); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }); + }); + + it('publishes a complex object via GET with encryption', (done) => { + const scope = utils + .createNock() + .get('/publish/myPublishKey/mySubKey/0/ch1/0/%22toDEeIZkmIyoiLpSojGu7n3%2B2t1rn7%2FDsrEZ1r8JKR4%3D%22') + .query({ + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + uuid: 'myUUID', + auth: 'myAuthKey', + }) + .reply(200, '[1,"Sent","14647523059145592"]', { 'content-type': 'text/javascript' }); + + pubnub.setCipherKey('myCipherKey'); + + pubnub.publish({ message: { such: 'object' }, channel: 'ch1' }, (status, response) => { + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.timetoken, "14647523059145592"); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }); + }); + + it('supports ttl param', (done) => { + const scope = utils + .createNock() + .get('/publish/myPublishKey/mySubKey/0/ch1/0/%22toDEeIZkmIyoiLpSojGu7n3%2B2t1rn7%2FDsrEZ1r8JKR4%3D%22') + .query({ + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + uuid: 'myUUID', + auth: 'myAuthKey', + ttl: '10', + }) + .reply(200, '[1,"Sent","14647523059145592"]', { 'content-type': 'text/javascript' }); + + pubnub.setCipherKey('myCipherKey'); + pubnub.publish({ message: { such: 'object' }, channel: 'ch1', ttl: 10 }, (status, response) => { + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.timetoken, "14647523059145592"); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }); + }); + + it('supports storeInHistory=0', (done) => { + const scope = utils + .createNock() + .get('/publish/myPublishKey/mySubKey/0/ch1/0/%22toDEeIZkmIyoiLpSojGu7n3%2B2t1rn7%2FDsrEZ1r8JKR4%3D%22') + .query({ + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + uuid: 'myUUID', + auth: 'myAuthKey', + store: '0', + }) + .reply(200, '[1,"Sent","14647523059145592"]', { 'content-type': 'text/javascript' }); + + pubnub.setCipherKey('myCipherKey'); + + pubnub.publish({ message: { such: 'object' }, channel: 'ch1', storeInHistory: false }, (status, response) => { + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.timetoken, "14647523059145592"); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }); + }); + + it('supports storeInHistory=1', (done) => { + const scope = utils + .createNock() + .get('/publish/myPublishKey/mySubKey/0/ch1/0/%22toDEeIZkmIyoiLpSojGu7n3%2B2t1rn7%2FDsrEZ1r8JKR4%3D%22') + .query({ + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + uuid: 'myUUID', + auth: 'myAuthKey', + store: '1', + }) + .reply(200, '[1,"Sent","14647523059145592"]', { 'content-type': 'text/javascript' }); + + pubnub.setCipherKey('myCipherKey'); + + pubnub.publish({ message: { such: 'object' }, channel: 'ch1', storeInHistory: true }, (status, response) => { + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.timetoken, "14647523059145592"); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }); + }); + + it('publishes a complex object via POST', (done) => { + const scope = utils + .createNock() + .post('/publish/myPublishKey/mySubKey/0/ch1/0', '{"such":"object"}') + .query({ + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + uuid: 'myUUID', + auth: 'myAuthKey', + }) + .reply(200, '[1,"Sent","14647523059145592"]', { 'content-type': 'text/javascript' }); + + pubnub.publish({ message: { such: 'object' }, channel: 'ch1', sendByPost: true }, (status, response) => { + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.timetoken, "14647523059145592"); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }); + }); + + it('publishes a complex object via POST with encryption', (done) => { + const scope = utils + .createNock() + .post('/publish/myPublishKey/mySubKey/0/ch1/0', '"toDEeIZkmIyoiLpSojGu7n3+2t1rn7/DsrEZ1r8JKR4="') + .query({ + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + uuid: 'myUUID', + auth: 'myAuthKey', + }) + .reply(200, '[1,"Sent","14647523059145592"]', { 'content-type': 'text/javascript' }); + + pubnub.setCipherKey('myCipherKey'); + + pubnub.publish({ message: { such: 'object' }, channel: 'ch1', sendByPost: true }, (status, response) => { + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.timetoken, "14647523059145592"); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }); + }); + + describe('#fire', () => { + it('publishes a complex object via GET', (done) => { + const scope = utils + .createNock() + .get('/publish/myPublishKey/mySubKey/0/ch1/0/%7B%22such%22%3A%22object%22%7D') + .query({ + norep: true, + store: 0, + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + uuid: 'myUUID', + auth: 'myAuthKey', + }) + .reply(200, '[1,"Sent","14647523059145592"]', { 'content-type': 'text/javascript' }); + + pubnub.fire({ message: { such: 'object' }, channel: 'ch1' }, (status, response) => { + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.timetoken, "14647523059145592"); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }); + }); + }); +}); diff --git a/test/integration/endpoints/push.test.js b/test/integration/endpoints/push.test.js deleted file mode 100644 index a3c163e8b..000000000 --- a/test/integration/endpoints/push.test.js +++ /dev/null @@ -1,632 +0,0 @@ -/* global describe, beforeEach, it, before, after */ -/* eslint no-console: 0 */ - -import assert from 'assert'; -import nock from 'nock'; -import utils from '../../utils'; -import PubNub from '../../../src/node/index'; - -describe('push endpoints', () => { - let pubnub; - - before(() => { - nock.disableNetConnect(); - }); - - after(() => { - nock.enableNetConnect(); - }); - - beforeEach(() => { - nock.cleanAll(); - pubnub = new PubNub({ - subscribeKey: 'mySubKey', - publishKey: 'myPublishKey', - uuid: 'myUUID', - }); - }); - - describe('adding channels to device', () => { - it('supports addition of multiple channels for apple', (done) => { - const scope = utils - .createNock() - .get('/v1/push/sub-key/mySubKey/devices/niceDevice') - .query({ - add: 'a,b', - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - type: 'apns', - uuid: 'myUUID', - }) - .reply(200, '[1, "Modified Channels"]'); - - pubnub.push.addChannels( - { channels: ['a', 'b'], device: 'niceDevice', pushGateway: 'apns' }, - (status) => { - assert.equal(status.error, false); - assert.equal(scope.isDone(), true); - done(); - } - ); - }); - - it('supports addition of multiple channels for apple (APNS2)', (done) => { - const scope = utils - .createNock() - .get('/v2/push/sub-key/mySubKey/devices-apns2/niceDevice') - .query({ - add: 'a,b', - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - environment: 'development', - topic: 'com.test.apns', - uuid: 'myUUID', - }) - .reply(200, '[1, "Modified Channels"]'); - - pubnub.push.addChannels( - { channels: ['a', 'b'], device: 'niceDevice', pushGateway: 'apns2', topic: 'com.test.apns' }, - (status) => { - assert.equal(status.error, false); - assert.equal(scope.isDone(), true); - done(); - } - ); - }); - - it('supports addition of multiple channels for microsoft', (done) => { - const scope = utils - .createNock() - .get('/v1/push/sub-key/mySubKey/devices/niceDevice') - .query({ - add: 'a,b', - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - type: 'mpns', - uuid: 'myUUID', - }) - .reply(200, '[1, "Modified Channels"]'); - - pubnub.push.addChannels( - { channels: ['a', 'b'], device: 'niceDevice', pushGateway: 'mpns' }, - (status) => { - assert.equal(status.error, false); - assert.equal(scope.isDone(), true); - done(); - } - ); - }); - - it('supports addition of multiple channels for google', (done) => { - const scope = utils - .createNock() - .get('/v1/push/sub-key/mySubKey/devices/niceDevice') - .query({ - add: 'a,b', - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - type: 'gcm', - uuid: 'myUUID', - }) - .reply(200, '[1, "Modified Channels"]'); - - pubnub.push.addChannels( - { channels: ['a', 'b'], device: 'niceDevice', pushGateway: 'gcm' }, - (status) => { - assert.equal(status.error, false); - assert.equal(scope.isDone(), true); - done(); - } - ); - }); - - it('should add push enabled for channels API telemetry information', (done) => { - let scope = utils.createNock().get('/v1/push/sub-key/mySubKey/devices/niceDevice').query(true); - const delays = [100, 200, 300, 400]; - const countedDelays = delays.slice(0, delays.length - 1); - const average = Math.floor(countedDelays.reduce((acc, delay) => acc + delay, 0) / countedDelays.length); - const leeway = 50; - - utils.runAPIWithResponseDelays(scope, - 200, - '[1, "Modified Channels"]', - delays, - (completion) => { - pubnub.push.addChannels( - { channels: ['a', 'b'], device: 'niceDevice', pushGateway: 'apns' }, - () => { completion(); } - ); - }) - .then((lastRequest) => { - utils.verifyRequestTelemetry(lastRequest.path, 'l_push', average, leeway); - done(); - }); - }).timeout(60000); - - it('should add APNS2 enabled for channels API telemetry information', (done) => { - let scope = utils.createNock().get('/v2/push/sub-key/mySubKey/devices-apns2/niceDevice').query(true); - const delays = [100, 200, 300, 400]; - const countedDelays = delays.slice(0, delays.length - 1); - const average = Math.floor(countedDelays.reduce((acc, delay) => acc + delay, 0) / countedDelays.length); - const leeway = 50; - - utils.runAPIWithResponseDelays(scope, - 200, - '[1, "Modified Channels"]', - delays, - (completion) => { - pubnub.push.addChannels( - { channels: ['a', 'b'], device: 'niceDevice', pushGateway: 'apns2', topic: 'com.test.apns' }, - () => { completion(); } - ); - }) - .then((lastRequest) => { - utils.verifyRequestTelemetry(lastRequest.path, 'l_push', average, leeway); - done(); - }); - }).timeout(60000); - }); - - describe('listing channels for device', () => { - it('supports channel listing for apple', (done) => { - const scope = utils - .createNock() - .get('/v1/push/sub-key/mySubKey/devices/coolDevice') - .query({ - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - type: 'apns', - uuid: 'myUUID', - }) - .reply(200, '["ch1", "ch2", "ch3"]'); - - pubnub.push.listChannels( - { device: 'coolDevice', pushGateway: 'apns' }, - (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.channels, ['ch1', 'ch2', 'ch3']); - assert.equal(scope.isDone(), true); - done(); - } - ); - }); - - it('supports channel listing for apple (APNS2)', (done) => { - const scope = utils - .createNock() - .get('/v2/push/sub-key/mySubKey/devices-apns2/coolDevice') - .query({ - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - environment: 'production', - topic: 'com.test.apns', - uuid: 'myUUID', - }) - .reply(200, '["ch1", "ch2", "ch3"]'); - - pubnub.push.listChannels( - { device: 'coolDevice', pushGateway: 'apns2', environment: 'production', topic: 'com.test.apns' }, - (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.channels, ['ch1', 'ch2', 'ch3']); - assert.equal(scope.isDone(), true); - done(); - } - ); - }); - - it('supports channel listing for microsoft', (done) => { - const scope = utils - .createNock() - .get('/v1/push/sub-key/mySubKey/devices/coolDevice') - .query({ - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - type: 'mpns', - uuid: 'myUUID', - }) - .reply(200, '["ch1", "ch2", "ch3"]'); - - pubnub.push.listChannels( - { device: 'coolDevice', pushGateway: 'mpns' }, - (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.channels, ['ch1', 'ch2', 'ch3']); - assert.equal(scope.isDone(), true); - done(); - } - ); - }); - - it('supports channel listing for google', (done) => { - const scope = utils - .createNock() - .get('/v1/push/sub-key/mySubKey/devices/coolDevice') - .query({ - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - type: 'gcm', - uuid: 'myUUID', - }) - .reply(200, '["ch1", "ch2", "ch3"]'); - - pubnub.push.listChannels( - { device: 'coolDevice', pushGateway: 'gcm' }, - (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.channels, ['ch1', 'ch2', 'ch3']); - assert.equal(scope.isDone(), true); - done(); - } - ); - }); - - it('should add push audit API telemetry information', (done) => { - let scope = utils.createNock().get('/v1/push/sub-key/mySubKey/devices/coolDevice').query(true); - const delays = [100, 200, 300, 400]; - const countedDelays = delays.slice(0, delays.length - 1); - const average = Math.floor(countedDelays.reduce((acc, delay) => acc + delay, 0) / countedDelays.length); - const leeway = 50; - - utils.runAPIWithResponseDelays(scope, - 200, - '["ch1", "ch2", "ch3"]', - delays, - (completion) => { - pubnub.push.listChannels( - { device: 'coolDevice', pushGateway: 'apns' }, - () => { completion(); } - ); - }) - .then((lastRequest) => { - utils.verifyRequestTelemetry(lastRequest.path, 'l_push', average, leeway); - done(); - }); - }).timeout(60000); - - it('should add APNS2 audit API telemetry information', (done) => { - let scope = utils.createNock().get('/v2/push/sub-key/mySubKey/devices-apns2/coolDevice').query(true); - const delays = [100, 200, 300, 400]; - const countedDelays = delays.slice(0, delays.length - 1); - const average = Math.floor(countedDelays.reduce((acc, delay) => acc + delay, 0) / countedDelays.length); - const leeway = 50; - - utils.runAPIWithResponseDelays(scope, - 200, - '["ch1", "ch2", "ch3"]', - delays, - (completion) => { - pubnub.push.listChannels( - { device: 'coolDevice', pushGateway: 'apns2', environment: 'production', topic: 'com.test.apns' }, - () => { completion(); } - ); - }) - .then((lastRequest) => { - utils.verifyRequestTelemetry(lastRequest.path, 'l_push', average, leeway); - done(); - }); - }).timeout(60000); - }); - - describe('supports deletion of channels', () => { - it('supports removal of multiple channels for apple', (done) => { - const scope = utils - .createNock() - .get('/v1/push/sub-key/mySubKey/devices/niceDevice') - .query({ - remove: 'a,b', - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - type: 'apns', - uuid: 'myUUID', - }) - .reply(200, '[1, "Modified Channels"]'); - - pubnub.push.removeChannels( - { channels: ['a', 'b'], device: 'niceDevice', pushGateway: 'apns' }, - (status) => { - assert.equal(status.error, false); - assert.equal(scope.isDone(), true); - done(); - } - ); - }); - - it('supports removal of multiple channels for apple (APNS2)', (done) => { - const scope = utils - .createNock() - .get('/v2/push/sub-key/mySubKey/devices-apns2/niceDevice') - .query({ - remove: 'a,b', - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - environment: 'development', - topic: 'com.test.apns', - uuid: 'myUUID', - }) - .reply(200, '[1, "Modified Channels"]'); - - pubnub.push.removeChannels( - { channels: ['a', 'b'], device: 'niceDevice', pushGateway: 'apns2', topic: 'com.test.apns' }, - (status) => { - assert.equal(status.error, false); - assert.equal(scope.isDone(), true); - done(); - } - ); - }); - - it('supports removal of multiple channels for microsoft', (done) => { - const scope = utils - .createNock() - .get('/v1/push/sub-key/mySubKey/devices/niceDevice') - .query({ - remove: 'a,b', - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - type: 'mpns', - uuid: 'myUUID', - }) - .reply(200, '[1, "Modified Channels"]'); - - pubnub.push.removeChannels( - { channels: ['a', 'b'], device: 'niceDevice', pushGateway: 'mpns' }, - (status) => { - assert.equal(status.error, false); - assert.equal(scope.isDone(), true); - done(); - } - ); - }); - - it('supports removal of multiple channels for google', (done) => { - const scope = utils - .createNock() - .get('/v1/push/sub-key/mySubKey/devices/niceDevice') - .query({ - remove: 'a,b', - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - type: 'gcm', - uuid: 'myUUID', - }) - .reply(200, '[1, "Modified Channels"]'); - - pubnub.push.removeChannels( - { - channels: ['a', 'b'], - device: 'niceDevice', - pushGateway: 'gcm', - uuid: 'myUUID', - }, - (status) => { - assert.equal(status.error, false); - assert.equal(scope.isDone(), true); - done(); - } - ); - }); - - it('supports channel listing with start and count params', async () => { - const scope = utils - .createNock() - .get('/v1/push/sub-key/mySubKey/devices/coolDevice') - .query({ - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - type: 'apns', - uuid: 'myUUID', - start: 'ch1', - count: 10, - }) - .reply(200, '["ch1", "ch2", "ch3"]'); - - var res = await pubnub.push.listChannels( - { device: 'coolDevice', pushGateway: 'apns', start: 'ch1', count: 10 }, - (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.channels, ['ch1', 'ch2', 'ch3']); - assert.equal(scope.isDone(), true); - done(); - }, - ); - }); - - it('supports channel listing with(APNS2) start and count params', async () => { - const scope = utils - .createNock() - .get('/v2/push/sub-key/mySubKey/devices-apns2/coolDevice') - .query({ - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - environment: 'production', - topic: 'com.test.apns', - uuid: 'myUUID', - start: 'ch1', - count: 10, - }) - .reply(200, '["ch1", "ch2", "ch3"]'); - pubnub.push.listChannels( - { - device: 'coolDevice', - pushGateway: 'apns2', - environment: 'production', - topic: 'com.test.apns', - start: 'ch1', - count: 10, - }, - (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.channels, ['ch1', 'ch2', 'ch3']); - assert.equal(scope.isDone(), true); - done(); - }, - ); - }); - - it('should add push disable for channels API telemetry information', (done) => { - let scope = utils.createNock().get('/v1/push/sub-key/mySubKey/devices/niceDevice').query(true); - const delays = [100, 200, 300, 400]; - const countedDelays = delays.slice(0, delays.length - 1); - const average = Math.floor(countedDelays.reduce((acc, delay) => acc + delay, 0) / countedDelays.length); - const leeway = 50; - - utils.runAPIWithResponseDelays(scope, - 200, - '[1, "Modified Channels"]', - delays, - (completion) => { - pubnub.push.removeChannels( - { channels: ['a', 'b'], device: 'niceDevice', pushGateway: 'apns' }, - () => { completion(); } - ); - }) - .then((lastRequest) => { - utils.verifyRequestTelemetry(lastRequest.path, 'l_push', average, leeway); - done(); - }); - }).timeout(60000); - - it('should add APNS2 disable for channels API telemetry information', (done) => { - let scope = utils.createNock().get('/v2/push/sub-key/mySubKey/devices-apns2/niceDevice').query(true); - const delays = [100, 200, 300, 400]; - const countedDelays = delays.slice(0, delays.length - 1); - const average = Math.floor(countedDelays.reduce((acc, delay) => acc + delay, 0) / countedDelays.length); - const leeway = 50; - - utils.runAPIWithResponseDelays(scope, - 200, - '[1, "Modified Channels"]', - delays, - (completion) => { - pubnub.push.removeChannels( - { channels: ['a', 'b'], device: 'niceDevice', pushGateway: 'apns2', topic: 'com.test.apns' }, - () => { completion(); } - ); - }) - .then((lastRequest) => { - utils.verifyRequestTelemetry(lastRequest.path, 'l_push', average, leeway); - done(); - }); - }).timeout(60000); - }); - - describe('supports removal of device', () => { - it('supports removal of device for apple', (done) => { - const scope = utils - .createNock() - .get('/v1/push/sub-key/mySubKey/devices/niceDevice/remove') - .query({ - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - type: 'apns', - uuid: 'myUUID', - }) - .reply(200, '[1, "Modified Channels"]'); - - pubnub.push.deleteDevice( - { device: 'niceDevice', pushGateway: 'apns' }, - (status) => { - assert.equal(status.error, false); - assert.equal(scope.isDone(), true); - done(); - } - ); - }); - - it('supports removal of device for apple (APNS2)', (done) => { - const scope = utils - .createNock() - .get('/v2/push/sub-key/mySubKey/devices-apns2/niceDevice/remove') - .query({ - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - environment: 'production', - topic: 'com.test.apns', - uuid: 'myUUID', - }) - .reply(200, '[1, "Modified Channels"]'); - - pubnub.push.deleteDevice( - { device: 'niceDevice', pushGateway: 'apns2', environment: 'production', topic: 'com.test.apns' }, - (status) => { - assert.equal(status.error, false); - assert.equal(scope.isDone(), true); - done(); - } - ); - }); - - it('supports removal of device for microsoft', (done) => { - const scope = utils - .createNock() - .get('/v1/push/sub-key/mySubKey/devices/niceDevice/remove') - .query({ - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - type: 'mpns', - uuid: 'myUUID', - }) - .reply(200, '[1, "Modified Channels"]'); - - pubnub.push.deleteDevice( - { device: 'niceDevice', pushGateway: 'mpns' }, - (status) => { - assert.equal(status.error, false); - assert.equal(scope.isDone(), true); - done(); - } - ); - }); - - it('supports removal of device for google', (done) => { - const scope = utils - .createNock() - .get('/v1/push/sub-key/mySubKey/devices/niceDevice/remove') - .query({ - pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, - type: 'gcm', - uuid: 'myUUID', - }) - .reply(200, '[1, "Modified Channels"]'); - - pubnub.push.deleteDevice( - { device: 'niceDevice', pushGateway: 'gcm' }, - (status) => { - assert.equal(status.error, false); - assert.equal(scope.isDone(), true); - done(); - } - ); - }); - - it('should add push disable for device API telemetry information', (done) => { - let scope = utils.createNock().get('/v1/push/sub-key/mySubKey/devices/niceDevice/remove').query(true); - const delays = [100, 200, 300, 400]; - const countedDelays = delays.slice(0, delays.length - 1); - const average = Math.floor(countedDelays.reduce((acc, delay) => acc + delay, 0) / countedDelays.length); - const leeway = 50; - - utils.runAPIWithResponseDelays(scope, - 200, - '[1, "Modified Channels"]', - delays, - (completion) => { - pubnub.push.deleteDevice( - { device: 'niceDevice', pushGateway: 'apns' }, - () => { completion(); } - ); - }) - .then((lastRequest) => { - utils.verifyRequestTelemetry(lastRequest.path, 'l_push', average, leeway); - done(); - }); - }).timeout(60000); - - it('should add APNS2 disable for device API telemetry information', (done) => { - let scope = utils.createNock().get('/v2/push/sub-key/mySubKey/devices-apns2/niceDevice/remove').query(true); - const delays = [100, 200, 300, 400]; - const countedDelays = delays.slice(0, delays.length - 1); - const average = Math.floor(countedDelays.reduce((acc, delay) => acc + delay, 0) / countedDelays.length); - const leeway = 50; - - utils.runAPIWithResponseDelays(scope, - 200, - '[1, "Modified Channels"]', - delays, - (completion) => { - pubnub.push.deleteDevice( - { device: 'niceDevice', pushGateway: 'apns2', environment: 'production', topic: 'com.test.apns' }, - () => { completion(); } - ); - }) - .then((lastRequest) => { - utils.verifyRequestTelemetry(lastRequest.path, 'l_push', average, leeway); - done(); - }); - }).timeout(60000); - }); -}); diff --git a/test/integration/endpoints/push.test.ts b/test/integration/endpoints/push.test.ts new file mode 100644 index 000000000..3cb11089d --- /dev/null +++ b/test/integration/endpoints/push.test.ts @@ -0,0 +1,342 @@ +/* global describe, beforeEach, it, before, after */ +/* eslint no-console: 0 */ + +import assert from 'assert'; +import nock from 'nock'; + +import PubNub from '../../../src/node/index'; +import utils from '../../utils'; + +describe('push endpoints', () => { + let pubnub: PubNub; + + before(() => { + nock.disableNetConnect(); + }); + + after(() => { + nock.enableNetConnect(); + }); + + beforeEach(() => { + nock.cleanAll(); + pubnub = new PubNub({ + subscribeKey: 'mySubKey', + publishKey: 'myPublishKey', + // @ts-expect-error Force override default value. + useRequestId: false, + uuid: 'myUUID', + }); + }); + + describe('adding channels to device', () => { + it('supports addition of multiple channels for apple', (done) => { + const scope = utils + .createNock() + .get('/v1/push/sub-key/mySubKey/devices/niceDevice') + .query({ + add: 'a,b', + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + type: 'apns', + uuid: 'myUUID', + }) + .reply(200, '[1, "Modified Channels"]', { 'content-type': 'text/javascript' }); + + pubnub.push.addChannels({ channels: ['a', 'b'], device: 'niceDevice', pushGateway: 'apns' }, (status) => { + try { + assert.equal(status.error, false); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }); + }); + + it('supports addition of multiple channels for apple (APNS2)', (done) => { + const scope = utils + .createNock() + .get('/v2/push/sub-key/mySubKey/devices-apns2/niceDevice') + .query({ + add: 'a,b', + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + environment: 'development', + topic: 'com.test.apns', + type: 'apns2', + uuid: 'myUUID', + }) + .reply(200, '[1, "Modified Channels"]', { 'content-type': 'text/javascript' }); + + pubnub.push.addChannels( + { channels: ['a', 'b'], device: 'niceDevice', pushGateway: 'apns2', topic: 'com.test.apns' }, + (status) => { + try { + assert.equal(status.error, false); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }, + ); + }); + + it('supports addition of multiple channels for google', (done) => { + const scope = utils + .createNock() + .get('/v1/push/sub-key/mySubKey/devices/niceDevice') + .query({ + add: 'a,b', + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + type: 'gcm', + uuid: 'myUUID', + }) + .reply(200, '[1, "Modified Channels"]', { 'content-type': 'text/javascript' }); + + pubnub.push.addChannels({ channels: ['a', 'b'], device: 'niceDevice', pushGateway: 'gcm' }, (status) => { + try { + assert.equal(status.error, false); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }); + }); + }); + + describe('listing channels for device', () => { + it('supports channel listing for apple', (done) => { + const scope = utils + .createNock() + .get('/v1/push/sub-key/mySubKey/devices/coolDevice') + .query({ + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + type: 'apns', + uuid: 'myUUID', + }) + .reply(200, '["ch1", "ch2", "ch3"]', { 'content-type': 'text/javascript' }); + + pubnub.push.listChannels({ device: 'coolDevice', pushGateway: 'apns' }, (status, response) => { + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.channels, ["ch1", "ch2", "ch3"]); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }); + }); + + it('supports channel listing for apple (APNS2)', (done) => { + const scope = utils + .createNock() + .get('/v2/push/sub-key/mySubKey/devices-apns2/coolDevice') + .query({ + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + environment: 'production', + topic: 'com.test.apns', + type: 'apns2', + uuid: 'myUUID', + }) + .reply(200, '["ch1", "ch2", "ch3"]', { 'content-type': 'text/javascript' }); + + pubnub.push.listChannels( + { device: 'coolDevice', pushGateway: 'apns2', environment: 'production', topic: 'com.test.apns' }, + (status, response) => { + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.channels, ["ch1", "ch2", "ch3"]); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }, + ); + }); + + it('supports channel listing for google', (done) => { + const scope = utils + .createNock() + .get('/v1/push/sub-key/mySubKey/devices/coolDevice') + .query({ + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + type: 'gcm', + uuid: 'myUUID', + }) + .reply(200, '["ch1", "ch2", "ch3"]', { 'content-type': 'text/javascript' }); + + pubnub.push.listChannels({ device: 'coolDevice', pushGateway: 'gcm' }, (status, response) => { + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.channels, ["ch1", "ch2", "ch3"]); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }); + }); + }); + + describe('supports deletion of channels', () => { + it('supports removal of multiple channels for apple', (done) => { + const scope = utils + .createNock() + .get('/v1/push/sub-key/mySubKey/devices/niceDevice') + .query({ + remove: 'a,b', + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + type: 'apns', + uuid: 'myUUID', + }) + .reply(200, '[1, "Modified Channels"]', { 'content-type': 'text/javascript' }); + + pubnub.push.removeChannels({ channels: ['a', 'b'], device: 'niceDevice', pushGateway: 'apns' }, (status) => { + try { + assert.equal(status.error, false); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }); + }); + + it('supports removal of multiple channels for apple (APNS2)', (done) => { + const scope = utils + .createNock() + .get('/v2/push/sub-key/mySubKey/devices-apns2/niceDevice') + .query({ + remove: 'a,b', + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + environment: 'development', + topic: 'com.test.apns', + type: 'apns2', + uuid: 'myUUID', + }) + .reply(200, '[1, "Modified Channels"]', { 'content-type': 'text/javascript' }); + + pubnub.push.removeChannels( + { channels: ['a', 'b'], device: 'niceDevice', pushGateway: 'apns2', topic: 'com.test.apns' }, + (status) => { + try { + assert.equal(status.error, false); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }, + ); + }); + + it('supports removal of multiple channels for google', (done) => { + const scope = utils + .createNock() + .get('/v1/push/sub-key/mySubKey/devices/niceDevice') + .query({ + remove: 'a,b', + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + type: 'gcm', + uuid: 'myUUID', + }) + .reply(200, '[1, "Modified Channels"]', { 'content-type': 'text/javascript' }); + + pubnub.push.removeChannels( + { + channels: ['a', 'b'], + device: 'niceDevice', + pushGateway: 'gcm', + }, + (status) => { + try { + assert.equal(status.error, false); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }, + ); + }); + }); + + describe('supports removal of device', () => { + it('supports removal of device for apple', (done) => { + const scope = utils + .createNock() + .get('/v1/push/sub-key/mySubKey/devices/niceDevice/remove') + .query({ + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + type: 'apns', + uuid: 'myUUID', + }) + .reply(200, '[1, "Modified Channels"]', { 'content-type': 'text/javascript' }); + + pubnub.push.deleteDevice({ device: 'niceDevice', pushGateway: 'apns' }, (status) => { + try { + assert.equal(status.error, false); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }); + }); + + it('supports removal of device for apple (APNS2)', (done) => { + const scope = utils + .createNock() + .get('/v2/push/sub-key/mySubKey/devices-apns2/niceDevice/remove') + .query({ + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + environment: 'production', + topic: 'com.test.apns', + type: 'apns2', + uuid: 'myUUID', + }) + .reply(200, '[1, "Modified Channels"]', { 'content-type': 'text/javascript' }); + + pubnub.push.deleteDevice( + { device: 'niceDevice', pushGateway: 'apns2', environment: 'production', topic: 'com.test.apns' }, + (status) => { + try { + assert.equal(status.error, false); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }, + ); + }); + + it('supports removal of device for google', (done) => { + const scope = utils + .createNock() + .get('/v1/push/sub-key/mySubKey/devices/niceDevice/remove') + .query({ + pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, + type: 'gcm', + uuid: 'myUUID', + }) + .reply(200, '[1, "Modified Channels"]', { 'content-type': 'text/javascript' }); + + pubnub.push.deleteDevice({ device: 'niceDevice', pushGateway: 'gcm' }, (status) => { + try { + assert.equal(status.error, false); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }); + }); + }); +}); diff --git a/test/integration/endpoints/signal.test.js b/test/integration/endpoints/signal.test.js deleted file mode 100644 index ebc8b213c..000000000 --- a/test/integration/endpoints/signal.test.js +++ /dev/null @@ -1,80 +0,0 @@ -/* global describe, beforeEach, it, before, after */ -/* eslint no-console: 0 */ - -import assert from 'assert'; -import nock from 'nock'; -import utils from '../../utils'; -import PubNub from '../../../src/node/index'; - -describe('signal endpoints', () => { - let pubnub; - - before(() => { - nock.disableNetConnect(); - }); - - after(() => { - nock.enableNetConnect(); - }); - - beforeEach(() => { - nock.cleanAll(); - pubnub = new PubNub({ - subscribeKey: 'mySubKey', - publishKey: 'myPublishKey', - uuid: 'myUUID', - authKey: 'myAuthKey', - }); - }); - - describe('##validation', () => { - it('fails if channel is missing', (done) => { - const scope = utils - .createNock() - .get('/signal/*') - .reply(200, '[1,"Sent","14647523059145592"]'); - - pubnub.signal({ message: { such: 'object' } }).catch((err) => { - assert.equal(scope.isDone(), false); - assert.equal(err.status.message, 'Missing Channel'); - done(); - }); - }); - }); - - it('publishes a complex object via GET', (done) => { - const scope = utils.createNock().get('/signal/myPublishKey/mySubKey/0/ch1/0/%7B%22such%22%3A%22object%22%7D') - .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', auth: 'myAuthKey' }) - .reply(200, '[1,"Sent","14647523059145592"]'); - - pubnub.signal({ message: { such: 'object' }, channel: 'ch1' }, (status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.timetoken, 14647523059145592); - assert.equal(scope.isDone(), true); - done(); - }); - }); - - it('should add signal API telemetry information', (done) => { - let scope = utils.createNock().get('/signal/myPublishKey/mySubKey/0/ch1/0/%7B%22such%22%3A%22object%22%7D').query(true); - const delays = [100, 200, 300, 400]; - const countedDelays = delays.slice(0, delays.length - 1); - const average = Math.floor(countedDelays.reduce((acc, delay) => acc + delay, 0) / countedDelays.length); - const leeway = 50; - - utils.runAPIWithResponseDelays(scope, - 200, - '[1,"Sent","14647523059145592"]', - delays, - (completion) => { - pubnub.signal( - { message: { such: 'object' }, channel: 'ch1' }, - () => { completion(); } - ); - }) - .then((lastRequest) => { - utils.verifyRequestTelemetry(lastRequest.path, 'l_sig', average, leeway); - done(); - }); - }).timeout(60000); -}); diff --git a/test/integration/endpoints/signal.test.ts b/test/integration/endpoints/signal.test.ts new file mode 100644 index 000000000..4aca88ebe --- /dev/null +++ b/test/integration/endpoints/signal.test.ts @@ -0,0 +1,72 @@ +/* global describe, beforeEach, it, before, after */ +/* eslint no-console: 0 */ + +import assert from 'assert'; +import nock from 'nock'; + +import PubNub from '../../../src/node/index'; +import utils from '../../utils'; + +describe('signal endpoints', () => { + let pubnub: PubNub; + + before(() => { + nock.disableNetConnect(); + }); + + after(() => { + nock.enableNetConnect(); + }); + + beforeEach(() => { + nock.cleanAll(); + pubnub = new PubNub({ + subscribeKey: 'mySubKey', + publishKey: 'myPublishKey', + uuid: 'myUUID', + // @ts-expect-error Force override default value. + useRequestId: false, + authKey: 'myAuthKey', + }); + }); + + describe('##validation', () => { + it('fails if channel is missing', (done) => { + const scope = utils + .createNock() + .get('/signal/*') + .reply(200, '[1,"Sent","14647523059145592"]', { 'content-type': 'text/javascript' }); + + // @ts-expect-error Intentionally don't include `channel`. + pubnub.signal({ message: { such: 'object' } }).catch((err) => { + try { + assert.equal(scope.isDone(), false); + assert.equal(err.status.message, "Missing 'channel'"); + done(); + } catch (error) { + done(error); + } + }); + }); + }); + + it('publishes a complex object via GET', (done) => { + const scope = utils + .createNock() + .get('/signal/myPublishKey/mySubKey/0/ch1/0/%7B%22such%22%3A%22object%22%7D') + .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', auth: 'myAuthKey' }) + .reply(200, '[1,"Sent","14647523059145592"]', { 'content-type': 'text/javascript' }); + + pubnub.signal({ message: { such: 'object' }, channel: 'ch1' }, (status, response) => { + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.timetoken, "14647523059145592"); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } + }); + }); +}); diff --git a/test/integration/endpoints/subscribe.test.js b/test/integration/endpoints/subscribe.test.ts similarity index 57% rename from test/integration/endpoints/subscribe.test.js rename to test/integration/endpoints/subscribe.test.ts index 5949d722d..9e4c6bd2f 100644 --- a/test/integration/endpoints/subscribe.test.js +++ b/test/integration/endpoints/subscribe.test.ts @@ -3,12 +3,13 @@ import assert from 'assert'; import nock from 'nock'; -import utils from '../../utils'; + import PubNub from '../../../src/node/index'; +import utils from '../../utils'; describe('subscribe endpoints', () => { - let pubnub; - let pubnubWithFiltering; + let pubnubWithFiltering: PubNub; + let pubnub: PubNub; before(() => { nock.disableNetConnect(); @@ -24,12 +25,16 @@ describe('subscribe endpoints', () => { subscribeKey: 'mySubKey', publishKey: 'myPublishKey', uuid: 'myUUID', + // @ts-expect-error Force override default value. + useRequestId: false, autoNetworkDetection: false, }); pubnubWithFiltering = new PubNub({ subscribeKey: 'mySubKey', publishKey: 'myPublishKey', uuid: 'myUUID', + // @ts-expect-error Force override default value. + useRequestId: false, filterExpression: 'hello!', autoNetworkDetection: false, }); @@ -43,7 +48,7 @@ describe('subscribe endpoints', () => { it('supports addition of multiple channels', (done) => { const scope = utils .createNock() - .get('/v2/subscribe/mySubKey/coolChannel%2CcoolChannel2/0') + .get('/v2/subscribe/mySubKey/coolChannel,coolChannel2/0') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -51,24 +56,23 @@ describe('subscribe endpoints', () => { }) .reply( 200, - '{"t":{"t":"14607577960932487","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Enter Message Here"},"b":"coolChan-bnel"}]}' + '{"t":{"t":"14607577960932487","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Enter Message Here"},"b":"coolChan-bnel"}]}', + { 'content-type': 'text/javascript' }, ); pubnub.addListener({ status(status) { if (status.category === 'PNConnectedCategory') { - assert.equal(scope.isDone(), true); - assert.deepEqual(pubnub.getSubscribedChannels(), [ - 'coolChannel', - 'coolChannel2', - ]); - assert.deepEqual(pubnub.getSubscribedChannelGroups(), []); - assert.deepEqual(status.affectedChannels, [ - 'coolChannel', - 'coolChannel2', - ]); - assert.deepEqual(status.affectedChannelGroups, []); - done(); + try { + assert.equal(scope.isDone(), true); + assert.deepEqual(pubnub.getSubscribedChannels(), ["coolChannel", "coolChannel2"]); + assert.deepEqual(pubnub.getSubscribedChannelGroups(), []); + assert.deepEqual(status.affectedChannels, ["coolChannel", "coolChannel2"]); + assert.deepEqual(status.affectedChannelGroups, []); + done(); + } catch (error) { + done(error); + } } }, }); @@ -79,7 +83,7 @@ describe('subscribe endpoints', () => { it('supports addition of multiple channels / channel groups', (done) => { const scope = utils .createNock() - .get('/v2/subscribe/mySubKey/coolChannel%2CcoolChannel2/0') + .get('/v2/subscribe/mySubKey/coolChannel,coolChannel2/0') .query({ 'channel-group': 'cg1,cg2', pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, @@ -88,24 +92,23 @@ describe('subscribe endpoints', () => { }) .reply( 200, - '{"t":{"t":"14607577960932487","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Enter Message Here"},"b":"coolChan-bnel"}]}' + '{"t":{"t":"14607577960932487","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Enter Message Here"},"b":"coolChan-bnel"}]}', + { 'content-type': 'text/javascript' }, ); pubnub.addListener({ status(status) { if (status.category === 'PNConnectedCategory') { - assert.equal(scope.isDone(), true); - assert.deepEqual(pubnub.getSubscribedChannels(), [ - 'coolChannel', - 'coolChannel2', - ]); - assert.deepEqual(pubnub.getSubscribedChannelGroups(), ['cg1', 'cg2']); - assert.deepEqual(status.affectedChannels, [ - 'coolChannel', - 'coolChannel2', - ]); - assert.deepEqual(status.affectedChannelGroups, ['cg1', 'cg2']); - done(); + try { + assert.equal(scope.isDone(), true); + assert.deepEqual(pubnub.getSubscribedChannels(), ["coolChannel", "coolChannel2"]); + assert.deepEqual(pubnub.getSubscribedChannelGroups(), ["cg1", "cg2"]); + assert.deepEqual(status.affectedChannels, ["coolChannel", "coolChannel2"]); + assert.deepEqual(status.affectedChannelGroups, ["cg1", "cg2"]); + done(); + } catch (error) { + done(error); + } } }, }); @@ -119,7 +122,7 @@ describe('subscribe endpoints', () => { it('supports just channel group', (done) => { const scope = utils .createNock() - .get('/v2/subscribe/mySubKey/%2C/0') + .get('/v2/subscribe/mySubKey/,/0') .query({ 'channel-group': 'cg1,cg2', pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, @@ -128,18 +131,23 @@ describe('subscribe endpoints', () => { }) .reply( 200, - '{"t":{"t":"14607577960932487","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Enter Message Here"},"b":"coolChan-bnel"}]}' + '{"t":{"t":"14607577960932487","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Enter Message Here"},"b":"coolChan-bnel"}]}', + { 'content-type': 'text/javascript' }, ); pubnub.addListener({ status(status) { if (status.category === 'PNConnectedCategory') { - assert.equal(scope.isDone(), true); - assert.deepEqual(pubnub.getSubscribedChannels(), []); - assert.deepEqual(pubnub.getSubscribedChannelGroups(), ['cg1', 'cg2']); - assert.deepEqual(status.affectedChannels, []); - assert.deepEqual(status.affectedChannelGroups, ['cg1', 'cg2']); - done(); + try { + assert.equal(scope.isDone(), true); + assert.deepEqual(pubnub.getSubscribedChannels(), []); + assert.deepEqual(pubnub.getSubscribedChannelGroups(), ["cg1", "cg2"]); + assert.deepEqual(status.affectedChannels, []); + assert.deepEqual(status.affectedChannelGroups, ["cg1", "cg2"]); + done(); + } catch (error) { + done(error); + } } }, }); @@ -150,7 +158,7 @@ describe('subscribe endpoints', () => { it('supports filter expression', (done) => { const scope = utils .createNock() - .get('/v2/subscribe/mySubKey/coolChannel%2CcoolChannel2/0') + .get('/v2/subscribe/mySubKey/coolChannel,coolChannel2/0') .query({ 'filter-expr': 'hello!', pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, @@ -159,27 +167,23 @@ describe('subscribe endpoints', () => { }) .reply( 200, - '{"t":{"t":"14607577960932487","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Enter Message Here"},"b":"coolChan-bnel"}]}' + '{"t":{"t":"14607577960932487","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Enter Message Here"},"b":"coolChan-bnel"}]}', + { 'content-type': 'text/javascript' }, ); pubnubWithFiltering.addListener({ status(status) { if (status.category === 'PNConnectedCategory') { - assert.equal(scope.isDone(), true); - assert.deepEqual(pubnubWithFiltering.getSubscribedChannels(), [ - 'coolChannel', - 'coolChannel2', - ]); - assert.deepEqual( - pubnubWithFiltering.getSubscribedChannelGroups(), - [] - ); - assert.deepEqual(status.affectedChannels, [ - 'coolChannel', - 'coolChannel2', - ]); - assert.deepEqual(status.affectedChannelGroups, []); - done(); + try { + assert.equal(scope.isDone(), true); + assert.deepEqual(pubnubWithFiltering.getSubscribedChannels(), ["coolChannel", "coolChannel2"]); + assert.deepEqual(pubnubWithFiltering.getSubscribedChannelGroups(), []); + assert.deepEqual(status.affectedChannels, ["coolChannel", "coolChannel2"]); + assert.deepEqual(status.affectedChannelGroups, []); + done(); + } catch (error) { + done(error); + } } }, }); diff --git a/test/integration/endpoints/time.test.js b/test/integration/endpoints/time.test.js deleted file mode 100644 index f5dafc402..000000000 --- a/test/integration/endpoints/time.test.js +++ /dev/null @@ -1,106 +0,0 @@ -/* global describe, beforeEach, it, before, after */ -/* eslint no-console: 0 */ - -import assert from 'assert'; -import nock from 'nock'; -import utils from '../../utils'; -import PubNub from '../../../src/node/index'; - -describe('time endpoints', () => { - let pubnub; - - before(() => { - nock.disableNetConnect(); - }); - - after(() => { - nock.enableNetConnect(); - }); - - beforeEach(() => { - nock.cleanAll(); - pubnub = new PubNub({ - uuid: 'myUUID', - keepAlive: true, - }); - }); - - it('calls the callback function when time is fetched', (done) => { - utils - .createNock() - .get('/time/0') - .query(true) - .reply(200, [14570763868573725]); - - pubnub.time((status, response) => { - assert.equal(status.error, false); - assert.deepEqual(response.timetoken, 14570763868573725); - done(); - }); - }); - - it('calls the callback function when time is fetched via promise', (done) => { - utils - .createNock() - .get('/time/0') - .query(true) - .reply(200, [14570763868573725]); - - pubnub.time().then((response) => { - assert.deepEqual(response.timetoken, 14570763868573725); - done(); - }); - }); - - it('calls the callback function when fetch failed', (done) => { - utils - .createNock() - .get('/time/0') - .query(true) - .reply(500, null); - - pubnub.time((status, response) => { - assert.equal(response, null); - assert.equal(status.error, true); - done(); - }); - }); - - it('calls the callback function when fetch failed', (done) => { - utils - .createNock() - .get('/time/0') - .query(true) - .reply(500, null); - - pubnub.time().catch((ex) => { - assert(ex instanceof Error); - assert.equal(ex.message, 'PubNub call failed, check status for details'); - assert.equal(ex.status.error, true); - assert.equal(ex.status.statusCode, 500); - done(); - }); - }); - - it('should add time API telemetry information', (done) => { - let scope = utils.createNock().get('/time/0').query(true); - const delays = [100, 200, 300, 400]; - const countedDelays = delays.slice(0, delays.length - 1); - const average = Math.floor(countedDelays.reduce((acc, delay) => acc + delay, 0) / countedDelays.length); - const leeway = 50; - - utils.runAPIWithResponseDelays(scope, - 200, - [14570763868573725], - delays, - (completion) => { - pubnub.time(() => { - completion(); - }); - }) - .then((lastRequest) => { - utils.verifyRequestTelemetry(lastRequest.path, 'l_time', average, leeway); - done(); - }); - }).timeout(60000); -}); diff --git a/test/integration/endpoints/time.test.ts b/test/integration/endpoints/time.test.ts new file mode 100644 index 000000000..1b71fa05e --- /dev/null +++ b/test/integration/endpoints/time.test.ts @@ -0,0 +1,89 @@ +/* global describe, beforeEach, it, before, after */ +/* eslint no-console: 0 */ + +import assert from 'assert'; +import nock from 'nock'; + +import { PubNubError } from '../../../src/errors/pubnub-error'; +import PubNub from '../../../src/node/index'; +import utils from '../../utils'; + +describe('time endpoints', () => { + let pubnub: PubNub; + + before(() => { + nock.disableNetConnect(); + }); + + after(() => { + nock.enableNetConnect(); + }); + + beforeEach(() => { + nock.cleanAll(); + pubnub = new PubNub({ + uuid: 'myUUID', + // @ts-expect-error Force override default value. + useRequestId: false, + keepAlive: true, + }); + }); + + it('calls the callback function when time is fetched', (done) => { + utils.createNock().get('/time/0').query(true).reply(200, ['14570763868573725']); + + pubnub.time((status, response) => { + try { + assert.equal(status.error, false); + assert(response !== null); + assert.deepEqual(response.timetoken, "14570763868573725"); + done(); + } catch (error) { + done(error); + } + }); + }); + + it('calls the callback function when time is fetched via promise', (done) => { + utils.createNock().get('/time/0').query(true).reply(200, ['14570763868573725']); + + pubnub.time().then((response) => { + try { + assert.deepEqual(response.timetoken, '14570763868573725'); + done(); + } catch (error) { + done(error); + } + }); + }); + + it('calls the callback function when fetch failed', (done) => { + utils.createNock().get('/time/0').query(true).reply(500, undefined); + + pubnub.time((status, response) => { + try { + assert.equal(response, null); + assert.equal(status.error, true); + done(); + } catch (error) { + done(error); + } + }); + }); + + it('calls the callback function when fetch failed', (done) => { + utils.createNock().get('/time/0').query(true).reply(500, undefined); + + pubnub.time().catch((ex) => { + try { + assert(ex instanceof PubNubError); + assert.equal(ex.message, "REST API request processing error, check status for details"); + assert.equal(ex.status!.error, true); + assert.equal(ex.status!.statusCode, 500); + done(); + } catch (error) { + done(error); + } + }); + }); +}); diff --git a/test/integration/operations/heartbeat.test.js b/test/integration/operations/heartbeat.test.ts similarity index 68% rename from test/integration/operations/heartbeat.test.js rename to test/integration/operations/heartbeat.test.ts index dae373613..1a9939b66 100644 --- a/test/integration/operations/heartbeat.test.js +++ b/test/integration/operations/heartbeat.test.ts @@ -1,13 +1,15 @@ /* global describe, beforeEach, it, before, afterEach, after */ /* eslint no-console: 0 */ +import { expect } from 'chai'; import assert from 'assert'; import nock from 'nock'; -import utils from '../../utils'; + import PubNub from '../../../src/node/index'; +import utils from '../../utils'; describe('heartbeat', () => { - let pubnub; + let pubnub: PubNub; before(() => { nock.disableNetConnect(); @@ -23,8 +25,10 @@ describe('heartbeat', () => { subscribeKey: 'mySubscribeKey', publishKey: 'myPublishKey', uuid: 'myUUID', - heartbeatInterval :1, // for quick test of heartbeat calls + // @ts-expect-error This configuration option normally is hidden. + useRequestId: false, announceSuccessfulHeartbeats: true, + heartbeatInterval: 1, // for quick test of heartbeat calls }); }); @@ -39,22 +43,25 @@ describe('heartbeat', () => { subscribeKey: 'mySubscribeKey', publishKey: 'myPublishKey', uuid: 'myUUID', + // @ts-expect-error This configuration option normally is hidden. announceSuccessfulHeartbeats: true, }); const scope = utils .createNock() - .get('/v2/presence/sub-key/mySubscribeKey/channel/ch1%2Cch2/heartbeat') + .get('/v2/presence/sub-key/mySubscribeKey/channel/ch1,ch2/heartbeat') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', heartbeat: '300', state: '{}', }) - .reply(200, '{"status": 200, "message": "OK", "service": "Presence"}'); + .reply(200, '{"status": 200, "message": "OK", "service": "Presence"}', { + 'content-type': 'text/javascript', + }); pubnub.subscribe({ channels: ['ch1', 'ch2'], withHeartbeats: true }); await expect(scope).to.have.not.been.requested; }); - + it('supports heartbeating for one channel', (done) => { const scope = utils .createNock() @@ -65,14 +72,20 @@ describe('heartbeat', () => { heartbeat: '300', state: '{}', }) - .reply(200, '{"status": 200, "message": "OK", "service": "Presence"}'); + .reply(200, '{"status": 200, "message": "OK", "service": "Presence"}', { + 'content-type': 'text/javascript', + }); pubnub.addListener({ status(status) { if (status.operation === 'PNHeartbeatOperation' && !status.error) { - assert.equal(status.error, false); - assert.equal(scope.isDone(), true); - done(); + try { + assert.equal(status.error, false); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } } }, }); @@ -83,21 +96,27 @@ describe('heartbeat', () => { it('supports heartbeating for multiple channels', (done) => { const scope = utils .createNock() - .get('/v2/presence/sub-key/mySubscribeKey/channel/ch1%2Cch2/heartbeat') + .get('/v2/presence/sub-key/mySubscribeKey/channel/ch1,ch2/heartbeat') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', heartbeat: '300', state: '{}', }) - .reply(200, '{"status": 200, "message": "OK", "service": "Presence"}'); + .reply(200, '{"status": 200, "message": "OK", "service": "Presence"}', { + 'content-type': 'text/javascript', + }); pubnub.addListener({ status(status) { if (status.operation === 'PNHeartbeatOperation' && !status.error) { - assert.equal(status.error, false); - assert.equal(scope.isDone(), true); - done(); + try { + assert.equal(status.error, false); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } } }, }); @@ -108,7 +127,7 @@ describe('heartbeat', () => { it('supports heartbeating for one channel group', (done) => { const scope = utils .createNock() - .get('/v2/presence/sub-key/mySubscribeKey/channel/%2C/heartbeat') + .get('/v2/presence/sub-key/mySubscribeKey/channel/,/heartbeat') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -116,14 +135,20 @@ describe('heartbeat', () => { state: '{}', 'channel-group': 'cg1', }) - .reply(200, '{"status": 200, "message": "OK", "service": "Presence"}'); + .reply(200, '{"status": 200, "message": "OK", "service": "Presence"}', { + 'content-type': 'text/javascript', + }); pubnub.addListener({ status(status) { if (status.operation === 'PNHeartbeatOperation' && !status.error) { - assert.equal(status.error, false); - assert.equal(scope.isDone(), true); - done(); + try { + assert.equal(status.error, false); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } } }, }); @@ -134,7 +159,7 @@ describe('heartbeat', () => { it('supports heartbeating for multiple channel group', (done) => { const scope = utils .createNock() - .get('/v2/presence/sub-key/mySubscribeKey/channel/%2C/heartbeat') + .get('/v2/presence/sub-key/mySubscribeKey/channel/,/heartbeat') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -142,14 +167,20 @@ describe('heartbeat', () => { state: '{}', 'channel-group': 'cg1,cg2', }) - .reply(200, '{"status": 200, "message": "OK", "service": "Presence"}'); + .reply(200, '{"status": 200, "message": "OK", "service": "Presence"}', { + 'content-type': 'text/javascript', + }); pubnub.addListener({ status(status) { if (status.operation === 'PNHeartbeatOperation' && !status.error) { - assert.equal(status.error, false); - assert.equal(scope.isDone(), true); - done(); + try { + assert.equal(status.error, false); + assert.equal(scope.isDone(), true); + done(); + } catch (error) { + done(error); + } } }, }); diff --git a/test/integration/operations/stateSetting.test.js b/test/integration/operations/stateSetting.test.ts similarity index 62% rename from test/integration/operations/stateSetting.test.js rename to test/integration/operations/stateSetting.test.ts index 32e468bd0..ced3d0e7e 100644 --- a/test/integration/operations/stateSetting.test.js +++ b/test/integration/operations/stateSetting.test.ts @@ -3,11 +3,12 @@ import assert from 'assert'; import nock from 'nock'; -import utils from '../../utils'; + import PubNub from '../../../src/node/index'; +import utils from '../../utils'; describe('setting state operation', () => { - let pubnub; + let pubnub: PubNub; before(() => { nock.disableNetConnect(); @@ -23,18 +24,21 @@ describe('setting state operation', () => { subscribeKey: 'mySubscribeKey', publishKey: 'myPublishKey', uuid: 'myUUID', + // @ts-expect-error Force override default value. + useRequestId: false, }); }); describe('#setState', () => { it('fails if no channels are provided', (done) => { pubnub.setState({ state: { hello: 'there' } }, (status) => { - assert.equal(status.error, true); - assert.equal( - status.message, - 'Please provide a list of channels and/or channel-groups' - ); - done(); + try { + assert.equal(status.error, true); + assert.equal(status.message, "Please provide a list of channels and/or channel-groups"); + done(); + } catch (error) { + done(error); + } }); }); @@ -49,26 +53,27 @@ describe('setting state operation', () => { }) .reply( 200, - '{ "status": 200, "message": "OK", "payload": { "age" : 20, "status" : "online" }, "service": "Presence"}' + '{ "status": 200, "message": "OK", "payload": { "age" : 20, "status" : "online" }, "service": "Presence"}', + { 'content-type': 'text/javascript' }, ); - pubnub.setState( - { channels: ['ch1'], state: { hello: 'there' } }, - (status, response) => { + pubnub.setState({ channels: ['ch1'], state: { hello: 'there' } }, (status, response) => { + try { assert.equal(status.error, false); - assert.deepEqual(response.state, { age: 20, status: 'online' }); + assert(response !== null); + assert.deepEqual(response.state, { age: 20, status: "online" }); assert.equal(scope.isDone(), true); done(); + } catch (error) { + done(error); } - ); + }); }); it('supports updating for multiple channels', (done) => { const scope = utils .createNock() - .get( - '/v2/presence/sub-key/mySubscribeKey/channel/ch1%2Cch2/uuid/myUUID/data' - ) + .get('/v2/presence/sub-key/mySubscribeKey/channel/ch1,ch2/uuid/myUUID/data') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -76,24 +81,27 @@ describe('setting state operation', () => { }) .reply( 200, - '{ "status": 200, "message": "OK", "payload": { "age" : 20, "status" : "online" }, "service": "Presence"}' + '{ "status": 200, "message": "OK", "payload": { "age" : 20, "status" : "online" }, "service": "Presence"}', + { 'content-type': 'text/javascript' }, ); - pubnub.setState( - { channels: ['ch1', 'ch2'], state: { hello: 'there' } }, - (status, response) => { + pubnub.setState({ channels: ['ch1', 'ch2'], state: { hello: 'there' } }, (status, response) => { + try { assert.equal(status.error, false); - assert.deepEqual(response.state, { age: 20, status: 'online' }); + assert(response !== null); + assert.deepEqual(response.state, { age: 20, status: "online" }); assert.equal(scope.isDone(), true); done(); + } catch (error) { + done(error); } - ); + }); }); it('supports updating for one channel group', (done) => { const scope = utils .createNock() - .get('/v2/presence/sub-key/mySubscribeKey/channel/%2C/uuid/myUUID/data') + .get('/v2/presence/sub-key/mySubscribeKey/channel/,/uuid/myUUID/data') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -102,24 +110,27 @@ describe('setting state operation', () => { }) .reply( 200, - '{ "status": 200, "message": "OK", "payload": { "age" : 20, "status" : "online" }, "service": "Presence"}' + '{ "status": 200, "message": "OK", "payload": { "age" : 20, "status" : "online" }, "service": "Presence"}', + { 'content-type': 'text/javascript' }, ); - pubnub.setState( - { channelGroups: ['cg1'], state: { hello: 'there' } }, - (status, response) => { + pubnub.setState({ channelGroups: ['cg1'], state: { hello: 'there' } }, (status, response) => { + try { assert.equal(status.error, false); - assert.deepEqual(response.state, { age: 20, status: 'online' }); + assert(response !== null); + assert.deepEqual(response.state, { age: 20, status: "online" }); assert.equal(scope.isDone(), true); done(); + } catch (error) { + done(error); } - ); + }); }); it('supports updating for multiple channel group', (done) => { const scope = utils .createNock() - .get('/v2/presence/sub-key/mySubscribeKey/channel/%2C/uuid/myUUID/data') + .get('/v2/presence/sub-key/mySubscribeKey/channel/,/uuid/myUUID/data') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -128,18 +139,21 @@ describe('setting state operation', () => { }) .reply( 200, - '{ "status": 200, "message": "OK", "payload": { "age" : 20, "status" : "online" }, "service": "Presence"}' + '{ "status": 200, "message": "OK", "payload": { "age" : 20, "status" : "online" }, "service": "Presence"}', + { 'content-type': 'text/javascript' }, ); - pubnub.setState( - { channelGroups: ['cg1', 'cg2'], state: { hello: 'there' } }, - (status, response) => { + pubnub.setState({ channelGroups: ['cg1', 'cg2'], state: { hello: 'there' } }, (status, response) => { + try { assert.equal(status.error, false); - assert.deepEqual(response.state, { age: 20, status: 'online' }); + assert(response !== null); + assert.deepEqual(response.state, { age: 20, status: "online" }); assert.equal(scope.isDone(), true); done(); + } catch (error) { + done(error); } - ); + }); }); it('supports promises', (done) => { @@ -153,7 +167,8 @@ describe('setting state operation', () => { }) .reply( 200, - '{ "status": 200, "message": "OK", "payload": { "age" : 20, "status" : "online" }, "service": "Presence"}' + '{ "status": 200, "message": "OK", "payload": { "age" : 20, "status" : "online" }, "service": "Presence"}', + { 'content-type': 'text/javascript' }, ); let promise = pubnub.setState({ diff --git a/test/integration/operations/unsubscribe.test.js b/test/integration/operations/unsubscribe.test.ts similarity index 59% rename from test/integration/operations/unsubscribe.test.js rename to test/integration/operations/unsubscribe.test.ts index f866096f9..c4c5de053 100644 --- a/test/integration/operations/unsubscribe.test.js +++ b/test/integration/operations/unsubscribe.test.ts @@ -3,11 +3,12 @@ import assert from 'assert'; import nock from 'nock'; -import utils from '../../utils'; + import PubNub from '../../../src/node/index'; +import utils from '../../utils'; describe('unsubscribe', () => { - let pubnub; + let pubnub: PubNub; before(() => { nock.disableNetConnect(); @@ -23,6 +24,8 @@ describe('unsubscribe', () => { subscribeKey: 'mySubscribeKey', publishKey: 'myPublishKey', uuid: 'myUUID', + // @ts-expect-error Force override default value. + useRequestId: false, }); pubnub.setHeartbeatInterval(0); }); @@ -44,36 +47,39 @@ describe('unsubscribe', () => { }) .reply( 200, - '{"t":{"t":"14607577960932487","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Enter Message Here"},"b":"coolChan-bnel"}]}' + '{"t":{"t":"14607577960932487","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Enter Message Here"},"b":"coolChan-bnel"}]}', + { 'content-type': 'text/javascript' }, ) .get('/v2/presence/sub-key/mySubscribeKey/channel/ch1/leave') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', }) - .reply(200, '{ "status": 200, "message": "OK", "service": "Presence"}'); + .reply(200, '{ "status": 200, "message": "OK", "service": "Presence"}', { 'content-type': 'text/javascript' }); pubnub.addListener({ status(status) { - if (status.category !== 'PNConnectedCategory') { - console.log('status', JSON.stringify(status )) - assert.equal(status.error, false); - assert.equal(scope.isDone(), true); - assert.deepEqual(status.affectedChannels, ['ch1']); - assert.deepEqual(status.affectedChannelGroups, []); - done(); - } + if (status.category !== PubNub.CATEGORIES.PNConnectedCategory) { + try { + assert.equal(status.error, false); + assert.equal(scope.isDone(), true); + assert.deepEqual(status.affectedChannels, ["ch1"]); + assert.deepEqual(status.affectedChannelGroups, []); + done(); + } catch (error) { + done(error); + } + } else pubnub.unsubscribe({ channels: ['ch1'] }); }, }); pubnub.subscribe({ channels: ['ch1'] }); - pubnub.unsubscribe({ channels: ['ch1'] }); }); it('supports leaving for multiple channels', (done) => { const scope = utils .createNock() - .get('/v2/subscribe/mySubscribeKey/ch1%2Cch2/0') + .get('/v2/subscribe/mySubscribeKey/ch1,ch2/0') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', @@ -81,35 +87,39 @@ describe('unsubscribe', () => { }) .reply( 200, - '{"t":{"t":"14607577960932487","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Enter Message Here"},"b":"coolChan-bnel"}]}' + '{"t":{"t":"14607577960932487","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Enter Message Here"},"b":"coolChan-bnel"}]}', + { 'content-type': 'text/javascript' }, ) - .get('/v2/presence/sub-key/mySubscribeKey/channel/ch1%2Cch2/leave') + .get('/v2/presence/sub-key/mySubscribeKey/channel/ch1,ch2/leave') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', }) - .reply(200, '{ "status": 200, "message": "OK", "service": "Presence"}'); + .reply(200, '{ "status": 200, "message": "OK", "service": "Presence"}', { 'content-type': 'text/javascript' }); pubnub.addListener({ status(status) { - if (status.category !== 'PNConnectedCategory') { - assert.equal(status.error, false); - assert.equal(scope.isDone(), true); - assert.deepEqual(status.affectedChannels, ['ch1', 'ch2']); - assert.deepEqual(status.affectedChannelGroups, []); - done(); - } + if (status.category !== PubNub.CATEGORIES.PNConnectedCategory) { + try { + assert.equal(status.error, false); + assert.equal(scope.isDone(), true); + assert.deepEqual(status.affectedChannels, ["ch1", "ch2"]); + assert.deepEqual(status.affectedChannelGroups, []); + done(); + } catch (error) { + done(error); + } + } else pubnub.unsubscribe({ channels: ['ch1', 'ch2'] }); }, }); pubnub.subscribe({ channels: ['ch1', 'ch2'] }); - pubnub.unsubscribe({ channels: ['ch1', 'ch2'] }); }); it('supports leaving for one channel group', (done) => { const scope = utils .createNock() - .get('/v2/subscribe/mySubscribeKey/%2C/0') + .get('/v2/subscribe/mySubscribeKey/,/0') .query({ 'channel-group': 'cg1', pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, @@ -118,36 +128,40 @@ describe('unsubscribe', () => { }) .reply( 200, - '{"t":{"t":"14607577960932487","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Enter Message Here"},"b":"coolChan-bnel"}]}' + '{"t":{"t":"14607577960932487","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Enter Message Here"},"b":"coolChan-bnel"}]}', + { 'content-type': 'text/javascript' }, ) - .get('/v2/presence/sub-key/mySubscribeKey/channel/%2C/leave') + .get('/v2/presence/sub-key/mySubscribeKey/channel/,/leave') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', 'channel-group': 'cg1', }) - .reply(200, '{ "status": 200, "message": "OK", "service": "Presence"}'); + .reply(200, '{ "status": 200, "message": "OK", "service": "Presence"}', { 'content-type': 'text/javascript' }); pubnub.addListener({ status(status) { - if (status.category !== 'PNConnectedCategory') { - assert.equal(status.error, false); - assert.equal(scope.isDone(), true); - assert.deepEqual(status.affectedChannels, []); - assert.deepEqual(status.affectedChannelGroups, ['cg1']); - done(); - } + if (status.category !== PubNub.CATEGORIES.PNConnectedCategory) { + try { + assert.equal(status.error, false); + assert.equal(scope.isDone(), true); + assert.deepEqual(status.affectedChannels, []); + assert.deepEqual(status.affectedChannelGroups, ["cg1"]); + done(); + } catch (error) { + done(error); + } + } else pubnub.unsubscribe({ channelGroups: ['cg1'] }); }, }); pubnub.subscribe({ channelGroups: ['cg1'] }); - pubnub.unsubscribe({ channelGroups: ['cg1'] }); }); it('supports leaving for multiple channel group', (done) => { const scope = utils .createNock() - .get('/v2/subscribe/mySubscribeKey/%2C/0') + .get('/v2/subscribe/mySubscribeKey/,/0') .query({ 'channel-group': 'cg1,cg2', pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, @@ -156,30 +170,34 @@ describe('unsubscribe', () => { }) .reply( 200, - '{"t":{"t":"14607577960932487","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Enter Message Here"},"b":"coolChan-bnel"}]}' + '{"t":{"t":"14607577960932487","r":1},"m":[{"a":"4","f":0,"i":"Client-g5d4g","p":{"t":"14607577960925503","r":1},"k":"sub-c-4cec9f8e-01fa-11e6-8180-0619f8945a4f","c":"coolChannel","d":{"text":"Enter Message Here"},"b":"coolChan-bnel"}]}', + { 'content-type': 'text/javascript' }, ) - .get('/v2/presence/sub-key/mySubscribeKey/channel/%2C/leave') + .get('/v2/presence/sub-key/mySubscribeKey/channel/,/leave') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', 'channel-group': 'cg1,cg2', }) - .reply(200, '{ "status": 200, "message": "OK", "service": "Presence"}'); + .reply(200, '{ "status": 200, "message": "OK", "service": "Presence"}', { 'content-type': 'text/javascript' }); pubnub.addListener({ status(status) { - if (status.category !== 'PNConnectedCategory') { - assert.equal(status.error, false); - assert.equal(scope.isDone(), true); - assert.deepEqual(status.affectedChannels, []); - assert.deepEqual(status.affectedChannelGroups, ['cg1', 'cg2']); - done(); - } + if (status.category !== PubNub.CATEGORIES.PNConnectedCategory) { + try { + assert.equal(status.error, false); + assert.equal(scope.isDone(), true); + assert.deepEqual(status.affectedChannels, []); + assert.deepEqual(status.affectedChannelGroups, ["cg1", "cg2"]); + done(); + } catch (error) { + done(error); + } + } else pubnub.unsubscribe({ channelGroups: ['cg1', 'cg2'] }); }, }); pubnub.subscribe({ channelGroups: ['cg1', 'cg2'] }); - pubnub.unsubscribe({ channelGroups: ['cg1', 'cg2'] }); }); it('supports partial leaving for channels', (done) => { @@ -190,47 +208,60 @@ describe('unsubscribe', () => { pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', }) - .reply(200, '{ "status": 200, "message": "OK", "service": "Presence"}'); + .reply(200, '{ "status": 200, "message": "OK", "service": "Presence"}', { 'content-type': 'text/javascript' }); pubnub.addListener({ status(status) { - if (status.operation !== 'PNUnsubscribeOperation') return; - assert.equal(status.error, false); - assert.equal(scope.isDone(), true); - assert.deepEqual(status.affectedChannels, ['ch1']); - assert.deepEqual(status.affectedChannelGroups, []); - done(); + if (status.operation !== PubNub.OPERATIONS.PNUnsubscribeOperation) { + pubnub.unsubscribe({ channels: ['ch1', 'ch3'] }); + return; + } + + try { + assert.equal(status.error, false); + assert.equal(scope.isDone(), true); + assert.deepEqual(status.affectedChannels, ["ch1"]); + assert.deepEqual(status.affectedChannelGroups, []); + done(); + } catch (error) { + done(error); + } }, }); pubnub.subscribe({ channels: ['ch1', 'ch2'] }); - pubnub.unsubscribe({ channels: ['ch1', 'ch3'] }); }); it('supports partial leaving for channel groups', (done) => { const scope = utils .createNock() - .get('/v2/presence/sub-key/mySubscribeKey/channel/%2C/leave') + .get('/v2/presence/sub-key/mySubscribeKey/channel/,/leave') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', 'channel-group': 'cg1', }) - .reply(200, '{ "status": 200, "message": "OK", "service": "Presence"}'); + .reply(200, '{ "status": 200, "message": "OK", "service": "Presence"}', { 'content-type': 'text/javascript' }); pubnub.addListener({ status(status) { - if (status.operation !== 'PNUnsubscribeOperation') return; - assert.equal(status.error, false); - assert.equal(scope.isDone(), true); - assert.deepEqual(status.affectedChannels, []); - assert.deepEqual(status.affectedChannelGroups, ['cg1']); - done(); + if (status.operation !== PubNub.OPERATIONS.PNUnsubscribeOperation) { + pubnub.unsubscribe({ channelGroups: ['cg1', 'cg3'] }); + return; + } + try { + assert.equal(status.error, false); + assert.equal(scope.isDone(), true); + assert.deepEqual(status.affectedChannels, []); + assert.deepEqual(status.affectedChannelGroups, ["cg1"]); + done(); + } catch (error) { + done(error); + } }, }); pubnub.subscribe({ channelGroups: ['cg1', 'cg2'] }); - pubnub.unsubscribe({ channelGroups: ['cg1', 'cg3'] }); }); }); @@ -238,22 +269,26 @@ describe('unsubscribe', () => { it('supports leaving channels / channel groups', (done) => { const scope = utils .createNock() - .get('/v2/presence/sub-key/mySubscribeKey/channel/ch1%2Cch2/leave') + .get('/v2/presence/sub-key/mySubscribeKey/channel/ch1,ch2/leave') .query({ pnsdk: `PubNub-JS-Nodejs/${pubnub.getVersion()}`, uuid: 'myUUID', 'channel-group': 'cg1,cg2', }) - .reply(200, '{ "status": 200, "message": "OK", "service": "Presence"}'); + .reply(200, '{ "status": 200, "message": "OK", "service": "Presence"}', { 'content-type': 'text/javascript' }); pubnub.addListener({ status(status) { - if (status.operation !== 'PNUnsubscribeOperation') return; - assert.equal(status.error, false); - assert.equal(scope.isDone(), true); - assert.deepEqual(status.affectedChannels, ['ch1', 'ch2']); - assert.deepEqual(status.affectedChannelGroups, ['cg1', 'cg2']); - done(); + if (status.operation !== PubNub.OPERATIONS.PNUnsubscribeOperation) return; + try { + assert.equal(status.error, false); + assert.equal(scope.isDone(), true); + assert.deepEqual(status.affectedChannels, ["ch1", "ch2"]); + assert.deepEqual(status.affectedChannelGroups, ["cg1", "cg2"]); + done(); + } catch (error) { + done(error); + } }, }); diff --git a/test/old_contract/world.ts b/test/old_contract/world.ts index 79a4577c5..e5c311258 100644 --- a/test/old_contract/world.ts +++ b/test/old_contract/world.ts @@ -39,13 +39,13 @@ class PubnubWorld extends World { subscribeKey: 'demo', }, accessManagerKeyset: { - publishKey: process.env.PUBLISH_KEY_ACCESS || 'pub-key', - subscribeKey: process.env.SUBSCRIBE_KEY_ACCESS || 'sub-key', - secretKey: process.env.SECRET_KEY_ACCESS || 'secret-key', + publishKey: process.env.PAM_PUBLISH_KEY || 'pub-key', + subscribeKey: process.env.PAM_SUBSCRIBE_KEY || 'sub-key', + secretKey: process.env.PAM_SECRET_KEY || 'secret-key', }, accessManagerWithoutSecretKeyKeyset: { - publishKey: process.env.PUBLISH_KEY_ACCESS || 'pub-key', - subscribeKey: process.env.SUBSCRIBE_KEY_ACCESS || 'sub-key', + publishKey: process.env.PAM_PUBLISH_KEY || 'pub-key', + subscribeKey: process.env.PAM_SUBSCRIBE_KEY || 'sub-key', }, tokenWithKnownAuthorizedUUID: 'qEF2AkF0GmEI03xDdHRsGDxDcmVzpURjaGFuoWljaGFubmVsLTEY70NncnChb2NoYW5uZWxfZ3JvdXAtMQVDdXNyoENzcGOgRHV1aWShZnV1aWQtMRhoQ3BhdKVEY2hhbqFtXmNoYW5uZWwtXFMqJBjvQ2dycKF0XjpjaGFubmVsX2dyb3VwLVxTKiQFQ3VzcqBDc3BjoER1dWlkoWpedXVpZC1cUyokGGhEbWV0YaBEdXVpZHR0ZXN0LWF1dGhvcml6ZWQtdXVpZENzaWdYIPpU-vCe9rkpYs87YUrFNWkyNq8CVvmKwEjVinnDrJJc', diff --git a/test/release/release.test.js b/test/release/release.test.ts similarity index 100% rename from test/release/release.test.js rename to test/release/release.test.ts diff --git a/test/setup.js b/test/setup.js deleted file mode 100644 index 1ab47da44..000000000 --- a/test/setup.js +++ /dev/null @@ -1,10 +0,0 @@ -const chai = require('chai'); -const chaiAsPromised = require('chai-as-promised'); -const chaiNock = require('chai-nock'); - -chai.use(chaiAsPromised); -chai.use(chaiNock); - -process.env.NODE_ENV = 'test'; - -global.expect = chai.expect; diff --git a/test/setup.ts b/test/setup.ts new file mode 100644 index 000000000..785f3b3d3 --- /dev/null +++ b/test/setup.ts @@ -0,0 +1,8 @@ +import chaiAsPromised from 'chai-as-promised'; +import chaiNock from 'chai-nock'; +import chai from 'chai'; + +chai.use(chaiAsPromised); +chai.use(chaiNock); + +process.env.NODE_ENV = 'test'; diff --git a/test/unit/base64.test.ts b/test/unit/base64.test.ts index e3daf4357..185358e50 100644 --- a/test/unit/base64.test.ts +++ b/test/unit/base64.test.ts @@ -1,8 +1,8 @@ -import { decode } from '../../src/core/components/base64_codec'; - import assert from 'assert'; -function assertBufferEqual(actual, expected) { +import { decode } from '../../src/core/components/base64_codec'; + +function assertBufferEqual(actual: ArrayBuffer, expected: number[]) { assert.deepStrictEqual(new Uint8Array(actual), Uint8Array.from(expected)); } diff --git a/test/unit/cbor.test.js b/test/unit/cbor.test.ts similarity index 84% rename from test/unit/cbor.test.js rename to test/unit/cbor.test.ts index 46eeeb758..67b3cd273 100644 --- a/test/unit/cbor.test.js +++ b/test/unit/cbor.test.ts @@ -1,14 +1,15 @@ /* global describe, it */ -import assert from 'assert'; import CborReader from 'cbor-sync'; +import assert from 'assert'; import Cbor from '../../src/cbor/common'; describe('cbor', () => { it('should decode token', () => { - const cbor = new Cbor(CborReader.decode, (base64String) => new Buffer.from(base64String, 'base64')); - let token = 'p0F2AkF0Gl043rhDdHRsCkNyZXOkRGNoYW6hZnNlY3JldAFDZ3JwoEN1c3KgQ3NwY6BDcGF0pERjaGFuoENncnCgQ3VzcqBDc3BjoERtZXRhoENzaWdYIGOAeTyWGJI-blahPGD9TuKlaW1YQgiB4uR_edmfq-61'; + const cbor = new Cbor(CborReader.decode, (base64String: string) => Buffer.from(base64String, 'base64')); + let token = + 'p0F2AkF0Gl043rhDdHRsCkNyZXOkRGNoYW6hZnNlY3JldAFDZ3JwoEN1c3KgQ3NwY6BDcGF0pERjaGFuoENncnCgQ3VzcqBDc3BjoERtZXRhoENzaWdYIGOAeTyWGJI-blahPGD9TuKlaW1YQgiB4uR_edmfq-61'; let decodedToken = cbor.decodeToken(token); diff --git a/test/unit/common.test.js b/test/unit/common.test.ts similarity index 64% rename from test/unit/common.test.js rename to test/unit/common.test.ts index 901fe5d3a..63bd5f567 100644 --- a/test/unit/common.test.js +++ b/test/unit/common.test.ts @@ -1,37 +1,44 @@ /* global describe, it */ -import assert from 'assert'; import lilUUID from 'lil-uuid'; -import PubNub from '../../src/node/index'; +import assert from 'assert'; + import CryptoJS from '../../src/core/components/cryptography/hmac-sha256'; +import { Payload } from '../../src/core/types/api'; +import PubNub from '../../src/node/index'; describe('#core / mounting point', () => { it('should have default heartbeat interval undefined', () => { - let pn = new PubNub({ uuid: 'myUUID' }); + let pn = new PubNub({ subscribeKey: 'demo', uuid: 'myUUID' }); + // @ts-expect-error Intentional access to the private configuration fields. assert(pn._config.getHeartbeatInterval() === undefined); }); it('should have correct heartbeat interval set when reducing presence timeout', () => { - let pn = new PubNub({ uuid: 'myUUID' }); + let pn = new PubNub({ subscribeKey: 'demo', uuid: 'myUUID' }); let presenceTimeout = 200; let expectedHeartBeat = presenceTimeout / 2 - 1; + + // @ts-expect-error Intentional access to the private configuration fields. pn._config.setPresenceTimeout(presenceTimeout); + // @ts-expect-error Intentional access to the private configuration fields. assert(pn._config.getHeartbeatInterval() === expectedHeartBeat); }); it('should support multiple pnsdk suffix', () => { - let pn = new PubNub({ uuid: 'myUUID' }); + let pn = new PubNub({ subscribeKey: 'demo', uuid: 'myUUID' }); let suffix1 = 'suffix1/0.1'; let suffix2 = 'suffix2/0.2'; pn._addPnsdkSuffix('a', suffix1); pn._addPnsdkSuffix('b', suffix2); + // @ts-expect-error Intentional access to the private configuration fields. assert(pn._config._getPnsdkSuffix(' ') === ' suffix1/0.1 suffix2/0.2'); }); it('should replace duplicate pnsdk suffix by name', () => { - let pn = new PubNub({ uuid: 'myUUID' }); + let pn = new PubNub({ subscribeKey: 'demo', uuid: 'myUUID' }); let suffix1 = 'suffix1/0.1'; let suffix2 = 'suffix2/0.2'; let suffix3 = 'suffix3/0.3'; @@ -40,11 +47,13 @@ describe('#core / mounting point', () => { pn._addPnsdkSuffix('b', suffix2); pn._addPnsdkSuffix('a', suffix3); // duplicate name should replace + // @ts-expect-error Intentional access to the private configuration fields. assert(pn._config._getPnsdkSuffix(' ') === ' suffix3/0.3 suffix2/0.2'); }); it('should default to empty pnsdk suffix', () => { - let pn = new PubNub({ uuid: 'myUUID' }); + let pn = new PubNub({ subscribeKey: 'demo', uuid: 'myUUID' }); + // @ts-expect-error Intentional access to the private configuration fields. assert(pn._config._getPnsdkSuffix(' ') === ''); }); @@ -53,12 +62,21 @@ describe('#core / mounting point', () => { }); it('supports encryption with static IV', () => { - let pn = new PubNub({ cipherKey: 'customKey', useRandomIVs: false, uuid: 'myUUID' }); + let pn = new PubNub({ + subscribeKey: 'demo', + cipherKey: 'customKey', + useRandomIVs: false, + uuid: 'myUUID', + }); assert.equal(pn.encrypt(JSON.stringify({ hi: 'there' })), 'TejX6F2JNqH/gIiGHWN4Cw=='); }); it('supports encryption with random IV', () => { - let pn = new PubNub({ cipherKey: 'customKey', uuid: 'myUUID' }); + let pn = new PubNub({ + subscribeKey: 'demo', + cipherKey: 'customKey', + uuid: 'myUUID', + }); const data1 = pn.encrypt(JSON.stringify({ hi: 'there' })); const data2 = pn.encrypt(JSON.stringify({ hi: 'there' })); @@ -67,12 +85,16 @@ describe('#core / mounting point', () => { }); it('supports encryption with custom key and static IV', () => { - let pn = new PubNub({ useRandomIVs: false, uuid: 'myUUID' }); + let pn = new PubNub({ + subscribeKey: 'demo', + useRandomIVs: false, + uuid: 'myUUID', + }); assert.equal(pn.encrypt(JSON.stringify({ hi: 'there' }), 'customKey'), 'TejX6F2JNqH/gIiGHWN4Cw=='); }); it('supports encryption with custom key and random IV', () => { - let pn = new PubNub({ uuid: 'myUUID' }); + let pn = new PubNub({ subscribeKey: 'demo', uuid: 'myUUID' }); const data1 = pn.encrypt(JSON.stringify({ hi: 'there' }), 'customKey'); const data2 = pn.encrypt(JSON.stringify({ hi: 'there' }), 'customKey'); @@ -81,12 +103,21 @@ describe('#core / mounting point', () => { }); it('supports decryption with static IV', () => { - let pn = new PubNub({ cipherKey: 'customKey', useRandomIVs: false, uuid: 'myUUID' }); + let pn = new PubNub({ + subscribeKey: 'demo', + cipherKey: 'customKey', + useRandomIVs: false, + uuid: 'myUUID', + }); assert.deepEqual(pn.decrypt('TejX6F2JNqH/gIiGHWN4Cw=='), { hi: 'there' }); }); it('supports decryption with random IV', () => { - let pn = new PubNub({ cipherKey: 'customKey', uuid: 'myUUID' }); + let pn = new PubNub({ + subscribeKey: 'demo', + cipherKey: 'customKey', + uuid: 'myUUID', + }); const data = pn.encrypt(JSON.stringify({ hi: 'there2' })); assert.notDeepEqual(pn.decrypt('TejX6F2JNqH/gIiGHWN4Cw=='), { hi: 'there' }); @@ -94,14 +125,18 @@ describe('#core / mounting point', () => { }); it('supports decryption with custom key and static IV', () => { - let pn = new PubNub({ useRandomIVs: false, uuid: 'myUUID' }); + let pn = new PubNub({ + subscribeKey: 'demo', + useRandomIVs: false, + uuid: 'myUUID', + }); assert.deepEqual(pn.decrypt('TejX6F2JNqH/gIiGHWN4Cw==', 'customKey'), { hi: 'there', }); }); it('supports decryption with custom key and random IV', () => { - let pn = new PubNub({ uuid: 'myUUID' }); + let pn = new PubNub({ subscribeKey: 'demo', uuid: 'myUUID' }); const data = pn.encrypt(JSON.stringify({ hi: 'there2' }), 'customKey'); assert.notDeepEqual(pn.decrypt('TejX6F2JNqH/gIiGHWN4Cw==', 'customKey'), { @@ -111,17 +146,25 @@ describe('#core / mounting point', () => { }); it('supports custom encryption/decryption', () => { - let customEncrypt = (data) => { + let customEncrypt = (data: Payload) => { + // @ts-expect-error Bundled library without types. let cipher = CryptoJS.AES.encrypt(JSON.stringify(data), 'customKey'); return cipher.toString(); }; - let customDecrypt = (data) => { + let customDecrypt = (data: Payload) => { + // @ts-expect-error Bundled library without types. let bytes = CryptoJS.AES.decrypt(data, 'customKey'); + // @ts-expect-error Bundled library without types. return JSON.parse(bytes.toString(CryptoJS.enc.Utf8)); }; - let pn = new PubNub({ customEncrypt, customDecrypt, uuid: 'myUUID' }); + let pn = new PubNub({ + subscribeKey: 'demo', + customEncrypt, + customDecrypt, + uuid: 'myUUID', + }); let ciphertext = pn.encrypt({ hi: 'there' }); diff --git a/test/unit/event_engine.test.ts b/test/unit/event_engine.test.ts index b45db4dc6..28dd1edfd 100644 --- a/test/unit/event_engine.test.ts +++ b/test/unit/event_engine.test.ts @@ -1,10 +1,13 @@ import nock from 'nock'; -import utils from '../utils'; + +import { Payload } from '../../src/core/types/api'; import PubNub from '../../src/node/index'; +import utils from '../utils'; describe('EventEngine', () => { - let pubnub: PubNub; + // @ts-expect-error Access event engine core for test purpose. let engine: PubNub['eventEngine']['engine']; + let pubnub: PubNub; before(() => { nock.disableNetConnect(); @@ -14,7 +17,8 @@ describe('EventEngine', () => { nock.enableNetConnect(); }); - let unsub; + let unsub: () => void; + beforeEach(() => { nock.cleanAll(); @@ -25,10 +29,12 @@ describe('EventEngine', () => { enableEventEngine: true, }); - engine = pubnub.eventEngine._engine; + // @ts-expect-error Access event engine core for test purpose. + engine = pubnub.eventEngine!._engine; - unsub = engine.subscribe((change) => { - console.log(change); + unsub = engine.subscribe((_change: Record) => { + // FOR DEBUG + // console.dir(_change); }); }); @@ -38,9 +44,9 @@ describe('EventEngine', () => { function forEvent(eventLabel: string, timeout?: number) { return new Promise((resolve, reject) => { - let timeoutId = null; + let timeoutId: NodeJS.Timeout | null = null; - const unsubscribe = engine.subscribe((change) => { + const unsubscribe = engine.subscribe((change: { type: string; event: { type: string } }) => { if (change.type === 'eventReceived' && change.event.type === eventLabel) { if (timeoutId) clearTimeout(timeoutId); unsubscribe(); @@ -59,9 +65,9 @@ describe('EventEngine', () => { function forState(stateLabel: string, timeout?: number) { return new Promise((resolve, reject) => { - let timeoutId = null; + let timeoutId: NodeJS.Timeout | null = null; - const unsubscribe = engine.subscribe((change) => { + const unsubscribe = engine.subscribe((change: { type: string; toState: { label: string } }) => { if (change.type === 'transitionDone' && change.toState.label === stateLabel) { if (timeoutId) clearTimeout(timeoutId); unsubscribe(); @@ -80,9 +86,9 @@ describe('EventEngine', () => { function forInvocation(invocationLabel: string, timeout?: number) { return new Promise((resolve, reject) => { - let timeoutId = null; + let timeoutId: NodeJS.Timeout | null = null; - const unsubscribe = engine.subscribe((change) => { + const unsubscribe = engine.subscribe((change: { type: string; invocation: { type: string } }) => { if (change.type === 'invocationDispatched' && change.invocation.type === invocationLabel) { if (timeoutId) clearTimeout(timeoutId); unsubscribe(); diff --git a/test/unit/event_engine_presence.test.ts b/test/unit/event_engine_presence.test.ts index 432886e45..5b009eb2f 100644 --- a/test/unit/event_engine_presence.test.ts +++ b/test/unit/event_engine_presence.test.ts @@ -1,10 +1,12 @@ import nock from 'nock'; -import utils from '../utils'; + import PubNub from '../../src/node/index'; +import utils from '../utils'; describe('EventEngine', () => { - let pubnub: PubNub; + // @ts-expect-error Access event engine core for test purpose. let engine: PubNub['presenceEventEngine']['engine']; + let pubnub: PubNub; before(() => { nock.disableNetConnect(); @@ -14,7 +16,8 @@ describe('EventEngine', () => { nock.enableNetConnect(); }); - let unsub; + let unsub: () => void; + beforeEach(() => { nock.cleanAll(); @@ -27,10 +30,12 @@ describe('EventEngine', () => { logVerbosity: true, }); + // @ts-expect-error Access event engine core for test purpose. engine = pubnub.presenceEventEngine._engine; - unsub = engine.subscribe((change) => { - console.log(change); + unsub = engine.subscribe((_change: Record) => { + // FOR DEBUG + // console.dir(change); }); }); @@ -40,9 +45,9 @@ describe('EventEngine', () => { function forEvent(eventLabel: string, timeout?: number) { return new Promise((resolve, reject) => { - let timeoutId = null; + let timeoutId: NodeJS.Timeout | null = null; - const unsubscribe = engine.subscribe((change) => { + const unsubscribe = engine.subscribe((change: { type: string; event: { type: string } }) => { if (change.type === 'eventReceived' && change.event.type === eventLabel) { if (timeoutId) clearTimeout(timeoutId); unsubscribe(); @@ -61,9 +66,9 @@ describe('EventEngine', () => { function forState(stateLabel: string, timeout?: number) { return new Promise((resolve, reject) => { - let timeoutId = null; + let timeoutId: NodeJS.Timeout | null = null; - const unsubscribe = engine.subscribe((change) => { + const unsubscribe = engine.subscribe((change: { type: string; toState: { label: string } }) => { if (change.type === 'transitionDone' && change.toState.label === stateLabel) { if (timeoutId) clearTimeout(timeoutId); unsubscribe(); @@ -82,9 +87,9 @@ describe('EventEngine', () => { function forInvocation(invocationLabel: string, timeout?: number) { return new Promise((resolve, reject) => { - let timeoutId = null; + let timeoutId: NodeJS.Timeout | null = null; - const unsubscribe = engine.subscribe((change) => { + const unsubscribe = engine.subscribe((change: { type: string; invocation: { type: string } }) => { if (change.type === 'invocationDispatched' && change.invocation.type === invocationLabel) { if (timeoutId) clearTimeout(timeoutId); unsubscribe(); @@ -101,13 +106,14 @@ describe('EventEngine', () => { }); } - it(' presence event_engine should work correctly', async () => { + it('presence event_engine should work correctly', async () => { utils .createNock() .get('/v2/presence/sub-key/demo/channel/test/heartbeat') .query(true) - .reply(200, '{"message":"OK", "service":"Presence"}'); + .reply(200, '{"message":"OK", "service":"Presence"}', { 'content-type': 'text/javascript' }); + // @ts-expect-error Intentional access to the private interface. pubnub.join({ channels: ['test'] }); await forEvent('JOINED', 1000); @@ -118,10 +124,9 @@ describe('EventEngine', () => { await forState('HEARTBEAT_COOLDOWN', 1000); + // @ts-expect-error Intentional access to the private interface. pubnub.leaveAll(); await forEvent('LEFT_ALL', 2000); - }); - }); diff --git a/test/unit/listener_manager.test.js b/test/unit/listener_manager.test.ts similarity index 59% rename from test/unit/listener_manager.test.js rename to test/unit/listener_manager.test.ts index 8a86faa1b..bdfd5bb23 100644 --- a/test/unit/listener_manager.test.js +++ b/test/unit/listener_manager.test.ts @@ -1,7 +1,9 @@ /* global describe, it */ import assert from 'assert'; -import ListenerManager from '../../src/core/components/listener_manager'; + +import { Listener, ListenerManager } from '../../src/core/components/listener_manager'; +import PubNub from '../../src/node'; describe('components/ListenerManager', () => { it('supports removal of listeners', () => { @@ -10,18 +12,28 @@ describe('components/ListenerManager', () => { let bool2 = false; let listener1 = { - message() { bool1 = true; } + message() { + bool1 = true; + }, }; let listener2 = { - message() { bool2 = true; } + message() { + bool2 = true; + }, }; listeners.addListener(listener1); listeners.addListener(listener2); listeners.removeListener(listener2); - listeners.announceMessage('hi'); + listeners.announceMessage({ + channel: 'ch', + subscription: 'ch', + message: 'hi', + timetoken: '123', + publisher: 'John', + }); assert(bool1, 'bool1 was triggered'); assert(!bool2, 'bool2 was not triggered'); @@ -34,23 +46,39 @@ describe('components/ListenerManager', () => { let bool3 = false; let listener1 = { - presence() { bool1 = true; } + presence() { + bool1 = true; + }, }; let listener2 = { - presence() { bool2 = true; } + presence() { + bool2 = true; + }, }; let listener3 = { - message() { bool3 = true; }, - status() { bool3 = true; } + message() { + bool3 = true; + }, + status() { + bool3 = true; + }, }; listeners.addListener(listener1); listeners.addListener(listener2); listeners.addListener(listener3); - listeners.announcePresence('hi'); + listeners.announcePresence({ + channel: 'ch', + subscription: 'ch', + action: 'join', + uuid: 'John', + occupancy: 1, + timetoken: '123', + timestamp: 123, + }); assert(bool1, 'bool1 was triggered'); assert(bool2, 'bool2 was triggered'); @@ -64,23 +92,31 @@ describe('components/ListenerManager', () => { let bool3 = false; let listener1 = { - status() { bool1 = true; } + status() { + bool1 = true; + }, }; let listener2 = { - status() { bool2 = true; } + status() { + bool2 = true; + }, }; let listener3 = { - message() { bool3 = true; }, - presence() { bool3 = true; } + message() { + bool3 = true; + }, + presence() { + bool3 = true; + }, }; listeners.addListener(listener1); listeners.addListener(listener2); listeners.addListener(listener3); - listeners.announceStatus('hi'); + listeners.announceStatus({ statusCode: 200, category: PubNub.CATEGORIES.PNConnectedCategory }); assert(bool1, 'bool1 was triggered'); assert(bool2, 'bool2 was triggered'); @@ -94,23 +130,37 @@ describe('components/ListenerManager', () => { let bool3 = false; let listener1 = { - message() { bool1 = true; } + message() { + bool1 = true; + }, }; let listener2 = { - message() { bool2 = true; } + message() { + bool2 = true; + }, }; let listener3 = { - status() { bool3 = true; }, - presence() { bool3 = true; } + status() { + bool3 = true; + }, + presence() { + bool3 = true; + }, }; listeners.addListener(listener1); listeners.addListener(listener2); listeners.addListener(listener3); - listeners.announceMessage('hi'); + listeners.announceMessage({ + channel: 'ch', + subscription: 'ch', + message: 'hi', + timetoken: '123', + publisher: 'John', + }); assert(bool1, 'bool1 was triggered'); assert(bool2, 'bool2 was triggered'); @@ -119,10 +169,10 @@ describe('components/ListenerManager', () => { it('announces network down events', () => { let listeners = new ListenerManager(); - let listener = { + let listener: Listener = { status(status) { - assert.deepEqual(status, { category: 'PNNetworkDownCategory' }); - } + assert.deepEqual(status, { category: PubNub.CATEGORIES.PNNetworkDownCategory }); + }, }; listeners.addListener(listener); @@ -132,10 +182,10 @@ describe('components/ListenerManager', () => { it('announces network up events', () => { let listeners = new ListenerManager(); - let listener = { + let listener: Listener = { status(status) { - assert.deepEqual(status, { category: 'PNNetworkUpCategory' }); - } + assert.deepEqual(status, { category: PubNub.CATEGORIES.PNNetworkUpCategory }); + }, }; listeners.addListener(listener); diff --git a/test/unit/networking.test.js b/test/unit/networking.test.js deleted file mode 100644 index 1ab2654f6..000000000 --- a/test/unit/networking.test.js +++ /dev/null @@ -1,136 +0,0 @@ -/* global describe, it, before, after */ - -import superagent from 'superagent'; -import sinon from 'sinon'; -import nock from 'nock'; -import assert from 'assert'; - -import Config from '../../src/core/components/config'; -import Networking from '../../src/networking'; -import { del, get, post } from '../../src/networking/modules/web-node'; -import { keepAlive, proxy } from '../../src/networking/modules/node'; - -describe('multiple origins', () => { - before(() => nock.disableNetConnect()); - after(() => nock.enableNetConnect()); - - it('should use a random origin from a supplied array of origins', () => { - const origins = ['test1.example.com', 'test2.example.com']; - const config = new Config({ setup: { ssl: true, origin: origins, uuid: 'myUUID' } }) - const networking = new Networking({}); - networking.init(config); - - const origin = networking.getStandardOrigin(); - - assert(origins.some((e) => `https://${e}` === origin), `Supplied origins do not contain "${origin}"`); - }); - - it('should use string origin if a string is supplied', () => { - const config = new Config({ setup: { ssl: true, origin: 'example.com', uuid: 'myUUID' } }) - const networking = new Networking({}); - networking.init(config); - - const origin = networking.getStandardOrigin(); - - assert.equal(origin, 'https://example.com'); - }); - - describe('shiftStandardOrigin', () => { - it('should use all origins if array is supplied', () => { - const origins = ['test1.example.com', 'test2.example.com']; - const config = new Config({ setup: { ssl: true, origin: origins, uuid: 'myUUID' } }) - const networking = new Networking({}); - networking.init(config); - - const firstOrigin = networking.getStandardOrigin(); - const secondOrigin = networking.shiftStandardOrigin(); - const thirdOrigin = networking.shiftStandardOrigin(); - - assert.equal(firstOrigin, thirdOrigin); - assert.notEqual(firstOrigin, secondOrigin); - }); - - it('should do nothing if string is supplied', () => { - const config = new Config({ setup: { ssl: true, origin: 'example.com', uuid: 'myUUID' } }) - const networking = new Networking({}); - networking.init(config); - - const firstOrigin = networking.getStandardOrigin(); - const secondOrigin = networking.shiftStandardOrigin(); - const thirdOrigin = networking.shiftStandardOrigin(); - - assert.equal(firstOrigin, secondOrigin); - assert.equal(secondOrigin, thirdOrigin); - assert.equal(thirdOrigin, firstOrigin); - }); - }); -}); - -describe('keep-alive agent', () => { - before(() => nock.disableNetConnect()); - after(() => nock.enableNetConnect()); - - const setupNetwork = (shouldSecure, enableKeepAlive) => { - const config = new Config({ setup: { origin: 'ps.pndsn.com', ssl: shouldSecure, keepAlive: enableKeepAlive, logVerbosity: false, uuid: 'myUUID' } }); - const networking = new Networking({ keepAlive, del, get, post, proxy }); - networking.init(config); - - return networking; - }; - - it('should not create if \'keepAlive\' is \'false\'', () => { - const networking = setupNetwork(false, false); - const superagentGetSpy = sinon.spy(superagent, 'get'); - - networking.GET({}, { url: '/time/0', headers: {} }, () => {}); - assert(superagentGetSpy.called, 'superagent not called with get'); - assert(superagentGetSpy.returnValues[0], 'request instance not created'); - assert(!superagentGetSpy.returnValues[0]._agent, 'keep-alive agent should not be created'); - - superagentGetSpy.restore(); - }); - - it('should create agent for insecure connection', () => { - const networking = setupNetwork(false, true); - const superagentGetSpy = sinon.spy(superagent, 'get'); - - networking.GET({}, { url: '/time/0', headers: {} }, () => {}); - assert(superagentGetSpy.returnValues[0]._agent, 'keep-alive agent not created'); - assert(superagentGetSpy.returnValues[0]._agent.defaultPort !== 443, 'keep-alive agent should access TLS (80) port'); - - superagentGetSpy.restore(); - }); - - it('should re-use created agent for insecure connection', () => { - const networking = setupNetwork(false, true); - const superagentGetSpy = sinon.spy(superagent, 'get'); - - networking.GET({}, { url: '/time/0', headers: {} }, () => {}); - networking.GET({}, { url: '/time/0', headers: {} }, () => {}); - assert(superagentGetSpy.returnValues[0]._agent === superagentGetSpy.returnValues[1]._agent, 'same user-agent should be used'); - - superagentGetSpy.restore(); - }); - - it('should create agent for secure connection', () => { - const networking = setupNetwork(true, true); - const superagentGetSpy = sinon.spy(superagent, 'get'); - - networking.GET({}, { url: '/time/0', headers: {} }, () => {}); - assert(superagentGetSpy.returnValues[0]._agent, 'keep-alive agent not created'); - assert(superagentGetSpy.returnValues[0]._agent.defaultPort === 443, 'keep-alive agent should access SSL (443) port'); - - superagentGetSpy.restore(); - }); - - it('should re-use created agent for secure connection', () => { - const networking = setupNetwork(true, true); - const superagentGetSpy = sinon.spy(superagent, 'get'); - - networking.GET({}, { url: '/time/0', headers: {} }, () => {}); - networking.GET({}, { url: '/time/0', headers: {} }, () => {}); - assert(superagentGetSpy.returnValues[0]._agent === superagentGetSpy.returnValues[1]._agent, 'same user-agent should be used'); - - superagentGetSpy.restore(); - }); -}); diff --git a/test/unit/networking.test.ts b/test/unit/networking.test.ts new file mode 100644 index 000000000..fad8a0ac0 --- /dev/null +++ b/test/unit/networking.test.ts @@ -0,0 +1,37 @@ +/* global describe, it, before, after */ + +import assert from 'assert'; +import nock from 'nock'; + +import { makeConfiguration } from '../../src/core/components/configuration'; +import { setDefaults } from '../../src/core/interfaces/configuration'; + +describe('multiple origins', () => { + before(() => nock.disableNetConnect()); + after(() => nock.enableNetConnect()); + + it('should use a random origin from a supplied array of origins', () => { + const origins = ['test1.example.com', 'test2.example.com']; + + const configuration = makeConfiguration({ + ...setDefaults({ subscribeKey: 'demo', ssl: true, origin: origins, uuid: 'myUUID' }), + sdkFamily: 'test', + }); + + assert( + origins.some((e) => `https://${e}` === configuration.origin), + `Supplied origins do not contain "${configuration.origin}"`, + ); + }); + + it('should use string origin if a string is supplied', () => { + const configuration = makeConfiguration({ + ...setDefaults({ subscribeKey: 'demo', ssl: true, origin: 'example.com', uuid: 'myUUID' }), + sdkFamily: 'test', + }); + + assert.equal(configuration.origin, 'https://example.com'); + }); + + // `shiftStandardOrigin` removed because originally `origin` picked only during PubNub client instance creation. +}); diff --git a/test/unit/notifications_payload.test.js b/test/unit/notifications_payload.test.ts similarity index 62% rename from test/unit/notifications_payload.test.js rename to test/unit/notifications_payload.test.ts index e9e86c795..a1f164e13 100644 --- a/test/unit/notifications_payload.test.js +++ b/test/unit/notifications_payload.test.ts @@ -1,8 +1,9 @@ /* global describe, beforeEach, it */ import assert from 'assert'; + +import { APNSNotificationPayload, FCMNotificationPayload } from '../../src/core/components/push_payload'; import PubNub from '../../src/node/index'; -import { APNSNotificationPayload, MPNSNotificationPayload, FCMNotificationPayload } from '../../src/core/components/push_payload'; describe('#notifications helper', () => { describe('payloads builder', () => { @@ -13,7 +14,6 @@ describe('#notifications helper', () => { let builder = PubNub.notificationPayload(expectedTitle, expectedBody); assert(builder.apns); - assert(builder.mpns); assert(builder.fcm); }); @@ -21,25 +21,34 @@ describe('#notifications helper', () => { let expectedTitle = PubNub.generateUUID(); let expectedBody = PubNub.generateUUID(); - let builder = PubNub.notificationPayload(expectedTitle, expectedBody); + const builder = PubNub.notificationPayload(expectedTitle, expectedBody); + const apnsPayload = builder.apns.toObject(); + const fcmPayload = builder.fcm.toObject(); - assert.equal(builder.apns.toObject().aps.alert.title, expectedTitle); - assert.equal(builder.apns.toObject().aps.alert.body, expectedBody); - assert.equal(builder.mpns.toObject().title, expectedTitle); - assert.equal(builder.mpns.toObject().back_content, expectedBody); - assert.equal(builder.fcm.toObject().notification.title, expectedTitle); - assert.equal(builder.fcm.toObject().notification.body, expectedBody); + assert(apnsPayload); + assert(apnsPayload.aps.alert); + assert.equal(apnsPayload.aps.alert.title, expectedTitle); + assert.equal(apnsPayload.aps.alert.body, expectedBody); + assert(fcmPayload); + assert(fcmPayload.notification); + assert.equal(fcmPayload.notification.title, expectedTitle); + assert.equal(fcmPayload.notification.body, expectedBody); }); it('should pass subtitle to builders', () => { let expectedSubtitle = PubNub.generateUUID(); - let builder = PubNub.notificationPayload(PubNub.generateUUID(), PubNub.generateUUID()); + const builder = PubNub.notificationPayload(PubNub.generateUUID(), PubNub.generateUUID()); builder.subtitle = expectedSubtitle; + const apnsPayload = builder.apns.toObject(); + const fcmPayload = builder.fcm.toObject(); - assert.equal(builder.apns.toObject().aps.alert.subtitle, expectedSubtitle); - assert.equal(builder.mpns.toObject().back_title, expectedSubtitle); - assert.equal(Object.keys(builder.fcm.notification).length, 2); + assert(apnsPayload); + assert(apnsPayload.aps.alert); + assert.equal(apnsPayload.aps.alert.subtitle, expectedSubtitle); + assert(fcmPayload); + assert(fcmPayload.notification); + assert.equal(Object.keys(fcmPayload.notification).length, 2); }); it('should pass badge to builders', () => { @@ -47,10 +56,14 @@ describe('#notifications helper', () => { let builder = PubNub.notificationPayload(PubNub.generateUUID(), PubNub.generateUUID()); builder.badge = expectedBadge; + const apnsPayload = builder.apns.toObject(); + const fcmPayload = builder.fcm.toObject(); - assert.equal(builder.apns.toObject().aps.badge, expectedBadge); - assert.equal(builder.mpns.toObject().count, expectedBadge); - assert.equal(Object.keys(builder.fcm.notification).length, 2); + assert(apnsPayload); + assert.equal(apnsPayload.aps.badge, expectedBadge); + assert(fcmPayload); + assert(fcmPayload.notification); + assert.equal(Object.keys(fcmPayload.notification).length, 2); }); it('should pass sound to builders', () => { @@ -58,10 +71,14 @@ describe('#notifications helper', () => { let builder = PubNub.notificationPayload(PubNub.generateUUID(), PubNub.generateUUID()); builder.sound = expectedSound; + const apnsPayload = builder.apns.toObject(); + const fcmPayload = builder.fcm.toObject(); - assert.equal(builder.apns.toObject().aps.sound, expectedSound); - assert.equal(Object.keys(builder.mpns.payload).length, 2); - assert.equal(builder.fcm.toObject().notification.sound, expectedSound); + assert(apnsPayload); + assert.equal(apnsPayload.aps.sound, expectedSound); + assert(fcmPayload); + assert(fcmPayload.notification); + assert.equal(fcmPayload.notification.sound, expectedSound); }); it('should set debug flag', () => { @@ -76,11 +93,11 @@ describe('#notifications helper', () => { let expectedBody = PubNub.generateUUID(); let expectedPayload = { pn_apns: { - aps: { alert: { title: expectedTitle, body: expectedBody } } + aps: { alert: { title: expectedTitle, body: expectedBody } }, }, pn_gcm: { - notification: { title: expectedTitle, body: expectedBody } - } + notification: { title: expectedTitle, body: expectedBody }, + }, }; let builder = PubNub.notificationPayload(expectedTitle, expectedBody); @@ -99,13 +116,13 @@ describe('#notifications helper', () => { { auth_method: 'token', targets: [{ environment: 'development', topic: expectedTopic }], - version: 'v2' - } - ] + version: 'v2', + }, + ], }, pn_gcm: { - notification: { title: expectedTitle, body: expectedBody } - } + notification: { title: expectedTitle, body: expectedBody }, + }, }; let builder = PubNub.notificationPayload(expectedTitle, expectedBody); @@ -124,7 +141,7 @@ describe('#notifications helper', () => { }); describe('apns builder', () => { - let platformPayloadStorage; + let platformPayloadStorage: Record; beforeEach(() => { platformPayloadStorage = {}; @@ -140,7 +157,7 @@ describe('#notifications helper', () => { assert.equal(Object.keys(platformPayloadStorage.aps.alert).length, 0); }); - it('should set notification \'title\' and \'body\' with constructor', () => { + it("should set notification 'title' and 'body' with constructor", () => { let expectedTitle = PubNub.generateUUID(); let expectedBody = PubNub.generateUUID(); @@ -151,7 +168,7 @@ describe('#notifications helper', () => { assert.equal(platformPayloadStorage.aps.alert.body, expectedBody); }); - it('should set \'subtitle\'', () => { + it("should set 'subtitle'", () => { let expectedSubtitle = PubNub.generateUUID(); let builder = new APNSNotificationPayload(platformPayloadStorage); @@ -160,7 +177,7 @@ describe('#notifications helper', () => { assert.equal(platformPayloadStorage.aps.alert.subtitle, expectedSubtitle); }); - it('should not set \'subtitle\' if value is empty', () => { + it("should not set 'subtitle' if value is empty", () => { let expectedSubtitle = ''; let builder = new APNSNotificationPayload(platformPayloadStorage); @@ -169,7 +186,7 @@ describe('#notifications helper', () => { assert(!platformPayloadStorage.aps.alert.subtitle); }); - it('should set \'body\'', () => { + it("should set 'body'", () => { let expectedBody = PubNub.generateUUID(); let builder = new APNSNotificationPayload(platformPayloadStorage); @@ -178,7 +195,7 @@ describe('#notifications helper', () => { assert.equal(platformPayloadStorage.aps.alert.body, expectedBody); }); - it('should not set \'body\' if value is empty', () => { + it("should not set 'body' if value is empty", () => { let expectedBody = ''; let builder = new APNSNotificationPayload(platformPayloadStorage); @@ -187,7 +204,7 @@ describe('#notifications helper', () => { assert(!platformPayloadStorage.aps.alert.body); }); - it('should set \'badge\'', () => { + it("should set 'badge'", () => { let expectedBadged = 16; let builder = new APNSNotificationPayload(platformPayloadStorage); @@ -196,14 +213,14 @@ describe('#notifications helper', () => { assert.equal(platformPayloadStorage.aps.badge, expectedBadged); }); - it('should not set \'badge\' if value is empty', () => { + it("should not set 'badge' if value is empty", () => { let builder = new APNSNotificationPayload(platformPayloadStorage); builder.badge = null; assert(!platformPayloadStorage.aps.badge); }); - it('should set \'sound\'', () => { + it("should set 'sound'", () => { let expectedSound = PubNub.generateUUID(); let builder = new APNSNotificationPayload(platformPayloadStorage); @@ -212,7 +229,7 @@ describe('#notifications helper', () => { assert.equal(platformPayloadStorage.aps.sound, expectedSound); }); - it('should not set \'sound\' if value is empty', () => { + it("should not set 'sound' if value is empty", () => { let expectedSound = ''; let builder = new APNSNotificationPayload(platformPayloadStorage); @@ -227,16 +244,18 @@ describe('#notifications helper', () => { assert.equal(builder.toObject(), null); }); - it('should set \'content-available\' when set silenced', () => { + it("should set 'content-available' when set silenced", () => { let builder = new APNSNotificationPayload(platformPayloadStorage, PubNub.generateUUID(), PubNub.generateUUID()); builder.sound = PubNub.generateUUID(); builder.badge = 20; builder.silent = true; + const payload = builder.toObject(); - assert.equal(builder.toObject().aps['content-available'], 1); - assert(!builder.toObject().aps.badge); - assert(!builder.toObject().aps.sound); - assert(!builder.toObject().aps.alert); + assert(payload); + assert.equal(payload.aps['content-available'], 1); + assert(!payload.aps.badge); + assert(!payload.aps.sound); + assert(!payload.aps.alert); }); it('should return valid payload object', () => { @@ -249,8 +268,8 @@ describe('#notifications helper', () => { aps: { alert: { title: expectedTitle, subtitle: expectedSubtitle, body: expectedBody }, badge: expectedBadge, - sound: expectedSound - } + sound: expectedSound, + }, }; let builder = new APNSNotificationPayload(platformPayloadStorage, expectedTitle, expectedBody); @@ -272,20 +291,21 @@ describe('#notifications helper', () => { aps: { alert: { title: expectedTitle, subtitle: expectedSubtitle, body: expectedBody }, badge: expectedBadge, - sound: expectedSound + sound: expectedSound, }, pn_push: [ { auth_method: 'token', targets: [{ environment: 'development', topic: expectedTopic }], - version: 'v2' - } - ] + version: 'v2', + }, + ], }; let builder = new APNSNotificationPayload(platformPayloadStorage, expectedTitle, expectedBody); builder.configurations = [{ targets: [{ topic: expectedTopic }] }]; builder.subtitle = expectedSubtitle; + // @ts-expect-error Intentional manual private field override. builder._apnsPushType = 'apns2'; builder.badge = expectedBadge; builder.sound = expectedSound; @@ -294,133 +314,8 @@ describe('#notifications helper', () => { }); }); - describe('mpns builder', () => { - let platformPayloadStorage; - - beforeEach(() => { - platformPayloadStorage = {}; - }); - - it('should set notification \'title\' and \'body\' with constructor', () => { - let expectedTitle = PubNub.generateUUID(); - let expectedBody = PubNub.generateUUID(); - - let builder = new MPNSNotificationPayload(platformPayloadStorage, expectedTitle, expectedBody); - - assert(builder); - assert.equal(platformPayloadStorage.title, expectedTitle); - assert.equal(platformPayloadStorage.back_content, expectedBody); - }); - - it('should set \'back_title\' when \'subtitle\' passed', () => { - let expectedSubtitle = PubNub.generateUUID(); - - let builder = new MPNSNotificationPayload(platformPayloadStorage); - builder.subtitle = expectedSubtitle; - - assert.equal(platformPayloadStorage.back_title, expectedSubtitle); - }); - - it('should set \'back_title\'', () => { - let expectedBackTitle = PubNub.generateUUID(); - - let builder = new MPNSNotificationPayload(platformPayloadStorage); - builder.backTitle = expectedBackTitle; - - assert.equal(platformPayloadStorage.back_title, expectedBackTitle); - }); - - it('should not set \'back_title\' if value is empty', () => { - let expectedBackTitle = ''; - - let builder = new MPNSNotificationPayload(platformPayloadStorage); - builder.backTitle = expectedBackTitle; - - assert(!platformPayloadStorage.back_title); - }); - - it('should set \'back_content\' when \'body\' passed', () => { - let expectedBody = PubNub.generateUUID(); - - let builder = new MPNSNotificationPayload(platformPayloadStorage); - builder.body = expectedBody; - - assert.equal(platformPayloadStorage.back_content, expectedBody); - }); - - it('should set \'back_content\' ', () => { - let expectedBackContent = PubNub.generateUUID(); - - let builder = new MPNSNotificationPayload(platformPayloadStorage); - builder.backContent = expectedBackContent; - - assert.equal(platformPayloadStorage.back_content, expectedBackContent); - }); - - it('should not set \'back_content\' if value is empty', () => { - let expectedBackContent = ''; - - let builder = new MPNSNotificationPayload(platformPayloadStorage); - builder.backContent = expectedBackContent; - - assert(!platformPayloadStorage.back_content); - }); - - it('should set \'count\' when \'badge\' passed', () => { - let expectedBadge = 26; - - let builder = new MPNSNotificationPayload(platformPayloadStorage); - builder.badge = expectedBadge; - - assert.equal(platformPayloadStorage.count, expectedBadge); - }); - - it('should set \'count\' ', () => { - let expectedCount = 26; - - let builder = new MPNSNotificationPayload(platformPayloadStorage); - builder.count = expectedCount; - - assert.equal(platformPayloadStorage.count, expectedCount); - }); - - it('should not set \'count\' if value is empty', () => { - let builder = new MPNSNotificationPayload(platformPayloadStorage); - builder.count = null; - - assert(!platformPayloadStorage.count); - }); - - it('should return null when no data provided', () => { - let builder = new MPNSNotificationPayload(platformPayloadStorage); - - assert.equal(builder.toObject(), null); - }); - - it('should return valid payload object', () => { - let expectedSubtitle = PubNub.generateUUID(); - let expectedTitle = PubNub.generateUUID(); - let expectedBody = PubNub.generateUUID(); - let expectedCount = 26; - let expectedPayload = { - type: 'flip', - title: expectedTitle, - back_title: expectedSubtitle, - back_content: expectedBody, - count: expectedCount - }; - - let builder = new MPNSNotificationPayload(platformPayloadStorage, expectedTitle, expectedBody); - builder.subtitle = expectedSubtitle; - builder.count = expectedCount; - builder.type = 'flip'; - - assert.deepEqual(builder.toObject(), expectedPayload); - }); - }); - describe('fcm builder', () => { - let platformPayloadStorage; + let platformPayloadStorage: Record; beforeEach(() => { platformPayloadStorage = {}; @@ -434,7 +329,7 @@ describe('#notifications helper', () => { assert(platformPayloadStorage.data); }); - it('should set notification \'title\' and \'body\' with constructor', () => { + it("should set notification 'title' and 'body' with constructor", () => { let expectedTitle = PubNub.generateUUID(); let expectedBody = PubNub.generateUUID(); @@ -445,7 +340,7 @@ describe('#notifications helper', () => { assert.equal(platformPayloadStorage.notification.body, expectedBody); }); - it('should not set \'subtitle\' because it is not supported', () => { + it("should not set 'subtitle' because it is not supported", () => { let expectedSubtitle = PubNub.generateUUID(); let builder = new FCMNotificationPayload(platformPayloadStorage); @@ -454,7 +349,7 @@ describe('#notifications helper', () => { assert.equal(Object.keys(platformPayloadStorage.notification).length, 0); }); - it('should set \'body\'', () => { + it("should set 'body'", () => { let expectedBody = PubNub.generateUUID(); let builder = new FCMNotificationPayload(platformPayloadStorage); @@ -463,7 +358,7 @@ describe('#notifications helper', () => { assert.equal(platformPayloadStorage.notification.body, expectedBody); }); - it('should not set \'body\' if value is empty', () => { + it("should not set 'body' if value is empty", () => { let expectedBody = ''; let builder = new FCMNotificationPayload(platformPayloadStorage); @@ -472,14 +367,14 @@ describe('#notifications helper', () => { assert(!platformPayloadStorage.notification.body); }); - it('should not set \'badge\' because it is not supported', () => { + it("should not set 'badge' because it is not supported", () => { let builder = new FCMNotificationPayload(platformPayloadStorage); builder.badge = 30; assert.equal(Object.keys(platformPayloadStorage.notification).length, 0); }); - it('should set \'sound\'', () => { + it("should set 'sound'", () => { let expectedSound = PubNub.generateUUID(); let builder = new FCMNotificationPayload(platformPayloadStorage); @@ -488,7 +383,7 @@ describe('#notifications helper', () => { assert.equal(platformPayloadStorage.notification.sound, expectedSound); }); - it('should not set \'sound\' if value is empty', () => { + it("should not set 'sound' if value is empty", () => { let expectedSound = ''; let builder = new FCMNotificationPayload(platformPayloadStorage); @@ -497,7 +392,7 @@ describe('#notifications helper', () => { assert(!platformPayloadStorage.notification.sound); }); - it('should set \'icon\'', () => { + it("should set 'icon'", () => { let expectedIcon = PubNub.generateUUID(); let builder = new FCMNotificationPayload(platformPayloadStorage); @@ -506,7 +401,7 @@ describe('#notifications helper', () => { assert.equal(platformPayloadStorage.notification.icon, expectedIcon); }); - it('should not set \'icon\' if value is empty', () => { + it("should not set 'icon' if value is empty", () => { let expectedIcon = ''; let builder = new FCMNotificationPayload(platformPayloadStorage); @@ -515,7 +410,7 @@ describe('#notifications helper', () => { assert(!platformPayloadStorage.notification.icon); }); - it('should set \'tag\'', () => { + it("should set 'tag'", () => { let expectedTag = PubNub.generateUUID(); let builder = new FCMNotificationPayload(platformPayloadStorage); @@ -524,7 +419,7 @@ describe('#notifications helper', () => { assert.equal(platformPayloadStorage.notification.tag, expectedTag); }); - it('should not set \'tag\' if value is empty', () => { + it("should not set 'tag' if value is empty", () => { let expectedTag = ''; let builder = new FCMNotificationPayload(platformPayloadStorage); @@ -539,22 +434,25 @@ describe('#notifications helper', () => { assert.equal(builder.toObject(), null); }); - it('should move \'notification\' under \'data\' when set silenced', () => { + it("should move 'notification' under 'data' when set silenced", () => { let expectedTitle = PubNub.generateUUID(); let expectedBody = PubNub.generateUUID(); let expectedSound = PubNub.generateUUID(); let expectedNotification = { title: expectedTitle, body: expectedBody, - sound: expectedSound + sound: expectedSound, }; let builder = new FCMNotificationPayload(platformPayloadStorage, expectedTitle, expectedBody); builder.sound = expectedSound; builder.silent = true; + const payload = builder.toObject(); - assert(!builder.toObject().notification); - assert.deepEqual(builder.toObject().data.notification, expectedNotification); + assert(payload); + assert(!payload.notification); + assert(payload.data); + assert.deepEqual(payload.data.notification, expectedNotification); }); it('should return valid payload object', () => { @@ -565,8 +463,8 @@ describe('#notifications helper', () => { notification: { title: expectedTitle, body: expectedBody, - sound: expectedSound - } + sound: expectedSound, + }, }; let builder = new FCMNotificationPayload(platformPayloadStorage, expectedTitle, expectedBody); diff --git a/test/utils.js b/test/utils.js deleted file mode 100644 index a6bf5e8f8..000000000 --- a/test/utils.js +++ /dev/null @@ -1,47 +0,0 @@ -/** */ - -import assert from 'assert'; -import nock from 'nock'; - -export default { - createNock() { - return nock('http://ps.pndsn.com:80', { - filteringScope: () => true, - }); - }, - runAPIWithResponseDelays(scope, statusCode, responseBody, delays, apiCall) { - let lastRequest = null; - - const callAPIWithDelayedResponse = (previousDelay, delay) => - new Promise((resolve) => { - const scopeWithDelay = scope.delay(-previousDelay).delay(delay).reply(statusCode, responseBody); - scopeWithDelay.once('request', (request) => { - lastRequest = request; - }); - - apiCall(() => { - scopeWithDelay.done(); - resolve(); - }); - }); - - let promisesResult = Promise.resolve(); - for (let delayIdx = 0; delayIdx < delays.length; delayIdx += 1) { - let previousDelay = delayIdx > 0 ? delays[delayIdx - 1] : 0; - let delay = delays[delayIdx]; - promisesResult = promisesResult.then(() => callAPIWithDelayedResponse(previousDelay, delay)); - } - - return promisesResult.then(() => lastRequest); - }, - verifyRequestTelemetry(requestPath, latencyKey, expectedLatency, leeway) { - const re = new RegExp(`${latencyKey}=(\\d+)`, 'i'); - const latencyString = (re.exec(requestPath) ?? [])[1]; - const latency = latencyString ? parseInt(latencyString, 10) : 0; - - assert( - latency >= expectedLatency && latency <= expectedLatency + leeway, - `Latency is outside of expected bounds: ${expectedLatency} <= ${latency} <= ${expectedLatency + leeway}`, - ); - }, -}; diff --git a/test/utils.ts b/test/utils.ts new file mode 100644 index 000000000..cce634f9f --- /dev/null +++ b/test/utils.ts @@ -0,0 +1,67 @@ +/** */ + +import nock, { Interceptor } from 'nock'; + +import chaiAsPromised from 'chai-as-promised'; +import chaiNock from 'chai-nock'; +import chai from 'chai'; + +import { Query } from '../src/core/types/api'; + +chai.use(chaiAsPromised); +chai.use(chaiNock); + +process.env.NODE_ENV = 'test'; + +export default { + createNock() { + return nock('https://ps.pndsn.com', { + filteringScope: (scope) => /ps\d*\.pndsn\.com/.test(scope), + // allowUnmocked: true, + }); + }, + runAPIWithResponseDelays( + scope: Interceptor, + statusCode: number, + responseBody: string, + delays: number[], + apiCall: (completion: () => void) => void, + ) { + let lastRequest: null = null; + + const callAPIWithDelayedResponse = (previousDelay: number, delay: number) => + new Promise((resolve) => { + const scopeWithDelay = scope + .delay(-previousDelay) + .delay(delay) + .reply(statusCode, responseBody, { 'content-type': 'text/javascript' }); + scopeWithDelay.once('request', (request) => { + lastRequest = request; + }); + + apiCall(() => { + scopeWithDelay.done(); + resolve(undefined); + }); + }); + + let promisesResult = Promise.resolve(); + for (let delayIdx = 0; delayIdx < delays.length; delayIdx += 1) { + let previousDelay = delayIdx > 0 ? delays[delayIdx - 1] : 0; + let delay = delays[delayIdx]; + promisesResult = promisesResult.then(() => callAPIWithDelayedResponse(previousDelay, delay)) as Promise; + } + + return promisesResult.then(() => lastRequest); + }, + matchQuery(actualQuery: Query, targetQuery: Query, excludeRequestId: boolean = true): boolean { + const actualKeys = Object.keys(actualQuery).filter((key) => key !== 'requestid' || !excludeRequestId); + const targetKeys = Object.keys(targetQuery); + + if (actualKeys.length !== targetKeys.length) return false; + + for (const key of targetKeys) if (actualQuery[key] !== targetQuery[key]) return false; + + return true; + }, +}; diff --git a/tsconfig.json b/tsconfig.json index 2103f09c5..f0fdf721e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,20 +1,29 @@ { "$schema": "https://json.schemastore.org/tsconfig", "compilerOptions": { - "target": "ES5", + "target": "ES6", "module": "CommonJS", "moduleResolution": "Node", - "esModuleInterop": true, "allowJs": true, "noEmitOnError": true, "strict": true, + "esModuleInterop": true, "outDir": "./lib", - "downlevelIteration": true + "downlevelIteration": true, + "removeComments": true }, "include": [ "src/**/*" ], "exclude": [ - "node_modules" + "node_modules", + "src/crypto/modules/WebCryptoModule/**/*", + "src/crypto/modules/web.ts", + "src/file/modules/web.ts", + "src/nativescript/**/*", + "src/titanium/**/*", + "src/transport/service-worker/**/*", + "src/transport/titanium-transport.ts", + "src/web/**/*" ] } \ No newline at end of file diff --git a/tsconfig.mocha.json b/tsconfig.mocha.json index 6e2fde3c2..4d9b5b750 100644 --- a/tsconfig.mocha.json +++ b/tsconfig.mocha.json @@ -1,13 +1,11 @@ { + "extends": "./tsconfig.json", "compilerOptions": { - "target": "ES5", - "module": "commonjs", - "moduleResolution": "Node", - "allowJs": true, - "noEmitOnError": true, + "module": "CommonJS", + "esModuleInterop": true, + "noImplicitAny": false, + "noEmit": true, "strict": true, - "esModuleInterop": true }, - "include": ["src/**/*"], - "exclude": ["node_modules"] + "include": ["test/**/*"] } diff --git a/tsconfig.rollup.json b/tsconfig.rollup.json index b72d08c52..e317fb87b 100644 --- a/tsconfig.rollup.json +++ b/tsconfig.rollup.json @@ -1,14 +1,30 @@ { "compilerOptions": { - "target": "ES5", - "module": "ESNext", + "target": "ES6", + "module": "ES6", "moduleResolution": "Node", - "allowJs": true, "noEmitOnError": true, "strict": true, - "outDir": "./lib" + "esModuleInterop": true, + "outDir": "./lib", + "lib": [ + "es6", + "webworker", + "dom" + ] }, "include": ["src/**/*"], - "exclude": ["node_modules", "src/node/**/*"] + "exclude": [ + "node_modules", + "test", + "src/file/modules/node.ts", + "src/file/modules/react-native.ts", + "src/node/**/*", + "src/react_native/**/*", + "src/nativescript/**/*", + "src/titanium/**/*", + "src/transport/node-transport.ts", + "src/transport/titanium-transport.ts" + ] }