diff --git a/.gitignore b/.gitignore index 2309cc8..f838fba 100644 --- a/.gitignore +++ b/.gitignore @@ -1,138 +1,5 @@ -# ---> Node -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* -.pnpm-debug.log* - -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage -*.lcov - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories node_modules/ -jspm_packages/ - -# Snowpack dependency directory (https://snowpack.dev/) -web_modules/ - -# TypeScript cache -*.tsbuildinfo - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional stylelint cache -.stylelintcache - -# Microbundle cache -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variable files -.env -.env.development.local -.env.test.local -.env.production.local -.env.local - -# parcel-bundler cache (https://parceljs.org/) -.cache -.parcel-cache - -# Next.js build output -.next -out - -# Nuxt.js build / generate output -.nuxt -dist - -# Gatsby files -.cache/ -# Comment in the public line in if your project uses Gatsby and not Next.js -# https://nextjs.org/blog/next-9-1#public-directory-support -# public - -# vuepress build output -.vuepress/dist - -# vuepress v2.x temp and cache directory -.temp -.cache - -# vitepress build output -**/.vitepress/dist - -# vitepress cache directory -**/.vitepress/cache - -# Docusaurus cache and generated files -.docusaurus - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# TernJS port file -.tern-port - -# Stores VSCode versions used for testing VSCode extensions -.vscode-test - -# yarn v2 -.yarn/cache -.yarn/unplugged -.yarn/build-state.yml -.yarn/install-state.gz -.pnp.* - +dist/ +artifacts/ +coverage/ +*.log diff --git a/LICENSE b/LICENSE index 072de65..b27e402 100644 --- a/LICENSE +++ b/LICENSE @@ -1,18 +1,21 @@ MIT License -Copyright (c) 2026 egmont11 +Copyright (c) 2026 SlopDetect contributors -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the -following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all copies or substantial -portions of the Software. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO -EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -USE OR OTHER DEALINGS IN THE SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 49d8587..3c0d39a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,74 @@ -# Slop-detect +# SlopDetect -Firefox rozšíření pro detekci AI generovaného obsahu. \ No newline at end of file +SlopDetect is a privacy-first Firefox extension that inspects webpages for machine-readable AI provenance and separately flags clusters of common generated-site patterns. + +It currently provides: + +- Automatic scanning of ordinary HTTP and HTTPS pages after load +- An in-page result card for flagged pages that collapses into a persistent score chip +- Local C2PA/Content Credentials parsing and validation for accessible images +- Recognition of AI-related C2PA digital source types +- Separate states for valid, detected, invalid, disclosed, inaccessible, and unknown evidence +- Publisher-disclosure discovery in HTML metadata, structured data, and visible labels +- A bounded, on-device heuristic scan for common visual, typography, layout, motion, and copy patterns +- Unsigned generator-metadata clues for images whose C2PA data was removed but whose export metadata survived +- A mixed-provenance page summary and optional in-page image badges +- A stable adapter API for provider-specific image and text watermark detectors +- On-device processing with no telemetry or remote detector calls + +SlopDetect does **not** infer that unmarked content is human-made. Its page-pattern score is a suspicion signal, not proof that AI authored a website. Deliberate human designs can match the same patterns, and generated sites can avoid them. + +## Development + +Requirements: Node.js 22 or newer and Firefox 128 or newer. + +```sh +npm install +npm run check +npm test +npm run lint +npm run build +npm start +``` + +The unpacked extension is written to `dist/`. A distributable XPI-compatible ZIP is produced in `artifacts/` with: + +```sh +npm run package +``` + +## Architecture + +- `src/content/` discovers visible page text, image URLs, disclosures, and bounded rendered-style heuristics, and renders image badges. +- `src/background/` fetches bounded image resources, verifies C2PA manifests, coordinates watermark adapters, caches results, and aggregates page status. +- `src/popup/` presents the current scan and requests optional cross-origin image access. +- `src/options/` manages privacy, badge, and resource-limit settings. +- `src/shared/` contains the message, evidence, and result contracts. + +Automatic operation requires persistent access to HTTP and HTTPS pages so the content script can inspect their rendered DOM and the background process can read image bytes. It does not run on Firefox settings pages or other privileged browser documents. Private-network image requests are rejected unless the scanned page has the same origin, redirects are rejected, credentials are omitted, and asset size/concurrency are bounded. + +Automatic scans begin shortly after `document_idle`, inspect the largest visible images first, and perform at most one bounded follow-up scan when a page adds substantial dynamic content. The default automatic image limit is 10 with a 10 MB per-image automatic cap; manual toolbar scans can inspect up to 50 using the configured size cap. Pages with no reportable status receive no in-page UI and no toolbar badge. Dismissing an alert keeps it dismissed until the page URL changes. + +## Detection semantics + +- **Verified AI:** a trusted, valid credential contains an AI-generation/manipulation source type. +- **Detected AI:** a readable credential or compatible watermark indicates AI origin without a trusted signer. +- **Publisher disclosed:** the publisher explicitly labels content as AI-generated. +- **AI-style patterns suspected:** at least two deterministic clues cross the configured suspicion threshold. The page remains origin-unknown. +- **Generator metadata detected:** unsigned image bytes name a known AI image tool or contain a recognizable workflow block. This can be removed or forged. +- **Invalid credential:** provenance data exists but validation reports an integrity or trust failure. +- **No supported evidence:** no compatible evidence was found; origin remains unknown. + +Text watermark schemes are currently provider-specific. `src/background/detectors.ts` intentionally ships with an empty registry until a public detector can be integrated and tested. This avoids false claims from generic AI-writing classifiers. + +The heuristic catalog currently covers purple/cyan and radial gradients, gradient text, side-tab borders, hairline shadows, extreme radii, icon tiles, oversized and italic-serif heroes, hero eyebrows, overused fonts, nested and repeated card grids, decorative looping motion, marquees, generic SaaS vocabulary, em-dash cadence, manufactured contrast, “theater” framing, and stock product promises. It is inspired by the deterministic patterns documented in the [Impeccable slop catalog](https://impeccable.style/slop/), but implemented independently and conservatively. + +## C2PA runtime + +The build packages `@contentauth/c2pa-web`, its worker, and its WebAssembly binary locally. Snapshots of the official C2PA signing and timestamp trust lists are also bundled. Remote manifests and OCSP fetching are disabled, so inspecting an asset does not cause the C2PA SDK to contact locations named by that asset. No executable code is loaded from a CDN. The extension CSP permits WebAssembly while continuing to restrict script and worker sources to the extension itself. + +`@contentauth/c2pa-web` 0.14.4 applies an HTTPS-only check to explicit worker URLs. Firefox identifies packaged extension resources with `moz-extension:` instead, so `src/background/c2pa.ts` contains a narrow compatibility adapter: the SDK's scheme check sees its required HTTPS shape, while the browser receives and loads the original same-extension worker URL. The adapter rejects non-extension worker locations. + +## License + +Source code in this repository is available under the MIT License. Third-party packages retain their respective licenses. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..a139825 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,5 @@ +# Security policy + +Please report security issues privately to the repository owner rather than opening a public issue containing exploit details. + +SlopDetect treats webpage content, resource URLs, metadata, and provenance manifests as untrusted input. The implementation bounds asset size and concurrency, rejects unsafe URL schemes and cross-origin private-network targets, omits credentials from media requests, disallows redirects, validates extension messages, and renders page annotations through an isolated Shadow DOM without injecting untrusted HTML. diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md new file mode 100644 index 0000000..50ea329 --- /dev/null +++ b/THIRD_PARTY_NOTICES.md @@ -0,0 +1,7 @@ +# Third-party notices + +SlopDetect uses `@contentauth/c2pa-web` and related Content Authenticity Initiative packages under their published licenses. See the package metadata and the [c2pa-js repository](https://github.com/contentauth/c2pa-js) for the applicable terms. + +The bundled `C2PA-TRUST-LIST.pem` and `C2PA-TSA-TRUST-LIST.pem` files are snapshots from the [C2PA Conformance Program public repository](https://github.com/c2pa-org/conformance-public), published under CC BY 4.0. The Coalition for Content Provenance and Authenticity maintains those lists; inclusion does not imply endorsement of SlopDetect. + +Other runtime and development dependencies are listed in `package.json` and retain their respective licenses. diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..d4e96da --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,33 @@ +import js from '@eslint/js'; +import tseslint from 'typescript-eslint'; + +export default tseslint.config( + { ignores: ['dist/**', 'artifacts/**', 'node_modules/**'] }, + js.configs.recommended, + ...tseslint.configs.recommended, + { + files: ['scripts/**/*.mjs'], + languageOptions: { + globals: { URL: 'readonly' } + } + }, + { + files: ['src/**/*.{ts,tsx}', 'tests/**/*.ts'], + languageOptions: { + globals: { + Blob: 'readonly', + browser: 'readonly', + crypto: 'readonly', + document: 'readonly', + fetch: 'readonly', + globalThis: 'readonly', + HTMLElement: 'readonly', + HTMLImageElement: 'readonly', + MutationObserver: 'readonly', + Node: 'readonly', + URL: 'readonly', + window: 'readonly' + } + } + } +); diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..0666e7d --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6440 @@ +{ + "name": "slopdetect", + "version": "0.3.2", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "slopdetect", + "version": "0.3.2", + "dependencies": { + "@contentauth/c2pa-web": "0.14.4", + "preact": "10.29.8", + "webextension-polyfill": "0.12.0" + }, + "devDependencies": { + "@eslint/js": "10.0.1", + "@types/firefox-webext-browser": "143.0.0", + "@types/webextension-polyfill": "0.12.6", + "esbuild": "0.28.2", + "eslint": "10.9.1", + "typescript": "6.0.3", + "typescript-eslint": "8.69.0", + "vitest": "4.1.11", + "web-ext": "10.6.0" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-8.0.0.tgz", + "integrity": "sha512-sL6cvO2IfkSu/iU+zs2S/w01B7A8V7suXSIKEN4hPFFdZoiPGxrj5pAG0lCaqLWiEIrjKzdznIWuaLcxPR53qw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@contentauth/c2pa-types": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@contentauth/c2pa-types/-/c2pa-types-0.7.4.tgz", + "integrity": "sha512-lPxm/5yvUqS2LItFMvgfCDWm8yCw9vsW32vrkCPgj4QkzGxQ9WuUkK32eWzsxBL9sCDbCQDNNtFroH6qTaU90w==" + }, + "node_modules/@contentauth/c2pa-utilities": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@contentauth/c2pa-utilities/-/c2pa-utilities-0.2.2.tgz", + "integrity": "sha512-mUHDB2QlVFRcB6jUk+puZRvfJLPjfA2aiJVqk1QrO8GakoWtNMdjbFA3cRhhuMa4W0rIFrWfi4s/lCTGtMSG4g==", + "license": "MIT", + "dependencies": { + "@contentauth/c2pa-types": "0.7.4", + "ts-deepmerge": "^8.0.0" + } + }, + "node_modules/@contentauth/c2pa-wasm": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/@contentauth/c2pa-wasm/-/c2pa-wasm-0.11.4.tgz", + "integrity": "sha512-MDrMFLCOzRC3a+XoKicionCGtnmtcFRgwbdHnuQYdfyNyG+ZlmEmd2T1MZsQQab9Lg1Bz9Mi0+g+M59soMwYYw==", + "license": "MIT" + }, + "node_modules/@contentauth/c2pa-web": { + "version": "0.14.4", + "resolved": "https://registry.npmjs.org/@contentauth/c2pa-web/-/c2pa-web-0.14.4.tgz", + "integrity": "sha512-P/kljZjuASDTJz0C90Iq3p/YYVs+NdjbBw80ZOlZvosvHi38uu8A/QN9MzYh64f53SuMCT745p3p0Ul42wlj6w==", + "license": "MIT", + "dependencies": { + "@contentauth/c2pa-types": "0.7.4", + "@contentauth/c2pa-utilities": "0.2.2", + "@contentauth/c2pa-wasm": "0.11.4", + "highgain": "^0.1.0" + } + }, + "node_modules/@devicefarmer/adbkit": { + "version": "3.3.9", + "resolved": "https://registry.npmjs.org/@devicefarmer/adbkit/-/adbkit-3.3.9.tgz", + "integrity": "sha512-AYxk5G/b2BPEfubcuxVEZEOpsLf0isqrPNJnnwAlUjZAiLdFg/uvLNRDuBhsC/Ar62X+rUhVlvlL+tKp9HCjfQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@devicefarmer/adbkit-logcat": "^2.1.2", + "@devicefarmer/adbkit-monkey": "~1.2.1", + "bluebird": "~3.7", + "commander": "^9.1.0", + "debug": "~4.3.1", + "node-forge": "^1.3.1", + "split": "~1.0.1" + }, + "bin": { + "adbkit": "bin/adbkit" + }, + "engines": { + "node": ">= 0.10.4" + } + }, + "node_modules/@devicefarmer/adbkit-logcat": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@devicefarmer/adbkit-logcat/-/adbkit-logcat-2.1.3.tgz", + "integrity": "sha512-yeaGFjNBc/6+svbDeul1tNHtNChw6h8pSHAt5D+JsedUrMTN7tla7B15WLDyekxsuS2XlZHRxpuC6m92wiwCNw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@devicefarmer/adbkit-monkey": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@devicefarmer/adbkit-monkey/-/adbkit-monkey-1.2.1.tgz", + "integrity": "sha512-ZzZY/b66W2Jd6NHbAhLyDWOEIBWC11VizGFk7Wx7M61JZRz7HR9Cq5P+65RKWUU7u6wgsE8Lmh9nE4Mz+U2eTg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.10.4" + } + }, + "node_modules/@devicefarmer/adbkit/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", + "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", + "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", + "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", + "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", + "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", + "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", + "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", + "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", + "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", + "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", + "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", + "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", + "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", + "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", + "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", + "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", + "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz", + "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", + "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz", + "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", + "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz", + "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", + "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", + "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", + "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", + "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz", + "integrity": "sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", + "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^3.0.5", + "debug": "^4.3.1", + "minimatch": "^10.2.4" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.7.0.tgz", + "integrity": "sha512-DObd/KKUsU+FaFv4PLxSRenpXfQWmPXXP3pPZ6/K1PCrMu2vQpMDMuQe/BqYeoLcz8ro0bVDF1RxOJgfVEdhUw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/core": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", + "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.7.tgz", + "integrity": "sha512-F42g89Qd5oAWtp0k0nnSrjziAKza7w8SVT4mStc18LZMaRb4J1HQAHLCalEtDCxrTuksx7NU9qsmeLwpOfPqWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.14.0", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.3.2", + "minimatch": "^3.1.5", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/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/eslintrc/node_modules/espree": { + "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.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/eslintrc/node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", + "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/@eslint/object-schema": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", + "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.2.tgz", + "integrity": "sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1", + "levn": "^0.4.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@fluent/syntax": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@fluent/syntax/-/syntax-0.19.0.tgz", + "integrity": "sha512-5D2qVpZrgpjtqU4eNOcWGp1gnUCgjfM+vKGE2y03kKN6z5EBhtx0qdRFbg8QuNNj8wXNoX93KJoYb+NqoxswmQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@fregante/relaxed-json": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@fregante/relaxed-json/-/relaxed-json-2.0.0.tgz", + "integrity": "sha512-PyUXQWB42s4jBli435TDiYuVsadwRHnMc27YaLouINktvTWsL3FcKrRMGawTayFk46X+n5bE23RjUTWQwrukWw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@mdn/browser-compat-data": { + "version": "8.0.8", + "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-8.0.8.tgz", + "integrity": "sha512-Rutrrc3FYOc+um4/QC4WFETNk2fV8NKWoqQl3tQfcVTQ1WFaoJRbsJBasSF34ltitmnYYD6ZsKW1cOQtSj1jbQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/@oxc-project/types": { + "version": "0.148.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.148.0.tgz", + "integrity": "sha512-Nm4s/jB+4FpFsPhWGEC4h7rzksesmtnMXomo6rCMcg/b8zLQuOziRgkCS1fxDCXOlJB/6Q8oABOZ/OP6RIPj9A==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/oxc-project" + } + }, + "node_modules/@pinojs/redact": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz", + "integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@pnpm/config.env-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", + "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", + "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "4.2.10" + }, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true, + "license": "ISC" + }, + "node_modules/@pnpm/npm-conf": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-3.0.3.tgz", + "integrity": "sha512-//0sR/cow/s4ICQaYoAobOl4aU8cjU6x/V24V7XkKotb9+O+3zySIYp146vpaobYHnxa4pZX8NkV54Z5AwbDKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@rolldown/binding-android-arm-eabi": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.7.tgz", + "integrity": "sha512-EypzgnYCwyVY4NDHKzGmNJT5b+XaQEBniHxsMdeIQLB/tcCzZnhqrzHpZFbX9iaxx+5RiB8caATBtfvZP7zVxQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.7.tgz", + "integrity": "sha512-l17HE9EweWaqJZhuUuNBN/FzM62xw+DECVnJyvMsxn8vJFAGLy5QfLDoYAcronkAN8VxKZHezDpulHDPx95vFw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.7.tgz", + "integrity": "sha512-8ED8ELFvHXc6OCETIn4gXObPiaR6bckM/ipXtbzlPVDRMBfEGjCKgO90F9YtfdpDatVx/ZQw7aZ1vUMf/+T3Mw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.7.tgz", + "integrity": "sha512-/WPripjtiAIZ2tWY7ddijORT0Ujg87wxWW/qcoFVCKAWVDPhtY0xr7Dj0M3GyNGz60jGwTElhro/mkF9dT7dDQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.7.tgz", + "integrity": "sha512-14DI4NcqpvbICxSnGLx3PmtDaWqRP/KGSGb6C+JLLVPeZRl6dKdHba3pGsqT3vpdTqhEYIPG0MMQ8c0xYqoJxA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.7.tgz", + "integrity": "sha512-bxrWIRvHWQvbJwi+VIie/kDJmQxcNE6xxWwZdqF/ExVAigtHkv54WTLQPb+QsZdnFy18fg7JPfWGL0RH6vwIlQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.7.tgz", + "integrity": "sha512-toOY2BChBZyuxU7OYX6Tn389di4IzAqPTycVcci0O7FSfBqzRB3RZn+K5Is6ANf4tmgRd/K1yZTsNTXbkXsnLg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.7.tgz", + "integrity": "sha512-lAIXTH/aiLRLxsTgQvfhjo4K1ydWIp00+V0voOr9beb/9ZmkUFrSIb03dXNFRgMNvkE6oGsF10ioQ6UsI+vS5Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.7.tgz", + "integrity": "sha512-kdnwS28Pkenp/mZMRwjXXXwxQ7pIsm+bF919LUK93BOyhcLsrVKdP2p9fxpiPNPAbNuch8ypQt0pm2P2LYCAGg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.7.tgz", + "integrity": "sha512-516OdsyLdr5E65paF3yBF55t8mfm9+gmtCsK3xI7XKXIT7EfRlHhxL8K/NR6Hu8BWSgF5+1w74lTL0+nxcc8Qw==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.7.tgz", + "integrity": "sha512-r8/z8n7GFaYRln3xmP1Cxy0HH/HLM0uBUPkEuSVEfKGDA89M0FsZRZJRSwe/tJjRx+fpH/gjorfhB8tmEbSFLA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.7.tgz", + "integrity": "sha512-pAsE8iiDxUg1xBqdhrTfg45AVDVpirjz00sblEYClGNNcMnDb+e8beQgqIAw6LvauX/APvgxUnwrgun/YYGBhw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.7.tgz", + "integrity": "sha512-lTcIYmmnQQA8Or/2DatS6oSqcdLHvendjS+zLu+FwgToynWMRSmQdpM65fTANJgIS4mjbMOo5KT2lnT9SAb96w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.7.tgz", + "integrity": "sha512-e3Gu3WxbNk/UqQhxqU7YIYO+9ZBvWNz3U+h/qRFosscMFzdRPbXYSaSWgSnklv2fz1TgzBTcti2z35c/7irsHw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.7.tgz", + "integrity": "sha512-W/jg5qoRSqjsEv0+dZi4e687mcHqmVuU0P4fK6qS/xjetW2Gmc1W8j//z5nAeNcC8Ttm0hV46IjcYeuVwYhuiw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/firefox-webext-browser": { + "version": "143.0.0", + "resolved": "https://registry.npmjs.org/@types/firefox-webext-browser/-/firefox-webext-browser-143.0.0.tgz", + "integrity": "sha512-865dYKMOP0CllFyHmgXV4IQgVL51OSQQCwSoihQ17EwugePKFSAZRc0EI+y7Ly4q7j5KyURlA7LgRpFieO4JOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "26.4.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.4.1.tgz", + "integrity": "sha512-k97ENvZWtvA6yqz5/FS6a7duDgOPEeOQOc2iKS/nY6mX6qJUKtLnWzQS+Xj6tXweyj6ZcTAK2Qecetnvi9nCLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~8.3.0" + } + }, + "node_modules/@types/webextension-polyfill": { + "version": "0.12.6", + "resolved": "https://registry.npmjs.org/@types/webextension-polyfill/-/webextension-polyfill-0.12.6.tgz", + "integrity": "sha512-XTNQSGiQaipt1iocbpHSjYHd+Ujcya+K5H4H2uH7JwycReTFixoYqGWIKih2Ec072NuEW2lAyXRDYmlEx00+cw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.69.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.69.0.tgz", + "integrity": "sha512-t5jQTKPIgVW1PE6dR6H6Qz5gm8zjMlX5/2gRaOGd9eO6V7J+tQc6iWKukEe7dY8u9HyYasQ0yfF0/FSSTEO2gA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.69.0", + "@typescript-eslint/type-utils": "8.69.0", + "@typescript-eslint/utils": "8.69.0", + "@typescript-eslint/visitor-keys": "8.69.0", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.69.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.8.tgz", + "integrity": "sha512-YYNsSlXBjMk92SKnkwvB5LOVSa6OznlFUGcsvrFgNJbJCd0M1XKeFVRc8ZByeCqz32FivYNHJVooLmdqrmvp/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.69.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.69.0.tgz", + "integrity": "sha512-l4b0DhWioGg6Gt2ebGlvfkFMOjRsauxtsnDRwUSRX1qHq3HdTfQHV8wW9zEXeciai6HfeaKOedQn2Zoofx3WBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.69.0", + "@typescript-eslint/types": "8.69.0", + "@typescript-eslint/typescript-estree": "8.69.0", + "@typescript-eslint/visitor-keys": "8.69.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.69.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.69.0.tgz", + "integrity": "sha512-yi4obFrHMmnsesWehHbkg9zMA7Jt8cXT+mKM08G999pH1yT6nqgsHx7MYm0uY1wAj8CqiBXYRJ7WAT0QdQHQXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.69.0", + "@typescript-eslint/types": "^8.69.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.69.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.69.0.tgz", + "integrity": "sha512-ewfspqWvSxKSOaplqAUNbaSFO0eB6w1EtQ+esfYFRm3614Ty4uNtExkcbgd6nWsXphbqKyf9ZYdbZdv2xEoWEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.69.0", + "@typescript-eslint/visitor-keys": "8.69.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.69.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.69.0.tgz", + "integrity": "sha512-xNqK7YTDZsLniQMV/4rpFR8Z5JlqeRvVjuG1YgF/mdPVH84HSD19L8CczMA0qg2RfwEV231GHH3VnToJDo4MfQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.69.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.69.0.tgz", + "integrity": "sha512-ZfoJAVg3JZndQEpEl9petVlxau3lRuElc4HRMuAlLCf8to04/iHz692RUSNmXKDjEuJmIL+KZ2/BsOcBc16dsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.69.0", + "@typescript-eslint/typescript-estree": "8.69.0", + "@typescript-eslint/utils": "8.69.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.69.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.69.0.tgz", + "integrity": "sha512-K3VrubUPhlo9VDBS6QdI8YB5j7ClpqLRdefcz6PFrhnwicehBweqQ9Evhl4l+FYz0HdDmMqIiSX0aldGRYtDCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.69.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.69.0.tgz", + "integrity": "sha512-AdFkgqck3Vudb/kWnxlyafU/4aBhHrbQ9locP2N4psXTy5mOBg0SHJumnLvx7r6g1gV4DKvUFwV2nJZBoqOD8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.69.0", + "@typescript-eslint/tsconfig-utils": "8.69.0", + "@typescript-eslint/types": "8.69.0", + "@typescript-eslint/visitor-keys": "8.69.0", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.69.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.69.0.tgz", + "integrity": "sha512-tUbx60BBqQa31kXF5MCsOOLL5E/WzUuxIn7YpAvq+eaUlqvk8/NXnXMBNAdLCr0icjkzem7iUA5QqWHe/hJ1aw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.69.0", + "@typescript-eslint/types": "8.69.0", + "@typescript-eslint/typescript-estree": "8.69.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.69.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.69.0.tgz", + "integrity": "sha512-+rmdgPA+EXkNgKYvHvFfhrs35utXbwaC5PGpDquSXcoXQDKUA5UjV0LmTucG/4JXkM31BTu4TilHtrN8IVBe8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.69.0", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vitest/expect": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.11.tgz", + "integrity": "sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.11", + "@vitest/utils": "4.1.11", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.11.tgz", + "integrity": "sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.1.11", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.11.tgz", + "integrity": "sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.11.tgz", + "integrity": "sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.1.11", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.11.tgz", + "integrity": "sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.11", + "@vitest/utils": "4.1.11", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.11.tgz", + "integrity": "sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.11.tgz", + "integrity": "sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.11", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/acorn": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", + "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/addons-linter": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/addons-linter/-/addons-linter-10.10.0.tgz", + "integrity": "sha512-1n5Xvn4DyHMsulchNDl4ucWnXXQhHwLif6eK80KjieI9KIK3xD+3OYXk5ZcA6a2J8y+Nrlvq9/vq6w7KOqT2MQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "@fluent/syntax": "0.19.0", + "@fregante/relaxed-json": "2.0.0", + "@mdn/browser-compat-data": "8.0.8", + "addons-moz-compare": "1.3.0", + "addons-scanner-utils": "15.4.0", + "ajv": "8.20.0", + "cheerio": "1.2.0", + "columnify": "1.6.0", + "common-tags": "1.8.2", + "css-tree": "3.2.1", + "deepmerge": "4.3.1", + "eslint": "9.39.4", + "eslint-plugin-no-unsanitized": "4.1.5", + "eslint-visitor-keys": "5.0.1", + "espree": "11.2.0", + "esprima": "4.0.1", + "fast-json-patch": "3.1.1", + "image-size": "2.0.2", + "json-merge-patch": "1.0.2", + "pino": "10.3.1", + "semver": "7.8.5", + "source-map-support": "0.5.21", + "upath": "3.0.8", + "yargs": "17.7.2", + "yauzl": "3.4.0" + }, + "bin": { + "addons-linter": "bin/addons-linter" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/addons-linter/node_modules/@eslint/config-array": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.5" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/addons-linter/node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/addons-linter/node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/addons-linter/node_modules/@eslint/js": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", + "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/addons-linter/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/addons-linter/node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/addons-linter/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/addons-linter/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/addons-linter/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/addons-linter/node_modules/brace-expansion": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/addons-linter/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/addons-linter/node_modules/eslint": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", + "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.2", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.5", + "@eslint/js": "9.39.4", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.5", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/addons-linter/node_modules/eslint-scope": { + "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": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/addons-linter/node_modules/eslint/node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/addons-linter/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/addons-linter/node_modules/eslint/node_modules/espree": { + "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.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/addons-linter/node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/addons-linter/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/addons-linter/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/addons-moz-compare": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/addons-moz-compare/-/addons-moz-compare-1.3.0.tgz", + "integrity": "sha512-/rXpQeaY0nOKhNx00pmZXdk5Mu+KhVlL3/pSBuAYwrxRrNiTvI/9xfQI8Lmm7DMMl+PDhtfAHY/0ibTpdeoQQQ==", + "dev": true, + "license": "MPL-2.0" + }, + "node_modules/addons-scanner-utils": { + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/addons-scanner-utils/-/addons-scanner-utils-15.4.0.tgz", + "integrity": "sha512-i3PnJx9YLZi96o4t4JWArP6JimC01949YVAcMJKHfyQ5qmUBaH21qNS8f12/RsloejW8IcCEljhh3Fq3gxFNsg==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "common-tags": "1.8.2", + "first-chunk-stream": "3.0.0", + "jsonwebtoken": "^9.0.3", + "strip-bom-stream": "4.0.0", + "upath": "3.0.7", + "yauzl": "3.4.0" + }, + "peerDependencies": { + "express": "5.2.1", + "safe-compare": "1.1.4" + }, + "peerDependenciesMeta": { + "express": { + "optional": true + }, + "safe-compare": { + "optional": true + } + } + }, + "node_modules/addons-scanner-utils/node_modules/upath": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/upath/-/upath-3.0.7.tgz", + "integrity": "sha512-VjBBquch25nUGMuVBpOb2Cj3gc8Kb7lJBqbsXR/0anZ/5uJsL14Kpth9JKfnBsckxCfgIp6hPvcvvmZ97R9X7g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/anodynos" + }, + { + "type": "polar", + "url": "https://polar.sh/anodynos" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/subscription/pkg/npm-upath" + } + ], + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/adm-zip": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.6.0.tgz", + "integrity": "sha512-XleryMhbuksdKtofnWZ9Sk+4CUTbms4Mb/EU32SZwToAyZ5RgVos/ki8n+yr0LWHOGKuakbXTuuYNHLQjhddgg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-align/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/ansi-align/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-differ": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-4.0.0.tgz", + "integrity": "sha512-Q6VPTLMsmXZ47ENG3V+wQyZS1ZxXMxFyYzA+Z/GMrJ6yIutAIEf9wTyroTzmGjNfox9/h3GdGBCVh43GVFx4Uw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/array-union": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-3.0.1.tgz", + "integrity": "sha512-1OvF9IbWwaeiM9VhzYXVQacMibxpXOMYVNIvMtKRyX9SImBXpKcFr8XvFDeEslCyuH/t6KRt7HEO94AlP8Iatw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" + }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/atomically": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/atomically/-/atomically-2.1.1.tgz", + "integrity": "sha512-P4w9o2dqARji6P7MHprklbfiArZAWvo07yW7qs3pdljb3BWr12FIB7W+p0zJiuiVsUpRO0iZn1kFFcpPegg0tQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "stubborn-fs": "^2.0.0", + "when-exit": "^2.1.4" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true, + "license": "ISC" + }, + "node_modules/boxen": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-8.0.1.tgz", + "integrity": "sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-align": "^3.0.1", + "camelcase": "^8.0.0", + "chalk": "^5.3.0", + "cli-boxes": "^3.0.0", + "string-width": "^7.2.0", + "type-fest": "^4.21.0", + "widest-line": "^5.0.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-8.0.0.tgz", + "integrity": "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cheerio": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.2.0.tgz", + "integrity": "sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "encoding-sniffer": "^0.2.1", + "htmlparser2": "^10.1.0", + "parse5": "^7.3.0", + "parse5-htmlparser2-tree-adapter": "^7.1.0", + "parse5-parser-stream": "^7.1.2", + "undici": "^7.19.0", + "whatwg-mimetype": "^4.0.0" + }, + "engines": { + "node": ">=20.18.1" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/chrome-launcher": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-1.2.0.tgz", + "integrity": "sha512-JbuGuBNss258bvGil7FT4HKdC3SC2K7UAEUqiPy3ACS3Yxo3hAW6bvFpCu2HsIJLgTqxgEX6BkujvzZfLpUD0Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^2.0.1" + }, + "bin": { + "print-chrome-path": "bin/print-chrome-path.cjs" + }, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/columnify": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.6.0.tgz", + "integrity": "sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "strip-ansi": "^6.0.1", + "wcwidth": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/common-tags": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", + "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/config-chain/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" + }, + "node_modules/configstore": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-7.1.0.tgz", + "integrity": "sha512-N4oog6YJWbR9kGyXvS7jEykLDXIE2C0ILYqNBZBp9iwiJpoCBWYsuAdW6PPFn6w06jjnC+3JstVvWHO4cZqvRg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "atomically": "^2.0.3", + "dot-prop": "^9.0.0", + "graceful-fs": "^4.2.11", + "xdg-basedir": "^5.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-select": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css-what": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-6.0.1.tgz", + "integrity": "sha512-G7Cqgaelq68XHJNGlZ7lrNQyhZGsFqpwtGFexqUv4IQdjKoSYF7ipZ9UuTJZUSQXFj/XaoBLuEVIVqr8EJngEQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-browser": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.1.tgz", + "integrity": "sha512-m1pAzaJgZ/gssEqlOhJkPJp8Xly7QyW6xcrkUa2KKcDeDSEMP7X8xipU3snUcfisTQx0w1AGae+9UtJSfVnXGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-prop": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-9.0.0.tgz", + "integrity": "sha512-1gxPBJpI/pcjQhKgIU91II6Wkay+dLcN3M6rf2uwP8hRur3HtQXjVrdAK3sjC0piaEuxzMwjXChcETiJl47lAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^4.18.2" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/encoding-sniffer": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.1.tgz", + "integrity": "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "^0.6.3", + "whatwg-encoding": "^3.1.1" + }, + "funding": { + "url": "https://github.com/fb55/encoding-sniffer?sponsor=1" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-module-lexer": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz", + "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==", + "dev": true, + "license": "MIT" + }, + "node_modules/es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", + "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.2", + "@esbuild/android-arm": "0.28.2", + "@esbuild/android-arm64": "0.28.2", + "@esbuild/android-x64": "0.28.2", + "@esbuild/darwin-arm64": "0.28.2", + "@esbuild/darwin-x64": "0.28.2", + "@esbuild/freebsd-arm64": "0.28.2", + "@esbuild/freebsd-x64": "0.28.2", + "@esbuild/linux-arm": "0.28.2", + "@esbuild/linux-arm64": "0.28.2", + "@esbuild/linux-ia32": "0.28.2", + "@esbuild/linux-loong64": "0.28.2", + "@esbuild/linux-mips64el": "0.28.2", + "@esbuild/linux-ppc64": "0.28.2", + "@esbuild/linux-riscv64": "0.28.2", + "@esbuild/linux-s390x": "0.28.2", + "@esbuild/linux-x64": "0.28.2", + "@esbuild/netbsd-arm64": "0.28.2", + "@esbuild/netbsd-x64": "0.28.2", + "@esbuild/openbsd-arm64": "0.28.2", + "@esbuild/openbsd-x64": "0.28.2", + "@esbuild/openharmony-arm64": "0.28.2", + "@esbuild/sunos-x64": "0.28.2", + "@esbuild/win32-arm64": "0.28.2", + "@esbuild/win32-ia32": "0.28.2", + "@esbuild/win32-x64": "0.28.2" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-goat": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-4.0.0.tgz", + "integrity": "sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.9.1.tgz", + "integrity": "sha512-9VaAkDURekixUQJy0oJYl2DcN6oKMfxay7XzaGYAWQwsb6qfKf+x76R2k1L8kb1boc+FyCAaTA9GmiKaaiaF+A==", + "dev": true, + "license": "MIT", + "workspaces": [ + "packages/*" + ], + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.5", + "@eslint/config-helpers": "^0.7.0", + "@eslint/core": "^1.2.1", + "@eslint/plugin-kit": "^0.7.2", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.2.0", + "esquery": "^1.7.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "minimatch": "^10.2.5", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-no-unsanitized": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-no-unsanitized/-/eslint-plugin-no-unsanitized-4.1.5.tgz", + "integrity": "sha512-MSB4hXPVFQrI8weqzs6gzl7reP2k/qSjtCoL2vUMSDejIIq9YL1ZKvq5/ORBXab/PvfBBrWO2jWviYpL+4Ghfg==", + "dev": true, + "license": "MPL-2.0", + "peerDependencies": { + "eslint": "^9 || ^10" + } + }, + "node_modules/eslint-scope": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expect-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", + "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-patch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.1.tgz", + "integrity": "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.7.tgz", + "integrity": "sha512-dOvZVzjdZdz7phd9v6jCbwxrBW3fK6n8Rc0CtdmM4bumzMnxywBYhuph6J819RRw/ku+rLbelwfMunktuzVVHg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "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": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/firefox-profile": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/firefox-profile/-/firefox-profile-4.7.1.tgz", + "integrity": "sha512-rUFGvJzXxhhOltBxf1aML9jTVismzgC3w00v2dG4Bxu5Xr6o9/D9QUT4do1ZUE9NHzmRFyQ6Bz+HBWnxZMO65w==", + "dev": true, + "license": "MIT", + "dependencies": { + "adm-zip": "~0.6.x", + "fs-extra": "^11.2.0", + "ini": "^4.1.3", + "minimist": "^1.2.8", + "xml2js": "^0.6.2" + }, + "bin": { + "firefox-profile": "lib/cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/first-chunk-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-3.0.0.tgz", + "integrity": "sha512-LNRvR4hr/S8cXXkIY5pTgVP7L3tq6LlYWcg9nWBuW7o1NMxKZo6oOVa/6GIekMGI0Iw7uC+HWimMe9u/VAeKqw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/flat-cache": { + "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.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.4.tgz", + "integrity": "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==", + "dev": true, + "license": "ISC" + }, + "node_modules/fs-extra": { + "version": "11.4.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.4.0.tgz", + "integrity": "sha512-EQsFzMUJkCKGr1ePqlYADkIUmHW1s3ZXr5Yqy6wbGrfUCphpl2maM/kyOIRA2HpP3AaFQTZXD4ldjek+nccddA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/fx-runner": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/fx-runner/-/fx-runner-1.6.0.tgz", + "integrity": "sha512-PEEUfnQJw0/io6SspBbR4EIeXFL/qe/sugesCyfr9M3llgyxNaOH8stvO6KJOKRjeUAvEB6oSZKS3lgjSEOsXg==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "commander": "^12.1.0", + "shell-quote": "1.10.0", + "which": "^4.0.0", + "winreg": "0.0.12" + }, + "bin": { + "fx-runner": "bin/fx-runner" + } + }, + "node_modules/fx-runner/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/fx-runner/node_modules/isexe": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.5.tgz", + "integrity": "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/fx-runner/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/global-directory": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz", + "integrity": "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "4.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/global-directory/node_modules/ini": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/highgain": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/highgain/-/highgain-0.1.0.tgz", + "integrity": "sha512-Vw/g2upw4MYLZ9e95k79+idMoPFEKvTQVTce9LCDfI+T6AiG+SdiR4WDKszB1grQy0O+uhxd6cqbdi3VhECdbA==", + "license": "ISC" + }, + "node_modules/htmlparser2": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz", + "integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "entities": "^7.0.1" + } + }, + "node_modules/htmlparser2/node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "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/image-size": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-2.0.2.tgz", + "integrity": "sha512-IRqXKlaXwgSMAMtpNzZa1ZAe8m+Sa1770Dhk8VkSsP9LS+iHD62Zd8FQKs8fbPiagBE7BzoFX23cxFnwshpV6w==", + "dev": true, + "license": "MIT", + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=16.x" + } + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/import-fresh": { + "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" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/index-to-position": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.2.0.tgz", + "integrity": "sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ini": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz", + "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-in-ci": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-in-ci/-/is-in-ci-1.0.0.tgz", + "integrity": "sha512-eUuAjybVTHMYWm/U+vBO1sY/JOCgoPCXRxzdju0K+K0BiGW0SChEL1MLC0PoCIR1OlPo5YAp8HuQoUlsWEICwg==", + "dev": true, + "license": "MIT", + "bin": { + "is-in-ci": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-in-ssh": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-in-ssh/-/is-in-ssh-1.0.0.tgz", + "integrity": "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-inside-container/node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-installed-globally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-1.0.0.tgz", + "integrity": "sha512-K55T22lfpQ63N4KEN57jZUAaAYqYHEe8veb/TycJRk9DdSCLLcovXz/mL6mOnhQaZsQGwPhuFopdQIlqGSEjiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "global-directory": "^4.0.1", + "is-path-inside": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-npm": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-6.1.0.tgz", + "integrity": "sha512-O2z4/kNgyjhQwVR1Wpkbfc19JIhggF97NZNCpWTnjH7kVcZMUrnut9XSN7txI7VdyIYk5ZatOq3zvSuWpU8hoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-path-inside": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz", + "integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jose": { + "version": "5.9.6", + "resolved": "https://registry.npmjs.org/jose/-/jose-5.9.6.tgz", + "integrity": "sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-merge-patch": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-merge-patch/-/json-merge-patch-1.0.2.tgz", + "integrity": "sha512-M6Vp2GN9L7cfuMXiWOmHj9bEFbeC250iVtcKQbqVgEsDVYnIsrNsbU+h/Y/PkbBQCtEa4Bez+Ebv0zfbC8ObLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + } + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonwebtoken": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", + "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==", + "dev": true, + "license": "MIT", + "dependencies": { + "jws": "^4.0.1", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "dev": true, + "license": "(MIT OR GPL-3.0-or-later)", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/ky": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/ky/-/ky-1.14.3.tgz", + "integrity": "sha512-9zy9lkjac+TR1c2tG+mkNSVlyOpInnWdSMiue4F+kq8TwJSgv6o8jhLRg8Ho6SnZ9wOYUq/yozts9qQCfk7bIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sindresorhus/ky?sponsor=1" + } + }, + "node_modules/latest-version": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-9.0.0.tgz", + "integrity": "sha512-7W0vV3rqv5tokqkBAFV1LbR7HPOWzXQDpDgEuib/aJ1jsZZx6x3c2mBI+TJhJzOhkGeaLbCKEHXEXLfirtG2JA==", + "dev": true, + "license": "MIT", + "dependencies": { + "package-json": "^10.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/lighthouse-logger": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-2.0.2.tgz", + "integrity": "sha512-vWl2+u5jgOQuZR55Z1WM0XDdrJT6mzMP8zHUct7xTlWhuQs+eV0g+QL0RQdFjT54zVmbhLCP8vIVpy1wGn/gCg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "debug": "^4.4.1", + "marky": "^1.2.2" + } + }, + "node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "dev": true, + "license": "MIT" + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/marky": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/marky/-/marky-1.3.0.tgz", + "integrity": "sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/multimatch": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-6.0.0.tgz", + "integrity": "sha512-I7tSVxHGPlmPN/enE3mS1aOSo6bWBfls+3HmuEeCUBCE7gWnm3cBXCBkpurzFjVRwC6Kld8lLaZ1Iv5vOcjvcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/minimatch": "^3.0.5", + "array-differ": "^4.0.0", + "array-union": "^3.0.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/multimatch/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/multimatch/node_modules/brace-expansion": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/multimatch/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/nanoid": { + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-forge": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.4.0.tgz", + "integrity": "sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==", + "dev": true, + "license": "(BSD-3-Clause OR GPL-2.0)", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/obug": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.4.tgz", + "integrity": "sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/open": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/open/-/open-11.0.0.tgz", + "integrity": "sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-browser": "^5.4.0", + "define-lazy-prop": "^3.0.0", + "is-in-ssh": "^1.0.0", + "is-inside-container": "^1.0.0", + "powershell-utils": "^0.1.0", + "wsl-utils": "^0.3.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-10.0.1.tgz", + "integrity": "sha512-ua1L4OgXSBdsu1FPb7F3tYH0F48a6kxvod4pLUlGY9COeJAJQNX/sNH2IiEmsxw7lqYiAwrdHMjz1FctOsyDQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ky": "^1.2.0", + "registry-auth-token": "^5.0.2", + "registry-url": "^6.0.1", + "semver": "^7.6.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true, + "license": "(MIT AND Zlib)" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz", + "integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "index-to-position": "^1.1.0", + "type-fest": "^4.39.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz", + "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "domhandler": "^5.0.3", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-parser-stream": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz", + "integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5/node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pino": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/pino/-/pino-10.3.1.tgz", + "integrity": "sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pinojs/redact": "^0.4.0", + "atomic-sleep": "^1.0.0", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^3.0.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^5.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^4.0.1", + "thread-stream": "^4.0.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-3.0.0.tgz", + "integrity": "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "split2": "^4.0.0" + } + }, + "node_modules/pino-std-serializers": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz", + "integrity": "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==", + "dev": true, + "license": "MIT" + }, + "node_modules/postcss": { + "version": "8.5.26", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", + "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.17", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/powershell-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.1.0.tgz", + "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/preact": { + "version": "10.29.8", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.29.8.tgz", + "integrity": "sha512-ej2aVZ+vZ8WO7tvlQWRM9N63A0KzF9q4mWJfDUHgYaIofWY9hu74QdnQrjoPMmZi2/nZ5gN0bJCQF49xQqx09Q==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + }, + "peerDependencies": { + "preact-render-to-string": ">=5" + }, + "peerDependenciesMeta": { + "preact-render-to-string": { + "optional": true + } + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/process-warning": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.1.0.tgz", + "integrity": "sha512-jQSaVHsPgtyw60e1rQ/A+/ArPEj/S8pS/vFnyGa/gYFXrKk/6RuDkoqVDQ5NI5MmS01698ltlAk0NoDBNLujRw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, + "node_modules/promise-toolbox": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/promise-toolbox/-/promise-toolbox-0.21.0.tgz", + "integrity": "sha512-NV8aTmpwrZv+Iys54sSFOBx3tuVaOBvvrft5PNppnxy9xpU/akHbaWIril22AB22zaPgrgwKdD0KsrM0ptUtpg==", + "dev": true, + "license": "ISC", + "dependencies": { + "make-error": "^1.3.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true, + "license": "ISC" + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pupa": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-3.3.0.tgz", + "integrity": "sha512-LjgDO2zPtoXP2wJpDjZrGdojii1uqO0cnwKoIoUzkfS98HDmbeiGmYiXo3lXeFlq2xvne1QFQhwYXSUCLKtEuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-goat": "^4.0.0" + }, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "dev": true, + "license": "MIT" + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/registry-auth-token": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.1.1.tgz", + "integrity": "sha512-P7B4+jq8DeD2nMsAcdfaqHbssgHtZ7Z5+++a5ask90fvmJ8p5je4mOa+wzu+DB4vQ5tdJV/xywY+UnVFeQLV5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pnpm/npm-conf": "^3.0.2" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/registry-url": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz", + "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "rc": "1.2.8" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "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/rolldown": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.7.tgz", + "integrity": "sha512-g0EtLvBjTUB7jhyV0S/TCup3v/XSVl45vUIGbOGU4QPiyjTenCe4mKuFvW9fEgYmS2Fo42AUssRmNuMziXdrig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.148.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm-eabi": "1.2.7", + "@rolldown/binding-android-arm64": "1.2.7", + "@rolldown/binding-darwin-arm64": "1.2.7", + "@rolldown/binding-darwin-x64": "1.2.7", + "@rolldown/binding-freebsd-x64": "1.2.7", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.7", + "@rolldown/binding-linux-arm64-gnu": "1.2.7", + "@rolldown/binding-linux-arm64-musl": "1.2.7", + "@rolldown/binding-linux-ppc64-gnu": "1.2.7", + "@rolldown/binding-linux-s390x-gnu": "1.2.7", + "@rolldown/binding-linux-x64-gnu": "1.2.7", + "@rolldown/binding-linux-x64-musl": "1.2.7", + "@rolldown/binding-openharmony-arm64": "1.2.7", + "@rolldown/binding-win32-arm64-msvc": "1.2.7", + "@rolldown/binding-win32-x64-msvc": "1.2.7" + } + }, + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/sax": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.1.tgz", + "integrity": "sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true, + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.10.0.tgz", + "integrity": "sha512-w1aiOKwKuRgtwAReIIj89puqg+I7GvX4IbLrvmhXbzQsj1+Zwi4VO3+fa6ZF91TWSjIxoEkKnMeHcLEODK5ZXA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/sonic-boom": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.1.tgz", + "integrity": "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "through": "2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.2.0.tgz", + "integrity": "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==", + "dev": true, + "license": "MIT" + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-5.0.0.tgz", + "integrity": "sha512-p+byADHF7SzEcVnLvc/r3uognM1hUhObuHXxJcgLCfD194XAkaLbjq3Wzb0N5G2tgIjH0dgT708Z51QxMeu60A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-bom-buf": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-buf/-/strip-bom-buf-2.0.0.tgz", + "integrity": "sha512-gLFNHucd6gzb8jMsl5QmZ3QgnUJmp7qn4uUSHNwEXumAp7YizoGYw19ZUVfuq4aBOQUtyn2k8X/CwzWB73W2lQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-utf8": "^0.2.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom-stream": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-4.0.0.tgz", + "integrity": "sha512-0ApK3iAkHv6WbgLICw/J4nhwHeDZsBxIIsOD+gHgZICL6SeJ0S9f/WZqemka9cjkTyMN5geId6e8U5WGFAn3cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "first-chunk-stream": "^3.0.0", + "strip-bom-buf": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.3.tgz", + "integrity": "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stubborn-fs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/stubborn-fs/-/stubborn-fs-2.0.0.tgz", + "integrity": "sha512-Y0AvSwDw8y+nlSNFXMm2g6L51rBGdAQT20J3YSOqxC53Lo3bjWRtr2BKcfYoAf352WYpsZSTURrA0tqhfgudPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "stubborn-utils": "^1.0.1" + } + }, + "node_modules/stubborn-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stubborn-utils/-/stubborn-utils-1.0.2.tgz", + "integrity": "sha512-zOh9jPYI+xrNOyisSelgym4tolKTJCQd5GBhK0+0xJvcYDcwlOoxF/rnFKQ2KRZknXSG9jWAp66fwP6AxN9STg==", + "dev": true, + "license": "MIT" + }, + "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/thread-stream": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-4.2.0.tgz", + "integrity": "sha512-e2zZ96wSChazBsbENf/Pcm/4swHt2cEKQ92rhUjkL9GCKiTDJIaTBenjE/m9DXi0QBmTMDkFDdOomUy20A1tDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "real-require": "^1.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/thread-stream/node_modules/real-require": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-1.0.0.tgz", + "integrity": "sha512-P4nbQYQfePJxRSmY+v/KINxVucm4NF3p3s7pJveMTtom52FR4YGltUQLB8idDXwDDWW+eYrWDFbuzUnjoWHF7g==", + "dev": true, + "license": "MIT" + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.0.tgz", + "integrity": "sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyrainbow": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.1.tgz", + "integrity": "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tmp": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz", + "integrity": "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/ts-deepmerge": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/ts-deepmerge/-/ts-deepmerge-8.0.0.tgz", + "integrity": "sha512-133O+10nJmVI8w5xeVZPEv5PIrv7iaUae07wv1aH8XJH95Ur6YIhWAPhPyP1YPlbPS9fCVcNIZTu7m8urRVF0A==", + "license": "ISC", + "engines": { + "node": ">=14.13.1" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.69.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.69.0.tgz", + "integrity": "sha512-B3MltX0VqjUBNEe3b3sSuiRbfa6XrfHFtBiPamjT5AsW/dfq+y+bc0wyuS9DxAS1LyzCxRp2+rxzpLUvqM2BvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.69.0", + "@typescript-eslint/parser": "8.69.0", + "@typescript-eslint/typescript-estree": "8.69.0", + "@typescript-eslint/utils": "8.69.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/undici": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.29.0.tgz", + "integrity": "sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/undici-types": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", + "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/upath": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/upath/-/upath-3.0.8.tgz", + "integrity": "sha512-YAsrLMIlhfSCm9rga5TZsJ1mXgahs7N0qOTokzU8mFz35hUrYMvVkaEPefI3rEb/vkAWAOj1Km/qdije9RC1kQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/anodynos" + }, + { + "type": "polar", + "url": "https://polar.sh/anodynos" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/subscription/pkg/npm-upath" + } + ], + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/update-notifier": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-7.3.1.tgz", + "integrity": "sha512-+dwUY4L35XFYEzE+OAL3sarJdUioVovq+8f7lcIJ7wnmnYQV5UD1Y/lcwaMSyaQ6Bj3JMj1XSTjZbNLHn/19yA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boxen": "^8.0.1", + "chalk": "^5.3.0", + "configstore": "^7.0.0", + "is-in-ci": "^1.0.0", + "is-installed-globally": "^1.0.0", + "is-npm": "^6.0.0", + "latest-version": "^9.0.0", + "pupa": "^3.1.0", + "semver": "^7.6.3", + "xdg-basedir": "^5.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/yeoman/update-notifier?sponsor=1" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.2.tgz", + "integrity": "sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.33.0", + "picomatch": "^4.0.5", + "postcss": "^8.5.26", + "rolldown": "~1.2.4", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.4.0 || ^0.5.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vitest": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.11.tgz", + "integrity": "sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.1.11", + "@vitest/mocker": "4.1.11", + "@vitest/pretty-format": "4.1.11", + "@vitest/runner": "4.1.11", + "@vitest/snapshot": "4.1.11", + "@vitest/spy": "4.1.11", + "@vitest/utils": "4.1.11", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^4.0.0-rc.1", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.1.11", + "@vitest/browser-preview": "4.1.11", + "@vitest/browser-webdriverio": "4.1.11", + "@vitest/coverage-istanbul": "4.1.11", + "@vitest/coverage-v8": "4.1.11", + "@vitest/ui": "4.1.11", + "happy-dom": "*", + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } + } + }, + "node_modules/watchpack": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.2.tgz", + "integrity": "sha512-6i/00NBjP4yGPs+caKSyRfpTF/8Torsu0MOW3mMzIbhgISFder8i7xbqgHlLMwJrdiN8ndBV3UA1/AfzPSr+jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/web-ext": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/web-ext/-/web-ext-10.6.0.tgz", + "integrity": "sha512-r1MfSwVy5wRQw3UgTUCw9CDViFIoDPri1Wq8qh/mRjC8T+K0TfuxKz68bzYTEP3rbAW6Wn8y7v/jXzBYd3LLGA==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "@babel/runtime": "8.0.0", + "@devicefarmer/adbkit": "3.3.9", + "addons-linter": "10.10.0", + "camelcase": "8.0.0", + "chrome-launcher": "1.2.0", + "debounce": "1.2.1", + "decamelize": "6.0.1", + "es6-error": "4.1.1", + "firefox-profile": "4.7.1", + "fx-runner": "1.6.0", + "https-proxy-agent": "^7.0.0", + "jose": "5.9.6", + "jszip": "3.10.1", + "multimatch": "6.0.0", + "open": "11.0.0", + "parse-json": "8.3.0", + "pino": "10.3.1", + "promise-toolbox": "0.21.0", + "source-map-support": "0.5.21", + "strip-bom": "5.0.0", + "strip-json-comments": "5.0.3", + "tmp": "0.2.7", + "update-notifier": "7.3.1", + "watchpack": "2.5.2", + "yargs": "17.7.2", + "zip-dir": "2.0.0" + }, + "bin": { + "web-ext": "bin/web-ext.js" + }, + "engines": { + "node": ">=20.0.0", + "npm": ">=8.0.0" + } + }, + "node_modules/webextension-polyfill": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/webextension-polyfill/-/webextension-polyfill-0.12.0.tgz", + "integrity": "sha512-97TBmpoWJEE+3nFBQ4VocyCdLKfw54rFaJ6EVQYLBCXqCIpLSZkwGgASpv4oPt9gdKCJ80RJlcmNzNn008Ag6Q==", + "license": "MPL-2.0" + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/when-exit": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/when-exit/-/when-exit-2.1.5.tgz", + "integrity": "sha512-VGkKJ564kzt6Ms1dbgPP/yuIoQCrsFAnRbptpC5wOEsDaNsbCB2bnfnaA8i/vRs5tjUSEOtIuvl9/MyVsvQZCg==", + "dev": true, + "license": "MIT" + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/widest-line": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-5.0.0.tgz", + "integrity": "sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/winreg": { + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/winreg/-/winreg-0.0.12.tgz", + "integrity": "sha512-typ/+JRmi7RqP1NanzFULK36vczznSNN8kWVA9vIqXyv8GhghUlwhGp1Xj3Nms1FsPcNnsQrJOR10N58/nQ9hQ==", + "dev": true, + "license": "BSD" + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/wsl-utils": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.3.1.tgz", + "integrity": "sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0", + "powershell-utils": "^0.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wsl-utils/node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xdg-basedir": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", + "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xml2js": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", + "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", + "dev": true, + "license": "MIT", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yauzl": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.4.0.tgz", + "integrity": "sha512-jIH9yLR9wqr0wOS0TpBvo/g/2UgZH5qePVbjgRliiF0BYvOZyaBknKsF+x9Iht0O6sqgnB93rCICdOZFecJuDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zip-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/zip-dir/-/zip-dir-2.0.0.tgz", + "integrity": "sha512-uhlsJZWz26FLYXOD6WVuq+fIcZ3aBPGo/cFdiLlv3KNwpa52IF3ISV8fLhQLiqVu5No3VhlqlgthN6gehil1Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "async": "^3.2.0", + "jszip": "^3.2.2" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..0f3c70a --- /dev/null +++ b/package.json @@ -0,0 +1,36 @@ +{ + "name": "slopdetect", + "version": "0.3.2", + "private": true, + "description": "A privacy-first Firefox extension for AI provenance and generated-site pattern detection.", + "type": "module", + "scripts": { + "clean": "node scripts/clean.mjs", + "build": "node scripts/build.mjs", + "check": "tsc --noEmit", + "test": "vitest run", + "test:watch": "vitest", + "lint": "eslint .", + "package": "npm run build && web-ext build --source-dir dist --artifacts-dir artifacts --overwrite-dest", + "start": "npm run build && web-ext run --source-dir dist" + }, + "dependencies": { + "@contentauth/c2pa-web": "0.14.4", + "preact": "10.29.8", + "webextension-polyfill": "0.12.0" + }, + "devDependencies": { + "@eslint/js": "10.0.1", + "@types/firefox-webext-browser": "143.0.0", + "@types/webextension-polyfill": "0.12.6", + "esbuild": "0.28.2", + "eslint": "10.9.1", + "typescript": "6.0.3", + "typescript-eslint": "8.69.0", + "vitest": "4.1.11", + "web-ext": "10.6.0" + }, + "engines": { + "node": ">=22" + } +} diff --git a/public/icons/icon.svg b/public/icons/icon.svg new file mode 100644 index 0000000..17f282a --- /dev/null +++ b/public/icons/icon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/manifest.json b/public/manifest.json new file mode 100644 index 0000000..d1409bf --- /dev/null +++ b/public/manifest.json @@ -0,0 +1,44 @@ +{ + "manifest_version": 3, + "name": "SlopDetect", + "version": "0.3.2", + "description": "Automatically inspect AI provenance and flag common generated-site patterns.", + "browser_specific_settings": { + "gecko": { + "id": "slopdetect@local", + "strict_min_version": "140.0", + "data_collection_permissions": { + "required": ["none"] + } + }, + "gecko_android": { + "strict_min_version": "142.0" + } + }, + "permissions": ["storage"], + "host_permissions": ["http://*/*", "https://*/*"], + "content_scripts": [{ + "matches": ["http://*/*", "https://*/*"], + "js": ["content.js"], + "run_at": "document_idle" + }], + "background": { + "scripts": ["background.js"] + }, + "action": { + "default_title": "Scan this page with SlopDetect", + "default_popup": "popup.html", + "default_icon": "icons/icon.svg" + }, + "options_ui": { + "page": "options.html", + "open_in_tab": true + }, + "icons": { + "48": "icons/icon.svg", + "96": "icons/icon.svg" + }, + "content_security_policy": { + "extension_pages": "script-src 'self' 'wasm-unsafe-eval'; worker-src 'self'; object-src 'self'" + } +} diff --git a/public/options.html b/public/options.html new file mode 100644 index 0000000..106b811 --- /dev/null +++ b/public/options.html @@ -0,0 +1,12 @@ + + + + + + SlopDetect settings + + +
+ + + diff --git a/public/popup.html b/public/popup.html new file mode 100644 index 0000000..f472169 --- /dev/null +++ b/public/popup.html @@ -0,0 +1,12 @@ + + + + + + SlopDetect + + +
+ + + diff --git a/public/trust/C2PA-TRUST-LIST.pem b/public/trust/C2PA-TRUST-LIST.pem new file mode 100644 index 0000000..a0d20fd --- /dev/null +++ b/public/trust/C2PA-TRUST-LIST.pem @@ -0,0 +1,656 @@ +Subject CN=Google C2PA Media Services 1P ICA G3, O=Google LLC, C=US +-----BEGIN CERTIFICATE----- +MIIC3DCCAmOgAwIBAgIUQfqlIUd2IVjaf5ss/439Fgke7j4wCgYIKoZIzj0EAwMw +QzELMAkGA1UEBhMCVVMxEzARBgNVBAoMCkdvb2dsZSBMTEMxHzAdBgNVBAMMFkdv +b2dsZSBDMlBBIFJvb3QgQ0EgRzMwHhcNMjUwNTA4MjIzNjI2WhcNMzAwNTA4MjIz +NjI2WjBRMQswCQYDVQQGEwJVUzETMBEGA1UECgwKR29vZ2xlIExMQzEtMCsGA1UE +AwwkR29vZ2xlIEMyUEEgTWVkaWEgU2VydmljZXMgMVAgSUNBIEczMHYwEAYHKoZI +zj0CAQYFK4EEACIDYgAEuCPlUxSiltqnB2lx2ES7FK+TVZWmAxRzzDjTzKZ8umoq +yvCqSLOkZBrOieaLqrp+rnzt0EADWWH3X62NqzEXRewW6rb/lS7VXkVCM02gC0Zg +JW7+PCsZgLoUBUQ+nkN5o4IBCDCCAQQwFwYDVR0gBBAwDjAMBgorBgEEAYPoXgEB +MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSUEGDAWBggrBgEFBQcDBAYKKwYBBAGD6F4C +ATASBgNVHRMBAf8ECDAGAQH/AgEAMGQGCCsGAQUFBwEBBFgwVjAsBggrBgEFBQcw +AoYgaHR0cDovL3BraS5nb29nL2MycGEvcm9vdC1nMy5jcnQwJgYIKwYBBQUHMAGG +Gmh0dHA6Ly9jMnBhLW9jc3AucGtpLmdvb2cvMB8GA1UdIwQYMBaAFJxc2IlTQ+da +1YHbA94ZfwQqKi2qMB0GA1UdDgQWBBTae+G9tCyKheAQ1muax0rx+t/2NzAKBggq +hkjOPQQDAwNnADBkAjACxtEE3NW13bwN1u/51ericNF6rkEhYVESDO6Jqb5cX37H +wg0X9S2rH+vXaoFZIHsCMC03wCKKomDHgqV47UtyyHpZlo5IZACW72Xdc4gipdWM +EmhvPk88dvxbYtn+LVd9zA== +-----END CERTIFICATE----- + +Subject CN=Google C2PA Mobile A 1P ICA G3 L1, O=Google LLC, C=US +-----BEGIN CERTIFICATE----- +MIIC2TCCAmCgAwIBAgIUdEQo46dHfO396b1NFkYHqblfVzAwCgYIKoZIzj0EAwMw +QzELMAkGA1UEBhMCVVMxEzARBgNVBAoMCkdvb2dsZSBMTEMxHzAdBgNVBAMMFkdv +b2dsZSBDMlBBIFJvb3QgQ0EgRzMwHhcNMjUwNTA4MjIzNjI3WhcNMzAwNTA4MjIz +NjI3WjBOMQswCQYDVQQGEwJVUzETMBEGA1UECgwKR29vZ2xlIExMQzEqMCgGA1UE +AwwhR29vZ2xlIEMyUEEgTW9iaWxlIEEgMVAgSUNBIEczIEwxMHYwEAYHKoZIzj0C +AQYFK4EEACIDYgAEiso7FbPFqaTmLWL6vJq0Q0FTLVILWVg1nyG1kR2JkEc5E9WW +k62YSJreXbX6axJqDGecSk5kvqcb9EVJ+wymonRaqy7Gk9c6fi9Hr1mK2mfJZRlX +CIXeMXeneVG8NMJ8o4IBCDCCAQQwFwYDVR0gBBAwDjAMBgorBgEEAYPoXgEBMA4G +A1UdDwEB/wQEAwIBBjAfBgNVHSUEGDAWBggrBgEFBQcDBAYKKwYBBAGD6F4CATAS +BgNVHRMBAf8ECDAGAQH/AgEAMGQGCCsGAQUFBwEBBFgwVjAsBggrBgEFBQcwAoYg +aHR0cDovL3BraS5nb29nL2MycGEvcm9vdC1nMy5jcnQwJgYIKwYBBQUHMAGGGmh0 +dHA6Ly9jMnBhLW9jc3AucGtpLmdvb2cvMB8GA1UdIwQYMBaAFJxc2IlTQ+da1YHb +A94ZfwQqKi2qMB0GA1UdDgQWBBSu91pCmLI7HftmLBUUmRZ631vvlDAKBggqhkjO +PQQDAwNnADBkAjA6bs5IFiYOZjmln6Bii/ShnzrqTn4GxKdCZhP79ul9iPz+mQyn +pORTyTY84SsxzicCMCI2tAB6n8FQ5BkN1apEUG5gcJlrrNd1rdqtBNXJZHXqYG1m +7T4gYBB4PHNYYFBGfA== +-----END CERTIFICATE----- + +Subject CN=Google C2PA Mobile A 1P ICA G3, O=Google LLC, C=US +-----BEGIN CERTIFICATE----- +MIIC1jCCAl2gAwIBAgIUXKoTHSLJjkXHIxvKY29YmxgOzoowCgYIKoZIzj0EAwMw +QzELMAkGA1UEBhMCVVMxEzARBgNVBAoMCkdvb2dsZSBMTEMxHzAdBgNVBAMMFkdv +b2dsZSBDMlBBIFJvb3QgQ0EgRzMwHhcNMjUwNTA4MjIzNjI4WhcNMzAwNTA4MjIz +NjI4WjBLMQswCQYDVQQGEwJVUzETMBEGA1UECgwKR29vZ2xlIExMQzEnMCUGA1UE +AwweR29vZ2xlIEMyUEEgTW9iaWxlIEEgMVAgSUNBIEczMHYwEAYHKoZIzj0CAQYF +K4EEACIDYgAEx5s4bjuNRDlYKtdj4Dd14esDWyBAk+fNPHFGlDcWX2lTdxgeeKYF +caw7ZdhD5fWAqUZ++M5wdXXUoGHDFAwfPmTaRKzZupUu7uMFZtolBzAuT2I51meH +EfMHU95kRkTIo4IBCDCCAQQwDgYDVR0PAQH/BAQDAgEGMB8GA1UdJQQYMBYGCCsG +AQUFBwMEBgorBgEEAYPoXgIBMBIGA1UdEwEB/wQIMAYBAf8CAQAwFwYDVR0gBBAw +DjAMBgorBgEEAYPoXgEBMGQGCCsGAQUFBwEBBFgwVjAsBggrBgEFBQcwAoYgaHR0 +cDovL3BraS5nb29nL2MycGEvcm9vdC1nMy5jcnQwJgYIKwYBBQUHMAGGGmh0dHA6 +Ly9jMnBhLW9jc3AucGtpLmdvb2cvMB8GA1UdIwQYMBaAFJxc2IlTQ+da1YHbA94Z +fwQqKi2qMB0GA1UdDgQWBBQOccStRBCOVzAFalyyAs6XkvF+IDAKBggqhkjOPQQD +AwNnADBkAjBjAj22bX3vKs/3Q4K0qE7jPwY3BljcaGyhTg9Gk6ni0+3TxuluLCq+ +zITXauG0qy0CMFfS4bUxKdwCjWOnamLCA9xiaO82my0UN0kvxNMFflLsmeO4PL+N +I/u3EJ347o+4jA== +-----END CERTIFICATE----- + +Subject CN=Google C2PA Mobile B 1P ICA G3 L1, O=Google LLC, C=US +-----BEGIN CERTIFICATE----- +MIIC2zCCAmCgAwIBAgIUBpMF/2hh9GWQEhKn4uebRk7j2PcwCgYIKoZIzj0EAwMw +QzELMAkGA1UEBhMCVVMxEzARBgNVBAoMCkdvb2dsZSBMTEMxHzAdBgNVBAMMFkdv +b2dsZSBDMlBBIFJvb3QgQ0EgRzMwHhcNMjUwNTA4MjIzNjI3WhcNMzAwNTA4MjIz +NjI3WjBOMQswCQYDVQQGEwJVUzETMBEGA1UECgwKR29vZ2xlIExMQzEqMCgGA1UE +AwwhR29vZ2xlIEMyUEEgTW9iaWxlIEIgMVAgSUNBIEczIEwxMHYwEAYHKoZIzj0C +AQYFK4EEACIDYgAEKGv3Fd3J1vOPfrR744lpYlGc05lZ57UyVDKGHTPj71PuwW19 +oHO932WXXf+K4jBkotgXeBChrhrTiUGxBdrmYRB1m6MyAJ/wT3xw06YRcGxoiW0b +IhbMN4YNIAMW76Noo4IBCDCCAQQwFwYDVR0gBBAwDjAMBgorBgEEAYPoXgEBMA4G +A1UdDwEB/wQEAwIBBjAfBgNVHSUEGDAWBggrBgEFBQcDBAYKKwYBBAGD6F4CATAS +BgNVHRMBAf8ECDAGAQH/AgEAMGQGCCsGAQUFBwEBBFgwVjAsBggrBgEFBQcwAoYg +aHR0cDovL3BraS5nb29nL2MycGEvcm9vdC1nMy5jcnQwJgYIKwYBBQUHMAGGGmh0 +dHA6Ly9jMnBhLW9jc3AucGtpLmdvb2cvMB8GA1UdIwQYMBaAFJxc2IlTQ+da1YHb +A94ZfwQqKi2qMB0GA1UdDgQWBBRLBf7gDA1hOViJqHtuE8btC3KB8TAKBggqhkjO +PQQDAwNpADBmAjEAhfcU5E3IKMRw/Wxd9YfUdxTpi5HM99JiHG0KmFxcPGd8tDBA +XkoxEV/OYIEeyVl4AjEA1QH3goidp0++w4rQ6P8wbdw3BtlkSJpGsQ4WQc0i5bWz +KyN/WtDOZj/RG3+bqaw+ +-----END CERTIFICATE----- + +Subject CN=Google C2PA Mobile B 1P ICA G3, O=Google LLC, C=US +-----BEGIN CERTIFICATE----- +MIIC1zCCAl2gAwIBAgIUac3GAHq5vTwO71pE75SNo8wcJVcwCgYIKoZIzj0EAwMw +QzELMAkGA1UEBhMCVVMxEzARBgNVBAoMCkdvb2dsZSBMTEMxHzAdBgNVBAMMFkdv +b2dsZSBDMlBBIFJvb3QgQ0EgRzMwHhcNMjUwNTA4MjIzNjI3WhcNMzAwNTA4MjIz +NjI3WjBLMQswCQYDVQQGEwJVUzETMBEGA1UECgwKR29vZ2xlIExMQzEnMCUGA1UE +AwweR29vZ2xlIEMyUEEgTW9iaWxlIEIgMVAgSUNBIEczMHYwEAYHKoZIzj0CAQYF +K4EEACIDYgAEbns1saor1bu/tYfe1ozY2yZwBgkcmIcmr552foAPn5v4zmS61OEs +C5VwKHBgi9uTuXZ8SSV1KSPyysqrgm542XLPWsMlkuWRfneQBANeLAk6aEBqDASo +DJ7Aoube5tuao4IBCDCCAQQwDgYDVR0PAQH/BAQDAgEGMB8GA1UdJQQYMBYGCCsG +AQUFBwMEBgorBgEEAYPoXgIBMBIGA1UdEwEB/wQIMAYBAf8CAQAwFwYDVR0gBBAw +DjAMBgorBgEEAYPoXgEBMGQGCCsGAQUFBwEBBFgwVjAsBggrBgEFBQcwAoYgaHR0 +cDovL3BraS5nb29nL2MycGEvcm9vdC1nMy5jcnQwJgYIKwYBBQUHMAGGGmh0dHA6 +Ly9jMnBhLW9jc3AucGtpLmdvb2cvMB8GA1UdIwQYMBaAFJxc2IlTQ+da1YHbA94Z +fwQqKi2qMB0GA1UdDgQWBBT4N2ZAjPoDJR1+UgU4KwafcJT5mDAKBggqhkjOPQQD +AwNoADBlAjEAg2SjBAAmAOvOLd1kKYZQzkiD6KSXe4+3zALTs5SQCK3xmmkxsFzJ +bBCIiuTbxsrIAjAhQm+LpSxSwkIZiwWI7rGiJMv7BCj38HhiQpmR5lr+anbBOQty +UsWhYsCGlDmiWzA= +-----END CERTIFICATE----- + +Subject CN=Google C2PA Root CA G3, O=Google LLC, C=US +-----BEGIN CERTIFICATE----- +MIICLjCCAbOgAwIBAgIUUZK4AROFKiXQZ1UG7FG6qPGc1g8wCgYIKoZIzj0EAwMw +QzELMAkGA1UEBhMCVVMxEzARBgNVBAoMCkdvb2dsZSBMTEMxHzAdBgNVBAMMFkdv +b2dsZSBDMlBBIFJvb3QgQ0EgRzMwIBcNMjUwNTA4MjIzMjIxWhgPMjA1MDA1MDgy +MjMyMjFaMEMxCzAJBgNVBAYTAlVTMRMwEQYDVQQKDApHb29nbGUgTExDMR8wHQYD +VQQDDBZHb29nbGUgQzJQQSBSb290IENBIEczMHYwEAYHKoZIzj0CAQYFK4EEACID +YgAEhv9f/juKcPpe3Fm7eAISMuSyS+tBxn0aYHC83J+qAsFWREGN9p6PN/OBoouP +zpOFRxvrlWoWmAI3p1lXyPg4E3eg7SNChgopUIpihGu6qlhP8rLXf3p8bhI5FTQ2 +MaF2o2YwZDASBgNVHRMBAf8ECDAGAQH/AgECMA4GA1UdDwEB/wQEAwIBBjAfBgNV +HSMEGDAWgBScXNiJU0PnWtWB2wPeGX8EKiotqjAdBgNVHQ4EFgQUnFzYiVND51rV +gdsD3hl/BCoqLaowCgYIKoZIzj0EAwMDaQAwZgIxAIyVEe5bdUMkk6BthEWy9QSE +Mb74BOyK8/8pgMX0NPwLlo1ikLNY78ov+k21vZrEZQIxANQ91muDXgPjAMAkzAlK +i32Z9VBB37ynTveKVC7ofTW0ZFfIIYYpWUR1+C4m2yRkOQ== +-----END CERTIFICATE----- + +Subject CN=SSL.com C2PA RSA Root CA 2025, O=SSL Corporation, C=US +-----BEGIN CERTIFICATE----- +MIIFlDCCA3ygAwIBAgIUExeshkq/ESresWEq3YWcEUTmxvowDQYJKoZIhvcNAQEL +BQAwTzEmMCQGA1UEAwwdU1NMLmNvbSBDMlBBIFJTQSBSb290IENBIDIwMjUxGDAW +BgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjELMAkGA1UEBhMCVVMwIBcNMjUxMTA3MTYy +NzEzWhgPMjA1MDExMDExNjI3MTNaME8xJjAkBgNVBAMMHVNTTC5jb20gQzJQQSBS +U0EgUm9vdCBDQSAyMDI1MRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xCzAJBgNV +BAYTAlVTMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA07LXx05AgfZn +F6CPMzpPwA+vGxfqi2Pw3/gvhAe4UdzmasSutCRK9sK66DZYta4AbYPS0/2IToqo +1n33f9/XrmQ62uM3XAyKXfg8UWUaj2WsyA3dIxY5l80B0S0EX0V1HpP6ygw1IDfJ +/KKkknn/0o14zmNkRzLpqQDOMoL4s+kli8NtkEOG8M8NrH5QJCNRL7lN0DG8TvRa +10Zfwyxnd4yw9DT2HWJInjC+Hww9QZua/u6bTy0pFHV0vVCgKQuPtbX8b60998t4 +b56trGesWapUefIEu6GH1CkQu7nhsk1Rf59+uPv1NQLOm7wbyghHtQQ00baR/687 +r7/qXxRLV1CFNH3nAgFfHkD8N07GWS5C1OOmkUPrc2f9tdKWOJ6USDJCOX1DkTee +o9RgwSJfLueDtAOp19dlBo2UW79A2MGN6VI119DoW04VUjxmPHLIWtt08ZRTHzvN +2I2DA3ic5Wt4pgSLXDZ6ztlFX4Y6nXwVFdWae9zwLpm9ttsF4fepLyPAUTuT9m0j +/oeQt3KmyxIukYD8I1PiSQ6YDLIiWFZcYC8LMyiYmQEX6spsE+IF37lx2nZ1OF+D +AOSCYYamZx6HYShgN4zN1QYTMJdxbz5JgRTIIioVdJTqeF/5GsSGP6f9Eym8ND9j +LQzm8MBEMfvlAgw0q1ieN2Q9INSN3qMCAwEAAaNmMGQwEgYDVR0TAQH/BAgwBgEB +/wIBAjAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFPwqSnU6gPqZY5Pwc1fsvpOw +fcN7MB8GA1UdIwQYMBaAFPwqSnU6gPqZY5Pwc1fsvpOwfcN7MA0GCSqGSIb3DQEB +CwUAA4ICAQBAqkR9j5wKs0T7e9gHTUWlLAnkWLyZI7AuEoXimyJ7Ocy1EwZyu3TD +Z2jCecLNXENnUwjuKaEm/8sCwzrVqpxzIgkS1jVLuVURlrj2+apT/7wBw8LCKMZ6 +cDhQJV3A1+9hyCc5ozkE1LgcJfWELrBWeBuj8rWLAf0DDgtwaED7nS9c9P8UgrxH +YTMe2AHWEfczXBirx5ubpNaokR0W01aSdXa97ohoS+ZmK0bxvmWCugI4tfsypsVl +lV2iD9v/BPLCVHP+7ot520mE21WdQKD69M54V8KAqfmNoG6I3TB2EcKJ0NpKI0zW +niSX05NDrv70INu+vAI8Sso/mRMHpuo03/0iTm3z8J4ACjwP071U0R3wCjTxN8z2 +95EwOf1/JQH5h0njkarxFsWsnHJtWwE3kGEibO3ivB2U3FyS1osN0bEA4X5CSeMF +GDJFCXVB0l4/KeHHNRk3DEVjr5dzcwt/C2DLj9VuaeWEWuVbA3/PDR/MnZzDtPj1 +TVLswGkWKwG+AyJaHkLysZD0IKwL4SZGGCRvyKw+G5Go0vvHVyUMPHqVTBApxY9l +pt6absyMPdRnf+w0tdFlhCd2rauRA0HX7JZ5xqnYjkfk0m7MpoauCsQR9udJvv5H +pMv7wvJRchf62/pPnjLKhN/dx9LR/EVqBPbPMhqdzO6ObQdqUJzXPQ== +-----END CERTIFICATE----- + +Subject CN=SSL.com C2PA ECC Root CA 2025, O=SSL Corporation, C=US +-----BEGIN CERTIFICATE----- +MIICRTCCAcugAwIBAgIUHTAeXakkTyAFDkZfyu8YyCO9ubgwCgYIKoZIzj0EAwIw +TzEmMCQGA1UEAwwdU1NMLmNvbSBDMlBBIEVDQyBSb290IENBIDIwMjUxGDAWBgNV +BAoMD1NTTCBDb3Jwb3JhdGlvbjELMAkGA1UEBhMCVVMwIBcNMjUwNzE4MTU1MTQ5 +WhgPMjA1MDA3MTIxNTUxNDlaME8xJjAkBgNVBAMMHVNTTC5jb20gQzJQQSBFQ0Mg +Um9vdCBDQSAyMDI1MRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xCzAJBgNVBAYT +AlVTMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEo3WOe9pIesN2XWe6KQdiUO+cU1mr ++Bs8opia0I+IA5m8oYhBJmJWPxLea7PH6tlW6f5wqkIOaeJkJ7X1pz3IHPjO8qkX +imKjiUwt/B7IoEj6rhoqkAV4AMO2BMxbS1MUo2YwZDASBgNVHRMBAf8ECDAGAQH/ +AgECMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUU50WGoV8zfcRPowvdPbBkJ1O +g6swHwYDVR0jBBgwFoAUU50WGoV8zfcRPowvdPbBkJ1Og6swCgYIKoZIzj0EAwID +aAAwZQIxALxN0Q+F+9KXOnYUKcW70UuxgitT8iwjTBGCIXJbJw4XaMtVdVGf4HwY +NITBgr+rWwIwczO4trazVV27OTCl8xNR0IH4UuyFgBVuzMsIj8IPkQw5mVhtvhY7 +nNgp3Dyy2LeE +-----END CERTIFICATE----- + +Subject emailAddress=ca@trufo.ai, CN=Trufo C2PA Root CA (2025, ECC P384), OU=CA Division, O=Trufo Inc., L=New York, ST=New York, C=US +-----BEGIN CERTIFICATE----- +MIIDOTCCAr6gAwIBAgIUbXqcPd1r9yQm/fznG9RlSWyXiwswCgYIKoZIzj0EAwMw +gagxCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhOZXcgWW9yazERMA8GA1UEBwwITmV3 +IFlvcmsxEzARBgNVBAoMClRydWZvIEluYy4xFDASBgNVBAsMC0NBIERpdmlzaW9u +MRowGAYJKoZIhvcNAQkBFgtjYUB0cnVmby5haTEsMCoGA1UEAwwjVHJ1Zm8gQzJQ +QSBSb290IENBICgyMDI1LCBFQ0MgUDM4NCkwHhcNMjUxMjMwMTkwNTAzWhcNNDUx +MjI1MTkwNTAzWjCBqDELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5ldyBZb3JrMREw +DwYDVQQHDAhOZXcgWW9yazETMBEGA1UECgwKVHJ1Zm8gSW5jLjEUMBIGA1UECwwL +Q0EgRGl2aXNpb24xGjAYBgkqhkiG9w0BCQEWC2NhQHRydWZvLmFpMSwwKgYDVQQD +DCNUcnVmbyBDMlBBIFJvb3QgQ0EgKDIwMjUsIEVDQyBQMzg0KTB2MBAGByqGSM49 +AgEGBSuBBAAiA2IABAp0qnhIwMtN6LeGdBVtHLPn85ecetr/lqcXFk8ypK9ukJzU +8LLv55Kh/MYTgEnuIKEOPhDxLDRdahc0mAjRnql4kLk395abw9WZjrBPek3qjv0q +ITR8VPYFABuZ5FRKx6OBpjCBozAdBgNVHQ4EFgQUA9Vfr36D5QQdWYAnSjT/Rf3r +SXgwHwYDVR0jBBgwFoAUA9Vfr36D5QQdWYAnSjT/Rf3rSXgwEgYDVR0TAQH/BAgw +BgEB/wIBAjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgorBgEEAYPoPAEB +MCQwIgYIKwYBBQUHAgEWFmh0dHBzOi8vdHJ1Zm8uYWkvY3BjcHMwCgYIKoZIzj0E +AwMDaQAwZgIxAMUeYWZyxS2maiVkNETL29RAuLn/gHYTkt97l6evXwHLN46v28mI +39BIf6slyWnrCwIxAPRs/FJ+DoA0d/PCkrF946S+pG7vRqLnjB9OhMdmrMPvzaqx +KQYOBVx7SE4Kz48W8A== +-----END CERTIFICATE----- + +Subject CN=vivo Content Provenance and Authenticity Root CA, O=vivo Mobile Communication Co., Ltd., C=CN +-----BEGIN CERTIFICATE----- +MIIC0zCCAjSgAwIBAgIJAMIN3t2/xTDAMAoGCCqGSM49BAMEMHYxOTA3BgNVBAMM +MHZpdm8gQ29udGVudCBQcm92ZW5hbmNlIGFuZCBBdXRoZW50aWNpdHkgUm9vdCBD +QTEsMCoGA1UECgwjdml2byBNb2JpbGUgQ29tbXVuaWNhdGlvbiBDby4sIEx0ZC4x +CzAJBgNVBAYTAkNOMCAXDTI1MDkxODA5MDkxM1oYDzIwNTUwOTExMDkwOTEzWjB2 +MTkwNwYDVQQDDDB2aXZvIENvbnRlbnQgUHJvdmVuYW5jZSBhbmQgQXV0aGVudGlj +aXR5IFJvb3QgQ0ExLDAqBgNVBAoMI3Zpdm8gTW9iaWxlIENvbW11bmljYXRpb24g +Q28uLCBMdGQuMQswCQYDVQQGEwJDTjCBmzAQBgcqhkjOPQIBBgUrgQQAIwOBhgAE +ANQigNuQ6RnYFSK2BWkaksR3fRFFytX4nzX3E4hLV/N/7m/XttNHxNDase0cAXwR +9pO23p6fb/9NbifILv2wzPn2ASMr306Y2frv/UjJ5J6WgHet2OFywRaPjFjJWRuk +4JCy0qoSxyyx230g8GYdacZzIqSzVTW7/Xz4mjnWDTOB/Db+o2YwZDASBgNVHRMB +Af8ECDAGAQH/AgECMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUgB0dwwUcpK4u +7az42vKC2y+nnY8wHwYDVR0jBBgwFoAUgB0dwwUcpK4u7az42vKC2y+nnY8wCgYI +KoZIzj0EAwQDgYwAMIGIAkIB9cjlRbw8I0+0VAIOENCEzKOfp2risHuo3KVqyaSV +K/T6KzMNvpq3ihA6ZjnuH9i5y5XWV//awWbFJDSuT0Bq+pwCQgHuthBjGmDl/nyc +r3MxJErDVYZBh4b140LQBU60MtiPERVYwme03ukGImPW/OKbEWYmnhHyMAf1ym/3 +UK/lOv3G2w== +-----END CERTIFICATE----- + +Subject CN=Xiaomi Root CA(EC-P384), O=Xiaomi Inc., L=Beijing, ST=Beijing, C=CN +-----BEGIN CERTIFICATE----- +MIICeDCCAf6gAwIBAgITAJQBmyrWaBV3JOroB8uDgC0MxDAKBggqhkjOPQQDAzBp +MQswCQYDVQQGEwJDTjEQMA4GA1UECBMHQmVpamluZzEQMA4GA1UEBxMHQmVpamlu +ZzEUMBIGA1UEChMLWGlhb21pIEluYy4xIDAeBgNVBAMTF1hpYW9taSBSb290IENB +KEVDLVAzODQpMCAXDTI1MDkyNTAxMjI0MFoYDzIwNTAwOTE5MDEyMjQwWjBpMQsw +CQYDVQQGEwJDTjEQMA4GA1UECBMHQmVpamluZzEQMA4GA1UEBxMHQmVpamluZzEU +MBIGA1UEChMLWGlhb21pIEluYy4xIDAeBgNVBAMTF1hpYW9taSBSb290IENBKEVD +LVAzODQpMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEDOfbCvQLZmlcAW7uOnEiCJ3K +pVxu+qYxrwBDbSIRsDc2xg9o94+8pX+mveme5SsSsKM/0ouu5+ECwhkxRof/1BDQ +21cK+n4HBY0G7P3RltI6moeDv4bdVvC4ni+yJpFvo2YwZDAdBgNVHQ4EFgQUm8DQ +DCIUeaz1o+Cc286YCgebcc4wHwYDVR0jBBgwFoAUm8DQDCIUeaz1o+Cc286YCgeb +cc4wEgYDVR0TAQH/BAgwBgEB/wIBAjAOBgNVHQ8BAf8EBAMCAQYwCgYIKoZIzj0E +AwMDaAAwZQIwUfj3heoA8iZfAMqHrZwarUM71v3Y1gqlltdgOzv9mix5O/EDxHcQ +m26a9NrrMTXmAjEAgwjR42dkym44QlV+QXR05vuMf1o/bdAXmJKvhjDgPTK9VYRa +gFLaTqFtjuZfDg3L +-----END CERTIFICATE----- + +Subject CN=DigiCert RSA4096 Root for C2PA G1, O=DigiCert, Inc., C=US +-----BEGIN CERTIFICATE----- +MIIFljCCA36gAwIBAgIQL2uv995UIpTpN6WRLwYnHDANBgkqhkiG9w0BAQwFADBS +MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xKjAoBgNVBAMT +IURpZ2lDZXJ0IFJTQTQwOTYgUm9vdCBmb3IgQzJQQSBHMTAgFw0yNTA4MjcwMDAw +MDBaGA8yMDUwMDgyNjIzNTk1OVowUjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRp +Z2lDZXJ0LCBJbmMuMSowKAYDVQQDEyFEaWdpQ2VydCBSU0E0MDk2IFJvb3QgZm9y +IEMyUEEgRzEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDTX44Mw12/ +in3jeV80FcoutZhxtvhZQHAdiFtiYd9Y+quavnHRqtcexRZQ0n1XtGXeiusE72M6 +G4dwdTsHXoXVNXjwrO9a/fA/46u+/T5ZU6FyRQdahwQNIXL5PVfqrjwX2Ta2Gby2 +z4tbhfzxtgJSosJGJsCGq5mGiBXIqBkbua0YOvuX1WifAuDQun84bw+qwCCWxSty +QuUcZMm6xl24ye5RZnz8xkctz/p68kgNa9IhJlHrZ3CAe1zEu3PrNS7Oq/uzN06t +Ji6rkpXCV6GlhN0RlEPmUb3pg8kYqQ9uca7u4UTyl/F9QqG2xMDgAtNDrfNbWpyO +fnoYGNQvQyD5M7slsz9j9sUcKwspaz8zmuu31UXPqmvME+UalDvFeknQZP+ft9Uv +8eICovCQxvy1Iwg3sjc2hO0lbYYn/JqGARg+5jP/SlkY4dSypdYBtBaAfVxTd+iQ +m4k1oAEIP7ujyQ+1U0F9gygQPwQrMOcyYINgkcsp36rb1znuxlIF6LIcfO1bkVSx +vHqd0CVP8vwrYXKJOr4dES1s4k12kxv+csvZWiuSqY0uhFUSMSE5id5zWW7H6ZCX +3J3Ati2MjyRjyyejDbTQdTS3wlF4f4bLaWidMWSZ3JCyZABXpj46RtdbhZgV7I7B +ZTXCI6FIBuUaiZzW9RHhVzR+qrfBOx40mwIDAQABo2YwZDASBgNVHRMBAf8ECDAG +AQH/AgECMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUVusnOJo+SNZygIWbesMH +UVoE8+UwHwYDVR0jBBgwFoAUVusnOJo+SNZygIWbesMHUVoE8+UwDQYJKoZIhvcN +AQEMBQADggIBAIjcpKt4FeVibq6zP1m2RUagL6PEW+8o5CC5kv0mDMcCgqNTsyNJ +lr/1yYzzpEC82QaCZ34g4eMXnOwq+5jF5xQ5b7RV7X9nFuPXh7r2CittMkBLPKp/ +jSApyfEI2qgNtPWc5voKRgPrkSuHu+wB5gTg7AkN9CCZeaauMesIIn7/8lWOSho9 +a5DVCJekYh+WcfnSP6l0ilRw1WhnAtPwadhcQ9zJxKe6LSdsH3yNJhViIQNrBhlA +O3BNZF1q2JfOM6TCiY/I+M8AfzuvxF/xyxeDlcRNo6QbfAvUybDOsleg9NxO+EK3 +VXTInzaWidoX9TRdEx0iiERj9OB7ehZBwTUllBH6UtxFy3X7YRSnO8ZdjtEERJmk +BNZztgd4KWBnaFMERI0ObiqN1az0uqe8sRULEJ1Ay79sTsJtiemNChMxmYb83XU1 +1wSX/W54tD6vPQPCwn84AeLgYSfA10QwRyAo99pwmjZzrCx5uBH7jCVYBkP7iQ6h +o3yHror7znE8LJrrWytOuumEFzxQ0NSaXjrDRKCLKTKnr8niIj+lB/SJsBua52a6 +HHRckrpDokgPSPOYI4A+ZGC//Ron9i3S8ce2dQHAWNCqB2ADtnu4Yf36OfmHdrCL +hzIxlPKKDPXwgxv7NTRFs1d7KcIpjYuZp71eZA74ZqxDgVa7CMkhdgML +-----END CERTIFICATE----- + +Subject CN=DigiCert ECC P384 Root for C2PA G1, O=DigiCert, Inc., C=US +-----BEGIN CERTIFICATE----- +MIICSTCCAc+gAwIBAgIQCZ2yarc/T5eBQYVHCJTdyjAKBggqhkjOPQQDAzBTMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xKzApBgNVBAMTIkRp +Z2lDZXJ0IEVDQyBQMzg0IFJvb3QgZm9yIEMyUEEgRzEwIBcNMjUwODI3MDAwMDAw +WhgPMjA1MDA4MjYyMzU5NTlaMFMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdp +Q2VydCwgSW5jLjErMCkGA1UEAxMiRGlnaUNlcnQgRUNDIFAzODQgUm9vdCBmb3Ig +QzJQQSBHMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABNHiy4U9/SpPSnQ3ogU+q3mn +M/f9zmLuqF8krS0LNUC0T81Nu57WCGSb6149CVpkRRC6BYlfGcBWVYXar4aX10oX +ggSiFPi93ovkAfUN9wikKqVu6amI7tRQPKXJ95UsFaNmMGQwEgYDVR0TAQH/BAgw +BgEB/wIBAjAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFPQYEa4JgolO/Ju0M/b0 +370CTpQ2MB8GA1UdIwQYMBaAFPQYEa4JgolO/Ju0M/b0370CTpQ2MAoGCCqGSM49 +BAMDA2gAMGUCMQCg31cyC7If2VPMUvqEr08WB6QhRVpAa+GNRlKUOJlSMq/y2tm+ +80RTxpV2RsYC9UsCMGkKQ0Yx4FIs1RhYtXVIgTyHrSxGne4/457DlIS+IMIJN5Yd +gMNj6G6tzM47QDGl2w== +-----END CERTIFICATE----- + +Subject CN=DigiCert RSA4096 L1 Claim Signing ICA for C2PA G1, O=DigiCert, Inc., C=US +-----BEGIN CERTIFICATE----- +MIIGxDCCBKygAwIBAgIQJ4BVBbBmDXnyAtI0JLlo5TANBgkqhkiG9w0BAQwFADBS +MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xKjAoBgNVBAMT +IURpZ2lDZXJ0IFJTQTQwOTYgUm9vdCBmb3IgQzJQQSBHMTAeFw0yNTA4MjcwMDAw +MDBaFw0zMDA4MjYyMzU5NTlaMGIxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdp +Q2VydCwgSW5jLjE6MDgGA1UEAxMxRGlnaUNlcnQgUlNBNDA5NiBMMSBDbGFpbSBT +aWduaW5nIElDQSBmb3IgQzJQQSBHMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC +AgoCggIBAKiOlc644cuaOoCElG+yGHBmAtfXRw3fSBfRTCf/9yaMQiyEGCxP8HKT +fxtdqD8zmXqePLCLzGM2ccGJx3w5RzpFdOhopwGIKsTm+C1wHmZc5Lws5wst7rFQ +stF8nIN9TBP5H6elZcoNaUhqCJ0bxmeXp6J0iiRKiuLF2j0Grfv4cBL8+XlLRE3g +Of1yqEsEZktfK9qeCUuugltxXwL1WP8IKgtkMeLo0QZQSAg4R+gyX6C1j64nlAtV +RewqSrug+Rkquz94doEscaq3w+ypp8pJ9ovpn9Zdx6PArh4uK90YB/ThB92Voi2x +K8T9D8xnzpONwBfKPiUS502160mZuF09Xgm6zBNRPFKmAdhN73QV4i5Hn2rv5104 +AR4QGvz5Egh/bZ5RElIutD/CvVrOS1fykm6ZIVuxqHUx0pxWkAsjRyCE+fuhczhW +QfVy2EUst98kNjUZC/OFF4TxfcWt7xu7CKNZb3rE7nrbMAbPLKPZjAlT7GlmEhaa +dw/Y3ap0sPnO3BtsBP3kOSed3lP3zEfokBLSYsQtwDWzdWanGE3nB2HvBmcviYdi +P48gXP/5uybnVlKUHXb0gBtdYzNTBx3ynoUrWtbNwvMuTKv6mmnuLxhGiEWEK+BY +StlfOiPvUdpyr+TMsaujPpWq9IUX6qmsOcl1gfujK/lJ3kuvSUm3AgMBAAGjggGE +MIIBgDASBgNVHRMBAf8ECDAGAQH/AgEAMBcGA1UdIAQQMA4wDAYKKwYBBAGD6F4B +ATAOBgNVHQ8BAf8EBAMCAQYwgYYGCCsGAQUFBwEBBHoweDAoBggrBgEFBQcwAYYc +aHR0cDovL29jc3Aub25lLmRpZ2ljZXJ0LmNvbTBMBggrBgEFBQcwAoZAaHR0cDov +L2NhY2VydHMub25lLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFJTQTQwOTZSb290Zm9y +QzJQQUcxLmNydDBNBgNVHR8ERjBEMEKgQKA+hjxodHRwOi8vY3JsLm9uZS5kaWdp +Y2VydC5jb20vRGlnaUNlcnRSU0E0MDk2Um9vdGZvckMyUEFHMS5jcmwwKQYDVR0l +BCIwIAYKKwYBBAGD6F4CAQYIKwYBBQUHAwQGCCsGAQUFBwMkMB0GA1UdDgQWBBTC +mxzaIdNwH6lU5HUf8IFpzcgbRTAfBgNVHSMEGDAWgBRW6yc4mj5I1nKAhZt6wwdR +WgTz5TANBgkqhkiG9w0BAQwFAAOCAgEAt8Kn2LQMxbL10BAx5ebm1G/TMTrgQN9y +f18ZE5qNk3ipoFFtijZzRT5zidKi+/956V11nPMgm90W/CMtapHImj3Da4eoShzl +7N6hPjGYuHJUFfCYaJFxgz0r2sdFYc0drpOlfLa+WVUmgXM8QhbWiHcyk37z8Ega +6p1fjFVH6QqKWwXhSuR5aH0QflBHJKdWRkRZSTNBU2Hj1FOqhZBPPM+jvLGWgkQg +hpQTrO9pTILZ0nb3rTkvClimBewUwTkjoB8M4UHifHcXJ7/RnFzj+KHR5kWdzVTz +uCLcIlTNeACYQZaAj/eT9vzI1n6IUoU04R/9STijYHr05VbH1jM94rDJzjE8Hjf+ +f8YV9X/38Rc3gcH1hLzAKqwIyF/XieaquJLXY90O1Ads/WTrNRlf5A4109FKnELd +w8R9vOneDvslbrHxu/MmoanzJlqxW1Sw6tlU0G2kMfyIH9y0RLmTiJndW9UXyzMU +tGID1N2lhdO0BmwBuzCbZWRHCD0NcP9l5Kc8fCL95OgdpRbivEFeGynZZiCjvrJ9 +tT+uGWQiBbTlEgR57e1KsEPFKxb0M81ewNEo+vhxaSoWvXv84ZM/Zc9a0ZqPMEPr +3073hQvLguizQTWJQstDjzlmOWF7K6hnI70rTNLhZBEFC3XJlBYxbUMlGdH4ebLc +9IUUXRE00ws= +-----END CERTIFICATE----- + +Subject CN=DigiCert ECC P384 L1 Claim Signing ICA for C2PA G1, O=DigiCert, Inc., C=US +-----BEGIN CERTIFICATE----- +MIIDdzCCAv2gAwIBAgIQUhYZxg4djFjAWbZwab2qqTAKBggqhkjOPQQDAzBTMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xKzApBgNVBAMTIkRp +Z2lDZXJ0IEVDQyBQMzg0IFJvb3QgZm9yIEMyUEEgRzEwHhcNMjUwODI3MDAwMDAw +WhcNMzAwODI2MjM1OTU5WjBjMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNl +cnQsIEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IEVDQyBQMzg0IEwxIENsYWltIFNp +Z25pbmcgSUNBIGZvciBDMlBBIEcxMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEJ2hi +wBWq/Dldnu/FxGwfHDAmRxezmmKQtIWSd/HYfiJW2T9wNJmSPywB5Kl7WBJXyaxy +Uwhn8tpDqBypcT0hlN8Mi8Cql9yj9t2MJXN3KshCyBiQWjcKnZoOFhW83E1oo4IB +hDCCAYAwEgYDVR0TAQH/BAgwBgEB/wIBADAXBgNVHSAEEDAOMAwGCisGAQQBg+he +AQEwTQYDVR0fBEYwRDBCoECgPoY8aHR0cDovL2NybC5vbmUuZGlnaWNlcnQuY29t +L0RpZ2lDZXJ0RUNDUDM4NFJvb3Rmb3JDMlBBRzEuY3JsMA4GA1UdDwEB/wQEAwIB +BjCBhgYIKwYBBQUHAQEEejB4MCgGCCsGAQUFBzABhhxodHRwOi8vb2NzcC5vbmUu +ZGlnaWNlcnQuY29tMEwGCCsGAQUFBzAChkBodHRwOi8vY2FjZXJ0cy5vbmUuZGln +aWNlcnQuY29tL0RpZ2lDZXJ0RUNDUDM4NFJvb3Rmb3JDMlBBRzEuY3J0MCkGA1Ud +JQQiMCAGCisGAQQBg+heAgEGCCsGAQUFBwMEBggrBgEFBQcDJDAdBgNVHQ4EFgQU +JqGs/hW9GFhOR/R0fNP8EaPxlocwHwYDVR0jBBgwFoAU9BgRrgmCiU78m7Qz9vTf +vQJOlDYwCgYIKoZIzj0EAwMDaAAwZQIwa6ohDos9g13+HZlgKR45C5K3qug4QUi3 +tHu79IL601lgQSDgpnclOmJOuWxZFxfGAjEA3kAU5JV6no1hQpZdtb11g+B5wCHW +bUVPYZLXZ1Ie2RaND1QmLeYYKbuqsC58ZtSw +-----END CERTIFICATE----- + +Subject CN=Adobe Product Issuing CA vault-a-or2.adobe.net cai, O=Adobe Inc, L=San Jose, ST=California, C=US +-----BEGIN CERTIFICATE----- +MIIDhDCCAwugAwIBAgIUTNz+Jl3kNFEJK5md8Tp/Cwsm/B4wCgYIKoZIzj0EAwMw +bzELMAkGA1UEBhMCVVMxETAPBgNVBAcTCFNhbiBKb3NlMRMwEQYDVQQKEwpBZG9i +ZSBJbmMuMRAwDgYDVQQLEwdQcm9kdWN0MSYwJAYDVQQDEx1BZG9iZSBQcm9kdWN0 +IEludGVybWVkaWF0ZSBDQTAeFw0yNTExMTkxODI5NDRaFw0zMDExMjAwMDMwMTRa +MIGGMTswOQYDVQQDEzJBZG9iZSBQcm9kdWN0IElzc3VpbmcgQ0EgdmF1bHQtYS1v +cjIuYWRvYmUubmV0IGNhaTESMBAGA1UEChMJQWRvYmUgSW5jMQswCQYDVQQGEwJV +UzERMA8GA1UEBxMIU2FuIEpvc2UxEzARBgNVBAgTCkNhbGlmb3JuaWEwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAASArJB/ZRkabuyoSoGy/6JS124LqMOeKRTruZ4GIxZ3 +Rg2UKXeWDINVsgXVewJalg98T0HgeXyXM8Ia0y0dLQUhxT++kVaascgJBuevPs8z +5Z+n+grN03x6ttUORdJ4O9qjggFOMIIBSjASBgNVHRMBAf8ECDAGAQH/AgEAMB8G +A1UdIwQYMBaAFBldp+77+M3A85KlrD7gVNgW7D8UMFsGCCsGAQUFBwEBBE8wTTBL +BggrBgEFBQcwAoY/aHR0cDovL3BraS1jZG4uYWRvYmUubmV0L2NhL2Fkb2JlX2lu +dGVybmFsX2ludGVybWVkaWF0ZV9wcm9kdWN0ME0GA1UdHwRGMEQwQqBAoD6GPGh0 +dHA6Ly9wa2ktY2RuLmFkb2JlLm5ldC9hZG9iZV9pbnRlcm5hbF9pbnRlcm1lZGlh +dGVfcHJvZHVjdDAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFC76762PJu/wKMyE +92MRuG8aw1sIMBcGA1UdIAQQMA4wDAYKKwYBBAGD6F4BATAfBgNVHSUEGDAWBgor +BgEEAYPoXgIBBggrBgEFBQcDBDAKBggqhkjOPQQDAwNnADBkAjAfjQ+ZR+qrZcyW +iOVr07JrjClkluOhKPreYGCIQjRXvZPiFPDorO1df9tEIPmJ2Q4CMAIfpEWAmTsA +ggP/MIJIBoTabnBjhwmUcaqRdjK/LuT3KvwkZzZ6R7iPDkQs0d+dQA== +-----END CERTIFICATE----- + +Subject CN=Irdeto C2PA Root CA G1, O=Irdeto BV, C=NL +-----BEGIN CERTIFICATE----- +MIICLDCCAbGgAwIBAgIUL8JDbqsQllkL9gozEdKhKc9GFAcwCgYIKoZIzj0EAwMw +QjELMAkGA1UEBhMCTkwxEjAQBgNVBAoMCUlyZGV0byBCVjEfMB0GA1UEAwwWSXJk +ZXRvIEMyUEEgUm9vdCBDQSBHMTAgFw0yNTEyMDUxMjQ0NDBaGA8yMDUwMTIwNTEy +NDQ0MFowQjELMAkGA1UEBhMCTkwxEjAQBgNVBAoMCUlyZGV0byBCVjEfMB0GA1UE +AwwWSXJkZXRvIEMyUEEgUm9vdCBDQSBHMTB2MBAGByqGSM49AgEGBSuBBAAiA2IA +BEOtgkWt4t4r3Fvn2vDshY1KcZ63/VTaZN7K2uiAcCeztiH+ZSFf4hA5cSCABRJ+ +VkWZYLvnhNLsCVbtEij6mDN5hf4VIUdUNgUonGZ6tkL1Djs3CUIkjD+nH/HXbCSj +pqNmMGQwEgYDVR0TAQH/BAgwBgEB/wIBAjAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O +BBYEFGs1MrTyCBABc00WKVK0njUakyplMB8GA1UdIwQYMBaAFGs1MrTyCBABc00W +KVK0njUakyplMAoGCCqGSM49BAMDA2kAMGYCMQCB1h+esIhAsddoGkZI1aXwwCFM +wL/cHskaM8JZsvUfcecGQmG08ZVesfUeCzei0SECMQCLjWbR4LY1mgfF+PzlieDZ +9DTcd5qOpJaSf90/8AnQA/UWGtRGqJsrmERInDoXEOA= +-----END CERTIFICATE----- + +Subject emailAddress=ca@tauth.io, CN=Tauth Root CA, OU=CA Division, O=Tauth Labs Inc., L=New York, ST=New York, C=US +-----BEGIN CERTIFICATE----- +MIIDjzCCAxWgAwIBAgIUW6zwDse+LBk8Yvy/u3p7lSjnaA4wCgYIKoZIzj0EAwMw +gZcxCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhOZXcgWW9yazERMA8GA1UEBwwITmV3 +IFlvcmsxGDAWBgNVBAoMD1RhdXRoIExhYnMgSW5jLjEUMBIGA1UECwwLQ0EgRGl2 +aXNpb24xFjAUBgNVBAMMDVRhdXRoIFJvb3QgQ0ExGjAYBgkqhkiG9w0BCQEWC2Nh +QHRhdXRoLmlvMB4XDTI2MDEwNTE2MDgzMVoXDTQ1MTIzMTE2MDgzMVowgZcxCzAJ +BgNVBAYTAlVTMREwDwYDVQQIDAhOZXcgWW9yazERMA8GA1UEBwwITmV3IFlvcmsx +GDAWBgNVBAoMD1RhdXRoIExhYnMgSW5jLjEUMBIGA1UECwwLQ0EgRGl2aXNpb24x +FjAUBgNVBAMMDVRhdXRoIFJvb3QgQ0ExGjAYBgkqhkiG9w0BCQEWC2NhQHRhdXRo +LmlvMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETgpV7Q9tsMzXFPduTyVt71IRRfU0 +yeZGVuXmVO6zyUXxqGCg07jafnMyv24pRwJ9Bk+ROhslNWFS0NhXjIINDuk4h5Ji +KcEEGBJIlGl7jOB/MPLF/HU7CfURT2ayXKXmo4IBHjCCARowHQYDVR0OBBYEFB3R +AQfd1ulUQKBf+J34TnS1CxI+MIHXBgNVHSMEgc8wgcyAFB3RAQfd1ulUQKBf+J34 +TnS1CxI+oYGdpIGaMIGXMQswCQYDVQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsx +ETAPBgNVBAcMCE5ldyBZb3JrMRgwFgYDVQQKDA9UYXV0aCBMYWJzIEluYy4xFDAS +BgNVBAsMC0NBIERpdmlzaW9uMRYwFAYDVQQDDA1UYXV0aCBSb290IENBMRowGAYJ +KoZIhvcNAQkBFgtjYUB0YXV0aC5pb4IUW6zwDse+LBk8Yvy/u3p7lSjnaA4wDwYD +VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwMDaAAwZQIx +AJzhLaivtrjOMyEAuoHQRIhN2u7kw2iWZZyAT6FJH4+GBYudax0dfewXeIvC0MH5 +SwIwAKojdigAO86Xvk6++B875ZpTjQIysPX0bGumbmAwcAmsqum9JLLIRCDz+7Kt +WrRP +-----END CERTIFICATE----- + +Subject CN=HUAWEI C2PA ECC384 Root CA E346, O=Huawei Technologies Co., Ltd., C=CN +-----BEGIN CERTIFICATE----- +MIICoDCCAiagAwIBAgIIKsblXSNLwF8wCgYIKoZIzj0EAwMwXzELMAkGA1UEBhMC +Q04xJjAkBgNVBAoMHUh1YXdlaSBUZWNobm9sb2dpZXMgQ28uLCBMdGQuMSgwJgYD +VQQDDB9IVUFXRUkgQzJQQSBFQ0MzODQgUm9vdCBDQSBFMzQ2MB4XDTI2MDQxMzAx +NTQxMFoXDTQ2MDQwODAxNTQxMFowXzELMAkGA1UEBhMCQ04xJjAkBgNVBAoMHUh1 +YXdlaSBUZWNobm9sb2dpZXMgQ28uLCBMdGQuMSgwJgYDVQQDDB9IVUFXRUkgQzJQ +QSBFQ0MzODQgUm9vdCBDQSBFMzQ2MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEOrBo +SivfM2LRlG3B4r52hE0vDjQR2iWv9sKTZXzkscQIasoH+uYBDDie9VcosH4Mfq/U +xN8ojhW7BZW38LT38SmYpJPZirtzKTyCD4ha4dU8tLcHoJsOn3p+kBw09Bvoo4Gu +MIGrMB8GA1UdIwQYMBaAFM/OyEcEDscO78w/okatAmz35ypMMB0GA1UdDgQWBBTP +zshHBA7HDu/MP6JGrQJs9+cqTDASBgNVHRMBAf8ECDAGAQH/AgECMEUGCCsGAQUF +BwELBDkwNzA1BggrBgEFBQcwBYYpaHR0cDovL2NhLmh1YXdlaWNsb3VkLmNvbS9y +ZXBvc2l0b3J5Lmh0bWwwDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2gAMGUC +MDCsqpRvJIPw6OAQi2Rj0CWnwJgK75YK5gj+K9xomIDu8ai/2ExrifL8JgROQOeZ +egIxAL3tT3Dp84wP18ohYU83gkRcA8j9B3T4BRpxY1Ew9IJMYJ2zqz0weFjAEGNC +9Z36XQ== +-----END CERTIFICATE----- + +Subject CN=Huanyu Trust C2PA EC-384 Root CA, O=Huanyu Trust Ltd, C=CN +-----BEGIN CERTIFICATE----- +MIICTTCCAdOgAwIBAgIUCqsLOXYNHdz0EBDsWKcrsiBcF10wCgYIKoZIzj0EAwMw +UzELMAkGA1UEBhMCQ04xGTAXBgNVBAoTEEh1YW55dSBUcnVzdCBMdGQxKTAnBgNV +BAMTIEh1YW55dSBUcnVzdCBDMlBBIEVDLTM4NCBSb290IENBMCAXDTI2MDQxMzA2 +MDUwOVoYDzIwNTEwNDEzMDYwNTA5WjBTMQswCQYDVQQGEwJDTjEZMBcGA1UEChMQ +SHVhbnl1IFRydXN0IEx0ZDEpMCcGA1UEAxMgSHVhbnl1IFRydXN0IEMyUEEgRUMt +Mzg0IFJvb3QgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARDnAlELrIETK81oB6E +/ZfbkGSH9YPhGdFpXTzDCHD3IsKPQdPPv/mF319XjdrZMECxpH9rbmWGuWrhq6K8 +zIGO27H2MUE658XNu6aO5xcZV/YdAMkG/YWPYo9CmCT4/SujZjBkMBIGA1UdEwEB +/wQIMAYBAf8CAQIwHwYDVR0jBBgwFoAUYc0ZfGc1yTPouBQYj81mEEdaefswHQYD +VR0OBBYEFGHNGXxnNckz6LgUGI/NZhBHWnn7MA4GA1UdDwEB/wQEAwIBBjAKBggq +hkjOPQQDAwNoADBlAjEAqfQxNSnmGxtt1QBKJbaY8AyUiaJxzX5MnH0l/ielnc6D +qBhIcALvKKc3a8MizR01AjB85bwUFBgs6WlIWZ6sFDDbCQzrWpPU11YQnj/mGom7 +yXjL/2axHPWPY2Do/ldP5mc= +-----END CERTIFICATE----- + +Subject CN=Verimago Root CA, O=Verimago LLC, ST=Washington, C=US +-----BEGIN CERTIFICATE----- +MIICTjCCAdSgAwIBAgIVAOFSVdVKiaIUGZlbNzPTi5bS/Gy+MAoGCCqGSM49BAMD +MFQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRUwEwYDVQQKEwxW +ZXJpbWFnbyBMTEMxGTAXBgNVBAMTEFZlcmltYWdvIFJvb3QgQ0EwHhcNMjYwNTE1 +MDE0NjUwWhcNNDYwNTE1MDE0NjUwWjBUMQswCQYDVQQGEwJVUzETMBEGA1UECBMK +V2FzaGluZ3RvbjEVMBMGA1UEChMMVmVyaW1hZ28gTExDMRkwFwYDVQQDExBWZXJp +bWFnbyBSb290IENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAExn74thYXg89OFcXC +obav4kqQAt0YDK4h28ovPP5RJWs77BBRwUhbdb0C6SMVFJ+MuyUK/cBoua+cSIOh +N6prHNqeHbZMi3nzlbVfEbDDWm9hy+OxXtOLlJQYL5zjUgkco2YwZDASBgNVHRMB +Af8ECDAGAQH/AgECMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUAkmvpVkpKvS1 +2ZHgaoysoshW7XowHwYDVR0jBBgwFoAUAkmvpVkpKvS12ZHgaoysoshW7XowCgYI +KoZIzj0EAwMDaAAwZQIwDqzc2oVzZezm4GeER3jPUDWNj4zsqdXciOoGO0JkAHmC +vyUBt8FH9vZK9d6bZ9DEAjEA5eFk9oFV8cm8pyJ2+hKo5ji/iip8A0T5U2GwHQyN +W4GXdTaTwkzPD7X6whoLKKB/ +-----END CERTIFICATE----- + +Subject CN=Verimago Claim Signing Issuing CA, O=Verimago LLC, ST=Washington, C=US +-----BEGIN CERTIFICATE----- +MIIDTDCCAtOgAwIBAgIUNcPH/7deevUcZvKM0EQGUJN99PMwCgYIKoZIzj0EAwMw +VDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xFTATBgNVBAoTDFZl +cmltYWdvIExMQzEZMBcGA1UEAxMQVmVyaW1hZ28gUm9vdCBDQTAeFw0yNjA1MTUw +MTQ2NTBaFw0zMTA1MTUwNzQ2NTBaMGUxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpX +YXNoaW5ndG9uMRUwEwYDVQQKEwxWZXJpbWFnbyBMTEMxKjAoBgNVBAMTIVZlcmlt +YWdvIENsYWltIFNpZ25pbmcgSXNzdWluZyBDQTB2MBAGByqGSM49AgEGBSuBBAAi +A2IABPB0fzGODSoLVNkTQWekSBkL6rD2h2//WP+4f1pdl9K8K0Z8Bt0SrlOXNtrp +I/ytOybRwV7nH3TDAWkZV833jc8Gjgqs7P0Q4ZZc4+4WIey3eD9084B8rLXs3/K/ +q7NyHaOCAVMwggFPMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEG +MCkGA1UdJQQiMCAGCisGAQQBg+heAgEGCCsGAQUFBwMEBggrBgEFBQcDJDAXBgNV +HSAEEDAOMAwGCisGAQQBg+heAQEwHQYDVR0OBBYEFCM0wx5MWMCrBF5eYt8J9b41 +TMwcMB8GA1UdIwQYMBaAFAJJr6VZKSr0tdmR4GqMrKLIVu16MDsGA1UdHwQ0MDIw +MKAuoCyGKmh0dHA6Ly9jYS52ZXJpbWFnby5pby9jcmwvaW50ZXJtZWRpYXRlLmNy +bDBoBggrBgEFBQcBAQRcMFowJgYIKwYBBQUHMAGGGmh0dHA6Ly9jYS52ZXJpbWFn +by5pby9vY3NwMDAGCCsGAQUFBzAChiRodHRwOi8vY2EudmVyaW1hZ28uaW8vY2Vy +dHMvcm9vdC5wZW0wCgYIKoZIzj0EAwMDZwAwZAIwDq2qaR9as+lyVFcwsUTlMIm/ +OGxgW4dqVg7jlsBST+3xvS0nIpZUS7lcF44FVcFdAjA5abgOYS/ie7NXxp3smYtu +FoKzc/V7TAaL0VS/HGB3x7sTa+D6HIY3/ls33Dy/4Gk= +-----END CERTIFICATE----- + +Subject CN=Snowball ECC P384 Root CA for C2PA G1, O=Snowball Technology Co., Ltd., C=CN +-----BEGIN CERTIFICATE----- +MIICiTCCAg6gAwIBAgIUVlsRGj1G9vJ4ws2jMYyFlFcKUokwCgYIKoZIzj0EAwMw +ZTELMAkGA1UEBhMCQ04xJjAkBgNVBAoMHVNub3diYWxsIFRlY2hub2xvZ3kgQ28u +LCBMdGQuMS4wLAYDVQQDDCVTbm93YmFsbCBFQ0MgUDM4NCBSb290IENBIGZvciBD +MlBBIEcxMB4XDTI2MDYxODA5MzkxOVoXDTQ2MDYxMzA5MzkxOVowZTELMAkGA1UE +BhMCQ04xJjAkBgNVBAoMHVNub3diYWxsIFRlY2hub2xvZ3kgQ28uLCBMdGQuMS4w +LAYDVQQDDCVTbm93YmFsbCBFQ0MgUDM4NCBSb290IENBIGZvciBDMlBBIEcxMHYw +EAYHKoZIzj0CAQYFK4EEACIDYgAELJUrcxeVmmYrb8Kl/YVAYYFiyuiqiIa6z/1n +FoCpB2JV/Qkwjdns7rOvLheWBi1s880NcwqD/KD9t9/SOgWTfD+WOAhtPioAql2Y +YUl0toOUzoXaAOB3+HIQRiKsL2RIo38wfTASBgNVHRMBAf8ECDAGAQH/AgECMA4G +A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU6R4F1vboIaKQly8jCAQX2lQhWPQwHwYD +VR0jBBgwFoAU6R4F1vboIaKQly8jCAQX2lQhWPQwFwYDVR0gBBAwDjAMBgorBgEE +AYPoXgEBMAoGCCqGSM49BAMDA2kAMGYCMQD6/xszsnZoYt+gYIsgYKTMFARxRpB5 +N16s2u2hgkuFs4zyLco1z7gOk0mv6EbBkm0CMQCcsqIQnr45MVjDUdn9L//VdGDO +6H+P67vBdmvb3LiLTB+Ey/JYYfnHHIKzJrRG4ls= +-----END CERTIFICATE----- + +Subject CN=Snowball ECC P384 Claim Signing ICA for C2PA G1, O=Snowball Technology Co., Ltd., C=CN +-----BEGIN CERTIFICATE----- +MIIDrjCCAzSgAwIBAgIUMPJ1KkDp+fvHaZOBsdKSnPm/hdowCgYIKoZIzj0EAwMw +ZTELMAkGA1UEBhMCQ04xJjAkBgNVBAoMHVNub3diYWxsIFRlY2hub2xvZ3kgQ28u +LCBMdGQuMS4wLAYDVQQDDCVTbm93YmFsbCBFQ0MgUDM4NCBSb290IENBIGZvciBD +MlBBIEcxMB4XDTI2MDYxODA5NDQ1OVoXDTMxMDYxOTA5NDQ1OVowbzELMAkGA1UE +BhMCQ04xJjAkBgNVBAoMHVNub3diYWxsIFRlY2hub2xvZ3kgQ28uLCBMdGQuMTgw +NgYDVQQDDC9Tbm93YmFsbCBFQ0MgUDM4NCBDbGFpbSBTaWduaW5nIElDQSBmb3Ig +QzJQQSBHMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJvqMpOfFPJuwAV3s2YGMbe7 +mRj48rsUZsJrMSOWU3SnssFtPEWTFh8QyM88zaFuprKC8nm53vnEMkGG+YtmZdBf +zsmayZqs9Rq6EQchDSF2vVNvE9wxAqhKJIawhYSTe6OCAZkwggGVMBIGA1UdEwEB +/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMCkGA1UdJQQiMCAGCisGAQQBg+he +AgEGCCsGAQUFBwMEBggrBgEFBQcDJDAdBgNVHQ4EFgQUt0FFkasBa70GGSB6Ntn5 +2UCzqwYwHwYDVR0jBBgwFoAU6R4F1vboIaKQly8jCAQX2lQhWPQwFwYDVR0gBBAw +DjAMBgorBgEEAYPoXgEBMIGUBggrBgEFBQcBAQSBhzCBhDAtBggrBgEFBQcwAYYh +aHR0cDovL29jc3AuYzJwYS5zbm93YmFsbHRlY2guY29tMFMGCCsGAQUFBzAChkdo +dHRwOi8vY2FjZXJ0cy5jMnBhLnNub3diYWxsdGVjaC5jb20vU25vd2JhbGxFQ0NQ +Mzg0Um9vdENBZm9yQzJQQUcxLmNydDBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8v +Y3JsLmMycGEuc25vd2JhbGx0ZWNoLmNvbS9Tbm93YmFsbEVDQ1AzODRSb290Q0Fm +b3JDMlBBRzEuY3JsMAoGCCqGSM49BAMDA2gAMGUCMQCp0U69fhqepzep6uvRFmGg +e+mgVJX1a2JsC3m+W6GAA62UruIAskoTmrEC0iZXMwYCMAcKDRNtDSwk9balyQ/8 +RUPGGwGS2AvOsUC0H84jMBNCL+DlPg7dJz1gc32QCv9sWA== +-----END CERTIFICATE----- + +Subject CN=Encypher C2PA Root CA 2026, OU=CA Division, O=Encypher Corp., L=San Francisco, ST=California, C=US +-----BEGIN CERTIFICATE----- +MIIDFDCCApqgAwIBAgIUS2zOIYRKaa59snU3NcNFadfTtoAwCgYIKoZIzj0EAwMw +gY4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1T +YW4gRnJhbmNpc2NvMRcwFQYDVQQKDA5FbmN5cGhlciBDb3JwLjEUMBIGA1UECwwL +Q0EgRGl2aXNpb24xIzAhBgNVBAMMGkVuY3lwaGVyIEMyUEEgUm9vdCBDQSAyMDI2 +MB4XDTI2MDUyMjEzNDk1NloXDTQ2MDUxNzEzNDk1NlowgY4xCzAJBgNVBAYTAlVT +MRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMRcw +FQYDVQQKDA5FbmN5cGhlciBDb3JwLjEUMBIGA1UECwwLQ0EgRGl2aXNpb24xIzAh +BgNVBAMMGkVuY3lwaGVyIEMyUEEgUm9vdCBDQSAyMDI2MHYwEAYHKoZIzj0CAQYF +K4EEACIDYgAE27XmRBc4mE0dYfUhLiuPiAnY3tRDMke9evylB+VgyMspT1svR9h3 +KXxr8tml+1oM82US+pw2jJenfUxoUJGVDY/lvwl+4Q+7vawXFd26yPv/CQSnhI+w +05+yiSiwshIOo4G2MIGzMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQD +AgEGMB0GA1UdDgQWBBS3gC7ps3/HLQbb3uuqL4U8gDnKEDAfBgNVHSMEGDAWgBS3 +gC7ps3/HLQbb3uuqL4U8gDnKEDBNBgNVHSAERjBEMEIGCisGAQQBg+heAQEwNDAy +BggrBgEFBQcCARYmaHR0cHM6Ly9jYS5lbmN5cGhlci5jb20vcmVwb3NpdG9yeS9j +cHMwCgYIKoZIzj0EAwMDaAAwZQIwYeb83YEb/Oh9uELuvO9jpb85orRWWQiceqf0 +sCwxtJw07/giyy/hI1BFvbQZcfkLAjEAj8jfwuJSJ9LjeeYL/VXStQWDHewxbIou +IKdYpS9ZBidpsi+01tpQY1j7apLAXMHO +-----END CERTIFICATE----- + +Subject CN=Encypher C2PA Issuing CA 2026, OU=CA Division, O=Encypher Corp., L=San Francisco, ST=California, C=US +-----BEGIN CERTIFICATE----- +MIID6zCCA3GgAwIBAgIUXzMIOXOrlyOjfKthGAPSSBM5n3UwCgYIKoZIzj0EAwMw +gY4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1T +YW4gRnJhbmNpc2NvMRcwFQYDVQQKDA5FbmN5cGhlciBDb3JwLjEUMBIGA1UECwwL +Q0EgRGl2aXNpb24xIzAhBgNVBAMMGkVuY3lwaGVyIEMyUEEgUm9vdCBDQSAyMDI2 +MB4XDTI2MDUyMjEzNDk1NloXDTMxMDUyMzEzNDk1NlowgZExCzAJBgNVBAYTAlVT +MRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMRcw +FQYDVQQKDA5FbmN5cGhlciBDb3JwLjEUMBIGA1UECwwLQ0EgRGl2aXNpb24xJjAk +BgNVBAMMHUVuY3lwaGVyIEMyUEEgSXNzdWluZyBDQSAyMDI2MHYwEAYHKoZIzj0C +AQYFK4EEACIDYgAEINEuEOHZL9o8vKynpXV9O+04syCIj+WeydlgTMJBMhiZ8MhE +yig+4R0kmGpX/RZjgSSQh/aQ4NYpv9SHx1r1t3agJEpfYv/jZB4AfeGC47OiEREe +wKHBWD1cVg6qrFtVo4IBiTCCAYUwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8B +Af8EBAMCAQYwIAYDVR0lBBkwFwYKKwYBBAGD6F4CAQYJKoZIhvcvAQEFMB0GA1Ud +DgQWBBT5K7GC8GHRLCg4CpI6Owg8ubeZ8DAfBgNVHSMEGDAWgBS3gC7ps3/HLQbb +3uuqL4U8gDnKEDA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY2EuZW5jeXBoZXIu +Y29tL2NybC9yb290LWNhLmNybDB1BggrBgEFBQcBAQRpMGcwJwYIKwYBBQUHMAGG +G2h0dHA6Ly9jYS5lbmN5cGhlci5jb20vb2NzcDA8BggrBgEFBQcwAoYwaHR0cDov +L2NhLmVuY3lwaGVyLmNvbS9yZXBvc2l0b3J5L2lzc3VpbmctY2EuY3J0ME0GA1Ud +IARGMEQwQgYKKwYBBAGD6F4BATA0MDIGCCsGAQUFBwIBFiZodHRwczovL2NhLmVu +Y3lwaGVyLmNvbS9yZXBvc2l0b3J5L2NwczAKBggqhkjOPQQDAwNoADBlAjABzhlt +QpFyat0q5DZPJh+XvWnRAUej/4yrnPkQgtZZufnTVg9csupYAtdD8EVvkJ8CMQDK +aReb1d/xaGyypi9HwEqVRaEClhopAogb+8VtoUbBD/3mKv0rGlYOUa9heE2DRkw= +-----END CERTIFICATE----- + +Subject CN=TrustAsia C2PA RSA Root CA, O=TrustAsia Technologies, Inc., C=CN +-----BEGIN CERTIFICATE----- +MIIFqDCCA5CgAwIBAgIUNqYa1cdsY+cp091HGRPKXzrE4kwwDQYJKoZIhvcNAQEM +BQAwWTELMAkGA1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dp +ZXMsIEluYy4xIzAhBgNVBAMMGlRydXN0QXNpYSBDMlBBIFJTQSBSb290IENBMCAX +DTI2MDYwNTAzNTMwMFoYDzIwNTEwNjA1MDM1MjU5WjBZMQswCQYDVQQGEwJDTjEl +MCMGA1UECgwcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5jLjEjMCEGA1UEAwwa +VHJ1c3RBc2lhIEMyUEEgUlNBIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQCvgJqlqXZ+SYbtl9dLK4SQ5Gt9KrPbOmWEeMYnh8UdB3+KzkrG +6PSZ1/s6KDIiEPNH1Sno7UOnTWzZ50Ce3Qq4PKFJBb9iJ0cbtw4qGOjHDhgXhozv +nPQhXy6uiEODKgsKRaZwxT7xer3ZOAbX/30tQDwyAavoEtb+F+o2faYxHwjojUnK +zO0Aaz68h7U5zMHgdMUvkqc0B5NIpoTixCj7Om2X0XROWAFx7ELrVxMmyL4PCWOj +caRXoP5QlDHiIc5Ck9/HD6VYr2jJG/8BFZqk9l+mgNlxjaIbp0D/B3D7WvxcGOFR +qiRJRni3LAsdVAMGPs/msUVBsYnTIEWb1o8qvkKpPOE0OtseEhWIQX4EDTA3Kim1 +xVqcS3+9irfDf7Jda2vOX1mamZa+Y89xCZcG7ce4u0fpE/NOs46dymoG/zU0uUvd +KOtzvddNuDOWymROa6SVG6uETSdVFRsQfR/Dp8MQegVLB6ITAfnXHc3Pn67B1ncs +L359DcwlZkqYGegsz//8ToRAlSSA/9C9vzlXfbGIg2HHtToHcwa6BjDkRpfdm6nk +egfCvoaWT4k/9vDQNXvg8Wee1vpUDKhB7y1SSaSkm+7wr8fV4ovFGSrbygpr0BuG +m+ShU3Vh+8UXAICPntscPAgNXidB9A8Zgib5rJjiVi0sxizPYueAchPQDwIDAQAB +o2YwZDASBgNVHRMBAf8ECDAGAQH/AgECMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4E +FgQUCdViRLQz3hH0IboHIKjSrMMHRYAwHwYDVR0jBBgwFoAUCdViRLQz3hH0IboH +IKjSrMMHRYAwDQYJKoZIhvcNAQEMBQADggIBAHInmN938SAQOkERvIrZDi14uVmZ +P5GgqQ6ZH4BF77RFcQcDl7Id+3WBf1WqSl0zyuq6HulYyM6pWikh0W5K/NBBLlt+ +zXtEHbW71jhAhCKALdbclT+KuqRRQbrzATXPyYB5Jb/7xlUIofilo70+lqNwahsy +Y5F+6XlOZ4JuA84RdfxGdyn/IJlOJ9mc2RbI6aAxMuFcsot483gOYtkU4Og0g9M7 +XsdLT2VXwuVk3hXwc7UWlZUm1Vn6dGmrcSj41wGlw9JGMU87OfzYFseGBDGDc2Xv +njFCY+SBAEWGk4m6ugNGat8OKBVNpnYGp0iNODMtQXJ0aUCvOziFPJY9li08sUDe +HI9ZwLB+yADsaC1gaX4eloRFsIyyl7YRQEY1/EfVw3wnN+XBJYyBw9v1RtpXDh/v +O2ezzXc1sdH/WgXMGGrRdiCAZb5mFkjTEoKXVnkGMn7bnJKuFgDQPWerA24Jck1J +QTuQBXJOAt8FVaYMjL6wPSIv84UjVXIRkOP4ZOydpYgykEl5LfOWcQtA4U6h+obS +35aB8YE1KC9rIeEE8q5onGo6tRYJzh+mB/XSUP35fNbwe4FkI3I6ZpNSS6wt9HY0 +DCYCNhAz7KP8RwexR/stlYyeUxbj3+jxK4AOGTZQEKBBWkoqfrPCDpybwpXCxxP5 +qtj6+iKCvpx9jmvr +-----END CERTIFICATE----- + +Subject CN=TrustAsia C2PA ECC Root CA, O=TrustAsia Technologies, Inc., C=CN +-----BEGIN CERTIFICATE----- +MIICWjCCAd+gAwIBAgIUdUWMu3G69tNb9bwz/0KTupxLm1kwCgYIKoZIzj0EAwMw +WTELMAkGA1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMs +IEluYy4xIzAhBgNVBAMMGlRydXN0QXNpYSBDMlBBIEVDQyBSb290IENBMCAXDTI2 +MDYwNTAzNTAwMFoYDzIwNTEwNjA1MDM0OTU5WjBZMQswCQYDVQQGEwJDTjElMCMG +A1UECgwcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5jLjEjMCEGA1UEAwwaVHJ1 +c3RBc2lhIEMyUEEgRUNDIFJvb3QgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQL +ERY0d7ug9MiCqmXnDjDs2med9zfTqTWOcG3OD5Q6FSEgNUcjT5Qy7xzKn1MfqaY4 +Ye3sf+Do7cCDR6AiFW6SqLQobfJ70jMDsSQYlrCCjMLvb+NdNPhED43s8fgehxyj +ZjBkMBIGA1UdEwEB/wQIMAYBAf8CAQIwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQW +BBT13DKCd7Jlz2rEe0vBlwo/CoR2mDAfBgNVHSMEGDAWgBT13DKCd7Jlz2rEe0vB +lwo/CoR2mDAKBggqhkjOPQQDAwNpADBmAjEAwp2Jie8k6/haTc/df3QsX+Ttg7Wp +ARtYTwJSP4Z+ggpf39sZ+7QPOE50BqBj9Q6zAjEAjZ+5glED9tav6r3jWuMOmKTB +kobBXzvjqTDLGG570BbSQfNmS3HRC6u5YTIpElpb +-----END CERTIFICATE----- + +Subject CN=RealReel C2PA Root CA, O=Whole Earth Labs LLC, C=US +-----BEGIN CERTIFICATE----- +MIICPzCCAcWgAwIBAgIUK7g4QvDKVbdq1t88l76ZMwiegK0wCgYIKoZIzj0EAwMw +TDELMAkGA1UEBhMCVVMxHTAbBgNVBAoMFFdob2xlIEVhcnRoIExhYnMgTExDMR4w +HAYDVQQDDBVSZWFsUmVlbCBDMlBBIFJvb3QgQ0EwIBcNMjYwNzI0MDAyNzAyWhgP +MjA1MTA3MjQwMDI3MDJaMEwxCzAJBgNVBAYTAlVTMR0wGwYDVQQKDBRXaG9sZSBF +YXJ0aCBMYWJzIExMQzEeMBwGA1UEAwwVUmVhbFJlZWwgQzJQQSBSb290IENBMHYw +EAYHKoZIzj0CAQYFK4EEACIDYgAEJVWLUwyoBcqwmv3cUuX4/fpVanvQdjJKG4Ca +zLx5XO/eu7qgxCurzpLTuRAC3Lr+tY4LA5shXTSFYqNRRlQnxkYugqEfqDJcUhks +1evDAlYZdBB3X134zjk9DHQElntEo2YwZDASBgNVHRMBAf8ECDAGAQH/AgEBMA4G +A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoaV/7ghFZ89nsoENzOrkL+Pmwg0wHwYD +VR0jBBgwFoAUoaV/7ghFZ89nsoENzOrkL+Pmwg0wCgYIKoZIzj0EAwMDaAAwZQIw +F8nY6P9IvWgtd9dKjnelTOZwICUuxVHbd/uHvU9hjwez+B33zyL1iP+8E/HUe9yD +AjEAmUnK720BAi3UXkj8kZHs74wnIy4oh8buxmiecO1akF4I3B+0+18SkclV6ytF ++Zms +-----END CERTIFICATE----- + +Subject CN=Castlabs C2PA ECC P-384 Root CA, OU=C2PA Trust Infrastructure, O=Castlabs, L=Berlin, ST=Berlin, C=DE +-----BEGIN CERTIFICATE----- +MIICyDCCAk2gAwIBAgIUN5SkK2Lb2Ts/j1AC3K8Y3eVydFQwCgYIKoZIzj0EAwMw +gZAxKDAmBgNVBAMMH0Nhc3RsYWJzIEMyUEEgRUNDIFAtMzg0IFJvb3QgQ0ExCzAJ +BgNVBAYTAkRFMQ8wDQYDVQQHDAZCZXJsaW4xETAPBgNVBAoMCENhc3RsYWJzMSIw +IAYDVQQLDBlDMlBBIFRydXN0IEluZnJhc3RydWN0dXJlMQ8wDQYDVQQIDAZCZXJs +aW4wHhcNMjYwNzA4MDE0NDMwWhcNMzYwNzA1MDE0NDMwWjCBkDEoMCYGA1UEAwwf +Q2FzdGxhYnMgQzJQQSBFQ0MgUC0zODQgUm9vdCBDQTELMAkGA1UEBhMCREUxDzAN +BgNVBAcMBkJlcmxpbjERMA8GA1UECgwIQ2FzdGxhYnMxIjAgBgNVBAsMGUMyUEEg +VHJ1c3QgSW5mcmFzdHJ1Y3R1cmUxDzANBgNVBAgMBkJlcmxpbjB2MBAGByqGSM49 +AgEGBSuBBAAiA2IABPXhd9L+pjQVnUXH6I7+oFSrd6JpO4A+CYDm/AuDZgJvwiuJ +lrM9dC3CAE7UAK8IcQEo85qzuak0TfLdPaJWD26+q3tJ/S7NW4sOKhH09KRN7iFq +XbsOe8FOxaQql/UrMqNmMGQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYB +Af8CAQIwHQYDVR0OBBYEFHNKe2PoAANQBj4/25eRv2VY4Fy7MB8GA1UdIwQYMBaA +FHNKe2PoAANQBj4/25eRv2VY4Fy7MAoGCCqGSM49BAMDA2kAMGYCMQDUlNJD49Ux +zwBccYHiz0wgmbIXBDdgpVrLfWTQnbi21BhfPBQ6j0HJ24FY36L5oj8CMQCv5+bK +gBIkJq9USBx2FjjDkukYjQMI/WDD6SH6QGTdotsH3cQQ6bjr9C+0ruxxx08= +-----END CERTIFICATE----- + diff --git a/public/trust/C2PA-TSA-TRUST-LIST.pem b/public/trust/C2PA-TSA-TRUST-LIST.pem new file mode 100644 index 0000000..30de202 --- /dev/null +++ b/public/trust/C2PA-TSA-TRUST-LIST.pem @@ -0,0 +1,496 @@ +Subject CN=Google C2PA Core Time-Stamping ICA G3, O=Google LLC, C=US +-----BEGIN CERTIFICATE----- +MIICzzCCAlagAwIBAgIURQCDbnITAsVkpJ5kM3b6jwm3ZPQwCgYIKoZIzj0EAwMw +QzELMAkGA1UEBhMCVVMxEzARBgNVBAoMCkdvb2dsZSBMTEMxHzAdBgNVBAMMFkdv +b2dsZSBDMlBBIFJvb3QgQ0EgRzMwHhcNMjUwNTA4MjIzNjI2WhcNNDAwNTA4MjIz +NjI2WjBSMQswCQYDVQQGEwJVUzETMBEGA1UECgwKR29vZ2xlIExMQzEuMCwGA1UE +AwwlR29vZ2xlIEMyUEEgQ29yZSBUaW1lLVN0YW1waW5nIElDQSBHMzB2MBAGByqG +SM49AgEGBSuBBAAiA2IABKN99/G9CCofRVkl4FL5qSDf/tsuj0Uh2E8K1c0Dcd1n +KixZbsCcJDJyInm5ApFfuabKR5+nxTRzE35exSVE6TEijjTVuBb+GsGrM+rGISwj +T/8B5ODBf/A4a8VyrSVLCqOB+zCB+DAXBgNVHSAEEDAOMAwGCisGAQQBg+heAQEw +DgYDVR0PAQH/BAQDAgEGMBMGA1UdJQQMMAoGCCsGAQUFBwMIMBIGA1UdEwEB/wQI +MAYBAf8CAQAwZAYIKwYBBQUHAQEEWDBWMCwGCCsGAQUFBzAChiBodHRwOi8vcGtp +Lmdvb2cvYzJwYS9yb290LWczLmNydDAmBggrBgEFBQcwAYYaaHR0cDovL2MycGEt +b2NzcC5wa2kuZ29vZy8wHwYDVR0jBBgwFoAUnFzYiVND51rVgdsD3hl/BCoqLaow +HQYDVR0OBBYEFN5Vl4xgdDsD4mq0RAZll2HK5fiOMAoGCCqGSM49BAMDA2cAMGQC +MEHGBo0dSnwBldblTYF0fGBdzHBCW0oRhGP/pYfclCTYgcyo+UdR5nYuiHZpKFhQ +cQIwcAumLdMem8XpEJsAEedT9O0lo+ksaufwbJ93BVh5HG3h37rxij8nE064uhpS +PiMt +-----END CERTIFICATE----- + +Subject CN=Google C2PA Pixel Time-Stamping ICA G3, O=Google LLC, C=US +-----BEGIN CERTIFICATE----- +MIIC0TCCAlegAwIBAgIUP2ie1DhmCwB0kqG0zYX4MkF5VsgwCgYIKoZIzj0EAwMw +QzELMAkGA1UEBhMCVVMxEzARBgNVBAoMCkdvb2dsZSBMTEMxHzAdBgNVBAMMFkdv +b2dsZSBDMlBBIFJvb3QgQ0EgRzMwHhcNMjUwNTA4MjIzNjQ1WhcNNDAwNTA4MjIz +NjQ1WjBTMQswCQYDVQQGEwJVUzETMBEGA1UECgwKR29vZ2xlIExMQzEvMC0GA1UE +AwwmR29vZ2xlIEMyUEEgUGl4ZWwgVGltZS1TdGFtcGluZyBJQ0EgRzMwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAAQ+8JePdivzSowun2WW4rDH0LXX9Iurbgh3xNHoKtIw +ei3+ayp1TC1AKjLbF+ZeNxLXHGaF6lwC20eGLp/gK7moar9ob8ltCnWFZXTZE1gK +BMORiCbTf1iVnRUykBcdr8ajgfswgfgwFwYDVR0gBBAwDjAMBgorBgEEAYPoXgEB +MA4GA1UdDwEB/wQEAwIBBjATBgNVHSUEDDAKBggrBgEFBQcDCDASBgNVHRMBAf8E +CDAGAQH/AgEAMGQGCCsGAQUFBwEBBFgwVjAsBggrBgEFBQcwAoYgaHR0cDovL3Br +aS5nb29nL2MycGEvcm9vdC1nMy5jcnQwJgYIKwYBBQUHMAGGGmh0dHA6Ly9jMnBh +LW9jc3AucGtpLmdvb2cvMB8GA1UdIwQYMBaAFJxc2IlTQ+da1YHbA94ZfwQqKi2q +MB0GA1UdDgQWBBSnltnit0LAWi0rd0qr3tBEM58EuzAKBggqhkjOPQQDAwNoADBl +AjEAsVIYGAu0tVemHYqq082P164T0B6NWstqZU2RTv8ZMV21tdBJYwnwDWWSYLmF +8s7kAjA59j5cHDebfKTUPcnxyhMUIJJ+qU6x8wM5E86O0FZyhb2G/kr3HrLkqzmB +Mo9QvzU= +-----END CERTIFICATE----- + +Subject CN=Google C2PA Root CA G3, O=Google LLC, C=US +-----BEGIN CERTIFICATE----- +MIICLjCCAbOgAwIBAgIUUZK4AROFKiXQZ1UG7FG6qPGc1g8wCgYIKoZIzj0EAwMw +QzELMAkGA1UEBhMCVVMxEzARBgNVBAoMCkdvb2dsZSBMTEMxHzAdBgNVBAMMFkdv +b2dsZSBDMlBBIFJvb3QgQ0EgRzMwIBcNMjUwNTA4MjIzMjIxWhgPMjA1MDA1MDgy +MjMyMjFaMEMxCzAJBgNVBAYTAlVTMRMwEQYDVQQKDApHb29nbGUgTExDMR8wHQYD +VQQDDBZHb29nbGUgQzJQQSBSb290IENBIEczMHYwEAYHKoZIzj0CAQYFK4EEACID +YgAEhv9f/juKcPpe3Fm7eAISMuSyS+tBxn0aYHC83J+qAsFWREGN9p6PN/OBoouP +zpOFRxvrlWoWmAI3p1lXyPg4E3eg7SNChgopUIpihGu6qlhP8rLXf3p8bhI5FTQ2 +MaF2o2YwZDASBgNVHRMBAf8ECDAGAQH/AgECMA4GA1UdDwEB/wQEAwIBBjAfBgNV +HSMEGDAWgBScXNiJU0PnWtWB2wPeGX8EKiotqjAdBgNVHQ4EFgQUnFzYiVND51rV +gdsD3hl/BCoqLaowCgYIKoZIzj0EAwMDaQAwZgIxAIyVEe5bdUMkk6BthEWy9QSE +Mb74BOyK8/8pgMX0NPwLlo1ikLNY78ov+k21vZrEZQIxANQ91muDXgPjAMAkzAlK +i32Z9VBB37ynTveKVC7ofTW0ZFfIIYYpWUR1+C4m2yRkOQ== +-----END CERTIFICATE----- + +Subject CN=SSL.com C2PA RSA Root CA 2025, O=SSL Corporation, C=US +-----BEGIN CERTIFICATE----- +MIIFlDCCA3ygAwIBAgIUExeshkq/ESresWEq3YWcEUTmxvowDQYJKoZIhvcNAQEL +BQAwTzEmMCQGA1UEAwwdU1NMLmNvbSBDMlBBIFJTQSBSb290IENBIDIwMjUxGDAW +BgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjELMAkGA1UEBhMCVVMwIBcNMjUxMTA3MTYy +NzEzWhgPMjA1MDExMDExNjI3MTNaME8xJjAkBgNVBAMMHVNTTC5jb20gQzJQQSBS +U0EgUm9vdCBDQSAyMDI1MRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xCzAJBgNV +BAYTAlVTMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA07LXx05AgfZn +F6CPMzpPwA+vGxfqi2Pw3/gvhAe4UdzmasSutCRK9sK66DZYta4AbYPS0/2IToqo +1n33f9/XrmQ62uM3XAyKXfg8UWUaj2WsyA3dIxY5l80B0S0EX0V1HpP6ygw1IDfJ +/KKkknn/0o14zmNkRzLpqQDOMoL4s+kli8NtkEOG8M8NrH5QJCNRL7lN0DG8TvRa +10Zfwyxnd4yw9DT2HWJInjC+Hww9QZua/u6bTy0pFHV0vVCgKQuPtbX8b60998t4 +b56trGesWapUefIEu6GH1CkQu7nhsk1Rf59+uPv1NQLOm7wbyghHtQQ00baR/687 +r7/qXxRLV1CFNH3nAgFfHkD8N07GWS5C1OOmkUPrc2f9tdKWOJ6USDJCOX1DkTee +o9RgwSJfLueDtAOp19dlBo2UW79A2MGN6VI119DoW04VUjxmPHLIWtt08ZRTHzvN +2I2DA3ic5Wt4pgSLXDZ6ztlFX4Y6nXwVFdWae9zwLpm9ttsF4fepLyPAUTuT9m0j +/oeQt3KmyxIukYD8I1PiSQ6YDLIiWFZcYC8LMyiYmQEX6spsE+IF37lx2nZ1OF+D +AOSCYYamZx6HYShgN4zN1QYTMJdxbz5JgRTIIioVdJTqeF/5GsSGP6f9Eym8ND9j +LQzm8MBEMfvlAgw0q1ieN2Q9INSN3qMCAwEAAaNmMGQwEgYDVR0TAQH/BAgwBgEB +/wIBAjAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFPwqSnU6gPqZY5Pwc1fsvpOw +fcN7MB8GA1UdIwQYMBaAFPwqSnU6gPqZY5Pwc1fsvpOwfcN7MA0GCSqGSIb3DQEB +CwUAA4ICAQBAqkR9j5wKs0T7e9gHTUWlLAnkWLyZI7AuEoXimyJ7Ocy1EwZyu3TD +Z2jCecLNXENnUwjuKaEm/8sCwzrVqpxzIgkS1jVLuVURlrj2+apT/7wBw8LCKMZ6 +cDhQJV3A1+9hyCc5ozkE1LgcJfWELrBWeBuj8rWLAf0DDgtwaED7nS9c9P8UgrxH +YTMe2AHWEfczXBirx5ubpNaokR0W01aSdXa97ohoS+ZmK0bxvmWCugI4tfsypsVl +lV2iD9v/BPLCVHP+7ot520mE21WdQKD69M54V8KAqfmNoG6I3TB2EcKJ0NpKI0zW +niSX05NDrv70INu+vAI8Sso/mRMHpuo03/0iTm3z8J4ACjwP071U0R3wCjTxN8z2 +95EwOf1/JQH5h0njkarxFsWsnHJtWwE3kGEibO3ivB2U3FyS1osN0bEA4X5CSeMF +GDJFCXVB0l4/KeHHNRk3DEVjr5dzcwt/C2DLj9VuaeWEWuVbA3/PDR/MnZzDtPj1 +TVLswGkWKwG+AyJaHkLysZD0IKwL4SZGGCRvyKw+G5Go0vvHVyUMPHqVTBApxY9l +pt6absyMPdRnf+w0tdFlhCd2rauRA0HX7JZ5xqnYjkfk0m7MpoauCsQR9udJvv5H +pMv7wvJRchf62/pPnjLKhN/dx9LR/EVqBPbPMhqdzO6ObQdqUJzXPQ== +-----END CERTIFICATE----- + +Subject CN=SSL.com C2PA ECC Root CA 2025, O=SSL Corporation, C=US +-----BEGIN CERTIFICATE----- +MIICRTCCAcugAwIBAgIUHTAeXakkTyAFDkZfyu8YyCO9ubgwCgYIKoZIzj0EAwIw +TzEmMCQGA1UEAwwdU1NMLmNvbSBDMlBBIEVDQyBSb290IENBIDIwMjUxGDAWBgNV +BAoMD1NTTCBDb3Jwb3JhdGlvbjELMAkGA1UEBhMCVVMwIBcNMjUwNzE4MTU1MTQ5 +WhgPMjA1MDA3MTIxNTUxNDlaME8xJjAkBgNVBAMMHVNTTC5jb20gQzJQQSBFQ0Mg +Um9vdCBDQSAyMDI1MRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xCzAJBgNVBAYT +AlVTMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEo3WOe9pIesN2XWe6KQdiUO+cU1mr ++Bs8opia0I+IA5m8oYhBJmJWPxLea7PH6tlW6f5wqkIOaeJkJ7X1pz3IHPjO8qkX +imKjiUwt/B7IoEj6rhoqkAV4AMO2BMxbS1MUo2YwZDASBgNVHRMBAf8ECDAGAQH/ +AgECMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUU50WGoV8zfcRPowvdPbBkJ1O +g6swHwYDVR0jBBgwFoAUU50WGoV8zfcRPowvdPbBkJ1Og6swCgYIKoZIzj0EAwID +aAAwZQIxALxN0Q+F+9KXOnYUKcW70UuxgitT8iwjTBGCIXJbJw4XaMtVdVGf4HwY +NITBgr+rWwIwczO4trazVV27OTCl8xNR0IH4UuyFgBVuzMsIj8IPkQw5mVhtvhY7 +nNgp3Dyy2LeE +-----END CERTIFICATE----- + +Subject emailAddress=ca@trufo.ai, CN=Trufo C2PA Root CA (2025, ECC P384), OU=CA Division, O=Trufo Inc., L=New York, ST=New York, C=US +-----BEGIN CERTIFICATE----- +MIIDOTCCAr6gAwIBAgIUbXqcPd1r9yQm/fznG9RlSWyXiwswCgYIKoZIzj0EAwMw +gagxCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhOZXcgWW9yazERMA8GA1UEBwwITmV3 +IFlvcmsxEzARBgNVBAoMClRydWZvIEluYy4xFDASBgNVBAsMC0NBIERpdmlzaW9u +MRowGAYJKoZIhvcNAQkBFgtjYUB0cnVmby5haTEsMCoGA1UEAwwjVHJ1Zm8gQzJQ +QSBSb290IENBICgyMDI1LCBFQ0MgUDM4NCkwHhcNMjUxMjMwMTkwNTAzWhcNNDUx +MjI1MTkwNTAzWjCBqDELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5ldyBZb3JrMREw +DwYDVQQHDAhOZXcgWW9yazETMBEGA1UECgwKVHJ1Zm8gSW5jLjEUMBIGA1UECwwL +Q0EgRGl2aXNpb24xGjAYBgkqhkiG9w0BCQEWC2NhQHRydWZvLmFpMSwwKgYDVQQD +DCNUcnVmbyBDMlBBIFJvb3QgQ0EgKDIwMjUsIEVDQyBQMzg0KTB2MBAGByqGSM49 +AgEGBSuBBAAiA2IABAp0qnhIwMtN6LeGdBVtHLPn85ecetr/lqcXFk8ypK9ukJzU +8LLv55Kh/MYTgEnuIKEOPhDxLDRdahc0mAjRnql4kLk395abw9WZjrBPek3qjv0q +ITR8VPYFABuZ5FRKx6OBpjCBozAdBgNVHQ4EFgQUA9Vfr36D5QQdWYAnSjT/Rf3r +SXgwHwYDVR0jBBgwFoAUA9Vfr36D5QQdWYAnSjT/Rf3rSXgwEgYDVR0TAQH/BAgw +BgEB/wIBAjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgorBgEEAYPoPAEB +MCQwIgYIKwYBBQUHAgEWFmh0dHBzOi8vdHJ1Zm8uYWkvY3BjcHMwCgYIKoZIzj0E +AwMDaQAwZgIxAMUeYWZyxS2maiVkNETL29RAuLn/gHYTkt97l6evXwHLN46v28mI +39BIf6slyWnrCwIxAPRs/FJ+DoA0d/PCkrF946S+pG7vRqLnjB9OhMdmrMPvzaqx +KQYOBVx7SE4Kz48W8A== +-----END CERTIFICATE----- + +Subject CN=DigiCert RSA4096 TSA ICA for C2PA G1, O=DigiCert, Inc., C=US +-----BEGIN CERTIFICATE----- +MIIGoTCCBImgAwIBAgIQHlk+WwlryKtFqaffcO7jpjANBgkqhkiG9w0BAQwFADBS +MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xKjAoBgNVBAMT +IURpZ2lDZXJ0IFJTQTQwOTYgUm9vdCBmb3IgQzJQQSBHMTAeFw0yNTA4MjcwMDAw +MDBaFw00MDA4MjYyMzU5NTlaMFUxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdp +Q2VydCwgSW5jLjEtMCsGA1UEAxMkRGlnaUNlcnQgUlNBNDA5NiBUU0EgSUNBIGZv +ciBDMlBBIEcxMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAyK6dRasG +6TUERcSoXIhQ1/Vk0FXmVELjxjqeQMAFCNJkUm8MEdV0g5va49TO/n7N1stKakEZ +Bu2wtNElU7Iz2ht048r5f9mCksUHQzpyKxytCsaE/sWmth4StqtRqjlF2sXrMRVc +5t/bHMOXxclMpuGMWggwKHPxSqQKd2/AuTIzfWshQPUrU/JLxv0BbRCXGm1tQ9CQ +BNrl1xQFxOZ0D+j4eDRYqZNo/jlKzAzY1OMN92rErcbTyZ6Senr7MYwsKKHjeRCO +tfcSmQCp7qw2mlF9QkqFSLPNirv4rSYfrkrWsrue6cYWSKGB+sEEyTOHTGNxi4e4 +NvX+1n8I3jPmbPQEgb3O+UTOxKa+mULBhwHaXeV1wfczgEBRdRXfn+Y7btJjLr8S +zroU0lTZTyarII/WKYKbHJwWF/Tni1Eu4/EnRxMQJz+gXBadQAM3RhfeYqiz53rd +aQgPosKqls1+0hJ4KVVcstiTeytSuG6bhDHL14fgSSl7aGndFU+6wBz+KIBVxs9j +38cQSiqJWgm30erGj2DTCEPDpFvBvSaDHm59kviaFLq/RgHqM1wDwXtyHrimMKmd +cCW+PWlhFqdpUiQ90a5JVIAJyWiOZ7Ko7GsG4y1nohJ9Wvm0V0AoQw+TFOPHRbVO +nhY/UIV9OZWZE9jTsWq2SD216kVvF4eCWi8CAwEAAaOCAW4wggFqMBIGA1UdEwEB +/wQIMAYBAf8CAQAwFwYDVR0gBBAwDjAMBgorBgEEAYPoXgEBMBMGA1UdJQQMMAoG +CCsGAQUFBwMIMA4GA1UdDwEB/wQEAwIBBjCBhgYIKwYBBQUHAQEEejB4MCgGCCsG +AQUFBzABhhxodHRwOi8vb2NzcC5vbmUuZGlnaWNlcnQuY29tMEwGCCsGAQUFBzAC +hkBodHRwOi8vY2FjZXJ0cy5vbmUuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0UlNBNDA5 +NlJvb3Rmb3JDMlBBRzEuY3J0ME0GA1UdHwRGMEQwQqBAoD6GPGh0dHA6Ly9jcmwu +b25lLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFJTQTQwOTZSb290Zm9yQzJQQUcxLmNy +bDAdBgNVHQ4EFgQURnZBGfLaiWXQIbuFjJH9X1GWG7wwHwYDVR0jBBgwFoAUVusn +OJo+SNZygIWbesMHUVoE8+UwDQYJKoZIhvcNAQEMBQADggIBAFB06NmfYUkxUr55 +hxDUOKmwrB7w5KKSnNkF90JJw3pXILQjutAs5rD6KuExSPwa/bMe1fMx0Eh+ma/U +4tPwJMyzyjNppXHbOhE7elQbqnXUw6eeLoxwKxTGQfKGwNA6DqNGHnNcT8325pxl +b0YmQ4IAoy93b9tt51q8suRH/3JhEbEFNHKlpU4lJKGWrirqL3D8g75ghKwA7E/2 +q9sWUmxOm5oHN8AoiGD3NXUCdGKWGhCSVxJB0c0mH6hJ9Pa+HO9aKRIdGb2EdciP +mIICOtrXMHIZd9VZJoVORQ0SI/9d92W9KAkZPFsa4xySVh/AnmsL5JVSa88JudFd +0yNRjdII4mqGvUu+FpwxAq0RUhnzAP9pUoEvq0lWd+LTxfkvvKg4hcL8nvHgxNqK +JEIdGXcouuFGp7ZPjw5OX6b4lycjtZrw+dvsihQ3KHpHqcDHSmMUHHk6mrj+0iP6 +xgrUpk02Q9kMEvN5Hf9M9DR6IgEv5b9B20x/ZaeEY7/PNlG7dAiBi+TN1s1/p0/W +GqP622vsQp/xmykypJd1H59AbdjW4kq16XkxQav3vDg4XzG09/1ztUICatcdVvgG +hCKOlPVNVK4Cp8+ylNKbApOzwZJ8s+wj8PnQBPtqSymVufdkGkyQiR0+aDJ9VXld +gTGEoa59zjtlgSyXKpTfifENxWpk +-----END CERTIFICATE----- + +Subject CN=DigiCert ECC P384 TSA ICA for C2PA G1, O=DigiCert, Inc., C=US +-----BEGIN CERTIFICATE----- +MIIDVTCCAtqgAwIBAgIQa/vORh9Mst4bJJF5DoeAazAKBggqhkjOPQQDAzBTMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xKzApBgNVBAMTIkRp +Z2lDZXJ0IEVDQyBQMzg0IFJvb3QgZm9yIEMyUEEgRzEwHhcNMjUwODI3MDAwMDAw +WhcNNDAwODI2MjM1OTU5WjBWMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNl +cnQsIEluYy4xLjAsBgNVBAMTJURpZ2lDZXJ0IEVDQyBQMzg0IFRTQSBJQ0EgZm9y +IEMyUEEgRzEwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAT8G1ndHhFlZDBFZ0YyRmd6 +x6AKtDvnSWQLr3tfRq4mDLw4veOCBgfqPJH2ofVoFuNVUpnaWIJQKx5tush8yQgG +NUDqcDtjcWqz+tBVNRPF7N1bXCrmPVHnOVxMlq9ykeOjggFuMIIBajASBgNVHRMB +Af8ECDAGAQH/AgEAMIGGBggrBgEFBQcBAQR6MHgwKAYIKwYBBQUHMAGGHGh0dHA6 +Ly9vY3NwLm9uZS5kaWdpY2VydC5jb20wTAYIKwYBBQUHMAKGQGh0dHA6Ly9jYWNl +cnRzLm9uZS5kaWdpY2VydC5jb20vRGlnaUNlcnRFQ0NQMzg0Um9vdGZvckMyUEFH +MS5jcnQwFwYDVR0gBBAwDjAMBgorBgEEAYPoXgEBME0GA1UdHwRGMEQwQqBAoD6G +PGh0dHA6Ly9jcmwub25lLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEVDQ1AzODRSb290 +Zm9yQzJQQUcxLmNybDATBgNVHSUEDDAKBggrBgEFBQcDCDAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0OBBYEFCCVvm3C1NqJFBP6pBOCIhPGHwgRMB8GA1UdIwQYMBaAFPQY +Ea4JgolO/Ju0M/b0370CTpQ2MAoGCCqGSM49BAMDA2kAMGYCMQD5QJg0LWan44KK +sMic+nWXydVCGoa7hzlNDYvZfuA/kx/SPUWqssA3TDPPyxwziOkCMQCopKRPtJ87 +CaQGUou1I+7hjCQWZvy0FaNEe/XYwK1kN/xc3U5ZqFqE50744xaOwsw= +-----END CERTIFICATE----- + +Subject CN=DigiCert ECC P384 Root for C2PA G1, O=DigiCert, Inc., C=US +-----BEGIN CERTIFICATE----- +MIICSTCCAc+gAwIBAgIQCZ2yarc/T5eBQYVHCJTdyjAKBggqhkjOPQQDAzBTMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xKzApBgNVBAMTIkRp +Z2lDZXJ0IEVDQyBQMzg0IFJvb3QgZm9yIEMyUEEgRzEwIBcNMjUwODI3MDAwMDAw +WhgPMjA1MDA4MjYyMzU5NTlaMFMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdp +Q2VydCwgSW5jLjErMCkGA1UEAxMiRGlnaUNlcnQgRUNDIFAzODQgUm9vdCBmb3Ig +QzJQQSBHMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABNHiy4U9/SpPSnQ3ogU+q3mn +M/f9zmLuqF8krS0LNUC0T81Nu57WCGSb6149CVpkRRC6BYlfGcBWVYXar4aX10oX +ggSiFPi93ovkAfUN9wikKqVu6amI7tRQPKXJ95UsFaNmMGQwEgYDVR0TAQH/BAgw +BgEB/wIBAjAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFPQYEa4JgolO/Ju0M/b0 +370CTpQ2MB8GA1UdIwQYMBaAFPQYEa4JgolO/Ju0M/b0370CTpQ2MAoGCCqGSM49 +BAMDA2gAMGUCMQCg31cyC7If2VPMUvqEr08WB6QhRVpAa+GNRlKUOJlSMq/y2tm+ +80RTxpV2RsYC9UsCMGkKQ0Yx4FIs1RhYtXVIgTyHrSxGne4/457DlIS+IMIJN5Yd +gMNj6G6tzM47QDGl2w== +-----END CERTIFICATE----- + +Subject CN=DigiCert RSA4096 Root for C2PA G1, O=DigiCert, Inc., C=US +-----BEGIN CERTIFICATE----- +MIIFljCCA36gAwIBAgIQL2uv995UIpTpN6WRLwYnHDANBgkqhkiG9w0BAQwFADBS +MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xKjAoBgNVBAMT +IURpZ2lDZXJ0IFJTQTQwOTYgUm9vdCBmb3IgQzJQQSBHMTAgFw0yNTA4MjcwMDAw +MDBaGA8yMDUwMDgyNjIzNTk1OVowUjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRp +Z2lDZXJ0LCBJbmMuMSowKAYDVQQDEyFEaWdpQ2VydCBSU0E0MDk2IFJvb3QgZm9y +IEMyUEEgRzEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDTX44Mw12/ +in3jeV80FcoutZhxtvhZQHAdiFtiYd9Y+quavnHRqtcexRZQ0n1XtGXeiusE72M6 +G4dwdTsHXoXVNXjwrO9a/fA/46u+/T5ZU6FyRQdahwQNIXL5PVfqrjwX2Ta2Gby2 +z4tbhfzxtgJSosJGJsCGq5mGiBXIqBkbua0YOvuX1WifAuDQun84bw+qwCCWxSty +QuUcZMm6xl24ye5RZnz8xkctz/p68kgNa9IhJlHrZ3CAe1zEu3PrNS7Oq/uzN06t +Ji6rkpXCV6GlhN0RlEPmUb3pg8kYqQ9uca7u4UTyl/F9QqG2xMDgAtNDrfNbWpyO +fnoYGNQvQyD5M7slsz9j9sUcKwspaz8zmuu31UXPqmvME+UalDvFeknQZP+ft9Uv +8eICovCQxvy1Iwg3sjc2hO0lbYYn/JqGARg+5jP/SlkY4dSypdYBtBaAfVxTd+iQ +m4k1oAEIP7ujyQ+1U0F9gygQPwQrMOcyYINgkcsp36rb1znuxlIF6LIcfO1bkVSx +vHqd0CVP8vwrYXKJOr4dES1s4k12kxv+csvZWiuSqY0uhFUSMSE5id5zWW7H6ZCX +3J3Ati2MjyRjyyejDbTQdTS3wlF4f4bLaWidMWSZ3JCyZABXpj46RtdbhZgV7I7B +ZTXCI6FIBuUaiZzW9RHhVzR+qrfBOx40mwIDAQABo2YwZDASBgNVHRMBAf8ECDAG +AQH/AgECMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUVusnOJo+SNZygIWbesMH +UVoE8+UwHwYDVR0jBBgwFoAUVusnOJo+SNZygIWbesMHUVoE8+UwDQYJKoZIhvcN +AQEMBQADggIBAIjcpKt4FeVibq6zP1m2RUagL6PEW+8o5CC5kv0mDMcCgqNTsyNJ +lr/1yYzzpEC82QaCZ34g4eMXnOwq+5jF5xQ5b7RV7X9nFuPXh7r2CittMkBLPKp/ +jSApyfEI2qgNtPWc5voKRgPrkSuHu+wB5gTg7AkN9CCZeaauMesIIn7/8lWOSho9 +a5DVCJekYh+WcfnSP6l0ilRw1WhnAtPwadhcQ9zJxKe6LSdsH3yNJhViIQNrBhlA +O3BNZF1q2JfOM6TCiY/I+M8AfzuvxF/xyxeDlcRNo6QbfAvUybDOsleg9NxO+EK3 +VXTInzaWidoX9TRdEx0iiERj9OB7ehZBwTUllBH6UtxFy3X7YRSnO8ZdjtEERJmk +BNZztgd4KWBnaFMERI0ObiqN1az0uqe8sRULEJ1Ay79sTsJtiemNChMxmYb83XU1 +1wSX/W54tD6vPQPCwn84AeLgYSfA10QwRyAo99pwmjZzrCx5uBH7jCVYBkP7iQ6h +o3yHror7znE8LJrrWytOuumEFzxQ0NSaXjrDRKCLKTKnr8niIj+lB/SJsBua52a6 +HHRckrpDokgPSPOYI4A+ZGC//Ron9i3S8ce2dQHAWNCqB2ADtnu4Yf36OfmHdrCL +hzIxlPKKDPXwgxv7NTRFs1d7KcIpjYuZp71eZA74ZqxDgVa7CMkhdgML +-----END CERTIFICATE----- + +Subject CN=Irdeto C2PA Root CA G1, O=Irdeto BV, C=NL +-----BEGIN CERTIFICATE----- +MIICLDCCAbGgAwIBAgIUL8JDbqsQllkL9gozEdKhKc9GFAcwCgYIKoZIzj0EAwMw +QjELMAkGA1UEBhMCTkwxEjAQBgNVBAoMCUlyZGV0byBCVjEfMB0GA1UEAwwWSXJk +ZXRvIEMyUEEgUm9vdCBDQSBHMTAgFw0yNTEyMDUxMjQ0NDBaGA8yMDUwMTIwNTEy +NDQ0MFowQjELMAkGA1UEBhMCTkwxEjAQBgNVBAoMCUlyZGV0byBCVjEfMB0GA1UE +AwwWSXJkZXRvIEMyUEEgUm9vdCBDQSBHMTB2MBAGByqGSM49AgEGBSuBBAAiA2IA +BEOtgkWt4t4r3Fvn2vDshY1KcZ63/VTaZN7K2uiAcCeztiH+ZSFf4hA5cSCABRJ+ +VkWZYLvnhNLsCVbtEij6mDN5hf4VIUdUNgUonGZ6tkL1Djs3CUIkjD+nH/HXbCSj +pqNmMGQwEgYDVR0TAQH/BAgwBgEB/wIBAjAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O +BBYEFGs1MrTyCBABc00WKVK0njUakyplMB8GA1UdIwQYMBaAFGs1MrTyCBABc00W +KVK0njUakyplMAoGCCqGSM49BAMDA2kAMGYCMQCB1h+esIhAsddoGkZI1aXwwCFM +wL/cHskaM8JZsvUfcecGQmG08ZVesfUeCzei0SECMQCLjWbR4LY1mgfF+PzlieDZ +9DTcd5qOpJaSf90/8AnQA/UWGtRGqJsrmERInDoXEOA= +-----END CERTIFICATE----- + +Subject CN=vivo Content Provenance and Authenticity Root CA, O=vivo Mobile Communication Co., Ltd., C=CN +-----BEGIN CERTIFICATE----- +MIIC0zCCAjSgAwIBAgIJAMIN3t2/xTDAMAoGCCqGSM49BAMEMHYxOTA3BgNVBAMM +MHZpdm8gQ29udGVudCBQcm92ZW5hbmNlIGFuZCBBdXRoZW50aWNpdHkgUm9vdCBD +QTEsMCoGA1UECgwjdml2byBNb2JpbGUgQ29tbXVuaWNhdGlvbiBDby4sIEx0ZC4x +CzAJBgNVBAYTAkNOMCAXDTI1MDkxODA5MDkxM1oYDzIwNTUwOTExMDkwOTEzWjB2 +MTkwNwYDVQQDDDB2aXZvIENvbnRlbnQgUHJvdmVuYW5jZSBhbmQgQXV0aGVudGlj +aXR5IFJvb3QgQ0ExLDAqBgNVBAoMI3Zpdm8gTW9iaWxlIENvbW11bmljYXRpb24g +Q28uLCBMdGQuMQswCQYDVQQGEwJDTjCBmzAQBgcqhkjOPQIBBgUrgQQAIwOBhgAE +ANQigNuQ6RnYFSK2BWkaksR3fRFFytX4nzX3E4hLV/N/7m/XttNHxNDase0cAXwR +9pO23p6fb/9NbifILv2wzPn2ASMr306Y2frv/UjJ5J6WgHet2OFywRaPjFjJWRuk +4JCy0qoSxyyx230g8GYdacZzIqSzVTW7/Xz4mjnWDTOB/Db+o2YwZDASBgNVHRMB +Af8ECDAGAQH/AgECMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUgB0dwwUcpK4u +7az42vKC2y+nnY8wHwYDVR0jBBgwFoAUgB0dwwUcpK4u7az42vKC2y+nnY8wCgYI +KoZIzj0EAwQDgYwAMIGIAkIB9cjlRbw8I0+0VAIOENCEzKOfp2risHuo3KVqyaSV +K/T6KzMNvpq3ihA6ZjnuH9i5y5XWV//awWbFJDSuT0Bq+pwCQgHuthBjGmDl/nyc +r3MxJErDVYZBh4b140LQBU60MtiPERVYwme03ukGImPW/OKbEWYmnhHyMAf1ym/3 +UK/lOv3G2w== +-----END CERTIFICATE----- + +Subject emailAddress=ca@tauth.io, CN=Tauth Root CA, OU=CA Division, O=Tauth Labs Inc., L=New York, ST=New York, C=US +-----BEGIN CERTIFICATE----- +MIIDjzCCAxWgAwIBAgIUW6zwDse+LBk8Yvy/u3p7lSjnaA4wCgYIKoZIzj0EAwMw +gZcxCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhOZXcgWW9yazERMA8GA1UEBwwITmV3 +IFlvcmsxGDAWBgNVBAoMD1RhdXRoIExhYnMgSW5jLjEUMBIGA1UECwwLQ0EgRGl2 +aXNpb24xFjAUBgNVBAMMDVRhdXRoIFJvb3QgQ0ExGjAYBgkqhkiG9w0BCQEWC2Nh +QHRhdXRoLmlvMB4XDTI2MDEwNTE2MDgzMVoXDTQ1MTIzMTE2MDgzMVowgZcxCzAJ +BgNVBAYTAlVTMREwDwYDVQQIDAhOZXcgWW9yazERMA8GA1UEBwwITmV3IFlvcmsx +GDAWBgNVBAoMD1RhdXRoIExhYnMgSW5jLjEUMBIGA1UECwwLQ0EgRGl2aXNpb24x +FjAUBgNVBAMMDVRhdXRoIFJvb3QgQ0ExGjAYBgkqhkiG9w0BCQEWC2NhQHRhdXRo +LmlvMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETgpV7Q9tsMzXFPduTyVt71IRRfU0 +yeZGVuXmVO6zyUXxqGCg07jafnMyv24pRwJ9Bk+ROhslNWFS0NhXjIINDuk4h5Ji +KcEEGBJIlGl7jOB/MPLF/HU7CfURT2ayXKXmo4IBHjCCARowHQYDVR0OBBYEFB3R +AQfd1ulUQKBf+J34TnS1CxI+MIHXBgNVHSMEgc8wgcyAFB3RAQfd1ulUQKBf+J34 +TnS1CxI+oYGdpIGaMIGXMQswCQYDVQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsx +ETAPBgNVBAcMCE5ldyBZb3JrMRgwFgYDVQQKDA9UYXV0aCBMYWJzIEluYy4xFDAS +BgNVBAsMC0NBIERpdmlzaW9uMRYwFAYDVQQDDA1UYXV0aCBSb290IENBMRowGAYJ +KoZIhvcNAQkBFgtjYUB0YXV0aC5pb4IUW6zwDse+LBk8Yvy/u3p7lSjnaA4wDwYD +VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwMDaAAwZQIx +AJzhLaivtrjOMyEAuoHQRIhN2u7kw2iWZZyAT6FJH4+GBYudax0dfewXeIvC0MH5 +SwIwAKojdigAO86Xvk6++B875ZpTjQIysPX0bGumbmAwcAmsqum9JLLIRCDz+7Kt +WrRP +-----END CERTIFICATE----- + +Subject CN=HUAWEI C2PA ECC384 Root CA E346, O=Huawei Technologies Co., Ltd., C=CN +-----BEGIN CERTIFICATE----- +MIICoDCCAiagAwIBAgIIKsblXSNLwF8wCgYIKoZIzj0EAwMwXzELMAkGA1UEBhMC +Q04xJjAkBgNVBAoMHUh1YXdlaSBUZWNobm9sb2dpZXMgQ28uLCBMdGQuMSgwJgYD +VQQDDB9IVUFXRUkgQzJQQSBFQ0MzODQgUm9vdCBDQSBFMzQ2MB4XDTI2MDQxMzAx +NTQxMFoXDTQ2MDQwODAxNTQxMFowXzELMAkGA1UEBhMCQ04xJjAkBgNVBAoMHUh1 +YXdlaSBUZWNobm9sb2dpZXMgQ28uLCBMdGQuMSgwJgYDVQQDDB9IVUFXRUkgQzJQ +QSBFQ0MzODQgUm9vdCBDQSBFMzQ2MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEOrBo +SivfM2LRlG3B4r52hE0vDjQR2iWv9sKTZXzkscQIasoH+uYBDDie9VcosH4Mfq/U +xN8ojhW7BZW38LT38SmYpJPZirtzKTyCD4ha4dU8tLcHoJsOn3p+kBw09Bvoo4Gu +MIGrMB8GA1UdIwQYMBaAFM/OyEcEDscO78w/okatAmz35ypMMB0GA1UdDgQWBBTP +zshHBA7HDu/MP6JGrQJs9+cqTDASBgNVHRMBAf8ECDAGAQH/AgECMEUGCCsGAQUF +BwELBDkwNzA1BggrBgEFBQcwBYYpaHR0cDovL2NhLmh1YXdlaWNsb3VkLmNvbS9y +ZXBvc2l0b3J5Lmh0bWwwDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2gAMGUC +MDCsqpRvJIPw6OAQi2Rj0CWnwJgK75YK5gj+K9xomIDu8ai/2ExrifL8JgROQOeZ +egIxAL3tT3Dp84wP18ohYU83gkRcA8j9B3T4BRpxY1Ew9IJMYJ2zqz0weFjAEGNC +9Z36XQ== +-----END CERTIFICATE----- + +Subject CN=Huanyu Trust C2PA EC-384 Root CA, O=Huanyu Trust Ltd, C=CN +-----BEGIN CERTIFICATE----- +MIICTTCCAdOgAwIBAgIUCqsLOXYNHdz0EBDsWKcrsiBcF10wCgYIKoZIzj0EAwMw +UzELMAkGA1UEBhMCQ04xGTAXBgNVBAoTEEh1YW55dSBUcnVzdCBMdGQxKTAnBgNV +BAMTIEh1YW55dSBUcnVzdCBDMlBBIEVDLTM4NCBSb290IENBMCAXDTI2MDQxMzA2 +MDUwOVoYDzIwNTEwNDEzMDYwNTA5WjBTMQswCQYDVQQGEwJDTjEZMBcGA1UEChMQ +SHVhbnl1IFRydXN0IEx0ZDEpMCcGA1UEAxMgSHVhbnl1IFRydXN0IEMyUEEgRUMt +Mzg0IFJvb3QgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARDnAlELrIETK81oB6E +/ZfbkGSH9YPhGdFpXTzDCHD3IsKPQdPPv/mF319XjdrZMECxpH9rbmWGuWrhq6K8 +zIGO27H2MUE658XNu6aO5xcZV/YdAMkG/YWPYo9CmCT4/SujZjBkMBIGA1UdEwEB +/wQIMAYBAf8CAQIwHwYDVR0jBBgwFoAUYc0ZfGc1yTPouBQYj81mEEdaefswHQYD +VR0OBBYEFGHNGXxnNckz6LgUGI/NZhBHWnn7MA4GA1UdDwEB/wQEAwIBBjAKBggq +hkjOPQQDAwNoADBlAjEAqfQxNSnmGxtt1QBKJbaY8AyUiaJxzX5MnH0l/ielnc6D +qBhIcALvKKc3a8MizR01AjB85bwUFBgs6WlIWZ6sFDDbCQzrWpPU11YQnj/mGom7 +yXjL/2axHPWPY2Do/ldP5mc= +-----END CERTIFICATE----- + +Subject CN=Snowball ECC P384 Root CA for C2PA G1, O=Snowball Technology Co., Ltd., C=CN +-----BEGIN CERTIFICATE----- +MIICiTCCAg6gAwIBAgIUVlsRGj1G9vJ4ws2jMYyFlFcKUokwCgYIKoZIzj0EAwMw +ZTELMAkGA1UEBhMCQ04xJjAkBgNVBAoMHVNub3diYWxsIFRlY2hub2xvZ3kgQ28u +LCBMdGQuMS4wLAYDVQQDDCVTbm93YmFsbCBFQ0MgUDM4NCBSb290IENBIGZvciBD +MlBBIEcxMB4XDTI2MDYxODA5MzkxOVoXDTQ2MDYxMzA5MzkxOVowZTELMAkGA1UE +BhMCQ04xJjAkBgNVBAoMHVNub3diYWxsIFRlY2hub2xvZ3kgQ28uLCBMdGQuMS4w +LAYDVQQDDCVTbm93YmFsbCBFQ0MgUDM4NCBSb290IENBIGZvciBDMlBBIEcxMHYw +EAYHKoZIzj0CAQYFK4EEACIDYgAELJUrcxeVmmYrb8Kl/YVAYYFiyuiqiIa6z/1n +FoCpB2JV/Qkwjdns7rOvLheWBi1s880NcwqD/KD9t9/SOgWTfD+WOAhtPioAql2Y +YUl0toOUzoXaAOB3+HIQRiKsL2RIo38wfTASBgNVHRMBAf8ECDAGAQH/AgECMA4G +A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU6R4F1vboIaKQly8jCAQX2lQhWPQwHwYD +VR0jBBgwFoAU6R4F1vboIaKQly8jCAQX2lQhWPQwFwYDVR0gBBAwDjAMBgorBgEE +AYPoXgEBMAoGCCqGSM49BAMDA2kAMGYCMQD6/xszsnZoYt+gYIsgYKTMFARxRpB5 +N16s2u2hgkuFs4zyLco1z7gOk0mv6EbBkm0CMQCcsqIQnr45MVjDUdn9L//VdGDO +6H+P67vBdmvb3LiLTB+Ey/JYYfnHHIKzJrRG4ls= +-----END CERTIFICATE----- + +Subject CN=Snowball ECC P384 TSA ICA for C2PA G1, O=Snowball Technology Co., Ltd., C=CN +-----BEGIN CERTIFICATE----- +MIIDjjCCAxSgAwIBAgIUVFsaHdwprWWlk08S4C67gq5M6qwwCgYIKoZIzj0EAwMw +ZTELMAkGA1UEBhMCQ04xJjAkBgNVBAoMHVNub3diYWxsIFRlY2hub2xvZ3kgQ28u +LCBMdGQuMS4wLAYDVQQDDCVTbm93YmFsbCBFQ0MgUDM4NCBSb290IENBIGZvciBD +MlBBIEcxMB4XDTI2MDYxODA5NDIxNFoXDTQxMDYxODA5NDIxNFowZTELMAkGA1UE +BhMCQ04xJjAkBgNVBAoMHVNub3diYWxsIFRlY2hub2xvZ3kgQ28uLCBMdGQuMS4w +LAYDVQQDDCVTbm93YmFsbCBFQ0MgUDM4NCBUU0EgSUNBIGZvciBDMlBBIEcxMHYw +EAYHKoZIzj0CAQYFK4EEACIDYgAEsI3OjbQCcr6lFS0Y1T8vaS8KcApdpQUAAee7 +EGSXvyuTfXcK9AUSYHxVZRiJjGliHgyVQL5C2tYEL4JOxw3ttxlvKVkuQI2MHd05 +7yOyrgn1YC/tsw6dRJhrt+u+7xFso4IBgzCCAX8wEgYDVR0TAQH/BAgwBgEB/wIB +ADAOBgNVHQ8BAf8EBAMCAQYwEwYDVR0lBAwwCgYIKwYBBQUHAwgwHQYDVR0OBBYE +FNBjlXQUhXxUL3xl/vB43xqIyE7NMB8GA1UdIwQYMBaAFOkeBdb26CGikJcvIwgE +F9pUIVj0MBcGA1UdIAQQMA4wDAYKKwYBBAGD6F4BATCBlAYIKwYBBQUHAQEEgYcw +gYQwLQYIKwYBBQUHMAGGIWh0dHA6Ly9vY3NwLmMycGEuc25vd2JhbGx0ZWNoLmNv +bTBTBggrBgEFBQcwAoZHaHR0cDovL2NhY2VydHMuYzJwYS5zbm93YmFsbHRlY2gu +Y29tL1Nub3diYWxsRUNDUDM4NFJvb3RDQWZvckMyUEFHMS5jcnQwVAYDVR0fBE0w +SzBJoEegRYZDaHR0cDovL2NybC5jMnBhLnNub3diYWxsdGVjaC5jb20vU25vd2Jh +bGxFQ0NQMzg0Um9vdENBZm9yQzJQQUcxLmNybDAKBggqhkjOPQQDAwNoADBlAjB0 +7SyNJ2s9Mdz78HJwm5aU3J5NdZF8XbNhPcKB76QqrbNjtb2ehkqceoYx3wkotCsC +MQDSJY/v5rMUu9DeqNTNnHSvBVTXEzqZj+k47QlVnv9Auu29JHFXrY+Gj+b3Cx6G +ZcE= +-----END CERTIFICATE----- + +Subject CN=Encypher C2PA Root CA 2026, OU=CA Division, O=Encypher Corp., L=San Francisco, ST=California, C=US +-----BEGIN CERTIFICATE----- +MIIDFDCCApqgAwIBAgIUS2zOIYRKaa59snU3NcNFadfTtoAwCgYIKoZIzj0EAwMw +gY4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1T +YW4gRnJhbmNpc2NvMRcwFQYDVQQKDA5FbmN5cGhlciBDb3JwLjEUMBIGA1UECwwL +Q0EgRGl2aXNpb24xIzAhBgNVBAMMGkVuY3lwaGVyIEMyUEEgUm9vdCBDQSAyMDI2 +MB4XDTI2MDUyMjEzNDk1NloXDTQ2MDUxNzEzNDk1NlowgY4xCzAJBgNVBAYTAlVT +MRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMRcw +FQYDVQQKDA5FbmN5cGhlciBDb3JwLjEUMBIGA1UECwwLQ0EgRGl2aXNpb24xIzAh +BgNVBAMMGkVuY3lwaGVyIEMyUEEgUm9vdCBDQSAyMDI2MHYwEAYHKoZIzj0CAQYF +K4EEACIDYgAE27XmRBc4mE0dYfUhLiuPiAnY3tRDMke9evylB+VgyMspT1svR9h3 +KXxr8tml+1oM82US+pw2jJenfUxoUJGVDY/lvwl+4Q+7vawXFd26yPv/CQSnhI+w +05+yiSiwshIOo4G2MIGzMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQD +AgEGMB0GA1UdDgQWBBS3gC7ps3/HLQbb3uuqL4U8gDnKEDAfBgNVHSMEGDAWgBS3 +gC7ps3/HLQbb3uuqL4U8gDnKEDBNBgNVHSAERjBEMEIGCisGAQQBg+heAQEwNDAy +BggrBgEFBQcCARYmaHR0cHM6Ly9jYS5lbmN5cGhlci5jb20vcmVwb3NpdG9yeS9j +cHMwCgYIKoZIzj0EAwMDaAAwZQIwYeb83YEb/Oh9uELuvO9jpb85orRWWQiceqf0 +sCwxtJw07/giyy/hI1BFvbQZcfkLAjEAj8jfwuJSJ9LjeeYL/VXStQWDHewxbIou +IKdYpS9ZBidpsi+01tpQY1j7apLAXMHO +-----END CERTIFICATE----- + +Subject CN=Encypher C2PA TSA Issuing CA 2026, OU=CA Division, O=Encypher Corp., L=San Francisco, ST=California, C=US +-----BEGIN CERTIFICATE----- +MIID3zCCA2WgAwIBAgIUfkelmX2xvvmLxUBI5ayBZXdGOz4wCgYIKoZIzj0EAwMw +gY4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1T +YW4gRnJhbmNpc2NvMRcwFQYDVQQKDA5FbmN5cGhlciBDb3JwLjEUMBIGA1UECwwL +Q0EgRGl2aXNpb24xIzAhBgNVBAMMGkVuY3lwaGVyIEMyUEEgUm9vdCBDQSAyMDI2 +MB4XDTI2MDUyNDE1NTUxOVoXDTMxMDUyNTE1NTUxOVowgZUxCzAJBgNVBAYTAlVT +MRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMRcw +FQYDVQQKDA5FbmN5cGhlciBDb3JwLjEUMBIGA1UECwwLQ0EgRGl2aXNpb24xKjAo +BgNVBAMMIUVuY3lwaGVyIEMyUEEgVFNBIElzc3VpbmcgQ0EgMjAyNjB2MBAGByqG +SM49AgEGBSuBBAAiA2IABAPWSlEq6MdUceWdJ5nsZSwXTBq+enJovg6OTABtcAdS +uEDTcD1t9eajKVlPvK7xqbG18InxR0Ave8UA6jNTFD+4f/fjqR/HbJAtX2l7lcv5 +lM9PiYJER64WF7Diyibcm6OCAXkwggF1MBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYD +VR0PAQH/BAQDAgEGMBMGA1UdJQQMMAoGCCsGAQUFBwMIMB0GA1UdDgQWBBRACKf4 +2ACoV/5pGlYPM5hBkBcWlTAfBgNVHSMEGDAWgBS3gC7ps3/HLQbb3uuqL4U8gDnK +EDA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY2EuZW5jeXBoZXIuY29tL2NybC9y +b290LWNhLmNybDByBggrBgEFBQcBAQRmMGQwJwYIKwYBBQUHMAGGG2h0dHA6Ly9j +YS5lbmN5cGhlci5jb20vb2NzcDA5BggrBgEFBQcwAoYtaHR0cDovL2NhLmVuY3lw +aGVyLmNvbS9yZXBvc2l0b3J5L3Jvb3QtY2EuY3J0ME0GA1UdIARGMEQwQgYKKwYB +BAGD6F4BATA0MDIGCCsGAQUFBwIBFiZodHRwczovL2NhLmVuY3lwaGVyLmNvbS9y +ZXBvc2l0b3J5L2NwczAKBggqhkjOPQQDAwNoADBlAjBXL0geKILQqoIKi9wD74Hr +id0nXiRZhyMrI39yGXDjq5/rqsQhCdOR+Gs4XIX9lhUCMQCb7yodaeskIdoHYjvV +y59amQPG8tMRAXIaybH/Df/Dwb2YD/D+hbgMn0MufkrB4/w= +-----END CERTIFICATE----- + +Subject CN=TrustAsia C2PA RSA Root CA, O=TrustAsia Technologies, Inc., C=CN +-----BEGIN CERTIFICATE----- +MIIFqDCCA5CgAwIBAgIUNqYa1cdsY+cp091HGRPKXzrE4kwwDQYJKoZIhvcNAQEM +BQAwWTELMAkGA1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dp +ZXMsIEluYy4xIzAhBgNVBAMMGlRydXN0QXNpYSBDMlBBIFJTQSBSb290IENBMCAX +DTI2MDYwNTAzNTMwMFoYDzIwNTEwNjA1MDM1MjU5WjBZMQswCQYDVQQGEwJDTjEl +MCMGA1UECgwcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5jLjEjMCEGA1UEAwwa +VHJ1c3RBc2lhIEMyUEEgUlNBIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQCvgJqlqXZ+SYbtl9dLK4SQ5Gt9KrPbOmWEeMYnh8UdB3+KzkrG +6PSZ1/s6KDIiEPNH1Sno7UOnTWzZ50Ce3Qq4PKFJBb9iJ0cbtw4qGOjHDhgXhozv +nPQhXy6uiEODKgsKRaZwxT7xer3ZOAbX/30tQDwyAavoEtb+F+o2faYxHwjojUnK +zO0Aaz68h7U5zMHgdMUvkqc0B5NIpoTixCj7Om2X0XROWAFx7ELrVxMmyL4PCWOj +caRXoP5QlDHiIc5Ck9/HD6VYr2jJG/8BFZqk9l+mgNlxjaIbp0D/B3D7WvxcGOFR +qiRJRni3LAsdVAMGPs/msUVBsYnTIEWb1o8qvkKpPOE0OtseEhWIQX4EDTA3Kim1 +xVqcS3+9irfDf7Jda2vOX1mamZa+Y89xCZcG7ce4u0fpE/NOs46dymoG/zU0uUvd +KOtzvddNuDOWymROa6SVG6uETSdVFRsQfR/Dp8MQegVLB6ITAfnXHc3Pn67B1ncs +L359DcwlZkqYGegsz//8ToRAlSSA/9C9vzlXfbGIg2HHtToHcwa6BjDkRpfdm6nk +egfCvoaWT4k/9vDQNXvg8Wee1vpUDKhB7y1SSaSkm+7wr8fV4ovFGSrbygpr0BuG +m+ShU3Vh+8UXAICPntscPAgNXidB9A8Zgib5rJjiVi0sxizPYueAchPQDwIDAQAB +o2YwZDASBgNVHRMBAf8ECDAGAQH/AgECMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4E +FgQUCdViRLQz3hH0IboHIKjSrMMHRYAwHwYDVR0jBBgwFoAUCdViRLQz3hH0IboH +IKjSrMMHRYAwDQYJKoZIhvcNAQEMBQADggIBAHInmN938SAQOkERvIrZDi14uVmZ +P5GgqQ6ZH4BF77RFcQcDl7Id+3WBf1WqSl0zyuq6HulYyM6pWikh0W5K/NBBLlt+ +zXtEHbW71jhAhCKALdbclT+KuqRRQbrzATXPyYB5Jb/7xlUIofilo70+lqNwahsy +Y5F+6XlOZ4JuA84RdfxGdyn/IJlOJ9mc2RbI6aAxMuFcsot483gOYtkU4Og0g9M7 +XsdLT2VXwuVk3hXwc7UWlZUm1Vn6dGmrcSj41wGlw9JGMU87OfzYFseGBDGDc2Xv +njFCY+SBAEWGk4m6ugNGat8OKBVNpnYGp0iNODMtQXJ0aUCvOziFPJY9li08sUDe +HI9ZwLB+yADsaC1gaX4eloRFsIyyl7YRQEY1/EfVw3wnN+XBJYyBw9v1RtpXDh/v +O2ezzXc1sdH/WgXMGGrRdiCAZb5mFkjTEoKXVnkGMn7bnJKuFgDQPWerA24Jck1J +QTuQBXJOAt8FVaYMjL6wPSIv84UjVXIRkOP4ZOydpYgykEl5LfOWcQtA4U6h+obS +35aB8YE1KC9rIeEE8q5onGo6tRYJzh+mB/XSUP35fNbwe4FkI3I6ZpNSS6wt9HY0 +DCYCNhAz7KP8RwexR/stlYyeUxbj3+jxK4AOGTZQEKBBWkoqfrPCDpybwpXCxxP5 +qtj6+iKCvpx9jmvr +-----END CERTIFICATE----- + +Subject CN=TrustAsia C2PA ECC Root CA, O=TrustAsia Technologies, Inc., C=CN +-----BEGIN CERTIFICATE----- +MIICWjCCAd+gAwIBAgIUdUWMu3G69tNb9bwz/0KTupxLm1kwCgYIKoZIzj0EAwMw +WTELMAkGA1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMs +IEluYy4xIzAhBgNVBAMMGlRydXN0QXNpYSBDMlBBIEVDQyBSb290IENBMCAXDTI2 +MDYwNTAzNTAwMFoYDzIwNTEwNjA1MDM0OTU5WjBZMQswCQYDVQQGEwJDTjElMCMG +A1UECgwcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5jLjEjMCEGA1UEAwwaVHJ1 +c3RBc2lhIEMyUEEgRUNDIFJvb3QgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQL +ERY0d7ug9MiCqmXnDjDs2med9zfTqTWOcG3OD5Q6FSEgNUcjT5Qy7xzKn1MfqaY4 +Ye3sf+Do7cCDR6AiFW6SqLQobfJ70jMDsSQYlrCCjMLvb+NdNPhED43s8fgehxyj +ZjBkMBIGA1UdEwEB/wQIMAYBAf8CAQIwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQW +BBT13DKCd7Jlz2rEe0vBlwo/CoR2mDAfBgNVHSMEGDAWgBT13DKCd7Jlz2rEe0vB +lwo/CoR2mDAKBggqhkjOPQQDAwNpADBmAjEAwp2Jie8k6/haTc/df3QsX+Ttg7Wp +ARtYTwJSP4Z+ggpf39sZ+7QPOE50BqBj9Q6zAjEAjZ+5glED9tav6r3jWuMOmKTB +kobBXzvjqTDLGG570BbSQfNmS3HRC6u5YTIpElpb +-----END CERTIFICATE----- + +Subject CN=Castlabs C2PA ECC P-384 Root CA, OU=C2PA Trust Infrastructure, O=Castlabs, L=Berlin, ST=Berlin, C=DE +-----BEGIN CERTIFICATE----- +MIICyDCCAk2gAwIBAgIUN5SkK2Lb2Ts/j1AC3K8Y3eVydFQwCgYIKoZIzj0EAwMw +gZAxKDAmBgNVBAMMH0Nhc3RsYWJzIEMyUEEgRUNDIFAtMzg0IFJvb3QgQ0ExCzAJ +BgNVBAYTAkRFMQ8wDQYDVQQHDAZCZXJsaW4xETAPBgNVBAoMCENhc3RsYWJzMSIw +IAYDVQQLDBlDMlBBIFRydXN0IEluZnJhc3RydWN0dXJlMQ8wDQYDVQQIDAZCZXJs +aW4wHhcNMjYwNzA4MDE0NDMwWhcNMzYwNzA1MDE0NDMwWjCBkDEoMCYGA1UEAwwf +Q2FzdGxhYnMgQzJQQSBFQ0MgUC0zODQgUm9vdCBDQTELMAkGA1UEBhMCREUxDzAN +BgNVBAcMBkJlcmxpbjERMA8GA1UECgwIQ2FzdGxhYnMxIjAgBgNVBAsMGUMyUEEg +VHJ1c3QgSW5mcmFzdHJ1Y3R1cmUxDzANBgNVBAgMBkJlcmxpbjB2MBAGByqGSM49 +AgEGBSuBBAAiA2IABPXhd9L+pjQVnUXH6I7+oFSrd6JpO4A+CYDm/AuDZgJvwiuJ +lrM9dC3CAE7UAK8IcQEo85qzuak0TfLdPaJWD26+q3tJ/S7NW4sOKhH09KRN7iFq +XbsOe8FOxaQql/UrMqNmMGQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYB +Af8CAQIwHQYDVR0OBBYEFHNKe2PoAANQBj4/25eRv2VY4Fy7MB8GA1UdIwQYMBaA +FHNKe2PoAANQBj4/25eRv2VY4Fy7MAoGCCqGSM49BAMDA2kAMGYCMQDUlNJD49Ux +zwBccYHiz0wgmbIXBDdgpVrLfWTQnbi21BhfPBQ6j0HJ24FY36L5oj8CMQCv5+bK +gBIkJq9USBx2FjjDkukYjQMI/WDD6SH6QGTdotsH3cQQ6bjr9C+0ruxxx08= +-----END CERTIFICATE----- diff --git a/public/trust/README.md b/public/trust/README.md new file mode 100644 index 0000000..79f7919 --- /dev/null +++ b/public/trust/README.md @@ -0,0 +1,5 @@ +The PEM files in this directory are snapshots of the official C2PA Conformance +Program trust lists from https://github.com/c2pa-org/conformance-public. + +They are bundled so credential trust validation remains local and reproducible. +Refresh both files before a release and record the update in the release notes. diff --git a/scripts/build.mjs b/scripts/build.mjs new file mode 100644 index 0000000..469eae4 --- /dev/null +++ b/scripts/build.mjs @@ -0,0 +1,40 @@ +import { cp, mkdir } from 'node:fs/promises'; +import { fileURLToPath } from 'node:url'; +import { build } from 'esbuild'; + +const root = new URL('../', import.meta.url); +const outdir = new URL('../dist/', import.meta.url); +const rootPath = fileURLToPath(root); +const outdirPath = fileURLToPath(outdir); + +await mkdir(outdir, { recursive: true }); +await cp(new URL('../public/', import.meta.url), outdir, { recursive: true }); +await cp( + new URL('../node_modules/@contentauth/c2pa-web/dist/resources/c2pa_bg.wasm', import.meta.url), + new URL('../dist/c2pa_bg.wasm', import.meta.url) +); +await cp( + new URL('../node_modules/@contentauth/c2pa-web/dist/c2pa_worker.js', import.meta.url), + new URL('../dist/c2pa_worker.js', import.meta.url) +); + +await build({ + absWorkingDir: rootPath, + entryPoints: { + background: 'src/background/index.ts', + content: 'src/content/index.ts', + popup: 'src/popup/index.tsx', + options: 'src/options/index.tsx' + }, + outdir: outdirPath, + bundle: true, + format: 'iife', + platform: 'browser', + target: ['firefox128'], + jsx: 'automatic', + jsxImportSource: 'preact', + sourcemap: true, + minify: true, + legalComments: 'eof', + logLevel: 'info' +}); diff --git a/scripts/clean.mjs b/scripts/clean.mjs new file mode 100644 index 0000000..5a5f169 --- /dev/null +++ b/scripts/clean.mjs @@ -0,0 +1,6 @@ +import { rm } from 'node:fs/promises'; + +await Promise.all([ + rm(new URL('../dist', import.meta.url), { recursive: true, force: true }), + rm(new URL('../artifacts', import.meta.url), { recursive: true, force: true }) +]); diff --git a/src/background/c2pa.ts b/src/background/c2pa.ts new file mode 100644 index 0000000..4c369c7 --- /dev/null +++ b/src/background/c2pa.ts @@ -0,0 +1,219 @@ +import { createC2pa } from '@contentauth/c2pa-web'; +import type { Evidence } from '../shared/types'; + +const AI_SOURCE_TYPES = [ + 'trainedalgorithmicmedia', + 'compositewithtrainedalgorithmicmedia', + 'algorithmicallyenhanced', + 'algorithmicmedia' +]; + +interface RecordLike { + [key: string]: unknown; +} + +let c2paPromise: ReturnType | undefined; + +/** + * c2pa-web 0.14.4 rejects every explicit worker URL whose protocol is not + * `https:`, including Firefox's same-extension `moz-extension:` URLs. The + * package only reads `protocol` and `toString()` before constructing Worker, + * so this adapter lets its HTTPS-only guard validate while Worker still + * receives the real, CSP-approved packaged URL. Keep this isolated until the + * upstream SDK accepts browser-extension schemes directly. + */ +export class FirefoxExtensionWorkerUrl extends URL { + readonly #packagedUrl: string; + + constructor(packagedUrl: string) { + super('https://slopdetect.invalid/c2pa_worker.js'); + if (!packagedUrl.startsWith('moz-extension:')) { + throw new Error('C2PA worker must be a packaged Firefox extension resource.'); + } + this.#packagedUrl = packagedUrl; + } + + override toString(): string { + return this.#packagedUrl; + } +} + +async function initialiseC2pa(): ReturnType { + const [trustList, timestampTrustList] = await Promise.all([ + fetch(browser.runtime.getURL('trust/C2PA-TRUST-LIST.pem')).then((response) => response.text()), + fetch(browser.runtime.getURL('trust/C2PA-TSA-TRUST-LIST.pem')).then((response) => response.text()) + ]); + return createC2pa({ + wasmSrc: browser.runtime.getURL('c2pa_bg.wasm'), + workerSrc: new FirefoxExtensionWorkerUrl(browser.runtime.getURL('c2pa_worker.js')), + settings: { + trust: { trustAnchors: `${trustList}\n${timestampTrustList}` }, + verify: { + verifyTrust: true, + verifyAfterReading: true, + verifyTimestampTrust: true, + ocspFetch: false, + remoteManifestFetch: false + } + } + }); +} + +function getC2pa(): ReturnType { + c2paPromise ??= initialiseC2pa(); + return c2paPromise; +} + +function isRecord(value: unknown): value is RecordLike { + return typeof value === 'object' && value !== null && !Array.isArray(value); +} + +function walk(value: unknown, visit: (key: string, value: unknown) => void): void { + if (Array.isArray(value)) { + value.forEach((item) => walk(item, visit)); + return; + } + if (!isRecord(value)) return; + for (const [key, child] of Object.entries(value)) { + visit(key, child); + walk(child, visit); + } +} + +function collectStrings(value: unknown): string[] { + const strings: string[] = []; + walk(value, (_key, child) => { + if (typeof child === 'string') strings.push(child); + }); + return strings; +} + +function collectValidationCodes(value: unknown): string[] { + const codes = new Set(); + walk(value, (key, child) => { + if (/^(code|status|validation_status|validationStatus)$/i.test(key) && typeof child === 'string') { + codes.add(child); + } + if (/validation_status|validationStatus/i.test(key) && Array.isArray(child)) { + for (const entry of child) { + if (typeof entry === 'string') codes.add(entry); + else if (isRecord(entry) && typeof entry.code === 'string') codes.add(entry.code); + } + } + }); + return [...codes]; +} + +function findFirstString(value: unknown, matchingKeys: RegExp): string | undefined { + let found: string | undefined; + walk(value, (key, child) => { + if (!found && matchingKeys.test(key) && typeof child === 'string') found = child; + }); + return found; +} + +function hasTrustedCredential(value: unknown): boolean { + let trusted = false; + walk(value, (key, child) => { + if (/trusted/i.test(key) && child === true) trusted = true; + if (/validation_state|validationState/i.test(key) && child === 'Trusted') trusted = true; + }); + return trusted; +} + +function hasInvalidValidationState(value: unknown): boolean { + let invalid = false; + walk(value, (key, child) => { + if (/validation_state|validationState/i.test(key) && child === 'Invalid') invalid = true; + }); + return invalid; +} + +function containsManifest(value: unknown): boolean { + if (!isRecord(value)) return false; + return Boolean(value.active_manifest || value.activeManifest || value.manifests || value.claims); +} + +function isInvalidStatus(code: string): boolean { + return /invalid|mismatch|malformed|error|failure|revoked|expired/i.test(code); +} + +function serialisable(value: unknown): unknown { + try { + return JSON.parse(JSON.stringify(value, (_key, item) => (typeof item === 'bigint' ? item.toString() : item))); + } catch { + return undefined; + } +} + +function isMissingManifestError(error: unknown): boolean { + const message = error instanceof Error ? error.message : String(error); + return /manifest.*(?:not found|absent)|jumbf.*not found|no claim|unsupported.*(?:mime|format)/i.test(message); +} + +export async function inspectC2pa(blob: Blob, includeRaw: boolean): Promise { + let reader: Awaited>['reader']['fromBlob']>> | undefined; + try { + const c2pa = await getC2pa(); + reader = await c2pa.reader.fromBlob(blob.type || 'application/octet-stream', blob); + if (!reader) return []; + const store: unknown = await reader.manifestStore(); + return evidenceFromManifestStore(store, includeRaw); + } catch (error) { + if (isMissingManifestError(error)) return []; + const message = error instanceof Error ? error.message : String(error); + return [{ + id: crypto.randomUUID(), + kind: 'limitation', + strength: 'none', + verdict: 'unknown', + title: 'C2PA inspection failed', + detail: message.slice(0, 300), + detector: '@contentauth/c2pa-web' + }]; + } finally { + await reader?.free(); + } +} + +export function evidenceFromManifestStore(store: unknown, includeRaw: boolean): Evidence[] { + if (!containsManifest(store)) return []; + + const strings = collectStrings(store); + const aiGenerated = strings.some((value) => { + const normalised = value.toLowerCase().replace(/[^a-z]/g, ''); + return AI_SOURCE_TYPES.some((type) => normalised.includes(type)); + }); + const statuses = collectValidationCodes(store); + const invalid = hasInvalidValidationState(store) || statuses.some(isInvalidStatus); + const trusted = hasTrustedCredential(store); + const issuer = findFirstString(store, /issuer|common_name|organization|signer/i); + + if (invalid) { + return [{ + id: crypto.randomUUID(), + kind: 'c2pa', + strength: 'invalid', + verdict: 'invalid', + title: 'Invalid Content Credential', + detail: `C2PA provenance was present but validation reported: ${statuses.join(', ') || 'an integrity error'}.`, + detector: '@contentauth/c2pa-web', + issuer, + raw: includeRaw ? serialisable(store) : undefined + }]; + } + + return [{ + id: crypto.randomUUID(), + kind: 'c2pa', + strength: trusted ? 'verified' : 'detected', + verdict: aiGenerated ? 'ai' : 'not-ai-asserted', + title: aiGenerated ? 'AI provenance credential' : 'Content Credential', + detail: aiGenerated + ? `A ${trusted ? 'trusted and valid' : 'readable but not trusted'} C2PA claim identifies AI generation or manipulation.` + : `A ${trusted ? 'trusted and valid' : 'readable but not trusted'} C2PA claim was found without an AI-generation assertion.`, + detector: '@contentauth/c2pa-web', + issuer, + raw: includeRaw ? serialisable(store) : undefined + }]; +} diff --git a/src/background/cache.ts b/src/background/cache.ts new file mode 100644 index 0000000..e35c834 --- /dev/null +++ b/src/background/cache.ts @@ -0,0 +1,31 @@ +interface CacheEntry { + value: T; + touchedAt: number; +} + +export class ResultCache { + readonly #entries = new Map>(); + #clock = 0; + + public constructor(private readonly maximumEntries = 200) {} + + public get(key: string): T | undefined { + const entry = this.#entries.get(key); + if (!entry) return undefined; + entry.touchedAt = ++this.#clock; + return entry.value; + } + + public set(key: string, value: T): void { + this.#entries.set(key, { value, touchedAt: ++this.#clock }); + if (this.#entries.size <= this.maximumEntries) return; + + const oldest = [...this.#entries.entries()].sort((left, right) => left[1].touchedAt - right[1].touchedAt)[0]; + if (oldest) this.#entries.delete(oldest[0]); + } +} + +export async function hashBlob(blob: Blob): Promise { + const digest = await crypto.subtle.digest('SHA-256', await blob.arrayBuffer()); + return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, '0')).join(''); +} diff --git a/src/background/detectors.ts b/src/background/detectors.ts new file mode 100644 index 0000000..f36a234 --- /dev/null +++ b/src/background/detectors.ts @@ -0,0 +1,38 @@ +import type { Evidence, ImageCandidate, TextCandidate } from '../shared/types'; + +export interface ImageWatermarkDetector { + readonly id: string; + readonly name: string; + supports(mimeType: string): boolean; + detect(blob: Blob, candidate: ImageCandidate): Promise; +} + +export interface TextWatermarkDetector { + readonly id: string; + readonly name: string; + readonly minimumTokens: number; + supports(language?: string): boolean; + detect(candidate: TextCandidate): Promise; +} + +// Watermark schemes currently require a provider-specific public SDK or API. +// Adapters are deliberately empty until a detector can be tested end-to-end. +export const imageWatermarkDetectors: readonly ImageWatermarkDetector[] = []; +export const textWatermarkDetectors: readonly TextWatermarkDetector[] = []; + +export async function runImageWatermarkDetectors( + blob: Blob, + candidate: ImageCandidate +): Promise { + const compatible = imageWatermarkDetectors.filter((detector) => detector.supports(blob.type)); + const results = await Promise.allSettled(compatible.map((detector) => detector.detect(blob, candidate))); + return results.flatMap((result) => (result.status === 'fulfilled' ? result.value : [])); +} + +export async function runTextWatermarkDetectors(candidate: TextCandidate): Promise { + const compatible = textWatermarkDetectors.filter( + (detector) => candidate.tokenEstimate >= detector.minimumTokens && detector.supports() + ); + const results = await Promise.allSettled(compatible.map((detector) => detector.detect(candidate))); + return results.flatMap((result) => (result.status === 'fulfilled' ? result.value : [])); +} diff --git a/src/background/disclosures.ts b/src/background/disclosures.ts new file mode 100644 index 0000000..d21d6be --- /dev/null +++ b/src/background/disclosures.ts @@ -0,0 +1,48 @@ +import type { Evidence, PageDisclosureCandidate } from '../shared/types'; + +const AI_DISCLOSURE = /\b(ai[- ]generated|generated (?:or manipulated )?by ai|artificially generated|created with (?:generative )?ai|synthetic media|trainedalgorithmicmedia)\b/i; +const AI_GENERATOR = /\b(chatgpt|openai|claude|anthropic|gemini|midjourney|dall[ -]?e|stable diffusion|firefly|copilot|framer ai|wix ai)\b/i; + +function evidenceId(prefix: string, value: string): string { + let hash = 0; + for (const character of value) hash = (hash * 31 + character.charCodeAt(0)) | 0; + return `${prefix}-${Math.abs(hash)}`; +} + +export function analyseDisclosures(candidates: PageDisclosureCandidate[]): Evidence[] { + const evidence: Evidence[] = []; + const seen = new Set(); + + for (const candidate of candidates) { + const value = candidate.value.trim().slice(0, 500); + if (!value) continue; + const identity = `${candidate.source}:${value}`.toLowerCase(); + if (seen.has(identity)) continue; + seen.add(identity); + + if (AI_DISCLOSURE.test(value) || /^(true|yes|1)$/i.test(value) && /ai/i.test(candidate.source)) { + evidence.push({ + id: evidenceId('disclosure', identity), + kind: 'disclosure', + strength: 'disclosed', + verdict: 'ai', + title: 'Publisher AI disclosure', + detail: `${candidate.source}: ${value}` + }); + continue; + } + + if (candidate.source.toLowerCase().includes('generator') && AI_GENERATOR.test(value)) { + evidence.push({ + id: evidenceId('generator', identity), + kind: 'generator', + strength: 'clue', + verdict: 'unknown', + title: 'AI-related generator metadata', + detail: `${candidate.source}: ${value}. This is a tooling clue, not proof that the page content was AI-generated.` + }); + } + } + + return evidence; +} diff --git a/src/background/heuristics.ts b/src/background/heuristics.ts new file mode 100644 index 0000000..50934b8 --- /dev/null +++ b/src/background/heuristics.ts @@ -0,0 +1,23 @@ +import type { Evidence, HeuristicFinding } from '../shared/types'; + +export function evidenceFromHeuristics(findings: HeuristicFinding[]): Evidence[] { + return findings.map((finding) => ({ + id: `heuristic:${finding.ruleId}`, + kind: 'heuristic', + strength: 'clue', + verdict: 'unknown', + title: finding.title, + detail: `${finding.detail}${finding.sample ? ` Example: ${finding.sample}` : ''}`, + detector: 'SlopDetect deterministic page heuristics', + category: finding.category, + score: finding.score, + occurrences: finding.occurrences + })); +} + +export function heuristicScore(evidence: Evidence[]): number { + const heuristicEvidence = evidence.filter((item) => item.kind === 'heuristic'); + const base = heuristicEvidence.reduce((sum, item) => sum + (item.score || 0), 0); + const categories = new Set(heuristicEvidence.map((item) => item.category).filter(Boolean)); + return base + Math.max(0, categories.size - 1); +} diff --git a/src/background/image-metadata.ts b/src/background/image-metadata.ts new file mode 100644 index 0000000..2bd9ea5 --- /dev/null +++ b/src/background/image-metadata.ts @@ -0,0 +1,42 @@ +import type { Evidence } from '../shared/types'; + +const MAX_METADATA_SCAN_BYTES = 2 * 1024 * 1024; + +interface GeneratorSignature { + name: string; + pattern: RegExp; +} + +const SIGNATURES: GeneratorSignature[] = [ + { name: 'OpenAI / DALL·E', pattern: /\b(?:openai|dall[ -]?e)\b/i }, + { name: 'Midjourney', pattern: /\bmidjourney\b/i }, + { name: 'Stable Diffusion', pattern: /\bstable[ _-]?diffusion\b/i }, + { name: 'AUTOMATIC1111', pattern: /\bautomatic1111\b/i }, + { name: 'ComfyUI', pattern: /\bcomfyui\b|"(?:ckpt_name|sampler_name|positive)"\s*:/i }, + { name: 'InvokeAI', pattern: /\binvokeai\b/i }, + { name: 'Fooocus', pattern: /\bfooocus\b/i }, + { name: 'NovelAI', pattern: /\bnovelai\b/i }, + { name: 'Stable Diffusion parameters', pattern: /\bsteps:\s*\d+[^\0]{0,300}\bsampler:\s*[^,\0]+[^\0]{0,300}\bcfg scale:\s*[\d.]+/i } +]; + +function evidenceId(name: string): string { + return `image-generator:${name.toLowerCase().replace(/[^a-z0-9]+/g, '-')}`; +} + +export async function inspectImageGeneratorMetadata(blob: Blob): Promise { + const head = await blob.slice(0, Math.min(blob.size, MAX_METADATA_SCAN_BYTES)).arrayBuffer(); + const text = new TextDecoder('latin1').decode(head); + const found = SIGNATURES.filter((signature) => signature.pattern.test(text)); + if (found.length === 0) return []; + + const names = [...new Set(found.map((signature) => signature.name))]; + return [{ + id: evidenceId(names.join('-')), + kind: 'generator', + strength: 'detected', + verdict: 'ai', + title: 'AI generator metadata detected', + detail: `The image bytes contain metadata associated with ${names.join(', ')}. This survives some exports, but it is unsigned and can be removed or forged.`, + detector: 'SlopDetect image metadata signatures' + }]; +} diff --git a/src/background/index.ts b/src/background/index.ts new file mode 100644 index 0000000..efc2052 --- /dev/null +++ b/src/background/index.ts @@ -0,0 +1,55 @@ +import browser from 'webextension-polyfill'; +import { scanPage } from './scanner'; +import type { RuntimeRequest, RuntimeResponse, ScanResult } from '../shared/types'; + +Object.assign(globalThis, { browser }); + +const tabResults = new Map(); + +browser.runtime.onMessage.addListener((message: unknown, sender: browser.Runtime.MessageSender) => { + const request = message as RuntimeRequest; + if (!request || typeof request !== 'object' || typeof request.type !== 'string') return undefined; + + if (request.type === 'analyse-page') { + return scanPage(request.page, request.mode) + .then((result): RuntimeResponse => { + if (sender.tab?.id !== undefined) { + tabResults.set(sender.tab.id, result); + const badge = ['verified-ai', 'provenance-detected', 'watermark-detected', 'publisher-disclosed'].includes(result.summary.status) ? 'AI' + : result.summary.status === 'invalid-credential' ? '!' + : result.summary.status === 'mixed-provenance' ? '≋' + : result.summary.status === 'heuristic-suspected' ? 'S' + : ''; + const color = ['verified-ai', 'watermark-detected'].includes(result.summary.status) ? '#6847ee' + : result.summary.status === 'invalid-credential' ? '#bd2535' + : result.summary.status === 'heuristic-suspected' ? '#b05d16' + : result.summary.status === 'mixed-provenance' ? '#4761a8' : '#956100'; + void browser.action.setBadgeText({ tabId: sender.tab.id, text: badge }); + void browser.action.setBadgeBackgroundColor({ tabId: sender.tab.id, color }); + } + return { ok: true, data: result }; + }) + .catch((error): RuntimeResponse => ({ + ok: false, + error: error instanceof Error ? error.message : String(error) + })); + } + + if (request.type === 'get-tab-result') { + return Promise.resolve({ ok: true, data: tabResults.get(request.tabId) } satisfies RuntimeResponse); + } + + if (request.type === 'clear-tab-result') { + tabResults.delete(request.tabId); + return Promise.resolve({ ok: true } satisfies RuntimeResponse); + } + + return undefined; +}); + +browser.tabs.onRemoved.addListener((tabId) => tabResults.delete(tabId)); +browser.tabs.onUpdated.addListener((tabId, changeInfo) => { + if (changeInfo.status !== 'loading' && changeInfo.url === undefined) return; + tabResults.delete(tabId); + void browser.action.setBadgeText({ tabId, text: '' }); +}); diff --git a/src/background/scanner.ts b/src/background/scanner.ts new file mode 100644 index 0000000..5b616f6 --- /dev/null +++ b/src/background/scanner.ts @@ -0,0 +1,165 @@ +import { inspectC2pa } from './c2pa'; +import { ResultCache, hashBlob } from './cache'; +import { analyseDisclosures } from './disclosures'; +import { evidenceFromHeuristics } from './heuristics'; +import { inspectImageGeneratorMetadata } from './image-metadata'; +import { runImageWatermarkDetectors, runTextWatermarkDetectors, textWatermarkDetectors } from './detectors'; +import { aggregateSummary, createAssetResult } from '../shared/status'; +import { + DEFAULT_SETTINGS, + type AssetResult, + type Evidence, + type ExtensionSettings, + type ImageCandidate, + type PageCandidate, + type ScanResult, + type TextCandidate +} from '../shared/types'; + +const imageCache = new ResultCache(200); +const AUTO_IMAGE_MAX_BYTES = 10 * 1024 * 1024; + +async function loadSettings(): Promise { + const saved = await browser.storage.local.get('settings'); + return { ...DEFAULT_SETTINGS, ...(saved.settings as Partial | undefined) }; +} + +function isPrivateHost(hostname: string): boolean { + const host = hostname.toLowerCase().replace(/^\[|\]$/g, ''); + if (host === 'localhost' || host === '::1' || host.endsWith('.local')) return true; + if (/^127\./.test(host) || /^10\./.test(host) || /^192\.168\./.test(host)) return true; + const private172 = /^172\.(\d{1,2})\./.exec(host); + return private172 ? Number(private172[1]) >= 16 && Number(private172[1]) <= 31 : false; +} + +function safeAssetUrl(value: string, pageUrl: string): URL | undefined { + try { + const url = new URL(value); + if (!['http:', 'https:', 'data:'].includes(url.protocol) || url.username || url.password) return undefined; + if (url.protocol === 'data:') return url; + const page = new URL(pageUrl); + if (isPrivateHost(url.hostname) && url.origin !== page.origin) return undefined; + return url; + } catch { + return undefined; + } +} + +async function fetchImage(candidate: ImageCandidate, maximumBytes: number, pageUrl: string): Promise { + const url = safeAssetUrl(candidate.url, pageUrl); + if (!url) throw new Error('Unsupported or unsafe image URL scheme.'); + const response = await fetch(url.href, { credentials: 'omit', cache: 'force-cache', redirect: 'error' }); + if (!response.ok) throw new Error(`Image request returned HTTP ${response.status}.`); + + const declaredLength = Number(response.headers.get('content-length') || 0); + if (declaredLength > maximumBytes) throw new Error(`Image exceeds the ${Math.round(maximumBytes / 1048576)} MB scan limit.`); + const blob = await response.blob(); + if (blob.size > maximumBytes) throw new Error(`Image exceeds the ${Math.round(maximumBytes / 1048576)} MB scan limit.`); + if (blob.type && !blob.type.startsWith('image/')) throw new Error(`Resource is ${blob.type}, not an image.`); + return blob; +} + +async function scanImage( + candidate: ImageCandidate, + settings: ExtensionSettings, + pageUrl: string +): Promise { + try { + const blob = await fetchImage(candidate, settings.maxImageBytes, pageUrl); + const cacheKey = `${await hashBlob(blob)}:${settings.includeRawEvidence}`; + let evidence = imageCache.get(cacheKey); + if (!evidence) { + evidence = [ + ...(await inspectC2pa(blob, settings.includeRawEvidence)), + ...(await inspectImageGeneratorMetadata(blob)), + ...(await runImageWatermarkDetectors(blob, candidate)) + ]; + imageCache.set(cacheKey, evidence); + } + return createAssetResult(candidate.id, 'image', candidate.alt || 'Image', evidence, candidate.url); + } catch (error) { + const detail = error instanceof Error ? error.message : String(error); + return createAssetResult(candidate.id, 'image', candidate.alt || 'Image', [{ + id: crypto.randomUUID(), + kind: 'limitation', + strength: 'none', + verdict: 'unknown', + title: 'Image could not be inspected', + detail + }], candidate.url); + } +} + +async function scanText(candidate: TextCandidate): Promise { + const evidence = await runTextWatermarkDetectors(candidate); + if (evidence.length === 0 && candidate.tokenEstimate >= 200 && textWatermarkDetectors.length === 0) { + evidence.push({ + id: crypto.randomUUID(), + kind: 'limitation', + strength: 'none', + verdict: 'unknown', + title: 'No compatible text-watermark detector', + detail: 'The text was collected, but no public interoperable detector is bundled for its watermark scheme.' + }); + } + return createAssetResult(candidate.id, 'text', `Text sample (${candidate.tokenEstimate} tokens)`, evidence); +} + +async function mapWithConcurrency( + items: T[], + concurrency: number, + mapper: (item: T) => Promise +): Promise { + const results = new Array(items.length); + let cursor = 0; + const workers = Array.from({ length: Math.min(concurrency, items.length) }, async () => { + while (cursor < items.length) { + const index = cursor++; + const item = items[index]; + if (item !== undefined) results[index] = await mapper(item); + } + }); + await Promise.all(workers); + return results; +} + +export async function scanPage(page: PageCandidate, mode: 'auto' | 'manual' = 'manual'): Promise { + const settings = await loadSettings(); + const imageLimit = mode === 'auto' + ? Math.min(settings.maxImagesPerPage, settings.maxAutoImagesPerPage) + : settings.maxImagesPerPage; + const imageSettings = mode === 'auto' + ? { ...settings, maxImageBytes: Math.min(settings.maxImageBytes, AUTO_IMAGE_MAX_BYTES) } + : settings; + const selectedImages = [...page.images] + .sort((left, right) => right.width * right.height - left.width * left.height) + .slice(0, imageLimit); + const pageEvidence = [ + ...analyseDisclosures(page.disclosures), + ...(settings.enableHeuristicDetection ? evidenceFromHeuristics(page.heuristics || []) : []) + ]; + const pageResult = createAssetResult('page', 'page', page.title || page.url, pageEvidence, page.url); + const [images, texts] = await Promise.all([ + mapWithConcurrency(selectedImages, 3, (candidate) => scanImage(candidate, imageSettings, page.url)), + mapWithConcurrency(page.texts, 2, scanText) + ]); + const warnings: string[] = []; + if (page.images.length > selectedImages.length) { + warnings.push(`${page.images.length - selectedImages.length} images were skipped because of the ${mode} scan limit.`); + } + if (textWatermarkDetectors.length === 0 && page.texts.some((text) => text.tokenEstimate >= 200)) { + warnings.push('Text was not classified: no compatible public watermark detector is bundled.'); + } + + return { + scanId: crypto.randomUUID(), + pageUrl: page.url, + pageTitle: page.title, + scannedAt: new Date().toISOString(), + summary: aggregateSummary(pageResult, images, texts, page.images.length, page.texts.length, settings.heuristicThreshold), + page: pageResult, + images, + texts, + warnings + }; +} diff --git a/src/content/badges.ts b/src/content/badges.ts new file mode 100644 index 0000000..ab8c115 --- /dev/null +++ b/src/content/badges.ts @@ -0,0 +1,75 @@ +import type { AssetResult, ScanResult } from '../shared/types'; +import { IMAGE_ID_ATTRIBUTE } from './discovery'; + +const HOST_ID = 'slopdetect-badge-layer'; +let refreshListener: (() => void) | undefined; + +function badgePresentation(result: AssetResult): { text: string; className: string; title: string } | undefined { + if (result.verdict === 'invalid') return { text: '!', className: 'invalid', title: 'Invalid provenance credential' }; + if (result.verdict === 'ai' && result.strength === 'verified') { + return { text: 'AI', className: 'ai', title: 'Verified AI provenance' }; + } + if (result.verdict === 'ai') return { text: 'AI', className: 'detected', title: 'AI origin detected or disclosed' }; + if (result.strength === 'verified' || result.strength === 'detected') { + return { text: 'CC', className: 'credential', title: 'Content Credential found' }; + } + return undefined; +} + +export function clearBadges(): void { + document.getElementById(HOST_ID)?.remove(); + if (refreshListener) { + window.removeEventListener('scroll', refreshListener, true); + window.removeEventListener('resize', refreshListener); + refreshListener = undefined; + } +} + +export function renderBadges(result: ScanResult): void { + clearBadges(); + const marked = result.images + .map((image) => ({ image, presentation: badgePresentation(image) })) + .filter((entry) => entry.presentation !== undefined); + if (marked.length === 0) return; + + const host = document.createElement('div'); + host.id = HOST_ID; + host.style.cssText = 'all:initial;position:fixed;inset:0;z-index:2147483647;pointer-events:none;'; + const root = host.attachShadow({ mode: 'closed' }); + const style = document.createElement('style'); + style.textContent = ` + .badge { position: fixed; min-width: 24px; height: 24px; padding: 0 6px; box-sizing: border-box; + display: grid; place-items: center; color: white; border: 2px solid white; border-radius: 999px; + font: 700 11px/1 system-ui, sans-serif; box-shadow: 0 2px 8px #0008; } + .ai { background: #6847ee; } .detected { background: #9b6500; } + .credential { background: #18735c; } .invalid { background: #bd2535; } + `; + root.append(style); + + const placements: Array<{ badge: HTMLDivElement; target: Element }> = []; + for (const entry of marked) { + const target = document.querySelector(`[${IMAGE_ID_ATTRIBUTE}="${window.CSS.escape(entry.image.id)}"]`); + if (!target || !entry.presentation) continue; + const badge = document.createElement('div'); + badge.className = `badge ${entry.presentation.className}`; + badge.textContent = entry.presentation.text; + badge.title = entry.presentation.title; + badge.setAttribute('aria-label', entry.presentation.title); + root.append(badge); + placements.push({ badge, target }); + } + + const position = (): void => { + for (const placement of placements) { + const rect = placement.target.getBoundingClientRect(); + placement.badge.style.left = `${Math.max(2, rect.right - 28)}px`; + placement.badge.style.top = `${Math.max(2, rect.top + 4)}px`; + placement.badge.style.display = rect.bottom < 0 || rect.top > window.innerHeight ? 'none' : 'grid'; + } + }; + position(); + refreshListener = position; + window.addEventListener('scroll', position, true); + window.addEventListener('resize', position); + document.documentElement.append(host); +} diff --git a/src/content/discovery.ts b/src/content/discovery.ts new file mode 100644 index 0000000..f0eef94 --- /dev/null +++ b/src/content/discovery.ts @@ -0,0 +1,154 @@ +import type { + ImageCandidate, + PageCandidate, + PageDisclosureCandidate, + TextCandidate +} from '../shared/types'; +import { discoverHeuristics } from './heuristics'; + +const IMAGE_ID_ATTRIBUTE = 'data-slopdetect-image-id'; +const MAX_TEXT_BLOCKS = 8; +const MIN_TEXT_CHARACTERS = 300; + +function isVisible(element: Element): boolean { + const rect = element.getBoundingClientRect(); + const style = window.getComputedStyle(element); + return rect.width > 0 && rect.height > 0 && style.visibility !== 'hidden' && style.display !== 'none'; +} + +function makeImageCandidate(element: Element, url: string, alt = ''): ImageCandidate | undefined { + if (!url || !isVisible(element)) return undefined; + const rect = element.getBoundingClientRect(); + if (rect.width < 16 || rect.height < 16) return undefined; + const existingId = element.getAttribute(IMAGE_ID_ATTRIBUTE); + const id = existingId || crypto.randomUUID(); + element.setAttribute(IMAGE_ID_ATTRIBUTE, id); + return { + id, + url: new URL(url, document.baseURI).href, + alt: alt.trim().slice(0, 200), + width: Math.round(rect.width), + height: Math.round(rect.height) + }; +} + +function discoverImages(): ImageCandidate[] { + const candidates: ImageCandidate[] = []; + const seenUrls = new Set(); + + for (const image of document.querySelectorAll('img')) { + const candidate = makeImageCandidate(image, image.currentSrc || image.src, image.alt); + if (candidate && !seenUrls.has(candidate.url)) { + candidates.push(candidate); + seenUrls.add(candidate.url); + } + } + + for (const image of document.querySelectorAll('svg image')) { + const href = image.getAttribute('href') || image.getAttribute('xlink:href') || ''; + const candidate = makeImageCandidate(image, href, image.getAttribute('aria-label') || 'SVG image'); + if (candidate && !seenUrls.has(candidate.url)) { + candidates.push(candidate); + seenUrls.add(candidate.url); + } + } + + const elements = [...document.querySelectorAll('body *')].slice(0, 2000); + for (const element of elements) { + const background = window.getComputedStyle(element).backgroundImage; + const match = /^url\(["']?(.*?)["']?\)$/.exec(background); + if (!match?.[1]) continue; + const candidate = makeImageCandidate(element, match[1], element.getAttribute('aria-label') || 'Background image'); + if (candidate && !seenUrls.has(candidate.url)) { + candidates.push(candidate); + seenUrls.add(candidate.url); + } + } + + return candidates; +} + +export function estimateTokens(text: string): number { + return text.trim() ? Math.ceil(text.trim().split(/\s+/).length * 1.3) : 0; +} + +function discoverText(): TextCandidate[] { + const selectors = 'article p, main p, [role="main"] p, article li, main li, blockquote'; + const values = [...document.querySelectorAll(selectors)] + .filter(isVisible) + .map((element) => element.innerText.trim()) + .filter((text) => text.length >= MIN_TEXT_CHARACTERS); + + const unique = [...new Set(values)].sort((left, right) => right.length - left.length).slice(0, MAX_TEXT_BLOCKS); + if (unique.length === 0) { + const root = document.querySelector('article, main, [role="main"]') || document.body; + const combined = root?.innerText.trim().slice(0, 24_000) || ''; + if (combined.length >= MIN_TEXT_CHARACTERS) unique.push(combined); + } + + return unique.map((text) => ({ id: crypto.randomUUID(), text, tokenEstimate: estimateTokens(text) })); +} + +function pushDisclosure( + output: PageDisclosureCandidate[], + source: string, + value: string | null | undefined +): void { + const trimmed = value?.trim(); + if (trimmed) output.push({ source, value: trimmed.slice(0, 2000) }); +} + +function discoverDisclosures(): PageDisclosureCandidate[] { + const candidates: PageDisclosureCandidate[] = []; + const interestingMeta = /ai|artificial|synthetic|provenance|credential|generator|content-origin/i; + + for (const meta of document.querySelectorAll('meta[name], meta[property]')) { + const name = meta.name || meta.getAttribute('property') || ''; + if (interestingMeta.test(name)) { + pushDisclosure(candidates, `meta:${name}`, meta.content); + } + } + + for (const link of document.querySelectorAll('link[rel]')) { + if (/credential|provenance|c2pa|manifest/i.test(link.rel)) { + pushDisclosure(candidates, `link:${link.rel}`, link.href); + } + } + + for (const script of document.querySelectorAll('script[type="application/ld+json"]')) { + if (/"(?:aiGenerated|isAIGenerated|contentOrigin|digitalSourceType)"\s*:\s*(?:true|"[^"]*(?:trainedAlgorithmicMedia|synthetic|AI)[^"]*")/i.test(script.textContent || '')) { + pushDisclosure(candidates, 'structured-data', script.textContent); + } + } + + const labelSelectors = 'figcaption, small, [class*="disclosure" i], [class*="provenance" i], [class*="credit" i], [aria-label*="AI-generated" i]'; + for (const element of document.querySelectorAll(labelSelectors)) { + const value = (element.innerText || element.getAttribute('aria-label') || '').trim(); + if (value.length <= 300 && /\b(?:AI[- ]generated|generated by AI|artificially generated|created with AI|synthetic media)\b/i.test(value)) { + pushDisclosure(candidates, 'visible-label', value); + } + } + + for (const element of document.querySelectorAll('[data-ai-generated], [data-content-origin]')) { + pushDisclosure( + candidates, + element.hasAttribute('data-ai-generated') ? 'data-ai-generated' : 'data-content-origin', + element.getAttribute('data-ai-generated') || element.getAttribute('data-content-origin') + ); + } + + return candidates; +} + +export function discoverPage(): PageCandidate { + return { + url: location.href, + title: document.title, + images: discoverImages(), + texts: discoverText(), + disclosures: discoverDisclosures(), + heuristics: discoverHeuristics() + }; +} + +export { IMAGE_ID_ATTRIBUTE }; diff --git a/src/content/heuristics.ts b/src/content/heuristics.ts new file mode 100644 index 0000000..60a5e14 --- /dev/null +++ b/src/content/heuristics.ts @@ -0,0 +1,247 @@ +import type { HeuristicCategory, HeuristicFinding } from '../shared/types'; + +const MAX_ELEMENTS = 1500; +const MAX_STYLED_ELEMENTS = 700; + +interface MutableFinding extends HeuristicFinding { + samples: Set; +} + +function finaliseFinding(finding: MutableFinding): HeuristicFinding { + return { + ruleId: finding.ruleId, + category: finding.category, + title: finding.title, + detail: finding.detail, + score: finding.score, + occurrences: finding.occurrences, + sample: finding.sample + }; +} + +function visible(element: HTMLElement): boolean { + const rect = element.getBoundingClientRect(); + const style = window.getComputedStyle(element); + return rect.width >= 12 && rect.height >= 8 && style.display !== 'none' && style.visibility !== 'hidden' && Number(style.opacity) !== 0; +} + +function pixels(value: string): number { + const parsed = Number.parseFloat(value); + return Number.isFinite(parsed) ? parsed : 0; +} + +function durationSeconds(value: string): number { + return value.split(',').reduce((maximum, item) => { + const trimmed = item.trim(); + const parsed = Number.parseFloat(trimmed); + return Math.max(maximum, trimmed.endsWith('ms') ? parsed / 1000 : parsed); + }, 0); +} + +function shortText(element: HTMLElement): string { + return (element.innerText || element.textContent || '').replace(/\s+/g, ' ').trim().slice(0, 100); +} + +function isCard(element: HTMLElement, style: CSSStyleDeclaration): boolean { + const rect = element.getBoundingClientRect(); + if (rect.width < 120 || rect.height < 55) return false; + const hasEdge = pixels(style.borderTopWidth) > 0 || style.boxShadow !== 'none'; + const hasSurface = style.backgroundColor !== 'rgba(0, 0, 0, 0)' || style.backgroundImage !== 'none'; + return pixels(style.borderRadius) >= 8 && (hasEdge || hasSurface); +} + +function structureSignature(element: HTMLElement): string { + const children = [...element.children].slice(0, 8); + return `${element.tagName}:${children.map((child) => child.tagName).join(',')}:${Boolean(element.querySelector('h2,h3,h4'))}:${Boolean(element.querySelector('p'))}`; +} + +function normaliseFont(fontFamily: string): string { + return fontFamily.split(',')[0]?.replace(/["']/g, '').trim().toLowerCase() || ''; +} + +function addFinding( + findings: Map, + ruleId: string, + category: HeuristicCategory, + title: string, + detail: string, + score: number, + sample = '' +): void { + const existing = findings.get(ruleId); + if (existing) { + existing.occurrences += 1; + if (sample) existing.samples.add(sample); + return; + } + findings.set(ruleId, { + ruleId, + category, + title, + detail, + score, + occurrences: 1, + sample: sample || undefined, + samples: new Set(sample ? [sample] : []) + }); +} + +export function analyseCopyPatterns(text: string): HeuristicFinding[] { + const findings = new Map(); + const clean = text.replace(/\s+/g, ' ').trim(); + const words = clean ? clean.split(/\s+/).length : 0; + const buzzwords = clean.match(/\b(?:seamlessly|streamline|empower|supercharge|elevate|unlock|revolutioni[sz]e|cutting-edge|next-generation|world-class|enterprise-grade|game-changer|transformative|delve|ever-evolving|digital landscape)\b/gi) || []; + const uniqueBuzzwords = [...new Set(buzzwords.map((word) => word.toLowerCase()))]; + if (uniqueBuzzwords.length >= 3) { + addFinding(findings, 'copy-marketing-buzzwords', 'copy', 'Dense generic marketing vocabulary', 'Several stock phrases commonly produced by generated SaaS copy appear together.', 2, uniqueBuzzwords.slice(0, 6).join(', ')); + } + + const emDashes = (clean.match(/—/g) || []).length; + if (emDashes >= 3 && (words === 0 || emDashes / words >= 0.003)) { + addFinding(findings, 'copy-em-dash-cadence', 'copy', 'Em-dash-heavy cadence', 'The page uses em dashes frequently enough to be a weak generated-copy signal.', 1, `${emDashes} em dashes in about ${words} words`); + } + + const aphorisms = clean.match(/\bnot\s+(?:just\s+)?[^.!?]{1,50}[.!?]\s+(?:it(?:'s| is)|we(?:'re| are)|a|the)\s+[^.!?]{1,55}[.!?]/gi) || []; + if (aphorisms.length >= 2) { + addFinding(findings, 'copy-aphoristic-contrast', 'copy', 'Repeated manufactured contrast', 'Multiple “not X, but Y” style fragments create a recurring generated-marketing cadence.', 2, aphorisms[0]); + } + + const theater = clean.match(/\b(?:growth|innovation|productivity|marketing|security|compliance|performance) theater\b/gi) || []; + if (theater.length > 0) { + addFinding(findings, 'copy-theater-framing', 'copy', '“Theater” framing', 'Dismissing a practice as “theater” is a recurring generated-copy tic.', 1, theater[0]); + } + + const stockPromises = clean.match(/\b(?:build the future|everything you need|ship faster|work smarter|future of work|designed for modern teams|from idea to impact)\b/gi) || []; + if (stockPromises.length >= 2) { + addFinding(findings, 'copy-stock-promises', 'copy', 'Stock AI-product promises', 'Several interchangeable startup promises appear on the same page.', 2, stockPromises.slice(0, 3).join(', ')); + } + + return [...findings.values()].map(finaliseFinding); +} + +export function discoverHeuristics(): HeuristicFinding[] { + const findings = new Map(); + const elements = [...document.querySelectorAll('body *')].slice(0, MAX_ELEMENTS); + const styled = elements.filter(visible).slice(0, MAX_STYLED_ELEMENTS); + const cards: HTMLElement[] = []; + const fontCounts = new Map(); + + for (const element of styled) { + const style = window.getComputedStyle(element); + const rect = element.getBoundingClientRect(); + const text = shortText(element); + const background = style.backgroundImage.toLowerCase(); + const radius = pixels(style.borderRadius); + const font = normaliseFont(style.fontFamily); + if (font) fontCounts.set(font, (fontCounts.get(font) || 0) + 1); + if (isCard(element, style)) cards.push(element); + + if (/repeating-(?:linear|radial)-gradient/.test(background)) { + addFinding(findings, 'visual-repeating-gradient', 'visual', 'Decorative repeating-gradient texture', 'Repeating gradient stripes or grids are a recurring generated-interface decoration.', 2); + } + if (/radial-gradient/.test(background) && rect.width >= 180 && rect.height >= 100) { + addFinding(findings, 'visual-radial-glow', 'visual', 'Decorative radial glow', 'A large radial-gradient halo is used as surface decoration.', 2); + } + if (/gradient/.test(background) && /(?:rgb\([^)]*(?:128|139|147|168|124|99)[^)]*\)|#(?:7c3aed|8b5cf6|9333ea|6366f1|06b6d4|22d3ee))/i.test(background)) { + addFinding(findings, 'visual-purple-cyan-gradient', 'visual', 'Purple/cyan gradient palette', 'Purple-to-blue or cyan gradients are a common generated landing-page default.', 2); + } + if (/gradient/.test(background) && (style.backgroundClip === 'text' || style.getPropertyValue('-webkit-background-clip') === 'text') && (style.color === 'transparent' || /rgba\([^)]*,\s*0\)/.test(style.color))) { + addFinding(findings, 'visual-gradient-text', 'visual', 'Gradient text', 'A heading or metric uses a decorative gradient fill.', 2, text); + } + + const sideWidths = [style.borderTopWidth, style.borderRightWidth, style.borderBottomWidth, style.borderLeftWidth].map(pixels); + const thickSides = sideWidths.filter((width) => width >= 4).length; + if (radius >= 8 && thickSides === 1 && sideWidths.filter((width) => width <= 2).length >= 3) { + addFinding(findings, 'visual-side-accent', 'visual', 'Side-tab accent border', 'A rounded panel has one thick colored edge, a recognizable generated-UI pattern.', 2, text); + } + if (radius >= 8 && sideWidths.some((width) => width > 0 && width <= 1.5) && style.boxShadow !== 'none' && /\s(?:1[6-9]|[2-9]\d)px/.test(style.boxShadow)) { + addFinding(findings, 'visual-hairline-shadow', 'visual', 'Hairline border with wide shadow', 'A thin border is paired with a large diffuse shadow.', 1, text); + } + if (radius >= 24 && rect.width >= 120 && rect.width <= 520 && rect.height >= 55 && rect.height <= 320 && !/^(button|input)$/i.test(element.tagName)) { + addFinding(findings, 'visual-extreme-radius', 'visual', 'Over-rounded cards', 'Small content panels use very large corner radii, producing the common soft-blob aesthetic.', 1, text); + } + + const isSmallSquare = rect.width >= 28 && rect.width <= 84 && rect.height >= 28 && rect.height <= 84 && Math.abs(rect.width - rect.height) <= 14; + if (isSmallSquare && radius >= 6 && element.parentElement?.querySelector(':scope > h2, :scope > h3, :scope > h4')) { + addFinding(findings, 'typography-icon-tile', 'typography', 'Icon tile stacked above a heading', 'A rounded-square icon container sits above a card heading, a frequent generated feature-card template.', 2, text); + } + + if (/^H1$/.test(element.tagName) && text.split(/\s+/).length >= 6 && pixels(style.fontSize) >= 48) { + addFinding(findings, 'typography-oversized-hero', 'typography', 'Oversized sentence-length hero', 'A long sentence is rendered at display size in the opening hierarchy.', 1, text); + } + if (/^H1$/.test(element.tagName) && style.fontStyle === 'italic' && /serif/.test(style.fontFamily) && pixels(style.fontSize) >= 44) { + addFinding(findings, 'typography-italic-serif-hero', 'typography', 'Italic serif hero headline', 'An oversized italic serif hero is a common recent AI-startup default.', 2, text); + } + + const nextHeading = element.nextElementSibling; + const uppercaseShort = text.length >= 2 && text.length <= 40 && text === text.toUpperCase() && /[A-Z]/.test(text); + const pill = radius >= rect.height * 0.4 && rect.width < 260; + if ((uppercaseShort || pill) && pixels(style.fontSize) <= 15 && nextHeading && /^H[1-3]$/.test(nextHeading.tagName)) { + addFinding(findings, 'typography-hero-eyebrow', 'typography', 'Hero eyebrow or pill', 'A small tracked label or pill appears directly above a large heading.', 2, text); + } + + const animation = style.animationName; + const infinite = style.animationIterationCount.split(',').some((value) => value.trim() === 'infinite'); + if (animation !== 'none' && infinite && durationSeconds(style.animationDuration) <= 4) { + if (/(?:status|pulse|ping|dot|live|online)/i.test(`${element.className} ${element.id} ${animation}`)) { + addFinding(findings, 'motion-pulsing-status', 'motion', 'Decorative pulsing status', 'A continuously animated status-like element may imply activity that is not data-driven.', 1, text); + } else if (rect.width >= 150) { + addFinding(findings, 'motion-looping-decoration', 'motion', 'Continuous decorative animation', 'A large element loops a short animation indefinitely.', 1, text); + } + } + if (element.tagName === 'MARQUEE') { + addFinding(findings, 'motion-marquee', 'motion', 'Auto-scrolling marquee', 'Content scrolls continuously instead of allowing the visitor to read at their own pace.', 2, text); + } + } + + const overusedFonts = ['inter', 'geist', 'space grotesk', 'instrument serif']; + const overusedCount = [...fontCounts.entries()].reduce((sum, [font, count]) => sum + (overusedFonts.some((name) => font.includes(name)) ? count : 0), 0); + if (styled.length >= 20 && overusedCount / styled.length >= 0.55) { + addFinding(findings, 'typography-overused-font', 'typography', 'Overused generated-UI font', 'Most visible elements use Inter, Geist, Space Grotesk, or Instrument Serif.', 1, `${Math.round(overusedCount / styled.length * 100)}% of sampled elements`); + } + if (styled.length >= 30 && fontCounts.size === 1) { + addFinding(findings, 'typography-single-font', 'typography', 'Single font throughout the page', 'The sampled page uses one font family for every role, flattening typographic hierarchy.', 1, [...fontCounts.keys()][0]); + } + + let nestedCards = 0; + const cardSet = new Set(cards); + for (const card of cards) { + let parent = card.parentElement; + while (parent && parent !== document.body) { + if (cardSet.has(parent)) { + nestedCards += 1; + break; + } + parent = parent.parentElement; + } + } + if (nestedCards >= 2) { + addFinding(findings, 'layout-nested-cards', 'layout', 'Cards nested inside cards', 'Several bordered or elevated panels are nested, creating generated “cardocalypse” depth.', 2, `${nestedCards} nested cards`); + } + + for (const parent of styled) { + const children = [...parent.children].filter((child): child is HTMLElement => child instanceof HTMLElement && visible(child)); + if (children.length < 3) continue; + const groups = new Map(); + for (const child of children) { + const signature = structureSignature(child); + const group = groups.get(signature) || []; + group.push(child); + groups.set(signature, group); + } + if ([...groups.values()].some((group) => group.length >= 3 && group[0]?.querySelector('h2,h3,h4') && group[0]?.querySelector('p'))) { + addFinding(findings, 'layout-identical-card-grid', 'layout', 'Repeated identical feature cards', 'Three or more sibling cards repeat the same icon/heading/copy structure.', 3); + break; + } + } + + const pageText = (document.body?.innerText || '').slice(0, 80_000); + for (const finding of analyseCopyPatterns(pageText)) { + findings.set(finding.ruleId, { ...finding, samples: new Set(finding.sample ? [finding.sample] : []) }); + } + + return [...findings.values()] + .map(finaliseFinding) + .sort((left, right) => right.score - left.score || right.occurrences - left.occurrences) + .slice(0, 30); +} diff --git a/src/content/index.ts b/src/content/index.ts new file mode 100644 index 0000000..8ec7963 --- /dev/null +++ b/src/content/index.ts @@ -0,0 +1,121 @@ +import browser from 'webextension-polyfill'; +import { clearBadges, renderBadges } from './badges'; +import { discoverPage } from './discovery'; +import { clearNotice, renderNotice } from './notice'; +import { + DEFAULT_SETTINGS, + type ContentRequest, + type ExtensionSettings, + type RuntimeResponse, + type ScanResult +} from '../shared/types'; + +interface SlopDetectGlobal { + __slopdetectInstalled?: boolean; +} + +const state = globalThis as typeof globalThis & SlopDetectGlobal; +const RESCAN_COOLDOWN_MS = 10_000; +const MAX_AUTOMATIC_SCANS_PER_URL = 2; + +if (!state.__slopdetectInstalled) { + state.__slopdetectInstalled = true; + let scheduledScan: number | undefined; + let lastScanAt = 0; + let lastUrl = location.href; + let automaticScansForUrl = 0; + let mutationCount = 0; + let scanSequence = 0; + + const loadSettings = async (): Promise => { + const saved = await browser.storage.local.get('settings'); + return { ...DEFAULT_SETTINGS, ...(saved.settings as Partial | undefined) }; + }; + + const scan = async (mode: 'auto' | 'manual'): Promise> => { + const settings = await loadSettings(); + if (mode === 'auto' && !settings.autoScan) return { ok: false, error: 'Automatic scanning is disabled.' }; + + const requestedUrl = location.href; + const sequence = ++scanSequence; + const response = await browser.runtime.sendMessage({ type: 'analyse-page', page: discoverPage(), mode }) as RuntimeResponse; + if (!response.ok || !response.data) return response; + if (sequence !== scanSequence || requestedUrl !== location.href || response.data.pageUrl !== location.href) { + return { ok: false, error: 'The page changed before scanning finished.' }; + } + + lastScanAt = Date.now(); + mutationCount = 0; + if (mode === 'auto') automaticScansForUrl += 1; + if (settings.showPageBadges) renderBadges(response.data); + else clearBadges(); + if (settings.showInPageNotice) renderNotice(response.data); + else clearNotice(); + return response; + }; + + const scheduleAutomaticScan = (delay: number, respectCooldown = true): void => { + if (automaticScansForUrl >= MAX_AUTOMATIC_SCANS_PER_URL) return; + if (scheduledScan !== undefined) window.clearTimeout(scheduledScan); + const cooldown = respectCooldown ? Math.max(0, RESCAN_COOLDOWN_MS - (Date.now() - lastScanAt)) : 0; + scheduledScan = window.setTimeout(() => { + scheduledScan = undefined; + void scan('auto').catch(() => { + // Protected or unloading pages may disappear during an automatic scan. + }); + }, Math.max(delay, cooldown)); + }; + + const resetForNavigation = (): void => { + if (location.href === lastUrl) return; + lastUrl = location.href; + automaticScansForUrl = 0; + mutationCount = 0; + clearBadges(); + clearNotice(true); + scheduleAutomaticScan(350, false); + }; + + browser.runtime.onMessage.addListener((message: unknown) => { + const request = message as ContentRequest; + if (request?.type === 'clear-badges') { + clearBadges(); + clearNotice(true); + return Promise.resolve({ ok: true } satisfies RuntimeResponse); + } + if (request?.type !== 'scan-page') return undefined; + return scan('manual'); + }); + + browser.storage.onChanged.addListener((changes, areaName) => { + if (areaName !== 'local' || !changes.settings) return; + const settings = { ...DEFAULT_SETTINGS, ...(changes.settings.newValue as Partial | undefined) }; + if (!settings.showPageBadges) clearBadges(); + if (!settings.showInPageNotice) clearNotice(); + if (settings.autoScan) scheduleAutomaticScan(150, false); + else if (scheduledScan !== undefined) { + window.clearTimeout(scheduledScan); + scheduledScan = undefined; + } + }); + + const observer = new MutationObserver((mutations) => { + resetForNavigation(); + for (const mutation of mutations) { + const additions = [...mutation.addedNodes].filter((node) => { + if (!(node instanceof HTMLElement)) return false; + return node.id !== 'slopdetect-page-notice' && node.id !== 'slopdetect-badge-layer'; + }); + mutationCount += additions.length; + } + if (mutationCount >= 25) scheduleAutomaticScan(1600); + }); + observer.observe(document.documentElement, { childList: true, subtree: true }); + window.addEventListener('popstate', resetForNavigation); + window.addEventListener('hashchange', resetForNavigation); + window.addEventListener('load', () => { + if (automaticScansForUrl === 0) scheduleAutomaticScan(200, false); + }, { once: true }); + + scheduleAutomaticScan(200, false); +} diff --git a/src/content/notice.ts b/src/content/notice.ts new file mode 100644 index 0000000..263893a --- /dev/null +++ b/src/content/notice.ts @@ -0,0 +1,175 @@ +import type { Evidence, PageStatus, ScanResult } from '../shared/types'; + +const HOST_ID = 'slopdetect-page-notice'; +const AUTO_COLLAPSE_MS = 9000; +let dismissedUrl: string | undefined; + +interface NoticePresentation { + icon: string; + title: string; + summary: string; + tone: 'purple' | 'amber' | 'orange' | 'blue' | 'red'; +} + +const PRESENTATION: Partial> = { + 'verified-ai': { icon: 'AI', title: 'Verified AI provenance', summary: 'A valid credential identifies AI-generated or AI-edited content.', tone: 'purple' }, + 'provenance-detected': { icon: 'AI', title: 'AI provenance detected', summary: 'AI provenance was found, but its signer is not trusted locally.', tone: 'amber' }, + 'watermark-detected': { icon: 'AI', title: 'AI watermark detected', summary: 'A compatible machine-readable watermark was detected.', tone: 'purple' }, + 'publisher-disclosed': { icon: 'AI', title: 'Publisher disclosed AI', summary: 'The publisher explicitly labels content on this page as AI-generated.', tone: 'amber' }, + 'heuristic-suspected': { icon: 'S', title: 'AI-style patterns suspected', summary: 'Several generated-site patterns appear together. This is a suspicion, not proof.', tone: 'orange' }, + 'mixed-provenance': { icon: '≋', title: 'Mixed provenance signals', summary: 'The page contains a mixture of AI, credential, or heuristic signals.', tone: 'blue' }, + 'invalid-credential': { icon: '!', title: 'Invalid provenance credential', summary: 'A credential was found but failed integrity validation.', tone: 'red' } +}; + +export function shouldShowNotice(result: ScanResult): boolean { + return PRESENTATION[result.summary.status] !== undefined; +} + +function strongestFindings(result: ScanResult): Evidence[] { + const rank = { invalid: 5, verified: 4, detected: 3, disclosed: 2, clue: 1, none: 0 } as const; + return [result.page, ...result.images, ...result.texts] + .flatMap((item) => item.evidence) + .filter((evidence) => evidence.kind !== 'limitation') + .sort((left, right) => rank[right.strength] - rank[left.strength] || (right.score || 0) - (left.score || 0)) + .slice(0, 5); +} + +export function clearNotice(resetDismissal = false): void { + document.getElementById(HOST_ID)?.remove(); + if (resetDismissal) dismissedUrl = undefined; +} + +export function renderNotice(result: ScanResult): void { + clearNotice(); + if (dismissedUrl === result.pageUrl) return; + const presentation = PRESENTATION[result.summary.status]; + if (!presentation) return; + + const host = document.createElement('aside'); + host.id = HOST_ID; + host.style.cssText = 'all:initial;position:fixed;right:18px;bottom:18px;z-index:2147483646;'; + const root = host.attachShadow({ mode: 'closed' }); + const style = document.createElement('style'); + style.textContent = ` + :host { color-scheme: light dark; } + * { box-sizing: border-box; } + .wrap { --accent:#b05d16; width:min(360px,calc(100vw - 24px)); color:#211f2c; font:13px/1.45 Inter,ui-sans-serif,system-ui,-apple-system,"Segoe UI",sans-serif; filter:drop-shadow(0 12px 32px #15122038); } + .wrap.purple { --accent:#6847ee; } .wrap.amber { --accent:#956100; } .wrap.orange { --accent:#b05d16; } + .wrap.blue { --accent:#4761a8; } .wrap.red { --accent:#bd2535; } + .card { overflow:hidden; background:#fff; border:1px solid #dedbe8; border-radius:16px; box-shadow:0 10px 30px #1512202b; } + .head { display:grid; grid-template-columns:36px 1fr auto; gap:10px; align-items:center; padding:12px; } + .mark { width:36px;height:36px;border-radius:11px;display:grid;place-items:center;background:var(--accent);color:#fff;font-weight:900;font-size:12px; } + h2 { margin:0;font-size:14px;line-height:1.25;color:inherit; } + .score { margin-top:2px;color:#686476;font-size:11px;font-weight:650; } + button { appearance:none;border:0;font:inherit;cursor:pointer; } + .icon { width:30px;height:30px;border-radius:8px;background:transparent;color:#686476;font-size:18px; } + .icon:hover { background:#f1eff7;color:#211f2c; } + .body { padding:0 14px 14px;border-top:1px solid #ece9f2; } + .summary { margin:11px 0 9px;color:#555160; } + ul { list-style:none;margin:0;padding:0;display:grid;gap:6px; } + li { padding:7px 8px;border-radius:9px;background:#f6f5fa; } + li strong { display:block;font-size:11px; } + li span { display:block;margin-top:1px;color:#686476;font-size:10px; } + .hint { margin:9px 0 0;color:#777281;font-size:10px; } + .chip { margin-left:auto;display:flex;align-items:center;gap:8px;padding:7px 10px 7px 7px;border-radius:999px;background:#fff;color:#211f2c;border:1px solid #dedbe8;box-shadow:0 6px 20px #1512202b;font-weight:750; } + .chip .mark { width:27px;height:27px;border-radius:50%;font-size:10px; } + .hidden { display:none; } + @media (prefers-reduced-motion:no-preference) { .card,.chip { animation:enter .2s ease-out; } @keyframes enter { from { opacity:0;transform:translateY(7px) } } } + @media (prefers-color-scheme:dark) { + .wrap { color:#f4f1fb; } .card,.chip { background:#211f2c;border-color:#454150; } .score,.summary,li span,.hint { color:#b2adbd; } + .body { border-color:#3b3846; } li { background:#2d2a39; } .icon { color:#b2adbd; } .icon:hover { background:#353140;color:#fff; } + } + `; + + const wrap = document.createElement('div'); + wrap.className = `wrap ${presentation.tone}`; + const card = document.createElement('section'); + card.className = 'card'; + card.setAttribute('role', 'status'); + card.setAttribute('aria-live', 'polite'); + + const scoreLabel = result.summary.heuristicScore > 0 + ? `Slop score ${result.summary.heuristicScore} · ${result.summary.heuristicFindings} pattern${result.summary.heuristicFindings === 1 ? '' : 's'}` + : `${result.summary.aiItems} AI evidence item${result.summary.aiItems === 1 ? '' : 's'}`; + const head = document.createElement('div'); + head.className = 'head'; + const mark = document.createElement('div'); + mark.className = 'mark'; + mark.textContent = presentation.icon; + const heading = document.createElement('div'); + const title = document.createElement('h2'); + title.textContent = presentation.title; + const score = document.createElement('div'); + score.className = 'score'; + score.textContent = scoreLabel; + heading.append(title, score); + head.append(mark, heading); + + const close = document.createElement('button'); + close.className = 'icon'; + close.type = 'button'; + close.title = 'Dismiss for this page'; + close.setAttribute('aria-label', 'Dismiss SlopDetect result for this page'); + close.textContent = '×'; + head.append(close); + + const body = document.createElement('div'); + body.className = 'body'; + const summary = document.createElement('p'); + summary.className = 'summary'; + summary.textContent = presentation.summary; + body.append(summary); + + const findings = strongestFindings(result); + if (findings.length > 0) { + const list = document.createElement('ul'); + for (const finding of findings) { + const item = document.createElement('li'); + const itemTitle = document.createElement('strong'); + itemTitle.textContent = finding.title; + const meta = document.createElement('span'); + meta.textContent = finding.kind === 'heuristic' + ? `${finding.category || 'pattern'} · +${finding.score || 0}${(finding.occurrences || 0) > 1 ? ` · ${finding.occurrences} matches` : ''}` + : finding.strength; + item.append(itemTitle, meta); + list.append(item); + } + body.append(list); + } + const hint = document.createElement('p'); + hint.className = 'hint'; + hint.textContent = 'Click the toolbar icon for complete evidence and limitations.'; + body.append(hint); + card.append(head, body); + + const chip = document.createElement('button'); + chip.className = 'chip hidden'; + chip.type = 'button'; + chip.setAttribute('aria-label', `${presentation.title}. ${scoreLabel}. Show details.`); + const chipMark = document.createElement('span'); + chipMark.className = 'mark'; + chipMark.textContent = presentation.icon; + const chipText = document.createElement('span'); + chipText.textContent = result.summary.heuristicScore > 0 ? `Score ${result.summary.heuristicScore}` : presentation.title; + chip.append(chipMark, chipText); + + const collapseTimer = window.setTimeout(() => { + card.classList.add('hidden'); + chip.classList.remove('hidden'); + }, AUTO_COLLAPSE_MS); + close.addEventListener('click', () => { + window.clearTimeout(collapseTimer); + dismissedUrl = result.pageUrl; + host.remove(); + }); + chip.addEventListener('click', () => { + window.clearTimeout(collapseTimer); + chip.classList.add('hidden'); + card.classList.remove('hidden'); + }); + card.addEventListener('click', () => window.clearTimeout(collapseTimer), { once: true }); + + wrap.append(card, chip); + root.append(style, wrap); + document.documentElement.append(host); +} diff --git a/src/global.d.ts b/src/global.d.ts new file mode 100644 index 0000000..35306c6 --- /dev/null +++ b/src/global.d.ts @@ -0,0 +1 @@ +declare module '*.css'; diff --git a/src/options/index.tsx b/src/options/index.tsx new file mode 100644 index 0000000..32c1797 --- /dev/null +++ b/src/options/index.tsx @@ -0,0 +1,92 @@ +import { render } from 'preact'; +import { useEffect, useState } from 'preact/hooks'; +import browser from 'webextension-polyfill'; +import { DEFAULT_SETTINGS, type ExtensionSettings } from '../shared/types'; +import './options.css'; + +function App(): preact.JSX.Element { + const [settings, setSettings] = useState(DEFAULT_SETTINGS); + const [notice, setNotice] = useState(''); + + useEffect(() => { + void browser.storage.local.get('settings').then((saved) => { + setSettings({ ...DEFAULT_SETTINGS, ...(saved.settings as Partial | undefined) }); + }); + }, []); + + const update = (key: K, value: ExtensionSettings[K]): void => { + setSettings((current) => ({ ...current, [key]: value })); + }; + + const save = async (): Promise => { + const safeSettings = { + ...settings, + maxImageBytes: Math.min(100, Math.max(1, settings.maxImageBytes / 1048576)) * 1048576, + maxImagesPerPage: Math.min(200, Math.max(1, Math.round(settings.maxImagesPerPage))), + maxAutoImagesPerPage: Math.min(30, Math.max(0, Math.round(settings.maxAutoImagesPerPage))), + heuristicThreshold: Math.min(20, Math.max(3, Math.round(settings.heuristicThreshold))) + }; + await browser.storage.local.set({ settings: safeSettings }); + setSettings(safeSettings); + setNotice('Settings saved.'); + window.setTimeout(() => setNotice(''), 2000); + }; + + return
+

