From 24244d8def625092f4af7c66efa74c073b29cc70 Mon Sep 17 00:00:00 2001 From: Herman Ho Date: Thu, 15 Aug 2024 22:44:08 +0100 Subject: [PATCH 1/5] fix: depedency packages update eslint to v9 --- .eslintrc.json | 50 ----- eslint.config.mjs | 53 +++++ package-lock.json | 543 +++++++++++++++++++++------------------------- package.json | 19 +- 4 files changed, 317 insertions(+), 348 deletions(-) delete mode 100644 .eslintrc.json create mode 100644 eslint.config.mjs diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index b958c59..0000000 --- a/.eslintrc.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "root": true, - "extends": [ - "eslint:recommended", - "plugin:jsdoc/recommended", - "plugin:jsdoc/recommended-typescript-flavor" - ], - "plugins": [ - "jsdoc" - ], - "env": { - "browser": true, - "es2023": true, - "node": true - }, - "globals": { - "config": true, - "Log": true, - "MM": true, - "Module": true, - "moment": true - }, - "parserOptions": { - "sourceType": "module", - "ecmaVersion": "latest", - "ecmaFeatures": { - "globalReturn": true - } - }, - "rules": { - "comma-dangle": [ - "error", - { - "arrays": "always-multiline", - "objects": "always-multiline", - "imports": "always-multiline", - "exports": "always-multiline", - "functions": "only-multiline" - } - ], - "eqeqeq": "error", - "no-prototype-builtins": "off", - "no-unused-vars": "off", - "no-useless-return": "error", - "no-var": "error", - "jsdoc/require-returns": "off", - "jsdoc/require-param-description": "off", - "semi": "error" - } -} \ No newline at end of file diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..dbaeb54 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,53 @@ +import jsdoc from "eslint-plugin-jsdoc"; +import globals from "globals"; +import js from "@eslint/js"; + +export default [ + js.configs.recommended, + jsdoc.configs['flat/recommended'], + jsdoc.configs['flat/recommended-typescript-flavor'], + { + plugins: { + jsdoc, + }, + + languageOptions: { + globals: { + ...globals.browser, + ...globals.node, + Log: true, + MM: true, + Module: true, + moment: true, + }, + + ecmaVersion: 13, + sourceType: "module", + + parserOptions: { + ecmaFeatures: { + globalReturn: true, + }, + }, + }, + + rules: { + "comma-dangle": ["error", { + arrays: "always-multiline", + objects: "always-multiline", + imports: "always-multiline", + exports: "always-multiline", + functions: "only-multiline", + }], + + eqeqeq: "error", + "no-prototype-builtins": "off", + "no-unused-vars": "off", + "no-useless-return": "error", + "no-var": "error", + "jsdoc/require-returns": "off", + "jsdoc/require-param-description": "off", + semi: "error", + }, + }, +]; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index b347feb..2a9510b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,15 +9,18 @@ "version": "1.0.1", "license": "MIT", "dependencies": { - "@azure/msal-node": "^2.9.2", + "@azure/msal-node": "^2.13.0", "@microsoft/microsoft-graph-client": "^3.0.7", "heic-convert": "^2.1.0", "moment": "^2.30.1" }, "devDependencies": { - "@microsoft/microsoft-graph-types": "^2.40.0", - "eslint": "^8.56.0", - "eslint-plugin-jsdoc": "^48.0.4" + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "^9.9.0", + "@types/magicmirror-module": "^2.16.5", + "eslint": "^9.9.0", + "eslint-plugin-jsdoc": "^50.2.2", + "globals": "^15.9.0" }, "engines": { "node": ">=18" @@ -33,19 +36,19 @@ } }, "node_modules/@azure/msal-common": { - "version": "14.12.0", - "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-14.12.0.tgz", - "integrity": "sha512-IDDXmzfdwmDkv4SSmMEyAniJf6fDu3FJ7ncOjlxkDuT85uSnLEhZi3fGZpoR7T4XZpOMx9teM9GXBgrfJgyeBw==", + "version": "14.14.1", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-14.14.1.tgz", + "integrity": "sha512-2Q3tqNz/PZLfSr8BvcHZVpRRfSn4MjGSqjj9J+HlBsmbf1Uu4P0WeXnemjTJwwx9KrmplsrN3UkZ/LPOR720rw==", "engines": { "node": ">=0.8.0" } }, "node_modules/@azure/msal-node": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-2.9.2.tgz", - "integrity": "sha512-8tvi6Cos3m+0KmRbPjgkySXi+UQU/QiuVRFnrxIwt5xZlEEFa69O04RTaNESGgImyBBlYbo2mfE8/U8Bbdk1WQ==", + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-2.13.0.tgz", + "integrity": "sha512-DhP97ycs7qlCVzzzWGzJiwAFyFj5okno74E4FUZ61oCLfKh4IxA1kxirqzrWuYZWpBe9HVPL6GA4NvmlEOBN5Q==", "dependencies": { - "@azure/msal-common": "14.12.0", + "@azure/msal-common": "14.14.1", "jsonwebtoken": "^9.0.0", "uuid": "^8.3.0" }, @@ -65,14 +68,14 @@ } }, "node_modules/@es-joy/jsdoccomment": { - "version": "0.41.0", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.41.0.tgz", - "integrity": "sha512-aKUhyn1QI5Ksbqcr3fFJj16p99QdjUxXAEuFst1Z47DRyoiMwivIH9MV/ARcJOCXVjPfjITciej8ZD2O/6qUmw==", + "version": "0.48.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.48.0.tgz", + "integrity": "sha512-G6QUWIcC+KvSwXNsJyDTHvqUdNoAVJPPgkc3+Uk4WBKqZvoXhlvazOgm9aL0HwihJLQf0l+tOE2UFzXBqCqgDw==", "dev": true, "dependencies": { "comment-parser": "1.4.1", - "esquery": "^1.5.0", - "jsdoc-type-pratt-parser": "~4.0.0" + "esquery": "^1.6.0", + "jsdoc-type-pratt-parser": "~4.1.0" }, "engines": { "node": ">=16" @@ -94,24 +97,38 @@ } }, "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==", + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", + "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, + "node_modules/@eslint/config-array": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.17.1.tgz", + "integrity": "sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==", + "dev": true, + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", + "espree": "^10.0.1", + "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -119,33 +136,40 @@ "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@eslint/js": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", - "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", + "version": "9.9.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.9.0.tgz", + "integrity": "sha512-hhetes6ZHP3BlXLxmd8K2SNgkhNSi+UcecbnwWKwpP7kyi/uC75DJ1lOOBO3xrC4jyojtGE3YxKZPHfk4yrgug==", "dev": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.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==", + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, "engines": { - "node": ">=10.10.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@humanwhocodes/module-importer": { @@ -161,11 +185,18 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", - "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", - "dev": true + "node_modules/@humanwhocodes/retry": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", + "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, "node_modules/@microsoft/microsoft-graph-client": { "version": "3.0.7", @@ -193,17 +224,6 @@ } } }, - "node_modules/@microsoft/microsoft-graph-client/node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" - }, - "node_modules/@microsoft/microsoft-graph-types": { - "version": "2.40.0", - "resolved": "https://registry.npmjs.org/@microsoft/microsoft-graph-types/-/microsoft-graph-types-2.40.0.tgz", - "integrity": "sha512-1fcPVrB/NkbNcGNfCy+Cgnvwxt6/sbIEEFgZHFBJ670zYLegENYJF8qMo7x3LqBjWX2/Eneq5BVVRCLTmlJN+g==", - "dev": true - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -239,16 +259,28 @@ "node": ">= 8" } }, - "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==", + "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/@types/magicmirror-module": { + "version": "2.16.5", + "resolved": "https://registry.npmjs.org/@types/magicmirror-module/-/magicmirror-module-2.16.5.tgz", + "integrity": "sha512-VXVvOG3bT2cd7+uxuVzt28ybyjz/MtlZuOMAv8rApQ6QcM81T8TDujgBayR1DLuPer3hwHPQkUN7Du8xhUE2Kg==", "dev": true }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -342,18 +374,6 @@ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" }, - "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/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -427,9 +447,9 @@ } }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -449,18 +469,6 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, - "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/ecdsa-sig-formatter": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", @@ -469,6 +477,12 @@ "safe-buffer": "^5.0.1" } }, + "node_modules/es-module-lexer": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", + "dev": true + }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -482,41 +496,37 @@ } }, "node_modules/eslint": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", - "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", + "version": "9.9.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.9.0.tgz", + "integrity": "sha512-JfiKJrbx0506OEerjK2Y1QlldtBxkAlLxT5OEcRF8uaQ86noDe2k31Vw9rnSWv+MXZHj7OOUV/dA0AhdLFcyvA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.56.0", - "@humanwhocodes/config-array": "^0.11.13", + "@eslint-community/regexpp": "^4.11.0", + "@eslint/config-array": "^0.17.1", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.9.0", "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.3.0", "@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", + "eslint-scope": "^8.0.2", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.1.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^8.0.0", "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", @@ -530,27 +540,37 @@ "eslint": "bin/eslint.js" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, "node_modules/eslint-plugin-jsdoc": { - "version": "48.0.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.0.4.tgz", - "integrity": "sha512-A0cH+5svWPXzGZszBjXA1t0aAqVGS+/x3i02KFmb73rU0iMLnadEcVWcD/dGBZHIfAMKr3YpWh58f6wn4N909w==", + "version": "50.2.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-50.2.2.tgz", + "integrity": "sha512-i0ZMWA199DG7sjxlzXn5AeYZxpRfMJjDPUl7lL9eJJX8TPRoIaxJU4ys/joP5faM5AXE1eqW/dslCj3uj4Nqpg==", "dev": true, "dependencies": { - "@es-joy/jsdoccomment": "~0.41.0", + "@es-joy/jsdoccomment": "~0.48.0", "are-docs-informative": "^0.0.2", "comment-parser": "1.4.1", - "debug": "^4.3.4", + "debug": "^4.3.6", "escape-string-regexp": "^4.0.0", - "esquery": "^1.5.0", - "is-builtin-module": "^3.2.1", - "semver": "^7.5.4", - "spdx-expression-parse": "^4.0.0" + "espree": "^10.1.0", + "esquery": "^1.6.0", + "parse-imports": "^2.1.1", + "semver": "^7.6.3", + "spdx-expression-parse": "^4.0.0", + "synckit": "^0.9.1" }, "engines": { "node": ">=18" @@ -560,16 +580,16 @@ } }, "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==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz", + "integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -587,27 +607,51 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "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==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", "dev": true, "dependencies": { - "acorn": "^8.9.0", + "acorn": "^8.12.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "eslint-visitor-keys": "^4.0.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, "dependencies": { "estraverse": "^5.1.0" @@ -674,15 +718,15 @@ } }, "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==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "dependencies": { - "flat-cache": "^3.0.4" + "flat-cache": "^4.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16.0.0" } }, "node_modules/find-up": { @@ -702,50 +746,24 @@ } }, "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" + "flatted": "^3.2.9", + "keyv": "^4.5.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16" } }, "node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", - "dev": true - }, - "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==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true }, - "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": { - "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/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -759,26 +777,17 @@ } }, "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "version": "15.9.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.9.0.tgz", + "integrity": "sha512-SmSKyLLKFbSr6rptvP8izbyxJL4ILwqO9Jg23UA0sDlGlu58V59D1//I3vlc0KJphVdUR7vMjHIplYnzBxorQA==", "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "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/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -846,37 +855,6 @@ "node": ">=0.8.19" } }, - "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==", - "dev": true, - "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==", - "dev": true - }, - "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": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -931,14 +909,20 @@ } }, "node_modules/jsdoc-type-pratt-parser": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", - "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.1.0.tgz", + "integrity": "sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==", "dev": true, "engines": { "node": ">=12.0.0" } }, + "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-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -991,6 +975,15 @@ "safe-buffer": "^5.0.1" } }, + "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": { + "json-buffer": "3.0.1" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -1068,17 +1061,6 @@ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" }, - "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==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -1110,15 +1092,6 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "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==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, "node_modules/optionator": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", @@ -1178,6 +1151,19 @@ "node": ">=6" } }, + "node_modules/parse-imports": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/parse-imports/-/parse-imports-2.1.1.tgz", + "integrity": "sha512-TDT4HqzUiTMO1wJRwg/t/hYk8Wdp3iF/ToMIlAoVQfL1Xs/sTxq1dKWSMjMbQmIarfWKymOyly40+zmPHXMqCA==", + "dev": true, + "dependencies": { + "es-module-lexer": "^1.5.3", + "slashes": "^3.0.12" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -1187,15 +1173,6 @@ "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==", - "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", @@ -1275,21 +1252,6 @@ "node": ">=0.10.0" } }, - "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" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -1333,12 +1295,9 @@ ] }, "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dependencies": { - "lru-cache": "^6.0.0" - }, + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "bin": { "semver": "bin/semver.js" }, @@ -1367,6 +1326,12 @@ "node": ">=8" } }, + "node_modules/slashes": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/slashes/-/slashes-3.0.12.tgz", + "integrity": "sha512-Q9VME8WyGkc7pJf6QEkj3wE+2CnvZMI+XJhwdTPR8Z/kWQRXi7boAWLDibRPyHRTUTPx5FaU7MsyrjI3yLB4HA==", + "dev": true + }, "node_modules/spdx-exceptions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", @@ -1425,12 +1390,33 @@ "node": ">=8" } }, + "node_modules/synckit": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.1.tgz", + "integrity": "sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==", + "dev": true, + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -1443,18 +1429,6 @@ "node": ">= 0.8.0" } }, - "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": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -1487,17 +1461,6 @@ "node": ">= 8" } }, - "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==", - "dev": true - }, - "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/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 94bc357..8131637 100644 --- a/package.json +++ b/package.json @@ -4,9 +4,9 @@ "description": "MagicMirror² module to display your photos from OneDrive.", "license": "MIT", "author": "hermanho", - "contributors": [ - "https://github.com/hermanho/MMM-OneDrive/graphs/contributors" - ], + "contributors": [ + "https://github.com/hermanho/MMM-OneDrive/graphs/contributors" + ], "scripts": { "install-prod": "npm install --no-audit --no-fund --no-update-notifier --only=prod --omit=dev", "lint:js": "eslint . --fix" @@ -20,17 +20,20 @@ "OneDrive" ], "dependencies": { - "@azure/msal-node": "^2.9.2", + "@azure/msal-node": "^2.13.0", "@microsoft/microsoft-graph-client": "^3.0.7", "heic-convert": "^2.1.0", "moment": "^2.30.1" }, "devDependencies": { - "@microsoft/microsoft-graph-types": "^2.40.0", - "eslint": "^8.56.0", - "eslint-plugin-jsdoc": "^48.0.4" + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "^9.9.0", + "@types/magicmirror-module": "^2.16.5", + "eslint": "^9.9.0", + "eslint-plugin-jsdoc": "^50.2.2", + "globals": "^15.9.0" }, "engines": { "node": ">=18" } -} \ No newline at end of file +} From 57ee5d194a72bd48dfac6ee1e26c1905891e9d62 Mon Sep 17 00:00:00 2001 From: Herman Ho Date: Thu, 15 Aug 2024 23:31:19 +0100 Subject: [PATCH 2/5] feat: album name can be regex --- MMM-OneDrive.js | 40 ++++-- OneDrivePhotos.js | 11 +- node_helper.js | 212 +++++++++++++++++++------------ package-lock.json | 24 +++- package.json | 5 +- types/microsoft-graph-types.d.ts | 8 ++ type.d.ts => types/type.d.ts | 0 7 files changed, 198 insertions(+), 102 deletions(-) create mode 100644 types/microsoft-graph-types.d.ts rename type.d.ts => types/type.d.ts (100%) diff --git a/MMM-OneDrive.js b/MMM-OneDrive.js index e02a2ee..17fecf3 100644 --- a/MMM-OneDrive.js +++ b/MMM-OneDrive.js @@ -42,7 +42,19 @@ Module.register("MMM-OneDrive", { this.firstScan = true; if (this.config.updateInterval < 1000 * 10) this.config.updateInterval = 1000 * 10; this.config.condition = Object.assign({}, this.defaults.condition, this.config.condition); - this.sendSocketNotification("INIT", this.config); + + const config = { ...this.config }; + for (let i = 0; i < config.albums.length; i++) { + const album = config.albums[i]; + if (album instanceof RegExp) { + config.albums[i] = { + source: album.source, + flags: album.flags, + }; + } + } + + this.sendSocketNotification("INIT", config); this.dynamicPosition = 0; }, @@ -53,12 +65,17 @@ Module.register("MMM-OneDrive", { if (noti === "INITIALIZED") { this.albums = payload; //set up timer once initialized, more robust against faults - this.updateTimer = setInterval(() => { - this.updatePhotos(); - }, this.config.updateInterval); + if (!this.updateTimer || this.updateTimer === null) { + Log.info("Start timer for updating photos."); + this.updateTimer = setInterval(() => { + this.updatePhotos(); + }, this.config.updateInterval); + } + } + if (noti === "UPDATE_ALBUMS") { + this.albums = payload; } if (noti === "MORE_PICS") { - console.log("MORE_PICSMORE_PICSMORE_PICS", payload); if (payload && Array.isArray(payload) && payload.length > 0) this.needMorePicsFlag = false; this.scanned = payload; this.index = 0; @@ -91,6 +108,7 @@ Module.register("MMM-OneDrive", { }, updatePhotos: function (dir = 0) { + Log.debug("Updating photos.."); this.firstScan = false; if (this.scanned.length === 0) { @@ -153,15 +171,12 @@ Module.register("MMM-OneDrive", { let current = document.getElementById("ONEDRIVE_PHOTO_CURRENT"); current.textContent = ""; //current.classList.remove("animated") - let dom = document.getElementById("ONEDRIVE_PHOTO"); + // let dom = document.getElementById("ONEDRIVE_PHOTO"); back.style.backgroundImage = `url(${url})`; current.style.backgroundImage = `url(${url})`; current.classList.add("animated"); - let info = document.getElementById("ONEDRIVE_PHOTO_INFO"); - let album = this.albums.find((a) => { - if (a.id === target._albumId) return true; - return false; - }); + const info = document.getElementById("ONEDRIVE_PHOTO_INFO"); + const album = this.albums.find((a) => a.id === target._albumId); if (this.config.autoInfoPosition) { let op = (album, target) => { let now = new Date(); @@ -177,7 +192,7 @@ Module.register("MMM-OneDrive", { if (typeof this.config.autoInfoPosition === "function") { op = this.config.autoInfoPosition; } - let [top, left, bottom, right] = op(album, target); + const [top, left, bottom, right] = op(album, target); info.style.setProperty("--top", top); info.style.setProperty("--left", left); info.style.setProperty("--bottom", bottom); @@ -200,7 +215,6 @@ Module.register("MMM-OneDrive", { infoText.appendChild(albumTitle); infoText.appendChild(photoTime); info.appendChild(infoText); - this.sendSocketNotification("IMAGE_LOADED", { id: target.id, index: this.index }); }, diff --git a/OneDrivePhotos.js b/OneDrivePhotos.js index b6d7b8c..bfca42a 100644 --- a/OneDrivePhotos.js +++ b/OneDrivePhotos.js @@ -19,8 +19,6 @@ const chunk = (arr, size) => class Auth extends EventEmitter { #debug = {}; - /** @type {import("@azure/msal-node").AccountInfo} */ - #msalAccount = null; /** @type {AuthProvider} */ #authProvider = null; @@ -42,12 +40,9 @@ class Auth extends EventEmitter { } this.#authProvider = new AuthProvider(msalConfig); console.log("[ONEDRIVE:CORE] Auth -> AuthProvider created"); - // this.#msalAccount = await this.#authProvider.login(); - // console.log("[ONEDRIVE:CORE] AuthProvider login done"); } get AuthProvider() { return this.#authProvider; } - // get AccountInfo() { return this.#msalAccount }; } class OneDrivePhotos { @@ -129,13 +124,13 @@ class OneDrivePhotos { async getAlbumType() { await this.onAuthReady(); let url = protectedResources.listAllAlbums.endpoint.replace("$$userId$$", this.#userId); - /** @type {import("@microsoft/microsoft-graph-types").DriveItem[]} */ + /** @type {microsoftgraph.DriveItem[]} */ let list = []; let found = 0; /** * * @param {string} pageUrl - * @returns {import("@microsoft/microsoft-graph-types").DriveItem[]} DriveItem + * @returns {microsoftgraph.DriveItem[]} DriveItem */ const getAlbum = async (pageUrl) => { this.log("Getting Album info chunks."); @@ -191,7 +186,7 @@ class OneDrivePhotos { /** @type {import("@microsoft/microsoft-graph-client").PageCollection} */ let response = await this.request(pageUrl, "get"); if (Array.isArray(response.value)) { - /** @type {import("@microsoft/microsoft-graph-types").DriveItem[]} */ + /** @type {microsoftgraph.DriveItem[]} */ const childrenItems = response.value; for (let item of childrenItems) { /** @type {OneDriveMediaItem} */ diff --git a/node_helper.js b/node_helper.js index ef6dde1..cd84129 100644 --- a/node_helper.js +++ b/node_helper.js @@ -7,7 +7,10 @@ const moment = require("moment"); const OneDrivePhotos = require("./OneDrivePhotos.js"); const { Readable } = require("stream"); const { finished } = require("stream/promises"); +const { RE2 } = require("re2-wasm"); +const { Set } = require('immutable'); const NodeHelper = require("node_helper"); +const Log = require("logger"); const { shuffle } = require("./shuffle.js"); const { error_to_string } = require("./error_to_string"); const sleep = require("./sleep.js"); @@ -22,8 +25,8 @@ module.exports = NodeHelper.create({ this.scanInterval = 1000 * 60 * 55; // fixed. no longer needs to be fixed this.config = {}; this.scanTimer = null; - /** @type {import("@microsoft/microsoft-graph-types").DriveItem} */ - this.albums = []; + /** @type {microsoftgraph.DriveItem} */ + this.selecetedAlbums = []; /** @type {OneDriveMediaItem[]} */ this.localPhotoList = []; this.localPhotoPntr = 0; @@ -31,6 +34,9 @@ module.exports = NodeHelper.create({ this.queue = null; this.uploadAlbumId; this.initializeTimer = null; + + this.CACHE_ALBUMNS_PATH = path.resolve(this.path, "cache", "selecetedAlbumsCache.json"); + this.CACHE_PHOTOLIST_PATH = path.resolve(this.path, "cache", "photoListCache.json"); }, socketNotificationReceived: function (notification, payload) { @@ -44,49 +50,49 @@ module.exports = NodeHelper.create({ case "IMAGE_LOAD_FAIL": { const { url, event, source, lineno, colno, error } = payload; - console.error("[ONEDRIVE] hidden.onerror", { event, source, lineno, colno }); + Log.error("[ONEDRIVE] hidden.onerror", { event, source, lineno, colno }); if (error) { - console.error("[ONEDRIVE] hidden.onerror error", error.message, error.name, error.stack); + Log.error("[ONEDRIVE] hidden.onerror error", error.message, error.name, error.stack); } - console.error("Image loading fails. Check your network.:", url); + Log.error("Image loading fails. Check your network.:", url); this.prepAndSendChunk(Math.ceil((20 * 60 * 1000) / this.config.updateInterval)).then(); // 20min * 60s * 1000ms / updateinterval in ms } break; case "IMAGE_LOADED": { const { id, index } = payload; - this.log("Image loaded:", `${this.lastLocalPhotoPntr} + ${index}`, id, payload); + this.log_debug("Image loaded:", `${this.lastLocalPhotoPntr} + ${index}`, id); } break; case "NEED_MORE_PICS": { - this.log("Used last pic in list"); + Log.info("Used last pic in list"); this.prepAndSendChunk(Math.ceil((20 * 60 * 1000) / this.config.updateInterval)).then(); // 20min * 60s * 1000ms / updateinterval in ms } break; case "MODULE_SUSPENDED_SKIP_UPDATE": - this.log("Module is suspended so skip the UI update"); + this.log_debug("Module is suspended so skip the UI update"); break; default: - this.log("Unknown notification received", notification); + Log.error("Unknown notification received", notification); } }, - log: function (...args) { - if (this.debug) console.log("[ONEDRIVE] [node_helper]", ...args); + log_debug: function (...args) { + if (this.debug) Log.info("[ONEDRIVE] [node_helper]", ...args); }, upload: async function (path) { if (!this.uploadAlbumId) { - this.log("No uploadable album exists."); + Log.info("No uploadable album exists."); return; } let uploadToken = await OneDrivePhoto.upload(path); if (uploadToken) { - let result = await OneDrivePhoto.create(uploadToken, this.uploadAlbumId); - this.log("Upload completed."); + await OneDrivePhoto.create(uploadToken, this.uploadAlbumId); + Log.info("Upload completed."); } else { - this.log("Upload Fails."); + Log.error("Upload Fails."); } }, @@ -98,6 +104,17 @@ module.exports = NodeHelper.create({ debug: this.debug, config: config, }); + + this.albumsFilters = []; + for (let album of config.albums) { + if (album.hasOwnProperty("source") && album.hasOwnProperty("flags")) { + this.albumsFilters.push(new RE2(album.source, album.flags + 'u')); + } else { + this.albumsFilters.push(album); + } + } + delete this.config.albums; + this.tryToIntitialize(); }, @@ -111,55 +128,38 @@ module.exports = NodeHelper.create({ 1 * 60 * 1000, ); - this.log("Starting Initialization"); - this.log("Getting album list"); - let albums = await this.getAlbums(); - for (let ta of this.config.albums) { - let matched = albums.find((a) => { - if (ta === a.name) return true; - return false; - }); - let exists = function (albums, album) { - return albums.some((expected) => album.id === expected.id); - }; - if (!matched) { - this.log(`Can't find "${ta}" in your album list.`); - } else if (!exists(this.albums, matched)) { - this.albums.push(matched); + Log.info("Starting Initialization"); + + //load cached album list - if available + if (fs.existsSync(this.CACHE_ALBUMNS_PATH)) { + try { + const data = await readFile(this.CACHE_ALBUMNS_PATH, "utf-8"); + this.selecetedAlbums = JSON.parse(data.toString()); + this.log_debug("successfully loaded selecetedAlbums"); + this.sendSocketNotification("UPDATE_ALBUMS", this.selecetedAlbums); // for fast startup + } catch (err) { + Log.error("unable to load selecetedAlbums cache", err); } } - this.log("Finish Album scanning. Properly scanned :", this.albums.length); - for (let a of this.albums) { - let url = a.coverPhotoBaseUrl; - let fpath = path.join(this.path, "cache", a.id); - let file = fs.createWriteStream(fpath); - const response = await fetch(url); - await finished(Readable.fromWeb(response.body).pipe(file)); - a.title = a.name; - } - - this.log("Initialized"); - this.sendSocketNotification("INITIALIZED", this.albums); //load cached list - if available - const cacheFilename = this.path + "/cache/photoListCache.json"; - if (fs.existsSynccacheFilename) { + if (fs.existsSync(this.CACHE_PHOTOLIST_PATH)) { try { - const data = await readFile(cacheFilename, "utf-8"); + const data = await readFile(this.CACHE_PHOTOLIST_PATH, "utf-8"); this.localPhotoList = JSON.parse(data.toString()); if (this.config.sort === "random") { shuffle(this.localPhotoList); } - this.log("successfully loaded cache of ", this.localPhotoList.length, " photos"); - await this.prepAndSendChunk(5); //only 5 for extra fast startup + this.log_debug("successfully loaded photo list cache of ", this.localPhotoList.length, " photos"); + await this.prepAndSendChunk(5); // only 5 for extra fast startup } catch (err) { - this.log("unable to load cache", err); + Log.error("unable to load photo list cache", err); } } - this.log("Initialization complete!"); + Log.info("Initialization complete!"); clearTimeout(this.initializeTimer); - this.log("Start first scanning."); + Log.info("Start first scanning."); this.startScanning(); }, @@ -169,7 +169,7 @@ module.exports = NodeHelper.create({ // await sleep(30000 - (new Date() - this.lastScanTime)); } this.lastScanTime = new Date(); - this.log("prepAndSendChunk"); + this.log_debug("prepAndSendChunk"); try { //find which ones to refresh @@ -178,7 +178,7 @@ module.exports = NodeHelper.create({ this.lastLocalPhotoPntr = 0; } let numItemsToRefresh = Math.min(desiredChunk, this.localPhotoList.length - this.localPhotoPntr, 20); //20 is api limit - this.log("num to ref: ", numItemsToRefresh, ", DesChunk: ", desiredChunk, ", totalLength: ", this.localPhotoList.length, ", Pntr: ", this.localPhotoPntr); + this.log_debug("num to ref: ", numItemsToRefresh, ", DesChunk: ", desiredChunk, ", totalLength: ", this.localPhotoList.length, ", Pntr: ", this.localPhotoPntr); const cachePath = this.path + "/cache/"; @@ -198,51 +198,102 @@ module.exports = NodeHelper.create({ // update pointer this.lastLocalPhotoPntr = this.localPhotoPntr; this.localPhotoPntr = this.localPhotoPntr + list.length; - this.log("refreshed: ", list.length, ", totalLength: ", this.localPhotoList.length, ", Pntr: ", this.localPhotoPntr); + this.log_debug("refreshed: ", list.length, ", totalLength: ", this.localPhotoList.length, ", Pntr: ", this.localPhotoPntr); } else { - this.log("couldn't send ", list.length, " pics"); + Log.error("couldn't send ", list.length, " pics"); } } catch (err) { - this.log("failed to refresh and send chunk: "); - this.log(error_to_string(err)); + Log.error("failed to refresh and send chunk: "); + Log.error(error_to_string(err)); } }, + /** @returns {microsoftgraph.DriveItem[]} */ getAlbums: async function () { try { let r = await OneDrivePhoto.getAlbums(); + r.forEach(item => { + item.title = item.name; + }); return r; } catch (err) { - this.log(error_to_string(err)); + Log.error(error_to_string(err)); } }, startScanning: function () { + const fn = () => { + const nextScanDt = new Date(Date.now() + this.scanInterval); + this.scanJob().then(() => { + Log.info("Next scan will be at", nextScanDt); + }); + }; // set up interval, then 1 fail won't stop future scans - this.scanTimer = setInterval(() => { - this.scanJob(); - }, this.scanInterval); - + this.scanTimer = setInterval(fn, this.scanInterval); // call for first time - this.scanJob(); + fn(); }, scanJob: async function () { - this.log("Start Album scanning"); + Log.info("Start Album scanning"); this.queue = null; + await this.getAlbumList(); try { - if (this.albums.length > 0) { - await this.getImageList(); + if (this.selecetedAlbums.length > 0) { + this.photos = await this.getImageList(); return true; } else { - this.log("There is no album to get photos."); - this.sendSocketNotification("ERROR", "There is no album to get photos."); + Log.warn("There is no album to get photos."); + // this.sendSocketNotification("ERROR", "There is no album to get photos."); return false; } } catch (err) { - this.log(error_to_string(err)); + Log.error(error_to_string(err)); } }, + getAlbumList: async function () { + Log.info("Getting album list"); + /** + * @type {microsoftgraph.DriveItem[]} + */ + let albums = await this.getAlbums(); + /** + * @type {microsoftgraph.DriveItem[]} + */ + let selecetedAlbums = []; + for (let ta of this.albumsFilters) { + const matches = albums.filter((a) => { + if (ta instanceof RE2) { + Log.debug(`RE2 match ${ta.source} -> '${a.title}' : ${ta.test(a.title)}`); + return ta.test(a.title); + } + else { + return ta === a.title; + } + }); + if (matches.length === 0) { + Log.warn(`Can't find "${ta instanceof RE2 ? ta.source : ta}" in your album list.`); + } + else { + selecetedAlbums.push(...matches); + } + } + selecetedAlbums = Set(selecetedAlbums).toArray(); + Log.info("Finish Album scanning. Properly scanned :", selecetedAlbums.length); + Log.info("Albums:", selecetedAlbums.map((a) => a.title).join(", ")); + this.writeFileSafe(this.CACHE_ALBUMNS_PATH, JSON.stringify(selecetedAlbums, null, 4), "Album list cache"); + + for (let a of selecetedAlbums) { + let url = a.coverPhotoBaseUrl; + let fpath = path.join(this.path, "cache", a.id); + let file = fs.createWriteStream(fpath); + const response = await fetch(url); + await finished(Readable.fromWeb(response.body).pipe(file)); + } + this.selecetedAlbums = selecetedAlbums; + Log.info("getAlbumList done"); + this.sendSocketNotification("INITIALIZED", selecetedAlbums); + }, getImageList: async function () { let condition = this.config.condition; @@ -276,13 +327,13 @@ module.exports = NodeHelper.create({ /** @type {OneDriveMediaItem[]} */ let photos = []; try { - for (let album of this.albums) { - this.log(`Prepare to get photo list from '${album.title}'`); + for (let album of this.selecetedAlbums) { + this.log_debug(`Prepare to get photo list from '${album.title}'`); let list = await OneDrivePhoto.getImageFromAlbum(album.id, photoCondition); list.forEach(i => { i._albumTitle = album.title; }); - this.log(`Got ${list.length} photo(s) from '${album.title}'`); + this.log_debug(`Got ${list.length} photo(s) from '${album.title}'`); photos = photos.concat(list); } if (photos.length > 0) { @@ -297,26 +348,29 @@ module.exports = NodeHelper.create({ } else { shuffle(photos); } - this.log(`Total indexed photos: ${photos.length}`); + Log.info(`Total indexed photos: ${photos.length}`); this.localPhotoList = [...photos]; this.localPhotoPntr = 0; this.lastLocalPhotoPntr = 0; this.prepAndSendChunk(50).then(); - try { - await writeFile(this.path + "/cache/photoListCache.json", JSON.stringify(photos, null, 4)); - this.log("Photo list cache saved"); - } catch (err) { - this.log(error_to_string(err)); - } + this.writeFileSafe(this.CACHE_PHOTOLIST_PATH, JSON.stringify(photos, null, 4), "Photo list cache"); } return photos; } catch (err) { - this.log(error_to_string(err)); + Log.error(error_to_string(err)); } }, stop: function () { clearInterval(this.scanTimer); }, + writeFileSafe: async function (filePath, data, fileDescription) { + try { + await writeFile(filePath, data); + this.log_debug(fileDescription + " saved"); + } catch (err) { + Log.error(error_to_string(err)); + } + }, }); diff --git a/package-lock.json b/package-lock.json index 2a9510b..08dc706 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,11 +12,14 @@ "@azure/msal-node": "^2.13.0", "@microsoft/microsoft-graph-client": "^3.0.7", "heic-convert": "^2.1.0", - "moment": "^2.30.1" + "immutable": "^5.0.0-beta.5", + "moment": "^2.30.1", + "re2-wasm": "^1.0.2" }, "devDependencies": { "@eslint/eslintrc": "^3.1.0", "@eslint/js": "^9.9.0", + "@microsoft/microsoft-graph-types": "^2.40.0", "@types/magicmirror-module": "^2.16.5", "eslint": "^9.9.0", "eslint-plugin-jsdoc": "^50.2.2", @@ -224,6 +227,12 @@ } } }, + "node_modules/@microsoft/microsoft-graph-types": { + "version": "2.40.0", + "resolved": "https://registry.npmjs.org/@microsoft/microsoft-graph-types/-/microsoft-graph-types-2.40.0.tgz", + "integrity": "sha512-1fcPVrB/NkbNcGNfCy+Cgnvwxt6/sbIEEFgZHFBJ670zYLegENYJF8qMo7x3LqBjWX2/Eneq5BVVRCLTmlJN+g==", + "dev": true + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -830,6 +839,11 @@ "node": ">= 4" } }, + "node_modules/immutable": { + "version": "5.0.0-rc.1", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.0.0-rc.1.tgz", + "integrity": "sha512-sW2Rt1jlDeEBTqHapJp6owkChOUwoHtbXhDHTa1tXJUl3WuLghuHaxjBZrL0Ih76awAdkcThu0m8QIXYU6nlrw==" + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -1228,6 +1242,14 @@ } ] }, + "node_modules/re2-wasm": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/re2-wasm/-/re2-wasm-1.0.2.tgz", + "integrity": "sha512-VXUdgSiUrE/WZXn6gUIVVIsg0+Hp6VPZPOaHCay+OuFKy6u/8ktmeNEf+U5qSA8jzGGFsg8jrDNu1BeHpz2pJA==", + "engines": { + "node": ">=10" + } + }, "node_modules/regenerator-runtime": { "version": "0.14.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", diff --git a/package.json b/package.json index 8131637..6acc961 100644 --- a/package.json +++ b/package.json @@ -23,11 +23,14 @@ "@azure/msal-node": "^2.13.0", "@microsoft/microsoft-graph-client": "^3.0.7", "heic-convert": "^2.1.0", - "moment": "^2.30.1" + "immutable": "^5.0.0-beta.5", + "moment": "^2.30.1", + "re2-wasm": "^1.0.2" }, "devDependencies": { "@eslint/eslintrc": "^3.1.0", "@eslint/js": "^9.9.0", + "@microsoft/microsoft-graph-types": "^2.40.0", "@types/magicmirror-module": "^2.16.5", "eslint": "^9.9.0", "eslint-plugin-jsdoc": "^50.2.2", diff --git a/types/microsoft-graph-types.d.ts b/types/microsoft-graph-types.d.ts new file mode 100644 index 0000000..940331a --- /dev/null +++ b/types/microsoft-graph-types.d.ts @@ -0,0 +1,8 @@ + +import "@microsoft/microsoft-graph-types"; + +declare namespace microsoftgraph { + interface DriveItem { + title: string; + } +} \ No newline at end of file diff --git a/type.d.ts b/types/type.d.ts similarity index 100% rename from type.d.ts rename to types/type.d.ts From 11aadc84b5419d245dfba985e39c484876823e3b Mon Sep 17 00:00:00 2001 From: Herman Ho Date: Thu, 15 Aug 2024 23:33:15 +0100 Subject: [PATCH 3/5] Update CHANGELOG.md, INSTALL.md, README.md --- CHANGELOG.md | 6 ++++++ INSTALL.md | 14 ++++++++++++-- OneDrivePhotos.js | 11 +++++++---- PhotosConverter.js | 22 ++++++++++++++-------- README.md | 2 +- node_helper.js | 5 ++++- 6 files changed, 44 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e4447e..6fb499f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ # MMM-OneDrive Change Log +**`[1.1.0] - 2024/08/15`** +- Fixed: albumn info did not show when startup caching +- Fixed: depedencies packages update +- Added: Allow regular expression ([RE2 engine](https://github.com/google/re2)) in album names +- Changed: Update README.md and INSTALL.md + **`[1.0.0] - 2023/07/17`** First version diff --git a/INSTALL.md b/INSTALL.md index 4f81293..8533075 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -2,9 +2,10 @@ 1. Install Module + Run the following command. For example, the Magic Mirror directory is `~/MagicMirror`. ```sh cd ~/MagicMirror/modules - git clone https://github.com/hermanho/MMM-OneDrive + git clone https://github.com/hermanho/MMM-OneDrive.git cd MMM-OneDrive npm run install-prod ``` @@ -13,12 +14,21 @@ ```sh cd ~/MagicMirror/modules - git clone https://github.com/hermanho/MMM-OneDrive + git clone https://github.com/hermanho/MMM-OneDrive.git docker exec -it -w /opt/magic_mirror/modules/MMM-OneDrive magic_mirror npm run install-prod ``` 1. Add MMM-OneDrive module config in ~/MagicMirror/config/config.js +## Upgrade + + Run the following command. For example, the Magic Mirror directory is `~/MagicMirror`. + ```sh + cd ~/MagicMirror/modules/MMM-OneDrive + git pull + npm run install-prod + ``` + ## Authorise OAuth Token ### On-device (Just do it on Raspberry PI with Desktop UI) diff --git a/OneDrivePhotos.js b/OneDrivePhotos.js index bfca42a..4ca2b40 100644 --- a/OneDrivePhotos.js +++ b/OneDrivePhotos.js @@ -242,8 +242,8 @@ class OneDrivePhotos { return list; // empty } } catch (err) { - this.log(".getImageFromAlbum()", err.toString()); - this.log(err); + this.logError(".getImageFromAlbum()", err.toString()); + this.logError(err); throw err; } }; @@ -254,7 +254,7 @@ class OneDrivePhotos { * * @param {OneDriveMediaItem[]} items * @param {string} cachePath - * @returns items + * @returns {OneDriveMediaItem[]} items */ async updateTheseMediaItems(items, cachePath) { if (items.length <= 0) { @@ -283,11 +283,14 @@ class OneDrivePhotos { if (r.status < 400) { grp[r.id].baseUrl = r.body.value['@microsoft.graph.downloadUrl']; } + else { + grp[r.id].baseUrl = null; + } } } } - const heicPhotos = items.filter(i => i.mimeType === "image/heic"); + const heicPhotos = items.filter(i => i.mimeType === "image/heic" && i.baseUrl); for (let photo of heicPhotos) { const buf = await convertHEIC(photo.baseUrl); const cacheFilename = encodeURI(path.join(cachePath, photo.id + "-convert.jpg")); diff --git a/PhotosConverter.js b/PhotosConverter.js index 0f1572e..8553d2b 100644 --- a/PhotosConverter.js +++ b/PhotosConverter.js @@ -5,14 +5,20 @@ const convert = require('heic-convert'); * @param {string} url */ const convertHEIC = async (url) => { - const resp = await fetch(url); - const inputBuffer = Buffer.from(await resp.arrayBuffer()); - const outputBuffer = await convert({ - buffer: inputBuffer, // the HEIC file buffer - format: 'JPEG', // output format - quality: 0.8, // the jpeg compression quality, between 0 and 1 - }); - return Buffer.from(outputBuffer); + try { + const resp = await fetch(url); + const inputBuffer = Buffer.from(await resp.arrayBuffer()); + const outputBuffer = await convert({ + buffer: inputBuffer, // the HEIC file buffer + format: 'JPEG', // output format + quality: 0.8, // the jpeg compression quality, between 0 and 1 + }); + return Buffer.from(outputBuffer); + } catch (err) { + console.error("Error in convertHEIC for url: ", url); + console.error(err?.stack || err); + throw err;; + } }; module.exports = { convertHEIC }; \ No newline at end of file diff --git a/README.md b/README.md index 1c3fcd5..27bf958 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Display your photos from album of OneDrive on [MagicMirror²](https://github.com ![screenshot](images/screenshot2.png) -## Installation +## Installation & Upgrade [INSTALL.md](INSTALL.md) diff --git a/node_helper.js b/node_helper.js index cd84129..f127bce 100644 --- a/node_helper.js +++ b/node_helper.js @@ -182,7 +182,10 @@ module.exports = NodeHelper.create({ const cachePath = this.path + "/cache/"; - // refresh them + /** + * refresh them + * @type {OneDriveMediaItem[]} + */ let list = []; if (numItemsToRefresh > 0) { list = await OneDrivePhoto.updateTheseMediaItems(this.localPhotoList.slice(this.localPhotoPntr, this.localPhotoPntr + numItemsToRefresh), cachePath); From 052fb6b366f17050fdb678e6451c274b63de9afa Mon Sep 17 00:00:00 2001 From: Herman Ho Date: Fri, 16 Aug 2024 00:31:41 +0100 Subject: [PATCH 4/5] feat: album name can be regex --- OneDrivePhotos.js | 1 + node_helper.js | 71 +++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 66 insertions(+), 6 deletions(-) diff --git a/OneDrivePhotos.js b/OneDrivePhotos.js index 4ca2b40..0a2c5ca 100644 --- a/OneDrivePhotos.js +++ b/OneDrivePhotos.js @@ -284,6 +284,7 @@ class OneDrivePhotos { grp[r.id].baseUrl = r.body.value['@microsoft.graph.downloadUrl']; } else { + console.error(r); grp[r.id].baseUrl = null; } } diff --git a/node_helper.js b/node_helper.js index f127bce..e58db51 100644 --- a/node_helper.js +++ b/node_helper.js @@ -13,14 +13,15 @@ const NodeHelper = require("node_helper"); const Log = require("logger"); const { shuffle } = require("./shuffle.js"); const { error_to_string } = require("./error_to_string"); -const sleep = require("./sleep.js"); + +const ONE_DAY = 24 * 60 * 60 * 1000; // 1 day in milliseconds /** * @type {OneDrivePhotos} */ let OneDrivePhoto = null; -module.exports = NodeHelper.create({ +const NodeHeleprObject = { start: function () { this.scanInterval = 1000 * 60 * 55; // fixed. no longer needs to be fixed this.config = {}; @@ -37,6 +38,7 @@ module.exports = NodeHelper.create({ this.CACHE_ALBUMNS_PATH = path.resolve(this.path, "cache", "selecetedAlbumsCache.json"); this.CACHE_PHOTOLIST_PATH = path.resolve(this.path, "cache", "photoListCache.json"); + this.CACHE_CONFIG = path.resolve(this.path, "cache", "config.json"); }, socketNotificationReceived: function (notification, payload) { @@ -131,7 +133,10 @@ module.exports = NodeHelper.create({ Log.info("Starting Initialization"); //load cached album list - if available - if (fs.existsSync(this.CACHE_ALBUMNS_PATH)) { + const cacheAlbumDt = new Date(await this.readCacheConfig("CACHE_ALBUMNS_PATH")); + const notExpiredCacheAlbum = cacheAlbumDt && (Date.now() - cacheAlbumDt.getTime() < ONE_DAY); + if (notExpiredCacheAlbum && fs.existsSync(this.CACHE_ALBUMNS_PATH)) { + Log.info("Loading cached albumns list"); try { const data = await readFile(this.CACHE_ALBUMNS_PATH, "utf-8"); this.selecetedAlbums = JSON.parse(data.toString()); @@ -143,7 +148,10 @@ module.exports = NodeHelper.create({ } //load cached list - if available - if (fs.existsSync(this.CACHE_PHOTOLIST_PATH)) { + const cachePhotoListDt = new Date(await this.readCacheConfig("CACHE_PHOTOLIST_PATH")); + const notExpiredCachePhotoList = cachePhotoListDt && (Date.now() - cachePhotoListDt.getTime() < ONE_DAY); + if (notExpiredCachePhotoList && fs.existsSync(this.CACHE_PHOTOLIST_PATH)) { + Log.info("Loading cached albumns list"); try { const data = await readFile(this.CACHE_PHOTOLIST_PATH, "utf-8"); this.localPhotoList = JSON.parse(data.toString()); @@ -247,13 +255,13 @@ module.exports = NodeHelper.create({ return true; } else { Log.warn("There is no album to get photos."); - // this.sendSocketNotification("ERROR", "There is no album to get photos."); return false; } } catch (err) { Log.error(error_to_string(err)); } }, + getAlbumList: async function () { Log.info("Getting album list"); /** @@ -285,6 +293,7 @@ module.exports = NodeHelper.create({ Log.info("Finish Album scanning. Properly scanned :", selecetedAlbums.length); Log.info("Albums:", selecetedAlbums.map((a) => a.title).join(", ")); this.writeFileSafe(this.CACHE_ALBUMNS_PATH, JSON.stringify(selecetedAlbums, null, 4), "Album list cache"); + this.saveCacheConfig("CACHE_ALBUMNS_PATH", new Date().toISOString()); for (let a of selecetedAlbums) { let url = a.coverPhotoBaseUrl; @@ -357,6 +366,7 @@ module.exports = NodeHelper.create({ this.lastLocalPhotoPntr = 0; this.prepAndSendChunk(50).then(); this.writeFileSafe(this.CACHE_PHOTOLIST_PATH, JSON.stringify(photos, null, 4), "Photo list cache"); + this.saveCacheConfig("CACHE_PHOTOLIST_PATH", new Date().toISOString()); } return photos; @@ -368,12 +378,61 @@ module.exports = NodeHelper.create({ stop: function () { clearInterval(this.scanTimer); }, + + readFileSafe: async function (filePath, fileDescription) { + try { + const data = await readFile(filePath, "utf-8"); + return data.toString(); + } catch (err) { + Log.error(`unable to read ${fileDescription}: ${filePath}`); + Log.error(error_to_string(err)); + } + }, + writeFileSafe: async function (filePath, data, fileDescription) { try { await writeFile(filePath, data); this.log_debug(fileDescription + " saved"); } catch (err) { + Log.error(`unable to write ${fileDescription}: ${filePath}`); Log.error(error_to_string(err)); } }, -}); + + readCacheConfig: async function (key) { + try { + let config = {}; + if (fs.existsSync(this.CACHE_CONFIG)) { + const configStr = await this.readFileSafe(this.CACHE_CONFIG, "Cache Config"); + config = JSON.parse(configStr); + } + if (Object(config).hasOwnProperty(key)) { + return config[key]; + } + else { + return undefined; + } + } catch (err) { + Log.error(`unable to read Cache Config`); + Log.error(error_to_string(err)); + } + }, + + saveCacheConfig: async function (key, value) { + try { + let config = {}; + if (fs.existsSync(this.CACHE_CONFIG)) { + const configStr = await this.readFileSafe(this.CACHE_CONFIG, "Cache Config"); + config = JSON.parse(configStr); + } + config[key] = value; + await this.writeFileSafe(this.CACHE_CONFIG, JSON.stringify(config, null, 4), "Cache Config"); + this.log_debug("Cache Config saved"); + } catch (err) { + Log.error(`unable to write Cache Config`); + Log.error(error_to_string(err)); + } + }, +}; + +module.exports = NodeHelper.create(NodeHeleprObject); From 384590e43bf29540ebe7bddb802a1a0226ea19d7 Mon Sep 17 00:00:00 2001 From: Herman Ho Date: Fri, 16 Aug 2024 00:54:20 +0100 Subject: [PATCH 5/5] chore: add github workflow --- .github/workflows/lint.yml | 35 +++++++++++++++++++++++++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/lint.yml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..bb1b90f --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,35 @@ +name: Lint + +on: + # Trigger the workflow on push or pull request, + # but only for the main branch + push: + branches: + - main + # Replace pull_request with pull_request_target if you + # plan to use this action with forks, see the Limitations section + pull_request: + branches: + - main + +jobs: + run-linters: + name: Run linters + runs-on: ubuntu-latest + + steps: + - name: Check out Git repository + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + + # ESLint and Prettier must be in `package.json` + - name: Install Node.js dependencies + run: npm ci + + - uses: sibiraj-s/action-eslint@v3 + with: + annotations: true diff --git a/package-lock.json b/package-lock.json index 08dc706..6f78f46 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "mmm-onedrive", - "version": "1.0.1", + "version": "1.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "mmm-onedrive", - "version": "1.0.1", + "version": "1.1.0", "license": "MIT", "dependencies": { "@azure/msal-node": "^2.13.0", diff --git a/package.json b/package.json index 6acc961..47d2847 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mmm-onedrive", - "version": "1.0.1", + "version": "1.1.0", "description": "MagicMirror² module to display your photos from OneDrive.", "license": "MIT", "author": "hermanho",