From 1720dfbeff2d39a4f7518f1ab2745b656e477934 Mon Sep 17 00:00:00 2001 From: Tobias Bocanegra Date: Wed, 26 Nov 2025 14:32:52 +0100 Subject: [PATCH] chore: fix linting --- .eslintignore | 5 - eslint.config.js | 55 + package-lock.json | 2107 +++++++++++++++------- package.json | 6 +- src/handlers/delete.js | 2 +- src/handlers/get.js | 2 +- src/handlers/head.js | 2 +- src/handlers/post.js | 2 +- src/handlers/unknown.js | 2 +- src/helpers/copy.js | 2 +- src/helpers/delete.js | 2 +- src/helpers/move.js | 2 +- src/helpers/rename.js | 2 +- src/helpers/source.js | 2 +- .eslintrc.cjs => src/index.d.ts | 24 +- src/index.js | 15 +- src/routes/config.js | 2 +- src/routes/copy.js | 2 +- src/routes/list.js | 2 +- src/routes/move.js | 2 +- src/routes/properties.js | 2 +- src/routes/source.js | 2 +- src/routes/version.js | 2 +- src/storage/bucket/list.js | 2 +- src/storage/kv/get.js | 2 +- src/storage/kv/put.js | 2 +- src/storage/object/copy.js | 3 +- src/storage/object/delete.js | 2 +- src/storage/object/get.js | 2 +- src/storage/object/list.js | 2 +- src/storage/object/move.js | 4 +- src/storage/object/put.js | 3 +- src/storage/utils/config.js | 2 +- src/storage/utils/list.js | 2 +- src/storage/utils/object.js | 2 +- src/storage/utils/version.js | 2 +- src/storage/version/get.js | 2 +- src/storage/version/list.js | 2 +- src/storage/version/put.js | 2 +- src/utils/auth.js | 2 +- src/utils/constants.js | 2 +- src/utils/daCtx.js | 2 +- src/utils/daResp.js | 15 +- test/handlers/get.test.js | 4 +- test/handlers/post.test.js | 4 +- test/handlers/unknown.test.js | 13 +- test/helpers/source.test.js | 20 +- test/index.test.js | 37 +- test/integration/conditional-e2e.test.js | 2 +- test/routes/config.test.js | 88 +- test/routes/copy.test.js | 39 +- test/routes/list.test.js | 33 +- test/routes/move.test.js | 38 +- test/routes/source.test.js | 243 ++- test/routes/version.test.js | 80 +- test/storage/bucket/list.test.js | 18 +- test/storage/bucket/mocks/env.js | 71 +- test/storage/kv/kv.test.js | 84 +- test/storage/object/conditionals.test.js | 127 +- test/storage/object/copy.test.js | 312 ++-- test/storage/object/delete.test.js | 128 +- test/storage/object/get.test.js | 11 +- test/storage/object/list.test.js | 11 +- test/storage/object/mocks/version/put.js | 14 +- test/storage/object/move.test.js | 60 +- test/storage/object/put.test.js | 36 +- test/storage/utils/list.test.js | 111 +- test/storage/utils/object.test.js | 2 +- test/storage/version/put.test.js | 284 +-- test/utils/auth.test.js | 580 +++--- test/utils/daCtx.test.js | 17 +- test/utils/daResp.test.js | 19 +- test/utils/mocks/auth.js | 15 +- test/utils/mocks/env.js | 48 +- test/utils/mocks/fetch.js | 64 +- test/utils/mocks/jose.js | 4 +- test/utils/mocks/req.js | 4 +- test/utils/mocks/s3.js | 15 +- test/utils/offlineValidation.test.js | 137 +- 79 files changed, 3087 insertions(+), 1989 deletions(-) delete mode 100644 .eslintignore create mode 100644 eslint.config.js rename .eslintrc.cjs => src/index.d.ts (59%) diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 19f2db75..00000000 --- a/.eslintignore +++ /dev/null @@ -1,5 +0,0 @@ -.vscode/* -coverage/* -dist/* -!.releaserc.js -test/* diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 00000000..ffa0c95c --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,55 @@ +/* + * Copyright 2025 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +import globals from 'globals'; +import { defineConfig, globalIgnores } from '@eslint/config-helpers' +import { recommended, source, test } from '@adobe/eslint-config-helix'; + +export default defineConfig([ + globalIgnores([ + 'coverage', + 'dist/*', + ]), + { + languageOptions: { + ...recommended.languageOptions, + globals: { + ...globals.serviceworker, + ...globals.browser, + ...globals.es6, + __rootdir: true, + }, + }, + rules: { + // 'import/extensions': [2, 'ignorePackages'], + 'import/prefer-default-export': 0, + + // console.log is the only means of logging in a cloudflare worker + 'no-console': 'off', + + // We have quite a lot of use cases where assignment to function + // parameters is definitely desirable + 'no-param-reassign': 'off', + + // Allow while (true) infinite loops + // 'no-constant-condition': ['error', { checkLoops: false }], + + // Quite useful to mark values as unused + // 'no-underscore-dangle': 'off', }, + }, + plugins: { + import: recommended.plugins.import, + }, + extends: [recommended], + }, + source, + test, +]); diff --git a/package-lock.json b/package-lock.json index 22fa4a60..53330908 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,17 +11,19 @@ "dependencies": { "@aws-sdk/client-s3": "^3.456.0", "@aws-sdk/s3-request-presigner": "^3.468.0", + "@cloudflare/workers-types": "4.20251126.0", "@ssttevee/cfw-formdata-polyfill": "^0.2.1", "jose": "^6.0.10" }, "devDependencies": { - "@adobe/eslint-config-helix": "2.0.6", + "@adobe/eslint-config-helix": "3.0.10", "@redocly/cli": "^1.4.1", "aws-sdk-client-mock": "^4.0.0", "c8": "^8.0.1", - "eslint": "8.56.0", + "eslint": "9.4.0", "esmock": "2.7.3", "mocha": "^10.2.0", + "sinon": "21.0.0", "wrangler": "^4.10.0" } }, @@ -35,21 +37,34 @@ } }, "node_modules/@adobe/eslint-config-helix": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@adobe/eslint-config-helix/-/eslint-config-helix-2.0.6.tgz", - "integrity": "sha512-xfvRjq0A0JKyNKUdG63leFLnJ0LSCqTZDcZmV5l1IV6eYGt2bA60Yz94oePm3hVxprqi+LAunLQ5Hrm1rF00Og==", + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@adobe/eslint-config-helix/-/eslint-config-helix-3.0.10.tgz", + "integrity": "sha512-DYfyd/RLHT9cAbkjj73sqkXEJAbnbWtRl4Tduq88Wqq0Ek47nxOr8AoWbOdrBRkvF3pRA8hS1SrQ9BhMxBytug==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "eslint-config-airbnb-base": "15.0.0", - "eslint-import-resolver-exports": "1.0.0-beta.5", - "eslint-plugin-header": "3.1.1", - "eslint-plugin-import": "2.29.1" + "@eslint/config-helpers": "0.3.1", + "eslint-plugin-import": "2.32.0", + "globals": "16.4.0" }, "engines": { "node": ">= 12" }, "peerDependencies": { - "eslint": "^8.0.0" + "eslint": "^9.0.0" + } + }, + "node_modules/@adobe/eslint-config-helix/node_modules/globals": { + "version": "16.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz", + "integrity": "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/@aws-crypto/crc32": { @@ -632,7 +647,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.726.0.tgz", "integrity": "sha512-5JzTX9jwev7+y2Jkzjz0pd1wobB5JQfPOQF3N2DrJ5Pao0/k6uRYwE4NqB0p0HlGrMTDm7xNq7OSPPIPG575Jw==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", @@ -1332,7 +1346,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.726.1.tgz", "integrity": "sha512-qh9Q9Vu1hrM/wMBOBIaskwnE4GTFaZu26Q6WHwyWNfj7J8a40vBxpW16c2vYXHLBtwRKM1be8uRLkmDwghpiNw==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", @@ -4492,6 +4505,12 @@ "node": ">=16" } }, + "node_modules/@cloudflare/workers-types": { + "version": "4.20251126.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20251126.0.tgz", + "integrity": "sha512-DSeI1Q7JYmh5/D/tw5eZCjrKY34v69rwj63hHt60nSQW5QLwWCbj/lLtNz9f2EPa+JCACwpLXHgCXfzJ29x66w==", + "license": "MIT OR Apache-2.0" + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -4969,16 +4988,66 @@ "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, + "node_modules/@eslint/config-array": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.15.1.tgz", + "integrity": "sha512-K4gzNq+yymn/EVsXYmf+SBcBro8MTf+aXJZUphM96CdzUEr+ClGDvAbpmaEK+cGVigVXIgs9gNmvHAlrzzY5JQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.1.tgz", + "integrity": "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==", + "dev": true, + "license": "Apache-2.0", + "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.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", "dev": true, + "license": "MIT", "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", @@ -4986,17 +5055,18 @@ "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/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5007,6 +5077,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -5015,12 +5086,23 @@ } }, "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.4.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.4.0.tgz", + "integrity": "sha512-fdI7VJjP3Rvc70lC4xkFXHB0fiPeojiL1PxVG6t1ZvXQrarj893PweuBTujxDUFk0Fxj4R7PIIAZ/aiiyZPZcg==", "dev": true, + "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@exodus/schemasafe": { @@ -5038,42 +5120,6 @@ "node": ">=14" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -5087,11 +5133,19 @@ "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.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, "node_modules/@img/sharp-darwin-arm64": { "version": "0.33.5", @@ -5593,49 +5647,60 @@ "npm": ">=7.0.0" } }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true, + "license": "MIT" + }, "node_modules/@sinonjs/commons": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "type-detect": "4.0.8" } }, "node_modules/@sinonjs/fake-timers": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", - "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "version": "13.0.5", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", + "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "@sinonjs/commons": "^3.0.0" + "@sinonjs/commons": "^3.0.1" } }, "node_modules/@sinonjs/samsam": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz", - "integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.3.tgz", + "integrity": "sha512-hw6HbX+GyVZzmaYNh82Ecj1vdGZrqVIn/keDTg63IgAwiQPO+xCz99uG6Woqgb4tM0mUiFENKZ4cqd7IX94AXQ==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "@sinonjs/commons": "^2.0.0", - "lodash.get": "^4.4.2", - "type-detect": "^4.0.8" + "@sinonjs/commons": "^3.0.1", + "type-detect": "^4.1.0" } }, - "node_modules/@sinonjs/samsam/node_modules/@sinonjs/commons": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", - "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "node_modules/@sinonjs/samsam/node_modules/type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", "dev": true, - "dependencies": { - "type-detect": "4.0.8" + "license": "MIT", + "engines": { + "node": ">=4" } }, "node_modules/@sinonjs/text-encoding": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", - "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", - "dev": true + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.3.tgz", + "integrity": "sha512-DE427ROAphMQzU4ENbliGYrBSYPXF+TtLg9S8vzeA+OF4ZKzoDdzfL8sxuMUGS/lgRhM6j1URSk9ghf7Xo1tyA==", + "dev": true, + "license": "(Unlicense OR Apache-2.0)" }, "node_modules/@smithy/abort-controller": { "version": "2.0.15", @@ -8161,7 +8226,8 @@ "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/node": { "version": "14.18.63", @@ -8190,19 +8256,12 @@ "integrity": "sha512-36ZrGJ8fgtBr6nwNnuJ9jXIj+bn/pF6UoqmrQT7+Y99+tFFeHHsoR54+194dHdyhPjgbeoNz3Qru0oRt0l6ASQ==", "dev": true }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, "node_modules/acorn": { "version": "8.14.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -8215,6 +8274,7 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, + "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } @@ -8233,6 +8293,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -8248,7 +8309,8 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/ansi-colors": { "version": "4.1.1", @@ -8303,13 +8365,14 @@ "dev": true }, "node_modules/array-buffer-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", - "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.5", - "is-array-buffer": "^3.0.4" + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" }, "engines": { "node": ">= 0.4" @@ -8319,35 +8382,20 @@ } }, "node_modules/array-includes": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", - "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.filter": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array.prototype.filter/-/array.prototype.filter-1.0.3.tgz", - "integrity": "sha512-VizNcj/RGJiUyQBgzwxzE5oHdeuXY5hSbbmKMlphj1cy1Vl7Pn2asCGbSrru6hSQjmCzqTBPVWAF/whmEOVHbw==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", + "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-array-method-boxes-properly": "^1.0.0", - "is-string": "^1.0.7" + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -8357,16 +8405,19 @@ } }, "node_modules/array.prototype.findlastindex": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.4.tgz", - "integrity": "sha512-hzvSHUshSpCflDR1QMUBLHGHP1VIEBegT4pix9H/Z92Xw3ySoy6c2qh7lJWTJnRJ8JCZ9bJNCgTyYaJGcJu6xQ==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", + "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.5", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", + "es-abstract": "^1.23.9", "es-errors": "^1.3.0", - "es-shim-unscopables": "^1.0.2" + "es-object-atoms": "^1.1.1", + "es-shim-unscopables": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -8376,15 +8427,16 @@ } }, "node_modules/array.prototype.flat": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", - "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -8394,15 +8446,16 @@ } }, "node_modules/array.prototype.flatmap": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", - "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -8412,19 +8465,19 @@ } }, "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", - "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", "dev": true, + "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.5", + "call-bind": "^1.0.8", "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.2.1", - "get-intrinsic": "^1.2.3", - "is-array-buffer": "^3.0.4", - "is-shared-array-buffer": "^1.0.2" + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" }, "engines": { "node": ">= 0.4" @@ -8442,11 +8495,25 @@ "printable-characters": "^1.0.42" } }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/available-typed-arrays": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.6.tgz", - "integrity": "sha512-j1QzY8iPNPG4o4xmO3ptzpRxTciqD3MgEHtifP/YnJpIo58Xu+ne4BejlbkuaLfXn/nz6HFiw29bLpj2PNMdGg==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, "engines": { "node": ">= 0.4" }, @@ -8465,6 +8532,58 @@ "tslib": "^2.1.0" } }, + "node_modules/aws-sdk-client-mock/node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/aws-sdk-client-mock/node_modules/diff": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/aws-sdk-client-mock/node_modules/sinon": { + "version": "16.1.3", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-16.1.3.tgz", + "integrity": "sha512-mjnWWeyxcAf9nC0bXcPmiDut+oE8HYridTNzBbF98AYVLmWwGRp2ISEpyhYflG1ifILT+eNn3BmKUJPxjXUPlA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0", + "@sinonjs/fake-timers": "^10.3.0", + "@sinonjs/samsam": "^8.0.0", + "diff": "^5.1.0", + "nise": "^5.1.4", + "supports-color": "^7.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/sinon" + } + }, + "node_modules/aws-sdk-client-mock/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -8587,15 +8706,47 @@ } }, "node_modules/call-bind": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.6.tgz", - "integrity": "sha512-Mj50FLHtlsoVfRfnHaZvyrooHcrlceNZdL/QBvJJVd9Ta55qCQK0gs4ss2oZDeV9zFCs6ewzYgVE5yfVmfFpVg==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "dev": true, + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.3", - "set-function-length": "^1.2.0" + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" }, "engines": { "node": ">= 0.4" @@ -8615,6 +8766,7 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -8776,12 +8928,6 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, - "node_modules/confusing-browser-globals": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", - "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", - "dev": true - }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -8803,7 +8949,6 @@ "integrity": "sha512-lo0kOocUlLKmm6kv/FswQL8zbkH7mVsLJ/FULClOhv8WRVmKLVcs6XPNQAzstfeJTCHMyButEwG+z1kHxHoDZw==", "dev": true, "hasInstallScript": true, - "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/core-js" @@ -8855,13 +9000,67 @@ "integrity": "sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==", "dev": true }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", "dev": true, + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" }, "engines": { "node": ">=6.0" @@ -8897,18 +9096,21 @@ "dev": true }, "node_modules/define-data-property": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.2.tgz", - "integrity": "sha512-SRtsSqsDbgpJBbW3pABMCOt6rQyeM8s8RiyeSN8jYG8sYmt/kGJejbydttUsnDs1tadr19tvhT4ShwMyoqAm4g==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "dev": true, + "license": "MIT", "dependencies": { + "es-define-property": "^1.0.0", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.2", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.1" + "gopd": "^1.0.1" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/define-properties": { @@ -8916,6 +9118,7 @@ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dev": true, + "license": "MIT", "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", @@ -8954,15 +9157,16 @@ } }, "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, "engines": { - "node": ">=6.0.0" + "node": ">=0.10.0" } }, "node_modules/dompurify": { @@ -8971,6 +9175,21 @@ "integrity": "sha512-kxxKlPEDa6Nc5WJi+qRgPbOAbgTpSULL+vI3NUXsZMlkJxTqYI9wg5ZTay2sFrdZRWHPWNi+EdAhcJf81WtoMQ==", "dev": true }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -8978,50 +9197,66 @@ "dev": true }, "node_modules/es-abstract": { - "version": "1.22.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", - "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", + "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", "dev": true, + "license": "MIT", "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "arraybuffer.prototype.slice": "^1.0.2", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.5", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.2", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.12", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "safe-array-concat": "^1.0.1", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.0", - "typed-array-byte-length": "^1.0.0", - "typed-array-byte-offset": "^1.0.0", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.13" + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" }, "engines": { "node": ">= 0.4" @@ -9030,53 +9265,78 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/es-array-method-boxes-properly": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", - "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", - "dev": true + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } }, "node_modules/es-errors": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, "engines": { "node": ">= 0.4" } }, "node_modules/es-set-tostringtag": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", - "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "dev": true, + "license": "MIT", "dependencies": { - "get-intrinsic": "^1.2.2", - "has-tostringtag": "^1.0.0", - "hasown": "^2.0.0" + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" } }, "node_modules/es-shim-unscopables": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", - "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", "dev": true, + "license": "MIT", "dependencies": { - "hasown": "^2.0.0" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" } }, "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", "dev": true, + "license": "MIT", "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" }, "engines": { "node": ">= 0.4" @@ -9153,42 +9413,38 @@ } }, "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.4.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.4.0.tgz", + "integrity": "sha512-sjc7Y8cUD1IlwYcTS9qPSvGjAC8Ne9LctpxKKu3x/1IC9bnOg98Zy6GxEJUfr1NojMgVPlyANXYns8oE2c1TAA==", "dev": true, - "peer": true, + "license": "MIT", "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/config-array": "^0.15.1", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.4.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", + "eslint-scope": "^8.0.1", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.0.1", "esquery": "^1.4.2", "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", @@ -9202,58 +9458,18 @@ "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" } }, - "node_modules/eslint-config-airbnb-base": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz", - "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==", - "dev": true, - "dependencies": { - "confusing-browser-globals": "^1.0.10", - "object.assign": "^4.1.2", - "object.entries": "^1.1.5", - "semver": "^6.3.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "peerDependencies": { - "eslint": "^7.32.0 || ^8.2.0", - "eslint-plugin-import": "^2.25.2" - } - }, - "node_modules/eslint-config-airbnb-base/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-import-resolver-exports": { - "version": "1.0.0-beta.5", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-exports/-/eslint-import-resolver-exports-1.0.0-beta.5.tgz", - "integrity": "sha512-o6t0w7muUpXr7MkUVzD5igQoDfAQvTmcPp8HEAJdNF8eOuAO+yn6I/TTyMxz9ecCwzX7e02vzlkHURoScUuidg==", - "dev": true, - "dependencies": { - "resolve.exports": "^2.0.0" - }, - "peerDependencies": { - "eslint": "*", - "eslint-plugin-import": "*" - } - }, "node_modules/eslint-import-resolver-node": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^3.2.7", "is-core-module": "^2.13.0", @@ -9265,15 +9481,17 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.1" } }, "node_modules/eslint-module-utils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", - "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz", + "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^3.2.7" }, @@ -9291,56 +9509,51 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.1" } }, - "node_modules/eslint-plugin-header": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-header/-/eslint-plugin-header-3.1.1.tgz", - "integrity": "sha512-9vlKxuJ4qf793CmeeSrZUvVClw6amtpghq3CuWcB5cUNnWHQhgcqy5eF8oVKFk1G3Y/CbchGfEaw3wiIJaNmVg==", - "dev": true, - "peerDependencies": { - "eslint": ">=7.7.0" - } - }, "node_modules/eslint-plugin-import": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", - "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "version": "2.32.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", + "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, - "peer": true, + "license": "MIT", "dependencies": { - "array-includes": "^3.1.7", - "array.prototype.findlastindex": "^1.2.3", - "array.prototype.flat": "^1.3.2", - "array.prototype.flatmap": "^1.3.2", + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.9", + "array.prototype.findlastindex": "^1.2.6", + "array.prototype.flat": "^1.3.3", + "array.prototype.flatmap": "^1.3.3", "debug": "^3.2.7", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.8.0", - "hasown": "^2.0.0", - "is-core-module": "^2.13.1", + "eslint-module-utils": "^2.12.1", + "hasown": "^2.0.2", + "is-core-module": "^2.16.1", "is-glob": "^4.0.3", "minimatch": "^3.1.2", - "object.fromentries": "^2.0.7", - "object.groupby": "^1.0.1", - "object.values": "^1.1.7", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.1", "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.9", "tsconfig-paths": "^3.15.0" }, "engines": { "node": ">=4" }, "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" } }, "node_modules/eslint-plugin-import/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -9351,27 +9564,17 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.1" } }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/eslint-plugin-import/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -9384,21 +9587,23 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "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.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", "dev": true, + "license": "BSD-2-Clause", "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" @@ -9426,6 +9631,19 @@ "concat-map": "0.0.1" } }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/eslint/node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -9461,17 +9679,44 @@ } }, "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.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.9.0", + "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "eslint-visitor-keys": "^4.2.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/espree/node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -9494,6 +9739,7 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -9553,7 +9799,8 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", @@ -9599,15 +9846,16 @@ } }, "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, + "license": "MIT", "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/fill-range": { @@ -9648,32 +9896,40 @@ } }, "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, + "license": "MIT", "dependencies": { "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" + "keyv": "^4.5.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16" } }, "node_modules/flatted": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", - "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", - "dev": true + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" }, "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", "dev": true, + "license": "MIT", "dependencies": { - "is-callable": "^1.1.3" + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/foreach": { @@ -9720,20 +9976,24 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" }, "engines": { "node": ">= 0.4" @@ -9747,10 +10007,21 @@ "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -9761,16 +10032,22 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dev": true, + "license": "MIT", "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -9785,6 +10062,20 @@ "integrity": "sha512-3UBAyM3u4ZBVYDsxOQfJDxEa6XTbpBDrOjp4mf7ExFRt5BKs/QywQQiJsh2B+hxcZLSapWqCRvElUe8DnKcFHA==", "dev": true }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-source": { "version": "2.0.12", "resolved": "https://registry.npmjs.org/get-source/-/get-source-2.0.12.tgz", @@ -9796,13 +10087,15 @@ } }, "node_modules/get-symbol-description": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.1.tgz", - "integrity": "sha512-KmuibvwbWaM4BHcBRYwJfZ1JxyJeBwB8ct9YYu67SvYdbEIlcQ2e56dHxfbobqW38GXo8/zDFqJeGtHiVbWyQw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.5", - "es-errors": "^1.3.0" + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" @@ -9872,27 +10165,27 @@ } }, "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", "dev": true, + "license": "MIT", "dependencies": { - "define-properties": "^1.1.3" + "define-properties": "^1.2.1", + "gopd": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -9902,23 +10195,18 @@ } }, "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3" + "license": "MIT", + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "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/handlebars": { "version": "4.7.8", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", @@ -9941,10 +10229,14 @@ } }, "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -9959,22 +10251,27 @@ } }, "node_modules/has-property-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", - "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, + "license": "MIT", "dependencies": { - "get-intrinsic": "^1.2.2" + "es-define-property": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, "engines": { "node": ">= 0.4" }, @@ -9983,10 +10280,11 @@ } }, "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -9999,6 +10297,7 @@ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, + "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" }, @@ -10010,10 +10309,11 @@ } }, "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -10043,19 +10343,21 @@ "dev": true }, "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } }, "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, + "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -10093,27 +10395,30 @@ "dev": true }, "node_modules/internal-slot": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", - "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", "dev": true, + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" + "hasown": "^2.0.2", + "side-channel": "^1.1.0" }, "engines": { "node": ">= 0.4" } }, "node_modules/is-array-buffer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", - "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1" + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" @@ -10129,13 +10434,37 @@ "dev": true, "optional": true }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", "dev": true, + "license": "MIT", "dependencies": { - "has-bigints": "^1.0.1" + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -10154,13 +10483,14 @@ } }, "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -10174,6 +10504,7 @@ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -10182,24 +10513,48 @@ } }, "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "dev": true, + "license": "MIT", "dependencies": { - "hasown": "^2.0.0" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", "dev": true, + "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -10217,6 +10572,22 @@ "node": ">=0.10.0" } }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -10226,6 +10597,26 @@ "node": ">=8" } }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -10238,11 +10629,25 @@ "node": ">=0.10.0" } }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -10260,12 +10665,14 @@ } }, "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", "dev": true, + "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -10293,13 +10700,16 @@ } }, "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -10308,25 +10718,44 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2" + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", "dev": true, + "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -10336,12 +10765,15 @@ } }, "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", "dev": true, + "license": "MIT", "dependencies": { - "has-symbols": "^1.0.2" + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -10351,12 +10783,13 @@ } }, "node_modules/is-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", - "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", "dev": true, + "license": "MIT", "dependencies": { - "which-typed-array": "^1.1.14" + "which-typed-array": "^1.1.16" }, "engines": { "node": ">= 0.4" @@ -10377,13 +10810,47 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2" + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -10393,7 +10860,8 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/isexe": { "version": "2.0.0", @@ -10489,7 +10957,8 @@ "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 + "dev": true, + "license": "MIT" }, "node_modules/json-pointer": { "version": "0.6.2", @@ -10517,6 +10986,7 @@ "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, + "license": "MIT", "dependencies": { "minimist": "^1.2.0" }, @@ -10528,13 +10998,15 @@ "version": "6.2.0", "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz", "integrity": "sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw==", - "dev": true + "dev": true, + "license": "MIT" }, "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, + "license": "MIT", "dependencies": { "json-buffer": "3.0.1" } @@ -10567,12 +11039,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", - "dev": true - }, "node_modules/lodash.isequal": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", @@ -10652,6 +11118,16 @@ "node": ">= 12" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/mime": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", @@ -10736,7 +11212,6 @@ "resolved": "https://registry.npmjs.org/mobx/-/mobx-6.11.0.tgz", "integrity": "sha512-qngYCmr0WJiFRSAtYe82DB7SbzvbhehkJjONs8ydynUwoazzUQHZdAlaJqUfks5j4HarhWsZrMRhV7HtSO9HOQ==", "dev": true, - "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/mobx" @@ -10978,6 +11453,7 @@ "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.9.tgz", "integrity": "sha512-qOnoujW4SV6e40dYxJOb3uvuoPHtmLzIk4TFo+j0jPJoC+5Z9xja5qH5JZobEPsa8+YYphMrOSwnrshEhG2qww==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@sinonjs/commons": "^3.0.0", "@sinonjs/fake-timers": "^11.2.2", @@ -10987,12 +11463,13 @@ } }, "node_modules/nise/node_modules/@sinonjs/fake-timers": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.2.2.tgz", - "integrity": "sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==", + "version": "11.3.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.3.1.tgz", + "integrity": "sha512-EVJO7nW5M/F5Tur0Rf2z/QoMo+1Ia963RiMtapiQrEWvY0iBUvADo8Beegwjpnle5BHkyHuoxSTW3jF43H1XRA==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "@sinonjs/commons": "^3.0.0" + "@sinonjs/commons": "^3.0.1" } }, "node_modules/node-fetch": { @@ -11125,10 +11602,14 @@ } }, "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -11138,51 +11619,43 @@ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.entries": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz", - "integrity": "sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/object.fromentries": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", - "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -11192,27 +11665,31 @@ } }, "node_modules/object.groupby": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.2.tgz", - "integrity": "sha512-bzBq58S+x+uo0VjurFT0UktpKHOZmv4/xePiOA1nbB9pMqpGK7rUPNgf+1YC+7mE+0HzhTMqNUuCqvKhj6FnBw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", "dev": true, + "license": "MIT", "dependencies": { - "array.prototype.filter": "^1.0.3", - "call-bind": "^1.0.5", + "call-bind": "^1.0.7", "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.0.0" + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" } }, "node_modules/object.values": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", - "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -11263,6 +11740,24 @@ "node": ">= 0.8.0" } }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -11298,6 +11793,7 @@ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, + "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -11342,7 +11838,8 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/path-to-regexp": { "version": "6.3.0", @@ -11402,6 +11899,16 @@ "node": ">=10" } }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/postcss": { "version": "8.4.31", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", @@ -11514,7 +12021,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", "dev": true, - "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -11527,7 +12033,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", "dev": true, - "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.0" @@ -11621,6 +12126,29 @@ "styled-components": "^4.1.1 || ^5.1.1 || ^6.0.5" } }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/reftools": { "version": "1.1.9", "resolved": "https://registry.npmjs.org/reftools/-/reftools-1.1.9.tgz", @@ -11637,14 +12165,18 @@ "dev": true }, "node_modules/regexp.prototype.flags": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", - "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "set-function-name": "^2.0.0" + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -11672,18 +12204,22 @@ } }, "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", "dev": true, + "license": "MIT", "dependencies": { - "is-core-module": "^2.13.0", + "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -11693,19 +12229,11 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, - "node_modules/resolve.exports": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", - "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -11755,14 +12283,16 @@ } }, "node_modules/safe-array-concat": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz", - "integrity": "sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.5", - "get-intrinsic": "^1.2.2", - "has-symbols": "^1.0.3", + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", "isarray": "^2.0.5" }, "engines": { @@ -11792,15 +12322,33 @@ } ] }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safe-regex-test": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", - "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.6", + "call-bound": "^1.0.2", "es-errors": "^1.3.0", - "is-regex": "^1.1.4" + "is-regex": "^1.2.1" }, "engines": { "node": ">= 0.4" @@ -11840,31 +12388,49 @@ } }, "node_modules/set-function-length": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz", - "integrity": "sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dev": true, + "license": "MIT", "dependencies": { - "define-data-property": "^1.1.2", + "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.3", + "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.1" + "has-property-descriptors": "^1.0.2" }, "engines": { "node": ">= 0.4" } }, "node_modules/set-function-name": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", - "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", "dev": true, + "license": "MIT", "dependencies": { - "define-data-property": "^1.0.1", + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.0" + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -11992,15 +12558,73 @@ "dev": true }, "node_modules/side-channel": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz", - "integrity": "sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.6", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -12053,16 +12677,16 @@ } }, "node_modules/sinon": { - "version": "16.1.3", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-16.1.3.tgz", - "integrity": "sha512-mjnWWeyxcAf9nC0bXcPmiDut+oE8HYridTNzBbF98AYVLmWwGRp2ISEpyhYflG1ifILT+eNn3BmKUJPxjXUPlA==", + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-21.0.0.tgz", + "integrity": "sha512-TOgRcwFPbfGtpqvZw+hyqJDvqfapr1qUlOizROIk4bBLjlsjlB00Pg6wMFXNtJRpu+eCZuVOaLatG7M8105kAw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "@sinonjs/commons": "^3.0.0", - "@sinonjs/fake-timers": "^10.3.0", - "@sinonjs/samsam": "^8.0.0", - "diff": "^5.1.0", - "nise": "^5.1.4", + "@sinonjs/commons": "^3.0.1", + "@sinonjs/fake-timers": "^13.0.5", + "@sinonjs/samsam": "^8.0.1", + "diff": "^7.0.0", "supports-color": "^7.2.0" }, "funding": { @@ -12071,10 +12695,11 @@ } }, "node_modules/sinon/node_modules/diff": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", - "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", + "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } @@ -12134,6 +12759,20 @@ "integrity": "sha512-GCp7vHAfpao+Qh/3Flh9DXEJ/qSi0KJwJw6zYlZOtRYXWUIpMM6mC2rIep/dK8RQqwW0KxGJIllmjPIBOGN8AA==", "dev": true }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/stoppable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", @@ -12168,14 +12807,19 @@ } }, "node_modules/string.prototype.trim": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", - "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -12185,28 +12829,37 @@ } }, "node_modules/string.prototype.trimend": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", - "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -12229,6 +12882,7 @@ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -12256,7 +12910,6 @@ "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.1.tgz", "integrity": "sha512-cpZZP5RrKRIClBW5Eby4JM1wElLVP4NQrJbJ0h10TidTyJf4SIIwa3zLXOoPb4gJi8MsJ8mjq5mu2IrEhZIAcQ==", "dev": true, - "peer": true, "dependencies": { "@emotion/is-prop-valid": "^1.2.1", "@emotion/unitless": "^0.8.0", @@ -12306,6 +12959,7 @@ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -12405,6 +13059,7 @@ "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", "dev": true, + "license": "MIT", "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", @@ -12434,46 +13089,38 @@ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/typed-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.1.tgz", - "integrity": "sha512-RSqu1UEuSlrBhHTWC8O9FnPjOduNs4M7rJ4pRKoEjtx1zUNOPN2sSXHLDX+Y2WPbHIxbvg4JFo2DNAEfPIKWoQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.6", + "call-bound": "^1.0.3", "es-errors": "^1.3.0", - "is-typed-array": "^1.1.13" + "is-typed-array": "^1.1.14" }, "engines": { "node": ">= 0.4" } }, "node_modules/typed-array-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", - "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", + "call-bind": "^1.0.8", "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" }, "engines": { "node": ">= 0.4" @@ -12483,16 +13130,19 @@ } }, "node_modules/typed-array-byte-offset": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", - "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", "dev": true, + "license": "MIT", "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" }, "engines": { "node": ">= 0.4" @@ -12502,14 +13152,21 @@ } }, "node_modules/typed-array-length": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", - "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", + "call-bind": "^1.0.7", "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -12535,15 +13192,19 @@ } }, "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", + "call-bound": "^1.0.3", "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -12566,7 +13227,6 @@ "resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.15.tgz", "integrity": "sha512-J/rEIZU8w6FOfLNz/hNKsnY+fFHWnu9MH4yRbSZF3xbbGHovcetXPs7sD+9p8L6CeNC//I9bhRYAOsBt2u7/OA==", "dev": true, - "peer": true, "dependencies": { "defu": "^6.1.4", "exsolve": "^1.0.4", @@ -12655,32 +13315,86 @@ } }, "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", "dev": true, + "license": "MIT", "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/which-typed-array": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.14.tgz", - "integrity": "sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg==", + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", "dev": true, + "license": "MIT", "dependencies": { - "available-typed-arrays": "^1.0.6", - "call-bind": "^1.0.5", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.1" + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -12701,7 +13415,6 @@ "integrity": "sha512-hqjX9swiHvrkOI3jlH9lrZsZRRv9lddUwcMe8Ua76jnyQz+brybWznNjHu8U5oswwcrFwvky1A4CcLjcLY31gQ==", "dev": true, "hasInstallScript": true, - "peer": true, "bin": { "workerd": "bin/workerd" }, diff --git a/package.json b/package.json index 649efdb5..8b68b73e 100644 --- a/package.json +++ b/package.json @@ -20,13 +20,14 @@ "author": "", "license": "Apache-2.0", "devDependencies": { - "@adobe/eslint-config-helix": "2.0.6", + "@adobe/eslint-config-helix": "3.0.10", "@redocly/cli": "^1.4.1", "aws-sdk-client-mock": "^4.0.0", "c8": "^8.0.1", - "eslint": "8.56.0", + "eslint": "9.4.0", "esmock": "2.7.3", "mocha": "^10.2.0", + "sinon": "21.0.0", "wrangler": "^4.10.0" }, "lint-staged": { @@ -36,6 +37,7 @@ "dependencies": { "@aws-sdk/client-s3": "^3.456.0", "@aws-sdk/s3-request-presigner": "^3.468.0", + "@cloudflare/workers-types": "4.20251126.0", "@ssttevee/cfw-formdata-polyfill": "^0.2.1", "jose": "^6.0.10" } diff --git a/src/handlers/delete.js b/src/handlers/delete.js index e6b0b774..f44946ed 100644 --- a/src/handlers/delete.js +++ b/src/handlers/delete.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/src/handlers/get.js b/src/handlers/get.js index 87916a3b..58a6ebdb 100644 --- a/src/handlers/get.js +++ b/src/handlers/get.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/src/handlers/head.js b/src/handlers/head.js index f2157384..ac93c092 100644 --- a/src/handlers/head.js +++ b/src/handlers/head.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/src/handlers/post.js b/src/handlers/post.js index 103cb978..1a71ad02 100644 --- a/src/handlers/post.js +++ b/src/handlers/post.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/src/handlers/unknown.js b/src/handlers/unknown.js index c6487208..dbe19289 100644 --- a/src/handlers/unknown.js +++ b/src/handlers/unknown.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/src/helpers/copy.js b/src/helpers/copy.js index 72b30cef..23af03d1 100644 --- a/src/helpers/copy.js +++ b/src/helpers/copy.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/src/helpers/delete.js b/src/helpers/delete.js index 94e42a73..d27b76aa 100644 --- a/src/helpers/delete.js +++ b/src/helpers/delete.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/src/helpers/move.js b/src/helpers/move.js index bad00c97..62604770 100644 --- a/src/helpers/move.js +++ b/src/helpers/move.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/src/helpers/rename.js b/src/helpers/rename.js index 3c5b530e..0fa0f5ab 100644 --- a/src/helpers/rename.js +++ b/src/helpers/rename.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/src/helpers/source.js b/src/helpers/source.js index f725adc7..9d779517 100644 --- a/src/helpers/source.js +++ b/src/helpers/source.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/.eslintrc.cjs b/src/index.d.ts similarity index 59% rename from .eslintrc.cjs rename to src/index.d.ts index 1097ea0d..53b94366 100644 --- a/.eslintrc.cjs +++ b/src/index.d.ts @@ -1,5 +1,5 @@ /* - * Copyright 2019 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 @@ -9,11 +9,19 @@ * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ +import {KVNamespace, R2Bucket, Service} from "@cloudflare/workers-types"; -module.exports = { - root: true, - extends: '@adobe/helix', - rules: { - 'no-await-in-loop': 0, - }, -}; +export interface Env { + S3_DEF_URL: string; + S3_ACCESS_KEY_ID: string; + S3_SECRET_ACCESS_KEY: string; + IMS_ORIGIN: string; + AEM_BUCKET_NAME: string; + + DA_AUTH: KVNamespace, + DA_CONFIG: KVNamespace, + DA_JOBS: KVNamespace, + AEM_CONTENT: R2Bucket; + + dacollab: Service; +} diff --git a/src/index.js b/src/index.js index 060ca17d..20cfb66b 100644 --- a/src/index.js +++ b/src/index.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 @@ -19,8 +19,15 @@ import deleteHandler from './handlers/delete.js'; import unknownHandler from './handlers/unknown.js'; export default { + /** + * @param {Request} req + * @param {Env} env + * @returns {Promise} + */ async fetch(req, env) { - if (req.method === 'OPTIONS') return daResp({ status: 204 }); + if (req.method === 'OPTIONS') { + return daResp({ status: 204 }); + } const daCtx = await getDaCtx(req, env); const { authorized, key } = daCtx; @@ -28,7 +35,9 @@ export default { const status = daCtx.users[0].email === 'anonymous' ? 401 : 403; return daResp({ status }); } - if (key?.startsWith('.da-versions')) return daResp({ status: 404 }); + if (key?.startsWith('.da-versions')) { + return daResp({ status: 404 }); + } let respObj; switch (req.method) { diff --git a/src/routes/config.js b/src/routes/config.js index 7d2ab9ce..3a78f7ff 100644 --- a/src/routes/config.js +++ b/src/routes/config.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/src/routes/copy.js b/src/routes/copy.js index 77debb4b..7b87ce11 100644 --- a/src/routes/copy.js +++ b/src/routes/copy.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/src/routes/list.js b/src/routes/list.js index dc4ddfb0..78c35300 100644 --- a/src/routes/list.js +++ b/src/routes/list.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/src/routes/move.js b/src/routes/move.js index 04d5065c..5ee193bd 100644 --- a/src/routes/move.js +++ b/src/routes/move.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/src/routes/properties.js b/src/routes/properties.js index 7eb477ae..768d8126 100644 --- a/src/routes/properties.js +++ b/src/routes/properties.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/src/routes/source.js b/src/routes/source.js index ea7abd9b..ddcace43 100644 --- a/src/routes/source.js +++ b/src/routes/source.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/src/routes/version.js b/src/routes/version.js index 3c7aa75c..d582b151 100644 --- a/src/routes/version.js +++ b/src/routes/version.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/src/storage/bucket/list.js b/src/storage/bucket/list.js index 731b2e59..7b8ab1b9 100644 --- a/src/storage/bucket/list.js +++ b/src/storage/bucket/list.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/src/storage/kv/get.js b/src/storage/kv/get.js index 7730ac45..31d96d60 100644 --- a/src/storage/kv/get.js +++ b/src/storage/kv/get.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/src/storage/kv/put.js b/src/storage/kv/put.js index 86f1ab99..14ea645f 100644 --- a/src/storage/kv/put.js +++ b/src/storage/kv/put.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/src/storage/object/copy.js b/src/storage/object/copy.js index a206c4e7..b3038619 100644 --- a/src/storage/object/copy.js +++ b/src/storage/object/copy.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 @@ -139,6 +139,7 @@ export default async function copyObject(env, daCtx, details, isRename) { if (resp.continuationToken) { continuationToken = `copy-${daCtx.org}-${details.source}-${details.destination}-${crypto.randomUUID()}`; while (resp.continuationToken) { + // eslint-disable-next-line no-await-in-loop resp = await listCommand(daCtx, { continuationToken: resp.continuationToken }, client); remainingKeys.push(...resp.sourceKeys); } diff --git a/src/storage/object/delete.js b/src/storage/object/delete.js index c00abbf4..5ece292d 100644 --- a/src/storage/object/delete.js +++ b/src/storage/object/delete.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/src/storage/object/get.js b/src/storage/object/get.js index a0c3ae78..8ca7e843 100644 --- a/src/storage/object/get.js +++ b/src/storage/object/get.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/src/storage/object/list.js b/src/storage/object/list.js index a6f0afde..a00ababf 100644 --- a/src/storage/object/list.js +++ b/src/storage/object/list.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/src/storage/object/move.js b/src/storage/object/move.js index 3216b6e1..3a54a740 100644 --- a/src/storage/object/move.js +++ b/src/storage/object/move.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 @@ -45,6 +45,7 @@ export default async function moveObject(env, daCtx, details) { do { try { const command = new ListObjectsV2Command({ ...input, ContinuationToken }); + // eslint-disable-next-line no-await-in-loop const resp = await client.send(command); const { Contents = [], NextContinuationToken } = resp; @@ -66,6 +67,7 @@ export default async function moveObject(env, daCtx, details) { return result; }); + // eslint-disable-next-line no-await-in-loop results.push(...await Promise.all(movedLoad)); ContinuationToken = NextContinuationToken; diff --git a/src/storage/object/put.js b/src/storage/object/put.js index 7569e466..fd926165 100644 --- a/src/storage/object/put.js +++ b/src/storage/object/put.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 @@ -71,6 +71,7 @@ export default async function putObject(env, daCtx, obj) { for (const input of inputs) { const command = new PutObjectCommand(input); + // eslint-disable-next-line no-await-in-loop await client.send(command); } diff --git a/src/storage/utils/config.js b/src/storage/utils/config.js index cce4f353..c1106aa5 100644 --- a/src/storage/utils/config.js +++ b/src/storage/utils/config.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/src/storage/utils/list.js b/src/storage/utils/list.js index 41a0996c..55363356 100644 --- a/src/storage/utils/list.js +++ b/src/storage/utils/list.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/src/storage/utils/object.js b/src/storage/utils/object.js index a095e8a8..e9396304 100644 --- a/src/storage/utils/object.js +++ b/src/storage/utils/object.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/src/storage/utils/version.js b/src/storage/utils/version.js index 81eb2a43..88159966 100644 --- a/src/storage/utils/version.js +++ b/src/storage/utils/version.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/src/storage/version/get.js b/src/storage/version/get.js index ee5a0341..74dfaea0 100644 --- a/src/storage/version/get.js +++ b/src/storage/version/get.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/src/storage/version/list.js b/src/storage/version/list.js index 510e2cb8..ad20dedb 100644 --- a/src/storage/version/list.js +++ b/src/storage/version/list.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/src/storage/version/put.js b/src/storage/version/put.js index d9b8c533..0fb36b55 100644 --- a/src/storage/version/put.js +++ b/src/storage/version/put.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/src/utils/auth.js b/src/utils/auth.js index 63b999b8..0c43ce35 100644 --- a/src/utils/auth.js +++ b/src/utils/auth.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/src/utils/constants.js b/src/utils/constants.js index f674b13a..9aff9b11 100644 --- a/src/utils/constants.js +++ b/src/utils/constants.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/src/utils/daCtx.js b/src/utils/daCtx.js index 181735ef..0e35887f 100644 --- a/src/utils/daCtx.js +++ b/src/utils/daCtx.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/src/utils/daResp.js b/src/utils/daResp.js index ba718c38..633972f4 100644 --- a/src/utils/daResp.js +++ b/src/utils/daResp.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 @@ -9,6 +9,17 @@ * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ +/** + * Creates a response + * @param status + * @param body + * @param contentType + * @param contentLength + * @param metadata + * @param etag + * @param ctx + * @returns {Response} + */ export default function daResp({ status, body, @@ -16,7 +27,7 @@ export default function daResp({ contentLength, metadata, etag, -}, ctx) { +}, ctx = null) { const headers = new Headers(); headers.append('Access-Control-Allow-Origin', '*'); headers.append('Access-Control-Allow-Methods', 'HEAD, GET, PUT, POST, DELETE'); diff --git a/test/handlers/get.test.js b/test/handlers/get.test.js index c0230432..9c3158f8 100644 --- a/test/handlers/get.test.js +++ b/test/handlers/get.test.js @@ -9,7 +9,7 @@ * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ -import assert from 'assert'; +import assert from 'node:assert'; import getHandler from '../../src/handlers/get.js'; @@ -32,7 +32,7 @@ describe('Get Route', () => { const env = { DA_AUTH }; const daCtx = { path: '/logout', - users: [ { ident: 'foo@bar.org'}, { ident: 'blah@blah.org' }] + users: [{ ident: 'foo@bar.org' }, { ident: 'blah@blah.org' }], }; const resp = await getHandler({ env, daCtx }); diff --git a/test/handlers/post.test.js b/test/handlers/post.test.js index 3ab85f18..3e245879 100644 --- a/test/handlers/post.test.js +++ b/test/handlers/post.test.js @@ -9,7 +9,7 @@ * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ -import assert from 'assert'; +import assert from 'node:assert'; import postHandler from '../../src/handlers/post.js'; @@ -22,7 +22,7 @@ describe('Post Route', () => { const env = { DA_AUTH }; const daCtx = { path: '/logout', - users: [ { ident: 'foo@bar.org'}, { ident: 'blah@blah.org' }] + users: [{ ident: 'foo@bar.org' }, { ident: 'blah@blah.org' }], }; const resp = await postHandler({ env, daCtx }); diff --git a/test/handlers/unknown.test.js b/test/handlers/unknown.test.js index 6b3ddff0..cee3586d 100644 --- a/test/handlers/unknown.test.js +++ b/test/handlers/unknown.test.js @@ -1,4 +1,15 @@ -import assert from 'assert'; +/* + * Copyright 2025 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +import assert from 'node:assert'; import unknownHandler from '../../src/handlers/unknown.js'; describe('unknownHandler', () => { diff --git a/test/helpers/source.test.js b/test/helpers/source.test.js index c63f31bb..8aa898f9 100644 --- a/test/helpers/source.test.js +++ b/test/helpers/source.test.js @@ -1,7 +1,19 @@ -import assert from 'assert'; +/* + * Copyright 2025 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +import assert from 'node:assert'; import putHelper from '../../src/helpers/source.js'; import env from '../utils/mocks/env.js'; + const daCtx = { org: 'cq', key: 'geometrixx/hello.html', propsKey: 'geometrixx/hello.html.props' }; const MOCK_URL = 'https://da.live/source/cq/geometrixx/hello'; @@ -18,7 +30,7 @@ describe('Source helper', () => { it('Returns null if unsupported content type', async () => { const opts = { headers: new Headers({ - 'Content-Type': `custom/form; boundary`, + 'Content-Type': 'custom/form; boundary', }), }; @@ -33,7 +45,7 @@ describe('Source helper', () => { body: {}, method: 'PUT', headers: new Headers({ - 'Content-Type': `multipart/form-data; boundary`, + 'Content-Type': 'multipart/form-data; boundary', }), }; @@ -50,7 +62,7 @@ describe('Source helper', () => { body, method: 'PUT', headers: new Headers({ - 'Content-Type': `application/x-www-form-urlencoded; boundary`, + 'Content-Type': 'application/x-www-form-urlencoded; boundary', }), }; diff --git a/test/index.test.js b/test/index.test.js index 35cdf522..b86ce7a6 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -1,4 +1,15 @@ -import assert from 'assert'; +/* + * Copyright 2025 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +import assert from 'node:assert'; import esmock from 'esmock'; import handler from '../src/index.js'; @@ -18,26 +29,22 @@ describe('fetch', () => { }); it('should return 401 when not authorized and not logged in', async () => { - const hnd = await esmock( - '../src/index.js', { - '../src/utils/daCtx.js': { - default: async () => ({ authorized: false, users: [{ email: 'anonymous' }] }) - } - } - ) + const hnd = await esmock('../src/index.js', { + '../src/utils/daCtx.js': { + default: async () => ({ authorized: false, users: [{ email: 'anonymous' }] }), + }, + }); const resp = await hnd.fetch({ method: 'GET' }, {}); assert.strictEqual(resp.status, 401); }); it('should return 403 when logged in but not authorized', async () => { - const hnd = await esmock( - '../src/index.js', { - '../src/utils/daCtx.js': { - default: async () => ({ authorized: false, users: [{ email: 'joe@bloggs.org' }] }) - } - } - ) + const hnd = await esmock('../src/index.js', { + '../src/utils/daCtx.js': { + default: async () => ({ authorized: false, users: [{ email: 'joe@bloggs.org' }] }), + }, + }); const resp = await hnd.fetch({ method: 'GET' }, {}); assert.strictEqual(resp.status, 403); diff --git a/test/integration/conditional-e2e.test.js b/test/integration/conditional-e2e.test.js index e3c18f19..f5fed269 100644 --- a/test/integration/conditional-e2e.test.js +++ b/test/integration/conditional-e2e.test.js @@ -10,7 +10,7 @@ * governing permissions and limitations under the License. */ -import assert from 'assert'; +import assert from 'node:assert'; import esmock from 'esmock'; import { S3Client, diff --git a/test/routes/config.test.js b/test/routes/config.test.js index c8534991..0a70a9e6 100644 --- a/test/routes/config.test.js +++ b/test/routes/config.test.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 @@ -9,7 +9,8 @@ * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ -import assert from 'assert'; +/* eslint-disable consistent-return */ +import assert from 'node:assert'; import esmock from 'esmock'; describe('Config', () => { @@ -18,9 +19,9 @@ describe('Config', () => { const env = {}; const req = {}; - const putKVCalled = [] + const putKVCalled = []; const putKV = async (r, q, c) => { - putKVCalled.push({r, q, c}); + putKVCalled.push({ r, q, c }); return 'called'; }; @@ -30,30 +31,27 @@ describe('Config', () => { } }; - const { postConfig } = await esmock( - '../../src/routes/config.js', { - '../../src/storage/kv/put.js': { - default: putKV, - }, - '../../src/utils/auth.js': { - hasPermission, - } - } - ); + const { postConfig } = await esmock('../../src/routes/config.js', { + '../../src/storage/kv/put.js': { + default: putKV, + }, + '../../src/utils/auth.js': { + hasPermission, + }, + }); const res = await postConfig({ req, env, daCtx: ctx }); assert.strictEqual(res, 'called'); - assert.deepStrictEqual(putKVCalled, [{r: req, q: env, c: ctx}]); + assert.deepStrictEqual(putKVCalled, [{ r: req, q: env, c: ctx }]); }); it('Test getConfig has permission', async () => { const ctx = {}; const env = {}; - const req = {}; - const getKVCalled = [] + const getKVCalled = []; const getKV = async (e, c) => { - getKVCalled.push({e, c}); + getKVCalled.push({ e, c }); return 'called'; }; @@ -63,20 +61,18 @@ describe('Config', () => { } }; - const { getConfig } = await esmock( - '../../src/routes/config.js', { - '../../src/storage/kv/get.js': { - default: getKV, - }, - '../../src/utils/auth.js': { - hasPermission, - } - } - ); + const { getConfig } = await esmock('../../src/routes/config.js', { + '../../src/storage/kv/get.js': { + default: getKV, + }, + '../../src/utils/auth.js': { + hasPermission, + }, + }); const res = await getConfig({ env, daCtx: ctx }); assert.strictEqual(res, 'called'); - assert.deepStrictEqual(getKVCalled, [{e: env, c: ctx}]); + assert.deepStrictEqual(getKVCalled, [{ e: env, c: ctx }]); }); it('Test no permission', async () => { @@ -84,33 +80,31 @@ describe('Config', () => { const env = {}; const req = {}; - const putKVCalled = [] + const putKVCalled = []; const putKV = async (r, e, c) => { - putKVCalled.push({r, e, c}); + putKVCalled.push({ r, e, c }); }; - const getKVCalled = [] + const getKVCalled = []; const getKV = async (e, c) => { - getKVCalled.push({e, c}); + getKVCalled.push({ e, c }); }; const hasPermission = () => false; - const { getConfig, postConfig } = await esmock( - '../../src/routes/config.js', { - '../../src/storage/kv/get.js': { - default: getKV, - }, - '../../src/storage/kv/put.js': { - default: putKV, - }, - '../../src/utils/auth.js': { - hasPermission, - } - } - ); + const { getConfig, postConfig } = await esmock('../../src/routes/config.js', { + '../../src/storage/kv/get.js': { + default: getKV, + }, + '../../src/storage/kv/put.js': { + default: putKV, + }, + '../../src/utils/auth.js': { + hasPermission, + }, + }); const res = await getConfig({ env, daCtx: ctx }); - assert.strictEqual(getKVCalled.length, 0, "Should not have read permission on config"); + assert.strictEqual(getKVCalled.length, 0, 'Should not have read permission on config'); assert.strictEqual(res.status, 403); const res2 = await postConfig({ req, env, daCtx: ctx }); diff --git a/test/routes/copy.test.js b/test/routes/copy.test.js index 380139fb..8a9da790 100644 --- a/test/routes/copy.test.js +++ b/test/routes/copy.test.js @@ -9,14 +9,16 @@ * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ -import assert from 'assert'; +import assert from 'node:assert'; import esmock from 'esmock'; describe('Copy Route', () => { it('Test copyHandler with permissions', async () => { const copyCalled = []; const copyObject = (e, c, d, m) => { - copyCalled.push({e, c, d, m}); + copyCalled.push({ + e, c, d, m, + }); return { status: 200 }; }; @@ -28,42 +30,39 @@ describe('Copy Route', () => { return false; } return true; - } - const copyHandler = await esmock( - '../../src/routes/copy.js', { - '../../src/storage/object/copy.js': { - default: copyObject - }, - '../../src/utils/auth.js': { - hasPermission } - } - ); + }; + const copyHandler = await esmock('../../src/routes/copy.js', { + '../../src/storage/object/copy.js': { + default: copyObject, + }, + '../../src/utils/auth.js': { hasPermission }, + }); const formdata = new Map(); - formdata.set('destination', '/myorg/MY/dest.html') + formdata.set('destination', '/myorg/MY/dest.html'); const req = { - formData: () => formdata + formData: () => formdata, }; - const resp = await copyHandler({ req, env: {}, daCtx: { key: 'my/src.html' }}); + const resp = await copyHandler({ req, env: {}, daCtx: { key: 'my/src.html' } }); assert.strictEqual(403, resp.status); assert.strictEqual(copyCalled.length, 0); - const resp2 = await copyHandler({ req, env: {}, daCtx: { key: 'my/src2.html' }}); + const resp2 = await copyHandler({ req, env: {}, daCtx: { key: 'my/src2.html' } }); assert.strictEqual(403, resp2.status); assert.strictEqual(copyCalled.length, 0); const formdata2 = new Map(); - formdata2.set('destination', '/myorg/MY/dest2.html') + formdata2.set('destination', '/myorg/MY/dest2.html'); const req2 = { - formData: () => formdata2 + formData: () => formdata2, }; - const resp3 = await copyHandler({ req: req2, env: {}, daCtx: { key: 'my/src.html' }}); + const resp3 = await copyHandler({ req: req2, env: {}, daCtx: { key: 'my/src.html' } }); assert.strictEqual(403, resp3.status); assert.strictEqual(copyCalled.length, 0); - const resp4 = await copyHandler({ req: req2, env: {}, daCtx: { key: 'my/src2.html' }}); + const resp4 = await copyHandler({ req: req2, env: {}, daCtx: { key: 'my/src2.html' } }); assert.strictEqual(200, resp4.status); assert.strictEqual(copyCalled.length, 1); assert.strictEqual('my/src2.html', copyCalled[0].d.source); diff --git a/test/routes/list.test.js b/test/routes/list.test.js index 99751653..95f9d531 100644 --- a/test/routes/list.test.js +++ b/test/routes/list.test.js @@ -9,7 +9,7 @@ * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ -import assert from 'assert'; +import assert from 'node:assert'; import esmock from 'esmock'; describe('List Route', () => { @@ -18,7 +18,7 @@ describe('List Route', () => { const listObjects = (e, c) => { loCalled.push({ e, c }); return {}; - } + }; const ctx = { org: 'foo', key: 'q/q/q' }; const hasPermission = (c, k, a) => { @@ -26,28 +26,31 @@ describe('List Route', () => { return false; } return true; - } + }; - const getList = await esmock( - '../../src/routes/list.js', { - '../../src/storage/object/list.js': { - default: listObjects - }, - '../../src/utils/auth.js': { - hasPermission - } - } - ); + const getList = await esmock('../../src/routes/list.js', { + '../../src/storage/object/list.js': { + default: listObjects, + }, + '../../src/utils/auth.js': { + hasPermission, + }, + }); const resp = await getList({ env: {}, daCtx: ctx, aclCtx: {} }); assert.strictEqual(403, resp.status); assert.strictEqual(0, loCalled.length); const aclCtx = { pathLookup: new Map() }; - await getList({ env: {}, daCtx: { org: 'bar', key: 'q/q', users: [], aclCtx }}); + await getList({ + env: {}, + daCtx: { + org: 'bar', key: 'q/q', users: [], aclCtx, + }, + }); assert.strictEqual(1, loCalled.length); assert.strictEqual('q/q', loCalled[0].c.key); - const childRules = aclCtx.childRules; + const { childRules } = aclCtx; assert.strictEqual(1, childRules.length); assert(childRules[0].startsWith('/q/q/**='), 'Should have defined some child rule'); }); diff --git a/test/routes/move.test.js b/test/routes/move.test.js index ca9cefe5..9f0b58fd 100644 --- a/test/routes/move.test.js +++ b/test/routes/move.test.js @@ -9,14 +9,14 @@ * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ -import assert from 'assert'; +import assert from 'node:assert'; import esmock from 'esmock'; describe('Move Route', () => { it('Test moveRoute with permissions', async () => { const moCalled = []; const moveObject = (e, c, d) => { - moCalled.push({e, c, d}); + moCalled.push({ e, c, d }); }; const hasPermission = (c, k, a) => { @@ -29,42 +29,40 @@ describe('Move Route', () => { return true; }; - const moveRoute = await esmock( - '../../src/routes/move.js', { - '../../src/storage/object/move.js': { - default: moveObject - }, - '../../src/utils/auth.js': { - hasPermission - } - } - ); + const moveRoute = await esmock('../../src/routes/move.js', { + '../../src/storage/object/move.js': { + default: moveObject, + }, + '../../src/utils/auth.js': { + hasPermission, + }, + }); const formdata = new Map(); formdata.set('destination', '/someorg/somedest/'); const req = { - formData: () => formdata - } + formData: () => formdata, + }; - const resp = await moveRoute({ req, env: {}, daCtx: { key: 'abc.html' }}); + const resp = await moveRoute({ req, env: {}, daCtx: { key: 'abc.html' } }); assert.strictEqual(403, resp.status); assert.strictEqual(0, moCalled.length); - const resp2 = await moveRoute({ req, env: {}, daCtx: { key: 'zzz.html' }}); + const resp2 = await moveRoute({ req, env: {}, daCtx: { key: 'zzz.html' } }); assert.strictEqual(403, resp2.status); assert.strictEqual(0, moCalled.length); const formdata2 = new Map(); formdata2.set('destination', '/someorg/someotherdest/'); const req2 = { - formData: () => formdata2 - } + formData: () => formdata2, + }; - const resp3 = await moveRoute({ req: req2, env: {}, daCtx: { key: 'abc.html' }}); + const resp3 = await moveRoute({ req: req2, env: {}, daCtx: { key: 'abc.html' } }); assert.strictEqual(403, resp3.status); assert.strictEqual(0, moCalled.length); - await moveRoute({ req: req2, env: {}, daCtx: { key: 'zzz.html' }}); + await moveRoute({ req: req2, env: {}, daCtx: { key: 'zzz.html' } }); assert.strictEqual(1, moCalled.length); assert.strictEqual('zzz.html', moCalled[0].d.source); assert.strictEqual('someotherdest', moCalled[0].d.destination); diff --git a/test/routes/source.test.js b/test/routes/source.test.js index 52538b2e..af6ffb25 100644 --- a/test/routes/source.test.js +++ b/test/routes/source.test.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 @@ -9,7 +9,8 @@ * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ -import assert from 'assert'; +/* eslint-disable camelcase,consistent-return */ +import assert from 'node:assert'; import esmock from 'esmock'; import { getAclCtx } from '../../src/utils/auth.js'; @@ -18,25 +19,24 @@ describe('Source Route', () => { it('Test invalidate using service binding', async () => { const sb_callbacks = []; const dacollab = { - fetch: async (url) => sb_callbacks.push(url) + fetch: async (url) => sb_callbacks.push(url), }; const env = { dacollab, - DA_COLLAB: 'http://localhost:4444' + DA_COLLAB: 'http://localhost:4444', }; - const daCtx = { aclCtx: { pathLookup: new Map() }}; + const daCtx = { aclCtx: { pathLookup: new Map() } }; const putResp = async (e, c) => { if (e === env && c === daCtx) { return { status: 200 }; } }; - const { postSource } = await esmock( - '../../src/routes/source.js', { - '../../src/storage/object/put.js': { - default: putResp - } + const { postSource } = await esmock('../../src/routes/source.js', { + '../../src/storage/object/put.js': { + default: putResp, + }, }); const headers = new Map(); @@ -44,7 +44,7 @@ describe('Source Route', () => { const req = { headers, - url: 'http://localhost:9876/source/somedoc.html' + url: 'http://localhost:9876/source/somedoc.html', }; const resp = await postSource({ req, env, daCtx }); @@ -53,11 +53,10 @@ describe('Source Route', () => { }); it('Test postSource from collab does not trigger invalidate callback', async () => { - const { postSource } = await esmock( - '../../src/routes/source.js', { - '../../src/storage/object/put.js': { - default: async () => ({ status: 201 }) - } + const { postSource } = await esmock('../../src/routes/source.js', { + '../../src/storage/object/put.js': { + default: async () => ({ status: 201 }), + }, }); const savedFetch = globalThis.fetch; @@ -73,11 +72,11 @@ describe('Source Route', () => { const req = { headers, - url: 'http://localhost:8787/source/a/b/mydoc.html' + url: 'http://localhost:8787/source/a/b/mydoc.html', }; const env = { DA_COLLAB: 'http://localhost:1234' }; - const daCtx = { aclCtx: { pathLookup: new Map() }}; + const daCtx = { aclCtx: { pathLookup: new Map() } }; const resp = await postSource({ req, env, daCtx }); assert.equal(201, resp.status); @@ -88,12 +87,10 @@ describe('Source Route', () => { }); it('Test failing postSource does not trigger callback', async () => { - const callbacks = []; - const { postSource } = await esmock( - '../../src/routes/source.js', { - '../../src/storage/object/put.js': { - default: async () => ({ status: 500 }) - } + const { postSource } = await esmock('../../src/routes/source.js', { + '../../src/storage/object/put.js': { + default: async () => ({ status: 500 }), + }, }); const savedFetch = globalThis.fetch; @@ -108,11 +105,11 @@ describe('Source Route', () => { const req = { headers, - url: 'http://localhost:8787/source/a/b/mydoc.html' + url: 'http://localhost:8787/source/a/b/mydoc.html', }; const env = { DA_COLLAB: 'http://localhost:1234' }; - const daCtx = { aclCtx: { pathLookup: new Map() }}; + const daCtx = { aclCtx: { pathLookup: new Map() } }; const resp = await postSource({ req, env, daCtx }); assert.equal(500, resp.status); @@ -124,130 +121,126 @@ describe('Source Route', () => { it('Test getSource', async () => { const env = {}; - const daCtx = { aclCtx: { pathLookup: new Map() }}; + const daCtx = { aclCtx: { pathLookup: new Map() } }; const called = []; const getResp = async (e, c) => { if (e === env && c === daCtx) { called.push('getObject'); - return {status: 200}; + return { status: 200 }; } }; - const { getSource } = await esmock( - '../../src/routes/source.js', { - '../../src/storage/object/get.js': { - default: getResp - } - } - ); - const resp = await getSource({env, daCtx}); + const { getSource } = await esmock('../../src/routes/source.js', { + '../../src/storage/object/get.js': { + default: getResp, + }, + }); + const resp = await getSource({ env, daCtx }); assert.equal(200, resp.status); assert.deepStrictEqual(called, ['getObject']); }); it('Test getSource with 204', async () => { const env = {}; - const daCtx = { aclCtx: { pathLookup: new Map() }}; + const daCtx = { aclCtx: { pathLookup: new Map() } }; const deleteResp = async (e, c) => { if (e === env && c === daCtx) { - return {status: 204}; + return { status: 204 }; } }; - const { deleteSource } = await esmock( - '../../src/routes/source.js', { - '../../src/storage/object/delete.js': { - default: deleteResp - } - } - ); + const { deleteSource } = await esmock('../../src/routes/source.js', { + '../../src/storage/object/delete.js': { + default: deleteResp, + }, + }); - const resp = await deleteSource({env, daCtx}); + const resp = await deleteSource({ env, daCtx }); assert.equal(204, resp.status); }); it('Test getSource with permissions', async () => { const DA_CONFIG = { 'test-source': { - "total": 1, - "limit": 1, - "offset": 0, - "permissions": { - "data": [ + total: 1, + limit: 1, + offset: 0, + permissions: { + data: [ { - "path": "/**", - "groups": "2345B0EA551D747/4711,123", - "actions": "read", + path: '/**', + groups: '2345B0EA551D747/4711,123', + actions: 'read', }, { - "path": "/**", - "groups": "2345B0EA551D747/8080", - "actions": "write", + path: '/**', + groups: '2345B0EA551D747/8080', + actions: 'write', }, { - "path": "/foo", - "groups": "2345B0EA551D747/4711", - "actions": "write", + path: '/foo', + groups: '2345B0EA551D747/4711', + actions: 'write', }, { - "path": "/bar", - "groups": "2345B0EA551D747/4711", - "actions": "", - } - ] + path: '/bar', + groups: '2345B0EA551D747/4711', + actions: '', + }, + ], }, - ":type": "multi-sheet" - } + ':type': 'multi-sheet', + }, }; const env = { DA_CONFIG: { - get: (name) => { - return DA_CONFIG[name]; - }, - } + get: (name) => DA_CONFIG[name], + }, }; - const daCtx = { users: [{ - orgs: [{ - orgIdent: '2345B0EA551D747', - groups: [{'groupName': '4711'}] - }]}], - org: 'test-source', env}; + const daCtx = { + users: [{ + orgs: [{ + orgIdent: '2345B0EA551D747', + groups: [{ groupName: '4711' }], + }], + }], + org: 'test-source', + env, + }; const called = []; const getResp = async (e, c) => { if (e === env && c === daCtx) { called.push('getObject'); - return {status: 200}; + return { status: 200 }; } }; - const { getSource } = await esmock( - '../../src/routes/source.js', { - '../../src/storage/object/get.js': { - default: getResp - } - } - ); + const { getSource } = await esmock('../../src/routes/source.js', { + '../../src/storage/object/get.js': { + default: getResp, + }, + }); daCtx.key = '/test'; daCtx.aclCtx = await getAclCtx(env, daCtx.org, daCtx.users, daCtx.key); - const resp = await getSource({env, daCtx}); + const resp = await getSource({ env, daCtx }); assert.equal(200, resp.status); assert.deepStrictEqual(called, ['getObject']); daCtx.key = '/bar'; daCtx.aclCtx = await getAclCtx(env, daCtx.org, daCtx.users, daCtx.key); - const resp2 = await getSource({env, daCtx}); + const resp2 = await getSource({ env, daCtx }); assert.equal(403, resp2.status); }); - it('Test deleteSource with permissions', async() => { + it('Test deleteSource with permissions', async () => { const deleteCalled = []; const deleteCall = (e, c, d) => { - deleteCalled.push({e, c, d}); + deleteCalled.push({ e, c, d }); }; const ctx = { key: '/a/b/c.html' }; @@ -256,24 +249,22 @@ describe('Source Route', () => { return false; } return true; - } + }; - const { deleteSource } = await esmock( - '../../src/routes/source.js', { - '../../src/storage/object/delete.js': { - default: deleteCall - }, - '../../src/utils/auth.js': { - hasPermission - }, - } - ); + const { deleteSource } = await esmock('../../src/routes/source.js', { + '../../src/storage/object/delete.js': { + default: deleteCall, + }, + '../../src/utils/auth.js': { + hasPermission, + }, + }); const resp = await deleteSource({ req: {}, env: {}, daCtx: ctx }); assert.strictEqual(403, resp.status); assert.strictEqual(deleteCalled.length, 0); - await deleteSource({ req: {}, env: {}, daCtx: { key: 'foobar.html' }}); + await deleteSource({ req: {}, env: {}, daCtx: { key: 'foobar.html' } }); assert.strictEqual(deleteCalled.length, 1); assert.strictEqual(deleteCalled[0].c.key, 'foobar.html'); }); @@ -281,7 +272,7 @@ describe('Source Route', () => { it('Test postSource with permissions', async () => { const putCalled = []; const putCall = (e, c, o) => { - putCalled.push({e, c, o}); + putCalled.push({ e, c, o }); return { status: 202 }; // 202 skips the invalidate collab which is easy for the test }; @@ -291,24 +282,22 @@ describe('Source Route', () => { return false; } return true; - } + }; - const { postSource } = await esmock( - '../../src/routes/source.js', { - '../../src/storage/object/put.js': { - default: putCall - }, - '../../src/utils/auth.js': { - hasPermission - }, - } - ); + const { postSource } = await esmock('../../src/routes/source.js', { + '../../src/storage/object/put.js': { + default: putCall, + }, + '../../src/utils/auth.js': { + hasPermission, + }, + }); const resp = await postSource({ req: {}, env: {}, daCtx: ctx }); assert.strictEqual(403, resp.status); assert.strictEqual(putCalled.length, 0); - await postSource({ req: { headers: new Headers() }, env: {}, daCtx: { key: 'haha.png' }}); + await postSource({ req: { headers: new Headers() }, env: {}, daCtx: { key: 'haha.png' } }); assert.strictEqual(putCalled.length, 1); assert.strictEqual(putCalled[0].c.key, 'haha.png'); }); @@ -316,23 +305,21 @@ describe('Source Route', () => { it('Test postSource with provided guid', async () => { const putCalled = []; const putCall = (e, c, o) => { - putCalled.push({e, c, o}); + putCalled.push({ e, c, o }); return { status: 202 }; // 202 skips the invalidate collab which is easy for the test }; const ctx = { key: '/foo/bar.png' }; - const hasPermission = () => true - - const { postSource } = await esmock( - '../../src/routes/source.js', { - '../../src/storage/object/put.js': { - default: putCall - }, - '../../src/utils/auth.js': { - hasPermission - }, - } - ); + const hasPermission = () => true; + + const { postSource } = await esmock('../../src/routes/source.js', { + '../../src/storage/object/put.js': { + default: putCall, + }, + '../../src/utils/auth.js': { + hasPermission, + }, + }); const body = new FormData(); body.append('data', 'some data'); @@ -347,4 +334,4 @@ describe('Source Route', () => { assert.strictEqual('some data', putCalled[0].o.data); assert.strictEqual(202, resp.status); }); -}); \ No newline at end of file +}); diff --git a/test/routes/version.test.js b/test/routes/version.test.js index 14c61765..3a59e154 100644 --- a/test/routes/version.test.js +++ b/test/routes/version.test.js @@ -9,14 +9,14 @@ * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ -import assert from 'assert'; +import assert from 'node:assert'; import esmock from 'esmock'; describe('Version Route', () => { it('get version list with permissions', async () => { const lovCalled = []; const listObjectVersions = (e, c) => { - lovCalled.push({e, c}); + lovCalled.push({ e, c }); return { status: 200 }; }; const hasPermission = (c, k, a) => { @@ -26,22 +26,20 @@ describe('Version Route', () => { return true; }; - const { getVersionList } = await esmock( - '../../src/routes/version.js', { - '../../src/storage/version/list.js': { - listObjectVersions - }, - '../../src/utils/auth.js': { - hasPermission - }, - } - ); + const { getVersionList } = await esmock('../../src/routes/version.js', { + '../../src/storage/version/list.js': { + listObjectVersions, + }, + '../../src/utils/auth.js': { + hasPermission, + }, + }); - const resp = await getVersionList({ env: {}, daCtx: { key: 'a/b/c.html' }}); + const resp = await getVersionList({ env: {}, daCtx: { key: 'a/b/c.html' } }); assert.strictEqual(403, resp.status); assert.strictEqual(0, lovCalled.length); - const resp2 = await getVersionList({ env: {}, daCtx: { key: 'a/b/c/d.html' }}); + const resp2 = await getVersionList({ env: {}, daCtx: { key: 'a/b/c/d.html' } }); assert.strictEqual(200, resp2.status); assert.strictEqual(1, lovCalled.length); assert.strictEqual('a/b/c/d.html', lovCalled[0].c.key); @@ -50,7 +48,7 @@ describe('Version Route', () => { it('post version source with permissions', async () => { const povCalled = []; const postObjectVersion = (r, e, c) => { - povCalled.push({r, e, c}); + povCalled.push({ r, e, c }); return { status: 201 }; }; const hasPermission = (c, k, a) => { @@ -60,22 +58,20 @@ describe('Version Route', () => { return true; }; - const { postVersionSource } = await esmock( - '../../src/routes/version.js', { - '../../src/storage/version/put.js': { - postObjectVersion - }, - '../../src/utils/auth.js': { - hasPermission - }, - } - ); + const { postVersionSource } = await esmock('../../src/routes/version.js', { + '../../src/storage/version/put.js': { + postObjectVersion, + }, + '../../src/utils/auth.js': { + hasPermission, + }, + }); - const resp = await postVersionSource({ req: {}, env: {}, daCtx: { key: 'hi.html' }}); + const resp = await postVersionSource({ req: {}, env: {}, daCtx: { key: 'hi.html' } }); assert.strictEqual(403, resp.status); assert.strictEqual(0, povCalled.length); - const resp2 = await postVersionSource({ req: {}, env: {}, daCtx: { key: 'ho.html' }}); + const resp2 = await postVersionSource({ req: {}, env: {}, daCtx: { key: 'ho.html' } }); assert.strictEqual(201, resp2.status); assert.strictEqual(1, povCalled.length); assert.strictEqual('ho.html', povCalled[0].c.key); @@ -85,13 +81,13 @@ describe('Version Route', () => { let mdPath; const govCalled = []; const getObjectVersion = (e, c, h) => { - govCalled.push({e, c, h}); + govCalled.push({ e, c, h }); return { status: 200, metadata: { - path: mdPath - } - } + path: mdPath, + }, + }; }; const hasPermission = (c, k, a) => { if (k === 'x/yyy/zzz.json' && a === 'read') { @@ -100,26 +96,24 @@ describe('Version Route', () => { return true; }; - const { getVersionSource } = await esmock( - '../../src/routes/version.js', { - '../../src/storage/version/get.js': { - getObjectVersion - }, - '../../src/utils/auth.js': { - hasPermission - }, - } - ); + const { getVersionSource } = await esmock('../../src/routes/version.js', { + '../../src/storage/version/get.js': { + getObjectVersion, + }, + '../../src/utils/auth.js': { + hasPermission, + }, + }); mdPath = 'huh.json'; - const resp = await getVersionSource({ env: {}, daCtx: { key: 'aaaa/bbbb.html' }, head: true}); + const resp = await getVersionSource({ env: {}, daCtx: { key: 'aaaa/bbbb.html' }, head: true }); assert.strictEqual(200, resp.status); assert.strictEqual(1, govCalled.length); assert.strictEqual('aaaa/bbbb.html', govCalled[0].c.key); assert(govCalled[0].h); mdPath = 'x/yyy/zzz.json'; - const resp2 = await getVersionSource({ env: {}, daCtx: { key: 'aaaa/bbbb.html' }, head: false}); + const resp2 = await getVersionSource({ env: {}, daCtx: { key: 'aaaa/bbbb.html' }, head: false }); assert.strictEqual(403, resp2.status); assert.strictEqual(2, govCalled.length); assert.strictEqual('aaaa/bbbb.html', govCalled[1].c.key); diff --git a/test/storage/bucket/list.test.js b/test/storage/bucket/list.test.js index cfab8252..999a1ee1 100644 --- a/test/storage/bucket/list.test.js +++ b/test/storage/bucket/list.test.js @@ -1,12 +1,22 @@ -import assert from 'assert'; +/* + * Copyright 2025 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +import assert from 'node:assert'; import listBuckets from '../../../src/storage/bucket/list.js'; -import env from './mocks/env.js'; describe('List', () => { const aclCtx = { - pathLookup: new Map() + pathLookup: new Map(), }; - const daCtx = { users: [{email: 'aparker@geometrixx.info'}], aclCtx }; + const daCtx = { users: [{ email: 'aparker@geometrixx.info' }], aclCtx }; /* This test has to be rewritten describe('Lists authed buckets', async () => { diff --git a/test/storage/bucket/mocks/env.js b/test/storage/bucket/mocks/env.js index 7cacc1b0..a07ec531 100644 --- a/test/storage/bucket/mocks/env.js +++ b/test/storage/bucket/mocks/env.js @@ -1,59 +1,68 @@ +/* + * Copyright 2025 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ const NAMESPACES = { orgs: [ { - "name": "adobe", - "created": "2024-01-09T23:38:05.949Z" + name: 'adobe', + created: '2024-01-09T23:38:05.949Z', }, { - "name": "geometrixx", - "created": "2023-11-30T06:04:10.008Z" + name: 'geometrixx', + created: '2023-11-30T06:04:10.008Z', }, { - "name": "wknd", - "created": "2023-11-30T06:04:10.008Z" - } + name: 'wknd', + created: '2023-11-30T06:04:10.008Z', + }, ], }; const DA_CONFIG = { geometrixx: { - "total": 1, - "limit": 1, - "offset": 0, - "data": [ - { - "key": "admin.role.all", - "value": "aparker@geometrixx.info" - } + total: 1, + limit: 1, + offset: 0, + data: [ + { + key: 'admin.role.all', + value: 'aparker@geometrixx.info', + }, ], - ":type": "sheet" + ':type': 'sheet', }, adobe: { - "total": 1, - "limit": 1, - "offset": 0, - "data": [ - { - "key": "admin.role.all", - "value": "notyou@you.com" - } + total: 1, + limit: 1, + offset: 0, + data: [ + { + key: 'admin.role.all', + value: 'notyou@you.com', + }, ], - ":type": "sheet" - } + ':type': 'sheet', + }, }; const env = { DA_AUTH: { - get: (kvNamespace) => { - return NAMESPACES[kvNamespace]; - } + get: (kvNamespace) => NAMESPACES[kvNamespace], }, DA_CONFIG: { get: (name) => { const nameConfig = DA_CONFIG[name]; console.log(nameConfig); return nameConfig; - } - } + }, + }, }; export default env; diff --git a/test/storage/kv/kv.test.js b/test/storage/kv/kv.test.js index 6b9df938..651a41ed 100644 --- a/test/storage/kv/kv.test.js +++ b/test/storage/kv/kv.test.js @@ -1,4 +1,16 @@ -import assert from 'assert'; +/* + * Copyright 2025 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +/* eslint-disable no-unused-vars */ +import assert from 'node:assert'; import getKv from '../../../src/storage/kv/get.js'; import putKv from '../../../src/storage/kv/put.js'; @@ -20,8 +32,8 @@ describe('KV storage', () => { it('Get success', async () => { const env = { DA_CONFIG: { - get: () => { return MOCK_CONFIG }, - } + get: () => MOCK_CONFIG, + }, }; const daCtx = { fullKey: 'adobe/geometrixx' }; @@ -31,7 +43,7 @@ describe('KV storage', () => { }); it('Get not found', async () => { - const env = { DA_CONFIG: { get: () => { return null } } }; + const env = { DA_CONFIG: { get: () => null } }; const daCtx = { fullKey: 'adobe/geometrixx' }; const resp = await getKv(env, daCtx); @@ -43,12 +55,12 @@ describe('KV storage', () => { const formData = new FormData(); formData.append('config', MOCK_CONFIG); - const req = { formData: () => { return formData; } }; + const req = { formData: () => formData }; const env = { DA_CONFIG: { - put: () => { return undefined }, - get: () => { return MOCK_CONFIG }, - } + put: () => undefined, + get: () => MOCK_CONFIG, + }, }; const daCtx = { fullKey: 'adobe/geometrixx' }; const resp = await putKv(req, env, daCtx); @@ -57,7 +69,7 @@ describe('KV storage', () => { }); it('Put without form data', async () => { - const req = { formData: () => { return null; } }; + const req = { formData: () => null }; const env = {}; const daCtx = { fullKey: 'adobe/geometrixx' }; const resp = await putKv(req, env, daCtx); @@ -69,12 +81,12 @@ describe('KV storage', () => { const formData = new FormData(); formData.append('config', 'abc'); - const req = { formData: () => { return formData; } }; + const req = { formData: () => formData }; const env = { DA_CONFIG: { - put: () => { return undefined }, - get: () => { return MOCK_CONFIG }, - } + put: () => undefined, + get: () => MOCK_CONFIG, + }, }; const daCtx = { fullKey: 'adobe/geometrixx' }; const resp = await putKv(req, env, daCtx); @@ -92,18 +104,18 @@ describe('Validate permission sheet', () => { { path: '/+*', actions: 'read', groups: 'me@foo.org' }, { path: 'CONFIG', actions: 'read', groups: 'hi@foo.org' }, { path: 'CONFIG', actions: 'write', groups: 'me@foo.org' }, - ] + ], }; const formData = new FormData(); formData.append('config', JSON.stringify(config)); - const req = { formData: () => { return formData; } }; + const req = { formData: () => formData }; const stored = []; const env = { DA_CONFIG: { put: (key, value) => { stored.push(value); }, - get: (key) => { return "dummy"; } - } + get: (key) => 'dummy', + }, }; const resp = await putKv(req, env, {}); @@ -119,20 +131,20 @@ describe('Validate permission sheet', () => { { path: '/+*', actions: 'read', groups: 'me@foo.org' }, { path: 'CONFIG', actions: 'read', groups: 'hi@foo.org' }, { path: 'CONFIG', actions: 'write', groups: 'me@foo.org' }, - ] + ], }, - blah: {} + blah: {}, }; const formData = new FormData(); formData.append('config', JSON.stringify(config)); - const req = { formData: () => { return formData; } }; + const req = { formData: () => formData }; const stored = []; const env = { DA_CONFIG: { put: (key, value) => { stored.push(value); }, - get: (key) => { return "dummy"; } - } + get: (key) => 'dummy', + }, }; const resp = await putKv(req, env, {}); @@ -147,19 +159,19 @@ describe('Validate permission sheet', () => { ':type': 'sheet', data: [ { path: '/+*', actions: 'write', groups: 'me@foo.org' }, - { path: 'CONFIG', actions: 'read', groups: 'me@foo.org' } - ] + { path: 'CONFIG', actions: 'read', groups: 'me@foo.org' }, + ], }; const formData = new FormData(); formData.append('config', JSON.stringify(config)); - const req = { formData: () => { return formData; } }; + const req = { formData: () => formData }; const stored = []; const env = { DA_CONFIG: { put: (key, value) => { stored.push(value); }, - get: (key) => { return "dummy"; } - } + get: (key) => 'dummy', + }, }; const resp = await putKv(req, env, {}); @@ -174,21 +186,21 @@ describe('Validate permission sheet', () => { permissions: { data: [ { path: '/+*', actions: 'write', groups: 'me@foo.org' }, - { path: 'CONFIG', actions: 'read', groups: 'me@foo.org' } + { path: 'CONFIG', actions: 'read', groups: 'me@foo.org' }, ], }, - foo: {} + foo: {}, }; const formData = new FormData(); formData.append('config', JSON.stringify(config)); - const req = { formData: () => { return formData; } }; + const req = { formData: () => formData }; const stored = []; const env = { DA_CONFIG: { put: (key, value) => { stored.push(value); }, - get: (key) => { return "dummy"; } - } + get: (key) => 'dummy', + }, }; const resp = await putKv(req, env, {}); @@ -202,18 +214,18 @@ describe('Validate permission sheet', () => { const config = { ':sheetname': 'other', ':type': 'sheet', - data: [] + data: [], }; const formData = new FormData(); formData.append('config', JSON.stringify(config)); - const req = { formData: () => { return formData; } }; + const req = { formData: () => formData }; const stored = []; const env = { DA_CONFIG: { put: (key, value) => { stored.push(value); }, - get: (key) => { return "dummy"; } - } + get: (key) => 'dummy', + }, }; const resp = await putKv(req, env, {}); diff --git a/test/storage/object/conditionals.test.js b/test/storage/object/conditionals.test.js index f63007eb..68c663b3 100644 --- a/test/storage/object/conditionals.test.js +++ b/test/storage/object/conditionals.test.js @@ -18,15 +18,14 @@ import { } from '@aws-sdk/client-s3'; import { mockClient } from 'aws-sdk-client-mock'; -const s3Mock = mockClient(S3Client); - import getObject from '../../../src/storage/object/get.js'; import { putObjectWithVersion } from '../../../src/storage/version/put.js'; +const s3Mock = mockClient(S3Client); + const ORG = 'adobe'; const KEY = 'wknd/index.html'; const BUCKET = 'root-bucket'; -const S3_KEY = `${ORG}/${KEY}`; describe('Conditional Headers', () => { beforeEach(() => { @@ -41,7 +40,12 @@ describe('Conditional Headers', () => { .rejects({ $metadata: { httpStatusCode: 304 } }); const conditionalHeaders = { ifNoneMatch: etag }; - const resp = await getObject({}, { bucket: BUCKET, org: ORG, key: KEY }, false, conditionalHeaders); + const resp = await getObject( + {}, + { bucket: BUCKET, org: ORG, key: KEY }, + false, + conditionalHeaders, + ); assert.strictEqual(resp.status, 304); assert.strictEqual(resp.body, ''); @@ -61,7 +65,12 @@ describe('Conditional Headers', () => { }); const conditionalHeaders = { ifNoneMatch: '"abc123"' }; - const resp = await getObject({}, { bucket: BUCKET, org: ORG, key: KEY }, false, conditionalHeaders); + const resp = await getObject( + {}, + { bucket: BUCKET, org: ORG, key: KEY }, + false, + conditionalHeaders, + ); assert.strictEqual(resp.status, 200); assert.deepStrictEqual(resp.body, Body); @@ -74,7 +83,12 @@ describe('Conditional Headers', () => { .rejects({ $metadata: { httpStatusCode: 304 } }); const conditionalHeaders = { ifNoneMatch: '*' }; - const resp = await getObject({}, { bucket: BUCKET, org: ORG, key: KEY }, false, conditionalHeaders); + const resp = await getObject( + {}, + { bucket: BUCKET, org: ORG, key: KEY }, + false, + conditionalHeaders, + ); assert.strictEqual(resp.status, 304); }); @@ -87,7 +101,12 @@ describe('Conditional Headers', () => { .rejects({ $metadata: { httpStatusCode: 412 } }); const conditionalHeaders = { ifMatch: '*' }; - const resp = await getObject({}, { bucket: BUCKET, org: ORG, key: KEY }, false, conditionalHeaders); + const resp = await getObject( + {}, + { bucket: BUCKET, org: ORG, key: KEY }, + false, + conditionalHeaders, + ); assert.strictEqual(resp.status, 412); }); @@ -105,7 +124,12 @@ describe('Conditional Headers', () => { }); const conditionalHeaders = { ifMatch: '*' }; - const resp = await getObject({}, { bucket: BUCKET, org: ORG, key: KEY }, false, conditionalHeaders); + const resp = await getObject( + {}, + { bucket: BUCKET, org: ORG, key: KEY }, + false, + conditionalHeaders, + ); assert.strictEqual(resp.status, 200); assert.deepStrictEqual(resp.body, Body); @@ -117,7 +141,12 @@ describe('Conditional Headers', () => { .rejects({ $metadata: { httpStatusCode: 412 } }); const conditionalHeaders = { ifMatch: '"wrongetag"' }; - const resp = await getObject({}, { bucket: BUCKET, org: ORG, key: KEY }, false, conditionalHeaders); + const resp = await getObject( + {}, + { bucket: BUCKET, org: ORG, key: KEY }, + false, + conditionalHeaders, + ); assert.strictEqual(resp.status, 412); }); @@ -189,7 +218,9 @@ describe('Conditional Headers', () => { .resolves({ $metadata: { httpStatusCode: 200 } }); const daCtx = { users: [{ email: 'test@example.com' }], ext: 'html', method: 'PUT' }; - const update = { bucket: BUCKET, org: ORG, key: KEY, body: Buffer.from('

new

'), type: 'text/html' }; + const update = { + bucket: BUCKET, org: ORG, key: KEY, body: Buffer.from('

new

'), type: 'text/html', + }; const clientConditionals = { ifMatch: '*' }; const resp = await putObjectWithVersion({}, daCtx, update, false, null, clientConditionals); @@ -213,7 +244,9 @@ describe('Conditional Headers', () => { .rejects({ $metadata: { httpStatusCode: 412 } }); const daCtx = { users: [{ email: 'test@example.com' }], ext: 'html', method: 'PUT' }; - const update = { bucket: BUCKET, org: ORG, key: KEY, body: Buffer.from('

new

'), type: 'text/html' }; + const update = { + bucket: BUCKET, org: ORG, key: KEY, body: Buffer.from('

new

'), type: 'text/html', + }; const clientConditionals = { ifMatch: '"wrongetag"' }; const resp = await putObjectWithVersion({}, daCtx, update, false, null, clientConditionals); @@ -234,7 +267,9 @@ describe('Conditional Headers', () => { .resolves({ $metadata: { httpStatusCode: 200 } }); const daCtx = { users: [{ email: 'test@example.com' }], ext: 'html', method: 'PUT' }; - const update = { bucket: BUCKET, org: ORG, key: KEY, body: Buffer.from('

new

'), type: 'text/html' }; + const update = { + bucket: BUCKET, org: ORG, key: KEY, body: Buffer.from('

new

'), type: 'text/html', + }; const clientConditionals = { ifNoneMatch: '*' }; const resp = await putObjectWithVersion({}, daCtx, update, false, null, clientConditionals); @@ -255,7 +290,9 @@ describe('Conditional Headers', () => { }); const daCtx = { users: [{ email: 'test@example.com' }], ext: 'html', method: 'PUT' }; - const update = { bucket: BUCKET, org: ORG, key: KEY, body: Buffer.from('

new

'), type: 'text/html' }; + const update = { + bucket: BUCKET, org: ORG, key: KEY, body: Buffer.from('

new

'), type: 'text/html', + }; const clientConditionals = { ifNoneMatch: '*' }; const resp = await putObjectWithVersion({}, daCtx, update, false, null, clientConditionals); @@ -272,7 +309,9 @@ describe('Conditional Headers', () => { .rejects({ $metadata: { httpStatusCode: 412 } }); const daCtx = { users: [{ email: 'test@example.com' }], ext: 'html', method: 'PUT' }; - const update = { bucket: BUCKET, org: ORG, key: KEY, body: Buffer.from('

new

'), type: 'text/html' }; + const update = { + bucket: BUCKET, org: ORG, key: KEY, body: Buffer.from('

new

'), type: 'text/html', + }; const clientConditionals = { ifNoneMatch: matchingEtag }; const resp = await putObjectWithVersion({}, daCtx, update, false, null, clientConditionals); @@ -290,9 +329,10 @@ describe('Conditional Headers', () => { .resolves({ $metadata: { httpStatusCode: 404 } }) .on(PutObjectCommand) .callsFake(() => { - callCount++; + callCount += 1; if (callCount === 1) { // First call fails with 412 + // eslint-disable-next-line prefer-promise-reject-errors return Promise.reject({ $metadata: { httpStatusCode: 412 } }); } // Second call succeeds @@ -300,7 +340,9 @@ describe('Conditional Headers', () => { }); const daCtx = { users: [{ email: 'test@example.com' }], ext: 'html', method: 'PUT' }; - const update = { bucket: BUCKET, org: ORG, key: KEY, body: Buffer.from('

new

'), type: 'text/html' }; + const update = { + bucket: BUCKET, org: ORG, key: KEY, body: Buffer.from('

new

'), type: 'text/html', + }; // No clientConditionals - should use internal retry logic const resp = await putObjectWithVersion({}, daCtx, update, false, null, null); @@ -319,7 +361,12 @@ describe('Conditional Headers', () => { .rejects({ $metadata: { httpStatusCode: 304 } }); const conditionalHeaders = { ifMatch: '"abc"', ifNoneMatch: '"abc"' }; - const resp = await getObject({}, { bucket: BUCKET, org: ORG, key: KEY }, false, conditionalHeaders); + const resp = await getObject( + {}, + { bucket: BUCKET, org: ORG, key: KEY }, + false, + conditionalHeaders, + ); // If-None-Match takes precedence for GET assert.strictEqual(resp.status, 304); @@ -340,7 +387,9 @@ describe('Conditional Headers', () => { .resolves({ $metadata: { httpStatusCode: 200 } }); const daCtx = { users: [{ email: 'test@example.com' }], ext: 'html', method: 'PUT' }; - const update = { bucket: BUCKET, org: ORG, key: KEY, body: Buffer.from('

new

'), type: 'text/html' }; + const update = { + bucket: BUCKET, org: ORG, key: KEY, body: Buffer.from('

new

'), type: 'text/html', + }; const clientConditionals = { ifMatch: '*', ifNoneMatch: '*' }; const resp = await putObjectWithVersion({}, daCtx, update, false, null, clientConditionals); @@ -356,7 +405,12 @@ describe('Conditional Headers', () => { .rejects({ $metadata: { httpStatusCode: 304 }, ETag: etag }); const conditionalHeaders = { ifNoneMatch: etag }; - const resp = await getObject({}, { bucket: BUCKET, org: ORG, key: KEY }, false, conditionalHeaders); + const resp = await getObject( + {}, + { bucket: BUCKET, org: ORG, key: KEY }, + false, + conditionalHeaders, + ); assert.strictEqual(resp.status, 304); assert.strictEqual(resp.etag, etag); @@ -373,7 +427,9 @@ describe('Conditional Headers', () => { ContentType: 'text/html', ContentLength: 15, ETag: actualEtag, - Metadata: { id: 'doc123', version: 'v1', timestamp: '123456', preparsingstore: '123456' }, + Metadata: { + id: 'doc123', version: 'v1', timestamp: '123456', preparsingstore: '123456', + }, $metadata: { httpStatusCode: 200 }, }) .on(PutObjectCommand) @@ -384,7 +440,9 @@ describe('Conditional Headers', () => { }); const daCtx = { users: [{ email: 'test@example.com' }], ext: 'html', method: 'PUT' }; - const update = { bucket: BUCKET, org: ORG, key: KEY, body: Buffer.from('

new

'), type: 'text/html' }; + const update = { + bucket: BUCKET, org: ORG, key: KEY, body: Buffer.from('

new

'), type: 'text/html', + }; const clientConditionals = { ifMatch: '*' }; const resp = await putObjectWithVersion({}, daCtx, update, false, null, clientConditionals); @@ -406,7 +464,12 @@ describe('Conditional Headers', () => { }); const conditionalHeaders = { ifNoneMatch: '""' }; - const resp = await getObject({}, { bucket: BUCKET, org: ORG, key: KEY }, false, conditionalHeaders); + const resp = await getObject( + {}, + { bucket: BUCKET, org: ORG, key: KEY }, + false, + conditionalHeaders, + ); // Should handle empty ETag without crashing assert(resp.status === 200 || resp.status === 304); @@ -481,7 +544,9 @@ describe('Conditional Headers', () => { }); const daCtx = { users: [{ email: 'test@example.com' }], ext: 'html', method: 'PUT' }; - const update = { bucket: BUCKET, org: ORG, key: KEY, body: Buffer.from('

new

'), type: 'text/html' }; + const update = { + bucket: BUCKET, org: ORG, key: KEY, body: Buffer.from('

new

'), type: 'text/html', + }; const clientConditionals = { ifNoneMatch: '*' }; const resp = await putObjectWithVersion({}, daCtx, update, false, null, clientConditionals); @@ -497,7 +562,9 @@ describe('Conditional Headers', () => { .resolves({ $metadata: { httpStatusCode: 404 } }); const daCtx = { users: [{ email: 'test@example.com' }], ext: 'html', method: 'PUT' }; - const update = { bucket: BUCKET, org: ORG, key: KEY, body: Buffer.from('

new

'), type: 'text/html' }; + const update = { + bucket: BUCKET, org: ORG, key: KEY, body: Buffer.from('

new

'), type: 'text/html', + }; const clientConditionals = { ifMatch: '*' }; const resp = await putObjectWithVersion({}, daCtx, update, false, null, clientConditionals); @@ -516,7 +583,9 @@ describe('Conditional Headers', () => { .resolves({ $metadata: { httpStatusCode: 200 }, ETag: newEtag }); const daCtx = { users: [{ email: 'test@example.com' }], ext: 'html', method: 'PUT' }; - const update = { bucket: BUCKET, org: ORG, key: KEY, body: Buffer.from('

new

'), type: 'text/html' }; + const update = { + bucket: BUCKET, org: ORG, key: KEY, body: Buffer.from('

new

'), type: 'text/html', + }; const resp = await putObjectWithVersion({}, daCtx, update, false, null, null); @@ -534,14 +603,18 @@ describe('Conditional Headers', () => { ContentType: 'text/html', ContentLength: 10, ETag: oldEtag, - Metadata: { id: 'doc123', version: 'v1', timestamp: '123456', preparsingstore: '123456' }, + Metadata: { + id: 'doc123', version: 'v1', timestamp: '123456', preparsingstore: '123456', + }, $metadata: { httpStatusCode: 200 }, }) .on(PutObjectCommand) .resolves({ $metadata: { httpStatusCode: 200 }, ETag: newEtag }); const daCtx = { users: [{ email: 'test@example.com' }], ext: 'html', method: 'PUT' }; - const update = { bucket: BUCKET, org: ORG, key: KEY, body: Buffer.from('

new

'), type: 'text/html' }; + const update = { + bucket: BUCKET, org: ORG, key: KEY, body: Buffer.from('

new

'), type: 'text/html', + }; const resp = await putObjectWithVersion({}, daCtx, update, false, null, null); diff --git a/test/storage/object/copy.test.js b/test/storage/object/copy.test.js index 6fc6ca1f..2c5fca40 100644 --- a/test/storage/object/copy.test.js +++ b/test/storage/object/copy.test.js @@ -1,14 +1,15 @@ /* - * Copyright 2024 Adobe. All rights reserved. - * This file is licensed to you under the Apache License, Version 2.0 (the 'License'); + * Copyright 2025 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ +/* eslint-disable no-unused-vars,consistent-return,max-classes-per-file */ import assert from 'node:assert'; import esmock from 'esmock'; import { CopyObjectCommand, ListObjectsV2Command, S3Client } from '@aws-sdk/client-s3'; @@ -42,18 +43,19 @@ describe('Object copy', () => { it('returns 403 when copying to a location without write permission', async () => { const pathLookup = new Map(); pathLookup.set('aaa@bbb.ccc', [ - {path: '/source/mysrc', actions: ['read']}, - {path: '/source/mydst', actions: ['read']} + { path: '/source/mysrc', actions: ['read'] }, + { path: '/source/mydst', actions: ['read'] }, ]); - const aclCtx = { pathLookup, actionSet: new Set(['read'])}; - const ctx = { aclCtx, key: 'source/mysrc', users: [{email: 'aaa@bbb.ccc'}] }; + const aclCtx = { pathLookup, actionSet: new Set(['read']) }; + const ctx = { aclCtx, key: 'source/mysrc', users: [{ email: 'aaa@bbb.ccc' }] }; const details = { source: 'mysrc', destination: 'mydst', }; + // eslint-disable-next-line no-shadow const { copyFile } = await import('../../../src/storage/object/copy.js'); const resp = await copyFile({}, {}, ctx, '/source/mysrc', details, false); assert.strictEqual(resp.$metadata.httpStatusCode, 403); @@ -90,12 +92,14 @@ describe('Object copy', () => { it('Copy to location with permission', async () => { const pathLookup = new Map(); pathLookup.set('aaa@bbb.ccc', [ - {path: '/source/mysrc', actions: ['read']}, - {path: '/source/mydst', actions: ['read', 'write']} + { path: '/source/mysrc', actions: ['read'] }, + { path: '/source/mydst', actions: ['read', 'write'] }, ]); - const aclCtx = { pathLookup, actionSet: new Set(['read'])}; - const ctx = { aclCtx, bucket: 'root-bucket', key: 'source/mysrc', org: 'org', users: [{email: 'aaa@bbb.ccc'}] }; + const aclCtx = { pathLookup, actionSet: new Set(['read']) }; + const ctx = { + aclCtx, bucket: 'root-bucket', key: 'source/mysrc', org: 'org', users: [{ email: 'aaa@bbb.ccc' }], + }; const details = { source: 'mysrc', @@ -103,16 +107,17 @@ describe('Object copy', () => { }; const mockS3Client = class { + // eslint-disable-next-line class-methods-use-this send(command) { return { command, $metadata: { httpStatusCode: 200 }, }; } + middlewareStack = { add: (a, b) => {}, }; - }; const mockGetObject = async (env, { bucket, org, key }, head) => { @@ -125,20 +130,19 @@ describe('Object copy', () => { } }; - const { copyFile } = await esmock( - '../../../src/storage/object/copy.js', { - '@aws-sdk/client-s3': { - S3Client: mockS3Client - }, - '../../../src/storage/object/get.js': { - default: mockGetObject, - }, - } - ) + // eslint-disable-next-line no-shadow + const { copyFile } = await esmock('../../../src/storage/object/copy.js', { + '@aws-sdk/client-s3': { + S3Client: mockS3Client, + }, + '../../../src/storage/object/get.js': { + default: mockGetObject, + }, + }); const resp = await copyFile({}, {}, ctx, 'source/mysrc', details, true); assert.strictEqual(resp.$metadata.httpStatusCode, 200); - const input = resp.command.input; + const { input } = resp.command; assert.strictEqual(input.Bucket, 'root-bucket'); assert.strictEqual(input.CopySource, 'root-bucket/org/source/mysrc'); assert.strictEqual(input.Key, 'org/source/mydst'); @@ -151,7 +155,7 @@ describe('Object copy', () => { s3Mock.on(ListObjectsV2Command).resolves({ Contents: [{ Key: 'mydir/xyz.html' }] }); const s3Sent = []; - s3Mock.on(CopyObjectCommand).callsFake((input => { + s3Mock.on(CopyObjectCommand).callsFake(((input) => { s3Sent.push(input); })); @@ -179,8 +183,8 @@ describe('Object copy', () => { const dacollab = { fetch: (url) => { collabcalls.push(url); - } - } + }, + }; const env = { dacollab }; const ctx = { bucket: 'root-bucket', @@ -196,13 +200,11 @@ describe('Object copy', () => { destination: 'mydir/newdir', }; - const copyObjectWithMock = await esmock( - '../../../src/storage/object/copy.js', { - '../../../src/storage/object/get.js': { - default: mockGetObject, - }, - } - ); + const copyObjectWithMock = await esmock('../../../src/storage/object/copy.js', { + '../../../src/storage/object/get.js': { + default: mockGetObject, + }, + }); await copyObjectWithMock.default(env, ctx, details, false); @@ -218,22 +220,24 @@ describe('Object copy', () => { assert.strictEqual(input.ContentType, 'text/html'); const md = input.Metadata; - assert(md.ID, "ID should be set"); - assert(md.Version, "Version should be set"); + assert(md.ID, 'ID should be set'); + assert(md.Version, 'Version should be set'); assert.strictEqual(typeof (md.Timestamp), 'string', 'Timestamp should be set as a string'); assert.strictEqual(md.Users, '[{"email":"haha@foo.com"}]'); assert.strictEqual(md.Path, 'mydir/newdir/xyz.html'); assert.strictEqual(1, collabcalls.length); - assert.deepStrictEqual(collabcalls, - ['https://localhost/api/v1/syncAdmin?doc=somehost.sometld/source/foo/mydir/newdir/xyz.html']); + assert.deepStrictEqual( + collabcalls, + ['https://localhost/api/v1/syncAdmin?doc=somehost.sometld/source/foo/mydir/newdir/xyz.html'], + ); }); it('Copies a file for rename', async () => { s3Mock.on(ListObjectsV2Command).resolves({ Contents: [{ Key: 'mydir/dir1/myfile.html' }] }); const s3Sent = []; - s3Mock.on(CopyObjectCommand).callsFake((input => { + s3Mock.on(CopyObjectCommand).callsFake(((input) => { s3Sent.push(input); })); @@ -261,23 +265,23 @@ describe('Object copy', () => { const dacollab = { fetch: (url) => { collabcalls.push(url); - } - } + }, + }; const env = { dacollab }; - const ctx = { bucket: 'root-bucket', org: 'testorg', key: 'mydir/dir1', origin: 'http://localhost:3000' }; + const ctx = { + bucket: 'root-bucket', org: 'testorg', key: 'mydir/dir1', origin: 'http://localhost:3000', + }; ctx.aclCtx = await getAclCtx(env, ctx.org, ctx.users, '/'); const details = { source: 'mydir/dir1', destination: 'mydir/dir2', }; - const copyObjectWithMock = await esmock( - '../../../src/storage/object/copy.js', { - '../../../src/storage/object/get.js': { - default: mockGetObject, - }, - } - ); + const copyObjectWithMock = await esmock('../../../src/storage/object/copy.js', { + '../../../src/storage/object/get.js': { + default: mockGetObject, + }, + }); await copyObjectWithMock.default(env, ctx, details, true); @@ -293,16 +297,20 @@ describe('Object copy', () => { assert.strictEqual(input.ContentType, 'text/html'); assert.ifError(input.Metadata); - assert.deepStrictEqual(collabcalls, - ['https://localhost/api/v1/syncAdmin?doc=http://localhost:3000/source/testorg/mydir/dir2/myfile.html']); + assert.deepStrictEqual( + collabcalls, + ['https://localhost/api/v1/syncAdmin?doc=http://localhost:3000/source/testorg/mydir/dir2/myfile.html'], + ); }); it('Adds copy condition', async () => { const msAdded = []; const mockS3Client = class { + // eslint-disable-next-line class-methods-use-this send(command) { return command; } + middlewareStack = { add: (a, b) => { msAdded.push(a); @@ -322,16 +330,15 @@ describe('Object copy', () => { return null; }; - const { copyFile } = await esmock( - '../../../src/storage/object/copy.js', { - '@aws-sdk/client-s3': { - S3Client: mockS3Client - }, - '../../../src/storage/object/get.js': { - default: mockGetObject, - }, - } - ) + // eslint-disable-next-line no-shadow + const { copyFile } = await esmock('../../../src/storage/object/copy.js', { + '@aws-sdk/client-s3': { + S3Client: mockS3Client, + }, + '../../../src/storage/object/get.js': { + default: mockGetObject, + }, + }); const collabCalled = []; const env = { @@ -343,7 +350,7 @@ describe('Object copy', () => { bucket: 'root-bucket', org: 'myorg', origin: 'https://blahblah:7890', - users: [{email: 'joe@bloggs.org', otherstuff: 'blah'}], + users: [{ email: 'joe@bloggs.org', otherstuff: 'blah' }], }; daCtx.aclCtx = await getAclCtx(env, daCtx.org, daCtx.users, '/'); const details = { @@ -383,11 +390,15 @@ describe('Object copy', () => { assert.strictEqual(nxtCalled.length, 1); assert.strictEqual(nxtCalled[0].request.foo, 'bar'); - assert.deepStrictEqual(nxtCalled[0].request.headers, - { aaa: 'bbb', 'cf-copy-destination-if-none-match': '*' }); + assert.deepStrictEqual( + nxtCalled[0].request.headers, + { aaa: 'bbb', 'cf-copy-destination-if-none-match': '*' }, + ); - assert.deepStrictEqual(collabCalled, - ['https://localhost/api/v1/syncAdmin?doc=https://blahblah:7890/source/myorg/mydst/abc/def.html']); + assert.deepStrictEqual( + collabCalled, + ['https://localhost/api/v1/syncAdmin?doc=https://blahblah:7890/source/myorg/mydst/abc/def.html'], + ); }); it('Copy content when destination already exists', async () => { @@ -396,9 +407,11 @@ describe('Object copy', () => { }; const mockS3Client = class { + // eslint-disable-next-line class-methods-use-this send() { throw error; } + middlewareStack = { add: () => {} }; }; const mockGetObject = async (e, u, h) => { @@ -409,28 +422,27 @@ describe('Object copy', () => { body: 'original body', contentLength: 42, contentType: 'text/html', - } + }; } }; - const puwv = [] + const puwv = []; const mockPutObjectWithVersion = async (e, c, u) => { - puwv.push({e, c, u}); + puwv.push({ e, c, u }); return 'beuaaark!'; }; - const { copyFile } = await esmock( - '../../../src/storage/object/copy.js', { - '../../../src/storage/object/get.js': { - default: mockGetObject, - }, - '../../../src/storage/version/put.js': { - putObjectWithVersion: mockPutObjectWithVersion, - }, - '@aws-sdk/client-s3': { - S3Client: mockS3Client, - }, + // eslint-disable-next-line no-shadow + const { copyFile } = await esmock('../../../src/storage/object/copy.js', { + '../../../src/storage/object/get.js': { + default: mockGetObject, }, - ); + '../../../src/storage/version/put.js': { + putObjectWithVersion: mockPutObjectWithVersion, + }, + '@aws-sdk/client-s3': { + S3Client: mockS3Client, + }, + }); const collabCalled = []; const env = { @@ -464,9 +476,11 @@ describe('Object copy', () => { }; const mockS3Client = class { + // eslint-disable-next-line class-methods-use-this send() { throw error; } + middlewareStack = { add: () => {} }; }; @@ -482,16 +496,15 @@ describe('Object copy', () => { return null; }; - const { copyFile } = await esmock( - '../../../src/storage/object/copy.js', { - '@aws-sdk/client-s3': { - S3Client: mockS3Client, - }, - '../../../src/storage/object/get.js': { - default: mockGetObject, - }, + // eslint-disable-next-line no-shadow + const { copyFile } = await esmock('../../../src/storage/object/copy.js', { + '@aws-sdk/client-s3': { + S3Client: mockS3Client, }, - ); + '../../../src/storage/object/get.js': { + default: mockGetObject, + }, + }); const collabCalled = []; const env = { @@ -507,8 +520,10 @@ describe('Object copy', () => { }; const resp = await copyFile({}, env, daCtx, 'qqqsrc/abc/def.html', details, false); assert.strictEqual(resp.$metadata.httpStatusCode, 404); - assert.deepStrictEqual(collabCalled, - ['https://localhost/api/v1/syncAdmin?doc=http://qqq/source/qqqorg/qqqdst/abc/def.html']); + assert.deepStrictEqual( + collabCalled, + ['https://localhost/api/v1/syncAdmin?doc=http://qqq/source/qqqorg/qqqdst/abc/def.html'], + ); }); }); @@ -519,29 +534,29 @@ describe('Object copy', () => { }); const s3Sent = []; - s3Mock.on(CopyObjectCommand).callsFake((input => { + s3Mock.on(CopyObjectCommand).callsFake(((input) => { s3Sent.push(input); })); - // Mock getObject to return content type for HEAD requests - const mockGetObject = async (env, { bucket, org, key }, head) => { - if (head && bucket === 'root-bucket' && org === 'foo') { - if (key === 'mydir/xyz.html') { - return { - contentType: 'text/html', - status: 200, - contentLength: 100, - }; - } else if (key === 'mydir' || key === 'mydir.props') { - return { - contentType: 'text/html', - status: 200, - contentLength: 100, - }; + // Mock getObject to return content type for HEAD requests + const mockGetObject = async (env, { bucket, org, key }, head) => { + if (head && bucket === 'root-bucket' && org === 'foo') { + if (key === 'mydir/xyz.html') { + return { + contentType: 'text/html', + status: 200, + contentLength: 100, + }; + } else if (key === 'mydir' || key === 'mydir.props') { + return { + contentType: 'text/html', + status: 200, + contentLength: 100, + }; + } } - } - return null; - }; + return null; + }; const env = { dacollab: { fetch: () => {} } }; const ctx = { @@ -556,13 +571,11 @@ describe('Object copy', () => { destination: 'mydir/newdir', }; - const copyObjectWithMock = await esmock( - '../../../src/storage/object/copy.js', { - '../../../src/storage/object/get.js': { - default: mockGetObject, - }, - } - ); + const copyObjectWithMock = await esmock('../../../src/storage/object/copy.js', { + '../../../src/storage/object/get.js': { + default: mockGetObject, + }, + }); const resp = await copyObjectWithMock.default(env, ctx, details, false); assert.strictEqual(resp.status, 204); @@ -576,10 +589,10 @@ describe('Object copy', () => { DA_JOBS: { put(key, value) { DA_JOBS[key] = value; - } + }, }, - dacollab: { fetch: () => {} } - } + dacollab: { fetch: () => {} }, + }; s3Mock.on(ListObjectsV2Command) .resolves({ Contents: [{ Key: 'mydir/xyz.html' }], @@ -592,6 +605,7 @@ describe('Object copy', () => { }); // Mock getObject to return content type for HEAD requests + // eslint-disable-next-line no-shadow const mockGetObject = async (env, { bucket, org, key }, head) => { if (head && bucket === 'root-bucket' && org === 'foo') { if (key === 'mydir/xyz.html' || key === 'mydir/abc.html') { @@ -612,7 +626,7 @@ describe('Object copy', () => { }; const s3Sent = []; - s3Mock.on(CopyObjectCommand).callsFake((input => { + s3Mock.on(CopyObjectCommand).callsFake(((input) => { s3Sent.push(input); })); @@ -628,13 +642,11 @@ describe('Object copy', () => { destination: 'mydir/newdir', }; - const copyObjectWithMock = await esmock( - '../../../src/storage/object/copy.js', { - '../../../src/storage/object/get.js': { - default: mockGetObject, - }, - } - ); + const copyObjectWithMock = await esmock('../../../src/storage/object/copy.js', { + '../../../src/storage/object/get.js': { + default: mockGetObject, + }, + }); const resp = await copyObjectWithMock.default(env, ctx, details, false); assert.strictEqual(resp.status, 206); @@ -647,7 +659,7 @@ describe('Object copy', () => { it('handles a continuation token w/ more', async () => { const continuationToken = 'copy-mydir-mydir/newdir-uuid'; const remaining = []; - for (let i = 0; i < 900; i++) { + for (let i = 0; i < 900; i += 1) { remaining.push(`mydir/file${i}.html`); } remaining.push('mydir/abc.html'); @@ -661,12 +673,13 @@ describe('Object copy', () => { }, get(key) { return DA_JOBS[key]; - } + }, }, - dacollab: { fetch: () => {} } - } + dacollab: { fetch: () => {} }, + }; // Mock getObject to return content type for HEAD requests + // eslint-disable-next-line no-shadow const mockGetObject = async (env, { bucket, org, key }, head) => { if (head && bucket === 'root-bucket' && org === 'foo' && key.startsWith('mydir/')) { return { @@ -691,17 +704,15 @@ describe('Object copy', () => { continuationToken, }; const s3Sent = []; - s3Mock.on(CopyObjectCommand).callsFake((input => { + s3Mock.on(CopyObjectCommand).callsFake(((input) => { s3Sent.push(input); })); - const copyObjectWithMock = await esmock( - '../../../src/storage/object/copy.js', { - '../../../src/storage/object/get.js': { - default: mockGetObject, - }, - } - ); + const copyObjectWithMock = await esmock('../../../src/storage/object/copy.js', { + '../../../src/storage/object/get.js': { + default: mockGetObject, + }, + }); const resp = await copyObjectWithMock.default(env, ctx, details, false); assert.strictEqual(resp.status, 206); @@ -723,12 +734,13 @@ describe('Object copy', () => { }, delete(key) { delete DA_JOBS[key]; - } + }, }, - dacollab: { fetch: () => {} } - } + dacollab: { fetch: () => {} }, + }; // Mock getObject to return content type for HEAD requests + // eslint-disable-next-line no-shadow const mockGetObject = async (env, { bucket, org, key }, head) => { if (head && bucket === 'root-bucket' && org === 'foo' && key === 'mydir/abc.html') { return { @@ -753,17 +765,15 @@ describe('Object copy', () => { continuationToken, }; const s3Sent = []; - s3Mock.on(CopyObjectCommand).callsFake((input => { + s3Mock.on(CopyObjectCommand).callsFake(((input) => { s3Sent.push(input); })); - const copyObjectWithMock = await esmock( - '../../../src/storage/object/copy.js', { - '../../../src/storage/object/get.js': { - default: mockGetObject, - }, - } - ); + const copyObjectWithMock = await esmock('../../../src/storage/object/copy.js', { + '../../../src/storage/object/get.js': { + default: mockGetObject, + }, + }); const resp = await copyObjectWithMock.default(env, ctx, details, false); assert.strictEqual(resp.status, 204); diff --git a/test/storage/object/delete.test.js b/test/storage/object/delete.test.js index 1c5572cf..3b04d1d6 100644 --- a/test/storage/object/delete.test.js +++ b/test/storage/object/delete.test.js @@ -1,14 +1,15 @@ /* - * Copyright 2024 Adobe. All rights reserved. - * This file is licensed to you under the Apache License, Version 2.0 (the 'License'); + * Copyright 2025 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ +/* eslint-disable consistent-return */ import assert from 'node:assert'; import esmock from 'esmock'; import { mockClient } from 'aws-sdk-client-mock'; @@ -16,7 +17,6 @@ import { ListObjectsV2Command, S3Client } from '@aws-sdk/client-s3'; const s3Mock = mockClient(S3Client); - describe('Object delete', () => { beforeEach(() => { s3Mock.reset(); @@ -24,7 +24,7 @@ describe('Object delete', () => { describe('single context', () => { it('Delete a file', async () => { - const collabCalled = [] + const collabCalled = []; const dacollab = { fetch: (u) => collabCalled.push(u) }; const client = {}; @@ -50,16 +50,14 @@ describe('Object delete', () => { } }; - const { deleteObject } = await esmock( - '../../../src/storage/object/delete.js', { - '../../../src/storage/version/put.js': { - postObjectVersionWithLabel: mockPostObjectVersion, - }, - '@aws-sdk/s3-request-presigner': { - getSignedUrl: mockSignedUrl, - } - } - ); + const { deleteObject } = await esmock('../../../src/storage/object/delete.js', { + '../../../src/storage/version/put.js': { + postObjectVersionWithLabel: mockPostObjectVersion, + }, + '@aws-sdk/s3-request-presigner': { + getSignedUrl: mockSignedUrl, + }, + }); const savedFetch = globalThis.fetch; try { @@ -102,16 +100,14 @@ describe('Object delete', () => { } }; - const { deleteObject } = await esmock( - '../../../src/storage/object/delete.js', { - '../../../src/storage/version/put.js': { - postObjectVersionWithLabel: mockPostObjectVersion, - }, - '@aws-sdk/s3-request-presigner': { - getSignedUrl: mockSignedUrl, - } - } - ); + const { deleteObject } = await esmock('../../../src/storage/object/delete.js', { + '../../../src/storage/version/put.js': { + postObjectVersionWithLabel: mockPostObjectVersion, + }, + '@aws-sdk/s3-request-presigner': { + getSignedUrl: mockSignedUrl, + }, + }); const savedFetch = globalThis.fetch; try { @@ -150,16 +146,14 @@ describe('Object delete', () => { } }; - const { deleteObject } = await esmock( - '../../../src/storage/object/delete.js', { - '../../../src/storage/version/put.js': { - postObjectVersionWithLabel: mockPostObjectVersion, - }, - '@aws-sdk/s3-request-presigner': { - getSignedUrl: mockSignedUrl, - } - } - ); + const { deleteObject } = await esmock('../../../src/storage/object/delete.js', { + '../../../src/storage/version/put.js': { + postObjectVersionWithLabel: mockPostObjectVersion, + }, + '@aws-sdk/s3-request-presigner': { + getSignedUrl: mockSignedUrl, + }, + }); const savedFetch = globalThis.fetch; try { @@ -198,16 +192,14 @@ describe('Object delete', () => { } }; - const { deleteObject } = await esmock( - '../../../src/storage/object/delete.js', { - '../../../src/storage/version/put.js': { - postObjectVersionWithLabel: mockPostObjectVersion, - }, - '@aws-sdk/s3-request-presigner': { - getSignedUrl: mockSignedUrl, - } - } - ); + const { deleteObject } = await esmock('../../../src/storage/object/delete.js', { + '../../../src/storage/version/put.js': { + postObjectVersionWithLabel: mockPostObjectVersion, + }, + '@aws-sdk/s3-request-presigner': { + getSignedUrl: mockSignedUrl, + }, + }); const savedFetch = globalThis.fetch; try { @@ -236,7 +228,7 @@ describe('Object delete', () => { const env = { dacollab: { fetch: () => { - } + }, }, }; const mockPostObjectVersion = async () => ({ status: 201 }); @@ -249,7 +241,7 @@ describe('Object delete', () => { }, '@aws-sdk/s3-request-presigner': { getSignedUrl: mockSignedUrl, - } + }, }, ); s3Mock.on(ListObjectsV2Command).resolves({ Contents: [{ Key: 'foo/bar.html' }] }); @@ -266,7 +258,7 @@ describe('Object delete', () => { const env = { dacollab: { fetch: () => { - } + }, }, }; const mockPostObjectVersion = async () => ({ status: 201 }); @@ -279,7 +271,7 @@ describe('Object delete', () => { }, '@aws-sdk/s3-request-presigner': { getSignedUrl: mockSignedUrl, - } + }, }, ); s3Mock.on(ListObjectsV2Command).resolves({ Contents: [{ Key: 'foo/bar.html' }], NextContinuationToken: 'token' }); @@ -288,30 +280,26 @@ describe('Object delete', () => { }); it('Delete permissions', async () => { - const listCommand = () => { - return { - sourceKeys: [ 'a', 'b', 'c'] - } - }; + const listCommand = () => ({ + sourceKeys: ['a', 'b', 'c'], + }); const getSignedUrl = (c, dc) => { assert.strictEqual(dc.input.Bucket, 'testbucket'); return dc.input.Key; - } + }; const mockS3Client = class {}; - const deleteObjects = await esmock( - '../../../src/storage/object/delete.js', { - '../../../src/storage/utils/list.js': { - listCommand - }, - '@aws-sdk/client-s3': { - S3Client: mockS3Client - }, - '@aws-sdk/s3-request-presigner': { - getSignedUrl - } - } - ); + const deleteObjects = await esmock('../../../src/storage/object/delete.js', { + '../../../src/storage/utils/list.js': { + listCommand, + }, + '@aws-sdk/client-s3': { + S3Client: mockS3Client, + }, + '@aws-sdk/s3-request-presigner': { + getSignedUrl, + }, + }); const pathLookup = new Map(); pathLookup.set('harry@foo.org', [ @@ -321,7 +309,9 @@ describe('Object delete', () => { ]); const aclCtx = { pathLookup }; const users = [{ email: 'harry@foo.org' }]; - const ctx = { bucket: 'testbucket', org: 'myorg', aclCtx, users, key: 'notused' }; + const ctx = { + bucket: 'testbucket', org: 'myorg', aclCtx, users, key: 'notused', + }; const fetchURLs = []; const savedFetch = globalThis.fetch; diff --git a/test/storage/object/get.test.js b/test/storage/object/get.test.js index ec3018b2..ec18a0b9 100644 --- a/test/storage/object/get.test.js +++ b/test/storage/object/get.test.js @@ -18,13 +18,13 @@ import { import { mockClient } from 'aws-sdk-client-mock'; import esmock from 'esmock'; -const s3Mock = mockClient(S3Client); - import getObject from '../../../src/storage/object/get.js'; +const s3Mock = mockClient(S3Client); + const ORG = 'adobe'; const KEY = 'wknd/index.html'; -const BUCKET = `root-bucket`; +const BUCKET = 'root-bucket'; const S3_KEY = `${ORG}/${KEY}`; @@ -37,7 +37,7 @@ describe('Get Object', () => { const Body = Buffer.from('

hello world

'); const ContentType = 'text/html'; const ContentLength = Body.length; - const LastModified = new Date().toISOString + const LastModified = new Date().toISOString; const Metadata = { foo: 'bar' }; const ETag = 'etag123'; s3Mock @@ -73,7 +73,7 @@ describe('Get Object', () => { '@aws-sdk/s3-request-presigner': { getSignedUrl: async () => fakeUrl, }, - } + }, ); const savedFetch = globalThis.fetch; @@ -121,6 +121,7 @@ describe('Get Object', () => { Key: S3_KEY, }).rejects(error); // Import getObject directly for head=false (no esmock needed) + // eslint-disable-next-line no-shadow const getObject = (await import('../../../src/storage/object/get.js')).default; const resp = await getObject({}, { bucket: BUCKET, org: ORG, key: KEY }, false); assert.strictEqual(resp.status, 404); diff --git a/test/storage/object/list.test.js b/test/storage/object/list.test.js index 211714ee..04cf3cae 100644 --- a/test/storage/object/list.test.js +++ b/test/storage/object/list.test.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 @@ -14,17 +14,16 @@ import assert from 'node:assert'; import { ListObjectsV2Command, S3Client } from '@aws-sdk/client-s3'; import { mockClient } from 'aws-sdk-client-mock'; -const s3Mock = mockClient(S3Client); - import listObjects from '../../../src/storage/object/list.js'; +const s3Mock = mockClient(S3Client); + const Contents = [ { Key: 'wknd/index.html', LastModified: new Date() }, { Key: 'wknd/nav.html', LastModified: new Date() }, { Key: 'wknd/footer.html', LastModified: new Date() }, ]; - describe('List Objects', () => { beforeEach(() => { s3Mock.reset(); @@ -50,11 +49,11 @@ describe('List Objects', () => { Prefix: 'acme/wknd/', Delimiter: '/', MaxKeys: 2, - }).resolves({ $metadata: { httpStatusCode: 200 }, Contents: [Contents[0], Contents[1]]}); + }).resolves({ $metadata: { httpStatusCode: 200 }, Contents: [Contents[0], Contents[1]] }); const daCtx = { bucket: 'rt-bkt', org: 'acme', key: 'wknd' }; const resp = await listObjects({}, daCtx, 2); const data = JSON.parse(resp.body); assert.strictEqual(data.length, 2, 'Should only return 2 items'); }); -}) +}); diff --git a/test/storage/object/mocks/version/put.js b/test/storage/object/mocks/version/put.js index 60f60dee..55613559 100644 --- a/test/storage/object/mocks/version/put.js +++ b/test/storage/object/mocks/version/put.js @@ -1,7 +1,19 @@ +/* + * Copyright 2025 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +// eslint-disable-next-line no-unused-vars export async function postObjectVersion(env, daCtx) { return 200; } export async function putObjectWithVersion(env, daCtx, update, body, guid) { - return { status: 201, metadata: { id: guid}}; + return { status: 201, metadata: { id: guid } }; } diff --git a/test/storage/object/move.test.js b/test/storage/object/move.test.js index d7cad825..63db4250 100644 --- a/test/storage/object/move.test.js +++ b/test/storage/object/move.test.js @@ -1,11 +1,11 @@ /* * Copyright 2025 Adobe. All rights reserved. - * This file is licensed to you under the Apache License, Version 2.0 (the 'License'); + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ @@ -15,20 +15,23 @@ import esmock from 'esmock'; describe('Move', () => { it('Move files with permission check', async () => { const mockS3Client = class { + // eslint-disable-next-line class-methods-use-this,no-unused-vars send(c) { - return { Contents: [ - { Key: 'myorg/somewhere/x.html' }, - { Key: 'myorg/somewhere/y.png' }, - { Key: 'myorg/somewhere/z.html' }, - ]}; + return { + Contents: [ + { Key: 'myorg/somewhere/x.html' }, + { Key: 'myorg/somewhere/y.png' }, + { Key: 'myorg/somewhere/z.html' }, + ], + }; } }; const copyFileCalled = []; const copyFile = (c, e, x, k, d, m) => { copyFileCalled.push({ k, d, m }); - if (k === 'somewhere/y.png') return { $metadata: { httpStatusCode: 403 }}; - return { $metadata: { httpStatusCode: 200 }}; + if (k === 'somewhere/y.png') return { $metadata: { httpStatusCode: 403 } }; + return { $metadata: { httpStatusCode: 200 } }; }; const deleteObjectCalled = []; @@ -37,19 +40,17 @@ describe('Move', () => { return { status: 204 }; }; - const moveObject = await esmock( - '../../../src/storage/object/move.js', { - '@aws-sdk/client-s3': { - S3Client: mockS3Client - }, - '../../../src/storage/object/copy.js': { - copyFile - }, - '../../../src/storage/object/delete.js': { - deleteObject - } - } - ); + const moveObject = await esmock('../../../src/storage/object/move.js', { + '@aws-sdk/client-s3': { + S3Client: mockS3Client, + }, + '../../../src/storage/object/copy.js': { + copyFile, + }, + '../../../src/storage/object/delete.js': { + deleteObject, + }, + }); const pathLookup = new Map(); pathLookup.set('blah@foo.org', [ @@ -58,14 +59,16 @@ describe('Move', () => { { path: '/somedest/+**', actions: ['read', 'write'] }, ]); const aclCtx = { pathLookup }; - const users = [ { email: 'blah@foo.org' }]; - const ctx = { org: 'myorg', aclCtx, users, key: 'q.html' }; + const users = [{ email: 'blah@foo.org' }]; + const ctx = { + org: 'myorg', aclCtx, users, key: 'q.html', + }; const details = { source: 'somewhere', destination: 'nonpermdest' }; const resp = await moveObject({}, ctx, details); assert.strictEqual(204, resp.status); assert.strictEqual(0, copyFileCalled.length); - assert.strictEqual(0, deleteObjectCalled.length) + assert.strictEqual(0, deleteObjectCalled.length); const details2 = { source: 'somewhere', destination: 'somedest' }; const resp2 = await moveObject({}, ctx, details2); @@ -79,8 +82,11 @@ describe('Move', () => { assert(paths.has('somewhere/z.html')); assert(paths.has('somewhere')); - assert.strictEqual(2, deleteObjectCalled.length, - 'Note that copy y.png failed, so should not have deleted it'); + assert.strictEqual( + 2, + deleteObjectCalled.length, + 'Note that copy y.png failed, so should not have deleted it', + ); assert(deleteObjectCalled.every((c) => c.m === true), 'Move should be specified'); const delPath = new Set(deleteObjectCalled.map((c) => c.k)); assert(delPath.has('somewhere')); diff --git a/test/storage/object/put.test.js b/test/storage/object/put.test.js index 353655ab..731ce103 100644 --- a/test/storage/object/put.test.js +++ b/test/storage/object/put.test.js @@ -1,19 +1,29 @@ -import assert from 'assert'; +/* + * Copyright 2025 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +import assert from 'node:assert'; import { strict as esmock } from 'esmock'; -import env from '../../utils/mocks/env.js'; - import { mockClient } from 'aws-sdk-client-mock'; import { S3Client } from '@aws-sdk/client-s3'; - -const s3Mock = mockClient(S3Client); +import env from '../../utils/mocks/env.js'; import { putObjectWithVersion, postObjectVersion } from './mocks/version/put.js'; + +const s3Mock = mockClient(S3Client); const putObject = await esmock('../../../src/storage/object/put.js', { '../../../src/storage/version/put.js': { putObjectWithVersion, postObjectVersion, - } + }, }); describe('Object storage', () => { @@ -23,7 +33,9 @@ describe('Object storage', () => { describe('Put success', async () => { it('Successfully puts text data', async () => { - const daCtx = { org: 'adobe', site: 'geometrixx', key: 'geometrixx', propsKey: 'geometrixx.props' }; + const daCtx = { + org: 'adobe', site: 'geometrixx', key: 'geometrixx', propsKey: 'geometrixx.props', + }; const obj = { data: '', guid: '8888' }; const resp = await putObject(env, daCtx, obj); assert.strictEqual(resp.status, 201); @@ -31,16 +43,20 @@ describe('Object storage', () => { }); it('Successfully puts file data', async () => { - const daCtx = { org: 'adobe', site: 'geometrixx', isFile: true, key: 'geometrixx/foo.html', pathname: '/foo', propsKey: 'geometrixx/foo.html.props' }; + const daCtx = { + org: 'adobe', site: 'geometrixx', isFile: true, key: 'geometrixx/foo.html', pathname: '/foo', propsKey: 'geometrixx/foo.html.props', + }; const data = new File(['foo'], 'foo.txt', { type: 'text/plain' }); const obj = { data }; const resp = await putObject(env, daCtx, obj); assert.strictEqual(resp.status, 201); - assert.strictEqual(JSON.parse(resp.body).source.editUrl, 'https://da.live/edit#/adobe/foo') + assert.strictEqual(JSON.parse(resp.body).source.editUrl, 'https://da.live/edit#/adobe/foo'); }); it('Successfully puts no data', async () => { - const daCtx = { org: 'adobe', site: 'geometrixx', key: 'geometrixx', propsKey: 'geometrixx.props' }; + const daCtx = { + org: 'adobe', site: 'geometrixx', key: 'geometrixx', propsKey: 'geometrixx.props', + }; const resp = await putObject(env, daCtx); assert.strictEqual(resp.status, 201); }); diff --git a/test/storage/utils/list.test.js b/test/storage/utils/list.test.js index d93c6b59..f4f3919e 100644 --- a/test/storage/utils/list.test.js +++ b/test/storage/utils/list.test.js @@ -1,5 +1,16 @@ +/* + * Copyright 2025 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ /* eslint-env mocha */ -import assert from 'assert'; +import assert from 'node:assert'; import sinon from 'sinon'; import getDaCtx from '../../../src/utils/daCtx.js'; @@ -24,7 +35,7 @@ const MOCK = { LastModified: new Date('2025-01-01'), }, { - Key: 'folder-only.props', + Key: 'folder-only.props', LastModified: new Date('2025-01-01'), }, { @@ -46,7 +57,7 @@ const MOCK = { { Key: 'empty-folder-with-sibling-file.html', LastModified: new Date('2025-01-01'), - } + }, ], }; @@ -62,7 +73,7 @@ describe('Format object list', () => { }); it('should return a contents-based folder', () => { - const folderOnly = list.find((item) => { return item.name === 'folder-only' }); + const folderOnly = list.find((item) => item.name === 'folder-only'); assert.strictEqual(folderOnly.name, 'folder-only'); }); @@ -70,18 +81,18 @@ describe('Format object list', () => { const found = list.reduce((acc, item) => { if (item.name === 'blog') acc.push(item); return acc; - },[]); + }, []); assert.strictEqual(found.length, 1); }); it('should not have a filename props file in the list', () => { - const propsSidecar = list.find((item) => { return item.name === 'dark-alley.jpg.props' }); + const propsSidecar = list.find((item) => item.name === 'dark-alley.jpg.props'); assert.strictEqual(propsSidecar, undefined); }); it('should handle empty folders with sibling file names of same name', () => { - const filtered = list.filter((item) => { return item.name === 'empty-folder-with-sibling-file' }); + const filtered = list.filter((item) => item.name === 'empty-folder-with-sibling-file'); assert.strictEqual(filtered.length, 2); }); @@ -110,13 +121,13 @@ describe('Format object list', () => { const mockWithExtensionFolder = { CommonPrefixes: [ { Prefix: 'file.jpg/' }, - { Prefix: 'normal-folder/' } - ] + { Prefix: 'normal-folder/' }, + ], }; const result = formatList(mockWithExtensionFolder, daCtx); - const extensionFolder = result.find(item => item.name === 'file.jpg'); + const extensionFolder = result.find((item) => item.name === 'file.jpg'); assert.strictEqual(extensionFolder, undefined); - const normalFolder = result.find(item => item.name === 'normal-folder'); + const normalFolder = result.find((item) => item.name === 'normal-folder'); assert(normalFolder); }); @@ -126,8 +137,8 @@ describe('Format object list', () => { { Key: 'file.name.with.multiple.dots', LastModified: new Date('2025-01-01'), - } - ] + }, + ], }; const result = formatList(mockWithComplexFile, daCtx); assert.strictEqual(result.length, 0); @@ -139,8 +150,8 @@ describe('Format object list', () => { { Key: '.hidden-file', LastModified: new Date('2025-01-01'), - } - ] + }, + ], }; const result = formatList(mockWithHiddenFile, daCtx); assert.strictEqual(result.length, 0); @@ -152,11 +163,11 @@ describe('Format object list', () => { { Key: 'test.props', LastModified: new Date('2025-01-01'), - } - ] + }, + ], }; const result = formatList(mockWithProps, daCtx); - const propsItem = result.find(item => item.name === 'test'); + const propsItem = result.find((item) => item.name === 'test'); assert(propsItem); assert.strictEqual(propsItem.ext, undefined); assert.strictEqual(propsItem.lastModified, undefined); @@ -169,11 +180,11 @@ describe('Format object list', () => { { Key: 'test.props', LastModified: new Date('2025-01-01'), - } - ] + }, + ], }; const result = formatList(mockWithBoth, daCtx); - const testItems = result.filter(item => item.name === 'test'); + const testItems = result.filter((item) => item.name === 'test'); assert.strictEqual(testItems.length, 1); }); @@ -182,8 +193,8 @@ describe('Format object list', () => { Contents: [ { Key: 'zebra.html', LastModified: new Date('2025-01-01') }, { Key: 'alpha.html', LastModified: new Date('2025-01-01') }, - { Key: 'beta.html', LastModified: new Date('2025-01-01') } - ] + { Key: 'beta.html', LastModified: new Date('2025-01-01') }, + ], }; const result = formatList(mockForSorting, daCtx); assert.strictEqual(result[0].name, 'alpha'); @@ -198,15 +209,15 @@ describe('listCommand', () => { beforeEach(() => { mockS3Client = { - send: sinon.stub() + send: sinon.stub(), }; - + // Create a proper daCtx object for testing testDaCtx = { bucket: 'test-bucket', org: 'adobecom', key: 'test', - ext: undefined + ext: undefined, }; }); @@ -217,7 +228,7 @@ describe('listCommand', () => { it('should return sourceKeys array when item has extension', async () => { const daCtxWithExt = { ...testDaCtx, ext: 'html' }; const result = await listCommand(daCtxWithExt, {}, mockS3Client); - + assert.deepStrictEqual(result, { sourceKeys: [testDaCtx.key] }); assert.strictEqual(mockS3Client.send.callCount, 0); }); @@ -226,34 +237,34 @@ describe('listCommand', () => { const mockResponse = { Contents: [ { Key: 'adobecom/test/file1.html' }, - { Key: 'adobecom/test/file2.html' } + { Key: 'adobecom/test/file2.html' }, ], - NextContinuationToken: 'next-token' + NextContinuationToken: 'next-token', }; - + mockS3Client.send.resolves(mockResponse); - + const result = await listCommand(testDaCtx, {}, mockS3Client); - + assert.strictEqual(mockS3Client.send.callCount, 1); assert.deepStrictEqual(result, { sourceKeys: [testDaCtx.key, `${testDaCtx.key}.props`, 'test/file1.html', 'test/file2.html'], - continuationToken: 'next-token' + continuationToken: 'next-token', }); }); it('should handle continuation token', async () => { const mockResponse = { Contents: [ - { Key: 'adobecom/test/file3.html' } - ] + { Key: 'adobecom/test/file3.html' }, + ], }; - + mockS3Client.send.resolves(mockResponse); - + const details = { continuationToken: 'prev-token' }; const result = await listCommand(testDaCtx, details, mockS3Client); - + assert.strictEqual(mockS3Client.send.callCount, 1); const callArgs = mockS3Client.send.firstCall.args[0]; console.log('Call args:', JSON.stringify(callArgs, null, 2)); @@ -261,39 +272,39 @@ describe('listCommand', () => { assert.strictEqual(callArgs.input.ContinuationToken, 'prev-token'); assert.deepStrictEqual(result, { sourceKeys: ['test/file3.html'], - continuationToken: undefined + continuationToken: undefined, }); }); it('should handle empty Contents response', async () => { const mockResponse = { - Contents: [] + Contents: [], }; - + mockS3Client.send.resolves(mockResponse); - + const result = await listCommand(testDaCtx, {}, mockS3Client); - + assert.deepStrictEqual(result, { sourceKeys: [testDaCtx.key, `${testDaCtx.key}.props`], - continuationToken: undefined + continuationToken: undefined, }); }); it('should handle response without NextContinuationToken', async () => { const mockResponse = { Contents: [ - { Key: 'test/file1.html' } - ] + { Key: 'test/file1.html' }, + ], }; - + mockS3Client.send.resolves(mockResponse); - + const result = await listCommand(testDaCtx, {}, mockS3Client); - + assert.deepStrictEqual(result, { sourceKeys: [testDaCtx.key, `${testDaCtx.key}.props`, 'test/file1.html'], - continuationToken: undefined + continuationToken: undefined, }); }); }); diff --git a/test/storage/utils/object.test.js b/test/storage/utils/object.test.js index 52a1e9cc..9d6f3adc 100644 --- a/test/storage/utils/object.test.js +++ b/test/storage/utils/object.test.js @@ -11,7 +11,7 @@ */ /* eslint-env mocha */ -import assert from 'assert'; +import assert from 'node:assert'; import { invalidateCollab } from '../../../src/storage/utils/object.js'; describe('Storage Object Utils tests', () => { diff --git a/test/storage/version/put.test.js b/test/storage/version/put.test.js index b6fafcdc..0259f313 100644 --- a/test/storage/version/put.test.js +++ b/test/storage/version/put.test.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 @@ -9,17 +9,18 @@ * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ -import assert from 'assert'; +/* eslint-disable no-unused-vars,camelcase */ +import assert from 'node:assert'; import esmock from 'esmock'; describe('Version Put', () => { it('Test putObjectWithVersion retry on new document', async () => { - const getObjectCalls = [] + const getObjectCalls = []; const mockGetObject = async (e, u, nb) => { - getObjectCalls.push({e, u, nb}); + getObjectCalls.push({ e, u, nb }); return { status: 404, - metadata: {} + metadata: {}, }; }; @@ -30,8 +31,8 @@ describe('Version Put', () => { sendCalls.push(cmd); const resp = { $metadata: { - httpStatusCode: firstCall ? 412 : 200 - } + httpStatusCode: firstCall ? 412 : 200, + }, }; if (firstCall) { firstCall = false; @@ -39,15 +40,15 @@ describe('Version Put', () => { } else { return resp; } - } + }, }; const { putObjectWithVersion } = await esmock('../../../src/storage/version/put.js', { '../../../src/storage/object/get.js': { - default: mockGetObject + default: mockGetObject, }, '../../../src/storage/utils/version.js': { - ifNoneMatch: () => mockS3Client + ifNoneMatch: () => mockS3Client, }, }); @@ -57,7 +58,7 @@ describe('Version Put', () => { const resp = await putObjectWithVersion(mockEnv, mockCtx, mockUpdate, false); assert.equal(201, resp.status); - assert(resp.metadata.id) + assert(resp.metadata.id); assert.equal(2, getObjectCalls.length); assert.equal(getObjectCalls[0].e, mockEnv); assert.equal(getObjectCalls[0].u, mockUpdate); @@ -72,12 +73,12 @@ describe('Version Put', () => { }); it('Test putObjectWithVersion error', async () => { - const getObjectCalls = [] + const getObjectCalls = []; const mockGetObject = async (e, u, nb) => { - getObjectCalls.push({e, u, nb}); + getObjectCalls.push({ e, u, nb }); return { status: 404, - metadata: {} + metadata: {}, }; }; @@ -87,19 +88,19 @@ describe('Version Put', () => { sendCalls.push(cmd); const resp = { $metadata: { - httpStatusCode: 510 - } + httpStatusCode: 510, + }, }; throw resp; - } + }, }; const { putObjectWithVersion } = await esmock('../../../src/storage/version/put.js', { '../../../src/storage/object/get.js': { - default: mockGetObject + default: mockGetObject, }, '../../../src/storage/utils/version.js': { - ifNoneMatch: () => mockS3Client + ifNoneMatch: () => mockS3Client, }, }); @@ -110,12 +111,12 @@ describe('Version Put', () => { }); it('Test putObjectWithVersion retry on existing document', async () => { - const getObjectCalls = [] + const getObjectCalls = []; const mockGetObject = async (e, u, nb) => { - getObjectCalls.push({e, u, nb}); + getObjectCalls.push({ e, u, nb }); return { status: 200, - metadata: {} + metadata: {}, }; }; @@ -126,8 +127,8 @@ describe('Version Put', () => { sendCalls.push(cmd); const resp = { $metadata: { - httpStatusCode: firstCall ? 412 : 200 - } + httpStatusCode: firstCall ? 412 : 200, + }, }; if (firstCall) { firstCall = false; @@ -135,25 +136,25 @@ describe('Version Put', () => { } else { return resp; } - } + }, }; const mockS3PutClient = { async send(cmd) { return { $metadata: { - httpStatusCode: 200 - } + httpStatusCode: 200, + }, }; - } + }, }; const { putObjectWithVersion } = await esmock('../../../src/storage/version/put.js', { '../../../src/storage/object/get.js': { - default: mockGetObject + default: mockGetObject, }, '../../../src/storage/utils/version.js': { ifMatch: () => mockS3Client, - ifNoneMatch: () => mockS3PutClient + ifNoneMatch: () => mockS3PutClient, }, }); @@ -177,12 +178,12 @@ describe('Version Put', () => { }); it('Test putObjectWithVersion retry fails on existing document', async () => { - const getObjectCalls = [] + const getObjectCalls = []; const mockGetObject = async (e, u, nb) => { - getObjectCalls.push({e, u, nb}); + getObjectCalls.push({ e, u, nb }); return { status: 200, - metadata: {} + metadata: {}, }; }; @@ -191,25 +192,25 @@ describe('Version Put', () => { async send(cmd) { sendCalls.push(cmd); throw new Error('testing 123'); - } + }, }; const mockS3PutClient = { async send(cmd) { return { $metadata: { - httpStatusCode: 200 - } + httpStatusCode: 200, + }, }; - } + }, }; const { putObjectWithVersion } = await esmock('../../../src/storage/version/put.js', { '../../../src/storage/object/get.js': { - default: mockGetObject + default: mockGetObject, }, '../../../src/storage/utils/version.js': { ifMatch: () => mockS3Client, - ifNoneMatch: () => mockS3PutClient + ifNoneMatch: () => mockS3PutClient, }, }); @@ -221,6 +222,7 @@ describe('Version Put', () => { }); it('Put Object With Version store content', async () => { + // eslint-disable-next-line consistent-return const mockGetObject = async (e, u, h) => { if (!h) { return { @@ -229,17 +231,17 @@ describe('Version Put', () => { id: 'x123', version: 'aaa-bbb', }, - status: 200 + status: 200, }; } - } + }; const s3VersionSent = []; const mockS3VersionClient = { send: (c) => { s3VersionSent.push(c); return { $metadata: { httpStatusCode: 200 } }; - } + }, }; const mockIfNoneMatch = () => mockS3VersionClient; @@ -248,13 +250,13 @@ describe('Version Put', () => { send: (c) => { s3Sent.push(c); return { $metadata: { httpStatusCode: 200 } }; - } + }, }; - const mockIfMatch = () => mockS3Client + const mockIfMatch = () => mockS3Client; const { putObjectWithVersion } = await esmock('../../../src/storage/version/put.js', { '../../../src/storage/object/get.js': { - default: mockGetObject + default: mockGetObject, }, '../../../src/storage/utils/version.js': { ifNoneMatch: mockIfNoneMatch, @@ -263,8 +265,10 @@ describe('Version Put', () => { }); const env = {}; - const daCtx= { bucket: 'bkt', org: 'myorg', ext: 'html' }; - const update = { bucket: 'bkt', body: 'new-body', org: 'myorg', key: 'a/x.html' }; + const daCtx = { bucket: 'bkt', org: 'myorg', ext: 'html' }; + const update = { + bucket: 'bkt', body: 'new-body', org: 'myorg', key: 'a/x.html', + }; const resp = await putObjectWithVersion(env, daCtx, update, true); assert.equal(200, resp.status); assert.equal('x123', resp.metadata.id); @@ -287,6 +291,7 @@ describe('Version Put', () => { }); it('Put Object With Version don\'t store content', async () => { + // eslint-disable-next-line consistent-return const mockGetObject = async (e, u, h) => { if (!h) { return { @@ -296,17 +301,17 @@ describe('Version Put', () => { preparsingstore: Date.now(), version: 'ver123', }, - status: 201 + status: 201, }; } - } + }; const s3VersionSent = []; const mockS3VersionClient = { send: (c) => { s3VersionSent.push(c); return { $metadata: { httpStatusCode: 200 } }; - } + }, }; const mockIfNoneMatch = () => mockS3VersionClient; @@ -315,13 +320,13 @@ describe('Version Put', () => { send: (c) => { s3Sent.push(c); return { $metadata: { httpStatusCode: 202 } }; - } + }, }; - const mockIfMatch = () => mockS3Client + const mockIfMatch = () => mockS3Client; const { putObjectWithVersion } = await esmock('../../../src/storage/version/put.js', { '../../../src/storage/object/get.js': { - default: mockGetObject + default: mockGetObject, }, '../../../src/storage/utils/version.js': { ifNoneMatch: mockIfNoneMatch, @@ -330,8 +335,12 @@ describe('Version Put', () => { }); const env = {}; - const daCtx= { bucket: 'bbb', org: 'myorg', ext: 'html', users: [{"email": "foo@acme.org"}, {"email": "bar@acme.org"}] }; - const update = { bucket: 'bbb', body: 'new-body', org: 'myorg', key: 'a/x.html' }; + const daCtx = { + bucket: 'bbb', org: 'myorg', ext: 'html', users: [{ email: 'foo@acme.org' }, { email: 'bar@acme.org' }], + }; + const update = { + bucket: 'bbb', body: 'new-body', org: 'myorg', key: 'a/x.html', + }; const resp = await putObjectWithVersion(env, daCtx, update, false); assert.equal(202, resp.status); assert.equal('q123-456', resp.metadata.id); @@ -349,20 +358,21 @@ describe('Version Put', () => { assert.equal('myorg/a/x.html', s3Sent[0].input.Key); assert.equal('q123-456', s3Sent[0].input.Metadata.ID); assert.equal('a/x.html', s3Sent[0].input.Metadata.Path); - assert.equal('[{\"email\":\"foo@acme.org\"},{\"email\":\"bar@acme.org\"}]', s3Sent[0].input.Metadata.Users); + assert.equal('[{"email":"foo@acme.org"},{"email":"bar@acme.org"}]', s3Sent[0].input.Metadata.Users); assert.notEqual('aaa-bbb', s3Sent[0].input.Metadata.Version); assert(s3Sent[0].input.Metadata.Timestamp > 0); assert((s3Sent[0].input.Metadata.Preparsingstore - s3Sent[0].input.Metadata.Timestamp) < 100); }); it('Put First Object With Version', async () => { + // eslint-disable-next-line consistent-return const mockGetObject = async (e, u, h) => { if (!h) { return { - status: 404 + status: 404, }; } - } + }; const s3Sent = []; const mockS3Client = { @@ -370,24 +380,24 @@ describe('Version Put', () => { s3Sent.push(c); return { $metadata: { - httpStatusCode: 200 - } + httpStatusCode: 200, + }, }; - } + }, }; const mockIfNoneMatch = () => mockS3Client; const { putObjectWithVersion } = await esmock('../../../src/storage/version/put.js', { '../../../src/storage/object/get.js': { - default: mockGetObject + default: mockGetObject, }, '../../../src/storage/utils/version.js': { - ifNoneMatch: mockIfNoneMatch + ifNoneMatch: mockIfNoneMatch, }, }); const env = {}; - const daCtx= { bucket: 'b-b', org: 'myorg' }; + const daCtx = { bucket: 'b-b', org: 'myorg' }; const update = { bucket: 'b-b', org: 'myorg', key: 'a/b/c' }; const resp = await putObjectWithVersion(env, daCtx, update, true); assert.equal(201, resp.status); @@ -402,13 +412,11 @@ describe('Version Put', () => { }); it('Put Object With Version ID clash', async () => { - const mockGetObject = async (e, u, h) => { - return { metadata: { id: 'x123' }, status: 200 }; - } + const mockGetObject = async (e, u, h) => ({ metadata: { id: 'x123' }, status: 200 }); const { putObjectWithVersion } = await esmock('../../../src/storage/version/put.js', { '../../../src/storage/object/get.js': { - default: mockGetObject + default: mockGetObject, }, }); @@ -417,9 +425,7 @@ describe('Version Put', () => { }); it('Put First Object With ID provided', async () => { - const mockGetObject = async (e, u, h) => { - return { status: 404 }; - } + const mockGetObject = async (e, u, h) => ({ status: 404 }); const s3Sent = []; const mockS3Client = { @@ -427,19 +433,19 @@ describe('Version Put', () => { s3Sent.push(c); return { $metadata: { - httpStatusCode: 200 - } + httpStatusCode: 200, + }, }; - } + }, }; const mockIfNoneMatch = () => mockS3Client; const { putObjectWithVersion } = await esmock('../../../src/storage/version/put.js', { '../../../src/storage/object/get.js': { - default: mockGetObject + default: mockGetObject, }, '../../../src/storage/utils/version.js': { - ifNoneMatch: mockIfNoneMatch + ifNoneMatch: mockIfNoneMatch, }, }); @@ -452,16 +458,17 @@ describe('Version Put', () => { it('Post Object With Version creates new version', async () => { const req = { json: () => ({ - label: 'foobar' - }) + label: 'foobar', + }), }; const env = {}; const ctx = { bucket: 'mybucket', org: 'org123', - key: 'q/r/t' + key: 'q/r/t', }; + // eslint-disable-next-line consistent-return const mockGetObject = async (e, u, h) => { if (e === env && !h) { const body = ReadableStream.from('doccontent'); @@ -471,8 +478,7 @@ describe('Version Put', () => { contentLength: 10, }; } - } - + }; const s3Sent = []; const mockS3Client = { @@ -480,10 +486,10 @@ describe('Version Put', () => { s3Sent.push(c); return { $metadata: { - httpStatusCode: 200 - } + httpStatusCode: 200, + }, }; - } + }, }; const mockIfMatch = () => mockS3Client; @@ -493,20 +499,20 @@ describe('Version Put', () => { s3INMSent.push(c); return { $metadata: { - httpStatusCode: 200 - } + httpStatusCode: 200, + }, }; - } + }, }; const mockIfNoneMatch = () => mockS3INMClient; const { postObjectVersion } = await esmock('../../../src/storage/version/put.js', { '../../../src/storage/object/get.js': { - default: mockGetObject + default: mockGetObject, }, '../../../src/storage/utils/version.js': { ifMatch: mockIfMatch, - ifNoneMatch: mockIfNoneMatch + ifNoneMatch: mockIfNoneMatch, }, }); @@ -532,7 +538,7 @@ describe('Version Put', () => { assert.equal('text/html', s3Sent[0].input.ContentType); assert.equal(10, s3Sent[0].input.ContentLength); - assert(s3INMSent[0].input.Body !== s3Sent[0].input.Body ) + assert(s3INMSent[0].input.Body !== s3Sent[0].input.Body); }); it('Test putObjectWithVersion HEAD', async () => { @@ -544,7 +550,7 @@ describe('Version Put', () => { timestamp: 123, users: '[{"email":"anonymous"}]', preparsingstore: 12345, - } + }; return { body: '', metadata, contentLength: 616 }; }; @@ -554,25 +560,25 @@ describe('Version Put', () => { sentToS3.push(c); return { $metadata: { - httpStatusCode: 201 - } + httpStatusCode: 201, + }, }; - } + }, }; const mockS3Client = () => s3Client; const { putObjectWithVersion } = await esmock('../../../src/storage/version/put.js', { '../../../src/storage/object/get.js': { - default: mockGetObject + default: mockGetObject, }, '../../../src/storage/utils/version.js': { - ifNoneMatch: mockS3Client + ifNoneMatch: mockS3Client, }, }); const resp = await putObjectWithVersion({}, { method: 'HEAD' }, {}); assert.equal(1, sentToS3.length); - const input = sentToS3[0].input; + const { input } = sentToS3[0]; assert.equal('', input.Body, 'Empty body for HEAD'); assert.equal(0, input.ContentLength, 'Should have used 0 as content length for HEAD'); assert.equal('/q', input.Metadata.Path); @@ -587,7 +593,7 @@ describe('Version Put', () => { version: '101', path: '/qwerty', timestamp: 1234, - } + }; return { body: 'Somebody...', metadata, contentLength: 616 }; }; @@ -597,10 +603,10 @@ describe('Version Put', () => { sentToS3.push(c); return { $metadata: { - httpStatusCode: 200 - } + httpStatusCode: 200, + }, }; - } + }, }; const mockS3Client = () => s3Client; @@ -610,20 +616,20 @@ describe('Version Put', () => { sentToS3_2.push(c); return { $metadata: { - httpStatusCode: 200 - } + httpStatusCode: 200, + }, }; - } + }, }; const mockS3Client2 = () => s3Client2; const { putObjectWithVersion } = await esmock('../../../src/storage/version/put.js', { '../../../src/storage/object/get.js': { - default: mockGetObject + default: mockGetObject, }, '../../../src/storage/utils/version.js': { ifNoneMatch: mockS3Client, - ifMatch: mockS3Client2 + ifMatch: mockS3Client2, }, }); @@ -632,14 +638,14 @@ describe('Version Put', () => { body: 'foobar', key: 'mypath', type: 'test/plain', - } + }; const ctx = { org: 'o1', - users: [{ email: 'hi@acme.com' }] - } - const resp = await putObjectWithVersion({}, ctx, update, true); + users: [{ email: 'hi@acme.com' }], + }; + await putObjectWithVersion({}, ctx, update, true); assert.equal(1, sentToS3.length); - const input = sentToS3[0].input; + const { input } = sentToS3[0]; assert.equal('Somebody...', input.Body); assert.equal(616, input.ContentLength); assert.equal('/qwerty', input.Metadata.Path); @@ -664,7 +670,7 @@ describe('Version Put', () => { version: '101', path: '/qwerty', timestamp: 1234, - } + }; return { body: 'Somebody...', metadata, contentLength: 616 }; }; @@ -674,10 +680,10 @@ describe('Version Put', () => { sentToS3.push(c); return { $metadata: { - httpStatusCode: 200 - } + httpStatusCode: 200, + }, }; - } + }, }; const mockS3Client = () => s3Client; @@ -687,20 +693,20 @@ describe('Version Put', () => { sentToS3_2.push(c); return { $metadata: { - httpStatusCode: 200 - } + httpStatusCode: 200, + }, }; - } + }, }; const mockS3Client2 = () => s3Client2; const { putObjectWithVersion } = await esmock('../../../src/storage/version/put.js', { '../../../src/storage/object/get.js': { - default: mockGetObject + default: mockGetObject, }, '../../../src/storage/utils/version.js': { ifNoneMatch: mockS3Client, - ifMatch: mockS3Client2 + ifMatch: mockS3Client2, }, }); @@ -709,18 +715,18 @@ describe('Version Put', () => { body: '', key: 'mypath', type: 'test/plain', - } + }; const ctx = { org: 'o1', users: [{ email: 'hi@acme.com' }], method: 'PUT', ext: 'html', - } + }; - const resp = await putObjectWithVersion({}, ctx, update, true); + await putObjectWithVersion({}, ctx, update, true); assert.equal(1, sentToS3.length); - const input = sentToS3[0].input; + const { input } = sentToS3[0]; assert.equal('Somebody...', input.Body); assert.equal(616, input.ContentLength); @@ -746,19 +752,19 @@ describe('Version Put', () => { const e = new Error('Test error1'); e.$metadata = { httpStatusCode: 418 }; throw e; - } + }, }; const s3client2 = { send: async (c) => { throw new Error('Test error2'); - } + }, }; const s3client3 = { send: async (c) => { const e = new Error('Test error3'); e.$metadata = {}; throw e; - } + }, }; let s3Client = null; const mockS3Client = () => s3Client; @@ -770,13 +776,13 @@ describe('Version Put', () => { }); s3Client = s3client1; - const resp = await putVersion({}, { Body: 'hello'}); + const resp = await putVersion({}, { Body: 'hello' }); assert.equal(418, resp.status); s3Client = s3client2; - const resp2 = await putVersion({}, { Body: 'hello'}); + const resp2 = await putVersion({}, { Body: 'hello' }); assert.equal(500, resp2.status); s3Client = s3client3; - const resp3 = await putVersion({}, { Body: 'hello'}); + const resp3 = await putVersion({}, { Body: 'hello' }); assert.equal(500, resp3.status); }); @@ -786,9 +792,9 @@ describe('Version Put', () => { async send(cmd) { sentCommands.push(cmd); return { - $metadata: { httpStatusCode: 200 } + $metadata: { httpStatusCode: 200 }, }; - } + }, }; const { putVersion } = await esmock('../../../src/storage/version/put.js', { @@ -806,7 +812,7 @@ describe('Version Put', () => { Ext: 'html', Metadata: { test: 'metadata' }, ContentLength: 12, - ContentType: 'text/html' + ContentType: 'text/html', }; await putVersion({}, testParams); @@ -827,9 +833,9 @@ describe('Version Put', () => { async send(cmd) { sentCommands.push(cmd); return { - $metadata: { httpStatusCode: 200 } + $metadata: { httpStatusCode: 200 }, }; - } + }, }; const mockGetObject = async () => ({ @@ -837,17 +843,17 @@ describe('Version Put', () => { body: 'test body', contentLength: 9, contentType: 'text/plain', - metadata: { existing: 'metadata' } + metadata: { existing: 'metadata' }, }); const { putObjectWithVersion } = await esmock('../../../src/storage/version/put.js', { '../../../src/storage/object/get.js': { - default: mockGetObject + default: mockGetObject, }, '../../../src/storage/utils/version.js': { ifNoneMatch: () => mockS3Client, generateId: () => 'generated-id', - generateVersion: () => 'generated-version' + generateVersion: () => 'generated-version', }, }); @@ -855,7 +861,7 @@ describe('Version Put', () => { const daCtx = { org: 'test-org', ext: 'txt', - users: [{ email: 'test@example.com' }] + users: [{ email: 'test@example.com' }], }; await putObjectWithVersion(env, daCtx, { key: 'test-file.txt' }, 'test body', 'test-guid'); diff --git a/test/utils/auth.test.js b/test/utils/auth.test.js index 401b4f6e..59ce2c03 100644 --- a/test/utils/auth.test.js +++ b/test/utils/auth.test.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 @@ -9,7 +9,8 @@ * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ -import assert from 'assert'; +/* eslint-disable no-shadow */ +import assert from 'node:assert'; import esmock from 'esmock'; // Mocks @@ -23,7 +24,8 @@ import { getUserActions, hasPermission, logout, - pathSorter } from '../../src/utils/auth.js'; + pathSorter, +} from '../../src/utils/auth.js'; // ES Mocks const { @@ -68,7 +70,7 @@ describe('DA auth', () => { it('authorized with user if email matches and anonymous if present', async () => { await withMockedFetch(async () => { const users = await getUsers(reqs.siteMulti, env); - assert.strictEqual(users[0].email, 'anonymous') + assert.strictEqual(users[0].email, 'anonymous'); assert.strictEqual(users[1].email, 'aparker@geometrixx.info'); }); }); @@ -82,7 +84,7 @@ describe('DA auth', () => { describe('set user', async () => { it('sets user', async () => { const headers = new Headers({ - 'Authorization': `Bearer aparker@geometrixx.info`, + Authorization: 'Bearer aparker@geometrixx.info', }); let userValue; @@ -96,103 +98,105 @@ describe('DA auth', () => { assert.strictEqual('123', userValue.ident); const expectedOrgs = [ - { orgName: 'Org1', + { + orgName: 'Org1', orgIdent: '2345B0EA551D747', groups: [ { groupName: 'READ_WRITE_STANDARD@DEV' }, { groupName: 'READ_ONLY_STANDARD@PROD' }, - ]}, + ], + }, { orgName: 'Org No groups', orgIdent: '139024093', groups: [] }, - { orgName: 'ACME Inc.', + { + orgName: 'ACME Inc.', orgIdent: 'EE23423423423', groups: [ { groupName: 'Emp' }, { groupName: 'org-test' }, - ]}, + ], + }, ]; assert.deepStrictEqual(expectedOrgs, userValue.orgs); }); }); - describe('path authorization', async () => { + describe('path authorization', async () => { const DA_CONFIG = { - 'test': { - "total": 1, - "limit": 1, - "offset": 0, - "permissions": { - "data": [ + test: { + total: 1, + limit: 1, + offset: 0, + permissions: { + data: [ { - "path": "/x", - "groups": "2345B0EA551D747/4711,123,joe@bloggs.org", - "actions": "write", + path: '/x', + groups: '2345B0EA551D747/4711,123,joe@bloggs.org', + actions: 'write', }, { - "path": "/**", - "groups": "2345B0EA551D747/4711,123,joe@bloggs.org", - "actions": "read", + path: '/**', + groups: '2345B0EA551D747/4711,123,joe@bloggs.org', + actions: 'read', }, { - "path": "/**", - "groups": "2345B0EA551D747/8080", - "actions": "write", + path: '/**', + groups: '2345B0EA551D747/8080', + actions: 'write', }, { - "path": "/foo", - "groups": "2345B0EA551D747/4711", - "actions": "write", + path: '/foo', + groups: '2345B0EA551D747/4711', + actions: 'write', }, { - "path": "/bar/ + **", - "groups": "2345B0EA551D747/4711", - "actions": "write", + path: '/bar/ + **', + groups: '2345B0EA551D747/4711', + actions: 'write', }, { - "path": "/bar/", - "groups": "2345B0EA551D747/4711", - "actions": "read", + path: '/bar/', + groups: '2345B0EA551D747/4711', + actions: 'read', }, { - "path": "/bar/q", - "groups": "2345B0EA551D747/4711", - "actions": "read", + path: '/bar/q', + groups: '2345B0EA551D747/4711', + actions: 'read', }, { - "path": "/", - "groups": "2345B0EA551D747/4711", - "actions": "write", + path: '/', + groups: '2345B0EA551D747/4711', + actions: 'write', }, { - "path": "/furb/", - "groups": "2345B0EA551D747/4711", - "actions": "write", + path: '/furb/', + groups: '2345B0EA551D747/4711', + actions: 'write', }, { - "path": "ACLTRACE", - "groups": "joe@bloggs.org", - "actions": "read", + path: 'ACLTRACE', + groups: 'joe@bloggs.org', + actions: 'read', }, { - "path": "CONFIG", - "groups": "123", - "actions": "write", - } - ] + path: 'CONFIG', + groups: '123', + actions: 'write', + }, + ], }, - ":type": "multi-sheet" - } + ':type': 'multi-sheet', + }, }; const env2 = { DA_CONFIG: { - get: (name) => { - return DA_CONFIG[name]; - }, - } + get: (name) => DA_CONFIG[name], + }, }; it('test path sorting', async () => { - const users = [{groups: [{orgIdent: '2345B0EA551D747', groupName: 4711}]}]; + const users = [{ groups: [{ orgIdent: '2345B0EA551D747', groupName: 4711 }] }]; const aclCtx = await getAclCtx(env2, 'test', users, '/mykey'); const paths = aclCtx.pathLookup.get('2345B0EA551D747/4711').map((x) => x.path); @@ -205,113 +209,162 @@ describe('DA auth', () => { }); it('test anonymous permissions', async () => { - const users = [{email: 'anonymous'}]; + const users = [{ email: 'anonymous' }]; const aclCtx = await getAclCtx(env2, 'test', users, '/test'); - assert(!hasPermission({users, org: 'test', aclCtx, key: ''}, '/test', 'read')); - assert(!hasPermission({users, org: 'test', aclCtx, key: ''}, '/test', 'write')); - assert(!hasPermission({users, org: 'test', aclCtx, key: '/test'}, '/test', 'read')); - assert(!hasPermission({users, org: 'test', aclCtx, key: '/test'}, '/test', 'write')); + assert(!hasPermission({ + users, org: 'test', aclCtx, key: '', + }, '/test', 'read')); + assert(!hasPermission({ + users, org: 'test', aclCtx, key: '', + }, '/test', 'write')); + assert(!hasPermission({ + users, org: 'test', aclCtx, key: '/test', + }, '/test', 'read')); + assert(!hasPermission({ + users, org: 'test', aclCtx, key: '/test', + }, '/test', 'write')); }); it('test hasPermissions', async () => { const key = ''; - const users = [{orgs: [{orgIdent: '2345B0EA551D747', groups: [{groupName: '4711'}]}]}]; + const users = [{ orgs: [{ orgIdent: '2345B0EA551D747', groups: [{ groupName: '4711' }] }] }]; const aclCtx = await getAclCtx(env2, 'test', users, key); - assert(hasPermission({users, org: 'test', aclCtx, key}, '/test', 'read')); - assert(!hasPermission({users, org: 'test', aclCtx, key}, '/test', 'write')); - assert(hasPermission({ users, org: 'test', aclCtx, key}, '/foo', 'write')); - assert(hasPermission({ users, org: 'test', aclCtx, key}, '/bar', 'write')); - assert(hasPermission({ users, org: 'test', aclCtx, key}, '/bar/something.jpg', 'write')); - assert(hasPermission({ users, org: 'test', aclCtx, key}, '/', 'write')); - assert(hasPermission({ users, org: 'test', aclCtx, key}, '/flob', 'read')); - assert(hasPermission({ users, org: 'test', aclCtx, key}, '/furb', 'write')); + assert(hasPermission({ + users, org: 'test', aclCtx, key, + }, '/test', 'read')); + assert(!hasPermission({ + users, org: 'test', aclCtx, key, + }, '/test', 'write')); + assert(hasPermission({ + users, org: 'test', aclCtx, key, + }, '/foo', 'write')); + assert(hasPermission({ + users, org: 'test', aclCtx, key, + }, '/bar', 'write')); + assert(hasPermission({ + users, org: 'test', aclCtx, key, + }, '/bar/something.jpg', 'write')); + assert(hasPermission({ + users, org: 'test', aclCtx, key, + }, '/', 'write')); + assert(hasPermission({ + users, org: 'test', aclCtx, key, + }, '/flob', 'read')); + assert(hasPermission({ + users, org: 'test', aclCtx, key, + }, '/furb', 'write')); }); it('test hasPermissions2', async () => { - const users = [{orgs: [{orgIdent: '2345B0EA551D747', groups: [{groupName: '8080'}]}]}]; + const users = [{ orgs: [{ orgIdent: '2345B0EA551D747', groups: [{ groupName: '8080' }] }] }]; const aclCtx = await getAclCtx(env2, 'test', users, '/test'); - assert(hasPermission({users, org: 'test', key: '/test', aclCtx}, 'test', 'write')); - assert(hasPermission({users, org: 'test', key: '/test', aclCtx}, 'test', 'read')); + assert(hasPermission({ + users, org: 'test', key: '/test', aclCtx, + }, 'test', 'write')); + assert(hasPermission({ + users, org: 'test', key: '/test', aclCtx, + }, 'test', 'read')); }); it('test hasPermissions3', async () => { const key = '/test'; - const users = [{orgs: [{orgIdent: '2345B0EA551D747', groups: [{groupName: '4711'},{groupName: '8080'}]}]}]; + const users = [{ orgs: [{ orgIdent: '2345B0EA551D747', groups: [{ groupName: '4711' }, { groupName: '8080' }] }] }]; const aclCtx = await getAclCtx(env2, 'test', users, key); - assert(hasPermission({users, org: 'test', aclCtx, key}, '/test', 'read')); - assert(hasPermission({users, org: 'test', aclCtx, key}, '/test', 'write')); + assert(hasPermission({ + users, org: 'test', aclCtx, key, + }, '/test', 'read')); + assert(hasPermission({ + users, org: 'test', aclCtx, key, + }, '/test', 'write')); }); it('test hasPermissions4', async () => { const key = ''; - const users = [{orgs: []}]; + const users = [{ orgs: [] }]; const aclCtx = await getAclCtx(env2, 'test', users, key); - assert(!hasPermission({users, org: 'test', aclCtx, key}, '/test', 'read')); + assert(!hasPermission({ + users, org: 'test', aclCtx, key, + }, '/test', 'read')); }); it('test hasPermissions5', async () => { const key = ''; - const users = [{orgs: [{ orgIdent: '123' }]}]; + const users = [{ orgs: [{ orgIdent: '123' }] }]; const aclCtx = await getAclCtx(env2, 'test', users, key); - assert(hasPermission({users, org: 'test', aclCtx, key}, '/test', 'read')); - assert(!hasPermission({users, org: 'test', aclCtx, key}, '/test', 'write')); + assert(hasPermission({ + users, org: 'test', aclCtx, key, + }, '/test', 'read')); + assert(!hasPermission({ + users, org: 'test', aclCtx, key, + }, '/test', 'write')); }); it('test hasPermissions6', async () => { - const users = [{email: 'joe@bloggs.org', orgs: []}]; + const users = [{ email: 'joe@bloggs.org', orgs: [] }]; const aclCtx = await getAclCtx(env2, 'test', users, '/test'); - assert(hasPermission({users, org: 'test', aclCtx, key: ''}, '/test', 'read')); - assert(!hasPermission({users, org: 'test', aclCtx, key: ''}, '/test', 'write')); - assert(hasPermission({users, org: 'test', aclCtx, key: '/test'}, '/test', 'read')); - assert(!hasPermission({users, org: 'test', aclCtx, key: '/test'}, '/test', 'write')); + assert(hasPermission({ + users, org: 'test', aclCtx, key: '', + }, '/test', 'read')); + assert(!hasPermission({ + users, org: 'test', aclCtx, key: '', + }, '/test', 'write')); + assert(hasPermission({ + users, org: 'test', aclCtx, key: '/test', + }, '/test', 'read')); + assert(!hasPermission({ + users, org: 'test', aclCtx, key: '/test', + }, '/test', 'write')); }); it('test trace information', async () => { - const users = [{email: 'joe@bloggs.org', orgs: [{orgIdent: '2345B0EA551D747', groups: [{groupName: '4711'}]}]}]; + const users = [{ email: 'joe@bloggs.org', orgs: [{ orgIdent: '2345B0EA551D747', groups: [{ groupName: '4711' }] }] }]; const aclCtx = await getAclCtx(env2, 'test', users, '/bar/blah.html'); const trace = aclCtx.actionTrace; assert.strictEqual(2, trace.length); - const emailTraceIdx = trace[0].group === 'joe@bloggs.org' ? 0 : 1 + const emailTraceIdx = trace[0].group === 'joe@bloggs.org' ? 0 : 1; const groupTraceIdx = 1 - emailTraceIdx; - assert.deepStrictEqual({group: 'joe@bloggs.org', path: '/**', actions: ['read']}, trace[emailTraceIdx]); - assert.deepStrictEqual( - { - group: '2345B0EA551D747/4711', - path: '/bar/+**', - actions: [ 'read', 'write' ] - }, trace[groupTraceIdx]); + assert.deepStrictEqual({ group: 'joe@bloggs.org', path: '/**', actions: ['read'] }, trace[emailTraceIdx]); + assert.deepStrictEqual({ + group: '2345B0EA551D747/4711', + path: '/bar/+**', + actions: ['read', 'write'], + }, trace[groupTraceIdx]); }); it('test CONFIG api', async () => { - const users = [{ orgs: [{ orgIdent: "123" }]}]; + const users = [{ orgs: [{ orgIdent: '123' }] }]; const aclCtx = await getAclCtx(env2, 'test', users, '/', 'config'); - assert(hasPermission({users, org: 'test', aclCtx, key: ''}, 'CONFIG', 'write', true)); - assert(hasPermission({users, org: 'test', aclCtx, key: '/somewhere'}, 'CONFIG', 'write', true)); + assert(hasPermission({ + users, org: 'test', aclCtx, key: '', + }, 'CONFIG', 'write', true)); + assert(hasPermission({ + users, org: 'test', aclCtx, key: '/somewhere', + }, 'CONFIG', 'write', true)); }); it('test CONFIG always has read permission', async () => { - const users = [{email: "blah@foo.org"}]; + const users = [{ email: 'blah@foo.org' }]; const aclCtx = await getAclCtx(env2, 'test', users, '/', 'config'); assert(aclCtx.actionSet.has('read')); }); it('test versionsource api always has read permission', async () => { - const users = [{email: "blah@foo.org"}]; + const users = [{ email: 'blah@foo.org' }]; const aclCtx = await getAclCtx(env2, 'test', users, '/', 'versionsource'); assert(aclCtx.actionSet.has('read')); }); it('test versionsource api grants read permission even without explicit permissions', async () => { - const users = [{email: "unauthorized@example.com"}]; + const users = [{ email: 'unauthorized@example.com' }]; const aclCtx = await getAclCtx(env2, 'test', users, '/restricted', 'versionsource'); assert(aclCtx.actionSet.has('read')); assert(!aclCtx.actionSet.has('write')); @@ -320,75 +373,97 @@ describe('DA auth', () => { describe('persmissions single sheet', () => { const DA_CONFIG = { - 'test': { - "data": [ + test: { + data: [ { - "path": "/**", - "groups": "2345B0EA551D747/4711,123,joe@bloggs.org", - "actions": "read", + path: '/**', + groups: '2345B0EA551D747/4711,123,joe@bloggs.org', + actions: 'read', }, { - "path": "/**", - "groups": "2345B0EA551D747/8080", - "actions": "write", + path: '/**', + groups: '2345B0EA551D747/8080', + actions: 'write', }, { - "path": "/foo", - "groups": "2345B0EA551D747/4711", - "actions": "write", + path: '/foo', + groups: '2345B0EA551D747/4711', + actions: 'write', }, { - "path": "/bar/ + **", - "groups": "2345B0EA551D747/4711", - "actions": "write", + path: '/bar/ + **', + groups: '2345B0EA551D747/4711', + actions: 'write', }, { - "path": "/", - "groups": "2345B0EA551D747/4711", - "actions": "write", + path: '/', + groups: '2345B0EA551D747/4711', + actions: 'write', }, { - "path": "/furb/", - "groups": "2345B0EA551D747/4711", - "actions": "write", + path: '/furb/', + groups: '2345B0EA551D747/4711', + actions: 'write', }, ], - ":type": "sheet", - ":sheetname": "permissions", - } + ':type': 'sheet', + ':sheetname': 'permissions', + }, }; const env = { DA_CONFIG: { - get: (name) => { - return DA_CONFIG[name]; - }, - } + get: (name) => DA_CONFIG[name], + }, }; it('test anonymous permissions', async () => { - const users = [{email: 'anonymous'}]; + const users = [{ email: 'anonymous' }]; const aclCtx = await getAclCtx(env, 'test', users, '/test'); - assert(!hasPermission({users, org: 'test', aclCtx, key: ''}, '/test', 'read')); - assert(!hasPermission({users, org: 'test', aclCtx, key: ''}, '/test', 'write')); - assert(!hasPermission({users, org: 'test', aclCtx, key: '/test'}, '/test', 'read')); - assert(!hasPermission({users, org: 'test', aclCtx, key: '/test'}, '/test', 'write')); + assert(!hasPermission({ + users, org: 'test', aclCtx, key: '', + }, '/test', 'read')); + assert(!hasPermission({ + users, org: 'test', aclCtx, key: '', + }, '/test', 'write')); + assert(!hasPermission({ + users, org: 'test', aclCtx, key: '/test', + }, '/test', 'read')); + assert(!hasPermission({ + users, org: 'test', aclCtx, key: '/test', + }, '/test', 'write')); }); it('test hasPermissions', async () => { const key = ''; - const users = [{orgs: [{orgIdent: '2345B0EA551D747', groups: [{groupName: '4711'}]}]}]; + const users = [{ orgs: [{ orgIdent: '2345B0EA551D747', groups: [{ groupName: '4711' }] }] }]; const aclCtx = await getAclCtx(env, 'test', users, key); - assert(hasPermission({users, org: 'test', aclCtx, key}, '/test', 'read')); - assert(!hasPermission({users, org: 'test', aclCtx, key}, '/test', 'write')); - assert(hasPermission({ users, org: 'test', aclCtx, key}, '/foo', 'write')); - assert(hasPermission({ users, org: 'test', aclCtx, key}, '/bar', 'write')); - assert(hasPermission({ users, org: 'test', aclCtx, key}, '/bar/something.jpg', 'write')); - assert(hasPermission({ users, org: 'test', aclCtx, key}, '/', 'write')); - assert(hasPermission({ users, org: 'test', aclCtx, key}, '/flob', 'read')); - assert(hasPermission({ users, org: 'test', aclCtx, key}, '/furb', 'write')); + assert(hasPermission({ + users, org: 'test', aclCtx, key, + }, '/test', 'read')); + assert(!hasPermission({ + users, org: 'test', aclCtx, key, + }, '/test', 'write')); + assert(hasPermission({ + users, org: 'test', aclCtx, key, + }, '/foo', 'write')); + assert(hasPermission({ + users, org: 'test', aclCtx, key, + }, '/bar', 'write')); + assert(hasPermission({ + users, org: 'test', aclCtx, key, + }, '/bar/something.jpg', 'write')); + assert(hasPermission({ + users, org: 'test', aclCtx, key, + }, '/', 'write')); + assert(hasPermission({ + users, org: 'test', aclCtx, key, + }, '/flob', 'read')); + assert(hasPermission({ + users, org: 'test', aclCtx, key, + }, '/furb', 'write')); }); }); @@ -400,6 +475,7 @@ describe('DA auth', () => { }); it('test getAclCtx missing props2', async () => { + // eslint-disable-next-line consistent-return const cfgGet = (o, t) => { if ((o === 'myorg') && (t.type === 'json')) { return {}; @@ -415,9 +491,10 @@ describe('DA auth', () => { }); it('test getAclCtx missing props3', async () => { + // eslint-disable-next-line consistent-return const cfgGet = (o, t) => { if ((o === 'someorg') && (t.type === 'json')) { - return { permissions: {}}; + return { permissions: {} }; } }; const DA_CONFIG = { get: cfgGet }; @@ -432,6 +509,7 @@ describe('DA auth', () => { it('test incorrect props doesnt break things', async () => { const data = [{ groups: 'abc', actions: 'read' }]; const permissions = { data }; + // eslint-disable-next-line consistent-return const cfgGet = (o, t) => { if ((o === 'someorg') && (t.type === 'json')) { return { permissions }; @@ -448,6 +526,7 @@ describe('DA auth', () => { it('test incorrect props doesnt break things', async () => { const data = [{ path: '/abc', actions: 'read' }]; const permissions = { data }; + // eslint-disable-next-line consistent-return const cfgGet = (o, t) => { if ((o === 'someorg') && (t.type === 'json')) { return { permissions }; @@ -464,6 +543,7 @@ describe('DA auth', () => { it('test correct props', async () => { const data = [{ path: '/abc', groups: 'a ha, b hoo', actions: 'read' }]; const permissions = { data }; + // eslint-disable-next-line consistent-return const cfgGet = (o, t) => { if ((o === 'someorg') && (t.type === 'json')) { return { permissions }; @@ -491,12 +571,12 @@ describe('DA auth', () => { describe('ACL context', () => { it('get user actions', () => { const patharr = [ - {path: '/da-aem-boilerplate/authtest/sub/sub/**', actions: []}, - {path: '/da-aem-boilerplate/authtest/sub/**', actions: ['read', 'write']}, - {path: '/da-aem-boilerplate/authtest/**', actions: ['read']}, - {path: '/**', actions: ['read', 'write']}, - {path: '/', actions: ['read', 'write']}, - {path: 'CONFIG', actions: ['read']}, + { path: '/da-aem-boilerplate/authtest/sub/sub/**', actions: [] }, + { path: '/da-aem-boilerplate/authtest/sub/**', actions: ['read', 'write'] }, + { path: '/da-aem-boilerplate/authtest/**', actions: ['read'] }, + { path: '/**', actions: ['read', 'write'] }, + { path: '/', actions: ['read', 'write'] }, + { path: 'CONFIG', actions: ['read'] }, ]; const pathlookup = new Map(); @@ -507,35 +587,45 @@ describe('DA auth', () => { ident: 'AAAA@bbb.e', }; - assert.deepStrictEqual(['read', 'write'], - [...getUserActions(pathlookup, user, '/').actions]); - assert.deepStrictEqual(['read'], - [...getUserActions(pathlookup, user, '/da-aem-boilerplate/authtest/sub').actions]); - assert.deepStrictEqual(['read'], - [...getUserActions(pathlookup, user, '/da-aem-boilerplate/authtest/q.html').actions]); - assert.deepStrictEqual(['read', 'write'], - [...getUserActions(pathlookup, user, '/da-aem-boilerplate/authtest/sub/sub').actions]); - assert.deepStrictEqual(['read'], - [...getUserActions(pathlookup, user, 'CONFIG').actions]); + assert.deepStrictEqual( + ['read', 'write'], + [...getUserActions(pathlookup, user, '/').actions], + ); + assert.deepStrictEqual( + ['read'], + [...getUserActions(pathlookup, user, '/da-aem-boilerplate/authtest/sub').actions], + ); + assert.deepStrictEqual( + ['read'], + [...getUserActions(pathlookup, user, '/da-aem-boilerplate/authtest/q.html').actions], + ); + assert.deepStrictEqual( + ['read', 'write'], + [...getUserActions(pathlookup, user, '/da-aem-boilerplate/authtest/sub/sub').actions], + ); + assert.deepStrictEqual( + ['read'], + [...getUserActions(pathlookup, user, 'CONFIG').actions], + ); }); }); it('get user actions2', () => { const patharr = [ - {path: '/da-aem-boilerplate/**', actions: ['read']}, - {path: '/da-aem-boilerplate', actions: ['read']}, - {path: '/somewhere', actions: ['read']}, - {path: '/foobar/+**', actions: []}, - {path: '/**', actions: ['read', 'write']}, - {path: '/', actions: ['read', 'write']}, + { path: '/da-aem-boilerplate/**', actions: ['read'] }, + { path: '/da-aem-boilerplate', actions: ['read'] }, + { path: '/somewhere', actions: ['read'] }, + { path: '/foobar/+**', actions: [] }, + { path: '/**', actions: ['read', 'write'] }, + { path: '/', actions: ['read', 'write'] }, ]; const pathlookup = new Map(); pathlookup.set('joe@acme.com', patharr); const patharr2 = [ - {path: '/da-aem-boilerplate/authtest/myfile', actions: ['read']}, - {path: '/da-aem-boilerplate/authtest/myother.html', actions: ['read']}, - {path: '/da-aem-boilerplate/authtest/**', actions: ['read', 'write']}, - {path: '/**', actions: []}, + { path: '/da-aem-boilerplate/authtest/myfile', actions: ['read'] }, + { path: '/da-aem-boilerplate/authtest/myother.html', actions: ['read'] }, + { path: '/da-aem-boilerplate/authtest/**', actions: ['read', 'write'] }, + { path: '/**', actions: [] }, ]; pathlookup.set('ABCDEFG/grp1', patharr2); @@ -545,43 +635,63 @@ describe('DA auth', () => { orgs: [{ orgName: 'org1', orgIdent: 'ABCDEFG', - groups: [{ groupName: 'grp1' }] - },{ + groups: [{ groupName: 'grp1' }], + }, { orgName: 'org2', orgIdent: 'ZZZZZZZ', - groups: [{ groupName: 'grp2' }] + groups: [{ groupName: 'grp2' }], }], }; - assert.deepStrictEqual(['read', 'write'], - [...getUserActions(pathlookup, user, '/').actions]); - assert.deepStrictEqual(['read', 'write'], - [...getUserActions(pathlookup, user, '/foo').actions]); - assert.deepStrictEqual(['read'], - [...getUserActions(pathlookup, user, '/da-aem-boilerplate').actions]); - assert.deepStrictEqual(['read'], - [...getUserActions(pathlookup, user, '/somewhere').actions]); - assert.deepStrictEqual(['read', 'write'], - [...getUserActions(pathlookup, user, '/somewhere/else').actions]); - assert.deepStrictEqual([], - [...getUserActions(pathlookup, user, '/foobar').actions]); - assert.deepStrictEqual([], - [...getUserActions(pathlookup, user, '/foobar/har').actions]); - assert.deepStrictEqual(['read'], - [...getUserActions(pathlookup, user, '/da-aem-boilerplate/authtest/myfile.html').actions]); - assert.deepStrictEqual(['read'], - [...getUserActions(pathlookup, user, '/da-aem-boilerplate/authtest/myother.html').actions]); - assert.deepStrictEqual(['read', 'write'], - [...getUserActions(pathlookup, user, '/da-aem-boilerplate/authtest/blah').actions]); + assert.deepStrictEqual( + ['read', 'write'], + [...getUserActions(pathlookup, user, '/').actions], + ); + assert.deepStrictEqual( + ['read', 'write'], + [...getUserActions(pathlookup, user, '/foo').actions], + ); + assert.deepStrictEqual( + ['read'], + [...getUserActions(pathlookup, user, '/da-aem-boilerplate').actions], + ); + assert.deepStrictEqual( + ['read'], + [...getUserActions(pathlookup, user, '/somewhere').actions], + ); + assert.deepStrictEqual( + ['read', 'write'], + [...getUserActions(pathlookup, user, '/somewhere/else').actions], + ); + assert.deepStrictEqual( + [], + [...getUserActions(pathlookup, user, '/foobar').actions], + ); + assert.deepStrictEqual( + [], + [...getUserActions(pathlookup, user, '/foobar/har').actions], + ); + assert.deepStrictEqual( + ['read'], + [...getUserActions(pathlookup, user, '/da-aem-boilerplate/authtest/myfile.html').actions], + ); + assert.deepStrictEqual( + ['read'], + [...getUserActions(pathlookup, user, '/da-aem-boilerplate/authtest/myother.html').actions], + ); + assert.deepStrictEqual( + ['read', 'write'], + [...getUserActions(pathlookup, user, '/da-aem-boilerplate/authtest/blah').actions], + ); }); it('test logout', async () => { const deleteCalled = []; const deleteFunc = async (id) => { deleteCalled.push(id); - } - const DA_AUTH = { delete: deleteFunc}; + }; + const DA_AUTH = { delete: deleteFunc }; const env = { DA_AUTH }; - const daCtx = { users: [{ ident: '1234@a'}, { ident: '5678@b'}] }; + const daCtx = { users: [{ ident: '1234@a' }, { ident: '5678@b' }] }; const resp = await logout({ env, daCtx }); assert.deepStrictEqual(new Set(['1234@a', '5678@b']), new Set(deleteCalled)); @@ -595,28 +705,28 @@ describe('DA auth', () => { orgs: [{ orgName: 'org1', orgIdent: 'ABCDEFG', - groups: [{ groupName: 'grp1' }] - },{ + groups: [{ groupName: 'grp1' }], + }, { orgName: 'org2', orgIdent: 'HIJKLMN', - groups: [{ groupName: 'grp2' }] - }] + groups: [{ groupName: 'grp2' }], + }], }; const pathLookup = new Map(); - pathLookup.set('ABCDEFG', [{ident: 'ABCDEFG', path: '/xyz', actions: ['read']}]); - pathLookup.set('ABCDEFG/grp1', [{ident: 'ABCDEFG/grp1', path: '/xyz', actions: ['read']}]); - pathLookup.set('ABCDEFG/111', [{ident: 'ABCDEFG/111', path: '/xyz', actions: ['read']}]); - pathLookup.set('ABCDEFG/foo@bar.org', [{ident: 'ABCDEFG/foo@bar.org', path: '/xyz', actions: ['read']}]); - pathLookup.set('org1/grp1', [{ident: 'org1/grp1', path: '/xyz', actions: ['read']}]); - pathLookup.set('org1/111', [{ident: 'org1/111', path: '/xyz', actions: ['read']}]); - pathLookup.set('HIJKLMN', [{ident: 'HIJKLMN', path: '/xyz', actions: ['read']}]); - pathLookup.set('HIJKLMN/grp2', [{ident: 'HIJKLMN/grp2', path: '/xyz', actions: ['read']}]); - pathLookup.set('HIJKLMN/222', [{ident: 'HIJKLMN/222', path: '/xyz', actions: ['read']}]); - pathLookup.set('HIJKLMN/foo@bar.org', [{ident: 'HIJKLMN/foo@bar.org', path: '/xyz', actions: ['read']}]); - pathLookup.set('org2/grp2', [{ident: 'org2/grp2', path: '/xyz', actions: ['read']}]); - pathLookup.set('org2/222', [{ident: 'org2/222', path: '/xyz', actions: ['read']}]); - pathLookup.set('foo@bar.org', [{ident: 'foo@bar.org', path: '/xyz', actions: ['read']}]); - pathLookup.set('1234@abcd', [{ident: '1234@abcd', path: '/xyz', actions: ['read']}]); + pathLookup.set('ABCDEFG', [{ ident: 'ABCDEFG', path: '/xyz', actions: ['read'] }]); + pathLookup.set('ABCDEFG/grp1', [{ ident: 'ABCDEFG/grp1', path: '/xyz', actions: ['read'] }]); + pathLookup.set('ABCDEFG/111', [{ ident: 'ABCDEFG/111', path: '/xyz', actions: ['read'] }]); + pathLookup.set('ABCDEFG/foo@bar.org', [{ ident: 'ABCDEFG/foo@bar.org', path: '/xyz', actions: ['read'] }]); + pathLookup.set('org1/grp1', [{ ident: 'org1/grp1', path: '/xyz', actions: ['read'] }]); + pathLookup.set('org1/111', [{ ident: 'org1/111', path: '/xyz', actions: ['read'] }]); + pathLookup.set('HIJKLMN', [{ ident: 'HIJKLMN', path: '/xyz', actions: ['read'] }]); + pathLookup.set('HIJKLMN/grp2', [{ ident: 'HIJKLMN/grp2', path: '/xyz', actions: ['read'] }]); + pathLookup.set('HIJKLMN/222', [{ ident: 'HIJKLMN/222', path: '/xyz', actions: ['read'] }]); + pathLookup.set('HIJKLMN/foo@bar.org', [{ ident: 'HIJKLMN/foo@bar.org', path: '/xyz', actions: ['read'] }]); + pathLookup.set('org2/grp2', [{ ident: 'org2/grp2', path: '/xyz', actions: ['read'] }]); + pathLookup.set('org2/222', [{ ident: 'org2/222', path: '/xyz', actions: ['read'] }]); + pathLookup.set('foo@bar.org', [{ ident: 'foo@bar.org', path: '/xyz', actions: ['read'] }]); + pathLookup.set('1234@abcd', [{ ident: '1234@abcd', path: '/xyz', actions: ['read'] }]); const res = getUserActions(pathLookup, user, '/xyz'); const matchedIds = res.trace.map((r) => r.ident); @@ -630,63 +740,59 @@ describe('DA auth', () => { assert(matchedIds.includes('foo@bar.org')); }); - function hasRule(rules, path, action) { - return rules.some((r) => r.path === path && r.actions.includes(action)); - } - it('test get child rules', async () => { const pathLookup = new Map(); pathLookup.set('a@foo.org', [ - {path: '/**', actions: ['read']}, - {path: '/something', actions: ['write']}, - {path: '/foo/bar', actions: ['write']}, - {path: '/blah/+**', actions: ['write']}, - {path: '/blah/haha', actions: ['read']}, - {path: '/blah/hoho/**', actions: ['read']}, - {path: '/blah/hoho/hihi', actions: ['read']}, - {path: '/hello/+**', actions: ['read','write']}, + { path: '/**', actions: ['read'] }, + { path: '/something', actions: ['write'] }, + { path: '/foo/bar', actions: ['write'] }, + { path: '/blah/+**', actions: ['write'] }, + { path: '/blah/haha', actions: ['read'] }, + { path: '/blah/hoho/**', actions: ['read'] }, + { path: '/blah/hoho/hihi', actions: ['read'] }, + { path: '/hello/+**', actions: ['read', 'write'] }, ]); pathLookup.set('ABCDEF', [ - {path: '/blah/hohoho', actions: ['read']}, - {path: '/blah/+**', actions: ['read']}, - {path: '/hello/+**', actions: ['read']}, + { path: '/blah/hohoho', actions: ['read'] }, + { path: '/blah/+**', actions: ['read'] }, + { path: '/hello/+**', actions: ['read'] }, ]); pathLookup.forEach((value) => value.sort(pathSorter)); const aclCtx = { pathLookup }; - const daCtx = { users: [{ email: 'a@foo.org', orgs: [{orgIdent: 'ABCDEF'}]}], aclCtx, key: '/blah' }; + const daCtx = { users: [{ email: 'a@foo.org', orgs: [{ orgIdent: 'ABCDEF' }] }], aclCtx, key: '/blah' }; getChildRules(daCtx); const rules = daCtx.aclCtx.childRules; assert.strictEqual(1, rules.length); assert(rules[0] === '/blah/**=read,write' || rules[0] === '/blah/**=write,read'); delete daCtx.aclCtx.childRules; - getChildRules({...daCtx, key: '/foo/'}); + getChildRules({ ...daCtx, key: '/foo/' }); const rules2 = daCtx.aclCtx.childRules; assert.strictEqual(1, rules2.length); assert.strictEqual('/foo/**=read', rules2[0]); delete daCtx.aclCtx.childRules; - getChildRules({...daCtx, key: '/something'}); + getChildRules({ ...daCtx, key: '/something' }); const rules3 = daCtx.aclCtx.childRules; assert.strictEqual(1, rules3.length); assert.strictEqual('/something/**=read', rules3[0]); delete daCtx.aclCtx.childRules; - getChildRules({...daCtx, key: '/blah/yee/haa'}); + getChildRules({ ...daCtx, key: '/blah/yee/haa' }); const rules4 = daCtx.aclCtx.childRules; assert.strictEqual(1, rules4.length); assert(rules4[0] === '/blah/yee/haa/**=read,write' || rules4[0] === '/blah/yee/haa/**=write,read'); delete daCtx.aclCtx.childRules; - const daCtx2 = { users: [{email: 'a@foo.org', groups: []}], aclCtx, key: '/blah' }; + const daCtx2 = { users: [{ email: 'a@foo.org', groups: [] }], aclCtx, key: '/blah' }; getChildRules(daCtx2); const rules5 = daCtx2.aclCtx.childRules; assert.strictEqual(1, rules5.length); assert.strictEqual('/blah/**=write', rules5[0]); delete daCtx.aclCtx.childRules; - const users = [{email: 'a@foo.org', orgs: []}, {email: 'blah@foo.org', orgs: [{orgIdent: 'ABCDEF'}]}]; + const users = [{ email: 'a@foo.org', orgs: [] }, { email: 'blah@foo.org', orgs: [{ orgIdent: 'ABCDEF' }] }]; const daCtx3 = { users, aclCtx, key: '/blah' }; getChildRules(daCtx3); const rules6 = daCtx3.aclCtx.childRules; @@ -704,7 +810,7 @@ describe('DA auth', () => { it('test get child rules when there are no acls', async () => { const pathLookup = new Map(); const aclCtx = { pathLookup }; - const daCtx = { users: [{email: 'anonymous'}], aclCtx, key: '/foo' }; + const daCtx = { users: [{ email: 'anonymous' }], aclCtx, key: '/foo' }; getChildRules(daCtx); const rules = daCtx.aclCtx.childRules; assert.strictEqual(1, rules.length); diff --git a/test/utils/daCtx.test.js b/test/utils/daCtx.test.js index b95bd8f5..904e6c8c 100644 --- a/test/utils/daCtx.test.js +++ b/test/utils/daCtx.test.js @@ -1,5 +1,16 @@ +/* + * Copyright 2025 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ /* eslint-env mocha */ -import assert from 'assert'; +import assert from 'node:assert'; import { strict as esmock } from 'esmock'; // Mocks @@ -7,9 +18,7 @@ import reqs from './mocks/req.js'; import env from './mocks/env.js'; import auth from './mocks/auth.js'; -const getDaCtx = await esmock( - '../../src/utils/daCtx.js', { '../../src/utils/auth.js': auth }, -); +const getDaCtx = await esmock('../../src/utils/daCtx.js', { '../../src/utils/auth.js': auth }); describe('DA context', () => { describe('API context', async () => { diff --git a/test/utils/daResp.test.js b/test/utils/daResp.test.js index 7589b736..78781197 100644 --- a/test/utils/daResp.test.js +++ b/test/utils/daResp.test.js @@ -9,8 +9,7 @@ * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ -import assert from 'assert'; -import esmock from 'esmock'; +import assert from 'node:assert'; import daResp from '../../src/utils/daResp.js'; @@ -21,7 +20,9 @@ describe('DA Resp', () => { const body = 'foobar'; const metadata = { id: '1234', LastModified: '2024-06-24T13:20:00.000Z' }; - const resp = daResp({status: 200, body, contentType: 'text/plain', contentLength: 777, metadata}, ctx); + const resp = daResp({ + status: 200, body, contentType: 'text/plain', contentLength: 777, metadata, + }, ctx); assert.strictEqual(body, await resp.text()); assert.strictEqual(200, resp.status); assert.strictEqual('*', resp.headers.get('Access-Control-Allow-Origin')); @@ -43,7 +44,7 @@ describe('DA Resp', () => { const body = null; const metadata = {}; - const resp = daResp({status: 404, body, metadata}, ctx); + const resp = daResp({ status: 404, body, metadata }, ctx); assert.strictEqual(404, resp.status); assert.strictEqual('*', resp.headers.get('Access-Control-Allow-Origin')); assert.strictEqual('HEAD, GET, PUT, POST, DELETE', resp.headers.get('Access-Control-Allow-Methods')); @@ -59,7 +60,7 @@ describe('DA Resp', () => { it('test 500', () => { const aclCtx = { actionSet: ['read', 'write'], pathLookup: new Map() }; const ctx = { key: 'foo/blah.html', aclCtx }; - const resp = daResp({status: 500}, ctx); + const resp = daResp({ status: 500 }, ctx); assert.strictEqual(500, resp.status); assert.strictEqual('*', resp.headers.get('Access-Control-Allow-Origin')); assert.strictEqual('HEAD, GET, PUT, POST, DELETE', resp.headers.get('Access-Control-Allow-Methods')); @@ -71,11 +72,11 @@ describe('DA Resp', () => { }); it('test child actions header', () => { - const aclCtx = { actionSet: ['read'], childRules: ['/haha/hoho/**=read,write'] } - const ctx = { key: 'foo/bar.html', aclCtx } - const resp = daResp({status: 200, body: 'foobar'}, ctx); + const aclCtx = { actionSet: ['read'], childRules: ['/haha/hoho/**=read,write'] }; + const ctx = { key: 'foo/bar.html', aclCtx }; + const resp = daResp({ status: 200, body: 'foobar' }, ctx); assert.strictEqual(200, resp.status); assert.strictEqual('X-da-actions, X-da-child-actions, X-da-acltrace, X-da-id, ETag', resp.headers.get('Access-Control-Expose-Headers')); assert.strictEqual('/haha/hoho/**=read,write', resp.headers.get('X-da-child-actions')); - }) + }); }); diff --git a/test/utils/mocks/auth.js b/test/utils/mocks/auth.js index 60cf6406..7809c7b7 100644 --- a/test/utils/mocks/auth.js +++ b/test/utils/mocks/auth.js @@ -1,4 +1,15 @@ +/* + * Copyright 2025 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ export default { - getUsers: () => { return [{ email: 'anonymous' }]; }, - getAclCtx: () => { return { actionSet: new Set() }; }, + getUsers: () => [{ email: 'anonymous' }], + getAclCtx: () => ({ actionSet: new Set() }), }; diff --git a/test/utils/mocks/env.js b/test/utils/mocks/env.js index eff14ddc..57698965 100644 --- a/test/utils/mocks/env.js +++ b/test/utils/mocks/env.js @@ -1,24 +1,36 @@ +/* + * Copyright 2025 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +/* eslint-disable no-unused-vars */ const NAMESPACES = { - 'geometrixx-da-props': { "admin.role.all":["aparker@geometrixx.info"] }, + 'geometrixx-da-props': { 'admin.role.all': ['aparker@geometrixx.info'] }, 'beagle-da-props': { }, - 'orgs': [ + orgs: [ { name: 'geometrixx' }, { name: 'beagle' }, - ] + ], }; const DA_CONFIG = { - 'geometrixx': { - "total": 1, - "limit": 1, - "offset": 0, - "data": [ + geometrixx: { + total: 1, + limit: 1, + offset: 0, + data: [ { - "key": "admin.role.all", - "value": "aPaRKer@Geometrixx.Info" - } + key: 'admin.role.all', + value: 'aPaRKer@Geometrixx.Info', + }, ], - ":type": "sheet" - } + ':type': 'sheet', + }, }; const env = { @@ -27,17 +39,13 @@ const env = { S3_SECRET_ACCESS_KEY: 'too-many-secrets', IMS_ORIGIN: 'https://ims-na1.adobelogin.com', DA_AUTH: { - get: (kvNamespace) => { - return NAMESPACES[kvNamespace]; - }, + get: (kvNamespace) => NAMESPACES[kvNamespace], put: (kvNamespace, value, expObj) => {}, }, DA_CONFIG: { - get: (name) => { - return DA_CONFIG[name]; - }, + get: (name) => DA_CONFIG[name], put: (name, value, expObj) => {}, - } + }, }; export default env; diff --git a/test/utils/mocks/fetch.js b/test/utils/mocks/fetch.js index 1720a107..ff6a7cc2 100644 --- a/test/utils/mocks/fetch.js +++ b/test/utils/mocks/fetch.js @@ -1,39 +1,51 @@ +/* + * Copyright 2025 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +/* eslint-disable camelcase */ const fetch = async (url, opts) => { const ok = !opts.headers.get('x-mock-fail'); const mockAuth = opts.headers.get('Authorization').split(' ').pop(); + // eslint-disable-next-line no-unused-vars const [email, created_at, expires_in] = mockAuth.split(':'); return { ok, status: 200, - json: async () => { - return url.endsWith('/ims/profile/v1') ? { - email: email, - userId: '123', - } : url.endsWith('/ims/organizations/v5') ? [{ - orgName: 'Org1', - orgRef: { ident: '2345B0EA551D747', authSrc: 'AdobeOrg' }, - orgType: 'Enterprise', - countryCode: 'US', - groups: [{ - groupName: 'READ_WRITE_STANDARD@DEV', role: 'TEAM_MEMBER', ident: 4711, groupType: 'USER', groupDisplayName: 'READ_WRITE_STANDARD@DEV', - }, { - groupName: 'READ_ONLY_STANDARD@PROD', role: 'TEAM_MEMBER', ident: 8080, groupType: 'USER', groupDisplayName: 'READ_ONLY_STANDARD@PROD', - }], + // eslint-disable-next-line no-nested-ternary + json: async () => (url.endsWith('/ims/profile/v1') ? { + email, + userId: '123', + } : url.endsWith('/ims/organizations/v5') ? [{ + orgName: 'Org1', + orgRef: { ident: '2345B0EA551D747', authSrc: 'AdobeOrg' }, + orgType: 'Enterprise', + countryCode: 'US', + groups: [{ + groupName: 'READ_WRITE_STANDARD@DEV', role: 'TEAM_MEMBER', ident: 4711, groupType: 'USER', groupDisplayName: 'READ_WRITE_STANDARD@DEV', }, { - orgName: 'Org No groups', orgRef: { ident: '139024093', authSrc: 'AdobeOrg' }, orgType: 'Enterprise', countryCode: 'US', groups: [], + groupName: 'READ_ONLY_STANDARD@PROD', role: 'TEAM_MEMBER', ident: 8080, groupType: 'USER', groupDisplayName: 'READ_ONLY_STANDARD@PROD', + }], + }, { + orgName: 'Org No groups', orgRef: { ident: '139024093', authSrc: 'AdobeOrg' }, orgType: 'Enterprise', countryCode: 'US', groups: [], + }, { + orgName: 'ACME Inc.', + orgRef: { ident: 'EE23423423423', authSrc: 'AdobeOrg' }, + orgType: 'Enterprise', + countryCode: 'US', + groups: [{ + groupName: 'Emp', role: 'TEAM_MEMBER', ident: 12312312, groupType: 'LICENSE', groupDisplayName: 'Emp', }, { - orgName: 'ACME Inc.', - orgRef: { ident: 'EE23423423423', authSrc: 'AdobeOrg' }, - orgType: 'Enterprise', - countryCode: 'US', - groups: [{ - groupName: 'Emp', role: 'TEAM_MEMBER', ident: 12312312, groupType: 'LICENSE', groupDisplayName: 'Emp', - }, { - groupName: 'org-test', role: 'TEAM_MEMBER', ident: 34243, groupType: 'LICENSE', groupDisplayName: 'org-test', - }], - }] : {}; - }, + groupName: 'org-test', role: 'TEAM_MEMBER', ident: 34243, groupType: 'LICENSE', groupDisplayName: 'org-test', + }], + }] : {}), }; }; diff --git a/test/utils/mocks/jose.js b/test/utils/mocks/jose.js index 5be0ea46..a7c5e8f5 100644 --- a/test/utils/mocks/jose.js +++ b/test/utils/mocks/jose.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 @@ -9,7 +9,9 @@ * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ +/* eslint-disable no-unused-vars,camelcase */ const jwtVerify = (token) => { + // eslint-disable-next-line prefer-const let [email, created_at = 0, expires_in = 0] = token.split(':'); created_at += Math.floor(new Date().getTime() / 1000); expires_in += created_at; diff --git a/test/utils/mocks/req.js b/test/utils/mocks/req.js index cb67781b..4ca5f9c9 100644 --- a/test/utils/mocks/req.js +++ b/test/utils/mocks/req.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 @@ -33,7 +33,7 @@ const optsWithExpAuth = { const optsWithMultiAuthAnon = { headers: new Headers({ - 'Authorization': `,Bearer aparker@geometrixx.info` + Authorization: ',Bearer aparker@geometrixx.info', }), }; diff --git a/test/utils/mocks/s3.js b/test/utils/mocks/s3.js index acdf10b1..5660172e 100644 --- a/test/utils/mocks/s3.js +++ b/test/utils/mocks/s3.js @@ -1,9 +1,16 @@ +/* + * Copyright 2025 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ class S3Client { } -class PutObjectCommand { - -} - export default S3Client; diff --git a/test/utils/offlineValidation.test.js b/test/utils/offlineValidation.test.js index 9355d4b4..7a714bf3 100644 --- a/test/utils/offlineValidation.test.js +++ b/test/utils/offlineValidation.test.js @@ -9,6 +9,11 @@ * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ +/* eslint-disable consistent-return */ +import assert from 'node:assert'; +import { generateKeyPair, exportJWK, SignJWT } from 'jose'; +import env from './mocks/env.js'; +import { getUsers } from '../../src/utils/auth.js'; const mockedResponses = new Map(); function mockFetch(url, response) { @@ -27,10 +32,6 @@ const fetch = async (url) => { }; }; global.fetch = fetch; -import assert from 'assert'; -import { generateKeyPair, exportJWK, SignJWT } from 'jose'; -import env from './mocks/env.js'; -import { getUsers } from '../../src/utils/auth.js'; async function generateMockKeyPair(kid) { const { publicKey, privateKey } = await generateKeyPair('RS256'); @@ -42,7 +43,7 @@ async function generateMockKeyPair(kid) { return { privateKey, publicKeyJwk, - } + }; } async function generateToken(kid, privateKey) { @@ -52,11 +53,11 @@ async function generateToken(kid, privateKey) { created_at: Date.now() / 1000, expires_in: 60, }) - .setProtectedHeader({ - alg: 'RS256', - kid, - }) - .sign(privateKey); + .setProtectedHeader({ + alg: 'RS256', + kid, + }) + .sign(privateKey); } function mockRequest(accessToken) { @@ -67,7 +68,7 @@ function mockRequest(accessToken) { Authorization: `Bearer ${accessToken}`, }), }, - ) + ); } describe('Offline Token Validation', async () => { @@ -76,19 +77,15 @@ describe('Offline Token Validation', async () => { mockFetch(`${env.IMS_ORIGIN}/ims/profile/v1`, { ok: true, status: 200, - json: async () => { - return { - email: 'mocked@example.com', - }; - }, + json: async () => ({ + email: 'mocked@example.com', + }), }); mockFetch(`${env.IMS_ORIGIN}/ims/organizations/v5`, { ok: true, status: 200, - json: async () => { - return []; - }, + json: async () => [], }); }); @@ -96,12 +93,10 @@ describe('Offline Token Validation', async () => { const kid = 'id1'; const { privateKey, publicKeyJwk } = await generateMockKeyPair(kid); - mockFetch(`https://ims-na1.adobelogin.com/ims/keys`, { + mockFetch('https://ims-na1.adobelogin.com/ims/keys', { ok: true, status: 200, - json: async () => { - return { keys: [publicKeyJwk] }; - }, + json: async () => ({ keys: [publicKeyJwk] }), }); const accessToken = await generateToken(kid, privateKey); @@ -123,28 +118,26 @@ describe('Offline Token Validation', async () => { cached = JSON.parse(value); } }, - } - } + }, + }; const users = await getUsers(mockRequest(accessToken), localEnv); - assert.deepStrictEqual(users, [{ email: 'mocked@example.com', orgs: [] } ]); + assert.deepStrictEqual(users, [{ email: 'mocked@example.com', orgs: [] }]); assert.ok(cacheLookup, 'Should have looked up the keys in the cache'); assert.ok(cached, 'Should have cached the keys'); assert.ok(cached.uat >= before, 'Timestamp of keys in cache should be after the test started'); assert.ok(cached.uat <= Date.now(), 'Timestamp of keys in cache should be before the test ended'); - assert.deepStrictEqual(cached.jwks, { keys: [publicKeyJwk]}, 'Cached keys should match the fetched keys'); + assert.deepStrictEqual(cached.jwks, { keys: [publicKeyJwk] }, 'Cached keys should match the fetched keys'); }); it('should only use keys from cache if present and not stale', async () => { const kid = 'id1'; const { privateKey, publicKeyJwk } = await generateMockKeyPair(kid); - mockFetch(`https://ims-na1.adobelogin.com/ims/keys`, { + mockFetch('https://ims-na1.adobelogin.com/ims/keys', { ok: true, status: 200, - json: async () => { - return { keys: [publicKeyJwk] }; - }, + json: async () => ({ keys: [publicKeyJwk] }), }); const accessToken = await generateToken(kid, privateKey); @@ -160,8 +153,8 @@ describe('Offline Token Validation', async () => { return JSON.stringify({ uat: Date.now() - 1000, jwks: { - keys: [publicKeyJwk] - } + keys: [publicKeyJwk], + }, }); } }, @@ -170,34 +163,32 @@ describe('Offline Token Validation', async () => { cached = true; } }, - } - } + }, + }; const users = await getUsers(mockRequest(accessToken), localEnv); - assert.deepStrictEqual(users, [{ email: 'mocked@example.com', orgs: [] } ]); + assert.deepStrictEqual(users, [{ email: 'mocked@example.com', orgs: [] }]); assert.ok(cacheLookup, 'Should have looked up the keys in the cache'); assert.ok(!cached, 'There should be no cache update'); - //assert.ok(!scope.isDone()); + // assert.ok(!scope.isDone()); }); it('should fetch key missing from cache if not in cooldown period', async () => { const kid1 = 'id1'; - const { + const { publicKeyJwk: publicKeyJwk1, } = await generateMockKeyPair(kid1); const kid2 = 'id2'; - const { + const { privateKey: privateKey2, publicKeyJwk: publicKeyJwk2, } = await generateMockKeyPair(kid2); - mockFetch(`https://ims-na1.adobelogin.com/ims/keys`, { + mockFetch('https://ims-na1.adobelogin.com/ims/keys', { ok: true, status: 200, - json: async () => { - return { keys: [publicKeyJwk1, publicKeyJwk2] }; - }, + json: async () => ({ keys: [publicKeyJwk1, publicKeyJwk2] }), }); const accessToken = await generateToken(kid2, privateKey2); @@ -214,7 +205,7 @@ describe('Offline Token Validation', async () => { uat: Date.now() - 120 * 1000, jwks: { keys: [publicKeyJwk1], - } + }, }); } }, @@ -223,13 +214,13 @@ describe('Offline Token Validation', async () => { cached = JSON.parse(value); } }, - } - } + }, + }; const before = Date.now(); const users = await getUsers(mockRequest(accessToken), localEnv); - assert.deepStrictEqual(users, [{ email: 'mocked@example.com', orgs: [] } ]); + assert.deepStrictEqual(users, [{ email: 'mocked@example.com', orgs: [] }]); assert.ok(cacheLookup, 'Should have looked up the keys in the cache'); assert.ok(cached, 'Should have cached the keys'); assert.ok(cached.uat >= before, 'Timestamp of keys in cache should be after the test started'); @@ -243,22 +234,20 @@ describe('Offline Token Validation', async () => { it('should not fetch key missing if in the cooldown period and fail validation', async () => { const kid1 = 'id1'; - const { + const { publicKeyJwk: publicKeyJwk1, } = await generateMockKeyPair(kid1); const kid2 = 'id2'; - const { + const { privateKey: privateKey2, publicKeyJwk: publicKeyJwk2, } = await generateMockKeyPair(kid2); - mockFetch(`https://ims-na1.adobelogin.com/ims/keys`, { + mockFetch('https://ims-na1.adobelogin.com/ims/keys', { ok: true, status: 200, - json: async () => { - return { keys: [publicKeyJwk1, publicKeyJwk2] }; - }, + json: async () => ({ keys: [publicKeyJwk1, publicKeyJwk2] }), }); const accessToken = await generateToken(kid2, privateKey2); @@ -275,7 +264,7 @@ describe('Offline Token Validation', async () => { uat: Date.now() - 20 * 1000, jwks: { keys: [publicKeyJwk1], - } + }, }); } }, @@ -284,26 +273,24 @@ describe('Offline Token Validation', async () => { cached = true; } }, - } - } + }, + }; const users = await getUsers(mockRequest(accessToken), localEnv); - assert.deepStrictEqual(users, [{ email: 'anonymous' } ]); + assert.deepStrictEqual(users, [{ email: 'anonymous' }]); assert.ok(cacheLookup, 'Should have looked up the keys in the cache'); assert.ok(!cached, 'Should not try to store keys in cache.'); - //assert.ok(!scope.isDone()); + // assert.ok(!scope.isDone()); }); it('should refresh cache after 24h', async () => { const kid = 'id1'; const { privateKey, publicKeyJwk } = await generateMockKeyPair(kid); - mockFetch(`https://ims-na1.adobelogin.com/ims/keys`, { + mockFetch('https://ims-na1.adobelogin.com/ims/keys', { ok: true, status: 200, - json: async () => { - return { keys: [publicKeyJwk] }; - }, + json: async () => ({ keys: [publicKeyJwk] }), }); const accessToken = await generateToken(kid, privateKey); @@ -321,8 +308,8 @@ describe('Offline Token Validation', async () => { return JSON.stringify({ uat: Date.now() - 25 * 60 * 60 * 1000, // more than 24h ago jwks: { - keys: [publicKeyJwk] - } + keys: [publicKeyJwk], + }, }); } }, @@ -331,28 +318,26 @@ describe('Offline Token Validation', async () => { cached = JSON.parse(value); } }, - } - } + }, + }; const users = await getUsers(mockRequest(accessToken), localEnv); - assert.deepStrictEqual(users, [{ email: 'mocked@example.com', orgs: [] } ]); + assert.deepStrictEqual(users, [{ email: 'mocked@example.com', orgs: [] }]); assert.ok(cacheLookup, 'Should have looked up the keys in the cache'); assert.ok(cached, 'Should have cached the keys'); assert.ok(cached.uat >= before, 'Timestamp of keys in cache should be after the test started'); assert.ok(cached.uat <= Date.now(), 'Timestamp of keys in cache should be before the test ended'); - assert.deepStrictEqual(cached.jwks, { keys: [publicKeyJwk]}, 'Cached keys should match the fetched keys'); + assert.deepStrictEqual(cached.jwks, { keys: [publicKeyJwk] }, 'Cached keys should match the fetched keys'); }); it('should not fail if storing in cache fails', async () => { const kid = 'id1'; const { privateKey, publicKeyJwk } = await generateMockKeyPair(kid); - mockFetch(`https://ims-na1.adobelogin.com/ims/keys`, { + mockFetch('https://ims-na1.adobelogin.com/ims/keys', { ok: true, status: 200, - json: async () => { - return { keys: [publicKeyJwk] }; - }, + json: async () => ({ keys: [publicKeyJwk] }), }); const accessToken = await generateToken(kid, privateKey); @@ -375,15 +360,15 @@ describe('Offline Token Validation', async () => { throw new Error('429: Too many requests'); } }, - } - } + }, + }; const users = await getUsers(mockRequest(accessToken), localEnv); - assert.deepStrictEqual(users, [{ email: 'mocked@example.com', orgs: [] } ]); + assert.deepStrictEqual(users, [{ email: 'mocked@example.com', orgs: [] }]); assert.ok(cacheLookup, 'Should have looked up the keys in the cache'); assert.ok(cacheAttempt, 'Should have try to cache the keys'); assert.ok(cacheAttempt.uat >= before, 'Timestamp of keys in cache should be after the test started'); assert.ok(cacheAttempt.uat <= Date.now(), 'Timestamp of keys in cache should be before the test ended'); - assert.deepStrictEqual(cacheAttempt.jwks, { keys: [publicKeyJwk]}, 'Cached attempt keys should match the fetched keys'); + assert.deepStrictEqual(cacheAttempt.jwks, { keys: [publicKeyJwk] }, 'Cached attempt keys should match the fetched keys'); }); });