SlopDetect settings

Privacy-first AI provenance inspection
+ +
+

Automatic protection

+

SlopDetect runs locally after ordinary HTTP and HTTPS pages load. Pages without meaningful evidence stay visually untouched.

+
+

Runs on initial load and once more when a page fills itself dynamically.

+ update('autoScan', event.currentTarget.checked)} /> +
+
+

Displays a compact result card only for flagged pages, then collapses it to a score chip.

+ update('showInPageNotice', event.currentTarget.checked)} /> +
+
+ +
+

Scanning

+
+

Adds small AI, Content Credential, or invalid-credential markers to the page.

+ update('showPageBadges', event.currentTarget.checked)} /> +
+
+

Scores deterministic visual, layout, motion, typography, and copy clues. These are suspicions, not provenance proof.

+ update('enableHeuristicDetection', event.currentTarget.checked)} /> +
+
+

Lower values flag more pages but increase false positives. Default: 6.

+ update('heuristicThreshold', Number(event.currentTarget.value))} /> +
+
+

Useful for auditing, but consumes more memory. It remains local.

+ update('includeRawEvidence', event.currentTarget.checked)} /> +
+
+

Checks the largest visible images first. Lower values reduce page-load work; zero scans only the site itself.

+ update('maxAutoImagesPerPage', Number(event.currentTarget.value))} /> +
+
+

