diff --git a/Makefile b/Makefile index 8b7d6ee..1e07a41 100644 --- a/Makefile +++ b/Makefile @@ -1,54 +1,71 @@ -.PHONY: - install clean install dev valid test prod all - tune2chrome tune2firefox .DEFAULT_GOAL := dev -CHROME_ZIP = "extension.chrome.zip" +# Ensure environment dependencies exist +REQUIRED_BINS := deno jq zip tree +$(foreach bin,$(REQUIRED_BINS),$(if $(shell command -v $(bin) 2> /dev/null),,$(error Missing dependency: `$(bin)`))) + CHROME_MANIFEST = ./manifest.chrome.json -FIREFOX_ZIP = "extension.firefox.zip" +CHROME_MANIFEST_VERSION != jq -j '.version' $(CHROME_MANIFEST) +CHROME_ZIP = "extension.chrome-$(CHROME_MANIFEST_VERSION).zip" FIREFOX_MANIFEST = ./manifest.firefox.json -DENO_DEV = NODE_ENV=development deno run --watch -DENO_PROD = NODE_ENV=production deno run -DENO_OPTIONS = --allow-env --allow-read --allow-run +FIREFOX_MANIFEST_VERSION != jq -j '.version' $(FIREFOX_MANIFEST) +FIREFOX_ZIP = "extension.firefox-$(FIREFOX_MANIFEST_VERSION).zip" +DENO_DEV = BUILD_MODE=development deno run --watch --allow-env --allow-read --allow-run +DENO_PROD = BUILD_MODE=production deno run --allow-env --allow-read --allow-run OUTPUT_DIR = ./public/ BUILD_DIR = ./public/build/ BUILD_SCRIPT = ./build.ts +.PHONY: clean clean: rm -rf ./node_modules ./deno.lock $(BUILD_DIR) $(CHROME_ZIP) $(FIREFOX_ZIP) +.PHONY: install install: deno install --allow-scripts +.PHONY: update +update: + deno update --latest + +.PHONY: dev dev: rm -rf $(BUILD_DIR) - $(DENO_DEV) $(DENO_OPTIONS) $(BUILD_SCRIPT) + $(DENO_DEV) $(BUILD_SCRIPT) +.PHONY: valid valid: deno fmt --unstable-component deno lint + deno check +.PHONY: test test: valid deno test --no-check --trace-leaks --reporter=dot +.PHONY: prod prod: test rm -rf $(BUILD_DIR) - $(DENO_PROD) $(DENO_OPTIONS) $(BUILD_SCRIPT) + $(DENO_PROD) $(BUILD_SCRIPT) + deno audit +.PHONY: tune2chrome tune2chrome: cp $(CHROME_MANIFEST) manifest.json +.PHONY: tune2firefox tune2firefox: cp $(FIREFOX_MANIFEST) manifest.json +.PHONY: all all: prod - make tune2firefox + $(MAKE) tune2firefox rm -rf $(FIREFOX_ZIP) zip -r $(FIREFOX_ZIP) $(OUTPUT_DIR) ./manifest.json > /dev/null - make tune2chrome + $(MAKE) tune2chrome rm -rf $(CHROME_ZIP) zip -r $(CHROME_ZIP) $(OUTPUT_DIR) ./manifest.json > /dev/null zip --delete $(CHROME_ZIP) "$(BUILD_DIR)firefox/*" > /dev/null - tree -Dis $(BUILD_DIR) *.zip + tree -Dis $(BUILD_DIR) *.zip | grep -E "\\.css|\\.js|\\.zip" diff --git a/README.md b/README.md index 0b3f0eb..a43479a 100644 --- a/README.md +++ b/README.md @@ -147,16 +147,18 @@ declare global { } ``` +### Build requirements +- Linux: [deno](https://docs.deno.com/runtime/getting_started/installation/), `make`, `jq`, `zip`, `tree` + ### Build instructions -- Linux -- [Deno](https://docs.deno.com/runtime/getting_started/installation/) 2.2.8 +Here is a short list to help you get started, for a full set of make commands refer to [./Makefile](./Makefile): ```sh -make install # install dependencies -make all # build for prod and make extension.${browser}.zip -make tune2chrome # or tune2firefox for relevant manifest.json file -make dev # local development +make clean install # install dependencies +make tune2chrome # or tune2firefox to generate relevant manifest.json file +make dev # build in development mode and watch for changes +make all # build in production mode and make extension zip files ``` #### Based on diff --git a/build.ts b/build.ts index 0c2c57d..5cd7e7f 100644 --- a/build.ts +++ b/build.ts @@ -2,8 +2,9 @@ import { build, type BuildOptions, context, stop } from 'esbuild'; import manifest from './manifest.json' with { type: 'json' }; import { vue3Plugin } from 'esbuild-plugin-vue-iii'; -const nodeEnv = Deno.env.get('NODE_ENV'); -const isProd = nodeEnv === 'production'; +const isProd = Deno.env.get('BUILD_MODE') === 'production'; +const buildMode = isProd ? 'production' : 'development'; +const logLevel = isProd ? 'warning' : 'debug'; const buildOptions: BuildOptions = { plugins: [ vue3Plugin({ @@ -35,11 +36,11 @@ const buildOptions: BuildOptions = { platform: 'browser', format: 'iife', target: 'esnext', - conditions: [`${nodeEnv}`], + conditions: [buildMode], minify: isProd, sourcemap: false, treeShaking: true, - logLevel: isProd ? 'warning' : 'debug', + logLevel, }; if (isProd) { diff --git a/deno.json b/deno.json index 67adf81..0bb87d8 100644 --- a/deno.json +++ b/deno.json @@ -4,6 +4,7 @@ "lib": ["dom", "dom.iterable", "dom.asynciterable", "deno.ns"], "strict": true }, + "exclude": ["tmp/"], "lint": { "include": [ "src/", @@ -32,10 +33,10 @@ ] }, "imports": { - "esbuild": "https://deno.land/x/esbuild@v0.25.2/mod.js", + "esbuild": "npm:esbuild@0.27.3", "esbuild-plugin-vue-iii": "npm:esbuild-plugin-vue-iii@0.5.0", - "@std/expect": "jsr:@std/expect@1.0.15", - "@std/testing": "jsr:@std/testing@1.0.11" + "@std/expect": "jsr:@std/expect@1.0.17", + "@std/testing": "jsr:@std/testing@1.0.17" } } diff --git a/deno.lock b/deno.lock index 043e250..60bbaed 100644 --- a/deno.lock +++ b/deno.lock @@ -1,245 +1,233 @@ { "version": "5", "specifiers": { - "jsr:@std/assert@^1.0.12": "1.0.12", - "jsr:@std/async@^1.0.12": "1.0.12", - "jsr:@std/data-structures@^1.0.6": "1.0.6", - "jsr:@std/expect@1.0.15": "1.0.15", - "jsr:@std/fs@^1.0.16": "1.0.16", - "jsr:@std/internal@^1.0.6": "1.0.6", - "jsr:@std/path@^1.0.8": "1.0.8", - "jsr:@std/testing@1.0.11": "1.0.11", - "npm:@noble/hashes@1.8.0": "1.8.0", - "npm:@types/chrome@*": "0.0.326", - "npm:@types/chrome@0.0.326": "0.0.326", - "npm:@types/diff-match-patch@1.0.36": "1.0.36", - "npm:@types/firefox-webext-browser@*": "120.0.4", - "npm:@types/firefox-webext-browser@120.0.4": "120.0.4", - "npm:diff-match-patch@1.0.5": "1.0.5", - "npm:esbuild-plugin-vue-iii@0.5.0": "0.5.0_esbuild@0.25.2_typescript@5.8.3", + "jsr:@std/assert@^1.0.14": "1.0.18", + "jsr:@std/assert@^1.0.17": "1.0.18", + "jsr:@std/async@^1.1.0": "1.1.1", + "jsr:@std/data-structures@^1.0.10": "1.0.10", + "jsr:@std/expect@1.0.17": "1.0.17", + "jsr:@std/fs@^1.0.22": "1.0.22", + "jsr:@std/internal@^1.0.10": "1.0.12", + "jsr:@std/internal@^1.0.12": "1.0.12", + "jsr:@std/path@^1.1.4": "1.1.4", + "jsr:@std/testing@1.0.17": "1.0.17", + "npm:@noble/hashes@2.0.1": "2.0.1", + "npm:@types/chrome@*": "0.1.36", + "npm:@types/chrome@0.1.36": "0.1.36", + "npm:@types/firefox-webext-browser@*": "143.0.0", + "npm:@types/firefox-webext-browser@143.0.0": "143.0.0", + "npm:esbuild-plugin-vue-iii@0.5.0": "0.5.0_esbuild@0.27.3_typescript@5.9.3", + "npm:esbuild@0.27.3": "0.27.3", "npm:jsondiffpatch@0.7.3": "0.7.3", - "npm:pinia@3.0.3": "3.0.3_typescript@5.8.3_vue@3.5.16__typescript@5.8.3", - "npm:typescript@5.8.3": "5.8.3", - "npm:vue-loader@17.4.2": "17.4.2_webpack@5.99.1", - "npm:vue@3.5.16": "3.5.16_typescript@5.8.3" + "npm:pinia@3.0.4": "3.0.4_typescript@5.9.3_vue@3.5.28__typescript@5.9.3", + "npm:typescript@5.9.3": "5.9.3", + "npm:vue-loader@17.4.2": "17.4.2_webpack@5.105.0__acorn@8.15.0", + "npm:vue@3.5.28": "3.5.28_typescript@5.9.3" }, "jsr": { - "@std/assert@1.0.12": { - "integrity": "08009f0926dda9cbd8bef3a35d3b6a4b964b0ab5c3e140a4e0351fbf34af5b9a", + "@std/assert@1.0.18": { + "integrity": "270245e9c2c13b446286de475131dc688ca9abcd94fc5db41d43a219b34d1c78", "dependencies": [ - "jsr:@std/internal" + "jsr:@std/internal@^1.0.12" ] }, - "@std/async@1.0.12": { - "integrity": "d1bfcec459e8012846fe4e38dfc4241ab23240ecda3d8d6dfcf6d81a632e803d" + "@std/async@1.1.1": { + "integrity": "8a79beb3378cc229ce65ba2c746cfd03e4855ddd891d1eb6b9e32128e0d5339c" }, - "@std/data-structures@1.0.6": { - "integrity": "76a7fd8080c66604c0496220a791860492ab21a04a63a969c0b9a0609bbbb760" + "@std/data-structures@1.0.10": { + "integrity": "f574f86b0e07c69b9edc555fcc814b57d29258bad39fd5a34ba8a80ecf033cfe" }, - "@std/expect@1.0.15": { - "integrity": "eca360007b5a7f13dbfa1294224baee7fb98dcd460d8461fe64eeae302902945", + "@std/expect@1.0.17": { + "integrity": "316b47dd65c33e3151344eb3267bf42efba17d1415425f07ed96185d67fc04d9", "dependencies": [ - "jsr:@std/assert", - "jsr:@std/internal" + "jsr:@std/assert@^1.0.14", + "jsr:@std/internal@^1.0.10" ] }, - "@std/fs@1.0.16": { - "integrity": "81878f62b6eeda0bf546197fc3daa5327c132fee1273f6113f940784a468b036", + "@std/fs@1.0.22": { + "integrity": "de0f277a58a867147a8a01bc1b181d0dfa80bfddba8c9cf2bacd6747bcec9308", "dependencies": [ "jsr:@std/path" ] }, - "@std/internal@1.0.6": { - "integrity": "9533b128f230f73bd209408bb07a4b12f8d4255ab2a4d22a1fd6d87304aca9a4" + "@std/internal@1.0.12": { + "integrity": "972a634fd5bc34b242024402972cd5143eac68d8dffaca5eaa4dba30ce17b027" }, - "@std/path@1.0.8": { - "integrity": "548fa456bb6a04d3c1a1e7477986b6cffbce95102d0bb447c67c4ee70e0364be" + "@std/path@1.1.4": { + "integrity": "1d2d43f39efb1b42f0b1882a25486647cb851481862dc7313390b2bb044314b5", + "dependencies": [ + "jsr:@std/internal@^1.0.12" + ] }, - "@std/testing@1.0.11": { - "integrity": "12b3db12d34f0f385a26248933bde766c0f8c5ad8b6ab34d4d38f528ab852f48", + "@std/testing@1.0.17": { + "integrity": "87bdc2700fa98249d48a17cd72413352d3d3680dcfbdb64947fd0982d6bbf681", "dependencies": [ - "jsr:@std/assert", + "jsr:@std/assert@^1.0.17", "jsr:@std/async", "jsr:@std/data-structures", "jsr:@std/fs", - "jsr:@std/internal", + "jsr:@std/internal@^1.0.12", "jsr:@std/path" ] } }, "npm": { - "@babel/helper-string-parser@7.25.9": { - "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==" - }, "@babel/helper-string-parser@7.27.1": { "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==" }, - "@babel/helper-validator-identifier@7.25.9": { - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==" - }, - "@babel/helper-validator-identifier@7.27.1": { - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==" - }, - "@babel/parser@7.27.0": { - "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==", - "dependencies": [ - "@babel/types@7.27.0" - ], - "bin": true + "@babel/helper-validator-identifier@7.28.5": { + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==" }, - "@babel/parser@7.27.5": { - "integrity": "sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg==", + "@babel/parser@7.29.0": { + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", "dependencies": [ - "@babel/types@7.27.6" + "@babel/types" ], "bin": true }, - "@babel/types@7.27.0": { - "integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==", - "dependencies": [ - "@babel/helper-string-parser@7.25.9", - "@babel/helper-validator-identifier@7.25.9" - ] - }, - "@babel/types@7.27.6": { - "integrity": "sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==", + "@babel/types@7.29.0": { + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", "dependencies": [ - "@babel/helper-string-parser@7.27.1", - "@babel/helper-validator-identifier@7.27.1" + "@babel/helper-string-parser", + "@babel/helper-validator-identifier" ] }, "@dmsnell/diff-match-patch@1.1.0": { "integrity": "sha512-yejLPmM5pjsGvxS9gXablUSbInW7H976c/FJ4iQxWIm7/38xBySRemTPDe34lhg1gVLbJntX0+sH0jYfU+PN9A==" }, - "@esbuild/aix-ppc64@0.25.2": { - "integrity": "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==", + "@esbuild/aix-ppc64@0.27.3": { + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", "os": ["aix"], "cpu": ["ppc64"] }, - "@esbuild/android-arm64@0.25.2": { - "integrity": "sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==", + "@esbuild/android-arm64@0.27.3": { + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", "os": ["android"], "cpu": ["arm64"] }, - "@esbuild/android-arm@0.25.2": { - "integrity": "sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==", + "@esbuild/android-arm@0.27.3": { + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", "os": ["android"], "cpu": ["arm"] }, - "@esbuild/android-x64@0.25.2": { - "integrity": "sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==", + "@esbuild/android-x64@0.27.3": { + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", "os": ["android"], "cpu": ["x64"] }, - "@esbuild/darwin-arm64@0.25.2": { - "integrity": "sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==", + "@esbuild/darwin-arm64@0.27.3": { + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", "os": ["darwin"], "cpu": ["arm64"] }, - "@esbuild/darwin-x64@0.25.2": { - "integrity": "sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==", + "@esbuild/darwin-x64@0.27.3": { + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", "os": ["darwin"], "cpu": ["x64"] }, - "@esbuild/freebsd-arm64@0.25.2": { - "integrity": "sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==", + "@esbuild/freebsd-arm64@0.27.3": { + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", "os": ["freebsd"], "cpu": ["arm64"] }, - "@esbuild/freebsd-x64@0.25.2": { - "integrity": "sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==", + "@esbuild/freebsd-x64@0.27.3": { + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", "os": ["freebsd"], "cpu": ["x64"] }, - "@esbuild/linux-arm64@0.25.2": { - "integrity": "sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==", + "@esbuild/linux-arm64@0.27.3": { + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", "os": ["linux"], "cpu": ["arm64"] }, - "@esbuild/linux-arm@0.25.2": { - "integrity": "sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==", + "@esbuild/linux-arm@0.27.3": { + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", "os": ["linux"], "cpu": ["arm"] }, - "@esbuild/linux-ia32@0.25.2": { - "integrity": "sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==", + "@esbuild/linux-ia32@0.27.3": { + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", "os": ["linux"], "cpu": ["ia32"] }, - "@esbuild/linux-loong64@0.25.2": { - "integrity": "sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==", + "@esbuild/linux-loong64@0.27.3": { + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", "os": ["linux"], "cpu": ["loong64"] }, - "@esbuild/linux-mips64el@0.25.2": { - "integrity": "sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==", + "@esbuild/linux-mips64el@0.27.3": { + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", "os": ["linux"], "cpu": ["mips64el"] }, - "@esbuild/linux-ppc64@0.25.2": { - "integrity": "sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==", + "@esbuild/linux-ppc64@0.27.3": { + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", "os": ["linux"], "cpu": ["ppc64"] }, - "@esbuild/linux-riscv64@0.25.2": { - "integrity": "sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==", + "@esbuild/linux-riscv64@0.27.3": { + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", "os": ["linux"], "cpu": ["riscv64"] }, - "@esbuild/linux-s390x@0.25.2": { - "integrity": "sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==", + "@esbuild/linux-s390x@0.27.3": { + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", "os": ["linux"], "cpu": ["s390x"] }, - "@esbuild/linux-x64@0.25.2": { - "integrity": "sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==", + "@esbuild/linux-x64@0.27.3": { + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", "os": ["linux"], "cpu": ["x64"] }, - "@esbuild/netbsd-arm64@0.25.2": { - "integrity": "sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==", + "@esbuild/netbsd-arm64@0.27.3": { + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", "os": ["netbsd"], "cpu": ["arm64"] }, - "@esbuild/netbsd-x64@0.25.2": { - "integrity": "sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==", + "@esbuild/netbsd-x64@0.27.3": { + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", "os": ["netbsd"], "cpu": ["x64"] }, - "@esbuild/openbsd-arm64@0.25.2": { - "integrity": "sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==", + "@esbuild/openbsd-arm64@0.27.3": { + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", "os": ["openbsd"], "cpu": ["arm64"] }, - "@esbuild/openbsd-x64@0.25.2": { - "integrity": "sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==", + "@esbuild/openbsd-x64@0.27.3": { + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", "os": ["openbsd"], "cpu": ["x64"] }, - "@esbuild/sunos-x64@0.25.2": { - "integrity": "sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==", + "@esbuild/openharmony-arm64@0.27.3": { + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "os": ["openharmony"], + "cpu": ["arm64"] + }, + "@esbuild/sunos-x64@0.27.3": { + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", "os": ["sunos"], "cpu": ["x64"] }, - "@esbuild/win32-arm64@0.25.2": { - "integrity": "sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==", + "@esbuild/win32-arm64@0.27.3": { + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", "os": ["win32"], "cpu": ["arm64"] }, - "@esbuild/win32-ia32@0.25.2": { - "integrity": "sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==", + "@esbuild/win32-ia32@0.27.3": { + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", "os": ["win32"], "cpu": ["ia32"] }, - "@esbuild/win32-x64@0.25.2": { - "integrity": "sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==", + "@esbuild/win32-x64@0.27.3": { + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", "os": ["win32"], "cpu": ["x64"] }, - "@jridgewell/gen-mapping@0.3.8": { - "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "@jridgewell/gen-mapping@0.3.13": { + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "dependencies": [ - "@jridgewell/set-array", "@jridgewell/sourcemap-codec", "@jridgewell/trace-mapping" ] @@ -247,28 +235,25 @@ "@jridgewell/resolve-uri@3.1.2": { "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==" }, - "@jridgewell/set-array@1.2.1": { - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==" - }, - "@jridgewell/source-map@0.3.6": { - "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "@jridgewell/source-map@0.3.11": { + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", "dependencies": [ "@jridgewell/gen-mapping", "@jridgewell/trace-mapping" ] }, - "@jridgewell/sourcemap-codec@1.5.0": { - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" + "@jridgewell/sourcemap-codec@1.5.5": { + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==" }, - "@jridgewell/trace-mapping@0.3.25": { - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "@jridgewell/trace-mapping@0.3.31": { + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "dependencies": [ "@jridgewell/resolve-uri", "@jridgewell/sourcemap-codec" ] }, - "@noble/hashes@1.8.0": { - "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==" + "@noble/hashes@2.0.1": { + "integrity": "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==" }, "@nodelib/fs.scandir@2.1.5": { "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", @@ -287,16 +272,13 @@ "fastq" ] }, - "@types/chrome@0.0.326": { - "integrity": "sha512-WS7jKf3ZRZFHOX7dATCZwqNJgdfiSF0qBRFxaO0LhIOvTNBrfkab26bsZwp6EBpYtqp8loMHJTnD6vDTLWPKYw==", + "@types/chrome@0.1.36": { + "integrity": "sha512-BvHbuyGttYXnGt5Gpwa4769KIinKHY1iLjlAPrrMBS2GI9m/XNMPtdsq0NgQalyuUdxvlMN/0OyGw0shFVIoUQ==", "dependencies": [ "@types/filesystem", "@types/har-format" ] }, - "@types/diff-match-patch@1.0.36": { - "integrity": "sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg==" - }, "@types/eslint-scope@3.7.7": { "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", "dependencies": [ @@ -311,8 +293,8 @@ "@types/json-schema" ] }, - "@types/estree@1.0.7": { - "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==" + "@types/estree@1.0.8": { + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==" }, "@types/filesystem@0.0.36": { "integrity": "sha512-vPDXOZuannb9FZdxgHnqSwAG/jvdGM8Wq+6N4D/d80z+D4HWH+bItqsZaVRQykAn6WEVeEkLm2oQigyHtgb0RA==", @@ -323,8 +305,8 @@ "@types/filewriter@0.0.33": { "integrity": "sha512-xFU8ZXTw4gd358lb2jw25nxY9QAgqn2+bKKjKOYfNCzN4DKCFetK7sPtrlpg66Ywe3vWY9FNxprZawAh9wfJ3g==" }, - "@types/firefox-webext-browser@120.0.4": { - "integrity": "sha512-lBrpf08xhiZBigrtdQfUaqX1UauwZ+skbFiL8u2Tdra/rklkKadYmIzTwkNZSWtuZ7OKpFqbE2HHfDoFqvZf6w==" + "@types/firefox-webext-browser@143.0.0": { + "integrity": "sha512-865dYKMOP0CllFyHmgXV4IQgVL51OSQQCwSoihQ17EwugePKFSAZRc0EI+y7Ly4q7j5KyURlA7LgRpFieO4JOw==" }, "@types/har-format@1.2.16": { "integrity": "sha512-fluxdy7ryD3MV6h8pTfTYpy/xQzCFC7m89nOH9y94cNqJ1mDIDPut7MnRHI3F6qRmh/cT2fUjG1MLdCNb4hE9A==" @@ -332,16 +314,19 @@ "@types/json-schema@7.0.15": { "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" }, - "@types/node@22.12.0": { - "integrity": "sha512-Fll2FZ1riMjNmlmJOdAyY5pUbkftXslB5DgEzlIuNaiWhXd00FhWxVC/r4yV/4wBb9JfImTu+jiSvXTkJ7F/gA==", + "@types/node@25.2.1": { + "integrity": "sha512-CPrnr8voK8vC6eEtyRzvMpgp3VyVRhgclonE7qYi6P9sXwYb59ucfrnmFBTaP0yUi8Gk4yZg/LlTJULGxvTNsg==", "dependencies": [ "undici-types" ] }, + "@types/trusted-types@2.0.7": { + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==" + }, "@typescript-eslint/types@4.33.0": { "integrity": "sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ==" }, - "@typescript-eslint/typescript-estree@4.33.0_typescript@5.8.3": { + "@typescript-eslint/typescript-estree@4.33.0_typescript@5.9.3": { "integrity": "sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==", "dependencies": [ "@typescript-eslint/types", @@ -360,90 +345,52 @@ "eslint-visitor-keys" ] }, - "@vue/compiler-core@3.5.13": { - "integrity": "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==", - "dependencies": [ - "@babel/parser@7.27.0", - "@vue/shared@3.5.13", - "entities", - "estree-walker", - "source-map-js" - ] - }, - "@vue/compiler-core@3.5.16": { - "integrity": "sha512-AOQS2eaQOaaZQoL1u+2rCJIKDruNXVBZSiUD3chnUrsoX5ZTQMaCvXlWNIfxBJuU15r1o7+mpo5223KVtIhAgQ==", + "@vue/compiler-core@3.5.28": { + "integrity": "sha512-kviccYxTgoE8n6OCw96BNdYlBg2GOWfBuOW4Vqwrt7mSKWKwFVvI8egdTltqRgITGPsTFYtKYfxIG8ptX2PJHQ==", "dependencies": [ - "@babel/parser@7.27.5", - "@vue/shared@3.5.16", + "@babel/parser", + "@vue/shared", "entities", "estree-walker", "source-map-js" ] }, - "@vue/compiler-dom@3.5.13": { - "integrity": "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==", + "@vue/compiler-dom@3.5.28": { + "integrity": "sha512-/1ZepxAb159jKR1btkefDP+J2xuWL5V3WtleRmxaT+K2Aqiek/Ab/+Ebrw2pPj0sdHO8ViAyyJWfhXXOP/+LQA==", "dependencies": [ - "@vue/compiler-core@3.5.13", - "@vue/shared@3.5.13" + "@vue/compiler-core", + "@vue/shared" ] }, - "@vue/compiler-dom@3.5.16": { - "integrity": "sha512-SSJIhBr/teipXiXjmWOVWLnxjNGo65Oj/8wTEQz0nqwQeP75jWZ0n4sF24Zxoht1cuJoWopwj0J0exYwCJ0dCQ==", + "@vue/compiler-sfc@3.5.28": { + "integrity": "sha512-6TnKMiNkd6u6VeVDhZn/07KhEZuBSn43Wd2No5zaP5s3xm8IqFTHBj84HJah4UepSUJTro5SoqqlOY22FKY96g==", "dependencies": [ - "@vue/compiler-core@3.5.16", - "@vue/shared@3.5.16" - ] - }, - "@vue/compiler-sfc@3.5.13": { - "integrity": "sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==", - "dependencies": [ - "@babel/parser@7.27.0", - "@vue/compiler-core@3.5.13", - "@vue/compiler-dom@3.5.13", - "@vue/compiler-ssr@3.5.13", - "@vue/shared@3.5.13", - "estree-walker", - "magic-string", - "postcss", - "source-map-js" - ] - }, - "@vue/compiler-sfc@3.5.16": { - "integrity": "sha512-rQR6VSFNpiinDy/DVUE0vHoIDUF++6p910cgcZoaAUm3POxgNOOdS/xgoll3rNdKYTYPnnbARDCZOyZ+QSe6Pw==", - "dependencies": [ - "@babel/parser@7.27.5", - "@vue/compiler-core@3.5.16", - "@vue/compiler-dom@3.5.16", - "@vue/compiler-ssr@3.5.16", - "@vue/shared@3.5.16", + "@babel/parser", + "@vue/compiler-core", + "@vue/compiler-dom", + "@vue/compiler-ssr", + "@vue/shared", "estree-walker", "magic-string", "postcss", "source-map-js" ] }, - "@vue/compiler-ssr@3.5.13": { - "integrity": "sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==", - "dependencies": [ - "@vue/compiler-dom@3.5.13", - "@vue/shared@3.5.13" - ] - }, - "@vue/compiler-ssr@3.5.16": { - "integrity": "sha512-d2V7kfxbdsjrDSGlJE7my1ZzCXViEcqN6w14DOsDrUCHEA6vbnVCpRFfrc4ryCP/lCKzX2eS1YtnLE/BuC9f/A==", + "@vue/compiler-ssr@3.5.28": { + "integrity": "sha512-JCq//9w1qmC6UGLWJX7RXzrGpKkroubey/ZFqTpvEIDJEKGgntuDMqkuWiZvzTzTA5h2qZvFBFHY7fAAa9475g==", "dependencies": [ - "@vue/compiler-dom@3.5.16", - "@vue/shared@3.5.16" + "@vue/compiler-dom", + "@vue/shared" ] }, - "@vue/devtools-api@7.7.6": { - "integrity": "sha512-b2Xx0KvXZObePpXPYHvBRRJLDQn5nhKjXh7vUhMEtWxz1AYNFOVIsh5+HLP8xDGL7sy+Q7hXeUxPHB/KgbtsPw==", + "@vue/devtools-api@7.7.9": { + "integrity": "sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g==", "dependencies": [ "@vue/devtools-kit" ] }, - "@vue/devtools-kit@7.7.6": { - "integrity": "sha512-geu7ds7tem2Y7Wz+WgbnbZ6T5eadOvozHZ23Atk/8tksHMFOFylKi1xgGlQlVn0wlkEf4hu+vd5ctj1G4kFtwA==", + "@vue/devtools-kit@7.7.9": { + "integrity": "sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA==", "dependencies": [ "@vue/devtools-shared", "birpc", @@ -454,47 +401,44 @@ "superjson" ] }, - "@vue/devtools-shared@7.7.6": { - "integrity": "sha512-yFEgJZ/WblEsojQQceuyK6FzpFDx4kqrz2ohInxNj5/DnhoX023upTv4OD6lNPLAA5LLkbwPVb10o/7b+Y4FVA==", + "@vue/devtools-shared@7.7.9": { + "integrity": "sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==", "dependencies": [ "rfdc" ] }, - "@vue/reactivity@3.5.16": { - "integrity": "sha512-FG5Q5ee/kxhIm1p2bykPpPwqiUBV3kFySsHEQha5BJvjXdZTUfmya7wP7zC39dFuZAcf/PD5S4Lni55vGLMhvA==", + "@vue/reactivity@3.5.28": { + "integrity": "sha512-gr5hEsxvn+RNyu9/9o1WtdYdwDjg5FgjUSBEkZWqgTKlo/fvwZ2+8W6AfKsc9YN2k/+iHYdS9vZYAhpi10kNaw==", "dependencies": [ - "@vue/shared@3.5.16" + "@vue/shared" ] }, - "@vue/runtime-core@3.5.16": { - "integrity": "sha512-bw5Ykq6+JFHYxrQa7Tjr+VSzw7Dj4ldR/udyBZbq73fCdJmyy5MPIFR9IX/M5Qs+TtTjuyUTCnmK3lWWwpAcFQ==", + "@vue/runtime-core@3.5.28": { + "integrity": "sha512-POVHTdbgnrBBIpnbYU4y7pOMNlPn2QVxVzkvEA2pEgvzbelQq4ZOUxbp2oiyo+BOtiYlm8Q44wShHJoBvDPAjQ==", "dependencies": [ "@vue/reactivity", - "@vue/shared@3.5.16" + "@vue/shared" ] }, - "@vue/runtime-dom@3.5.16": { - "integrity": "sha512-T1qqYJsG2xMGhImRUV9y/RseB9d0eCYZQ4CWca9ztCuiPj/XWNNN+lkNBuzVbia5z4/cgxdL28NoQCvC0Xcfww==", + "@vue/runtime-dom@3.5.28": { + "integrity": "sha512-4SXxSF8SXYMuhAIkT+eBRqOkWEfPu6nhccrzrkioA6l0boiq7sp18HCOov9qWJA5HML61kW8p/cB4MmBiG9dSA==", "dependencies": [ "@vue/reactivity", "@vue/runtime-core", - "@vue/shared@3.5.16", + "@vue/shared", "csstype" ] }, - "@vue/server-renderer@3.5.16_vue@3.5.16__typescript@5.8.3_typescript@5.8.3": { - "integrity": "sha512-BrX0qLiv/WugguGsnQUJiYOE0Fe5mZTwi6b7X/ybGB0vfrPH9z0gD/Y6WOR1sGCgX4gc25L1RYS5eYQKDMoNIg==", + "@vue/server-renderer@3.5.28_vue@3.5.28__typescript@5.9.3_typescript@5.9.3": { + "integrity": "sha512-pf+5ECKGj8fX95bNincbzJ6yp6nyzuLDhYZCeFxUNp8EBrQpPpQaLX3nNCp49+UbgbPun3CeVE+5CXVV1Xydfg==", "dependencies": [ - "@vue/compiler-ssr@3.5.16", - "@vue/shared@3.5.16", + "@vue/compiler-ssr", + "@vue/shared", "vue" ] }, - "@vue/shared@3.5.13": { - "integrity": "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==" - }, - "@vue/shared@3.5.16": { - "integrity": "sha512-c/0fWy3Jw6Z8L9FmTyYfkpM5zklnqqa9+a6dz3DvONRKW2NEbh46BP0FHuLFSWi2TnQEtp91Z6zOWNrU6QiyPg==" + "@vue/shared@3.5.28": { + "integrity": "sha512-cfWa1fCGBxrvaHRhvV3Is0MgmrbSCxYTXCSCau2I0a1Xw1N1pHAvkWCiXPRAqjvToILvguNyEwjevUqAuBQWvQ==" }, "@webassemblyjs/ast@1.14.1": { "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", @@ -603,8 +547,14 @@ "@xtuc/long@4.2.2": { "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" }, - "acorn@8.14.1": { - "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", + "acorn-import-phases@1.0.4_acorn@8.15.0": { + "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", + "dependencies": [ + "acorn" + ] + }, + "acorn@8.15.0": { + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "bin": true }, "ajv-formats@2.1.1_ajv@8.17.1": { @@ -641,8 +591,12 @@ "array-union@2.1.0": { "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" }, - "birpc@2.3.0": { - "integrity": "sha512-ijbtkn/F3Pvzb6jHypHRyve2QApOCZDR25D/VnkY2G/lBNcXCTsnsCxgY4k4PkVB7zfwzYbY3O9Lcqe3xufS5g==" + "baseline-browser-mapping@2.9.19": { + "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==", + "bin": true + }, + "birpc@2.9.0": { + "integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==" }, "braces@3.0.3": { "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", @@ -650,9 +604,10 @@ "fill-range" ] }, - "browserslist@4.24.4": { - "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", + "browserslist@4.28.1": { + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", "dependencies": [ + "baseline-browser-mapping", "caniuse-lite", "electron-to-chromium", "node-releases", @@ -663,8 +618,8 @@ "buffer-from@1.1.2": { "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, - "caniuse-lite@1.0.30001709": { - "integrity": "sha512-NgL3vUTnDrPCZ3zTahp4fsugQ4dc7EKTSzwQDPEel6DMoMnfH2jhry9n2Zm8onbSR+f/QtKHFOA+iAQu4kbtWA==" + "caniuse-lite@1.0.30001769": { + "integrity": "sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==" }, "chalk@4.1.2": { "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", @@ -688,58 +643,61 @@ "commander@2.20.3": { "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, - "copy-anything@3.0.5": { - "integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==", + "copy-anything@4.0.5": { + "integrity": "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==", "dependencies": [ "is-what" ] }, - "csstype@3.1.3": { - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + "csstype@3.2.3": { + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==" }, - "debug@4.4.0": { - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "debug@4.4.3": { + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dependencies": [ "ms" ] }, - "diff-match-patch@1.0.5": { - "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==" - }, "dir-glob@3.0.1": { "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dependencies": [ "path-type" ] }, - "electron-to-chromium@1.5.130": { - "integrity": "sha512-Ou2u7L9j2XLZbhqzyX0jWDj6gA8D3jIfVzt4rikLf3cGBa0VdReuFimBKS9tQJA4+XpeCxj1NoWlfBXzbMa9IA==" + "dompurify@3.3.1": { + "integrity": "sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==", + "optionalDependencies": [ + "@types/trusted-types" + ] + }, + "electron-to-chromium@1.5.286": { + "integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==" }, - "enhanced-resolve@5.18.1": { - "integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==", + "enhanced-resolve@5.19.0": { + "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==", "dependencies": [ "graceful-fs", "tapable" ] }, - "entities@4.5.0": { - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==" + "entities@7.0.1": { + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==" }, - "es-module-lexer@1.6.0": { - "integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==" + "es-module-lexer@2.0.0": { + "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==" }, - "esbuild-plugin-vue-iii@0.5.0_esbuild@0.25.2_typescript@5.8.3": { + "esbuild-plugin-vue-iii@0.5.0_esbuild@0.27.3_typescript@5.9.3": { "integrity": "sha512-q1G4nsttwZ0tLPwNeaiVMIcJO6PjgkeAPKmZM3NhTf/HZrFC3BvwWCoD9GLvJvPSEoNmvDIbdGRAJ3Ps8horoA==", "dependencies": [ "@typescript-eslint/typescript-estree", - "@vue/compiler-sfc@3.5.13", + "@vue/compiler-sfc", "esbuild", "querystring", "source-map" ] }, - "esbuild@0.25.2": { - "integrity": "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==", + "esbuild@0.27.3": { + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", "optionalDependencies": [ "@esbuild/aix-ppc64", "@esbuild/android-arm", @@ -762,6 +720,7 @@ "@esbuild/netbsd-x64", "@esbuild/openbsd-arm64", "@esbuild/openbsd-x64", + "@esbuild/openharmony-arm64", "@esbuild/sunos-x64", "@esbuild/win32-arm64", "@esbuild/win32-ia32", @@ -814,11 +773,11 @@ "micromatch" ] }, - "fast-uri@3.0.6": { - "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==" + "fast-uri@3.1.0": { + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==" }, - "fastq@1.19.1": { - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "fastq@1.20.1": { + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", "dependencies": [ "reusify" ] @@ -876,8 +835,8 @@ "is-number@7.0.0": { "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, - "is-what@4.1.16": { - "integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==" + "is-what@5.5.0": { + "integrity": "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==" }, "jest-worker@27.5.1": { "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", @@ -900,11 +859,11 @@ ], "bin": true }, - "loader-runner@4.3.0": { - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==" + "loader-runner@4.3.1": { + "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==" }, - "magic-string@0.30.17": { - "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "magic-string@0.30.21": { + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", "dependencies": [ "@jridgewell/sourcemap-codec" ] @@ -944,8 +903,8 @@ "neo-async@2.6.2": { "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, - "node-releases@2.0.19": { - "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==" + "node-releases@2.0.27": { + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==" }, "path-type@4.0.0": { "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" @@ -959,8 +918,8 @@ "picomatch@2.3.1": { "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" }, - "pinia@3.0.3_typescript@5.8.3_vue@3.5.16__typescript@5.8.3": { - "integrity": "sha512-ttXO/InUULUXkMHpTdp9Fj4hLpD/2AoJdmAbAeW2yu1iy1k+pkFekQXw5VpC0/5p51IOR/jDaDRfRWRnMMsGOA==", + "pinia@3.0.4_typescript@5.9.3_vue@3.5.28__typescript@5.9.3": { + "integrity": "sha512-l7pqLUFTI/+ESXn6k3nu30ZIzW5E2WZF/LaHJEpoq6ElcLD+wduZoB2kBN19du6K/4FDpPMazY2wJr+IndBtQw==", "dependencies": [ "@vue/devtools-api", "typescript", @@ -970,8 +929,8 @@ "typescript" ] }, - "postcss@8.5.3": { - "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", + "postcss@8.5.6": { + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", "dependencies": [ "nanoid", "picocolors", @@ -1009,8 +968,8 @@ "safe-buffer@5.2.1": { "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, - "schema-utils@4.3.0_ajv@8.17.1": { - "integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==", + "schema-utils@4.3.3_ajv@8.17.1": { + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", "dependencies": [ "@types/json-schema", "ajv", @@ -1018,8 +977,8 @@ "ajv-keywords" ] }, - "semver@7.7.1": { - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "semver@7.7.4": { + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "bin": true }, "serialize-javascript@6.0.2": { @@ -1047,8 +1006,8 @@ "speakingurl@14.0.1": { "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==" }, - "superjson@2.2.2": { - "integrity": "sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==", + "superjson@2.2.6": { + "integrity": "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==", "dependencies": [ "copy-anything" ] @@ -1065,11 +1024,11 @@ "has-flag" ] }, - "tapable@2.2.1": { - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==" + "tapable@2.3.0": { + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==" }, - "terser-webpack-plugin@5.3.14_webpack@5.99.1": { - "integrity": "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==", + "terser-webpack-plugin@5.3.16_webpack@5.105.0__acorn@8.15.0": { + "integrity": "sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==", "dependencies": [ "@jridgewell/trace-mapping", "jest-worker", @@ -1079,8 +1038,8 @@ "webpack" ] }, - "terser@5.39.0": { - "integrity": "sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==", + "terser@5.46.0": { + "integrity": "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==", "dependencies": [ "@jridgewell/source-map", "acorn", @@ -1098,22 +1057,22 @@ "tslib@1.14.1": { "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, - "tsutils@3.21.0_typescript@5.8.3": { + "tsutils@3.21.0_typescript@5.9.3": { "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", "dependencies": [ "tslib", "typescript" ] }, - "typescript@5.8.3": { - "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "typescript@5.9.3": { + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "bin": true }, - "undici-types@6.20.0": { - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==" + "undici-types@7.16.0": { + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==" }, - "update-browserslist-db@1.1.3_browserslist@4.24.4": { - "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "update-browserslist-db@1.2.3_browserslist@4.28.1": { + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "dependencies": [ "browserslist", "escalade", @@ -1121,7 +1080,7 @@ ], "bin": true }, - "vue-loader@17.4.2_webpack@5.99.1": { + "vue-loader@17.4.2_webpack@5.105.0__acorn@8.15.0": { "integrity": "sha512-yTKOA4R/VN4jqjw4y5HrynFL8AK0Z3/Jt7eOJXEitsm0GMRHDBjCfCiuTiLP7OESvsZYo2pATCWhDqxC5ZrM6w==", "dependencies": [ "chalk", @@ -1130,39 +1089,41 @@ "webpack" ] }, - "vue@3.5.16_typescript@5.8.3": { - "integrity": "sha512-rjOV2ecxMd5SiAmof2xzh2WxntRcigkX/He4YFJ6WdRvVUrbt6DxC1Iujh10XLl8xCDRDtGKMeO3D+pRQ1PP9w==", + "vue@3.5.28_typescript@5.9.3": { + "integrity": "sha512-BRdrNfeoccSoIZeIhyPBfvWSLFP4q8J3u8Ju8Ug5vu3LdD+yTM13Sg4sKtljxozbnuMu1NB1X5HBHRYUzFocKg==", "dependencies": [ - "@vue/compiler-dom@3.5.16", - "@vue/compiler-sfc@3.5.16", + "@vue/compiler-dom", + "@vue/compiler-sfc", "@vue/runtime-dom", "@vue/server-renderer", - "@vue/shared@3.5.16", + "@vue/shared", "typescript" ], "optionalPeers": [ "typescript" ] }, - "watchpack@2.4.2": { - "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "watchpack@2.5.1": { + "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", "dependencies": [ "glob-to-regexp", "graceful-fs" ] }, - "webpack-sources@3.2.3": { - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==" + "webpack-sources@3.3.3": { + "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==" }, - "webpack@5.99.1": { - "integrity": "sha512-o9gY7ibHPFxLjF6NtvQ6+5CGknsPTRllsL6SEnqR2Zhjk02hiIioJYLS7dvrWaykrRbbmhvDeKp36mKHNbKYiw==", + "webpack@5.105.0_acorn@8.15.0": { + "integrity": "sha512-gX/dMkRQc7QOMzgTe6KsYFM7DxeIONQSui1s0n/0xht36HvrgbxtM1xBlgx596NbpHuQU8P7QpKwrZYwUX48nw==", "dependencies": [ "@types/eslint-scope", "@types/estree", + "@types/json-schema", "@webassemblyjs/ast", "@webassemblyjs/wasm-edit", "@webassemblyjs/wasm-parser", "acorn", + "acorn-import-phases", "browserslist", "chrome-trace-event", "enhanced-resolve", @@ -1184,32 +1145,26 @@ "bin": true } }, - "remote": { - "https://deno.land/x/denoflate@1.2.1/mod.ts": "f5628e44b80b3d80ed525afa2ba0f12408e3849db817d47a883b801f9ce69dd6", - "https://deno.land/x/denoflate@1.2.1/pkg/denoflate.js": "b9f9ad9457d3f12f28b1fb35c555f57443427f74decb403113d67364e4f2caf4", - "https://deno.land/x/denoflate@1.2.1/pkg/denoflate_bg.wasm.js": "d581956245407a2115a3d7e8d85a9641c032940a8e810acbd59ca86afd34d44d", - "https://deno.land/x/esbuild@v0.25.2/mod.js": "fde73e72559dc2932556506581bc61462cff72d0394382334500d956851cd9f5" - }, "workspace": { "dependencies": [ - "jsr:@std/expect@1.0.15", - "jsr:@std/testing@1.0.11", + "jsr:@std/expect@1.0.17", + "jsr:@std/testing@1.0.17", "npm:@types/chrome@*", "npm:@types/firefox-webext-browser@*", - "npm:esbuild-plugin-vue-iii@0.5.0" + "npm:esbuild-plugin-vue-iii@0.5.0", + "npm:esbuild@0.27.3" ], "packageJson": { "dependencies": [ - "npm:@noble/hashes@1.8.0", - "npm:@types/chrome@0.0.326", - "npm:@types/diff-match-patch@1.0.36", - "npm:@types/firefox-webext-browser@120.0.4", - "npm:diff-match-patch@1.0.5", + "npm:@noble/hashes@2.0.1", + "npm:@types/chrome@0.1.36", + "npm:@types/firefox-webext-browser@143.0.0", + "npm:dompurify@3.3.1", "npm:jsondiffpatch@0.7.3", - "npm:pinia@3.0.3", - "npm:typescript@5.8.3", + "npm:pinia@3.0.4", + "npm:typescript@5.9.3", "npm:vue-loader@17.4.2", - "npm:vue@3.5.16" + "npm:vue@3.5.28" ] } } diff --git a/manifest.chrome.json b/manifest.chrome.json index b62f911..7772985 100644 --- a/manifest.chrome.json +++ b/manifest.chrome.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "console.diff(...)", - "version": "3.1.1", + "version": "3.2.0", "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlCx2Bl0li+3idvfrH9cQL/MzphafGFqMUA2P+0vbyhwxsxWl0llOaGQbkirX5qCoAVHoUCPqu3hCjpVCv35igPbfqDs5bdLZZmXt2F0HjEQnWI/eZKd9IKcKYMplEeL2BodmpU02VrP1UnUzQHZeeMWk9ybgWOqCimkwliILVubRj5dxNB9AidLwO4Z5iGq/OvW9AJMYdxKxrLP2lF6/GGNcCBg+iCJZwlQOhFB9LbUjytT4ws3bIEX4b5zmWLqGKR1NiZfGug2eCWXt9oEKg2WkbXmBBzFKqxnM/bBUrVR29N9qNgx0f42qnyhsW3Bo4kPzE3d0asXCV5nofLTLEwIDAQAB", "description": "Compare objects in memory with console.diff(old, new) devtools function", "minimum_chrome_version": "135.0", diff --git a/manifest.firefox.json b/manifest.firefox.json index 5da5be0..6e2ea18 100644 --- a/manifest.firefox.json +++ b/manifest.firefox.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "jsdiff.diff(...)", - "version": "3.1.0", + "version": "3.2.0", "description": "Compare objects in memory with jsdiff.diff(old, new) devtools function", "browser_specific_settings": { "gecko": { diff --git a/package.json b/package.json index da2f4bc..72af190 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,14 @@ { "type": "module", "devDependencies": { - "@noble/hashes": "1.8.0", - "@types/chrome": "0.0.326", - "@types/diff-match-patch": "1.0.36", - "@types/firefox-webext-browser": "120.0.4", - "diff-match-patch": "1.0.5", + "@noble/hashes": "2.0.1", + "@types/chrome": "0.1.36", + "@types/firefox-webext-browser": "143.0.0", + "dompurify": "3.3.1", "jsondiffpatch": "0.7.3", - "pinia": "3.0.3", - "typescript": "5.8.3", - "vue": "3.5.16", + "pinia": "3.0.4", + "typescript": "5.9.3", + "vue": "3.5.28", "vue-loader": "17.4.2" } } diff --git a/src/@types/index.d.ts b/src/@types/index.d.ts index 7826de3..2e23de7 100644 --- a/src/@types/index.d.ts +++ b/src/@types/index.d.ts @@ -1,3 +1,5 @@ +import { type TConsoleAPI } from '../jsdiff-console.ts'; + export {}; declare global { @@ -5,9 +7,8 @@ declare global { const __app_version__: string; const __app_homepage__: string; - interface Window { - wrappedJSObject: { jsdiff: () => void }; - } + // firefox + var wrappedJSObject: { jsdiff: TConsoleAPI }; // firefox extension context // currently not present in '@types/firefox-webext-browser' diff --git a/src/api/clone.ts b/src/api/clone.ts index ffa874c..8eca7e1 100644 --- a/src/api/clone.ts +++ b/src/api/clone.ts @@ -22,7 +22,7 @@ import { UniqueLookupCatalog, } from './cloneCatalog.ts'; -interface ISerializeToObject { +export interface ISerializableObject { [key: string | symbol]: unknown; } interface IFunction { @@ -110,7 +110,7 @@ function serializeMap( record.seen = true; - const obj: ISerializeToObject = {}; + const obj: ISerializableObject = Object.create(null); for (const [k, v] of value) { const newKey = serializeMapKey(commonCatalog, k); @@ -161,7 +161,10 @@ function serializeMapKey( return rv; } -function serializeObject(commonCatalog: CommonLookupCatalog, value: object) { +function serializeObject( + commonCatalog: CommonLookupCatalog, + value: ISerializableObject, +) { const record = commonCatalog.lookup(value, TAG_RECURRING_OBJECT); if (record.seen) { return record.name; @@ -174,7 +177,7 @@ function serializeObject(commonCatalog: CommonLookupCatalog, value: object) { return recursiveClone(commonCatalog, toJsonValue); } - const rv: ISerializeToObject = {}; + const rv: ISerializableObject = Object.create(null); for (const key of Reflect.ownKeys(value)) { const { newKey, newValue } = serializeObjectKey(commonCatalog, key, value); rv[newKey] = newValue; @@ -186,7 +189,7 @@ function serializeObject(commonCatalog: CommonLookupCatalog, value: object) { function serializeObjectKey( commonCatalog: CommonLookupCatalog, key: string | symbol, - value: ISerializeToObject, + value: ISerializableObject, ) { let newKey: string, newValue: unknown; @@ -242,7 +245,7 @@ function isNumericSpecials(value: unknown): value is bigint | number { ); } -function isArray(that: unknown): that is unknown[] { +export function isArray(that: unknown): that is unknown[] { return ( // NOTE: firefox content script has instances to compare with // in `window` (not in `globalThis`) @@ -301,13 +304,12 @@ function isSymbol(that: unknown): that is symbol { return typeof that === 'symbol'; } -function isGlobalSymbol(that: symbol): that is symbol { +function isGlobalSymbol(that: symbol): boolean { return Symbol.keyFor(that) !== undefined; } -function isObject(that: unknown): that is object { - return (that !== null && typeof that === 'object') || - that instanceof window.Object; +function isObject(that: unknown): that is ISerializableObject { + return (that !== null && typeof that === 'object'); } function isRegExp(that: unknown): that is RegExp { @@ -317,3 +319,33 @@ function isRegExp(that: unknown): that is RegExp { function isURL(that: unknown): that is URL { return that instanceof URL; } + +/** + * @note: use when reoccurrence is not expected + * @param unk - expects object | array | primitives, nothing else exotic + */ +export function stripDeepObjectPrototype(unk: T): T { + if (Object.prototype.toString.call(unk) === '[object Array]') { + const rv = []; + + // @ts-expect-error in 2026, typescript doesn't know yet + for (const value of unk) { + rv.push(stripDeepObjectPrototype(value)); // recursion + } + + return rv; + } + + if (Object.prototype.toString.call(unk) === '[object Object]') { + const rv = Object.create(null); + const obj = unk; + + for (const key of Reflect.ownKeys(obj)) { + rv[key] = stripDeepObjectPrototype(obj[key]); // recursion + } + + return rv; + } + + return unk; +} diff --git a/src/api/cloneCatalog.ts b/src/api/cloneCatalog.ts index 1ad45fd..1730b32 100644 --- a/src/api/cloneCatalog.ts +++ b/src/api/cloneCatalog.ts @@ -1,4 +1,3 @@ -type TUniqueInstanceTag = (id: string, value: unknown) => string; export type TCommonInstanceTag = (id: string) => string; type ICatalogUniqueRecord = string; @@ -11,7 +10,10 @@ export class UniqueLookupCatalog { #records: WeakMap = new WeakMap(); #index = 0; - lookup(key: WeakKey, tag: TUniqueInstanceTag) { + lookup< + TMapKey extends WeakKey, + TTagFn extends (id: string, value: TMapKey) => string, + >(key: TMapKey, tag: TTagFn): string { let record = this.#records.get(key); if (record) { return record; diff --git a/src/api/const.ts b/src/api/const.ts index 6fe3348..b79f373 100644 --- a/src/api/const.ts +++ b/src/api/const.ts @@ -13,8 +13,8 @@ export const TAG_RECURRING_SET = (id: string) => `[${id}] Set⟪♻️⟫`; export const TAG_RECURRING_MAP = (id: string) => `[${id}] Map⟪♻️⟫`; export const TAG_DOM_ELEMENT = (id: string, value: Document | Element) => `{${id}} DOM⟪${value.nodeName}⟫`; -export const TAG_UNIQUE_SYMBOL = (id: string, smbl: symbol) => - `{${id}} ${smbl.toString()}`; +export const TAG_UNIQUE_SYMBOL = (id: string, value: symbol) => + `{${id}} ${value.toString()}`; export const TAG_GLOBAL_SYMBOL = (smbl: symbol) => `${smbl.toString()}`; export const TAG_NATIVE_FUNCTION = (name: string) => `ƒ${name ? ` ${name}` : ''}⟪native⟫`; diff --git a/src/api/deltaHtml/HtmlFormatter.ts b/src/api/deltaHtml/HtmlFormatter.ts deleted file mode 100644 index 987f941..0000000 --- a/src/api/deltaHtml/HtmlFormatter.ts +++ /dev/null @@ -1,166 +0,0 @@ -import { escapeHTML } from '../toolkit.ts'; -import BaseFormatter from 'jsondiffpatch/formatters/base'; -import type { - BaseFormatterContext, - DeltaType, - NodeType, -} from 'jsondiffpatch/formatters/base'; -import type { - AddedDelta, - ArrayDelta, - DeletedDelta, - ModifiedDelta, - MovedDelta, - ObjectDelta, - TextDiffDelta, -} from 'jsondiffpatch'; -export type { Delta } from 'jsondiffpatch'; - -export class HtmlFormatter extends BaseFormatter { - override typeFormattterErrorFormatter( - context: BaseFormatterContext, - err: unknown, - ) { - context.out( - `
${escapeHTML(String(err))}
`, - ); - } - - formatValue(context: BaseFormatterContext, value: unknown) { - context.out(`
${escapeHTML(JSON.stringify(value, null, 2))}
`); - } - - formatTextDiffString(context: BaseFormatterContext, value: string) { - const lines = this.parseTextDiff(value); - context.out('
    '); - for (let i = 0, l = lines.length; i < l; i++) { - const line = lines[i]; - context.out( - '
  • ' + - `${line.location.line}${line.location.chr}
    `, - ); - const pieces = line.pieces; - for (let i = 0, I = pieces.length; i < I; i++) { - const piece = pieces[i]; - context.out( - `${ - escapeHTML( - decodeURI(piece.text), - ) - }`, - ); - } - context.out('
  • '); - } - context.out('
'); - } - - rootBegin( - context: BaseFormatterContext, - type: DeltaType, - nodeType: NodeType, - ) { - const nodeClass = `jsondiffpatch-${type}${ - nodeType ? ` jsondiffpatch-child-node-type-${nodeType}` : '' - }`; - context.out(`
`); - } - - rootEnd(context: BaseFormatterContext) { - context.out('
'); - } - - nodeBegin( - context: BaseFormatterContext, - _key: string, - leftKey: string | number, - type: DeltaType, - nodeType: NodeType, - ) { - const nodeClass = `jsondiffpatch-${type}${ - nodeType ? ` jsondiffpatch-child-node-type-${nodeType}` : '' - }`; - context.out( - `
  • ${ - typeof leftKey === 'string' ? escapeHTML(leftKey) : leftKey - }
    `, - ); - } - - nodeEnd(context: BaseFormatterContext) { - context.out('
  • '); - } - - format_unchanged( - context: BaseFormatterContext, - _delta: undefined, - left: unknown, - ) { - if (typeof left === 'undefined') { - return; - } - context.out('
    '); - this.formatValue(context, left); - context.out('
    '); - } - - format_movedestination( - context: BaseFormatterContext, - _delta: undefined, - left: unknown, - ) { - if (typeof left === 'undefined') { - return; - } - context.out('
    '); - this.formatValue(context, left); - context.out('
    '); - } - - format_node( - context: BaseFormatterContext, - delta: ObjectDelta | ArrayDelta, - left: unknown, - ) { - // recurse - const nodeType = delta._t === 'a' ? 'array' : 'object'; - context.out( - `
      `, - ); - this.formatDeltaChildren(context, delta, left); - context.out('
    '); - } - - format_added(context: BaseFormatterContext, delta: AddedDelta) { - context.out('
    '); - this.formatValue(context, delta[0]); - context.out('
    '); - } - - format_modified(context: BaseFormatterContext, delta: ModifiedDelta) { - context.out('
    '); - this.formatValue(context, delta[0]); - context.out('
    '); - context.out('
    '); - this.formatValue(context, delta[1]); - context.out('
    '); - } - - format_deleted(context: BaseFormatterContext, delta: DeletedDelta) { - context.out('
    '); - this.formatValue(context, delta[0]); - context.out('
    '); - } - - format_moved(context: BaseFormatterContext, delta: MovedDelta) { - context.out('
    '); - this.formatValue(context, delta[0]); - context.out('
    '); - } - - format_textdiff(context: BaseFormatterContext, delta: TextDiffDelta) { - context.out('
    '); - this.formatTextDiffString(context, delta[0]); - context.out('
    '); - } -} diff --git a/src/api/deltaHtml/api.ts b/src/api/deltaHtml/api.ts deleted file mode 100644 index ffb9e81..0000000 --- a/src/api/deltaHtml/api.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { type Delta, HtmlFormatter } from './HtmlFormatter.ts'; - -let htmlFormatter: HtmlFormatter; - -export function buildDeltaElement( - delta: Delta, - left: unknown, - hide: boolean, -): Element | null { - if (!htmlFormatter) { - htmlFormatter = new HtmlFormatter(); - } - - const html = htmlFormatter.format(delta, left); - if (!html) { - return null; - } - - const tmpEl = document.createElement('div'); - tmpEl.innerHTML = html; - const rv = tmpEl.firstElementChild; - hideUnchanged(hide, rv); - - return rv!; -} - -const unchangedHiddenClass = 'jsondiffpatch-unchanged-hidden'; -export function hideUnchanged(hide: boolean, el: Element | null) { - if (!el) { - return; - } - - if (hide) { - el.classList.add(unchangedHiddenClass); - } else { - el.classList.remove(unchangedHiddenClass); - } -} diff --git a/src/api/diffApi.ts b/src/api/diffApi.ts index 6263fb7..b7edbb1 100644 --- a/src/api/diffApi.ts +++ b/src/api/diffApi.ts @@ -1,19 +1,25 @@ import { hasValue } from './toolkit.ts'; -import DiffMatchPatch from 'diff-match-patch'; -import { create } from 'jsondiffpatch'; +import { type ISerializableObject } from './clone.ts'; +import { create, type Delta } from 'jsondiffpatch/with-text-diffs'; +import { format as formatHtml } from 'jsondiffpatch/formatters/html'; +import { format as formatRFC6902 } from 'jsondiffpatch/formatters/jsonpatch'; +import DOMPurify from 'dompurify'; export type { Delta } from 'jsondiffpatch'; +const OBJECT_ID_IN_ARRAY = ['id', '_id', 'uuid', 'guid', 'ulid']; + const patcher = create({ // used to match objects when diffing arrays, by default only === operator is used - objectHash(obj, index) { - // this function is used only to when objects are not equal by ref - const rv = hasValue(obj) - ? 'id' in obj && hasValue(obj.id) - ? obj.id - : '_id' in obj && hasValue(obj._id) - ? obj._id - : index - : index; + objectHash(item: object, index?: number) { + const obj = item; + let rv: unknown = index; + + for (const prop of OBJECT_ID_IN_ARRAY) { + if (hasValue(obj[prop])) { + rv = obj[prop]; + break; + } + } return hasValue(rv) ? String(rv) : undefined; }, @@ -21,17 +27,60 @@ const patcher = create({ arrays: { // default true, detect items moved inside the array (otherwise they will be registered as remove+add) detectMove: false, - // default false, the value of items moved is not included in deltas - includeValueOnMove: true, }, textDiff: { - diffMatchPatch: DiffMatchPatch, - // default 60, minimum string length (left and right sides) to use text diff algorythm: google-diff-match-patch - minLength: 120, + minLength: 120, // default 60 }, }); export function diff(left: unknown, right: unknown) { return patcher.diff(left, right); } + +export function formatDeltaAsRFC6902(delta: Delta) { + try { + return formatRFC6902(delta); + } catch (e) { + return String(e); + } +} + +export function buildDeltaElement( + delta: Delta, + left: unknown, + hide: boolean, +): Element | null { + let html: string | undefined; + + try { + html = formatHtml(delta, left); + html = DOMPurify.sanitize(html || ''); + } catch (e) { + console.error('buildDeltaElement', e); + } + + if (!html) { + return null; + } + + const virtualEl = document.createElement('div'); + virtualEl.innerHTML = html; + const rv = virtualEl.firstElementChild; + hideUnchanged(hide, rv); + + return rv; +} + +const unchangedHiddenClass = 'jsondiffpatch-unchanged-hidden'; +export function hideUnchanged(hide: boolean, el: Element | null) { + if (!el) { + return; + } + + if (hide) { + el.classList.add(unchangedHiddenClass); + } else { + el.classList.remove(unchangedHiddenClass); + } +} diff --git a/src/api/onColourSchemeChange.ts b/src/api/onColourSchemeChange.ts deleted file mode 100644 index 6091487..0000000 --- a/src/api/onColourSchemeChange.ts +++ /dev/null @@ -1,21 +0,0 @@ -export type TColourScheme = 'light' | 'dark'; - -/** - * NOTE: if OS is dark but devtools is default - then scheme is dark - */ -export function onColourSchemeChange( - callback: (scheme: TColourScheme) => void, -) { - const devtoolsScheme = chrome.devtools.panels.themeName; - const osDarkScheme = globalThis.matchMedia('(prefers-color-scheme: dark)'); - - if (devtoolsScheme === 'dark' || osDarkScheme.matches) { - callback('dark'); - } else { - callback('light'); - } - - osDarkScheme.addEventListener('change', (e: MediaQueryListEvent) => { - callback(e.matches ? 'dark' : 'light'); - }); -} diff --git a/src/api/proxy.ts b/src/api/proxy.ts index f64872c..722173e 100644 --- a/src/api/proxy.ts +++ b/src/api/proxy.ts @@ -67,16 +67,16 @@ export async function proxyCompareHandler( } as ICompareMessage, handleResponse, ); - } catch (error: unknown) { - if (error?.message === ERROR_QUOTA_EXCEEDED) { + } catch (error) { + if (error instanceof Error && error.message === ERROR_QUOTA_EXCEEDED) { await chrome.storage.local.set({ lastError: ERROR_QUOTA_EXCEEDED }); chrome.runtime.sendMessage( { source: 'jsdiff-proxy-to-panel-error' } as IErrorMessage, handleResponse, ); - } else if (error?.message) { - console.error('Unhandled', error.message); + } else { + console.error('Unhandled', error); } } } diff --git a/src/api/toolkit.ts b/src/api/toolkit.ts index 242a8b0..f870756 100644 --- a/src/api/toolkit.ts +++ b/src/api/toolkit.ts @@ -1,12 +1,12 @@ -import { sha256 } from '@noble/hashes/sha2'; -import { bytesToHex } from '@noble/hashes/utils'; +import { sha256 } from '@noble/hashes/sha2.js'; +import { bytesToHex, utf8ToBytes } from '@noble/hashes/utils.js'; export function hasValue(o: unknown): boolean { return undefined !== o && null !== o; } export function hashString(str: string) { - return bytesToHex(sha256(str)); + return bytesToHex(sha256(utf8ToBytes(str))); } export function isSearchKeyboardEvent(e: KeyboardEvent) { diff --git a/src/api/useRuntime.ts b/src/api/useRuntime.ts index d17f3f4..2719f58 100644 --- a/src/api/useRuntime.ts +++ b/src/api/useRuntime.ts @@ -14,14 +14,18 @@ import { BACKGROUND_SCRIPT_CONNECTION_INTERVAL, BACKGROUND_SCRIPT_CONNECTION_NAME, } from './const.ts'; +import type { TRuntimeMessageOptions } from './proxy.ts'; -type TRuntimeListener = (...args: unknown[]) => void; +type TRuntimeListener = (e: TRuntimeMessageOptions) => void; +type TRuntimeListenerAsync = (e: TRuntimeMessageOptions) => Promise; -const allListeners = new Set(); +const allListeners = new Set(); -function callAllListeners(...args: unknown[]) { +function callAllListeners(e: TRuntimeMessageOptions) { for (const listener of allListeners) { - listener(...args); + Promise.try(listener, e).catch((err) => + void console.error('RuntimeListener', err) + ); } } @@ -30,6 +34,8 @@ function getFirefoxPort(callback: TRuntimeListener) { name: BACKGROUND_SCRIPT_CONNECTION_NAME, }); + // @ts-expect-error: expects callback with argument of type `object` + // and not `any` as in chrome api port.onMessage.addListener(callback); return port; @@ -37,10 +43,10 @@ function getFirefoxPort(callback: TRuntimeListener) { if (typeof browser !== 'undefined') { // firefox - // deno-lint-ignore no-unused-vars let port = getFirefoxPort(callAllListeners); setInterval(() => { + port.disconnect(); port = getFirefoxPort(callAllListeners); }, BACKGROUND_SCRIPT_CONNECTION_INTERVAL); } else { @@ -49,10 +55,10 @@ if (typeof browser !== 'undefined') { } export function useRuntime() { - const localListeners = new Set(); + const localListeners = new Set(); return { - connect(listener: TRuntimeListener) { + connect(listener: TRuntimeListenerAsync) { localListeners.add(listener); allListeners.add(listener); }, diff --git a/src/jsdiff-console.ts b/src/jsdiff-console.ts index 899bf3c..c3492d4 100644 --- a/src/jsdiff-console.ts +++ b/src/jsdiff-console.ts @@ -22,16 +22,19 @@ const consoleAPI = { }, }; +export type TConsoleAPI = typeof consoleAPI; + if (typeof browser === 'undefined') { // chrome Object.assign(console, consoleAPI); console.debug(`✚ console.diff()`); } else if (typeof cloneInto === 'function') { // firefox - // the technic described in: - // @link: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Sharing_objects_with_page_scripts - globalThis.wrappedJSObject.jsdiff = cloneInto(consoleAPI, window, { - cloneFunctions: true, - }); + // the technic described in https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Sharing_objects_with_page_scripts + globalThis.wrappedJSObject.jsdiff = cloneInto( + consoleAPI, + window, + { cloneFunctions: true }, + ); console.debug(`✚ jsdiff.diff()`); } diff --git a/src/stores/compare.store.ts b/src/stores/compare.store.ts index 17d44ec..9fcfb1e 100644 --- a/src/stores/compare.store.ts +++ b/src/stores/compare.store.ts @@ -1,10 +1,11 @@ import { type Delta, diff } from '../api/diffApi.ts'; import { hasValue } from '../api/toolkit.ts'; +import { stripDeepObjectPrototype } from '../api/clone.ts'; +import type { TRuntimeMessageOptions } from '../api/proxy.ts'; import { defineStore } from 'pinia'; import { markRaw } from 'vue'; import { useRuntime } from '../api/useRuntime.ts'; import { useSearchStore } from './search.store.ts'; -import type { TRuntimeMessageOptions } from '../api/proxy.ts'; interface ICompareState { timestamp: number; @@ -20,6 +21,14 @@ function defaultCompareState(): ICompareState { }; } +function castrateObject(that: T): T { + if (that !== null && typeof that === 'object') { + return markRaw(Object.freeze(stripDeepObjectPrototype(that))); + } + + return that; +} + export const useCompareStore = defineStore('compareStore', { state: () => ({ initialized: false, @@ -37,17 +46,15 @@ export const useCompareStore = defineStore('compareStore', { }, deltaObj(): Delta { - return diff(this.compare.left, this.compare.right); + return castrateObject(diff(this.compare.left, this.compare.right)); }, }, actions: { assign({ left, right, timestamp }: ICompareState) { this.compare = { - left: left !== null && typeof left === 'object' ? markRaw(left) : left, - right: right !== null && typeof right === 'object' - ? markRaw(right) - : right, + left: castrateObject(left), + right: castrateObject(right), timestamp: timestamp || Date.now(), }; }, @@ -80,14 +87,14 @@ export const compareStoreRuntimeService = { if (hasValue(lastApiReq)) { compareStore.assign(lastApiReq as ICompareState); } - compareStore.lastError = lastError || ''; + compareStore.lastError = lastError ? String(lastError) : ''; compareStore.initialized = true; }); runtime.connect(async (e: TRuntimeMessageOptions) => { if ('jsdiff-proxy-to-panel-error' === e.source) { const { lastError } = await chrome.storage.local.get(['lastError']); - compareStore.lastError = lastError || ''; + compareStore.lastError = lastError ? String(lastError) : ''; compareStore.inprogress = false; } else if ('jsdiff-proxy-to-panel-inprogress' === e.source) { compareStore.inprogress = e.on; diff --git a/src/view/panel.header.vue b/src/view/panel.header.vue index e6d3398..347e2bb 100644 --- a/src/view/panel.header.vue +++ b/src/view/panel.header.vue @@ -73,7 +73,7 @@ const onClearResults = () => { flex-shrink: 0; width: 100%; background-color: var(--header-background); - border-bottom: var(--header-border); + border-bottom: 1px solid var(--header-border); display: flex; align-items: center; height: var(--header-height); diff --git a/src/view/panel.search.vue b/src/view/panel.search.vue index 7ca7ba8..ecf53a3 100644 --- a/src/view/panel.search.vue +++ b/src/view/panel.search.vue @@ -121,7 +121,7 @@ const onNextSearch = () => { display: flex; align-items: center; margin-left: 10px; - color: rgb(var(--colour-found-this-background)); + color: var(--colour-found-this-background); font-size: 12px; font-weight: bold; diff --git a/src/view/panel.vue b/src/view/panel.vue index 8865768..dc1d0b3 100644 --- a/src/view/panel.vue +++ b/src/view/panel.vue @@ -1,5 +1,5 @@