diff options
| author | Oskar Nyberg <oskar@mullvad.net> | 2021-04-14 13:48:56 +0200 |
|---|---|---|
| committer | Oskar Nyberg <oskar@mullvad.net> | 2021-04-14 13:48:56 +0200 |
| commit | 130f56e4b4530d096403250f675ec42031ca64f2 (patch) | |
| tree | a696588a0712414bfd8605d4c39c6367600046f2 | |
| parent | 937a8a3ea26dddb761e85e74228069f6f1b6a591 (diff) | |
| parent | 1f3b51141b7da5cb2c38618708f606326413f5de (diff) | |
| download | mullvadvpn-130f56e4b4530d096403250f675ec42031ca64f2.tar.xz mullvadvpn-130f56e4b4530d096403250f675ec42031ca64f2.zip | |
Merge branch 'remove-moment-js'
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | gui/locales/messages.pot | 124 | ||||
| -rw-r--r-- | gui/package-lock.json | 769 | ||||
| -rw-r--r-- | gui/package.json | 7 | ||||
| -rw-r--r-- | gui/src/main/account-data-cache.ts | 11 | ||||
| -rw-r--r-- | gui/src/main/index.ts | 3 | ||||
| -rw-r--r-- | gui/src/renderer/components/Settings.tsx | 3 | ||||
| -rw-r--r-- | gui/src/renderer/components/WireguardKeys.tsx | 16 | ||||
| -rw-r--r-- | gui/src/renderer/containers/SettingsPage.tsx | 1 | ||||
| -rw-r--r-- | gui/src/renderer/containers/WireguardKeysPage.tsx | 1 | ||||
| -rw-r--r-- | gui/src/shared/account-expiry.ts | 53 | ||||
| -rw-r--r-- | gui/src/shared/date-helper.ts | 121 | ||||
| -rw-r--r-- | gui/src/shared/logging.ts | 17 | ||||
| -rw-r--r-- | gui/src/shared/notifications/close-to-account-expiry.ts | 16 | ||||
| -rw-r--r-- | gui/test/date-helper.spec.ts | 152 |
15 files changed, 668 insertions, 627 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 64bbc5ff0c..d7b5c11ae0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ Line wrap the file at 100 chars. Th ### Fixed - Fix relay selection failing to pick a WireGuard relay when no tunnel protocol is specified. +- Fix time left not always being translated in desktop app settings. #### Windows - Prevent tray icons from being extraced to `%TEMP%` directory. diff --git a/gui/locales/messages.pot b/gui/locales/messages.pot index 088dfe0550..6cfb89cabf 100644 --- a/gui/locales/messages.pot +++ b/gui/locales/messages.pot @@ -2,6 +2,61 @@ msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" +msgid "1 day" +msgid_plural "%d days" +msgstr[0] "" +msgstr[1] "" + +msgid "1 day left" +msgid_plural "%d days left" +msgstr[0] "" +msgstr[1] "" + +msgid "1 month" +msgid_plural "%d months" +msgstr[0] "" +msgstr[1] "" + +msgid "1 month left" +msgid_plural "%d months left" +msgstr[0] "" +msgstr[1] "" + +msgid "1 year" +msgid_plural "%d years" +msgstr[0] "" +msgstr[1] "" + +msgid "1 year left" +msgid_plural "%d years left" +msgstr[0] "" +msgstr[1] "" + +msgid "a day ago" +msgid_plural "%d days ago" +msgstr[0] "" +msgstr[1] "" + +msgid "a minute ago" +msgid_plural "%d minutes ago" +msgstr[0] "" +msgstr[1] "" + +msgid "a month ago" +msgid_plural "%d months ago" +msgstr[0] "" +msgstr[1] "" + +msgid "a year ago" +msgid_plural "%d years ago" +msgstr[0] "" +msgstr[1] "" + +msgid "an hour ago" +msgid_plural "%d hours ago" +msgstr[0] "" +msgstr[1] "" + msgid "Back" msgstr "" @@ -41,6 +96,15 @@ msgstr "" msgid "Invalid account number" msgstr "" +msgid "less than a day" +msgstr "" + +msgid "less than a day left" +msgstr "" + +msgid "less than a minute ago" +msgstr "" + msgid "Open URL" msgstr "" @@ -92,20 +156,6 @@ msgctxt "accessibility" msgid "Select location. Current location is %(location)s" msgstr "" -#. The remaining time left on the account measured in days. -#. Available placeholders: -#. %(duration)s - The remaining time measured in days. -msgctxt "account-expiry" -msgid "%(duration)s days" -msgstr "" - -#. The remaining time left on the account displayed across the app. -#. Available placeholders: -#. %(duration)s - a localized remaining time (in minutes, hours, or days) until the account expiry -msgctxt "account-expiry" -msgid "%(duration)s left" -msgstr "" - #. Title label in navigation bar msgctxt "account-view" msgid "Account" @@ -1175,27 +1225,6 @@ msgstr "" msgid "You may need to go back to the app's main screen and click Disconnect before trying again. Don't worry, the information you entered will remain in the form." msgstr "" -msgid "less than a day left" -msgstr "" - -msgid "less than a minute ago" -msgstr "" - -msgid "1 day left" -msgid_plural "%d days left" -msgstr[0] "" -msgstr[1] "" - -msgid "1 month left" -msgid_plural "%d months left" -msgstr[0] "" -msgstr[1] "" - -msgid "1 year left" -msgid_plural "%d years left" -msgstr[0] "" -msgstr[1] "" - msgid "Account credit expires in a day" msgid_plural "Account credit expires in %d days" msgstr[0] "" @@ -1205,28 +1234,3 @@ msgid "Account credit expires in an hour" msgid_plural "Account credit expires in %d hours" msgstr[0] "" msgstr[1] "" - -msgid "a day ago" -msgid_plural "%d days ago" -msgstr[0] "" -msgstr[1] "" - -msgid "a minute ago" -msgid_plural "%d minutes ago" -msgstr[0] "" -msgstr[1] "" - -msgid "a month ago" -msgid_plural "%d months ago" -msgstr[0] "" -msgstr[1] "" - -msgid "a year ago" -msgid_plural "%d years ago" -msgstr[0] "" -msgstr[1] "" - -msgid "an hour ago" -msgid_plural "%d hours ago" -msgstr[0] "" -msgstr[1] "" diff --git a/gui/package-lock.json b/gui/package-lock.json index e44373c850..9db878e062 100644 --- a/gui/package-lock.json +++ b/gui/package-lock.json @@ -15,7 +15,6 @@ "d3-geo": "^1.12.1", "gettext-parser": "^4.0.3", "google-protobuf": "^3.14.0", - "moment": "^2.29.1", "node-gettext": "^3.0.0", "rbush": "^2.0.2", "react": "^17.0.1", @@ -52,8 +51,8 @@ "@types/styled-components": "^5.1.4", "@types/topojson-specification": "^1.0.1", "@types/uuid": "^3.4.4", - "@typescript-eslint/eslint-plugin": "^4.8.2", - "@typescript-eslint/parser": "^4.8.2", + "@typescript-eslint/eslint-plugin": "^4.21.0", + "@typescript-eslint/parser": "^4.21.0", "browser-sync": "^2.26.13", "browserify": "^17.0.0", "chai": "^4.2.0", @@ -80,7 +79,7 @@ "spa-server": "^1.0.0", "ts-node": "^9.1.1", "tsc-watch": "^4.2.9", - "typescript": "^4.1.5", + "typescript": "^4.2.3", "vinyl-buffer": "^1.0.1", "vinyl-source-stream": "^2.0.0" }, @@ -808,12 +807,12 @@ } }, "node_modules/@nodelib/fs.scandir": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", - "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", + "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==", "dev": true, "dependencies": { - "@nodelib/fs.stat": "2.0.3", + "@nodelib/fs.stat": "2.0.4", "run-parallel": "^1.1.9" }, "engines": { @@ -821,21 +820,21 @@ } }, "node_modules/@nodelib/fs.stat": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", - "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz", + "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==", "dev": true, "engines": { "node": ">= 8" } }, "node_modules/@nodelib/fs.walk": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", - "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz", + "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==", "dev": true, "dependencies": { - "@nodelib/fs.scandir": "2.1.3", + "@nodelib/fs.scandir": "2.1.4", "fastq": "^1.6.0" }, "engines": { @@ -1008,9 +1007,9 @@ } }, "node_modules/@types/json-schema": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz", - "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==", + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", + "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", "dev": true }, "node_modules/@types/minimatch": { @@ -1207,56 +1206,35 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.8.2.tgz", - "integrity": "sha512-gQ06QLV5l1DtvYtqOyFLXD9PdcILYqlrJj2l+CGDlPtmgLUzc1GpqciJFIRvyfvgLALpnxYINFuw+n9AZhPBKQ==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.21.0.tgz", + "integrity": "sha512-FPUyCPKZbVGexmbCFI3EQHzCZdy2/5f+jv6k2EDljGdXSRc0cKvbndd2nHZkSLqCNOPk0jB6lGzwIkglXcYVsQ==", "dev": true, "dependencies": { - "@typescript-eslint/experimental-utils": "4.8.2", - "@typescript-eslint/scope-manager": "4.8.2", + "@typescript-eslint/experimental-utils": "4.21.0", + "@typescript-eslint/scope-manager": "4.21.0", "debug": "^4.1.1", "functional-red-black-tree": "^1.0.1", + "lodash": "^4.17.15", "regexpp": "^3.0.0", "semver": "^7.3.2", "tsutils": "^3.17.1" }, "engines": { "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.8.2.tgz", - "integrity": "sha512-qHQ8ODi7mMin4Sq2eh/6eu03uVzsf5TX+J43xRmiq8ujng7ViQSHNPLOHGw/Wr5dFEoxq/ubKhzClIIdQy5q3g==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "4.8.2", - "@typescript-eslint/visitor-keys": "4.8.2" }, - "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.8.2.tgz", - "integrity": "sha512-z1/AVcVF8ju5ObaHe2fOpZYEQrwHyZ7PTOlmjd3EoFeX9sv7UekQhfrCmgUO7PruLNfSHrJGQvrW3Q7xQ8EoAw==", - "dev": true, - "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.8.2.tgz", - "integrity": "sha512-Vg+/SJTMZJEKKGHW7YC21QxgKJrSbxoYYd3MEUGtW7zuytHuEcksewq0DUmo4eh/CTNrVJGSdIY9AtRb6riWFw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "4.8.2", - "eslint-visitor-keys": "^2.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, - "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "peerDependencies": { + "@typescript-eslint/parser": "^4.0.0", + "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/debug": { @@ -1271,15 +1249,6 @@ "node": ">=6.0" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/eslint-visitor-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", - "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -1287,137 +1256,54 @@ "dev": true }, "node_modules/@typescript-eslint/experimental-utils": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.8.2.tgz", - "integrity": "sha512-hpTw6o6IhBZEsQsjuw/4RWmceRyESfAiEzAEnXHKG1X7S5DXFaZ4IO1JO7CW1aQ604leQBzjZmuMI9QBCAJX8Q==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.21.0.tgz", + "integrity": "sha512-cEbgosW/tUFvKmkg3cU7LBoZhvUs+ZPVM9alb25XvR0dal4qHL3SiUqHNrzoWSxaXA9gsifrYrS1xdDV6w/gIA==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.3", - "@typescript-eslint/scope-manager": "4.8.2", - "@typescript-eslint/types": "4.8.2", - "@typescript-eslint/typescript-estree": "4.8.2", + "@typescript-eslint/scope-manager": "4.21.0", + "@typescript-eslint/types": "4.21.0", + "@typescript-eslint/typescript-estree": "4.21.0", "eslint-scope": "^5.0.0", "eslint-utils": "^2.0.0" }, "engines": { "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/scope-manager": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.8.2.tgz", - "integrity": "sha512-qHQ8ODi7mMin4Sq2eh/6eu03uVzsf5TX+J43xRmiq8ujng7ViQSHNPLOHGw/Wr5dFEoxq/ubKhzClIIdQy5q3g==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "4.8.2", - "@typescript-eslint/visitor-keys": "4.8.2" }, - "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" - } - }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/types": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.8.2.tgz", - "integrity": "sha512-z1/AVcVF8ju5ObaHe2fOpZYEQrwHyZ7PTOlmjd3EoFeX9sv7UekQhfrCmgUO7PruLNfSHrJGQvrW3Q7xQ8EoAw==", - "dev": true, - "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" - } - }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.8.2.tgz", - "integrity": "sha512-HToGNwI6fekH0dOw3XEVESUm71Onfam0AKin6f26S2FtUmO7o3cLlWgrIaT1q3vjB3wCTdww3Dx2iGq5wtUOCg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "4.8.2", - "@typescript-eslint/visitor-keys": "4.8.2", - "debug": "^4.1.1", - "globby": "^11.0.1", - "is-glob": "^4.0.1", - "lodash": "^4.17.15", - "semver": "^7.3.2", - "tsutils": "^3.17.1" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.8.2.tgz", - "integrity": "sha512-Vg+/SJTMZJEKKGHW7YC21QxgKJrSbxoYYd3MEUGtW7zuytHuEcksewq0DUmo4eh/CTNrVJGSdIY9AtRb6riWFw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "4.8.2", - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" - } - }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^1.1.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/eslint-visitor-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", - "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", - "dev": true, - "engines": { - "node": ">=10" + "peerDependencies": { + "eslint": "*" } }, - "node_modules/@typescript-eslint/experimental-utils/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==", - "dev": true - }, "node_modules/@typescript-eslint/parser": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.8.2.tgz", - "integrity": "sha512-u0leyJqmclYr3KcXOqd2fmx6SDGBO0MUNHHAjr0JS4Crbb3C3d8dwAdlazy133PLCcPn+aOUFiHn72wcuc5wYw==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.21.0.tgz", + "integrity": "sha512-eyNf7QmE5O/l1smaQgN0Lj2M/1jOuNg2NrBm1dqqQN0sVngTLyw8tdCbih96ixlhbF1oINoN8fDCyEH9SjLeIA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "4.8.2", - "@typescript-eslint/types": "4.8.2", - "@typescript-eslint/typescript-estree": "4.8.2", + "@typescript-eslint/scope-manager": "4.21.0", + "@typescript-eslint/types": "4.21.0", + "@typescript-eslint/typescript-estree": "4.21.0", "debug": "^4.1.1" }, "engines": { "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@typescript-eslint/parser/node_modules/debug": { @@ -1439,44 +1325,60 @@ "dev": true }, "node_modules/@typescript-eslint/scope-manager": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.8.2.tgz", - "integrity": "sha512-qHQ8ODi7mMin4Sq2eh/6eu03uVzsf5TX+J43xRmiq8ujng7ViQSHNPLOHGw/Wr5dFEoxq/ubKhzClIIdQy5q3g==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.21.0.tgz", + "integrity": "sha512-kfOjF0w1Ix7+a5T1knOw00f7uAP9Gx44+OEsNQi0PvvTPLYeXJlsCJ4tYnDj5PQEYfpcgOH5yBlw7K+UEI9Agw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "4.8.2", - "@typescript-eslint/visitor-keys": "4.8.2" + "@typescript-eslint/types": "4.21.0", + "@typescript-eslint/visitor-keys": "4.21.0" }, "engines": { "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, "node_modules/@typescript-eslint/types": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.8.2.tgz", - "integrity": "sha512-z1/AVcVF8ju5ObaHe2fOpZYEQrwHyZ7PTOlmjd3EoFeX9sv7UekQhfrCmgUO7PruLNfSHrJGQvrW3Q7xQ8EoAw==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.21.0.tgz", + "integrity": "sha512-+OQaupjGVVc8iXbt6M1oZMwyKQNehAfLYJJ3SdvnofK2qcjfor9pEM62rVjBknhowTkh+2HF+/KdRAc/wGBN2w==", "dev": true, "engines": { "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.8.2.tgz", - "integrity": "sha512-HToGNwI6fekH0dOw3XEVESUm71Onfam0AKin6f26S2FtUmO7o3cLlWgrIaT1q3vjB3wCTdww3Dx2iGq5wtUOCg==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.21.0.tgz", + "integrity": "sha512-ZD3M7yLaVGVYLw4nkkoGKumb7Rog7QID9YOWobFDMQKNl+vPxqVIW/uDk+MDeGc+OHcoG2nJ2HphwiPNajKw3w==", "dev": true, "dependencies": { - "@typescript-eslint/types": "4.8.2", - "@typescript-eslint/visitor-keys": "4.8.2", + "@typescript-eslint/types": "4.21.0", + "@typescript-eslint/visitor-keys": "4.21.0", "debug": "^4.1.1", "globby": "^11.0.1", "is-glob": "^4.0.1", - "lodash": "^4.17.15", "semver": "^7.3.2", "tsutils": "^3.17.1" }, "engines": { "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { @@ -1489,6 +1391,11 @@ }, "engines": { "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/ms": { @@ -1498,25 +1405,20 @@ "dev": true }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.8.2.tgz", - "integrity": "sha512-Vg+/SJTMZJEKKGHW7YC21QxgKJrSbxoYYd3MEUGtW7zuytHuEcksewq0DUmo4eh/CTNrVJGSdIY9AtRb6riWFw==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.21.0.tgz", + "integrity": "sha512-dH22dROWGi5Z6p+Igc8bLVLmwy7vEe8r+8c+raPQU0LxgogPUrRAtRGtvBWmlr9waTu3n+QLt/qrS/hWzk1x5w==", "dev": true, "dependencies": { - "@typescript-eslint/types": "4.8.2", + "@typescript-eslint/types": "4.21.0", "eslint-visitor-keys": "^2.0.0" }, "engines": { "node": "^8.10.0 || ^10.13.0 || >=11.10.1" - } - }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", - "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", - "dev": true, - "engines": { - "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, "node_modules/@ungap/promise-all-settled": { @@ -6905,12 +6807,12 @@ } }, "node_modules/eslint-scope": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", - "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "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, "dependencies": { - "esrecurse": "^4.1.0", + "esrecurse": "^4.3.0", "estraverse": "^4.1.1" }, "engines": { @@ -7037,40 +6939,6 @@ "node": ">=6.0.0" } }, - "node_modules/eslint/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, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint/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": ">=4.0" - } - }, - "node_modules/eslint/node_modules/esrecurse/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/eslint/node_modules/glob-parent": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", @@ -7234,17 +7102,26 @@ } }, "node_modules/esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "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": "^4.1.0" + "estraverse": "^5.2.0" }, "engines": { "node": ">=4.0" } }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/estraverse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", @@ -7577,9 +7454,9 @@ "dev": true }, "node_modules/fast-glob": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", - "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", + "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -7618,9 +7495,9 @@ } }, "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "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" @@ -7682,9 +7559,9 @@ "dev": true }, "node_modules/fastq": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", - "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", + "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -8447,9 +8324,9 @@ } }, "node_modules/globby": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", - "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz", + "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==", "dev": true, "dependencies": { "array-union": "^2.1.0", @@ -8461,6 +8338,9 @@ }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/globby/node_modules/ignore": { @@ -12033,6 +11913,7 @@ "version": "2.29.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==", + "dev": true, "engines": { "node": "*" } @@ -13342,6 +13223,26 @@ "node": ">=0.4.x" } }, + "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/quickselect": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-1.1.1.tgz", @@ -14095,10 +13996,27 @@ } }, "node_modules/run-parallel": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", - "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", - "dev": true + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "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" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } }, "node_modules/rx": { "version": "4.1.0", @@ -16360,9 +16278,9 @@ } }, "node_modules/typescript": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.5.tgz", - "integrity": "sha512-6OSu9PTIzmn9TCDiovULTnET6BgXtDYL4Gg4szY+cGsc3JP1dQL8qvE8kShTRx1NIw4Q9IBHlwODjkjWEtMUyA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", + "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -18250,28 +18168,28 @@ } }, "@nodelib/fs.scandir": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", - "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", + "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==", "dev": true, "requires": { - "@nodelib/fs.stat": "2.0.3", + "@nodelib/fs.stat": "2.0.4", "run-parallel": "^1.1.9" } }, "@nodelib/fs.stat": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", - "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz", + "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==", "dev": true }, "@nodelib/fs.walk": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", - "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz", + "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==", "dev": true, "requires": { - "@nodelib/fs.scandir": "2.1.3", + "@nodelib/fs.scandir": "2.1.4", "fastq": "^1.6.0" } }, @@ -18435,9 +18353,9 @@ } }, "@types/json-schema": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz", - "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==", + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", + "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", "dev": true }, "@types/minimatch": { @@ -18634,46 +18552,21 @@ "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.8.2.tgz", - "integrity": "sha512-gQ06QLV5l1DtvYtqOyFLXD9PdcILYqlrJj2l+CGDlPtmgLUzc1GpqciJFIRvyfvgLALpnxYINFuw+n9AZhPBKQ==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.21.0.tgz", + "integrity": "sha512-FPUyCPKZbVGexmbCFI3EQHzCZdy2/5f+jv6k2EDljGdXSRc0cKvbndd2nHZkSLqCNOPk0jB6lGzwIkglXcYVsQ==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "4.8.2", - "@typescript-eslint/scope-manager": "4.8.2", + "@typescript-eslint/experimental-utils": "4.21.0", + "@typescript-eslint/scope-manager": "4.21.0", "debug": "^4.1.1", "functional-red-black-tree": "^1.0.1", + "lodash": "^4.17.15", "regexpp": "^3.0.0", "semver": "^7.3.2", "tsutils": "^3.17.1" }, "dependencies": { - "@typescript-eslint/scope-manager": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.8.2.tgz", - "integrity": "sha512-qHQ8ODi7mMin4Sq2eh/6eu03uVzsf5TX+J43xRmiq8ujng7ViQSHNPLOHGw/Wr5dFEoxq/ubKhzClIIdQy5q3g==", - "dev": true, - "requires": { - "@typescript-eslint/types": "4.8.2", - "@typescript-eslint/visitor-keys": "4.8.2" - } - }, - "@typescript-eslint/types": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.8.2.tgz", - "integrity": "sha512-z1/AVcVF8ju5ObaHe2fOpZYEQrwHyZ7PTOlmjd3EoFeX9sv7UekQhfrCmgUO7PruLNfSHrJGQvrW3Q7xQ8EoAw==", - "dev": true - }, - "@typescript-eslint/visitor-keys": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.8.2.tgz", - "integrity": "sha512-Vg+/SJTMZJEKKGHW7YC21QxgKJrSbxoYYd3MEUGtW7zuytHuEcksewq0DUmo4eh/CTNrVJGSdIY9AtRb6riWFw==", - "dev": true, - "requires": { - "@typescript-eslint/types": "4.8.2", - "eslint-visitor-keys": "^2.0.0" - } - }, "debug": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", @@ -18683,12 +18576,6 @@ "ms": "2.1.2" } }, - "eslint-visitor-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", - "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", - "dev": true - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -18698,110 +18585,28 @@ } }, "@typescript-eslint/experimental-utils": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.8.2.tgz", - "integrity": "sha512-hpTw6o6IhBZEsQsjuw/4RWmceRyESfAiEzAEnXHKG1X7S5DXFaZ4IO1JO7CW1aQ604leQBzjZmuMI9QBCAJX8Q==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.21.0.tgz", + "integrity": "sha512-cEbgosW/tUFvKmkg3cU7LBoZhvUs+ZPVM9alb25XvR0dal4qHL3SiUqHNrzoWSxaXA9gsifrYrS1xdDV6w/gIA==", "dev": true, "requires": { "@types/json-schema": "^7.0.3", - "@typescript-eslint/scope-manager": "4.8.2", - "@typescript-eslint/types": "4.8.2", - "@typescript-eslint/typescript-estree": "4.8.2", + "@typescript-eslint/scope-manager": "4.21.0", + "@typescript-eslint/types": "4.21.0", + "@typescript-eslint/typescript-estree": "4.21.0", "eslint-scope": "^5.0.0", "eslint-utils": "^2.0.0" - }, - "dependencies": { - "@typescript-eslint/scope-manager": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.8.2.tgz", - "integrity": "sha512-qHQ8ODi7mMin4Sq2eh/6eu03uVzsf5TX+J43xRmiq8ujng7ViQSHNPLOHGw/Wr5dFEoxq/ubKhzClIIdQy5q3g==", - "dev": true, - "requires": { - "@typescript-eslint/types": "4.8.2", - "@typescript-eslint/visitor-keys": "4.8.2" - } - }, - "@typescript-eslint/types": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.8.2.tgz", - "integrity": "sha512-z1/AVcVF8ju5ObaHe2fOpZYEQrwHyZ7PTOlmjd3EoFeX9sv7UekQhfrCmgUO7PruLNfSHrJGQvrW3Q7xQ8EoAw==", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.8.2.tgz", - "integrity": "sha512-HToGNwI6fekH0dOw3XEVESUm71Onfam0AKin6f26S2FtUmO7o3cLlWgrIaT1q3vjB3wCTdww3Dx2iGq5wtUOCg==", - "dev": true, - "requires": { - "@typescript-eslint/types": "4.8.2", - "@typescript-eslint/visitor-keys": "4.8.2", - "debug": "^4.1.1", - "globby": "^11.0.1", - "is-glob": "^4.0.1", - "lodash": "^4.17.15", - "semver": "^7.3.2", - "tsutils": "^3.17.1" - } - }, - "@typescript-eslint/visitor-keys": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.8.2.tgz", - "integrity": "sha512-Vg+/SJTMZJEKKGHW7YC21QxgKJrSbxoYYd3MEUGtW7zuytHuEcksewq0DUmo4eh/CTNrVJGSdIY9AtRb6riWFw==", - "dev": true, - "requires": { - "@typescript-eslint/types": "4.8.2", - "eslint-visitor-keys": "^2.0.0" - } - }, - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } - } - }, - "eslint-visitor-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", - "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", - "dev": true - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } } }, "@typescript-eslint/parser": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.8.2.tgz", - "integrity": "sha512-u0leyJqmclYr3KcXOqd2fmx6SDGBO0MUNHHAjr0JS4Crbb3C3d8dwAdlazy133PLCcPn+aOUFiHn72wcuc5wYw==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.21.0.tgz", + "integrity": "sha512-eyNf7QmE5O/l1smaQgN0Lj2M/1jOuNg2NrBm1dqqQN0sVngTLyw8tdCbih96ixlhbF1oINoN8fDCyEH9SjLeIA==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "4.8.2", - "@typescript-eslint/types": "4.8.2", - "@typescript-eslint/typescript-estree": "4.8.2", + "@typescript-eslint/scope-manager": "4.21.0", + "@typescript-eslint/types": "4.21.0", + "@typescript-eslint/typescript-estree": "4.21.0", "debug": "^4.1.1" }, "dependencies": { @@ -18823,33 +18628,32 @@ } }, "@typescript-eslint/scope-manager": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.8.2.tgz", - "integrity": "sha512-qHQ8ODi7mMin4Sq2eh/6eu03uVzsf5TX+J43xRmiq8ujng7ViQSHNPLOHGw/Wr5dFEoxq/ubKhzClIIdQy5q3g==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.21.0.tgz", + "integrity": "sha512-kfOjF0w1Ix7+a5T1knOw00f7uAP9Gx44+OEsNQi0PvvTPLYeXJlsCJ4tYnDj5PQEYfpcgOH5yBlw7K+UEI9Agw==", "dev": true, "requires": { - "@typescript-eslint/types": "4.8.2", - "@typescript-eslint/visitor-keys": "4.8.2" + "@typescript-eslint/types": "4.21.0", + "@typescript-eslint/visitor-keys": "4.21.0" } }, "@typescript-eslint/types": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.8.2.tgz", - "integrity": "sha512-z1/AVcVF8ju5ObaHe2fOpZYEQrwHyZ7PTOlmjd3EoFeX9sv7UekQhfrCmgUO7PruLNfSHrJGQvrW3Q7xQ8EoAw==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.21.0.tgz", + "integrity": "sha512-+OQaupjGVVc8iXbt6M1oZMwyKQNehAfLYJJ3SdvnofK2qcjfor9pEM62rVjBknhowTkh+2HF+/KdRAc/wGBN2w==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.8.2.tgz", - "integrity": "sha512-HToGNwI6fekH0dOw3XEVESUm71Onfam0AKin6f26S2FtUmO7o3cLlWgrIaT1q3vjB3wCTdww3Dx2iGq5wtUOCg==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.21.0.tgz", + "integrity": "sha512-ZD3M7yLaVGVYLw4nkkoGKumb7Rog7QID9YOWobFDMQKNl+vPxqVIW/uDk+MDeGc+OHcoG2nJ2HphwiPNajKw3w==", "dev": true, "requires": { - "@typescript-eslint/types": "4.8.2", - "@typescript-eslint/visitor-keys": "4.8.2", + "@typescript-eslint/types": "4.21.0", + "@typescript-eslint/visitor-keys": "4.21.0", "debug": "^4.1.1", "globby": "^11.0.1", "is-glob": "^4.0.1", - "lodash": "^4.17.15", "semver": "^7.3.2", "tsutils": "^3.17.1" }, @@ -18872,21 +18676,13 @@ } }, "@typescript-eslint/visitor-keys": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.8.2.tgz", - "integrity": "sha512-Vg+/SJTMZJEKKGHW7YC21QxgKJrSbxoYYd3MEUGtW7zuytHuEcksewq0DUmo4eh/CTNrVJGSdIY9AtRb6riWFw==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.21.0.tgz", + "integrity": "sha512-dH22dROWGi5Z6p+Igc8bLVLmwy7vEe8r+8c+raPQU0LxgogPUrRAtRGtvBWmlr9waTu3n+QLt/qrS/hWzk1x5w==", "dev": true, "requires": { - "@typescript-eslint/types": "4.8.2", + "@typescript-eslint/types": "4.21.0", "eslint-visitor-keys": "^2.0.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", - "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", - "dev": true - } } }, "@ungap/promise-all-settled": { @@ -23268,33 +23064,6 @@ "esutils": "^2.0.2" } }, - "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, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "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, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - }, "glob-parent": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", @@ -23518,12 +23287,12 @@ } }, "eslint-scope": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", - "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "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, "requires": { - "esrecurse": "^4.1.0", + "esrecurse": "^4.3.0", "estraverse": "^4.1.1" } }, @@ -23593,12 +23362,20 @@ } }, "esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "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, "requires": { - "estraverse": "^4.1.0" + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } } }, "estraverse": { @@ -23880,9 +23657,9 @@ "dev": true }, "fast-glob": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", - "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", + "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", @@ -23912,9 +23689,9 @@ } }, "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "requires": { "is-glob": "^4.0.1" @@ -23966,9 +23743,9 @@ "dev": true }, "fastq": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", - "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", + "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", "dev": true, "requires": { "reusify": "^1.0.4" @@ -24589,9 +24366,9 @@ } }, "globby": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", - "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz", + "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==", "dev": true, "requires": { "array-union": "^2.1.0", @@ -27499,7 +27276,8 @@ "moment": { "version": "2.29.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", - "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" + "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==", + "dev": true }, "ms": { "version": "2.0.0", @@ -28566,6 +28344,12 @@ "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", "dev": true }, + "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 + }, "quickselect": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-1.1.1.tgz", @@ -29194,10 +28978,13 @@ } }, "run-parallel": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", - "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", - "dev": true + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } }, "rx": { "version": "4.1.0", @@ -31114,9 +30901,9 @@ } }, "typescript": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.5.tgz", - "integrity": "sha512-6OSu9PTIzmn9TCDiovULTnET6BgXtDYL4Gg4szY+cGsc3JP1dQL8qvE8kShTRx1NIw4Q9IBHlwODjkjWEtMUyA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", + "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==", "dev": true }, "ua-parser-js": { diff --git a/gui/package.json b/gui/package.json index 34bfb75e16..258a5b3f08 100644 --- a/gui/package.json +++ b/gui/package.json @@ -17,7 +17,6 @@ "d3-geo": "^1.12.1", "gettext-parser": "^4.0.3", "google-protobuf": "^3.14.0", - "moment": "^2.29.1", "node-gettext": "^3.0.0", "rbush": "^2.0.2", "react": "^17.0.1", @@ -58,8 +57,8 @@ "@types/styled-components": "^5.1.4", "@types/topojson-specification": "^1.0.1", "@types/uuid": "^3.4.4", - "@typescript-eslint/eslint-plugin": "^4.8.2", - "@typescript-eslint/parser": "^4.8.2", + "@typescript-eslint/eslint-plugin": "^4.21.0", + "@typescript-eslint/parser": "^4.21.0", "browser-sync": "^2.26.13", "browserify": "^17.0.0", "chai": "^4.2.0", @@ -86,7 +85,7 @@ "spa-server": "^1.0.0", "ts-node": "^9.1.1", "tsc-watch": "^4.2.9", - "typescript": "^4.1.5", + "typescript": "^4.2.3", "vinyl-buffer": "^1.0.1", "vinyl-source-stream": "^2.0.0" }, diff --git a/gui/src/main/account-data-cache.ts b/gui/src/main/account-data-cache.ts index a03728e004..7d3c59e5ef 100644 --- a/gui/src/main/account-data-cache.ts +++ b/gui/src/main/account-data-cache.ts @@ -1,6 +1,6 @@ -import moment from 'moment'; -import { hasExpired } from '../shared/account-expiry'; +import { closeToExpiry, hasExpired } from '../shared/account-expiry'; import { AccountToken, IAccountData } from '../shared/daemon-rpc-types'; +import { DateComponent, dateByAddingComponent } from '../shared/date-helper'; import log from '../shared/logging'; import consumePromise from '../shared/promise'; import { Scheduler } from '../shared/scheduler'; @@ -105,13 +105,12 @@ export default class AccountDataCache { private calculateRefetchDelay(accountExpiry: string) { const currentDate = new Date(); - const oneMinuteBeforeExpiry = moment(accountExpiry).subtract(1, 'minute'); - const closeToExpiry = moment(accountExpiry).isSameOrBefore(moment().add(3, 'days')); + const oneMinuteBeforeExpiry = dateByAddingComponent(accountExpiry, DateComponent.minute, -1); if (hasExpired(accountExpiry)) { return EXPIRED_ACCOUNT_REFRESH_PERIOD; - } else if (oneMinuteBeforeExpiry.isSameOrAfter(currentDate) && closeToExpiry) { - return oneMinuteBeforeExpiry.diff(currentDate); + } else if (oneMinuteBeforeExpiry >= currentDate && closeToExpiry(accountExpiry)) { + return oneMinuteBeforeExpiry.getTime() - currentDate.getTime(); } else { return undefined; } diff --git a/gui/src/main/index.ts b/gui/src/main/index.ts index efbf9a4aa3..43807de5c3 100644 --- a/gui/src/main/index.ts +++ b/gui/src/main/index.ts @@ -10,7 +10,6 @@ import { shell, Tray, } from 'electron'; -import moment from 'moment'; import * as path from 'path'; import { sprintf } from 'sprintf-js'; import * as uuid from 'uuid'; @@ -1339,7 +1338,7 @@ class ApplicationMain { this.notificationController.notify(closeToExpiryNotification.getSystemNotification()); const twelveHours = 12 * 60 * 60 * 1000; - const remainingMilliseconds = moment(this.accountData.expiry).diff(new Date()); + const remainingMilliseconds = new Date(this.accountData.expiry).getTime() - Date.now(); const delay = Math.min(twelveHours, remainingMilliseconds); this.accountExpiryNotificationScheduler.schedule(() => this.handleAccountExpiry(), delay); } diff --git a/gui/src/renderer/components/Settings.tsx b/gui/src/renderer/components/Settings.tsx index 00c5d846f0..56b8fd5494 100644 --- a/gui/src/renderer/components/Settings.tsx +++ b/gui/src/renderer/components/Settings.tsx @@ -29,7 +29,6 @@ export interface IProps { preferredLocaleDisplayName: string; loginState: LoginState; accountExpiry?: string; - expiryLocale: string; appVersion: string; consistentVersion: boolean; upToDateVersion: boolean; @@ -106,7 +105,7 @@ export default class Settings extends React.Component<IProps> { const isOutOfTime = this.props.accountExpiry ? hasExpired(this.props.accountExpiry) : false; const formattedExpiry = this.props.accountExpiry - ? formatRemainingTime(this.props.accountExpiry, this.props.expiryLocale).toUpperCase() + ? formatRemainingTime(this.props.accountExpiry).toUpperCase() : ''; const outOfTimeMessage = messages.pgettext('settings-view', 'OUT OF TIME'); diff --git a/gui/src/renderer/components/WireguardKeys.tsx b/gui/src/renderer/components/WireguardKeys.tsx index 9c181ad57e..f6e143e6a3 100644 --- a/gui/src/renderer/components/WireguardKeys.tsx +++ b/gui/src/renderer/components/WireguardKeys.tsx @@ -1,7 +1,7 @@ -import moment from 'moment'; import * as React from 'react'; import { sprintf } from 'sprintf-js'; import { TunnelState } from '../../shared/daemon-rpc-types'; +import { formatRelativeDate } from '../../shared/date-helper'; import { messages } from '../../shared/gettext'; import log from '../../shared/logging'; import { IWgKey, WgKeyState } from '../redux/settings/reducers'; @@ -35,7 +35,6 @@ import { export interface IProps { keyState: WgKeyState; isOffline: boolean; - locale: string; tunnelState: TunnelState; windowFocused: boolean; @@ -56,14 +55,14 @@ export default class WireguardKeys extends React.Component<IProps, IState> { public state = { recentlyGeneratedKey: false, userHasInitiatedVerification: false, - ageOfKeyString: WireguardKeys.ageOfKeyString(this.props.keyState, this.props.locale), + ageOfKeyString: WireguardKeys.ageOfKeyString(this.props.keyState), }; private keyAgeUpdateInterval?: number; public static getDerivedStateFromProps(props: IProps) { return { - ageOfKeyString: WireguardKeys.ageOfKeyString(props.keyState, props.locale), + ageOfKeyString: WireguardKeys.ageOfKeyString(props.keyState), }; } @@ -276,11 +275,12 @@ export default class WireguardKeys extends React.Component<IProps, IState> { } } - private static ageOfKeyString(keyState: WgKeyState, locale: string): string { + private static ageOfKeyString(keyState: WgKeyState): string { switch (keyState.type) { case 'key-set': - case 'being-verified': - return moment(keyState.key.created).locale(locale).fromNow(); + case 'being-verified': { + return formatRelativeDate(new Date(), keyState.key.created, true); + } default: return '-'; } @@ -288,7 +288,7 @@ export default class WireguardKeys extends React.Component<IProps, IState> { private setAgeOfKeyStringState = () => { this.setState({ - ageOfKeyString: WireguardKeys.ageOfKeyString(this.props.keyState, this.props.locale), + ageOfKeyString: WireguardKeys.ageOfKeyString(this.props.keyState), }); }; diff --git a/gui/src/renderer/containers/SettingsPage.tsx b/gui/src/renderer/containers/SettingsPage.tsx index 7d233e9f06..6985fd927c 100644 --- a/gui/src/renderer/containers/SettingsPage.tsx +++ b/gui/src/renderer/containers/SettingsPage.tsx @@ -10,7 +10,6 @@ const mapStateToProps = (state: IReduxState, props: IAppContext) => ({ ), loginState: state.account.status, accountExpiry: state.account.expiry, - expiryLocale: state.userInterface.locale, appVersion: state.version.current, consistentVersion: state.version.consistent, upToDateVersion: state.version.suggestedUpgrade ? false : true, diff --git a/gui/src/renderer/containers/WireguardKeysPage.tsx b/gui/src/renderer/containers/WireguardKeysPage.tsx index 9e5fa6fc8c..e07e4718f2 100644 --- a/gui/src/renderer/containers/WireguardKeysPage.tsx +++ b/gui/src/renderer/containers/WireguardKeysPage.tsx @@ -9,7 +9,6 @@ import { IReduxState, ReduxDispatch } from '../redux/store'; const mapStateToProps = (state: IReduxState) => ({ keyState: state.settings.wireguardKeyState, isOffline: state.connection.isBlocked, - locale: state.userInterface.locale, tunnelState: state.connection.status, windowFocused: state.userInterface.windowFocused, }); diff --git a/gui/src/shared/account-expiry.ts b/gui/src/shared/account-expiry.ts index a76eb6ecc4..7ca382efb2 100644 --- a/gui/src/shared/account-expiry.ts +++ b/gui/src/shared/account-expiry.ts @@ -1,52 +1,27 @@ -import moment from 'moment'; -import { sprintf } from 'sprintf-js'; -import { messages } from './gettext'; +import { DateComponent, DateType, formatRelativeDate, dateByAddingComponent } from './date-helper'; import { capitalize } from './string-helpers'; -type DateArgument = string | Date | moment.Moment; - -export function hasExpired(expiry: DateArgument): boolean { - return moment(expiry).isSameOrBefore(new Date()); +export function hasExpired(expiry: DateType): boolean { + return new Date(expiry).getTime() < Date.now(); } -export function formatDate(date: DateArgument, locale: string): string { - return moment(date).locale(locale).format('lll'); +export function closeToExpiry(expiry: DateType): boolean { + return ( + !hasExpired(expiry) && + new Date(expiry) <= dateByAddingComponent(new Date(), DateComponent.day, 3) + ); } -export function formatDurationUntilExpiry(expiry: DateArgument, locale: string): string { - const expiryMoment = moment(expiry).locale(locale); - const daysDiff = expiryMoment.diff(new Date(), 'days'); - - // Below three months we want to show the duration in days. Moments fromNow() method starts - // measuring duration in months from 26 days and up. - // https://momentjs.com/docs/#/displaying/fromnow/ - if (daysDiff >= 26 && daysDiff <= 90) { - return sprintf( - // TRANSLATORS: The remaining time left on the account measured in days. - // TRANSLATORS: Available placeholders: - // TRANSLATORS: %(duration)s - The remaining time measured in days. - messages.pgettext('account-expiry', '%(duration)s days'), - { duration: daysDiff }, - ); - } else { - return expiryMoment.fromNow(true); - } +export function formatDate(date: DateType, locale: string): string { + return new Intl.DateTimeFormat(locale, { dateStyle: 'medium', timeStyle: 'short' }).format( + new Date(date), + ); } export function formatRemainingTime( - expiry: DateArgument, - locale: string, + expiry: DateType, shouldCapitalizeFirstLetter?: boolean, ): string { - const duration = formatDurationUntilExpiry(expiry, locale); - - const remaining = sprintf( - // TRANSLATORS: The remaining time left on the account displayed across the app. - // TRANSLATORS: Available placeholders: - // TRANSLATORS: %(duration)s - a localized remaining time (in minutes, hours, or days) until the account expiry - messages.pgettext('account-expiry', '%(duration)s left'), - { duration }, - ); - + const remaining = formatRelativeDate(new Date(), expiry, true); return shouldCapitalizeFirstLetter ? capitalize(remaining) : remaining; } diff --git a/gui/src/shared/date-helper.ts b/gui/src/shared/date-helper.ts new file mode 100644 index 0000000000..0011ed8fc2 --- /dev/null +++ b/gui/src/shared/date-helper.ts @@ -0,0 +1,121 @@ +import { sprintf } from 'sprintf-js'; +import { messages } from './gettext'; + +export type DateType = Date | string; + +export enum DateComponent { + day, + hour, + minute, +} + +export function dateByAddingComponent(date: DateType, component: DateComponent, value: number) { + const modifiedDate = new Date(date); + switch (component) { + case DateComponent.day: + modifiedDate.setDate(modifiedDate.getDate() + value); + break; + case DateComponent.hour: + modifiedDate.setHours(modifiedDate.getHours() + value); + break; + case DateComponent.minute: + modifiedDate.setMinutes(modifiedDate.getMinutes() + value); + break; + } + + return modifiedDate; +} + +export class DateDiff { + private readonly fromDate: Date; + private readonly toDate: Date; + + public constructor(fromDate: DateType, toDate: DateType) { + this.fromDate = new Date(fromDate); + this.toDate = new Date(toDate); + } + + get milliseconds(): number { + return this.toDate.getTime() - this.fromDate.getTime(); + } + + get seconds(): number { + return this.floor(this.milliseconds / 1000); + } + + get minutes(): number { + return this.floor(this.seconds / 60); + } + + get hours(): number { + return this.floor(this.minutes / 60); + } + + get days(): number { + return this.floor(this.hours / 24); + } + + get months(): number { + const months = new Date(Math.abs(this.milliseconds)).getUTCMonth(); + const monthsWithSign = this.milliseconds >= 0 ? months : -months; + return this.years * 12 + monthsWithSign; + } + + get years(): number { + const years = new Date(Math.abs(this.milliseconds)).getUTCFullYear() - 1970; + return this.milliseconds >= 0 ? years : -years; + } + + private floor(n: number): number { + return n >= 0 ? Math.floor(n) : Math.ceil(n); + } +} + +export function formatRelativeDate( + fromDate: DateType, + toDate: DateType, + withSuffix = false, +): string { + const diff = new DateDiff(fromDate, toDate); + const years = Math.abs(diff.years); + const months = Math.abs(diff.months); + const days = Math.abs(diff.days); + const hours = Math.abs(diff.hours); + const minutes = Math.abs(diff.minutes); + + if (!withSuffix) { + if (years > 0) { + return sprintf(messages.ngettext('1 year', '%d years', years), years); + } else if (months >= 3) { + return sprintf(messages.ngettext('1 month', '%d months', months), months); + } else if (days > 0) { + return sprintf(messages.ngettext('1 day', '%d days', days), days); + } else { + return messages.gettext('less than a day'); + } + } else if (diff.milliseconds > 0) { + if (years > 0) { + return sprintf(messages.ngettext('1 year left', '%d years left', years), years); + } else if (months >= 3) { + return sprintf(messages.ngettext('1 month left', '%d months left', months), months); + } else if (days > 0) { + return sprintf(messages.ngettext('1 day left', '%d days left', days), days); + } else { + return messages.gettext('less than a day left'); + } + } else { + if (years > 0) { + return sprintf(messages.ngettext('a year ago', '%d years ago', years), years); + } else if (months > 0) { + return sprintf(messages.ngettext('a month ago', '%d months ago', months), months); + } else if (days > 0) { + return sprintf(messages.ngettext('a day ago', '%d days ago', days), days); + } else if (hours > 0) { + return sprintf(messages.ngettext('an hour ago', '%d hours ago', hours), hours); + } else if (minutes > 0) { + return sprintf(messages.ngettext('a minute ago', '%d minutes ago', minutes), minutes); + } else { + return messages.gettext('less than a minute ago'); + } + } +} diff --git a/gui/src/shared/logging.ts b/gui/src/shared/logging.ts index 84eaa5f25c..f8c71fc41e 100644 --- a/gui/src/shared/logging.ts +++ b/gui/src/shared/logging.ts @@ -1,4 +1,3 @@ -import moment from 'moment'; import { ILogInput, ILogOutput, LogLevel } from './logging-types'; export class Logger { @@ -13,7 +12,7 @@ export class Logger { } public log(level: LogLevel, ...data: unknown[]) { - const time = moment().format('YYYY-MM-DD HH:mm:ss.SSS'); + const time = this.getDateString(); const stringifiedData = data.map(this.stringifyData).join(' '); const message = `[${time}][${LogLevel[level]}] ${stringifiedData}`; @@ -30,6 +29,20 @@ export class Logger { this.outputs.forEach((output) => output.dispose?.()); } + private getDateString(): string { + const date = new Date(); + const year = date.getFullYear(); + const month = Number(date.getMonth() + 1) + .toString() + .padStart(2, '0'); + const day = Number(date.getDate()).toString().padStart(2, '0'); + const hour = Number(date.getHours()).toString().padStart(2, '0'); + const minute = Number(date.getMinutes()).toString().padStart(2, '0'); + const second = Number(date.getSeconds()).toString().padStart(2, '0'); + const millisecond = Number(date.getMilliseconds()).toString().padStart(3, '0'); + return `${year}-${month}-${day} ${hour}:${minute}:${second}.${millisecond}`; + } + private stringifyData(data: unknown): string { return typeof data === 'string' ? data : JSON.stringify(data); } diff --git a/gui/src/shared/notifications/close-to-account-expiry.ts b/gui/src/shared/notifications/close-to-account-expiry.ts index 2e3c5ae49e..e0f13b33b3 100644 --- a/gui/src/shared/notifications/close-to-account-expiry.ts +++ b/gui/src/shared/notifications/close-to-account-expiry.ts @@ -1,8 +1,8 @@ -import moment from 'moment'; import { sprintf } from 'sprintf-js'; import { links } from '../../config.json'; import { messages } from '../../shared/gettext'; -import { formatDurationUntilExpiry, formatRemainingTime, hasExpired } from '../account-expiry'; +import { closeToExpiry, formatRemainingTime } from '../account-expiry'; +import { formatRelativeDate } from '../date-helper'; import { InAppNotification, InAppNotificationProvider, @@ -19,13 +19,7 @@ export class CloseToAccountExpiryNotificationProvider implements InAppNotificationProvider, SystemNotificationProvider { public constructor(private context: CloseToAccountExpiryNotificationContext) {} - public mayDisplay() { - const willHaveExpiredInThreeDays = moment(this.context.accountExpiry).isSameOrBefore( - moment().add(3, 'days'), - ); - - return !hasExpired(this.context.accountExpiry) && willHaveExpiredInThreeDays; - } + public mayDisplay = () => closeToExpiry(this.context.accountExpiry); public getSystemNotification(): SystemNotification { const message = sprintf( @@ -37,7 +31,7 @@ export class CloseToAccountExpiryNotificationProvider 'Account credit expires in %(duration)s. Buy more credit.', ), { - duration: formatDurationUntilExpiry(this.context.accountExpiry, this.context.locale), + duration: formatRelativeDate(new Date(), this.context.accountExpiry), }, ); @@ -56,7 +50,7 @@ export class CloseToAccountExpiryNotificationProvider public getInAppNotification(): InAppNotification { const subtitle = sprintf( messages.pgettext('in-app-notifications', '%(duration)s. Buy more credit.'), - { duration: formatRemainingTime(this.context.accountExpiry, this.context.locale, true) }, + { duration: formatRemainingTime(this.context.accountExpiry, true) }, ); return { diff --git a/gui/test/date-helper.spec.ts b/gui/test/date-helper.spec.ts new file mode 100644 index 0000000000..5ae9c5d496 --- /dev/null +++ b/gui/test/date-helper.spec.ts @@ -0,0 +1,152 @@ +import { expect } from 'chai'; +import { it, describe } from 'mocha'; +import * as date from '../src/shared/date-helper'; + +describe('Date helper', () => { + it('should modify minutes', () => { + const initialDate = new Date('2021-01-01 13:37:10'); + const earlierDate = date.dateByAddingComponent(initialDate, date.DateComponent.minute, -50); + const laterDate = date.dateByAddingComponent(initialDate, date.DateComponent.minute, 100); + + expect(earlierDate.getFullYear()).to.equal(2021); + expect(earlierDate.getMonth()).to.equal(0); + expect(earlierDate.getDate()).to.equal(1); + expect(earlierDate.getHours()).to.equal(12); + expect(earlierDate.getMinutes()).to.equal(47); + expect(earlierDate.getSeconds()).to.equal(10); + + expect(laterDate.getFullYear()).to.equal(2021); + expect(laterDate.getMonth()).to.equal(0); + expect(laterDate.getDate()).to.equal(1); + expect(laterDate.getHours()).to.equal(15); + expect(laterDate.getMinutes()).to.equal(17); + expect(laterDate.getSeconds()).to.equal(10); + }); + + it('should modify hours', () => { + const initialDate = new Date('2021-01-01 13:37:10'); + const earlierDate = date.dateByAddingComponent(initialDate, date.DateComponent.hour, -50); + const laterDate = date.dateByAddingComponent(initialDate, date.DateComponent.hour, 100); + + expect(earlierDate.getFullYear()).to.equal(2020); + expect(earlierDate.getMonth()).to.equal(11); + expect(earlierDate.getDate()).to.equal(30); + expect(earlierDate.getHours()).to.equal(11); + expect(earlierDate.getMinutes()).to.equal(37); + expect(earlierDate.getSeconds()).to.equal(10); + + expect(laterDate.getFullYear()).to.equal(2021); + expect(laterDate.getMonth()).to.equal(0); + expect(laterDate.getDate()).to.equal(5); + expect(laterDate.getHours()).to.equal(17); + expect(laterDate.getMinutes()).to.equal(37); + expect(laterDate.getSeconds()).to.equal(10); + }); + + it('should modify days', () => { + const initialDate = new Date('2021-01-01 13:37:10'); + const earlierDate = date.dateByAddingComponent(initialDate, date.DateComponent.day, -50); + const laterDate = date.dateByAddingComponent(initialDate, date.DateComponent.day, 100); + + expect(earlierDate.getFullYear()).to.equal(2020); + expect(earlierDate.getMonth()).to.equal(10); + expect(earlierDate.getDate()).to.equal(12); + expect(earlierDate.getHours()).to.equal(13); + expect(earlierDate.getMinutes()).to.equal(37); + expect(earlierDate.getSeconds()).to.equal(10); + + expect(laterDate.getFullYear()).to.equal(2021); + expect(laterDate.getMonth()).to.equal(3); + expect(laterDate.getDate()).to.equal(11); + expect(laterDate.getHours()).to.equal(13); + expect(laterDate.getMinutes()).to.equal(37); + expect(laterDate.getSeconds()).to.equal(10); + }); + + it('should calculate positive difference between dates', () => { + const diff1 = new date.DateDiff('2021-01-14 13:37:10', '2021-02-01 14:40:12'); + expect(diff1.years).to.equal(0); + expect(diff1.months).to.equal(0); + expect(diff1.days).to.equal(18); + expect(diff1.hours).to.equal(diff1.days * 24 + 1); + expect(diff1.minutes).to.equal(diff1.hours * 60 + 3); + expect(diff1.seconds).to.equal(diff1.minutes * 60 + 2); + + const diff2 = new date.DateDiff('2021-01-14 13:37:10', '2021-02-14 14:40:12'); + expect(diff2.years).to.equal(0); + expect(diff2.months).to.equal(1); + expect(diff2.days).to.equal(31); + expect(diff2.hours).to.equal(diff2.days * 24 + 1); + expect(diff2.minutes).to.equal(diff2.hours * 60 + 3); + expect(diff2.seconds).to.equal(diff2.minutes * 60 + 2); + + const diff3 = new date.DateDiff('2021-01-14 13:37:10', '2022-01-14 13:37:09'); + expect(diff3.years).to.equal(0); + expect(diff3.months).to.equal(11); + expect(diff3.days).to.equal(364); + expect(diff3.hours).to.equal(diff3.days * 24 + 23); + expect(diff3.minutes).to.equal(diff3.hours * 60 + 59); + expect(diff3.seconds).to.equal(diff3.minutes * 60 + 59); + }); + + it('should calculate negative difference between dates', () => { + const diff1 = new date.DateDiff('2021-02-01 14:40:12', '2021-01-14 13:37:10'); + expect(diff1.years).to.equal(0); + expect(diff1.months).to.equal(0); + expect(diff1.days).to.equal(-18, 'aa'); + expect(diff1.hours).to.equal(diff1.days * 24 - 1); + expect(diff1.minutes).to.equal(diff1.hours * 60 - 3); + expect(diff1.seconds).to.equal(diff1.minutes * 60 - 2); + }); + + it('should format positive difference as string', () => { + const diff1 = date.formatRelativeDate('2021-01-01 13:37:10', '2021-01-01 13:37:20'); + expect(diff1).to.equal('less than a day'); + + const diff2 = date.formatRelativeDate('2021-01-01 13:37:10', '2021-01-02 13:37:20'); + expect(diff2).to.equal('1 day'); + + const diff3 = date.formatRelativeDate('2021-01-01 13:37:10', '2021-02-25 13:37:20'); + expect(diff3).to.equal('55 days'); + + const diff4 = date.formatRelativeDate('2021-01-01 13:37:10', '2021-04-25 13:37:20'); + expect(diff4).to.equal('3 months'); + + const diff5 = date.formatRelativeDate('2021-01-01 13:37:10', '2031-04-25 13:37:20'); + expect(diff5).to.equal('10 years'); + }); + + it('should format positive difference as string suffixed with "left"', () => { + const diff1 = date.formatRelativeDate('2021-01-01 13:37:10', '2021-01-01 13:37:20', true); + expect(diff1).to.equal('less than a day left'); + + const diff2 = date.formatRelativeDate('2021-01-01 13:37:10', '2021-01-02 13:37:20', true); + expect(diff2).to.equal('1 day left'); + + const diff3 = date.formatRelativeDate('2021-01-01 13:37:10', '2021-02-25 13:37:20', true); + expect(diff3).to.equal('55 days left'); + + const diff4 = date.formatRelativeDate('2021-01-01 13:37:10', '2021-04-25 13:37:20', true); + expect(diff4).to.equal('3 months left'); + + const diff5 = date.formatRelativeDate('2021-01-01 13:37:10', '2031-04-25 13:37:20', true); + expect(diff5).to.equal('10 years left'); + }); + + it('should format negative difference as string', () => { + const diff1 = date.formatRelativeDate('2021-01-01 13:37:20', '2021-01-01 13:37:10', true); + expect(diff1).to.equal('less than a minute ago'); + + const diff2 = date.formatRelativeDate('2021-01-02 13:37:20', '2021-01-01 13:37:10', true); + expect(diff2).to.equal('a day ago'); + + const diff3 = date.formatRelativeDate('2021-02-25 13:37:20', '2021-01-01 13:37:10', true); + expect(diff3).to.equal('a month ago'); + + const diff4 = date.formatRelativeDate('2021-04-25 13:37:20', '2021-01-01 13:37:10', true); + expect(diff4).to.equal('3 months ago'); + + const diff5 = date.formatRelativeDate('2031-04-25 13:37:20', '2021-01-01 13:37:10', true); + expect(diff5).to.equal('10 years ago'); + }); +}); |