A toolbar rescan may inspect more images than the automatic page-load scan.

+ update('maxImagesPerPage', Number(event.currentTarget.value))} /> +
+
+

Resources larger than this are left as unknown.

+ update('maxImageBytes', Number(event.currentTarget.value) * 1048576)} /> +
+
{notice}
+
+ +
+

Detection policy

+

SlopDetect keeps verified provenance, unsigned generator metadata, and stylistic suspicions separate. Heuristics can produce false positives and never prove who authored a site. C2PA inspection happens locally using @contentauth/c2pa-web. Remote services are not enabled.

+
+
; +} + +const app = document.getElementById('app'); +if (app) render(, app); diff --git a/src/options/options.css b/src/options/options.css new file mode 100644 index 0000000..6b86fd2 --- /dev/null +++ b/src/options/options.css @@ -0,0 +1,22 @@ +@import '../ui/base.css'; + +body { min-height: 100vh; } +.shell { width: min(760px, calc(100% - 32px)); margin: 40px auto; display: grid; gap: 18px; } +.heading { display: flex; align-items: center; gap: 14px; } +.heading img { width: 48px; height: 48px; } +h1 { margin: 0; font-size: 28px; } +h2 { margin: 0 0 8px; font-size: 17px; } +p { line-height: 1.55; } +.setting { display: flex; justify-content: space-between; gap: 24px; align-items: start; padding: 12px 0; border-bottom: 1px solid #e3e0eb; } +.setting:last-child { border: 0; } +.setting label { font-weight: 700; } +.setting p { margin: 4px 0 0; font-size: 13px; } +.setting input[type="number"] { width: 90px; padding: 7px; border: 1px solid #aaa5b8; border-radius: 8px; } +.row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; } +.notice { font-size: 13px; min-height: 20px; color: #276755; } +code { background: #ece9f4; padding: 2px 5px; border-radius: 4px; } + +@media (prefers-color-scheme: dark) { + .setting { border-color: #393645; } + code { background: #312e3d; } +} diff --git a/src/popup/index.tsx b/src/popup/index.tsx new file mode 100644 index 0000000..ae939c4 --- /dev/null +++ b/src/popup/index.tsx @@ -0,0 +1,112 @@ +import { render } from 'preact'; +import { useEffect, useState } from 'preact/hooks'; +import browser from 'webextension-polyfill'; +import type { AssetResult, PageStatus, RuntimeResponse, ScanResult } from '../shared/types'; +import './popup.css'; + +const STATUS: Record = { + 'verified-ai': { title: 'Verified AI provenance', detail: 'A valid provenance credential identifies AI-generated or manipulated content.' }, + 'provenance-detected': { title: 'AI provenance detected', detail: 'A readable credential identifies AI origin, but its signer is not trusted by the bundled trust list.' }, + 'watermark-detected': { title: 'AI watermark detected', detail: 'A compatible watermark detector found machine-readable AI evidence.' }, + 'publisher-disclosed': { title: 'Publisher disclosed AI', detail: 'The page contains an explicit AI-content disclosure.' }, + 'heuristic-suspected': { title: 'AI-style patterns suspected', detail: 'Several visual, layout, motion, or copy patterns associated with generated sites appear together. This is not proof of AI authorship.' }, + 'mixed-provenance': { title: 'Mixed provenance', detail: 'The inspected items contain different or partial provenance signals.' }, + 'invalid-credential': { title: 'Invalid credential', detail: 'Provenance metadata was found but failed integrity validation.' }, + 'no-supported-evidence': { title: 'No supported evidence', detail: 'No compatible marking was found. This does not mean the content is human-made.' }, + 'unable-to-inspect': { title: 'Unable to inspect', detail: 'The page or its relevant resources could not be accessed.' } +}; + +async function activeTab(): Promise { + const tabs = await browser.tabs.query({ active: true, currentWindow: true }); + const tab = tabs[0]; + if (!tab?.id) throw new Error('No active browser tab is available.'); + return tab; +} + +function EvidenceList({ result }: { result: ScanResult }): preact.JSX.Element | null { + const items = [result.page, ...result.images, ...result.texts].filter( + (item) => item.evidence.length > 0 && (item.strength !== 'none' || item.evidence.some((entry) => entry.kind === 'limitation')) + ); + if (items.length === 0) return null; + + return
+ {items.map((item: AssetResult) =>
+ {item.kind === 'image' ? 'Image' : item.kind === 'text' ? 'Text' : 'Page'}: {item.label.slice(0, 80)} + {item.evidence.map((evidence) =>
+ {evidence.title} + {evidence.detail} + {evidence.kind === 'heuristic' &&
{evidence.category} · +{evidence.score} point{evidence.score === 1 ? '' : 's'}{(evidence.occurrences || 0) > 1 ? ` · ${evidence.occurrences} matches` : ''}
} + {evidence.issuer &&
Issuer: {evidence.issuer}
} +
)} +
)} +
; +} + +function App(): preact.JSX.Element { + const [result, setResult] = useState(); + const [busy, setBusy] = useState(false); + const [error, setError] = useState(''); + + useEffect(() => { + void (async () => { + try { + const tab = await activeTab(); + const response = await browser.runtime.sendMessage({ type: 'get-tab-result', tabId: tab.id }) as RuntimeResponse; + if (response.ok && response.data?.pageUrl === tab.url) setResult(response.data); + } catch { + // The active tab may be a protected Firefox page. + } + })(); + }, []); + + const scan = async (): Promise => { + setBusy(true); + setError(''); + try { + const tab = await activeTab(); + const response = await browser.tabs.sendMessage(tab.id!, { type: 'scan-page' }) as RuntimeResponse; + if (!response.ok || !response.data) throw new Error(response.error || 'The scan did not return a result.'); + setResult(response.data); + } catch (scanError) { + setError(scanError instanceof Error ? scanError.message : String(scanError)); + } finally { + setBusy(false); + } + }; + + const status = result ? STATUS[result.summary.status] : undefined; + return
+
+
Automatic page check

SlopDetect

+
+ +
+ + +
+ + {error &&
{error}
} + + {!result ?
+

No result for this page yet

+

Pages scan automatically after loading. Use the button above to request a fresh full scan.

+
: <> +
+
Current page
+

{status?.title}

+

{status?.detail}

+
+
+
{result.summary.heuristicScore}slop score
+
{result.summary.inspectedImages}/{result.summary.totalImages}images inspected
+
{result.summary.heuristicFindings}style clues
+
+ {result.warnings.length > 0 &&
    {result.warnings.map((warning) =>
  • {warning}
  • )}
} + +

No mark found means unknown, not human-made. Scanned {new Date(result.scannedAt).toLocaleString()}.

+ } +
; +} + +const app = document.getElementById('app'); +if (app) render(, app); diff --git a/src/popup/popup.css b/src/popup/popup.css new file mode 100644 index 0000000..dcca2d1 --- /dev/null +++ b/src/popup/popup.css @@ -0,0 +1,45 @@ +@import '../ui/base.css'; + +body { width: 360px; } +.shell { padding: 13px; display: grid; gap: 10px; } +.header { display: flex; align-items: center; min-height: 32px; } +.eyebrow { margin-bottom: 1px; color: #777281; font-size: 9px; font-weight: 800; letter-spacing: .09em; text-transform: uppercase; } +h1 { font-size: 17px; line-height: 1.1; margin: 0; } +.toolbar-actions { display: grid; grid-template-columns: 1fr auto; gap: 7px; } +.toolbar-actions .button { min-height: 36px; padding: 8px 13px; border-radius: 9px; } +.status { --status:#74707e; border-left: 4px solid var(--status); padding: 11px 12px; } +.status.verified-ai, .status.watermark-detected { --status:#6847ee; } +.status.provenance-detected, .status.publisher-disclosed { --status:#956100; } +.status.heuristic-suspected { --status:#b05d16; } +.status.mixed-provenance { --status:#4761a8; } +.status.invalid-credential { --status:#bd2535; } +.status-label { display:flex;align-items:center;gap:6px;margin-bottom:4px;color:#777281;font-size:9px;font-weight:800;letter-spacing:.08em;text-transform:uppercase; } +.status-label span { width:7px;height:7px;border-radius:50%;background:var(--status); } +.status h2 { margin: 0 0 3px; font-size: 14px; } +.status p { margin: 0; font-size: 12px; line-height: 1.4; } +.stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 7px; } +.stat { text-align: center; padding: 7px 4px; border-radius: 8px; background: #f1eff7; } +.stat strong { display: block; font-size: 15px; } +.stat span { font-size: 10px; color: #686476; } +.warnings { margin: 0; padding-left: 20px; font-size: 12px; color: #73510d; } +.results { display: grid; gap: 6px; max-height: 220px; overflow: auto; } +details.item { border: 1px solid #e2dfeb; border-radius: 9px; padding: 8px 10px; } +details.item summary { cursor: pointer; font-size: 12px; font-weight: 700; } +.evidence { margin-top: 8px; padding-top: 7px; border-top: 1px solid #ece9f2; font-size: 11px; line-height: 1.4; } +.evidence strong { display: block; } +.evidence-meta { margin-top: 3px; color: #7a4a15; font-weight: 700; text-transform: capitalize; } +.empty-copy { border-top: 1px solid #e2dfeb; padding: 10px 2px 2px; } +.empty-copy h2 { font-size: 13px; margin: 0 0 4px; } +.empty-copy p { font-size: 11px; line-height: 1.45; margin: 0; } +.footnote { margin: 0; font-size: 10px; line-height: 1.4; } + +@media (prefers-color-scheme: dark) { + .stat { background: #2d2a39; } + .stat span { color: #aaa5b8; } + details.item { border-color: #3b3846; } + .evidence { border-color: #3b3846; } + .evidence-meta { color: #e4a55f; } + .warnings { color: #e4c16f; } + .eyebrow, .status-label { color: #aaa5b8; } + .empty-copy { border-color: #3b3846; } +} diff --git a/src/shared/status.ts b/src/shared/status.ts new file mode 100644 index 0000000..56f893a --- /dev/null +++ b/src/shared/status.ts @@ -0,0 +1,95 @@ +import type { + AssetResult, + Evidence, + EvidenceStrength, + OriginVerdict, + PageStatus, + ScanSummary +} from './types'; +import { heuristicScore } from '../background/heuristics'; + +const strengthRank: Record = { + none: 0, + clue: 1, + disclosed: 2, + detected: 3, + verified: 4, + invalid: 5 +}; + +export function strongestEvidence(evidence: Evidence[]): EvidenceStrength { + return evidence.reduce( + (strongest, item) => (strengthRank[item.strength] > strengthRank[strongest] ? item.strength : strongest), + 'none' + ); +} + +export function verdictFromEvidence(evidence: Evidence[]): OriginVerdict { + if (evidence.some((item) => item.verdict === 'invalid')) return 'invalid'; + if (evidence.some((item) => item.verdict === 'ai')) return 'ai'; + if (evidence.some((item) => item.verdict === 'not-ai-asserted')) return 'not-ai-asserted'; + return 'unknown'; +} + +export function createAssetResult( + id: string, + kind: AssetResult['kind'], + label: string, + evidence: Evidence[], + sourceUrl?: string +): AssetResult { + return { + id, + kind, + label, + sourceUrl, + verdict: verdictFromEvidence(evidence), + strength: strongestEvidence(evidence), + evidence + }; +} + +export function aggregateSummary( + page: AssetResult, + images: AssetResult[], + texts: AssetResult[], + totalImages: number, + totalTextBlocks: number, + heuristicThreshold = 6 +): ScanSummary { + const items = [page, ...images, ...texts]; + const aiItems = items.filter((item) => item.verdict === 'ai').length; + const invalidItems = items.filter((item) => item.verdict === 'invalid').length; + const disclosedItems = items.filter((item) => item.strength === 'disclosed').length; + const inaccessibleItems = items.filter((item) => + item.evidence.some((evidence) => evidence.kind === 'limitation') + ).length; + const evidenceBearingItems = items.filter((item) => item.strength !== 'none').length; + const pageHeuristicScore = heuristicScore(page.evidence); + const heuristicFindings = page.evidence.filter((evidence) => evidence.kind === 'heuristic').length; + + let status: PageStatus; + if (invalidItems > 0) status = 'invalid-credential'; + else if (aiItems > 0 && aiItems < items.length && evidenceBearingItems > aiItems) status = 'mixed-provenance'; + else if (items.some((item) => item.verdict === 'ai' && item.strength === 'verified')) status = 'verified-ai'; + else if (items.some((item) => item.evidence.some((evidence) => evidence.kind === 'watermark' && evidence.verdict === 'ai'))) status = 'watermark-detected'; + else if (items.some((item) => item.verdict === 'ai' && item.strength === 'detected')) status = 'provenance-detected'; + else if (items.some((item) => item.verdict === 'ai' && item.strength === 'disclosed')) status = 'publisher-disclosed'; + else if (pageHeuristicScore >= heuristicThreshold && heuristicFindings >= 2) status = 'heuristic-suspected'; + else if (inaccessibleItems > 0 && images.length === 0 && texts.length === 0) status = 'unable-to-inspect'; + else status = 'no-supported-evidence'; + + return { + status, + inspectedImages: images.length, + totalImages, + inspectedTextBlocks: texts.length, + totalTextBlocks, + aiItems, + invalidItems, + disclosedItems, + inaccessibleItems, + heuristicScore: pageHeuristicScore, + heuristicFindings + }; +} diff --git a/src/shared/types.ts b/src/shared/types.ts new file mode 100644 index 0000000..f95ef83 --- /dev/null +++ b/src/shared/types.ts @@ -0,0 +1,142 @@ +export type EvidenceStrength = 'verified' | 'detected' | 'disclosed' | 'clue' | 'invalid' | 'none'; +export type OriginVerdict = 'ai' | 'not-ai-asserted' | 'unknown' | 'invalid'; +export type AssetKind = 'image' | 'text' | 'page'; + +export interface Evidence { + id: string; + kind: 'c2pa' | 'watermark' | 'disclosure' | 'generator' | 'heuristic' | 'limitation'; + strength: EvidenceStrength; + verdict: OriginVerdict; + title: string; + detail: string; + detector?: string; + issuer?: string; + category?: HeuristicCategory; + score?: number; + occurrences?: number; + raw?: unknown; +} + +export type HeuristicCategory = 'visual' | 'typography' | 'layout' | 'motion' | 'copy'; + +export interface HeuristicFinding { + ruleId: string; + category: HeuristicCategory; + title: string; + detail: string; + score: number; + occurrences: number; + sample?: string; +} + +export interface ImageCandidate { + id: string; + url: string; + alt: string; + width: number; + height: number; +} + +export interface TextCandidate { + id: string; + text: string; + tokenEstimate: number; +} + +export interface PageDisclosureCandidate { + source: string; + value: string; +} + +export interface PageCandidate { + url: string; + title: string; + images: ImageCandidate[]; + texts: TextCandidate[]; + disclosures: PageDisclosureCandidate[]; + heuristics: HeuristicFinding[]; +} + +export interface AssetResult { + id: string; + kind: AssetKind; + label: string; + sourceUrl?: string; + verdict: OriginVerdict; + strength: EvidenceStrength; + evidence: Evidence[]; +} + +export type PageStatus = + | 'verified-ai' + | 'provenance-detected' + | 'watermark-detected' + | 'publisher-disclosed' + | 'heuristic-suspected' + | 'mixed-provenance' + | 'invalid-credential' + | 'no-supported-evidence' + | 'unable-to-inspect'; + +export interface ScanSummary { + status: PageStatus; + inspectedImages: number; + totalImages: number; + inspectedTextBlocks: number; + totalTextBlocks: number; + aiItems: number; + invalidItems: number; + disclosedItems: number; + inaccessibleItems: number; + heuristicScore: number; + heuristicFindings: number; +} + +export interface ScanResult { + scanId: string; + pageUrl: string; + pageTitle: string; + scannedAt: string; + summary: ScanSummary; + page: AssetResult; + images: AssetResult[]; + texts: AssetResult[]; + warnings: string[]; +} + +export interface ExtensionSettings { + autoScan: boolean; + showInPageNotice: boolean; + showPageBadges: boolean; + includeRawEvidence: boolean; + maxImageBytes: number; + maxImagesPerPage: number; + maxAutoImagesPerPage: number; + enableHeuristicDetection: boolean; + heuristicThreshold: number; +} + +export const DEFAULT_SETTINGS: ExtensionSettings = { + autoScan: true, + showInPageNotice: true, + showPageBadges: true, + includeRawEvidence: false, + maxImageBytes: 25 * 1024 * 1024, + maxImagesPerPage: 50, + maxAutoImagesPerPage: 10, + enableHeuristicDetection: true, + heuristicThreshold: 6 +}; + +export type RuntimeRequest = + | { type: 'analyse-page'; page: PageCandidate; mode?: 'auto' | 'manual' } + | { type: 'get-tab-result'; tabId: number } + | { type: 'clear-tab-result'; tabId: number }; + +export type ContentRequest = { type: 'scan-page' } | { type: 'clear-badges' }; + +export interface RuntimeResponse { + ok: boolean; + data?: T; + error?: string; +} diff --git a/src/ui/base.css b/src/ui/base.css new file mode 100644 index 0000000..467f3c7 --- /dev/null +++ b/src/ui/base.css @@ -0,0 +1,36 @@ +:root { + color-scheme: light dark; + font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + background: #f6f5fb; + color: #211f2c; + font-synthesis: none; +} + +* { box-sizing: border-box; } +body { margin: 0; } +button, input { font: inherit; } +button { cursor: pointer; } + +.button { + border: 0; + border-radius: 10px; + padding: 10px 14px; + background: #6847ee; + color: white; + font-weight: 700; +} +.button:hover { background: #5738d5; } +.button:disabled { cursor: wait; opacity: .65; } +.button.secondary { background: #e7e3f9; color: #31266a; } +.button.danger { background: #f7dfe2; color: #7e1826; } + +.muted { color: #686476; } +.card { background: white; border: 1px solid #dedbe8; border-radius: 14px; padding: 14px; } +.error { color: #9d1f31; background: #fbe9ec; border-radius: 10px; padding: 10px; } + +@media (prefers-color-scheme: dark) { + :root { background: #171620; color: #f4f1fb; } + .card { background: #211f2c; border-color: #393645; } + .muted { color: #aaa5b8; } + .button.secondary { background: #38324f; color: #eee9ff; } +} diff --git a/tests/c2pa.test.ts b/tests/c2pa.test.ts new file mode 100644 index 0000000..d5206c1 --- /dev/null +++ b/tests/c2pa.test.ts @@ -0,0 +1,57 @@ +import { describe, expect, it } from 'vitest'; +import { evidenceFromManifestStore, FirefoxExtensionWorkerUrl } from '../src/background/c2pa'; + +describe('C2PA evidence interpretation', () => { + it('recognises a trusted AI digital source type', () => { + const result = evidenceFromManifestStore({ + active_manifest: 'example:claim', + validation_state: 'Trusted', + manifests: { + 'example:claim': { + signature_info: { issuer: 'Example CA' }, + assertions: [{ data: { digitalSourceType: 'http://cv.iptc.org/newscodes/digitalsourcetype/trainedAlgorithmicMedia' } }] + } + } + }, false); + + expect(result[0]).toMatchObject({ strength: 'verified', verdict: 'ai', issuer: 'Example CA' }); + }); + + it('does not claim trusted status for a merely valid signer', () => { + const result = evidenceFromManifestStore({ + active_manifest: 'example:claim', + validation_state: 'Valid', + manifests: { + 'example:claim': { source_type: 'trainedAlgorithmicMedia' } + } + }, false); + expect(result[0]).toMatchObject({ strength: 'detected', verdict: 'ai' }); + }); + + it('prioritises a failed integrity status', () => { + const result = evidenceFromManifestStore({ + active_manifest: 'example:claim', + validation_state: 'Invalid', + manifests: { 'example:claim': {} }, + validation_status: [{ code: 'assertion.dataHash.mismatch' }] + }, false); + expect(result[0]).toMatchObject({ strength: 'invalid', verdict: 'invalid' }); + }); + + it('returns no evidence when a manifest is absent', () => { + expect(evidenceFromManifestStore({ validation_state: 'Valid' }, false)).toEqual([]); + }); +}); + +describe('Firefox worker URL compatibility', () => { + it('passes the pinned SDK HTTPS guard but resolves to the packaged extension worker', () => { + const packaged = 'moz-extension://12345678-1234-1234-1234-123456789abc/c2pa_worker.js'; + const workerUrl = new FirefoxExtensionWorkerUrl(packaged); + expect(workerUrl.protocol).toBe('https:'); + expect(workerUrl.toString()).toBe(packaged); + }); + + it('refuses non-extension worker resources', () => { + expect(() => new FirefoxExtensionWorkerUrl('https://example.com/worker.js')).toThrow(/packaged Firefox extension resource/); + }); +}); diff --git a/tests/cache.test.ts b/tests/cache.test.ts new file mode 100644 index 0000000..f5d21e2 --- /dev/null +++ b/tests/cache.test.ts @@ -0,0 +1,21 @@ +import { describe, expect, it } from 'vitest'; +import { ResultCache, hashBlob } from '../src/background/cache'; + +describe('result cache', () => { + it('evicts the least recently used entry', () => { + const cache = new ResultCache(2); + cache.set('one', 1); + cache.set('two', 2); + expect(cache.get('one')).toBe(1); + cache.set('three', 3); + expect(cache.get('two')).toBeUndefined(); + expect(cache.get('one')).toBe(1); + }); + + it('hashes identical content consistently', async () => { + const first = await hashBlob(new Blob(['same content'])); + const second = await hashBlob(new Blob(['same content'])); + expect(first).toBe(second); + expect(first).toMatch(/^[a-f0-9]{64}$/); + }); +}); diff --git a/tests/disclosures.test.ts b/tests/disclosures.test.ts new file mode 100644 index 0000000..89733cd --- /dev/null +++ b/tests/disclosures.test.ts @@ -0,0 +1,20 @@ +import { describe, expect, it } from 'vitest'; +import { analyseDisclosures } from '../src/background/disclosures'; + +describe('publisher disclosure parsing', () => { + it('recognises explicit AI-origin metadata', () => { + const result = analyseDisclosures([{ source: 'meta:ai-generated', value: 'true' }]); + expect(result).toHaveLength(1); + expect(result[0]).toMatchObject({ strength: 'disclosed', verdict: 'ai' }); + }); + + it('treats generator metadata as a clue rather than proof', () => { + const result = analyseDisclosures([{ source: 'meta:generator', value: 'Framer AI' }]); + expect(result).toHaveLength(1); + expect(result[0]).toMatchObject({ strength: 'clue', verdict: 'unknown' }); + }); + + it('ignores ordinary website-generator metadata', () => { + expect(analyseDisclosures([{ source: 'meta:generator', value: 'WordPress 7.0' }])).toEqual([]); + }); +}); diff --git a/tests/heuristics.test.ts b/tests/heuristics.test.ts new file mode 100644 index 0000000..9f3c364 --- /dev/null +++ b/tests/heuristics.test.ts @@ -0,0 +1,27 @@ +import { describe, expect, it } from 'vitest'; +import { analyseCopyPatterns } from '../src/content/heuristics'; +import { evidenceFromHeuristics, heuristicScore } from '../src/background/heuristics'; + +describe('page heuristics', () => { + it('finds dense buzzwords and em-dash cadence without declaring an AI verdict', () => { + const text = 'Supercharge your workflow with our world-class, enterprise-grade platform — move faster — work smarter — without compromise.'; + const findings = analyseCopyPatterns(text); + expect(findings.map((finding) => finding.ruleId)).toEqual(expect.arrayContaining([ + 'copy-marketing-buzzwords', + 'copy-em-dash-cadence' + ])); + expect(evidenceFromHeuristics(findings).every((item) => item.verdict === 'unknown')).toBe(true); + }); + + it('adds a diversity point when independent categories agree', () => { + const evidence = evidenceFromHeuristics([ + { ruleId: 'one', category: 'visual', title: 'One', detail: 'One', score: 2, occurrences: 1 }, + { ruleId: 'two', category: 'layout', title: 'Two', detail: 'Two', score: 3, occurrences: 1 } + ]); + expect(heuristicScore(evidence)).toBe(6); + }); + + it('ignores ordinary direct prose', () => { + expect(analyseCopyPatterns('The archive contains monthly invoices. Select a year, then download the required PDF.')).toEqual([]); + }); +}); diff --git a/tests/image-metadata.test.ts b/tests/image-metadata.test.ts new file mode 100644 index 0000000..041fe81 --- /dev/null +++ b/tests/image-metadata.test.ts @@ -0,0 +1,14 @@ +import { describe, expect, it } from 'vitest'; +import { inspectImageGeneratorMetadata } from '../src/background/image-metadata'; + +describe('image generator metadata clues', () => { + it('recognises a Stable Diffusion parameters block', async () => { + const blob = new Blob(['PNG metadata\0Steps: 30, Sampler: Euler a, CFG scale: 7, Seed: 42']); + const evidence = await inspectImageGeneratorMetadata(blob); + expect(evidence[0]).toMatchObject({ kind: 'generator', strength: 'detected', verdict: 'ai' }); + }); + + it('does not flag an ordinary image byte sequence', async () => { + expect(await inspectImageGeneratorMetadata(new Blob(['ordinary image metadata']))).toEqual([]); + }); +}); diff --git a/tests/notice.test.ts b/tests/notice.test.ts new file mode 100644 index 0000000..05fb307 --- /dev/null +++ b/tests/notice.test.ts @@ -0,0 +1,42 @@ +import { describe, expect, it } from 'vitest'; +import { shouldShowNotice } from '../src/content/notice'; +import type { PageStatus, ScanResult } from '../src/shared/types'; + +function resultWithStatus(status: PageStatus): ScanResult { + return { + scanId: 'scan', + pageUrl: 'https://example.com/', + pageTitle: 'Example', + scannedAt: new Date(0).toISOString(), + summary: { + status, + inspectedImages: 0, + totalImages: 0, + inspectedTextBlocks: 0, + totalTextBlocks: 0, + aiItems: 0, + invalidItems: 0, + disclosedItems: 0, + inaccessibleItems: 0, + heuristicScore: status === 'heuristic-suspected' ? 7 : 0, + heuristicFindings: status === 'heuristic-suspected' ? 3 : 0 + }, + page: { id: 'page', kind: 'page', label: 'Example', verdict: 'unknown', strength: 'none', evidence: [] }, + images: [], + texts: [], + warnings: [] + }; +} + +describe('in-page result visibility', () => { + it('shows meaningful heuristic and provenance results', () => { + expect(shouldShowNotice(resultWithStatus('heuristic-suspected'))).toBe(true); + expect(shouldShowNotice(resultWithStatus('verified-ai'))).toBe(true); + expect(shouldShowNotice(resultWithStatus('invalid-credential'))).toBe(true); + }); + + it('stays silent on unknown or inaccessible pages', () => { + expect(shouldShowNotice(resultWithStatus('no-supported-evidence'))).toBe(false); + expect(shouldShowNotice(resultWithStatus('unable-to-inspect'))).toBe(false); + }); +}); diff --git a/tests/status.test.ts b/tests/status.test.ts new file mode 100644 index 0000000..cb40c72 --- /dev/null +++ b/tests/status.test.ts @@ -0,0 +1,74 @@ +import { describe, expect, it } from 'vitest'; +import { aggregateSummary, createAssetResult, strongestEvidence, verdictFromEvidence } from '../src/shared/status'; +import type { Evidence } from '../src/shared/types'; + +const evidence = (overrides: Partial): Evidence => ({ + id: crypto.randomUUID(), + kind: 'c2pa', + strength: 'none', + verdict: 'unknown', + title: 'Evidence', + detail: 'Test evidence', + ...overrides +}); + +describe('evidence precedence', () => { + it('treats invalid credentials as stronger than positive evidence', () => { + const items = [ + evidence({ strength: 'verified', verdict: 'ai' }), + evidence({ strength: 'invalid', verdict: 'invalid' }) + ]; + expect(strongestEvidence(items)).toBe('invalid'); + expect(verdictFromEvidence(items)).toBe('invalid'); + }); + + it('never turns empty evidence into a human-origin assertion', () => { + const result = createAssetResult('one', 'image', 'Unsigned image', []); + expect(result.verdict).toBe('unknown'); + expect(result.strength).toBe('none'); + }); +}); + +describe('page aggregation', () => { + const unknownPage = createAssetResult('page', 'page', 'Page', []); + + it('reports verified AI when a trusted AI credential is present', () => { + const image = createAssetResult('image', 'image', 'Image', [ + evidence({ strength: 'verified', verdict: 'ai' }) + ]); + expect(aggregateSummary(unknownPage, [image], [], 1, 0).status).toBe('verified-ai'); + }); + + it('reports mixed provenance when AI and non-AI assertions coexist', () => { + const ai = createAssetResult('ai', 'image', 'AI', [evidence({ strength: 'verified', verdict: 'ai' })]); + const camera = createAssetResult('camera', 'image', 'Camera', [ + evidence({ strength: 'verified', verdict: 'not-ai-asserted' }) + ]); + expect(aggregateSummary(unknownPage, [ai, camera], [], 2, 0).status).toBe('mixed-provenance'); + }); + + it('prioritises invalid credentials', () => { + const invalid = createAssetResult('bad', 'image', 'Invalid', [ + evidence({ strength: 'invalid', verdict: 'invalid' }) + ]); + expect(aggregateSummary(unknownPage, [invalid], [], 1, 0).status).toBe('invalid-credential'); + }); + + it('reports suspicion without asserting AI authorship when heuristic clues cross the threshold', () => { + const suspectedPage = createAssetResult('page', 'page', 'Page', [ + evidence({ kind: 'heuristic', strength: 'clue', category: 'visual', score: 3 }), + evidence({ kind: 'heuristic', strength: 'clue', category: 'layout', score: 2 }) + ]); + const summary = aggregateSummary(suspectedPage, [], [], 0, 0, 6); + expect(summary.status).toBe('heuristic-suspected'); + expect(suspectedPage.verdict).toBe('unknown'); + expect(summary.heuristicScore).toBe(6); + }); + + it('does not elevate a single weak style clue', () => { + const page = createAssetResult('page', 'page', 'Page', [ + evidence({ kind: 'heuristic', strength: 'clue', category: 'visual', score: 2 }) + ]); + expect(aggregateSummary(page, [], [], 0, 0, 6).status).toBe('no-supported-evidence'); + }); +}); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..c9a649a --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "Bundler", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "jsx": "react-jsx", + "jsxImportSource": "preact", + "strict": true, + "noUncheckedIndexedAccess": true, + "noImplicitOverride": true, + "skipLibCheck": true, + "types": ["firefox-webext-browser", "vitest/globals"] + }, + "include": ["src", "tests", "scripts"] +}