Compare commits

..

45 Commits

Author SHA1 Message Date
github-actions[bot] 718b063ed7 chore(release): wxt v0.21.1
📼 VHS / Create VHS (push) Cancelled after 0s
2026-07-26 23:13:13 +00:00
Aaron 87a96d4661 chore: Add vite to template projects (#2517) 2026-07-26 18:02:38 -05:00
Aaron d8a86e7633 docs: Add section about install footprint 2026-07-26 18:02:38 -05:00
Aaron c3eaef6fb4 docs: Finalize migration guide for wxt v0.21 (#2516) 2026-07-26 18:02:38 -05:00
Aaron d1a956342d ci: Use @aklinker1/zero-changelog for release notes (#2515) 2026-07-26 18:02:38 -05:00
Aaron 0fdac0d4e4 feat(Firefox): List files in sources zip (#2513) 2026-07-26 18:02:38 -05:00
Aaron 7965ab0592 chore: Add type to type imports 2026-07-26 18:02:38 -05:00
Aaron 54d10af1fd fix(TS)!: Update .wxt/tsconfig.json compiler options, require TS >=5.4 (#2512)
BREAKING CHANGE: Updates `.wxt/tsconfig.json` defaults to latest recommended settings for vite projects and requires Typescript 5.4 or later. See #2512 for details on what compiler options were changed.

Co-authored-by: cookesan <cookesan@users.noreply.github.com>
2026-07-26 18:02:38 -05:00
Aaron 7dbe18ba0c fix!: Update content and unlisted script globalName default to false (#2511)
BREAKING CHANGE: If your script needs to return a value, like for `browser.scripting.executeScript`, set `globalName: true` to maintain the old behavior.
2026-07-26 18:02:38 -05:00
Aaron d4f78b623e Fix markdownlint 2026-07-26 18:02:38 -05:00
Aaron 7d6caad9b5 fix: Loosen version of @webext-core/isolated-element
Allows reverting to v1 if styles break
2026-07-26 18:02:38 -05:00
Aaron 0b352f6eff fix: Remove console.log 2026-07-26 18:02:38 -05:00
Aaron 885f8f0b76 docs: Cleanup v0.21 migration guide 2026-07-26 18:02:38 -05:00
ТΞNSΛI eae835fa80 feat!: new template variable {{versionName}} and change of the behaviour of {{version}} (#1612)
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2026-07-26 18:02:38 -05:00
Kai Gritun 782a5b85f1 fix(zip)!: make includeSources/excludeSources follow standard allowlist behavior (#2114)
Co-authored-by: Eli <88557639+lishaduck@users.noreply.github.com>
Co-authored-by: ТΞNSΛI <tensai@gmx.net>
Co-authored-by: Aaron <aaronklinker1@gmail.com>
Co-authored-by: Patryk Kuniczak <p.kuniczak@gmail.com>
Co-authored-by: Kai Gritun <kai@kaigritun.com>
2026-07-26 18:02:38 -05:00
Aaron 961cfa5f2a chore(deps)!: Upgrade major dependencies (#2508) 2026-07-26 18:02:38 -05:00
fkatsuhiro ada0c86877 chore!: Remove deprecated APIs (#2488)
Co-authored-by: Gliches <nishumurmu017@gmail.com>
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2026-07-26 18:02:38 -05:00
Gliches 13151509b6 fix!: Remove url: import feature (#2456)
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2026-07-26 18:02:38 -05:00
Aaron b7bdb11a15 chore!: Upgrade @webext-core/isolated-element v1 → v3 (#2098)
Co-authored-by: Eli <88557639+lishaduck@users.noreply.github.com>
Co-authored-by: ТΞNSΛI <tensai@gmx.net>
Co-authored-by: Patryk Kuniczak <p.kuniczak@gmail.com>
2026-07-26 18:02:38 -05:00
Aaron ab679ba413 fix: Handle edge case where eslint version cannot be found 2026-07-26 18:02:38 -05:00
Patryk Kuniczak f69b594401 feat!: Change default behavior of getUnimportEslintOptions true flag (#2296) 2026-07-26 18:02:38 -05:00
Aaron be3af14f9d chore(deps): Remove esbuild dependency (#2506) 2026-07-26 18:02:38 -05:00
Aaron 3679bc772e chore(deps): Upgrade to @types/node 22 2026-07-26 18:02:38 -05:00
Aaron 9da43b6b75 Fix formatting 2026-07-26 18:02:38 -05:00
Aaron 008f5a66c9 chore!: Bump minimum supported Node version to >=22 2026-07-26 18:02:38 -05:00
Aaron cffacffe34 fix!: Make web-ext a peer dependency (#2079)
Co-authored-by: Patryk Kuniczak <p.kuniczak@gmail.com>
2026-07-26 18:02:38 -05:00
ТΞNSΛI 3bd7aea9ee feat!: add {{modeSuffix}} to zip templates and update defaults (#1623)
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2026-07-26 18:02:38 -05:00
Eli 4b26d872ec refactor!: move to module-runner (#1946) 2026-07-26 18:02:38 -05:00
Eli c10d09fbdb refactor: make vite a default peer (#1945) 2026-07-26 18:02:38 -05:00
fkatsuhiro 9698f2fdd9 fix: Deprecated useAppConfig in favour of getAppConfig (#2487)
Co-authored-by: Gliches <nishumurmu017@gmail.com>
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2026-07-26 11:44:52 -05:00
github-actions[bot] 299b0add80 docs: Update wxt init GIF 2026-07-26 15:04:13 +00:00
Aaron ec3d3196a9 ci: Run VHS workflow on PRs that touch relevant files 2026-07-26 10:01:54 -05:00
github-actions[bot] 13be7c5bfd docs: Update wxt init GIF 2026-07-26 15:01:02 +00:00
Aaron 575240aaf1 ci: Allow the VHS action to commit to main 2026-07-26 09:58:27 -05:00
Thribhuvan b124c82ed4 docs: use consola's fancy reporter in init demo GIF (#2485) 2026-07-26 09:50:44 -05:00
Gliches 6c5a1b0d2e fix: add user exclusion for GitHub Actions in PR closed workflow (#2509) 2026-07-26 09:32:34 -05:00
Gliches eb93fa4535 fix: docs sidebar header, background color issue (#2504) 2026-07-26 10:37:37 +02:00
nnthanh01061999 5bd36e90bf docs: add MindSnap to showcase (#2499) 2026-07-21 17:57:14 +00:00
Hugo Villanueva Jimenez 172d37193e Docs: add ArcPort extensions entries to showcase (#2495) 2026-07-17 18:31:58 +00:00
Eason d92d5a4892 Add Adaptive Tab Bar Colour to extension showcase (#2490) 2026-07-11 17:42:31 +00:00
aklinker1 40c6c19802 fix: Upgrade @wxt-dev/browser to latest @types/chrome version 2026-07-02 01:05:26 +00:00
Aaron 653fccc8eb docs: Cleanup the "extension APIs" page (#2473) 2026-07-01 21:02:23 +05:30
Nazım Gediz Aydındoğmuş 95657939a8 docs: Added "Teams Chat Exporter" Edge Addons (edgeId) to extension showcase (#2472) 2026-06-30 22:12:08 +00:00
Arthur a578dbf633 feat(analytics): add posthog as an analytics provider (#2414)
Co-authored-by: Aaron <aaronklinker1@gmail.com>
2026-06-30 21:20:04 +00:00
github-actions[bot] f14ec35889 chore(release): @wxt-dev/i18n v0.2.6
📼 VHS / Create VHS (push) Cancelled after 0s
2026-06-30 21:02:33 +00:00
85 changed files with 1677 additions and 1111 deletions
+1
View File
@@ -27,6 +27,7 @@ jobs:
github.event.pull_request.user.login != 'aklinker1' &&
github.event.pull_request.user.login != 'Timeraa' &&
github.event.pull_request.user.login != 'PatrykKuniczak' &&
github.event.pull_request.user.login != 'nishu-murmu' &&
github.event.pull_request.user.login != 'dependabot[bot]' &&
github.event.pull_request.user.login != 'copilot-swe-agent[bot]'
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+50 -18
View File
@@ -20,6 +20,13 @@ on:
- unocss
- webextension-polyfill
- wxt
bump:
description: Blank (auto), a version (1.4.1), or major/minor/patch
type: string
dryRun:
description: Do a dry-run and don't publish anything
type: boolean
default: false
permissions:
contents: read
@@ -29,15 +36,20 @@ jobs:
name: Validate
uses: './.github/workflows/validate.yml'
secrets: inherit
if: ${{ inputs.dryRun != true }}
publish:
name: Publish
name: Publish ${{ case(inputs.dryRun, ' (dry-run)', '') }}
runs-on: ubuntu-24.04
permissions:
contents: write # Push version changes
id-token: write # OIDC for NPM publishing
needs:
- validate
# Allow dry runs to skip validation but still run this job
if: |
always() &&
(needs.validate.result == 'success' || needs.validate.result == 'skipped')
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
@@ -52,22 +64,42 @@ jobs:
run: |
git config user.name 'github-actions[bot]'
git config user.email 'github-actions[bot]@users.noreply.github.com'
git config --global push.followTags true
- name: Bump and Tag
run: |
bun run scripts/bump-package-version.ts ${{ inputs.package }}
git push
git push --tags
- name: Upgrade NPM for Provence
run: sudo npm i -g npm@latest
- name: Publish to NPM
working-directory: packages/${{ inputs.package }}
run: |
bun pm pack
sudo npm i -g npm@latest
npm publish *.tgz
- name: Create GitHub release
run: bun run scripts/create-github-release.ts ${{ inputs.package }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Bump and Release
uses: aklinker1/zero-changelog/actions/release@b6fcca17cebfc45f996b80fe5926da924d8441f8 # 0.2.1
with:
bump: ${{ inputs.bump }}
path: packages/${{ inputs.package }}
# Include documentation updates in WXT's releases
additionalDirs: |-
${{ case(
inputs.package == 'wxt', 'docs',
''
) }}
# Use package name in commit message
commitTemplate: |-
${{ case(
inputs.package == 'wxt', 'chore(release): wxt v{{version}}',
'chore(release): @wxt-dev/{{dirname}} v{{version}}'
) }}
# Use package name in release name
releaseNameTemplate: |-
${{ case(
inputs.package == 'wxt', 'wxt v{{version}}',
'@wxt-dev/{{dirname}} v{{version}}'
) }}
# Update lockfile with new versions since it includes the package versions
preCommitCommands: |-
bun i
publishCommands: |-
bun pm pack
npm publish *.tgz
dryRun: ${{ inputs.dryRun }}
dryRunPublishCommands: |-
bun pm pack
npm publish *.tgz --dry-run
githubToken: ${{ secrets.GITHUB_TOKEN }}
latestRelease: ${{ inputs.package == 'wxt' }}
-44
View File
@@ -1,44 +0,0 @@
name: 🔄 Sync Releases
on:
workflow_dispatch:
inputs:
package:
description: Package to sync
default: wxt
type: choice
options:
- analytics
- auto-icons
- i18n
- is-background
- module-react
- module-solid
- module-svelte
- module-vue
- runner
- storage
- webextension-polyfill
- wxt
permissions:
contents: read
jobs:
sync:
name: Sync Releases
runs-on: ubuntu-22.04
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Setup
uses: ./.github/actions/setup
with:
installArgs: --ignore-scripts
- name: Sync Releases
run: bun run scripts/sync-releases.ts ${{ inputs.package }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+8 -1
View File
@@ -2,7 +2,12 @@ name: 📼 VHS
on:
push:
paths:
- 'docs/tapes/*.tape'
- docs/tapes/*.tape
- .github/workflows/vhs.yml
pull_request:
paths:
- docs/tapes/*.tape
- .github/workflows/vhs.yml
workflow_dispatch:
permissions:
@@ -18,6 +23,8 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
ssh-key: ${{ secrets.DEPLOY_KEY }}
- name: Setup
uses: ./.github/actions/setup
-1
View File
@@ -53,7 +53,6 @@ Or see the [installation guide](https://wxt.dev/guide/installation.html) to get
- 📦 [Module system](https://wxt.dev/guide/essentials/wxt-modules.html#overview) for reusing code between extensions
- 🖍️ Quickly bootstrap a new project
- 📏 Bundle analysis
- ⬇️ Download and bundle remote URL imports
## Sponsors
Generated
+231 -109
View File
@@ -11,7 +11,6 @@
"@types/bun": "catalog:",
"@types/semver": "^7.7.1",
"@vitest/coverage-v8": "^4.1.6",
"changelogen": "^0.6.2",
"consola": "^3.4.2",
"cspell": "^9.7.0",
"feed": "^5.2.1",
@@ -83,13 +82,13 @@
},
"packages/browser": {
"name": "@wxt-dev/browser",
"version": "0.2.0",
"version": "0.2.2",
"dependencies": {
"@types/filesystem": "*",
"@types/har-format": "*",
},
"devDependencies": {
"@types/chrome": "0.2.0",
"@types/chrome": "0.2.2",
"@types/node": "catalog:",
"nano-spawn": "catalog:",
"typescript": "catalog:",
@@ -98,7 +97,7 @@
},
"packages/i18n": {
"name": "@wxt-dev/i18n",
"version": "0.2.5",
"version": "0.2.6",
"dependencies": {
"@wxt-dev/browser": "workspace:^",
"chokidar": "^5.0.0",
@@ -287,7 +286,7 @@
},
"packages/wxt": {
"name": "wxt",
"version": "0.20.27",
"version": "0.21.1",
"bin": {
"wxt": "./bin/wxt.mjs",
"wxt-publish-extension": "./bin/wxt-publish-extension.mjs",
@@ -295,9 +294,9 @@
"dependencies": {
"@1natsu/wait-element": "^4.1.2",
"@aklinker1/rollup-plugin-visualizer": "5.12.0",
"@webext-core/fake-browser": "^1.3.4",
"@webext-core/isolated-element": "^1.1.3",
"@webext-core/match-patterns": "^1.0.3",
"@webext-core/fake-browser": "^2.0.1",
"@webext-core/isolated-element": "^1.1.3 || ^2 || ^3",
"@webext-core/match-patterns": "^2.0.0",
"@wxt-dev/browser": "workspace:^",
"@wxt-dev/storage": "workspace:^1.0.0",
"async-mutex": "^0.5.0",
@@ -307,8 +306,7 @@
"ci-info": "^4.4.0",
"consola": "^3.4.2",
"defu": "^6.1.4",
"dotenv-expand": "^12.0.3",
"esbuild": "^0.27.1",
"dotenv-expand": "^13.0.0",
"filesize": "^11.0.17",
"get-port-please": "^3.2.0",
"giget": "^1.2.3 || ^2.0.0 || ^3.0.0",
@@ -327,12 +325,10 @@
"open": "^11.0.0",
"picomatch": "^4.0.3",
"prompts": "^2.4.2",
"publish-browser-extension": "^2.3.0 || ^3.0.2 || ^4.0.5",
"publish-browser-extension": "^5.1.0",
"scule": "^1.3.0",
"tinyglobby": "^0.2.16",
"unimport": "^3.13.1 || ^4.0.0 || ^5.0.0 || ^6.0.0",
"vite": "^5.4.19 || ^6.3.4 || ^7.0.0 || ^8.0.0-0",
"vite-node": "^3.2.4 || ^5.0.0 || ^6.0.0",
"web-ext-run": "^0.2.4",
},
"devDependencies": {
@@ -352,14 +348,21 @@
"publint": "catalog:",
"tsdown": "catalog:",
"typescript": "catalog:",
"vite": "catalog:",
"vitest": "catalog:",
"vitest-plugin-random-seed": "catalog:",
"web-ext": "^10.5.0",
},
"peerDependencies": {
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
"typescript": ">=5.4",
"vite": "^6.3.4 || ^7.0.0 || ^8.0.0-0",
"web-ext": ">=9.2.0",
},
"optionalPeers": [
"eslint",
"typescript",
"web-ext",
],
},
"packages/wxt-demo": {
@@ -394,7 +397,7 @@
"@aklinker1/buildc": "^1.1.7",
"@aklinker1/check": "^2.4.0",
"@types/bun": "^1.3.5",
"@types/node": "^20.17.6",
"@types/node": "^22",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"@webext-core/fake-browser": "^1.3.4",
@@ -404,6 +407,7 @@
"tsdown": "^0.21.0",
"typescript": "^6.0.3",
"unocss": "^66.6.8",
"vite": "^7.3.1",
"vitest": "^4.1.5",
"vitest-plugin-random-seed": "^1.1.2",
},
@@ -488,7 +492,7 @@
"@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw=="],
"@babel/runtime": ["@babel/runtime@7.28.2", "", {}, "sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA=="],
"@babel/runtime": ["@babel/runtime@8.0.0", "", {}, "sha512-sL6cvO2IfkSu/iU+zs2S/w01B7A8V7suXSIKEN4hPFFdZoiPGxrj5pAG0lCaqLWiEIrjKzdznIWuaLcxPR53qw=="],
"@babel/template": ["@babel/template@7.28.6", "", { "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/parser": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ=="],
@@ -728,12 +732,20 @@
"@eslint/core": ["@eslint/core@1.2.1", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ=="],
"@eslint/eslintrc": ["@eslint/eslintrc@3.3.6", "", { "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.0", "minimatch": "^3.1.5", "strip-json-comments": "^3.1.1" } }, "sha512-l2Ul9PrHsPCKcEY/ac7VgFj9D80C7S68sOKc618SyHDPK36s1XcFebXY0iTzUVn4Yq+YbwvSnDmCz9yxjX+QrA=="],
"@eslint/js": ["@eslint/js@9.39.4", "", {}, "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw=="],
"@eslint/object-schema": ["@eslint/object-schema@3.0.5", "", {}, "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw=="],
"@eslint/plugin-kit": ["@eslint/plugin-kit@0.7.1", "", { "dependencies": { "@eslint/core": "^1.2.1", "levn": "^0.4.1" } }, "sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ=="],
"@faker-js/faker": ["@faker-js/faker@10.3.0", "", {}, "sha512-It0Sne6P3szg7JIi6CgKbvTZoMjxBZhcv91ZrqrNuaZQfB5WoqYYbzCUOq89YR+VY8juY9M1vDWmDDa2TzfXCw=="],
"@fluent/syntax": ["@fluent/syntax@0.19.0", "", {}, "sha512-5D2qVpZrgpjtqU4eNOcWGp1gnUCgjfM+vKGE2y03kKN6z5EBhtx0qdRFbg8QuNNj8wXNoX93KJoYb+NqoxswmQ=="],
"@fregante/relaxed-json": ["@fregante/relaxed-json@2.0.0", "", {}, "sha512-PyUXQWB42s4jBli435TDiYuVsadwRHnMc27YaLouINktvTWsL3FcKrRMGawTayFk46X+n5bE23RjUTWQwrukWw=="],
"@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="],
"@humanfs/node": ["@humanfs/node@0.16.7", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.4.0" } }, "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ=="],
@@ -812,6 +824,8 @@
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
"@mdn/browser-compat-data": ["@mdn/browser-compat-data@8.0.4", "", {}, "sha512-up6DsNsaPt3jq5d2TGx4UOXIqBKU0D86dxWwcVmmOOEYqP1rFaV1XcAcwHxMvb6bbtMfY5JpjUCszzy/aVc4yA=="],
"@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.1", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" } }, "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A=="],
"@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
@@ -928,6 +942,8 @@
"@parcel/watcher-win32-x64": ["@parcel/watcher-win32-x64@2.5.6", "", { "os": "win32", "cpu": "x64" }, "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw=="],
"@pinojs/redact": ["@pinojs/redact@0.4.0", "", {}, "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg=="],
"@pnpm/config.env-replace": ["@pnpm/config.env-replace@1.1.0", "", {}, "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w=="],
"@pnpm/network.ca-file": ["@pnpm/network.ca-file@1.0.2", "", { "dependencies": { "graceful-fs": "4.2.10" } }, "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA=="],
@@ -1062,7 +1078,7 @@
"@types/chai": ["@types/chai@5.2.3", "", { "dependencies": { "@types/deep-eql": "*", "assertion-error": "^2.0.1" } }, "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA=="],
"@types/chrome": ["@types/chrome@0.2.0", "", { "dependencies": { "@types/filesystem": "*", "@types/har-format": "*" } }, "sha512-K/i7EKEVSpmyXXjE0ev5oASWBYMY6yM8LFSutG2PkM1DmxJUggZsoaTc0W1RsVwDDKrsZEjpHFAbqqxlRxGsSg=="],
"@types/chrome": ["@types/chrome@0.2.2", "", { "dependencies": { "@types/filesystem": "*", "@types/har-format": "*" } }, "sha512-8rSMZ4cvo2xmaSyQg0sN5yRL7oiDkntLoiHxUhfwQnv1mvnkrdoZ25SlNrKWmYKaeP50WvrfWj1pmc02+U9KKw=="],
"@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="],
@@ -1102,7 +1118,7 @@
"@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="],
"@types/node": ["@types/node@20.19.33", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-Rs1bVAIdBs5gbTIKza/tgpMuG1k3U/UMJLWecIMxNdJFDMzcM5LOiLVRYh3PilWEYDIeUDv7bpiHPLPsbydGcw=="],
"@types/node": ["@types/node@22.20.1", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q=="],
"@types/normalize-path": ["@types/normalize-path@3.0.2", "", {}, "sha512-DO++toKYPaFn0Z8hQ7Tx+3iT9t77IJo/nDiqTXilgEP+kPNIYdpS9kh3fXuc53ugqwp9pxC1PVjCpV1tQDyqMA=="],
@@ -1228,9 +1244,9 @@
"@webext-core/fake-browser": ["@webext-core/fake-browser@1.3.4", "", { "dependencies": { "lodash.merge": "^4.6.2" } }, "sha512-nZcVWr3JpwpS5E6hKpbAwAMBM/AXZShnfW0F76udW8oLd6Kv0nbW6vFS07md4Na/0ntQonk3hFnlQYGYBAlTrA=="],
"@webext-core/isolated-element": ["@webext-core/isolated-element@1.1.4", "", { "dependencies": { "is-potential-custom-element-name": "^1.0.1" } }, "sha512-JXF0F3b9JvSFmgrZ9fiaR1kiRZHXCSvwSctdahzIDmZXk2eq5H1Qev/Xk2wo3FxuwHPbdkcqDqvAowGZKLR9Ew=="],
"@webext-core/isolated-element": ["@webext-core/isolated-element@3.0.0", "", { "dependencies": { "is-potential-custom-element-name": "^1.0.1" } }, "sha512-PmSIBMSe+rFw6eXzpJoV+glc1HPO40clcT9FJ7rSfCQzNewK8/nQZoBYWen2cMqdXdBNM9to/IbNNu5mdQLaPg=="],
"@webext-core/match-patterns": ["@webext-core/match-patterns@1.0.3", "", {}, "sha512-NY39ACqCxdKBmHgw361M9pfJma8e4AZo20w9AY+5ZjIj1W2dvXC8J31G5fjfOGbulW9w4WKpT8fPooi0mLkn9A=="],
"@webext-core/match-patterns": ["@webext-core/match-patterns@2.0.0", "", {}, "sha512-EsyMMKfQuSE4rWCjP/TifwvUWlhC/OhiGn5OK3p9F0d57UmtLib0nzguzPKyxM1/kZV7SkE+jYXkE8gsdPRLmw=="],
"@wxt-dev/analytics": ["@wxt-dev/analytics@workspace:packages/analytics"],
@@ -1262,21 +1278,27 @@
"acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="],
"addons-linter": ["addons-linter@10.8.0", "", { "dependencies": { "@fluent/syntax": "0.19.0", "@fregante/relaxed-json": "2.0.0", "@mdn/browser-compat-data": "8.0.4", "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.7", "yargs": "17.7.2", "yauzl": "3.4.0" }, "bin": { "addons-linter": "bin/addons-linter" } }, "sha512-AotpGWlp5FrmUIH8kjyYjQvCmthnSqPLpw7kOEl7DfoAWEndOCV/ONuekAVM8QObiei802RyyIClEaekA51n5g=="],
"addons-moz-compare": ["addons-moz-compare@1.3.0", "", {}, "sha512-/rXpQeaY0nOKhNx00pmZXdk5Mu+KhVlL3/pSBuAYwrxRrNiTvI/9xfQI8Lmm7DMMl+PDhtfAHY/0ibTpdeoQQQ=="],
"addons-scanner-utils": ["addons-scanner-utils@15.4.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" }, "optionalPeers": ["express", "safe-compare"] }, "sha512-i3PnJx9YLZi96o4t4JWArP6JimC01949YVAcMJKHfyQ5qmUBaH21qNS8f12/RsloejW8IcCEljhh3Fq3gxFNsg=="],
"adm-zip": ["adm-zip@0.5.16", "", {}, "sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ=="],
"agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
"ajv": ["ajv@6.14.0", "", { "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" } }, "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw=="],
"algoliasearch": ["algoliasearch@5.48.0", "", { "dependencies": { "@algolia/abtesting": "1.14.0", "@algolia/client-abtesting": "5.48.0", "@algolia/client-analytics": "5.48.0", "@algolia/client-common": "5.48.0", "@algolia/client-insights": "5.48.0", "@algolia/client-personalization": "5.48.0", "@algolia/client-query-suggestions": "5.48.0", "@algolia/client-search": "5.48.0", "@algolia/ingestion": "1.48.0", "@algolia/monitoring": "1.48.0", "@algolia/recommend": "5.48.0", "@algolia/requester-browser-xhr": "5.48.0", "@algolia/requester-fetch": "5.48.0", "@algolia/requester-node-http": "5.48.0" } }, "sha512-aD8EQC6KEman6/S79FtPdQmB7D4af/etcRL/KwiKFKgAE62iU8c5PeEQvpvIcBPurC3O/4Lj78nOl7ZcoazqSw=="],
"ansi-align": ["ansi-align@3.0.1", "", { "dependencies": { "string-width": "^4.1.0" } }, "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w=="],
"ansi-escapes": ["ansi-escapes@7.3.0", "", { "dependencies": { "environment": "^1.0.0" } }, "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg=="],
"ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
"ansi-sequence-parser": ["ansi-sequence-parser@1.1.3", "", {}, "sha512-+fksAx9eG3Ab6LDnLs3ZqZa8KVJ/jYnX+D4Qe1azX+LFGFAXqynCQLOdLpNYN/l9e7l6hMWwZbrnctqr6eSQSw=="],
"ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="],
"ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
"ansis": ["ansis@4.2.0", "", {}, "sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig=="],
@@ -1360,8 +1382,6 @@
"chalk-template": ["chalk-template@1.1.2", "", { "dependencies": { "chalk": "^5.2.0" } }, "sha512-2bxTP2yUH7AJj/VAXfcA+4IcWGdQ87HwBANLt5XxGTeomo8yG0y95N1um9i5StvhT/Bl0/2cARA5v1PpPXUxUA=="],
"changelogen": ["changelogen@0.6.2", "", { "dependencies": { "c12": "^3.0.4", "confbox": "^0.2.2", "consola": "^3.4.2", "convert-gitmoji": "^0.1.5", "mri": "^1.2.0", "node-fetch-native": "^1.6.6", "ofetch": "^1.4.1", "open": "^10.1.2", "pathe": "^2.0.3", "pkg-types": "^2.2.0", "scule": "^1.3.0", "semver": "^7.7.2", "std-env": "^3.9.0" }, "bin": { "changelogen": "dist/cli.mjs" } }, "sha512-QtC7+r9BxoUm+XDAwhLbz3CgU134J1ytfE3iCpLpA4KFzX2P1e6s21RrWDwUBzfx66b1Rv+6lOA2nS2btprd+A=="],
"character-entities": ["character-entities@2.0.2", "", {}, "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ=="],
"character-entities-html4": ["character-entities-html4@2.1.0", "", {}, "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA=="],
@@ -1370,6 +1390,10 @@
"character-reference-invalid": ["character-reference-invalid@2.0.1", "", {}, "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw=="],
"cheerio": ["cheerio@1.2.0", "", { "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" } }, "sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg=="],
"cheerio-select": ["cheerio-select@2.1.0", "", { "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" } }, "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g=="],
"chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="],
"chrome-launcher": ["chrome-launcher@1.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" } }, "sha512-JbuGuBNss258bvGil7FT4HKdC3SC2K7UAEUqiPy3ACS3Yxo3hAW6bvFpCu2HsIJLgTqxgEX6BkujvzZfLpUD0Q=="],
@@ -1382,12 +1406,10 @@
"cli-boxes": ["cli-boxes@3.0.0", "", {}, "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g=="],
"cli-cursor": ["cli-cursor@5.0.0", "", { "dependencies": { "restore-cursor": "^5.0.0" } }, "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw=="],
"cli-truncate": ["cli-truncate@5.1.1", "", { "dependencies": { "slice-ansi": "^7.1.0", "string-width": "^8.0.0" } }, "sha512-SroPvNHxUnk+vIW/dOSfNqdy1sPEFkrTk6TUtqLCnBlo3N7TNYYkzzN7uSD6+jVjrdO4+p8nH7JzH6cIvUem6A=="],
"cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="],
"clone": ["clone@1.0.4", "", {}, "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg=="],
"clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="],
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
@@ -1396,6 +1418,8 @@
"colorette": ["colorette@2.0.20", "", {}, "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w=="],
"columnify": ["columnify@1.6.0", "", { "dependencies": { "strip-ansi": "^6.0.1", "wcwidth": "^1.0.0" } }, "sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q=="],
"comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="],
"commander": ["commander@14.0.3", "", {}, "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw=="],
@@ -1404,6 +1428,8 @@
"comment-parser": ["comment-parser@1.4.6", "", {}, "sha512-ObxuY6vnbWTN6Od72xfwN9DbzC7Y2vv8u1Soi9ahRKL37gb6y1qk6/dgjs+3JWuXJHWvsg3BXIwzd/rkmAwavg=="],
"common-tags": ["common-tags@1.8.2", "", {}, "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA=="],
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
"concat-stream": ["concat-stream@1.6.2", "", { "dependencies": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^2.2.2", "typedarray": "^0.0.6" } }, "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw=="],
@@ -1420,8 +1446,6 @@
"conventional-commits-parser": ["conventional-commits-parser@7.0.0", "", { "dependencies": { "@simple-libs/stream-utils": "^2.0.0", "meow": "^14.0.0" }, "bin": { "conventional-commits-parser": "./dist/cli/index.js" } }, "sha512-dZe/p+FgGQLNJFqaCgNdl8j6a7gI8xuaN30Wy5g7nvyK3jqOpNUEUZ3pGJ5D68h89uRh038FtkeOk/bnGmYkmg=="],
"convert-gitmoji": ["convert-gitmoji@0.1.5", "", {}, "sha512-4wqOafJdk2tqZC++cjcbGcaJ13BZ3kwldf06PTiAQRAB76Z1KJwZNL1SaRZMi2w1FM9RYTgZ6QErS8NUl/GBmQ=="],
"convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],
"copy-anything": ["copy-anything@4.0.5", "", { "dependencies": { "is-what": "^5.2.0" } }, "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA=="],
@@ -1462,6 +1486,8 @@
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
"decamelize": ["decamelize@6.0.1", "", {}, "sha512-G7Cqgaelq68XHJNGlZ7lrNQyhZGsFqpwtGFexqUv4IQdjKoSYF7ipZ9UuTJZUSQXFj/XaoBLuEVIVqr8EJngEQ=="],
"decode-named-character-reference": ["decode-named-character-reference@1.3.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q=="],
"deep-extend": ["deep-extend@0.6.0", "", {}, "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="],
@@ -1474,6 +1500,8 @@
"default-browser-id": ["default-browser-id@5.0.1", "", {}, "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q=="],
"defaults": ["defaults@1.0.4", "", { "dependencies": { "clone": "^1.0.2" } }, "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A=="],
"define-lazy-prop": ["define-lazy-prop@3.0.0", "", {}, "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg=="],
"defu": ["defu@6.1.7", "", {}, "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ=="],
@@ -1502,7 +1530,7 @@
"dotenv": ["dotenv@17.4.2", "", {}, "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw=="],
"dotenv-expand": ["dotenv-expand@12.0.3", "", { "dependencies": { "dotenv": "^16.4.5" } }, "sha512-uc47g4b+4k/M/SeaW1y4OApx+mtLWl92l5LMPP0GNXctZqELk+YGgOPIIC5elYmUH4OuoK3JLhuRUYegeySiFA=="],
"dotenv-expand": ["dotenv-expand@13.0.0", "", { "dependencies": { "dotenv": "^17.4.2" } }, "sha512-aBfBS8eYIeXmpHI9ThIlA7/WLq+SLt18iXUZhb52rW89QLKQFoIpPG1bPeewoPZsTyjSSO3T7234FBVUM1V2rA=="],
"dts-resolver": ["dts-resolver@2.1.3", "", { "peerDependencies": { "oxc-resolver": ">=11.0.0" }, "optionalPeers": ["oxc-resolver"] }, "sha512-bihc7jPC90VrosXNzK0LTE2cuLP6jr0Ro8jk+kMugHReJVLIpHz/xadeq3MhuwyO4TD4OA3L1Q8pBBFRc08Tsw=="],
@@ -1518,14 +1546,14 @@
"empathic": ["empathic@2.0.0", "", {}, "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA=="],
"encoding-sniffer": ["encoding-sniffer@0.2.1", "", { "dependencies": { "iconv-lite": "^0.6.3", "whatwg-encoding": "^3.1.1" } }, "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw=="],
"end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="],
"entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="],
"env-paths": ["env-paths@4.0.0", "", { "dependencies": { "is-safe-filename": "^0.1.0" } }, "sha512-pxP8eL2SwwaTRi/KHYwLYXinDs7gL3jxFcBYmEdYfZmZXbaVDvdppd0XBU8qVz03rDfKZMXg1omHCbsJjZrMsw=="],
"environment": ["environment@1.1.0", "", {}, "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q=="],
"error-ex": ["error-ex@1.3.4", "", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ=="],
"es-module-lexer": ["es-module-lexer@2.0.0", "", {}, "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw=="],
@@ -1542,6 +1570,8 @@
"eslint": ["eslint@10.2.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.2", "@eslint/config-array": "^0.23.4", "@eslint/config-helpers": "^0.5.4", "@eslint/core": "^1.2.0", "@eslint/plugin-kit": "^0.7.0", "@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.4", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-+L0vBFYGIpSNIt/KWTpFonPrqYvgKw1eUI5Vn7mEogrQcWtWYtNQ7dNqC+px/J0idT3BAkiWrhfS7k+Tum8TUA=="],
"eslint-plugin-no-unsanitized": ["eslint-plugin-no-unsanitized@4.1.5", "", { "peerDependencies": { "eslint": "^9 || ^10" } }, "sha512-MSB4hXPVFQrI8weqzs6gzl7reP2k/qSjtCoL2vUMSDejIIq9YL1ZKvq5/ORBXab/PvfBBrWO2jWviYpL+4Ghfg=="],
"eslint-scope": ["eslint-scope@9.1.2", "", { "dependencies": { "@types/esrecurse": "^4.3.1", "@types/estree": "^1.0.8", "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ=="],
"eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="],
@@ -1564,8 +1594,6 @@
"esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="],
"eventemitter3": ["eventemitter3@5.0.4", "", {}, "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw=="],
"expect-type": ["expect-type@1.3.0", "", {}, "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA=="],
"exsolve": ["exsolve@1.0.8", "", {}, "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA=="],
@@ -1582,12 +1610,16 @@
"fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="],
"fast-json-patch": ["fast-json-patch@3.1.1", "", {}, "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ=="],
"fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="],
"fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="],
"fast-redact": ["fast-redact@3.5.0", "", {}, "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A=="],
"fast-uri": ["fast-uri@3.1.4", "", {}, "sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw=="],
"fastq": ["fastq@1.20.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw=="],
"fault": ["fault@2.0.1", "", { "dependencies": { "format": "^0.2.0" } }, "sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ=="],
@@ -1608,6 +1640,8 @@
"firefox-profile": ["firefox-profile@4.7.0", "", { "dependencies": { "adm-zip": "~0.5.x", "fs-extra": "^11.2.0", "ini": "^4.1.3", "minimist": "^1.2.8", "xml2js": "^0.6.2" }, "bin": { "firefox-profile": "lib/cli.js" } }, "sha512-aGApEu5bfCNbA4PGUZiRJAIU6jKmghV2UVdklXAofnNtiDjqYw0czLS46W7IfFqVKgKhFB8Ao2YoNGHY4BoIMQ=="],
"first-chunk-stream": ["first-chunk-stream@3.0.0", "", {}, "sha512-LNRvR4hr/S8cXXkIY5pTgVP7L3tq6LlYWcg9nWBuW7o1NMxKZo6oOVa/6GIekMGI0Iw7uC+HWimMe9u/VAeKqw=="],
"flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="],
"flatted": ["flatted@3.4.2", "", {}, "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA=="],
@@ -1624,7 +1658,7 @@
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
"fx-runner": ["fx-runner@1.4.0", "", { "dependencies": { "commander": "2.9.0", "shell-quote": "1.7.3", "spawn-sync": "1.0.15", "when": "3.7.7", "which": "1.2.4", "winreg": "0.0.12" }, "bin": { "fx-runner": "bin/fx-runner" } }, "sha512-rci1g6U0rdTg6bAaBboP7XdRu01dzTAaKXxFf+PUqGuCv6Xu7o8NZdY1D5MvKGIjb6EdS1g3VlXOgksir1uGkg=="],
"fx-runner": ["fx-runner@1.5.0", "", { "dependencies": { "commander": "^12.1.0", "shell-quote": "1.8.4", "which": "^4.0.0", "winreg": "0.0.12" }, "bin": { "fx-runner": "bin/fx-runner" } }, "sha512-EstfdRQu04tM+SXR3pBmc0+GYKZj9FMHAvA8XAbKPzTvUeHP0v1/F3aQ10bG7EluR6phvFqsvn5Z7SvYJsEgNw=="],
"gensequence": ["gensequence@8.0.8", "", {}, "sha512-omMVniXEXpdx/vKxGnPRoO2394Otlze28TyxECbFVyoSpZ9H3EO7lemjcB12OpQJzRW4e5tt/dL1rOxry6aMHg=="],
@@ -1648,6 +1682,8 @@
"global-directory": ["global-directory@5.0.0", "", { "dependencies": { "ini": "6.0.0" } }, "sha512-1pgFdhK3J2LeM+dVf2Pd424yHx2ou338lC0ErNP2hPx4j8eW1Sp0XqSjNxtk6Tc4Kr5wlWtSvz8cn2yb7/SG/w=="],
"globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="],
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
"graceful-readlink": ["graceful-readlink@1.0.1", "", {}, "sha512-8tLu60LgxF6XpdbK8OW3FA+IfTNBn1ZHGHKF4KQbEeSkajYw5PlYJcKluntgegDPTg8UkHjpet1T82vk6TQ68w=="],
@@ -1678,8 +1714,14 @@
"htmlparser2": ["htmlparser2@10.1.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.2.2", "entities": "^7.0.1" } }, "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ=="],
"https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="],
"iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
"ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
"image-size": ["image-size@2.0.2", "", { "bin": { "image-size": "bin/image-size.js" } }, "sha512-IRqXKlaXwgSMAMtpNzZa1ZAe8m+Sa1770Dhk8VkSsP9LS+iHD62Zd8FQKs8fbPiagBE7BzoFX23cxFnwshpV6w=="],
"immediate": ["immediate@3.0.6", "", {}, "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="],
"immutable": ["immutable@5.1.4", "", {}, "sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA=="],
@@ -1692,6 +1734,8 @@
"imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="],
"index-to-position": ["index-to-position@1.2.0", "", {}, "sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw=="],
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
"ini": ["ini@4.1.3", "", {}, "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg=="],
@@ -1746,6 +1790,8 @@
"is-safe-filename": ["is-safe-filename@0.1.1", "", {}, "sha512-4SrR7AdnY11LHfDKTZY1u6Ga3RuxZdl3YKWWShO5iyuG5h8QS4GD2tOb04peBJ5I7pXbR+CGBNEhTcwK+FzN3g=="],
"is-utf8": ["is-utf8@0.2.1", "", {}, "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q=="],
"is-what": ["is-what@4.1.16", "", {}, "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A=="],
"is-wsl": ["is-wsl@3.1.1", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw=="],
@@ -1764,6 +1810,8 @@
"jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
"jose": ["jose@5.9.6", "", {}, "sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ=="],
"js-tokens": ["js-tokens@10.0.0", "", {}, "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q=="],
"js-yaml": ["js-yaml@4.2.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw=="],
@@ -1772,6 +1820,8 @@
"json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="],
"json-merge-patch": ["json-merge-patch@1.0.2", "", { "dependencies": { "fast-deep-equal": "^3.1.3" } }, "sha512-M6Vp2GN9L7cfuMXiWOmHj9bEFbeC250iVtcKQbqVgEsDVYnIsrNsbU+h/Y/PkbBQCtEa4Bez+Ebv0zfbC8ObLg=="],
"json-parse-even-better-errors": ["json-parse-even-better-errors@3.0.2", "", {}, "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ=="],
"json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
@@ -1818,8 +1868,6 @@
"linkify-it": ["linkify-it@5.0.1", "", { "dependencies": { "uc.micro": "^2.0.0" } }, "sha512-wVoTjP4Q6R0NW5hiZkVJaFZPWgtXfoGF+6LucL3/FtiNjmcHhYjEr5f1Kqjirc1nBW07J/ZuRFumqr2oqccEWg=="],
"listr2": ["listr2@10.1.0", "", { "dependencies": { "cli-truncate": "^5.0.0", "colorette": "^2.0.20", "eventemitter3": "^5.0.1", "log-update": "^7.0.2", "rfdc": "^1.4.1", "wrap-ansi": "^9.0.0" } }, "sha512-/6t2KgDYIcCjhELwvrRxi1gaJ4xCGLTjNvh6mSjYenBkrZxggek8EwCbwBU33GMUCpyyrOzz2TzylrO5mTiI1w=="],
"local-pkg": ["local-pkg@1.1.2", "", { "dependencies": { "mlly": "^1.7.4", "pkg-types": "^2.3.0", "quansync": "^0.2.11" } }, "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A=="],
"locate-character": ["locate-character@3.0.0", "", {}, "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA=="],
@@ -1842,8 +1890,6 @@
"lodash.once": ["lodash.once@4.1.1", "", {}, "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="],
"log-update": ["log-update@7.1.0", "", { "dependencies": { "ansi-escapes": "^7.1.0", "cli-cursor": "^5.0.0", "slice-ansi": "^7.1.2", "strip-ansi": "^7.1.2", "wrap-ansi": "^9.0.2" } }, "sha512-y9pi/ZOQQVvTgfRDEHV1Cj4zQUkJZPipEUNOxhn1R6KgmdMs7LKvXWCd9eMVPGJgvYzFLCenecWr0Ps8ChVv2A=="],
"longest-streak": ["longest-streak@3.1.0", "", {}, "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="],
"lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
@@ -1958,8 +2004,6 @@
"millify": ["millify@6.1.0", "", { "dependencies": { "yargs": "^17.0.1" }, "bin": { "millify": "bin/millify" } }, "sha512-H/E3J6t+DQs/F2YgfDhxUVZz/dF8JXPPKTLHL/yHCcLZLtCXJDUaqvhJXQwqOVBvbyNn4T0WjLpIHd7PAw7fBA=="],
"mimic-function": ["mimic-function@5.0.1", "", {}, "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA=="],
"minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="],
"minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
@@ -2018,8 +2062,6 @@
"once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
"onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="],
"oniguruma-to-es": ["oniguruma-to-es@3.1.1", "", { "dependencies": { "emoji-regex-xs": "^1.0.0", "regex": "^6.0.1", "regex-recursion": "^6.0.2" } }, "sha512-bUH8SDvPkH3ho3dvwJwfonjlQ4R80vjyvrU8YpxuROddv55vAEJrTuCuCVUhhsHbtlD9tGGbaNApGQckXhS8iQ=="],
"open": ["open@11.0.0", "", { "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" } }, "sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw=="],
@@ -2050,10 +2092,14 @@
"parse-entities": ["parse-entities@4.0.2", "", { "dependencies": { "@types/unist": "^2.0.0", "character-entities-legacy": "^3.0.0", "character-reference-invalid": "^2.0.0", "decode-named-character-reference": "^1.0.0", "is-alphanumerical": "^2.0.0", "is-decimal": "^2.0.0", "is-hexadecimal": "^2.0.0" } }, "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw=="],
"parse-json": ["parse-json@7.1.1", "", { "dependencies": { "@babel/code-frame": "^7.21.4", "error-ex": "^1.3.2", "json-parse-even-better-errors": "^3.0.0", "lines-and-columns": "^2.0.3", "type-fest": "^3.8.0" } }, "sha512-SgOTCX/EZXtZxBE5eJ97P4yGM5n37BwRU+YMsH4vNzFqJV/oWFXXCmwFlgWUM4PrakybVOueJJ6pwHqSVhTFDw=="],
"parse-json": ["parse-json@8.3.0", "", { "dependencies": { "@babel/code-frame": "^7.26.2", "index-to-position": "^1.1.0", "type-fest": "^4.39.1" } }, "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ=="],
"parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="],
"parse5-htmlparser2-tree-adapter": ["parse5-htmlparser2-tree-adapter@7.1.0", "", { "dependencies": { "domhandler": "^5.0.3", "parse5": "^7.0.0" } }, "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g=="],
"parse5-parser-stream": ["parse5-parser-stream@7.1.2", "", { "dependencies": { "parse5": "^7.0.0" } }, "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow=="],
"path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="],
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
@@ -2070,9 +2116,9 @@
"picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="],
"pino": ["pino@9.7.0", "", { "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.1.1", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.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": "^3.0.0" }, "bin": { "pino": "bin.js" } }, "sha512-vnMCM6xZTb1WDmLvtG2lE/2p+t9hDEIvTWJsu6FejkE62vB7gDhvzrpFR4Cw2to+9JNQxVnkAKVPA1KPB98vWg=="],
"pino": ["pino@10.3.1", "", { "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" } }, "sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg=="],
"pino-abstract-transport": ["pino-abstract-transport@2.0.0", "", { "dependencies": { "split2": "^4.0.0" } }, "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw=="],
"pino-abstract-transport": ["pino-abstract-transport@3.0.0", "", { "dependencies": { "split2": "^4.0.0" } }, "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg=="],
"pino-std-serializers": ["pino-std-serializers@7.1.0", "", {}, "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw=="],
@@ -2108,7 +2154,7 @@
"publint": ["publint@0.3.18", "", { "dependencies": { "@publint/pack": "^0.1.4", "package-manager-detector": "^1.6.0", "picocolors": "^1.1.1", "sade": "^1.8.1" }, "bin": { "publint": "src/cli.js" } }, "sha512-JRJFeBTrfx4qLwEuGFPk+haJOJN97KnPuK01yj+4k/Wj5BgoOK5uNsivporiqBjk2JDaslg7qJOhGRnpltGeog=="],
"publish-browser-extension": ["publish-browser-extension@4.0.5", "", { "dependencies": { "cac": "^6.7.14", "consola": "^3.4.2", "dotenv": "^17.2.4", "form-data-encoder": "^4.1.0", "formdata-node": "^6.0.3", "jsonwebtoken": "^9.0.3", "listr2": "^10.1.0", "ofetch": "^1.5.1", "zod": "3.25.76 || ^4.3.6" }, "bin": { "publish-extension": "bin/publish-extension.mjs" } }, "sha512-EePAn3VIHJS/jqCuvs1NgPgoecCT8+RsES76hbgYe2Ze1dyvB0tX60C1PCrV8Z8fv56mW3E59s9Gd/GwWiw7dw=="],
"publish-browser-extension": ["publish-browser-extension@5.1.0", "", { "dependencies": { "cac": "^6.7.14", "consola": "^3.4.2", "dotenv": "^17.2.4", "form-data-encoder": "^4.1.0", "formdata-node": "^6.0.3", "tasuku": "^2.3.0" }, "bin": { "publish-extension": "bin/publish-extension.mjs" } }, "sha512-cRP5AV5UhXGheK//GwI3dCKPDtvStbcoqwerh6HZ7McB6RpepQmkHjSAWXmNGik0Eu0sRhPPuRUNmgvCn+cFrg=="],
"pump": ["pump@3.0.3", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA=="],
@@ -2162,12 +2208,12 @@
"require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="],
"require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="],
"resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="],
"resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="],
"restore-cursor": ["restore-cursor@5.1.0", "", { "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" } }, "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA=="],
"retry": ["retry@0.12.0", "", {}, "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow=="],
"reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="],
@@ -2192,6 +2238,8 @@
"safe-stable-stringify": ["safe-stable-stringify@2.5.0", "", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="],
"safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
"sass": ["sass@1.97.3", "", { "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", "source-map-js": ">=0.6.2 <2.0.0" }, "optionalDependencies": { "@parcel/watcher": "^2.4.1" }, "bin": { "sass": "sass.js" } }, "sha512-fDz1zJpd5GycprAbu4Q2PV/RprsRtKC/0z82z0JLgdytmcq0+ujJbJ/09bPGDxCLkKY3Np5cRAOcWiVkLXJURg=="],
"sax": ["sax@1.4.4", "", {}, "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw=="],
@@ -2220,7 +2268,7 @@
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
"shell-quote": ["shell-quote@1.7.3", "", {}, "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw=="],
"shell-quote": ["shell-quote@1.8.4", "", {}, "sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ=="],
"shellwords": ["shellwords@0.1.1", "", {}, "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww=="],
@@ -2236,8 +2284,6 @@
"sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="],
"slice-ansi": ["slice-ansi@7.1.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "is-fullwidth-code-point": "^5.0.0" } }, "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w=="],
"smol-toml": ["smol-toml@1.6.1", "", {}, "sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg=="],
"solid-js": ["solid-js@1.9.11", "", { "dependencies": { "csstype": "^3.1.0", "seroval": "~1.5.0", "seroval-plugins": "~1.5.0" } }, "sha512-WEJtcc5mkh/BnHA6Yrg4whlF8g6QwpmXXRg4P2ztPmcKeHHlH4+djYecBLhSpecZY2RRECXYUwIc/C2r3yzQ4Q=="],
@@ -2278,9 +2324,13 @@
"strip-bom": ["strip-bom@5.0.0", "", {}, "sha512-p+byADHF7SzEcVnLvc/r3uognM1hUhObuHXxJcgLCfD194XAkaLbjq3Wzb0N5G2tgIjH0dgT708Z51QxMeu60A=="],
"strip-bom-buf": ["strip-bom-buf@2.0.0", "", { "dependencies": { "is-utf8": "^0.2.1" } }, "sha512-gLFNHucd6gzb8jMsl5QmZ3QgnUJmp7qn4uUSHNwEXumAp7YizoGYw19ZUVfuq4aBOQUtyn2k8X/CwzWB73W2lQ=="],
"strip-bom-stream": ["strip-bom-stream@4.0.0", "", { "dependencies": { "first-chunk-stream": "^3.0.0", "strip-bom-buf": "^2.0.0" } }, "sha512-0ApK3iAkHv6WbgLICw/J4nhwHeDZsBxIIsOD+gHgZICL6SeJ0S9f/WZqemka9cjkTyMN5geId6e8U5WGFAn3cQ=="],
"strip-bom-string": ["strip-bom-string@1.0.0", "", {}, "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g=="],
"strip-json-comments": ["strip-json-comments@5.0.2", "", {}, "sha512-4X2FR3UwhNUE9G49aIsJW5hRRR3GXGTBTZRMfv568O60ojM8HcWjV/VxAxCDW3SUND33O6ZY66ZuRcdkj73q2g=="],
"strip-json-comments": ["strip-json-comments@5.0.3", "", {}, "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw=="],
"strip-literal": ["strip-literal@3.1.0", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg=="],
@@ -2296,7 +2346,9 @@
"tabbable": ["tabbable@6.4.0", "", {}, "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg=="],
"thread-stream": ["thread-stream@3.1.0", "", { "dependencies": { "real-require": "^0.2.0" } }, "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A=="],
"tasuku": ["tasuku@2.3.0", "", {}, "sha512-9Jtk+XAnttslCw4i9RceSZGr2PT5TLn0vUyWnoP2SdlSYzkiYRY6kB5qnPi5IQ/Em8e4oBow1rpaA39iijTIrA=="],
"thread-stream": ["thread-stream@4.2.0", "", { "dependencies": { "real-require": "^1.0.0" } }, "sha512-e2zZ96wSChazBsbENf/Pcm/4swHt2cEKQ92rhUjkL9GCKiTDJIaTBenjE/m9DXi0QBmTMDkFDdOomUy20A1tDQ=="],
"through": ["through@2.3.8", "", {}, "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg=="],
@@ -2308,7 +2360,7 @@
"tinyrainbow": ["tinyrainbow@3.1.0", "", {}, "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw=="],
"tmp": ["tmp@0.2.5", "", {}, "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow=="],
"tmp": ["tmp@0.2.7", "", {}, "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw=="],
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
@@ -2332,7 +2384,7 @@
"type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="],
"type-fest": ["type-fest@3.13.1", "", {}, "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g=="],
"type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="],
"type-level-regexp": ["type-level-regexp@0.1.17", "", {}, "sha512-wTk4DH3cxwk196uGLK/E9pE45aLfeKJacKmcEgEOA/q5dnPGNxXt0cfYdFxb57L+sEpf1oJH4Dnx/pnRcku9jg=="],
@@ -2360,6 +2412,8 @@
"unconfig-core": ["unconfig-core@7.5.0", "", { "dependencies": { "@quansync/fs": "^1.0.0", "quansync": "^1.0.0" } }, "sha512-Su3FauozOGP44ZmKdHy2oE6LPjk51M/TRRjHv2HNCWiDvfvCoxC2lno6jevMA91MYAdCdwP05QnWdWpSbncX/w=="],
"undici": ["undici@7.29.0", "", {}, "sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw=="],
"undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
"unified": ["unified@11.0.5", "", { "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", "devlop": "^1.0.0", "extend": "^3.0.0", "is-plain-obj": "^4.0.0", "trough": "^2.0.0", "vfile": "^6.0.0" } }, "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA=="],
@@ -2388,6 +2442,8 @@
"unrun": ["unrun@0.2.34", "", { "dependencies": { "rolldown": "1.0.0-rc.12" }, "peerDependencies": { "synckit": "^0.11.11" }, "optionalPeers": ["synckit"], "bin": { "unrun": "dist/cli.mjs" } }, "sha512-LyaghRBR++r7svhDK6tnDz2XaYHWdneBOA0jbS8wnRsHerI9MFljX4fIiTgbbNbEVzZ0C9P1OjWLLe1OqoaaEw=="],
"upath": ["upath@3.0.7", "", {}, "sha512-VjBBquch25nUGMuVBpOb2Cj3gc8Kb7lJBqbsXR/0anZ/5uJsL14Kpth9JKfnBsckxCfgIp6hPvcvvmZ97R9X7g=="],
"update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="],
"update-notifier": ["update-notifier@7.3.1", "", { "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" } }, "sha512-+dwUY4L35XFYEzE+OAL3sarJdUioVovq+8f7lcIJ7wnmnYQV5UD1Y/lcwaMSyaQ6Bj3JMj1XSTjZbNLHn/19yA=="],
@@ -2404,8 +2460,6 @@
"vite": ["vite@7.3.1", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.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" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA=="],
"vite-node": ["vite-node@5.3.0", "", { "dependencies": { "cac": "^6.7.14", "es-module-lexer": "^2.0.0", "obug": "^2.1.1", "pathe": "^2.0.3", "vite": "^7.3.1" }, "bin": { "vite-node": "dist/cli.mjs" } }, "sha512-8f20COPYJujc3OKPX6OuyBy3ZIv2det4eRRU4GY1y2MjbeGSUmPjedxg1b72KnTagCofwvZ65ThzjxDW2AtQFQ=="],
"vite-plugin-solid": ["vite-plugin-solid@2.11.10", "", { "dependencies": { "@babel/core": "^7.23.3", "@types/babel__core": "^7.20.4", "babel-preset-solid": "^1.8.4", "merge-anything": "^5.1.7", "solid-refresh": "^0.6.3", "vitefu": "^1.0.4" }, "peerDependencies": { "@testing-library/jest-dom": "^5.16.6 || ^5.17.0 || ^6.*", "solid-js": "^1.7.2", "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" }, "optionalPeers": ["@testing-library/jest-dom"] }, "sha512-Yr1dQybmtDtDAHkii6hXuc1oVH9CPcS/Zb2jN/P36qqcrkNnVPsMTzQ06jyzFPFjj3U1IYKMVt/9ZqcwGCEbjw=="],
"vitefu": ["vitefu@1.1.1", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" }, "optionalPeers": ["vite"] }, "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ=="],
@@ -2434,7 +2488,11 @@
"vue": ["vue@3.5.34", "", { "dependencies": { "@vue/compiler-dom": "3.5.34", "@vue/compiler-sfc": "3.5.34", "@vue/runtime-dom": "3.5.34", "@vue/server-renderer": "3.5.34", "@vue/shared": "3.5.34" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-WdLBG9gm02OgJIG9axd5Hpx0TFLdzVgfG2evFFu8Rur5O/IoGc5cMjnjh3tPL6GnRGsYvUhBSKVPYVcxRKpMCA=="],
"watchpack": ["watchpack@2.4.4", "", { "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" } }, "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA=="],
"watchpack": ["watchpack@2.5.2", "", { "dependencies": { "graceful-fs": "^4.1.2" } }, "sha512-6i/00NBjP4yGPs+caKSyRfpTF/8Torsu0MOW3mMzIbhgISFder8i7xbqgHlLMwJrdiN8ndBV3UA1/AfzPSr+jg=="],
"wcwidth": ["wcwidth@1.0.1", "", { "dependencies": { "defaults": "^1.0.3" } }, "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg=="],
"web-ext": ["web-ext@10.5.0", "", { "dependencies": { "@babel/runtime": "8.0.0", "@devicefarmer/adbkit": "3.3.8", "addons-linter": "10.8.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.0", "fx-runner": "1.5.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" } }, "sha512-tveUHhZHu5A2Qrs7u+hbh2S+7ZPuKVH/ILzqkRwpdivFOnVmgPhDLtmtGNKT3a8N9PZbW5uP6INe6Byj5qePVQ=="],
"web-ext-run": ["web-ext-run@0.2.4", "", { "dependencies": { "@babel/runtime": "7.28.2", "@devicefarmer/adbkit": "3.3.8", "chrome-launcher": "1.2.0", "debounce": "1.2.1", "es6-error": "4.1.1", "firefox-profile": "4.7.0", "fx-runner": "1.4.0", "multimatch": "6.0.0", "node-notifier": "10.0.1", "parse-json": "7.1.1", "pino": "9.7.0", "promise-toolbox": "0.21.0", "set-value": "4.1.0", "source-map-support": "0.5.21", "strip-bom": "5.0.0", "strip-json-comments": "5.0.2", "tmp": "0.2.5", "update-notifier": "7.3.1", "watchpack": "2.4.4", "zip-dir": "2.0.0" } }, "sha512-rQicL7OwuqWdQWI33JkSXKcp7cuv1mJG8u3jRQwx/8aDsmhbTHs9ZRmNYOL+LX0wX8edIEQX8jj4bB60GoXtKA=="],
@@ -2442,6 +2500,8 @@
"webpack-virtual-modules": ["webpack-virtual-modules@0.6.2", "", {}, "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ=="],
"whatwg-encoding": ["whatwg-encoding@3.1.1", "", { "dependencies": { "iconv-lite": "0.6.3" } }, "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ=="],
"whatwg-mimetype": ["whatwg-mimetype@3.0.0", "", {}, "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q=="],
"when": ["when@3.7.7", "", {}, "sha512-9lFZp/KHoqH6bPKjbWqa+3Dg/K/r2v0X/3/G2x4DBGchVS2QX2VXL3cZV994WQVnTM1/PD71Az25nAzryEUugw=="],
@@ -2496,8 +2556,6 @@
"zip-dir": ["zip-dir@2.0.0", "", { "dependencies": { "async": "^3.2.0", "jszip": "^3.2.2" } }, "sha512-uhlsJZWz26FLYXOD6WVuq+fIcZ3aBPGo/cFdiLlv3KNwpa52IF3ISV8fLhQLiqVu5No3VhlqlgthN6gehil1Dg=="],
"zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
"zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="],
"@1natsu/wait-element/defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="],
@@ -2538,12 +2596,28 @@
"@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
"@eslint/eslintrc/espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="],
"@eslint/eslintrc/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
"@eslint/eslintrc/js-yaml": ["js-yaml@4.3.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q=="],
"@eslint/eslintrc/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="],
"@eslint/eslintrc/strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="],
"@oxc-parser/binding-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.4", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow=="],
"@parcel/watcher/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
"@pnpm/network.ca-file/graceful-fs": ["graceful-fs@4.2.10", "", {}, "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="],
"@types/prompts/@types/node": ["@types/node@20.19.33", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-Rs1bVAIdBs5gbTIKza/tgpMuG1k3U/UMJLWecIMxNdJFDMzcM5LOiLVRYh3PilWEYDIeUDv7bpiHPLPsbydGcw=="],
"@types/ws/@types/node": ["@types/node@20.19.33", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-Rs1bVAIdBs5gbTIKza/tgpMuG1k3U/UMJLWecIMxNdJFDMzcM5LOiLVRYh3PilWEYDIeUDv7bpiHPLPsbydGcw=="],
"@types/yauzl/@types/node": ["@types/node@20.19.33", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-Rs1bVAIdBs5gbTIKza/tgpMuG1k3U/UMJLWecIMxNdJFDMzcM5LOiLVRYh3PilWEYDIeUDv7bpiHPLPsbydGcw=="],
"@unocss/cli/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
"@unocss/vite/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
@@ -2604,6 +2678,16 @@
"@wxt-dev/unocss/tinyglobby": ["tinyglobby@0.2.17", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g=="],
"addons-linter/ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="],
"addons-linter/eslint": ["eslint@9.39.4", "", { "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" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ=="],
"addons-linter/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
"addons-linter/yauzl": ["yauzl@3.4.0", "", { "dependencies": { "pend": "~1.2.0" } }, "sha512-jIH9yLR9wqr0wOS0TpBvo/g/2UgZH5qePVbjgRliiF0BYvOZyaBknKsF+x9Iht0O6sqgnB93rCICdOZFecJuDw=="],
"addons-scanner-utils/yauzl": ["yauzl@3.4.0", "", { "dependencies": { "pend": "~1.2.0" } }, "sha512-jIH9yLR9wqr0wOS0TpBvo/g/2UgZH5qePVbjgRliiF0BYvOZyaBknKsF+x9Iht0O6sqgnB93rCICdOZFecJuDw=="],
"ansi-align/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
"ast-kit/@babel/parser": ["@babel/parser@8.0.0-rc.1", "", { "dependencies": { "@babel/types": "^8.0.0-rc.1" }, "bin": "./bin/babel-parser.js" }, "sha512-6HyyU5l1yK/7h9Ki52i5h6mDAx4qJdiLQO4FdCyJNoB/gy3T3GGJdhQzzbZgvgZCugYBvwtQiWRt94QKedHnkA=="],
@@ -2614,30 +2698,24 @@
"boxen/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
"boxen/type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="],
"bun-types/@types/node": ["@types/node@20.19.33", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-Rs1bVAIdBs5gbTIKza/tgpMuG1k3U/UMJLWecIMxNdJFDMzcM5LOiLVRYh3PilWEYDIeUDv7bpiHPLPsbydGcw=="],
"c12/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
"changelogen/c12": ["c12@3.3.3", "", { "dependencies": { "chokidar": "^5.0.0", "confbox": "^0.2.2", "defu": "^6.1.4", "dotenv": "^17.2.3", "exsolve": "^1.0.8", "giget": "^2.0.0", "jiti": "^2.6.1", "ohash": "^2.0.11", "pathe": "^2.0.3", "perfect-debounce": "^2.0.0", "pkg-types": "^2.3.0", "rc9": "^2.1.2" }, "peerDependencies": { "magicast": "*" }, "optionalPeers": ["magicast"] }, "sha512-750hTRvgBy5kcMNPdh95Qo+XUBeGo8C7nsKSmedDmaQI+E0r82DwHeM6vBewDe4rGFbnxoa4V9pw+sPh5+Iz8Q=="],
"cheerio/whatwg-mimetype": ["whatwg-mimetype@4.0.0", "", {}, "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg=="],
"changelogen/open": ["open@10.2.0", "", { "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "wsl-utils": "^0.1.0" } }, "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA=="],
"changelogen/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
"changelogen/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
"changelogen/std-env": ["std-env@3.10.0", "", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="],
"chrome-launcher/@types/node": ["@types/node@20.19.33", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-Rs1bVAIdBs5gbTIKza/tgpMuG1k3U/UMJLWecIMxNdJFDMzcM5LOiLVRYh3PilWEYDIeUDv7bpiHPLPsbydGcw=="],
"chrome-launcher/is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "^2.0.0" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="],
"cli-truncate/string-width": ["string-width@8.1.1", "", { "dependencies": { "get-east-asian-width": "^1.3.0", "strip-ansi": "^7.1.0" } }, "sha512-KpqHIdDL9KwYk22wEOg/VIqYbrnLeSApsKT/bSj6Ez7pn3CftUiLAv2Lccpq1ALcpLV9UX1Ppn92npZWu2w/aw=="],
"cliui/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
"cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
"cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
"columnify/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
"config-chain/ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="],
"copy-anything/is-what": ["is-what@5.5.0", "", {}, "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw=="],
@@ -2650,10 +2728,6 @@
"dom-serializer/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
"dot-prop/type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="],
"dotenv-expand/dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="],
"eslint/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
"espree/acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="],
@@ -2662,14 +2736,16 @@
"flat-cache/flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="],
"fx-runner/commander": ["commander@2.9.0", "", { "dependencies": { "graceful-readlink": ">= 1.0.0" } }, "sha512-bmkUukX8wAOjHdN26xj5c4ctEV22TQ7dQYhSmuckKhToXrkUn0iIaolHdIxYYqD55nhpSPA9zPQ1yP57GdXP2A=="],
"fx-runner/commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="],
"fx-runner/which": ["which@1.2.4", "", { "dependencies": { "is-absolute": "^0.1.7", "isexe": "^1.1.1" }, "bin": { "which": "./bin/which" } }, "sha512-zDRAqDSBudazdfM9zpiI30Fu9ve47htYXcGi3ln0wfKu2a7SmrT6F3VDoYONu//48V8Vz4TdCRNPjtvyRO3yBA=="],
"fx-runner/which": ["which@4.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg=="],
"global-directory/ini": ["ini@6.0.0", "", {}, "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ=="],
"gray-matter/js-yaml": ["js-yaml@3.14.2", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg=="],
"happy-dom/@types/node": ["@types/node@20.19.33", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-Rs1bVAIdBs5gbTIKza/tgpMuG1k3U/UMJLWecIMxNdJFDMzcM5LOiLVRYh3PilWEYDIeUDv7bpiHPLPsbydGcw=="],
"import-fresh/parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="],
"import-fresh/resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="],
@@ -2724,14 +2800,10 @@
"publish-browser-extension/cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="],
"publish-browser-extension/dotenv": ["dotenv@17.2.4", "", {}, "sha512-mudtfb4zRB4bVvdj0xRo+e6duH1csJRM8IukBqfTRvHotn9+LBXB8ynAidP9zHqoRC/fsllXgk4kCKlR21fIhw=="],
"rc/ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="],
"rc/strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="],
"restore-cursor/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
"rolldown/@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.12", "", {}, "sha512-HHMwmarRKvoFsJorqYlFeFRzXZqCt2ETQlEDOb9aqssrnVBB1/+xgTGtuTrIk5vzLNX1MjMtTf7W9z3tsSbrxw=="],
"rolldown-plugin-dts/@babel/parser": ["@babel/parser@8.0.0-rc.3", "", { "dependencies": { "@babel/types": "^8.0.0-rc.3" }, "bin": "./bin/babel-parser.js" }, "sha512-B20dvP3MfNc/XS5KKCHy/oyWl5IA6Cn9YjXRdDlCjNmUFrjvLXMNUfQq/QUy9fnG2gYkKKcrto2YaF9B32ToOQ=="],
@@ -2746,14 +2818,14 @@
"sharp/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
"slice-ansi/is-fullwidth-code-point": ["is-fullwidth-code-point@5.1.0", "", { "dependencies": { "get-east-asian-width": "^1.3.1" } }, "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ=="],
"solid-refresh/@babel/generator": ["@babel/generator@7.29.1", "", { "dependencies": { "@babel/parser": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw=="],
"source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
"strip-literal/js-tokens": ["js-tokens@9.0.1", "", {}, "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ=="],
"thread-stream/real-require": ["real-require@1.0.0", "", {}, "sha512-P4nbQYQfePJxRSmY+v/KINxVucm4NF3p3s7pJveMTtom52FR4YGltUQLB8idDXwDDWW+eYrWDFbuzUnjoWHF7g=="],
"tsdown/defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="],
"tsdown/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
@@ -2784,10 +2856,6 @@
"vite/tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
"vite-node/cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="],
"vite-node/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
"vitepress/@vitejs/plugin-vue": ["@vitejs/plugin-vue@5.2.4", "", { "peerDependencies": { "vite": "^5.0.0 || ^6.0.0", "vue": "^3.2.25" } }, "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA=="],
"vitepress/shiki": ["shiki@2.5.0", "", { "dependencies": { "@shikijs/core": "2.5.0", "@shikijs/engine-javascript": "2.5.0", "@shikijs/engine-oniguruma": "2.5.0", "@shikijs/langs": "2.5.0", "@shikijs/themes": "2.5.0", "@shikijs/types": "2.5.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-mI//trrsaiCIPsja5CNfsyNOqgAZUb6VpJA+340toL42UpzQlXpwRV9nch69X6gaUxrr9kaOOa6e3y3uAkGFxQ=="],
@@ -2808,12 +2876,30 @@
"vue/@vue/shared": ["@vue/shared@3.5.34", "", {}, "sha512-24uqU4OIiX29ryC3MeWid/Xf2fa2EFRUVLb77nRhk+UrTVrh/XiGtFAFmJBAtBRbjwNdsPRP+jj/OL27Eg1NDA=="],
"web-ext-run/@babel/runtime": ["@babel/runtime@7.28.2", "", {}, "sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA=="],
"web-ext-run/fx-runner": ["fx-runner@1.4.0", "", { "dependencies": { "commander": "2.9.0", "shell-quote": "1.7.3", "spawn-sync": "1.0.15", "when": "3.7.7", "which": "1.2.4", "winreg": "0.0.12" }, "bin": { "fx-runner": "bin/fx-runner" } }, "sha512-rci1g6U0rdTg6bAaBboP7XdRu01dzTAaKXxFf+PUqGuCv6Xu7o8NZdY1D5MvKGIjb6EdS1g3VlXOgksir1uGkg=="],
"web-ext-run/parse-json": ["parse-json@7.1.1", "", { "dependencies": { "@babel/code-frame": "^7.21.4", "error-ex": "^1.3.2", "json-parse-even-better-errors": "^3.0.0", "lines-and-columns": "^2.0.3", "type-fest": "^3.8.0" } }, "sha512-SgOTCX/EZXtZxBE5eJ97P4yGM5n37BwRU+YMsH4vNzFqJV/oWFXXCmwFlgWUM4PrakybVOueJJ6pwHqSVhTFDw=="],
"web-ext-run/pino": ["pino@9.7.0", "", { "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.1.1", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.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": "^3.0.0" }, "bin": { "pino": "bin.js" } }, "sha512-vnMCM6xZTb1WDmLvtG2lE/2p+t9hDEIvTWJsu6FejkE62vB7gDhvzrpFR4Cw2to+9JNQxVnkAKVPA1KPB98vWg=="],
"web-ext-run/strip-json-comments": ["strip-json-comments@5.0.2", "", {}, "sha512-4X2FR3UwhNUE9G49aIsJW5hRRR3GXGTBTZRMfv568O60ojM8HcWjV/VxAxCDW3SUND33O6ZY66ZuRcdkj73q2g=="],
"web-ext-run/tmp": ["tmp@0.2.5", "", {}, "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow=="],
"web-ext-run/watchpack": ["watchpack@2.4.4", "", { "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" } }, "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA=="],
"widest-line/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
"wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="],
"wrap-ansi/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
"wsl-utils/is-wsl": ["is-wsl@3.1.0", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw=="],
"wxt/@webext-core/fake-browser": ["@webext-core/fake-browser@2.0.1", "", { "dependencies": { "@wxt-dev/browser": "*", "lodash.merge": "^4.6.2" } }, "sha512-4x5z1z8F0KU8ShF4ForXJ8qnA8oZTy7HYjI91Mbpdzp3H3hU9HR6TNPUxfWtSpFz2FwgEircuJKQg0qFIn6RLg=="],
"wxt/tinyglobby": ["tinyglobby@0.2.17", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g=="],
"yargs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
@@ -2824,6 +2910,12 @@
"@babel/generator/@babel/types/@babel/helper-string-parser": ["@babel/helper-string-parser@8.0.0-rc.3", "", {}, "sha512-AmwWFx1m8G/a5cXkxLxTiWl+YEoWuoFLUCwqMlNuWO1tqAYITQAbCRPUkyBHv1VOFgfjVOqEj6L3u15J5ZCzTA=="],
"@eslint/eslintrc/espree/acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="],
"@eslint/eslintrc/espree/eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="],
"@eslint/eslintrc/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
"@vueuse/core/vue/@vue/compiler-dom": ["@vue/compiler-dom@3.5.28", "", { "dependencies": { "@vue/compiler-core": "3.5.28", "@vue/shared": "3.5.28" } }, "sha512-/1ZepxAb159jKR1btkefDP+J2xuWL5V3WtleRmxaT+K2Aqiek/Ab/+Ebrw2pPj0sdHO8ViAyyJWfhXXOP/+LQA=="],
"@vueuse/core/vue/@vue/compiler-sfc": ["@vue/compiler-sfc@3.5.28", "", { "dependencies": { "@babel/parser": "^7.29.0", "@vue/compiler-core": "3.5.28", "@vue/compiler-dom": "3.5.28", "@vue/compiler-ssr": "3.5.28", "@vue/shared": "3.5.28", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", "postcss": "^8.5.6", "source-map-js": "^1.2.1" } }, "sha512-6TnKMiNkd6u6VeVDhZn/07KhEZuBSn43Wd2No5zaP5s3xm8IqFTHBj84HJah4UepSUJTro5SoqqlOY22FKY96g=="],
@@ -2848,6 +2940,30 @@
"@vueuse/shared/vue/@vue/server-renderer": ["@vue/server-renderer@3.5.28", "", { "dependencies": { "@vue/compiler-ssr": "3.5.28", "@vue/shared": "3.5.28" }, "peerDependencies": { "vue": "3.5.28" } }, "sha512-pf+5ECKGj8fX95bNincbzJ6yp6nyzuLDhYZCeFxUNp8EBrQpPpQaLX3nNCp49+UbgbPun3CeVE+5CXVV1Xydfg=="],
"addons-linter/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
"addons-linter/eslint/@eslint/config-array": ["@eslint/config-array@0.21.2", "", { "dependencies": { "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", "minimatch": "^3.1.5" } }, "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw=="],
"addons-linter/eslint/@eslint/config-helpers": ["@eslint/config-helpers@0.4.2", "", { "dependencies": { "@eslint/core": "^0.17.0" } }, "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw=="],
"addons-linter/eslint/@eslint/core": ["@eslint/core@0.17.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ=="],
"addons-linter/eslint/@eslint/plugin-kit": ["@eslint/plugin-kit@0.4.1", "", { "dependencies": { "@eslint/core": "^0.17.0", "levn": "^0.4.1" } }, "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA=="],
"addons-linter/eslint/ajv": ["ajv@6.14.0", "", { "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" } }, "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw=="],
"addons-linter/eslint/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
"addons-linter/eslint/eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="],
"addons-linter/eslint/eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="],
"addons-linter/eslint/espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="],
"addons-linter/eslint/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
"addons-linter/eslint/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="],
"ansi-align/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
"ast-kit/@babel/parser/@babel/types": ["@babel/types@8.0.0-rc.1", "", { "dependencies": { "@babel/helper-string-parser": "^8.0.0-rc.1", "@babel/helper-validator-identifier": "^8.0.0-rc.1" } }, "sha512-ubmJ6TShyaD69VE9DQrlXcdkvJbmwWPB8qYj0H2kaJi29O7vJT9ajSdBd2W8CG34pwL9pYA74fi7RHC1qbLoVQ=="],
@@ -2856,25 +2972,13 @@
"boxen/string-width/get-east-asian-width": ["get-east-asian-width@1.4.0", "", {}, "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q=="],
"changelogen/c12/defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="],
"changelogen/c12/dotenv": ["dotenv@17.2.4", "", {}, "sha512-mudtfb4zRB4bVvdj0xRo+e6duH1csJRM8IukBqfTRvHotn9+LBXB8ynAidP9zHqoRC/fsllXgk4kCKlR21fIhw=="],
"changelogen/c12/giget": ["giget@2.0.0", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "defu": "^6.1.4", "node-fetch-native": "^1.6.6", "nypm": "^0.6.0", "pathe": "^2.0.3" }, "bin": { "giget": "dist/cli.mjs" } }, "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA=="],
"changelogen/c12/rc9": ["rc9@2.1.2", "", { "dependencies": { "defu": "^6.1.4", "destr": "^2.0.3" } }, "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg=="],
"changelogen/open/wsl-utils": ["wsl-utils@0.1.0", "", { "dependencies": { "is-wsl": "^3.1.0" } }, "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw=="],
"cli-truncate/string-width/get-east-asian-width": ["get-east-asian-width@1.4.0", "", {}, "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q=="],
"cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
"cliui/wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
"columnify/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
"cspell/tinyglobby/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
"fx-runner/which/isexe": ["isexe@1.1.2", "", {}, "sha512-d2eJzK691yZwPHcv1LbeAOa91yMJ9QmfTgSO1oXB65ezVhXQsxBac2vEB4bMVms9cGzaA99n6V2viHMq82VLDw=="],
"fx-runner/which/isexe": ["isexe@3.1.5", "", {}, "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w=="],
"gray-matter/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="],
@@ -2888,8 +2992,6 @@
"sass/chokidar/readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
"slice-ansi/is-fullwidth-code-point/get-east-asian-width": ["get-east-asian-width@1.4.0", "", {}, "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q=="],
"tsdown/tinyglobby/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
"typedoc/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
@@ -2908,6 +3010,18 @@
"vitepress/vue/@vue/server-renderer": ["@vue/server-renderer@3.5.28", "", { "dependencies": { "@vue/compiler-ssr": "3.5.28", "@vue/shared": "3.5.28" }, "peerDependencies": { "vue": "3.5.28" } }, "sha512-pf+5ECKGj8fX95bNincbzJ6yp6nyzuLDhYZCeFxUNp8EBrQpPpQaLX3nNCp49+UbgbPun3CeVE+5CXVV1Xydfg=="],
"web-ext-run/fx-runner/commander": ["commander@2.9.0", "", { "dependencies": { "graceful-readlink": ">= 1.0.0" } }, "sha512-bmkUukX8wAOjHdN26xj5c4ctEV22TQ7dQYhSmuckKhToXrkUn0iIaolHdIxYYqD55nhpSPA9zPQ1yP57GdXP2A=="],
"web-ext-run/fx-runner/shell-quote": ["shell-quote@1.7.3", "", {}, "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw=="],
"web-ext-run/fx-runner/which": ["which@1.2.4", "", { "dependencies": { "is-absolute": "^0.1.7", "isexe": "^1.1.1" }, "bin": { "which": "./bin/which" } }, "sha512-zDRAqDSBudazdfM9zpiI30Fu9ve47htYXcGi3ln0wfKu2a7SmrT6F3VDoYONu//48V8Vz4TdCRNPjtvyRO3yBA=="],
"web-ext-run/parse-json/type-fest": ["type-fest@3.13.1", "", {}, "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g=="],
"web-ext-run/pino/pino-abstract-transport": ["pino-abstract-transport@2.0.0", "", { "dependencies": { "split2": "^4.0.0" } }, "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw=="],
"web-ext-run/pino/thread-stream": ["thread-stream@3.1.0", "", { "dependencies": { "real-require": "^0.2.0" } }, "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A=="],
"widest-line/string-width/emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="],
"widest-line/string-width/get-east-asian-width": ["get-east-asian-width@1.4.0", "", {}, "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q=="],
@@ -2918,6 +3032,8 @@
"yargs/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
"@eslint/eslintrc/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
"@vueuse/core/vue/@vue/compiler-dom/@vue/compiler-core": ["@vue/compiler-core@3.5.28", "", { "dependencies": { "@babel/parser": "^7.29.0", "@vue/shared": "3.5.28", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-kviccYxTgoE8n6OCw96BNdYlBg2GOWfBuOW4Vqwrt7mSKWKwFVvI8egdTltqRgITGPsTFYtKYfxIG8ptX2PJHQ=="],
"@vueuse/core/vue/@vue/compiler-sfc/@vue/compiler-core": ["@vue/compiler-core@3.5.28", "", { "dependencies": { "@babel/parser": "^7.29.0", "@vue/shared": "3.5.28", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-kviccYxTgoE8n6OCw96BNdYlBg2GOWfBuOW4Vqwrt7mSKWKwFVvI8egdTltqRgITGPsTFYtKYfxIG8ptX2PJHQ=="],
@@ -2960,16 +3076,18 @@
"@vueuse/shared/vue/@vue/server-renderer/@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.28", "", { "dependencies": { "@vue/compiler-dom": "3.5.28", "@vue/shared": "3.5.28" } }, "sha512-JCq//9w1qmC6UGLWJX7RXzrGpKkroubey/ZFqTpvEIDJEKGgntuDMqkuWiZvzTzTA5h2qZvFBFHY7fAAa9475g=="],
"addons-linter/eslint/@eslint/config-array/@eslint/object-schema": ["@eslint/object-schema@2.1.7", "", {}, "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA=="],
"addons-linter/eslint/espree/acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="],
"addons-linter/eslint/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
"ansi-align/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
"ast-kit/@babel/parser/@babel/types/@babel/helper-string-parser": ["@babel/helper-string-parser@8.0.0-rc.1", "", {}, "sha512-vi/pfmbrOtQmqgfboaBhaCU50G7mcySVu69VU8z+lYoPPB6WzI9VgV7WQfL908M4oeSH5fDkmoupIqoE0SdApw=="],
"ast-kit/@babel/parser/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@8.0.0-rc.1", "", {}, "sha512-I4YnARytXC2RzkLNVnf5qFNFMzp679qZpmtw/V3Jt2uGnWiIxyJtaukjG7R8pSx8nG2NamICpGfljQsogj+FbQ=="],
"changelogen/c12/giget/citty": ["citty@0.1.6", "", { "dependencies": { "consola": "^3.2.3" } }, "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ=="],
"changelogen/open/wsl-utils/is-wsl": ["is-wsl@3.1.0", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw=="],
"multimatch/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
"typedoc/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
@@ -3034,6 +3152,8 @@
"vitepress/vue/@vue/server-renderer/@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.28", "", { "dependencies": { "@vue/compiler-dom": "3.5.28", "@vue/shared": "3.5.28" } }, "sha512-JCq//9w1qmC6UGLWJX7RXzrGpKkroubey/ZFqTpvEIDJEKGgntuDMqkuWiZvzTzTA5h2qZvFBFHY7fAAa9475g=="],
"web-ext-run/fx-runner/which/isexe": ["isexe@1.1.2", "", {}, "sha512-d2eJzK691yZwPHcv1LbeAOa91yMJ9QmfTgSO1oXB65ezVhXQsxBac2vEB4bMVms9cGzaA99n6V2viHMq82VLDw=="],
"yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
"@vueuse/core/vue/@vue/compiler-dom/@vue/compiler-core/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
@@ -3042,6 +3162,8 @@
"@vueuse/shared/vue/@vue/compiler-dom/@vue/compiler-core/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
"addons-linter/eslint/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
"vitepress/vue/@vue/compiler-dom/@vue/compiler-core/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
}
}
+3
View File
@@ -19,6 +19,7 @@ words:
- automount
- avenir
- bidi
- blocklists
- buildc
- bunx
- cachable
@@ -29,6 +30,7 @@ words:
- comctx
- confbox
- configfile
- consola
- consolas
- Cpath
- crbug
@@ -89,6 +91,7 @@ words:
- pbbf
- personaltoolbar
- portaling
- posthog
- prebundled
- prefs
- proxified
+4
View File
@@ -81,3 +81,7 @@ body {
.item {
z-index: 1;
}
.VPSidebar .curtain {
z-index: 2;
}
+13
View File
@@ -401,6 +401,7 @@
- # Teams Chat Exporter
chromeId: jmghclbfbbapimhbgnpffbimphlpolnm
firefoxSlug: teams-chat-exporter
edgeId: phlomfiieaggnbfpacmjmidcjdlaiplp
- # Lofi BGM Player - Free lofi focus music for work & study
chromeId: jdcppdokgfbnhiacbeplahgnciahnhck
@@ -518,3 +519,15 @@
- # Leetcode Enhancer
chromeId: cpoclfijojgjiafnlgnhjalkaiabcjch
- # Adaptive Tab Bar Colour
firefoxSlug: adaptive-tab-bar-colour
- #ArcPort - Tab Checkpoint
chromeId: kajmnfhpmkimleehomeioondgfcjjnbp
- #ArcPort - Tab Rebrand
chromeId: pgmohcikgaeddapienpncpbiklbmfkgp
- #MindSnap
chromeId: mdcpckfcphpicfpiopfcpeambjknjabl
Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

After

Width:  |  Height:  |  Size: 138 KiB

+4 -4
View File
@@ -43,7 +43,7 @@ ESLint doesn't know about the auto-imported variables unless they are explicitly
:::code-group
```ts [ESLint 9]
```ts [ESLint >=9]
export default defineConfig({
imports: {
eslintrc: {
@@ -53,7 +53,7 @@ export default defineConfig({
});
```
```ts [ESLint 8]
```ts [ESLint <=8]
export default defineConfig({
imports: {
eslintrc: {
@@ -69,7 +69,7 @@ Then in your ESLint config, import and use the generated file:
:::code-group
```js [ESLint 9]
```js [ESLint >=9]
// eslint.config.mjs
import autoImports from './.wxt/eslint-auto-imports.mjs';
@@ -81,7 +81,7 @@ export default [
];
```
```js [ESLint 8]
```js [ESLint <=8]
// .eslintrc.mjs
export default {
extends: ['./.wxt/eslintrc-auto-import.json'],
@@ -4,11 +4,17 @@ outline: deep
# Browser Startup
During development, WXT will use any of the below packages to automatically open a browser with your extension installed.
- [`web-ext` by Mozilla](https://www.npmjs.com/package/web-ext)
Just install the dependency you want WXT to use to open the browser.
## `web-ext` Usage
> See the [API Reference](/api/reference/wxt/interfaces/WebExtConfig) for a full list of config.
During development, WXT uses [`web-ext` by Mozilla](https://www.npmjs.com/package/web-ext) to automatically open a browser window with your extension installed.
## Config Files
### Config Files
You can configure browser startup in 3 places:
@@ -25,9 +31,9 @@ You can configure browser startup in 3 places:
2. `<rootDir>/wxt.config.ts`: Via the [`webExt` config](/api/reference/wxt/interfaces/InlineConfig#webext), included in version control
3. `$HOME/web-ext.config.ts`: Provide default values for all WXT projects on your computer
## Recipes
### Recipes
### Set Browser Binaries
#### Set Browser Binaries
To set or customize the browser opened during development:
@@ -57,7 +63,7 @@ export default defineConfig({
By default, WXT will try to automatically discover where Chrome/Firefox are installed. However, if you have chrome installed in a non-standard location, you need to set it manually as shown above.
### Persist Data
#### Persist Data
By default, to keep from modifying your browser's existing profiles, `web-ext` creates a brand new profile every time you run the `dev` script.
@@ -94,9 +100,9 @@ Now, next time you run the `dev` script, a persistent profile will be created in
You can use any directory you'd like for `--user-data-dir`, the examples above create a persistent profile for each WXT project. To create a profile for all WXT projects, you can put the `chrome-data` directory inside your user's home directory.
:::
### Disable Opening Browser
#### Disable Opening Browser
If you prefer to load the extension into your browser manually, you can disable the auto-open behavior:
If you don't want to uninstall `web-ext`, like to test in your normal profile, you can do so via `disabled: true`:
```ts [web-ext.config.ts]
import { defineWebExtConfig } from 'wxt';
+32 -35
View File
@@ -76,27 +76,33 @@ Alternatively, if you're trying to use similar APIs under different names (to su
});
```
### Augmenting the Browser Type
## Add Firefox Types
WXT's `browser` types are based on the `@types/chrome` package. That means some Firefox-specific APIs may not be typed, like `browser.sidebarAction`. If you want to add types for these APIs, you can augment the browser type to add them yourself:
WXT's `browser` types are based on the `@types/chrome` package. That means some Firefox-specific APIs may not be typed, like `browser.sidebarAction`. If you want to add types for these APIs, you can augment the browser type by:
```ts
// <srcDir>/browser-types.d.ts
import '@wxt-dev/browser';
import type { SidebarAction } from 'webextension-polyfill';
1. Installing `@wxt-dev/browser` as a direct dependency
declare module '@wxt-dev/browser' {
namespace Browser {
export const sidebarAction: SidebarAction.Static;
}
}
```
```sh
pnpm add @wxt-dev/browser
```
> For this to work, you may need to install `@wxt-dev/browser` as a direct dependency.
>
> ```sh
> pnpm add @wxt-dev/browser
> ```
2. Augmenting the `Browser` type:
```ts
// <srcDir>/browser-types.d.ts
import '@wxt-dev/browser';
import type { SidebarAction } from 'webextension-polyfill';
declare module '@wxt-dev/browser' {
namespace Browser {
export const sidebarAction: SidebarAction.Static;
}
}
```
You can add types from any source: `webextension-polyfill`, `@types/firefox-webext-browser`, or your own custom types.
See TypeScript's documentation on [declaration merging](https://www.typescriptlang.org/docs/handbook/declaration-merging.html) for more information.
## Entrypoint Limitations
@@ -116,41 +122,32 @@ The fix is simple, just move your API usage into the entrypoint's main function:
:::code-group
<!-- prettier-ignore -->
```ts [background.ts]
browser.action.onClicked.addListener(() => {
/* ... */
}); // [!code --]
browser.action.onClicked.addListener(() => { /* ... */ }); // [!code --]
export default defineBackground(() => {
browser.action.onClicked.addListener(() => {
/* ... */
}); // [!code ++]
browser.action.onClicked.addListener(() => { /* ... */ }); // [!code ++]
});
```
<!-- prettier-ignore -->
```ts [content.ts]
browser.runtime.onMessage.addListener(() => {
/* ... */
}); // [!code --]
browser.runtime.onMessage.addListener(() => { /* ... */ }); // [!code --]
export default defineContentScript({
main() {
browser.runtime.onMessage.addListener(() => {
/* ... */
}); // [!code ++]
browser.runtime.onMessage.addListener(() => { /* ... */ }); // [!code ++]
},
});
```
<!-- prettier-ignore -->
```ts [unlisted.ts]
browser.runtime.onMessage.addListener(() => {
/* ... */
}); // [!code --]
browser.runtime.onMessage.addListener(() => { /* ... */ }); // [!code --]
export default defineUnlistedScript(() => {
browser.runtime.onMessage.addListener(() => {
/* ... */
}); // [!code ++]
browser.runtime.onMessage.addListener(() => { /* ... */ }); // [!code ++]
});
```
-31
View File
@@ -1,31 +0,0 @@
# Remote Code
WXT will automatically download and bundle imports with the `url:` prefix so the extension does not depend on remote code, [a requirement from Google for MV3](https://developer.chrome.com/docs/extensions/migrating/improve-security/#remove-remote-code).
## Google Analytics
For example, you can import Google Analytics:
```ts
// utils/google-analytics.ts
import 'url:https://www.googletagmanager.com/gtag/js?id=G-XXXXXX';
window.dataLayer = window.dataLayer || [];
// NOTE: This line is different from Google's documentation
window.gtag = function () {
dataLayer.push(arguments);
};
gtag('js', new Date());
gtag('config', 'G-XXXXXX');
```
Then you can import this in your HTML files to enable Google Analytics:
```ts
// popup/main.ts
import '~/utils/google-analytics';
gtag('event', 'event_name', {
key: 'value',
});
```
-1
View File
@@ -21,7 +21,6 @@ This plugin does several things:
- Polyfills the extension API, `browser`, with an in-memory implementation using [`@webext-core/fake-browser`](https://webext-core.aklinker1.io/fake-browser/installation)
- Adds all vite config or plugins in `wxt.config.ts`
- Configures auto-imports (if enabled)
- Applies internal WXT vite plugins for things like [bundling remote code](/guide/essentials/remote-code)
- Sets up global variables provided by WXT (`import.meta.env.BROWSER`, `import.meta.env.MANIFEST_VERSION`, `import.meta.env.IS_CHROME`, etc)
- Configures aliases (`@/*`, `@@/*`, etc) so imports can be resolved
-1
View File
@@ -24,7 +24,6 @@ Lets compare the features of WXT vs [Plasmo](https://docs.plasmo.com/framework)
| Supports all frontend frameworks | ✅ | 🟡 [^c] | ✅ |
| Framework specific entrypoints (like `Popup.tsx`) | 🟡 [^d] | ✅ [^e] | ❌ |
| Automated publishing | ✅ | ✅ | ❌ |
| Remote Code Bundling (Google Analytics) | ✅ | ✅ | ❌ |
| Unlisted HTML Pages | ✅ | ✅ | ✅ |
| Unlisted Scripts | ✅ | ❌ | ❌ |
| ESM Content Scripts | ❌ [^l] | ❌ | ✅ |
+1 -1
View File
@@ -51,7 +51,7 @@ Here's specific steps for other popular frameworks/build tools.
3. Move public `assets/*` into the `public/` directory
4. If you use CSUI, migrate to WXT's `createContentScriptUi`
5. Convert Plasmo's custom import resolutions to Vite's
6. If importing remote code via a URL, add a `url:` prefix so it works with WXT
6. Importing remote code via a URL is not supported in WXT, see [this issue](https://github.com/wxt-dev/wxt/issues/2262) for alternatives
7. Replace your [Plasmo tags](https://docs.plasmo.com/framework/workflows/build#with-a-custom-tag) (`--tag`) with [WXT build modes](/guide/essentials/config/build-mode) (`--mode`)
8. ⚠️ Compare the old production manifest to `.output/*/manifest.json`. They should have the same content as before. If not, tweak your entrypoints and config until they are the same.
+337 -1
View File
@@ -15,7 +15,7 @@ To upgrade WXT to the latest major version:
```
2. Follow the upgrade steps below to fix any breaking changes.
3. Run `wxt prepare`. It should succeed and type errors will go away afterwords.
3. Run `wxt prepare`. It should succeed and type errors will go away afterwards.
```sh
pnpm wxt prepare
@@ -35,6 +35,342 @@ Listed below are all the breaking changes you should address when upgrading to a
Currently, WXT is in pre-release. This means changes to the second digit, `v0.X`, are considered major and have breaking changes. Once v1 is released, only major version bumps will have breaking changes.
## v0.20.0 &rarr; v0.21.0
This release focuses on trimming WXT's install footprint and simplifying project configuration.
:::tip
Read through all the changes once before updating your code.
:::
### Install Footprint
When installing `wxt` v0.20, it downloaded 98 MB and 366 packages to your `node_modules`. v0.21 cuts this down to 64 MB / 320 packages - that's 65.3% the previous size! This is a good improvement, but frankly, not good enough. Why?
- `wxt init` is slow for new developers trying it out
- Less exposure to supply chain attacks
- More compute and storage used by servers hosting the package and clients downloading it degrades hardware and shortens their life-cycle
If you want to explore WXT's dependencies and why it's so large, here's a few links:
- <https://pkg-size.dev/wxt>
- <https://npmgraph.js.org/?q=wxt@0.21.0>
- <https://node-modules.dev/grid/depth#install=wxt@0.21.0>
We'll continue working on minimizing WXT's install footprint.
### Minimum Node.js, Vite, and TypeScript Versions
| Tool | Old requirement | New requirement |
| ---------- | --------------------------------- | ---------------------------------- |
| Node.js | `>=20.12.0` | `>=22` |
| Vite | `^5.4.19 \|\| ^6.3.4 \|\| ^7.0.0` | `^6.3.4 \|\| ^7.0.0 \|\| ^8.0.0-0` |
| TypeScript | Not enforced | `>=5.4` |
Vite 5 support was dropped as part of moving WXT's dev server off `vite-node` and onto Vite's native `ModuleRunner`/Environment API, which requires Vite &ge;6.3.4.
### `vite`, `web-ext`, and `typescript` Are Now Peer Dependencies
Previously, WXT installed its own copies of `vite` and `web-ext` for you (you never had to add them to your `package.json`). Now, all three are declared as [`peerDependencies`](https://docs.npmjs.com/cli/v10/configuring-npm/package-json#peerdependencies) instead of regular dependencies, so **your project controls the exact version that gets used**, and WXT's install size shrinks.
- `vite` is a **required** peer, add it to your `devDependencies`.
- `web-ext` and `typescript` are **optional** peers, only needed if you use the corresponding features (see [below](#opt-into-opening-the-browser-during-dev-mode) for `web-ext`).
```sh
pnpm add -D vite typescript
```
### Opt Into Opening the Browser During Dev Mode
In v0.21, `web-ext` is now an optional peer dependency - if it's installed, the browser will be opened automatically. If not, the feature is disabled.
- **To continue opening the browser automatically**: Install `web-ext` as a dependency
```sh
pnpm add -D web-ext
```
- **If you don't use this feature**: Don't install it and you can delete any `web-ext.config.ts` options and/or remove any `webExt.enabled: false` config
You can still disable this behavior by setting `webExt.enabled: false` in your `wxt.config.ts` file or `web-ext.config.ts` file if the package is present.
> Projects created with `wxt init` will include `web-ext` in their `package.json`, opting new projects into this feature by default.
### `.wxt/tsconfig.json` Compiler Option Changes
The generated `.wxt/tsconfig.json` was updated to match Vite's current recommended TypeScript settings, and now requires **TypeScript &ge;5.4**.
```jsonc
{
"compilerOptions": {
"lib": ["ESNext", "DOM", "DOM.Iterable"], // [!code ++]
"target": "ESNext",
"module": "ESNext", // [!code --]
"module": "Preserve", // [!code ++]
"moduleDetection": "force", // [!code ++]
"moduleResolution": "Bundler",
"allowImportingTsExtensions": true, // [!code ++]
"verbatimModuleSyntax": true, // [!code ++]
"noEmit": true,
"esModuleInterop": true, // [!code --]
"forceConsistentCasingInFileNames": true, // [!code --]
"resolveJsonModule": true, // [!code --]
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true, // [!code ++]
"noUncheckedIndexedAccess": true, // [!code ++]
"noImplicitOverride": true, // [!code ++]
},
}
```
If these changes do cause problems, `verbatimModuleSyntax` and `noUncheckedIndexedAccess` are the two most likely culprits. It's recommended you fix the issues and leave the new settings enabled.
However, if you want to revert the config back and upgrade to the recommended options at a later time, you can add the following to your `wxt.config.ts` file:
<details>
```ts
export default defineConfig({
hooks: {
'prepare:tsconfig': (_, { tsconfig }) => {
// Reverts TSConfig back to WXT v0.20
// - https://wxt.dev/guide/resources/upgrading.html#wxttsconfigjson-compiler-option-changes
delete tsconfig.lib;
tsconfig.module = 'ESNext';
delete tsconfig.moduleDetection;
delete tsconfig.allowImportingTsExtensions;
delete tsconfig.verbatimModuleSyntax;
tsconfig.esModuleInterop = true;
tsconfig.forceConsistentCasingInFileNames = true;
tsconfig.resolveJsonModule = true;
delete tsconfig.noFallthroughCasesInSwitch;
delete tsconfig.noUncheckedIndexedAccess;
delete tsconfig.noImplicitOverride;
},
},
});
```
</details>
### `url:` Imports Removed
The `url:` import feature (importing and bundling remote code by URL, e.g. `import 'url:https://code.jquery.com/jquery.js'`) has been removed due to the supply-chain risk of a compromised CDN silently injecting code into your build.
There is no config flag to restore this behavior. If you relied on it:
- **Prefer an NPM package** if one exists for the library you need.
- **Vendor the file**: download it once, commit it to your repo, and import it locally like any other file. This lets you review the code and track changes via version control, instead of trusting a URL to never change.
:::details Why was this removed?
See <https://github.com/wxt-dev/wxt/issues/2262> and <https://github.com/wxt-dev/wxt/issues/2229> for the full discussion. A proposal to restore this behind a mandatory integrity hash is being tracked in [#2514](https://github.com/wxt-dev/wxt/pull/2514); if there's enough demand, it may come back as a separate, opt-in WXT module instead of core.
:::
### Zip Filename Template Changes
The default filename templates for `zip.artifactTemplate` and `zip.sourcesTemplate` changed, and the <span v-pre>`{{version}}`</span> template variable's meaning changed:
- <span v-pre>`{{version}}`</span> now always resolves to `manifest.version` (previously it resolved to `manifest.version_name ?? manifest.version`).
- A new <span v-pre>`{{versionName}}`</span> variable was added with the old <span v-pre>`{{version}}`</span> behavior (`manifest.version_name ?? manifest.version`).
- A new <span v-pre>`{{packageVersion}}`</span> variable was added, resolving to your `package.json`'s version.
- A new <span v-pre>`{{modeSuffix}}`</span> variable was added (`-dev` for development builds, `''` for production).
The defaults themselves changed to use these new variables:
```diff
- artifactTemplate: '{{name}}-{{version}}-{{browser}}.zip'
+ artifactTemplate: '{{name}}-{{packageVersion}}-{{browser}}{{modeSuffix}}.zip'
- sourcesTemplate: '{{name}}-{{version}}-sources.zip'
+ sourcesTemplate: '{{name}}-{{packageVersion}}-sources{{modeSuffix}}.zip'
```
- **If you don't customize `artifactTemplate`/`sourcesTemplate`**: your production zip filenames will not change, but dev and other build modes will be output to separate directories.
> If you previously install the dev version of your extension in your browser, note that the output directory has changed and you'll need to re-install it next time you run the dev command.
- **If you have a custom template**: replace any <span v-pre>`{{version}}`</span> usage with <span v-pre>`{{versionName}}`</span> to keep the old value, or explicitly opt back into the old defaults:
```ts [wxt.config.ts]
export default defineConfig({
zip: {
artifactTemplate: '{{name}}-{{versionName}}-{{browser}}.zip',
sourcesTemplate: '{{name}}-{{versionName}}-sources.zip',
},
});
```
For more info on the difference between `manifest.version` and `manifest.version_name`, see the [Manifest Config docs](/guide/essentials/config/manifest#version-and-version-name).
### Sources ZIP: `includeSources`/`excludeSources` Now Behave Like a Standard Allowlist
Previously, `includeSources`/`excludeSources` behaved counterintuitively: `all files - excludeSources + includedSources = zipped files`. This is not the standard behavior for allowlist/blocklists.
As of v0.21, these options behave as expected: `includedSources - excludeSources = zipped files`.
Additionally, a new `zip.dotSources` option (default `false`) was added to control whether hidden files/directories can be included in the zip.
This will likely be the biggest pain point of the upgrade. You will need to rebuild your included and excluded sources lists from scratch. Luckily, it's simpler than before!
1. Do you need any hidden files? If so, set `zip.dotSources` to `true`
1. Add base files and directories that need to be in the ZIP to `zip.includeSources`
1. Run `wxt zip -b firefox` and confirm all the files you need are included
1. Remove files from the zip by adding them to `zip.excludeSources`
1. Run `wxt zip -b firefox` and confirm only the files you need are in the zip
:::tip
`wxt zip -b firefox` now prints every file included in the sources ZIP. This will help you identify missing or unwanted files more quickly.
:::
Here's an example configuration:
```ts
// wxt.config.ts
export default defineConfig({
srcDir: 'src',
zip: {
// Say I have a .tool-versions file I want to include
dotSources: true,
// Specify base folders and files to include
includeSources: [
'src',
'public',
'package.json',
'bun.lock',
'README.md',
'.tool-versions',
],
// Exclude any folders inside the base folders that are not needed, like test data
excludeSources: ['**/__fixtures__'],
},
});
```
### `createShadowRootUi` DOM Changes
`@webext-core/isolated-element` was upgraded from v1 to v3. The only breaking change relevant to WXT projects is the changes the internal structure of the shadow root's DOM, simplifying it from a full `<html>` document to just a `div`:
:::code-group
```html [Before]
<html>
<head>
<style>
...
</style>
</head>
<body>
...your app
</body>
</html>
```
```html [After]
<style>
...
</style>
<div>...your app</div>
```
:::
Historically, CSS frameworks haven't had good support for shadow roots, so we needed a full `<html>` structure for styles to be applied correctly. But that has change this past few years, frameworks have started to include the `host:` selector alongside `root:`, which is required for base styles to be applied to the shadow root's host element:
```css
:root { /* [!code --] */
:root, :host { /* [!code ++] */
/* base styles... */
}
```
If you use `createShadowRootUi`, see if your UI looks the same after this update without any changes.
If the styles are broken, you can continue using the full `<html>` structure by installing the v1 of `@webext-core/isolated-element` - WXT will respect whatever version of the package is listed in your `package.json`.
```sh
pnpm add @webext-core/isolated-element@^1
```
In the next major version, support for `@webext-core/isolated-element` v1 will be dropped, so you have some time to migrate.
### Content & Unlisted Script `globalName` Now Defaults to `false`
Content scripts and unlisted scripts are built as an IIFE. Previously, WXT generated a global variable to hold the IIFE's return value for all scripts by default. Now, no global variable is generated by default, producing a smaller, anonymous IIFE that prevents variable collisions with the page.
If you rely on the return value of your script, for example when injecting it with `browser.scripting.executeScript` and reading `InjectionResult.result`, set `globalName: true` to restore the old behavior:
```ts
export default defineUnlistedScript({
globalName: true, // [!code ++]
main() {
return 'some value';
},
});
```
This applies per-entrypoint, to both `defineContentScript` and `defineUnlistedScript`.
### ESLint Auto-Import Config Now Detects Your Installed ESLint Version
Setting `imports.eslintrc.enabled: true` used to always assume you wanted the legacy ESLint 8 config format (`.wxt/eslintrc-auto-import.json`), regardless of which ESLint version you actually had installed.
Now, `true` behaves the same as `'auto'`: WXT detects your installed ESLint version and generates the matching file automatically (ESLint 9+ &rarr; `eslint-auto-imports.mjs`, ESLint &le;8 &rarr; `eslintrc-auto-import.json`).
- If you're on ESLint 9+ but never explicitly set `enabled: 9`, you'll now get the new flat-config file instead of the legacy one.
- To force the old ESLint 8 format regardless of your installed version, set `enabled: 8` explicitly.
See the [ESLint config docs](/guide/essentials/config/auto-imports#eslint) for the full set of options and how to wire up the generated file.
### Deprecated APIs Removed From v0.21
APIs deprecated in v0.20 have been removed:
- `wxt.config.runner` / `ExtensionRunnerConfig` / `defineRunnerConfig` &rarr; use `wxt.config.webExt` / `defineWebExtConfig` instead.
- `dev.server.hostname` &rarr; use `dev.server.host` instead.
- The `wxt/testing` barrel export &rarr; import from the specific submodule instead:
```ts
import { fakeBrowser, WxtVitest } from 'wxt/testing'; // [!code --]
import { fakeBrowser } from 'wxt/testing/fake-browser'; // [!code ++]
import { WxtVitest } from 'wxt/testing/vitest-plugin'; // [!code ++]
```
- The `clean(root: string)` JS API overload &rarr; Pass a root like this instead `clean({ root: './my-extension' })`
### CWS v2 API Support
`publish-browser-extension` was upgraded to v5, which adds support for the new Chrome Web Store API v2 to `wxt submit`! Instead of using a refresh token, it uses a service account, which is much easier to setup and never expires. It also supports a few other features: <https://developer.chrome.com/blog/cws-api-v2>
To setup your project to use v2, run `wxt submit init` and go through the setup process for the CWS, selecting v2 when prompted.
v1 will stop working **15th October 2026**, so you have a few months to migrate.
### Other Dependency Upgrades
A few dependencies were bumped to their latest major versions:
- **`@webext-core/fake-browser` v1 &rarr; v2**: If you use `wxt/testing/fake-browser` (or `@webext-core/fake-browser` directly) in unit tests, note that its types now match `@wxt-dev/browser` instead of `webextension-polyfill`. This is the same change WXT's own `browser` went through in [v0.20](#webextension-polyfill-removed). Most notably, **mocking `browser.runtime.onMessage` listeners that return a promise no longer works**, use `sendResponse` instead:
```ts
fakeBrowser.runtime.onMessage.addListener(async () => { // [!code --]
return await someAsyncWork(); // [!code --]
fakeBrowser.runtime.onMessage.addListener((_message, _sender, sendResponse) => { // [!code ++]
someAsyncWork().then(sendResponse); // [!code ++]
return true; // [!code ++]
});
```
If you use use a messaging library, it will likely continue working as-is.
- **`@webext-core/match-patterns` v1 &rarr; v2** and **`dotenv-expand` v12 &rarr; v13**: No action needed, non-breaking for WXT's usage.
## New Deprecations in v0.20
Deprecated APIs will be removed in the next major release.
- `useAppConfig` deprecated in favor of `getAppConfig` - same function, just renamed. This avoids react linters mistaking it as a hook.
## v0.19.0 &rarr; v0.20.0
v0.20 is a big release! There are lots of breaking changes because this version is intended to be a release candidate for v1.0. If all goes well, v1.0 will be released with no additional breaking changes.
-5
View File
@@ -66,11 +66,6 @@ features:
- icon: 📏
title: Bundle Analysis
details: Tools for analyzing the final extension bundle and minimizing your extension's size.
- icon: ⬇️
title: Bundle Remote Code
details: Downloads and bundles remote code imported from URLs.
link: /guide/essentials/remote-code
linkText: Read docs
---
## Sponsors
+3
View File
@@ -37,6 +37,9 @@ Hide
# Create a temporary folder for demo
Type 'mkdir packages/wxt/init-demo' Enter
Type 'cd packages/wxt/init-demo' Enter
# Unset CI variables inherited from the GitHub Actions runner so consola
# picks its fancy reporter instead of the basic one (#2461)
Type 'unset CI GITHUB_ACTIONS' Enter
Type 'clear' Enter
Show
+2 -2
View File
@@ -21,7 +21,7 @@
"@aklinker1/buildc": "^1.1.7",
"@aklinker1/check": "^2.4.0",
"@types/bun": "^1.3.5",
"@types/node": "^20.17.6",
"@types/node": "^22",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"@webext-core/fake-browser": "^1.3.4",
@@ -31,6 +31,7 @@
"tsdown": "^0.21.0",
"typescript": "^6.0.3",
"unocss": "^66.6.8",
"vite": "^7.3.1",
"vitest": "^4.1.5",
"vitest-plugin-random-seed": "^1.1.2"
},
@@ -42,7 +43,6 @@
"@types/bun": "catalog:",
"@types/semver": "^7.7.1",
"@vitest/coverage-v8": "^4.1.6",
"changelogen": "^0.6.2",
"consola": "^3.4.2",
"cspell": "^9.7.0",
"feed": "^5.2.1",
+30
View File
@@ -6,6 +6,7 @@ Report analytics events from your web extension extension.
- [Google Analytics 4 (Measurement Protocol)](#google-analytics-4-measurement-protocol)
- [Moderok](#moderok)
- [PostHog](#posthog)
- [Umami](#umami)
## Install With WXT
@@ -156,6 +157,35 @@ export default defineAppConfig({
For a full walkthrough — module setup, sending events, and all provider options — see the [Moderok WXT guide](https://docs.moderok.dev/guide/wxt).
### PostHog
[PostHog](https://posthog.com/) is an open source product analytics platform. It supports event tracking, session recording, feature flags, surveys, and more.
In your PostHog project settings, find your **Project API key** and save it to your `.env` file:
```dotenv
WXT_POSTHOG_API_KEY='phc_...'
```
Then add the `posthog` provider to your `<srcDir>/app.config.ts` file:
```ts
import { posthog } from '@wxt-dev/analytics/providers/posthog';
export default defineAppConfig({
analytics: {
providers: [
posthog({
apiKey: import.meta.env.WXT_POSTHOG_API_KEY,
// apiHost defaults to 'https://us.i.posthog.com'.
// Change to 'https://eu.i.posthog.com' for EU Cloud, or your self-hosted URL.
apiHost: 'https://eu.i.posthog.com',
}),
],
},
});
```
### Umami
[Umami](https://umami.is/) is a privacy-first, open source analytics platform.
+4
View File
@@ -1,5 +1,6 @@
import { defineAppConfig } from 'wxt/utils/define-app-config';
import { googleAnalytics4 } from './modules/analytics/providers/google-analytics-4';
import { posthog } from './modules/analytics/providers/posthog';
import { umami } from './modules/analytics/providers/umami';
export default defineAppConfig({
@@ -10,6 +11,9 @@ export default defineAppConfig({
apiSecret: '...',
measurementId: '...',
}),
posthog({
apiKey: '...',
}),
umami({
apiUrl: 'https://umami.aklinker1.io/api',
domain: 'analytics.wxt.dev',
@@ -18,7 +18,7 @@ export const googleAnalytics4 =
eventProperties: Record<string, string | undefined> | undefined,
): Promise<void> => {
const url = new URL(
config?.debug ? '/debug/mp/collect' : '/mp/collect',
config.debug ? '/debug/mp/collect' : '/mp/collect',
options.apiUrl ?? 'https://www.google-analytics.com',
);
if (options.apiSecret)
@@ -38,6 +38,12 @@ export const googleAnalytics4 =
]),
);
if (config.debug) {
console.debug(
'[@wxt-dev/analytics] Sending event to Google Analytics 4:',
{ eventName, eventProperties },
);
}
await fetch(url.href, {
method: 'POST',
body: JSON.stringify({
@@ -0,0 +1,83 @@
import { defineAnalyticsProvider } from '../client';
export interface PostHogProviderOptions {
/** Your PostHog project API key. */
apiKey: string;
/**
* PostHog API host URL.
*
* @default 'https://us.i.posthog.com'
*/
apiHost?: string;
}
export const posthog = defineAnalyticsProvider<PostHogProviderOptions>(
(_, config, options) => {
const apiHost = (options.apiHost ?? 'https://us.i.posthog.com').replace(
/\/$/,
'',
);
const capture = async (
distinctId: string,
event: string,
properties: Record<string, unknown>,
): Promise<void> => {
if (config.debug) {
console.debug('[@wxt-dev/analytics] Sending event to PostHog:', {
event,
properties,
});
}
const body: PostHogCaptureBody = {
api_key: options.apiKey,
distinct_id: distinctId,
event,
properties,
timestamp: new Date().toISOString(),
};
await fetch(`${apiHost}/i/v0/e/`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});
};
return {
identify: async (event) => {
await capture(event.user.id, '$identify', {
$set: event.user.properties,
});
},
page: async (event) => {
await capture(event.user.id, '$pageview', {
$current_url: event.page.url,
$title: event.page.title,
$session_id: event.meta.sessionId,
$screen: event.meta.screen,
$language: event.meta.language,
$referrer: event.meta.referrer,
$set: event.user.properties,
});
},
track: async (event) => {
await capture(event.user.id, event.event.name, {
...event.event.properties,
$screen: event.meta.screen,
$language: event.meta.language,
$referrer: event.meta.referrer,
$set: event.user.properties,
});
},
};
},
);
/** @see https://posthog.com/docs/api/capture */
interface PostHogCaptureBody {
api_key: string;
distinct_id: string;
event: string;
properties: Record<string, unknown>;
timestamp: string;
}
+4
View File
@@ -62,6 +62,10 @@
"./providers/umami": {
"types": "./dist/providers/umami.d.mts",
"default": "./dist/providers/umami.mjs"
},
"./providers/posthog": {
"types": "./dist/providers/posthog.d.mts",
"default": "./dist/providers/posthog.mjs"
}
},
"module": "./dist/index.mjs",
+1
View File
@@ -10,6 +10,7 @@ export default defineConfig({
'./modules/analytics/providers/google-analytics-4.ts',
'providers/umami': './modules/analytics/providers/umami.ts',
'providers/moderok': './modules/analytics/providers/moderok.ts',
'providers/posthog': './modules/analytics/providers/posthog.ts',
},
deps: {
neverBundle: ['#analytics'],
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "@wxt-dev/browser",
"description": "Provides a cross-browser API for using extension APIs and types based on @types/chrome",
"version": "0.2.0",
"version": "0.2.2",
"type": "module",
"main": "src/index.mjs",
"types": "src/index.d.ts",
@@ -25,7 +25,7 @@
"src"
],
"devDependencies": {
"@types/chrome": "0.2.0",
"@types/chrome": "0.2.2",
"@types/node": "catalog:",
"nano-spawn": "catalog:",
"typescript": "catalog:",
+48 -15
View File
@@ -383,22 +383,53 @@ export namespace Browser {
* Permissions: "alarms"
*/
export namespace alarms {
interface AlarmCreateInfo {
/** Length of time in minutes after which the {@link onAlarm} event should fire. */
delayInMinutes?: number | undefined;
/** If set, the onAlarm event should fire every `periodInMinutes` minutes after the initial event specified by `when` or `delayInMinutes`. If not set, the alarm will only fire once. */
periodInMinutes?: number | undefined;
/** Time at which the alarm should fire, in milliseconds past the epoch (e.g. `Date.now() + n`). */
when?: number | undefined;
}
type AlarmCreateInfo =
& {
/**
* Whether the alarm should persist across sessions (browser restarts). In Chrome, this defaults to true to match historical behavior, but you should set this explicitly to maximize compatibility across browsers.
* @since Chrome 150
*/
persistAcrossSessions?: boolean | undefined;
}
& (
| {
/** Length of time in minutes after which the {@link onAlarm} event should fire. */
delayInMinutes: number;
/** If set, the onAlarm event should fire every `periodInMinutes` minutes after the initial event specified by `when` or `delayInMinutes`. If not set, the alarm will only fire once. */
periodInMinutes?: number | undefined;
/** Time at which the alarm should fire, in milliseconds past the epoch (e.g. `Date.now() + n`). */
when?: never | undefined;
}
| {
/** Length of time in minutes after which the {@link onAlarm} event should fire. */
delayInMinutes?: number | undefined;
/** If set, the onAlarm event should fire every `periodInMinutes` minutes after the initial event specified by `when` or `delayInMinutes`. If not set, the alarm will only fire once. */
periodInMinutes: number;
/** Time at which the alarm should fire, in milliseconds past the epoch (e.g. `Date.now() + n`). */
when?: number | undefined;
}
| {
/** Length of time in minutes after which the {@link onAlarm} event should fire. */
delayInMinutes?: never | undefined;
/** If set, the onAlarm event should fire every `periodInMinutes` minutes after the initial event specified by `when` or `delayInMinutes`. If not set, the alarm will only fire once. */
periodInMinutes?: number | undefined;
/** Time at which the alarm should fire, in milliseconds past the epoch (e.g. `Date.now() + n`). */
when: number;
}
);
interface Alarm {
/** If not null, the alarm is a repeating alarm and will fire again in `periodInMinutes` minutes. */
periodInMinutes?: number;
/** Time at which this alarm was scheduled to fire, in milliseconds past the epoch (e.g. `Date.now() + n`). For performance reasons, the alarm may have been delayed an arbitrary amount beyond this. */
scheduledTime: number;
/** Name of this alarm. */
name: string;
/** If not null, the alarm is a repeating alarm and will fire again in `periodInMinutes` minutes. */
periodInMinutes?: number;
/**
* Whether the alarm should persist across sessions (browser restarts).
* @since Chrome 150
*/
persistAcrossSessions: boolean;
/** Time at which this alarm was scheduled to fire, in milliseconds past the epoch (e.g. `Date.now() + n`). For performance reasons, the alarm may have been delayed an arbitrary amount beyond this. */
scheduledTime: number;
}
/**
@@ -7606,7 +7637,7 @@ export namespace Browser {
* Creates a new offscreen document for the extension.
* @param parameters The parameters describing the offscreen document to create.
*
* Can return its result via Promise in Manifest V3.
* Can return its result via Promise.
*/
function createDocument(parameters: CreateParameters): Promise<void>;
function createDocument(parameters: CreateParameters, callback: () => void): void;
@@ -7614,7 +7645,7 @@ export namespace Browser {
/**
* Closes the currently-open offscreen document for the extension.
*
* Can return its result via Promise in Manifest V3.
* Can return its result via Promise.
*/
function closeDocument(): Promise<void>;
function closeDocument(callback: () => void): void;
@@ -7622,7 +7653,8 @@ export namespace Browser {
/**
* Determines whether the extension has an active document.
*
* Can return its result via Promise in Manifest V3.
* Can return its result via Promise.
* @since Chrome 150
*/
function hasDocument(): Promise<boolean>;
function hasDocument(callback: (result: boolean) => void): void;
@@ -9184,6 +9216,7 @@ export namespace Browser {
| "identity"
| "identity.email"
| "idle"
| "input"
| "loginState"
| "management"
| "nativeMessaging"
+31
View File
@@ -1,5 +1,36 @@
# Changelog
## v0.2.6
[compare changes](https://github.com/wxt-dev/wxt/compare/i18n-v0.2.5...i18n-v0.2.6)
### 🚀 Enhancements
- Add named substitutions to i18n ([#2440](https://github.com/wxt-dev/wxt/pull/2440))
### 🏡 Chore
- Add `prettier-plugin-jsdoc` to project ([#2171](https://github.com/wxt-dev/wxt/pull/2171))
- Replace fast-glob and ora with lighter alternatives ([#2173](https://github.com/wxt-dev/wxt/pull/2173))
- **deps:** Upgrade deps ([#2175](https://github.com/wxt-dev/wxt/pull/2175))
- Add prepack script to all packages ([032f7931](https://github.com/wxt-dev/wxt/commit/032f7931))
- Remove `any` from `i18n`'s internal types ([#2201](https://github.com/wxt-dev/wxt/pull/2201))
- Add cspell and fix all typos ([6621aaf8](https://github.com/wxt-dev/wxt/commit/6621aaf8))
- Migrate monorepo to use Bun instead of PNPM ([#2009](https://github.com/wxt-dev/wxt/pull/2009))
- Add new types for i18n ([#2121](https://github.com/wxt-dev/wxt/pull/2121))
- **deps-dev:** Bump typescript from 5.9.3 to 6.0.3 ([#2325](https://github.com/wxt-dev/wxt/pull/2325))
- **deps-dev:** Bump oxlint from 1.59.0 to 1.63.0 ([#2356](https://github.com/wxt-dev/wxt/pull/2356))
- Use `catalog:` for dev dependencies ([#2357](https://github.com/wxt-dev/wxt/pull/2357))
- **deps:** Bump tinyglobby from 0.2.15 to 0.2.16 ([#2366](https://github.com/wxt-dev/wxt/pull/2366))
- Add benchmarks for i18n vs vanilla usage ([#2372](https://github.com/wxt-dev/wxt/pull/2372))
### ❤️ Contributors
- T ([@cookesan](https://github.com/cookesan))
- Aaron ([@aklinker1](https://github.com/aklinker1))
- Patryk Kuniczak ([@PatrykKuniczak](https://github.com/PatrykKuniczak))
- Florian Metz ([@Timeraa](https://github.com/Timeraa))
## v0.2.5
[compare changes](https://github.com/wxt-dev/wxt/compare/i18n-v0.2.4...i18n-v0.2.5)
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@wxt-dev/i18n",
"description": "Type-safe wrapper around browser.i18n.getMessage with additional features",
"version": "0.2.5",
"version": "0.2.6",
"type": "module",
"repository": {
"type": "git",
+1 -1
View File
@@ -1,6 +1,6 @@
import 'wxt';
import { addImportPreset, addViteConfig, defineWxtModule } from 'wxt/modules';
import react, { Options as PluginOptions } from '@vitejs/plugin-react';
import react, { type Options as PluginOptions } from '@vitejs/plugin-react';
import type { PluginOption } from 'vite';
export default defineWxtModule<ReactModuleOptions>({
+1 -1
View File
@@ -1,4 +1,4 @@
import { Component } from 'solid-js';
import type { Component } from 'solid-js';
export const App: Component = () => {
const [count, setCount] = createSignal(0);
+1 -1
View File
@@ -1,6 +1,6 @@
import 'wxt';
import { addImportPreset, addViteConfig, defineWxtModule } from 'wxt/modules';
import solid, { Options as PluginOptions } from 'vite-plugin-solid';
import solid, { type Options as PluginOptions } from 'vite-plugin-solid';
export default defineWxtModule<SolidModuleOptions>({
name: '@wxt-dev/module-solid',
@@ -1,6 +1,3 @@
// @ts-expect-error: URL imports not typed
import 'url:https://code.jquery.com/jquery-3.7.1.slim.min.js';
console.log(browser.runtime.id);
logId();
console.log(2);
+1 -1
View File
@@ -1,5 +1,5 @@
import { defineProject } from 'vitest/config';
import { WxtVitest } from 'wxt/testing';
import { WxtVitest } from 'wxt/testing/vitest-plugin';
export default defineProject({
test: {
+127 -1
View File
@@ -1,5 +1,131 @@
# Changelog
## v0.21.1
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.20.27...wxt-v0.21.1)
### 🚀 Features
- Add `prepare:tsconfig` hook for updating `.wxt/tsconfig.json` file ([#2450](https://github.com/wxt-dev/wxt/pull/2450))
- Add watch options config ([#2439](https://github.com/wxt-dev/wxt/pull/2439))
- Export `getEntrypointBundlePath` from `wxt` ([#2463](https://github.com/wxt-dev/wxt/pull/2463))
- Add `{{modeSuffix}}` to zip templates and update defaults ([#1623](https://github.com/wxt-dev/wxt/pull/1623))
- Change default behavior of `getUnimportEslintOptions` true flag ([#2296](https://github.com/wxt-dev/wxt/pull/2296))
- New template variable `{{versionName}}` and change of the behaviour of `{{version}}` ([#1612](https://github.com/wxt-dev/wxt/pull/1612))
- **Firefox**: List files in sources zip ([#2513](https://github.com/wxt-dev/wxt/pull/2513))
### 🩹 Fixes
- `wxt clean` removes `.wxt/` directory at project root ([#2415](https://github.com/wxt-dev/wxt/pull/2415))
- Handle spread content script configs ([#2448](https://github.com/wxt-dev/wxt/pull/2448))
- Avoid deprecated Rollup asset name access ([#2453](https://github.com/wxt-dev/wxt/pull/2453))
- **init**: Allow entering an empty directory for project path ([#2458](https://github.com/wxt-dev/wxt/pull/2458))
- Opening the browser issue in windows. ([#2436](https://github.com/wxt-dev/wxt/pull/2436))
- File reloading mechanism and add profile watch ignores ([#2112](https://github.com/wxt-dev/wxt/pull/2112))
- Docs sidebar header, background color issue ([#2504](https://github.com/wxt-dev/wxt/pull/2504))
- Deprecated `useAppConfig` in favour of `getAppConfig` ([#2487](https://github.com/wxt-dev/wxt/pull/2487))
- Make `web-ext` a peer dependency ([#2079](https://github.com/wxt-dev/wxt/pull/2079))
- Handle edge case where eslint version cannot be found ([`ab679ba`](https://github.com/wxt-dev/wxt/commit/ab679ba413772849e0c263315587334b42c25ed0))
- Remove `url:` import feature ([#2456](https://github.com/wxt-dev/wxt/pull/2456))
- **zip**: Make `includeSources`/`excludeSources` follow standard allowlist behavior ([#2114](https://github.com/wxt-dev/wxt/pull/2114))
- Remove `console.log` ([`0b352f6`](https://github.com/wxt-dev/wxt/commit/0b352f6eff1fbb45034b788a134742d03db81816))
- Loosen version of `@webext-core/isolated-element` ([`7d6caad`](https://github.com/wxt-dev/wxt/commit/7d6caad9b52bc263d0acb4263153fe0e05e24b76))
- Update content and unlisted script `globalName` default to `false` ([#2511](https://github.com/wxt-dev/wxt/pull/2511))
- **TS**: Update `.wxt/tsconfig.json` compiler options, require TS >=5.4 ([#2512](https://github.com/wxt-dev/wxt/pull/2512))
### 💅 Refactors
- Make vite a default peer ([#1945](https://github.com/wxt-dev/wxt/pull/1945))
- Move to module-runner ([#1946](https://github.com/wxt-dev/wxt/pull/1946))
### 📖 Documentation
- Move Bun tabs to first position in installation ([#2428](https://github.com/wxt-dev/wxt/pull/2428))
- Added package manager tab group synchronization across the entire installation page ([#2421](https://github.com/wxt-dev/wxt/pull/2421))
- Make vitepress components css files more readable and simply ([#2272](https://github.com/wxt-dev/wxt/pull/2272))
- Use bright green for example hover and link colors ([`d7f8ebe`](https://github.com/wxt-dev/wxt/commit/d7f8ebec3904ea6efa803c9d7b5dcd9b3ea59a01))
- Document PerBrowser options for entrypoints (#2304) ([#2403](https://github.com/wxt-dev/wxt/pull/2403))
- Show Edge Add-ons in showcase ([#2452](https://github.com/wxt-dev/wxt/pull/2452))
- Don't underline the comma when hovering over showcase item store links ([#2454](https://github.com/wxt-dev/wxt/pull/2454))
- Fix `undefined` issue for `ExampleSearch.vue` ([#2370](https://github.com/wxt-dev/wxt/pull/2370))
- Update extension-showcase.yml ([#2457](https://github.com/wxt-dev/wxt/pull/2457))
- Added "NiceTab" Edge Addons (edgeId) to extension showcase ([#2455](https://github.com/wxt-dev/wxt/pull/2455))
- Prioritize Bun in package manager options ([#2425](https://github.com/wxt-dev/wxt/pull/2425))
- Update BlogLayout.vue `useData` to correctly type ([#2369](https://github.com/wxt-dev/wxt/pull/2369))
- Revert #2380 - locationWatcher ([#2416](https://github.com/wxt-dev/wxt/pull/2416))
- Added "Teams Chat Exporter" Edge Addons (edgeId) to extension showcase ([#2472](https://github.com/wxt-dev/wxt/pull/2472))
- Cleanup the "extension APIs" page ([#2473](https://github.com/wxt-dev/wxt/pull/2473))
- Add MindSnap to showcase ([#2499](https://github.com/wxt-dev/wxt/pull/2499))
- Use consola's fancy reporter in init demo GIF ([#2485](https://github.com/wxt-dev/wxt/pull/2485))
- Update `wxt init` GIF ([`13be7c5`](https://github.com/wxt-dev/wxt/commit/13be7c5bfdedc6660fc799ded6d868736dffcb86))
- Update `wxt init` GIF ([`299b0ad`](https://github.com/wxt-dev/wxt/commit/299b0add803caab65f707ab73a677fc92f8e3379))
- Cleanup v0.21 migration guide ([`885f8f0`](https://github.com/wxt-dev/wxt/commit/885f8f0b76d8daa635957edcd0783cb3b2a41ade))
- Finalize migration guide for wxt v0.21 ([#2516](https://github.com/wxt-dev/wxt/pull/2516))
- Add section about install footprint ([`d8a86e7`](https://github.com/wxt-dev/wxt/commit/d8a86e76336be263271673028ee7677efeecf905))
### 🏡 Chore
- Skip package manager tests when binaries are missing ([#2441](https://github.com/wxt-dev/wxt/pull/2441))
- **deps**: Bump actions/setup-go from 6.4.0 to 6.5.0 ([#2432](https://github.com/wxt-dev/wxt/pull/2432))
- Bump minimum supported Node version to >=22 ([`008f5a6`](https://github.com/wxt-dev/wxt/commit/008f5a66c9eb9e01a3dd1db0545e362254641089))
- **deps**: Remove `esbuild` dependency ([#2506](https://github.com/wxt-dev/wxt/pull/2506))
- Upgrade `@webext-core/isolated-element` v1 → v3 ([#2098](https://github.com/wxt-dev/wxt/pull/2098))
- Remove deprecated APIs ([#2488](https://github.com/wxt-dev/wxt/pull/2488))
- **deps**: Upgrade major dependencies ([#2508](https://github.com/wxt-dev/wxt/pull/2508))
### 🤖 CI
- Fix VHS action ([#2459](https://github.com/wxt-dev/wxt/pull/2459))
- Use `@aklinker1/zero-changelog` for release notes ([#2515](https://github.com/wxt-dev/wxt/pull/2515))
### ⚠️ Breaking Changes
- Add `{{modeSuffix}}` to zip templates and update defaults
- Change default behavior of `getUnimportEslintOptions` true flag
- New template variable `{{versionName}}` and change of the behaviour of `{{version}}`
- Make `web-ext` a peer dependency
- Remove `url:` import feature
- **zip**: Make `includeSources`/`excludeSources` follow standard allowlist behavior
- [#2511](https://github.com/wxt-dev/wxt/pull/2511): If your script needs to return a value, like for `browser.scripting.executeScript`, set `globalName: true` to maintain the old behavior.
- [#2512](https://github.com/wxt-dev/wxt/pull/2512): Updates `.wxt/tsconfig.json` defaults to latest recommended settings for vite projects and requires Typescript 5.4 or later. See #2512 for details on what compiler options were changed.
- Move to module-runner
- Bump minimum supported Node version to >=22
- Upgrade `@webext-core/isolated-element` v1 → v3
- Remove deprecated APIs
- **deps**: Upgrade major dependencies
### ❤️ Contributors
- [@z1lV3r](https://github.com/z1lV3r)
- Peter Wong <www121ppp@gmail.com>
- wangpeng618 <wangpeng618@jd.com>
- Thribhuvan <thribhuvan003@gmail.com>
- ТΞNSΛI <tensai@gmx.net>
- silverfish2525 <silverfish25@proton.me>
- [@PatrykKuniczak](https://github.com/PatrykKuniczak)
- [@nishu-murmu](https://github.com/nishu-murmu)
- Nazım Gediz Aydındoğmuş <nga@hotmail.com.tr>
- Kai Gritun <kaigritun@gmail.com>
- Kai Gritun <kai@kaigritun.com>
- [@github-actions[bot]](https://github.com/github-actions[bot])
- [@ded-furby](https://github.com/ded-furby)
- [@dashitongzhi](https://github.com/dashitongzhi)
- [@cookesan](https://github.com/cookesan)
- Shubhrajit Sadhukhan <champa.281982@gmail.com>
- BlazerYoo <blazeryoo1921@gmail.com>
- [@aklinker1](https://github.com/aklinker1)
- [@lishaduck](https://github.com/lishaduck)
- [@nnthanh01061999](https://github.com/nnthanh01061999)
- [@cookesan](https://github.com/cookesan)
- [@smashedr](https://github.com/smashedr)
- [@dependabot[bot]](https://github.com/dependabot[bot])
- [@ded-furby](https://github.com/ded-furby)
- [@ZerGo0](https://github.com/ZerGo0)
- [@LUIDevo](https://github.com/LUIDevo)
- [@dashitongzhi](https://github.com/dashitongzhi)
- [@fkatsuhiro](https://github.com/fkatsuhiro)
## v0.20.27
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.20.26...wxt-v0.20.27)
@@ -3697,4 +3823,4 @@ Initial release of WXT. Full support for production builds and initial toolkit f
### 🤖 CI
- Create validation workflow ([#12](https://github.com/wxt-dev/wxt/pull/12))
- Create release workflow ([#13](https://github.com/wxt-dev/wxt/pull/13))
- Create release workflow ([#13](https://github.com/wxt-dev/wxt/pull/13))
-1
View File
@@ -54,7 +54,6 @@ Or see the [installation guide](https://wxt.dev/guide/installation.html) to get
- 📦 [Module system](https://wxt.dev/guide/essentials/wxt-modules.html#overview) for reusing code between extensions
- 🖍️ Quickly bootstrap a new project
- 📏 Bundle analysis
- ⬇️ Download and bundle remote URL imports
## Sponsors
@@ -119,8 +119,8 @@ export default {
"
`;
exports[`Auto Imports > eslintrc > "enabled: true" should output a JSON config file compatible with ESlint 8 1`] = `
".wxt/eslintrc-auto-import.json
exports[`Auto Imports > eslintrc > "enabled: true" should output a JSON config file compatible with ESlint of package.json 1`] = `
".wxt/eslint-auto-imports.mjs
----------------------------------------
{
"globals": {
+5 -5
View File
@@ -28,7 +28,7 @@ describe('Auto Imports', () => {
const defineContentScript: typeof import('wxt/utils/define-content-script').defineContentScript
const defineUnlistedScript: typeof import('wxt/utils/define-unlisted-script').defineUnlistedScript
const defineWxtPlugin: typeof import('wxt/utils/define-wxt-plugin').defineWxtPlugin
const fakeBrowser: typeof import('wxt/testing').fakeBrowser
const fakeBrowser: typeof import('wxt/testing/fake-browser').fakeBrowser
const getAppConfig: typeof import('wxt/utils/app-config').getAppConfig
const injectScript: typeof import('wxt/utils/inject-script').injectScript
const storage: typeof import('wxt/utils/storage').storage
@@ -124,7 +124,7 @@ describe('Auto Imports', () => {
export { defineWxtPlugin } from 'wxt/utils/define-wxt-plugin';
export { injectScript, ScriptPublicPath, InjectScriptOptions } from 'wxt/utils/inject-script';
export { InvalidMatchPattern, MatchPattern } from 'wxt/utils/match-patterns';
export { fakeBrowser } from 'wxt/testing';
export { fakeBrowser } from 'wxt/testing/fake-browser';
export { startOfDay } from '../utils/time';
}
"
@@ -209,7 +209,7 @@ describe('Auto Imports', () => {
export { defineWxtPlugin } from 'wxt/utils/define-wxt-plugin';
export { injectScript, ScriptPublicPath, InjectScriptOptions } from 'wxt/utils/inject-script';
export { InvalidMatchPattern, MatchPattern } from 'wxt/utils/match-patterns';
export { fakeBrowser } from 'wxt/testing';
export { fakeBrowser } from 'wxt/testing/fake-browser';
}
"
`);
@@ -217,7 +217,7 @@ describe('Auto Imports', () => {
});
describe('eslintrc', () => {
it('"enabled: true" should output a JSON config file compatible with ESlint 8', async () => {
it('"enabled: true" should output a JSON config file compatible with ESlint of package.json', async () => {
const project = new TestProject();
project.addFile('entrypoints/popup.html', `<html></html>`);
@@ -230,7 +230,7 @@ describe('Auto Imports', () => {
});
expect(
await project.serializeFile('.wxt/eslintrc-auto-import.json'),
await project.serializeFile('.wxt/eslint-auto-imports.mjs'),
).toMatchSnapshot();
});
+4 -4
View File
@@ -10,7 +10,7 @@ describe('Dev Mode', () => {
);
const server = await project.startServer({
runner: {
webExt: {
disabled: true,
},
});
@@ -30,7 +30,7 @@ describe('Dev Mode', () => {
);
const server = await project.startServer({
runner: { disabled: true },
webExt: { disabled: true },
dev: { server: { port: 4400 } },
});
try {
@@ -51,7 +51,7 @@ describe('Dev Mode', () => {
);
const server = await project.startServer({
runner: { disabled: true },
webExt: { disabled: true },
dev: { server: { port } },
});
try {
@@ -76,7 +76,7 @@ describe('Dev Mode', () => {
try {
await expect(
project.startServer({
runner: { disabled: true },
webExt: { disabled: true },
dev: { server: { port, strictPort: true } },
}),
).rejects.toThrow();
@@ -1,15 +0,0 @@
import { test, expect } from 'vitest';
import spawn from 'nano-spawn';
// Tests to ensure the total size of the WXT module is as small as possible
// https://pkg-size.dev/wxt
test('Only one version of esbuild should be installed (each version is ~20mb of node_modules)', async () => {
const { stdout } = await spawn('bun', ['why', 'esbuild']);
// This text represents the wxt package being responsible for a version of esbuild?
// If this doesn't work, we'll need to find a better way to check this.
const count = stdout.match(/\n [└├]─ wxt@workspace/g)?.length || 0;
expect(count).toBe(1);
});
@@ -506,7 +506,7 @@ describe('Output Directory Structure', () => {
});
describe('globalName option', () => {
it('generates an IIFE with a default name', async () => {
it('does not generate a IIFE return variable by default', async () => {
const project = new TestProject();
project.addFile(
'entrypoints/content.js',
@@ -518,6 +518,25 @@ describe('Output Directory Structure', () => {
await project.build({ vite: () => ({ build: { minify: false } }) });
const output = await project.serializeFile(
'.output/chrome-mv3/content-scripts/content.js',
);
expect(output.includes('var content')).toBe(false);
});
it('does generates the IIFE name based on the entrypoint name when true', async () => {
const project = new TestProject();
project.addFile(
'entrypoints/content.js',
`export default defineContentScript({
globalName: true,
matches: ["*://*/*"],
main() {},
})`,
);
await project.build({ vite: () => ({ build: { minify: false } }) });
const output = await project.serializeFile(
'.output/chrome-mv3/content-scripts/content.js',
);
@@ -1,26 +0,0 @@
import { describe, it, expect } from 'vitest';
import { TestProject } from '../utils';
describe('Remote Code', () => {
it('should download "url:*" modules and include them in the final bundle', async () => {
const url = 'https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js';
const project = new TestProject();
project.addFile(
'entrypoints/popup.ts',
`import "url:${url}"
export default defineUnlistedScript(() => {})`,
);
await project.build();
const output = await project.serializeFile('.output/chrome-mv3/popup.js');
expect(output).toContain(
// Some text that will hopefully be in future versions of this script
'__lodash_placeholder__',
);
expect(output).not.toContain(url);
expect(
await project.pathExists(`.wxt/cache/${encodeURIComponent(url)}`),
).toBe(true);
});
});
+157
View File
@@ -0,0 +1,157 @@
import { expect, describe, vi, it, beforeEach } from 'vitest';
import { ExtensionRunner } from '../../src';
import { createSafariRunner } from '../../src/core/runners/safari';
import { createManualRunner } from '../../src/core/runners/manual';
import { createWebExtRunner } from '../../src/core/runners/web-ext';
import { createWslRunner } from '../../src/core/runners/wsl';
import { TestProject } from '../utils';
import { wxt } from '../../src/core/wxt';
// Globals for modifying mock behaviors
let isWsl = false;
let importWebExtRunnerError: Error | undefined = undefined;
// Mock runners to create constants for checking equality
type TestExtensionRunner = { name: string } & ExtensionRunner;
function createMockExtensionRunner(name: string): TestExtensionRunner {
return {
name,
closeBrowser: () => Promise.resolve(),
openBrowser: () => Promise.resolve(),
};
}
vi.mock('../../src/core/runners/safari', () => {
const runner = createMockExtensionRunner('safari');
return { createSafariRunner: () => runner };
});
const safariRunner = createSafariRunner();
vi.mock('../../src/core/runners/manual', () => {
const runner = createMockExtensionRunner('manual');
return { createManualRunner: () => runner };
});
const manualRunner = createManualRunner();
vi.mock('../../src/core/runners/web-ext', () => {
const runner = createMockExtensionRunner('web-ext');
return {
createWebExtRunner: () => {
if (!importWebExtRunnerError) return runner;
else throw importWebExtRunnerError;
},
};
});
const webExtRunner = createWebExtRunner();
vi.mock('../../src/core/runners/wsl', () => {
const runner = createMockExtensionRunner('wsl');
return { createWslRunner: () => runner };
});
const wslRunner = createWslRunner();
// Other mocks
vi.mock('is-wsl', () => ({
get default() {
return isWsl;
},
}));
/** Imitate a real module not found error - needs the correct `code` property. */
class ModuleNotFoundError extends Error {
code = 'ERR_MODULE_NOT_FOUND';
constructor(mod: string) {
super(`Cannot find package '${mod}' imported from ...`);
this.name = 'ModuleNotFoundError';
}
}
describe('Runners', () => {
beforeEach(() => {
isWsl = false;
importWebExtRunnerError = undefined;
});
describe('build', () => {
const command = 'build';
it('should use the manual runner as a placeholder since the runner is not used during builds', async () => {
await TestProject.simple().registerWxt(command);
expect(wxt.config.runner).toBe(manualRunner);
});
});
describe('dev', () => {
const command = 'serve';
describe('inside WSL', () => {
beforeEach(() => {
isWsl = true;
});
it('should use the WSL runner', async () => {
await TestProject.simple().registerWxt(command);
expect(wxt.config.runner).toBe(wslRunner);
});
});
describe('web-ext is installed', () => {
it('should use the web-ext runner', async () => {
await TestProject.simple().registerWxt(command);
expect(wxt.config.runner).toBe(webExtRunner);
});
describe('disabled', () => {
it('should use the manual runner', async () => {
await TestProject.simple().registerWxt(command, {
webExt: { disabled: true },
});
expect(wxt.config.runner).toBe(manualRunner);
});
});
});
describe('web-ext is not installed', () => {
beforeEach(() => {
importWebExtRunnerError = new ModuleNotFoundError('web-ext');
});
it('should use the manual runner', async () => {
await TestProject.simple().registerWxt(command);
expect(wxt.config.runner).toBe(manualRunner);
});
});
describe('some other error when importing the web-ext runner', () => {
beforeEach(() => {
importWebExtRunnerError = Error('test');
});
it('should throw the error', async () => {
await expect(TestProject.simple().registerWxt(command)).rejects.toThrow(
importWebExtRunnerError,
);
});
});
describe('targeting safari', () => {
it('should use the safari runner', async () => {
await TestProject.simple().registerWxt(command, {
browser: 'safari',
});
expect(wxt.config.runner).toBe(safariRunner);
});
});
});
});
@@ -324,15 +324,23 @@ describe('TypeScript Project', () => {
----------------------------------------
{
"compilerOptions": {
"lib": [
"ESNext",
"DOM",
"DOM.Iterable"
],
"target": "ESNext",
"module": "ESNext",
"module": "Preserve",
"moduleDetection": "force",
"moduleResolution": "Bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"noEmit": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
"paths": {
"@": [
".."
@@ -406,15 +414,23 @@ describe('TypeScript Project', () => {
----------------------------------------
{
"compilerOptions": {
"lib": [
"ESNext",
"DOM",
"DOM.Iterable"
],
"target": "ESNext",
"module": "ESNext",
"module": "Preserve",
"moduleDetection": "force",
"moduleResolution": "Bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"noEmit": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
"paths": {
"@": [
"../src"
@@ -473,15 +489,23 @@ describe('TypeScript Project', () => {
----------------------------------------
{
"compilerOptions": {
"lib": [
"ESNext",
"DOM",
"DOM.Iterable"
],
"target": "ESNext",
"module": "ESNext",
"module": "Preserve",
"moduleDetection": "force",
"moduleResolution": "Bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"noEmit": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
"paths": {
"example": [
"../example"
+55 -16
View File
@@ -64,21 +64,23 @@ describe('Zipping', () => {
it('should correctly apply template variables for zip file names based on provided config', async () => {
const project = new TestProject({
name: 'test',
version: '1.0.0',
version: '1.0.0-beta.1',
});
project.addFile(
'entrypoints/background.ts',
'export default defineBackground(() => {});',
);
const artifactZip = '.output/test-1.0.0-firefox-development.zip';
const sourcesZip = '.output/test-1.0.0-development-sources.zip';
const artifactZip = '.output/test-1.0.0-beta.1-firefox-dev.zip';
const sourcesZip = '.output/test-1.0.0-beta.1-sources-dev.zip';
await project.zip({
browser: 'firefox',
mode: 'development',
zip: {
artifactTemplate: '{{name}}-{{version}}-{{browser}}-{{mode}}.zip',
sourcesTemplate: '{{name}}-{{version}}-{{mode}}-sources.zip',
artifactTemplate:
'{{name}}-{{packageVersion}}-{{browser}}{{modeSuffix}}.zip',
sourcesTemplate:
'{{name}}-{{packageVersion}}-sources{{modeSuffix}}.zip',
},
});
@@ -108,7 +110,7 @@ describe('Zipping', () => {
expect(await project.pathExists(unzipDir, '.hidden-dir/file')).toBe(false);
});
it('should not zip files inside hidden directories if only the directory is specified', async () => {
it('should zip hidden files and directories when dotSources is enabled', async () => {
const project = new TestProject({
name: 'test',
version: '1.0.0',
@@ -125,17 +127,17 @@ describe('Zipping', () => {
await project.zip({
browser: 'firefox',
zip: {
includeSources: ['.hidden-dir'],
dotSources: true,
},
});
await extract(sourcesZip, { dir: unzipDir });
expect(await project.pathExists(unzipDir, '.hidden-dir/file')).toBe(false);
expect(await project.pathExists(unzipDir, '.hidden-dir/file')).toBe(true);
expect(await project.pathExists(unzipDir, '.hidden-dir/nested/file')).toBe(
false,
true,
);
});
it('should allow zipping hidden files into sources when explicitly listed', async () => {
it('should allow ignoring some hidden files', async () => {
const project = new TestProject({
name: 'test',
version: '1.0.0',
@@ -154,20 +156,57 @@ describe('Zipping', () => {
await project.zip({
browser: 'firefox',
zip: {
includeSources: ['.env', '.hidden-dir/file', '.hidden-dir/nested/**'],
dotSources: true,
excludeSources: ['.hidden-dir/nested'],
},
});
await extract(sourcesZip, { dir: unzipDir });
expect(await project.pathExists(unzipDir, '.env')).toBe(true);
expect(await project.pathExists(unzipDir, '.hidden-dir/file')).toBe(true);
expect(await project.pathExists(unzipDir, '.hidden-dir/nested/file1')).toBe(
true,
false,
);
expect(await project.pathExists(unzipDir, '.hidden-dir/nested/file2')).toBe(
true,
false,
);
});
it('should not include all files when includeSources is provided', async () => {
const project = new TestProject({
name: 'test',
version: '1.0.0',
});
project.addFile(
'entrypoints/background.ts',
'export default defineBackground(() => {});',
);
project.addFile('utils/example.ts', 'export const x = 1;');
project.addFile('secrets/api-key.txt', 'supersecret');
project.addFile('cache/data.json', '{}');
const unzipDir = project.resolvePath('.output/test-1.0.0-sources');
const sourcesZip = project.resolvePath('.output/test-1.0.0-sources.zip');
await project.zip({
browser: 'firefox',
zip: {
includeSources: ['entrypoints/**', 'utils/**'],
},
});
await extract(sourcesZip, { dir: unzipDir });
// Included files should be present
expect(
await project.pathExists(unzipDir, 'entrypoints/background.ts'),
).toBe(true);
expect(await project.pathExists(unzipDir, 'utils/example.ts')).toBe(true);
// Non-included files should NOT be present (allowlist behavior)
expect(await project.pathExists(unzipDir, 'secrets/api-key.txt')).toBe(
false,
);
expect(await project.pathExists(unzipDir, 'cache/data.json')).toBe(false);
});
it('should exclude skipped entrypoints from respective browser sources zip', async () => {
const project = new TestProject({
name: 'test',
@@ -186,8 +225,7 @@ describe('Zipping', () => {
`export default defineContentScript({
matches: ['*://*/*'],
main(ctx) {},
});
`,
});`,
);
const unzipDir = project.resolvePath('.output/test-1.0.0-sources');
const sourcesZip = project.resolvePath('.output/test-1.0.0-sources.zip');
@@ -287,7 +325,8 @@ describe('Zipping', () => {
await project.zip({
zip: {
exclude: ['**/*.json', '!manifest.json'],
// Exclude all JSON files except for ones named `manifest.json`
exclude: ['**/!(manifest).json'],
},
});
+23
View File
@@ -7,6 +7,7 @@ import { glob } from 'tinyglobby';
import {
InlineConfig,
UserConfig,
WxtCommand,
build,
createServer,
prepare,
@@ -14,6 +15,7 @@ import {
} from '../src';
import { normalizePath } from '../src/core/utils';
import { pathExists, readJson } from '../src/core/utils/fs';
import { registerWxt } from '../src/core/wxt';
// Run "bun wxt" to use the "wxt" dev script, not the "wxt" binary from the
// wxt package. This uses the TS files instead of the compiled JS package
@@ -23,6 +25,18 @@ export const WXT_PACKAGE_DIR = resolve(__dirname, '..');
export const E2E_DIR = resolve(WXT_PACKAGE_DIR, 'e2e');
export class TestProject {
/**
* Create the simplest WXT project possible: one blank popup entrypoint, no
* custom config.
*/
static simple(): TestProject {
const project = new TestProject();
project.addFile('entrypoints/popup.html', '<html></html>');
return project;
}
files: Array<[string, string]> = [];
config: UserConfig | undefined;
readonly root: string;
@@ -84,6 +98,15 @@ export class TestProject {
return this.resolvePath(filename);
}
/**
* Register the global `wxt` object for this project. After calling, you can
* import `wxt` like normal and inspect it.
*/
async registerWxt(command: WxtCommand, config: InlineConfig = {}) {
await this.writeProjectToDisk();
await registerWxt(command, { ...config, root: this.root });
}
async prepare(config: InlineConfig = {}) {
await this.writeProjectToDisk();
await prepare({ ...config, root: this.root });
+20 -17
View File
@@ -1,7 +1,7 @@
{
"name": "wxt",
"type": "module",
"version": "0.20.27",
"version": "0.21.1",
"description": "⚡ Next-gen Web Extension Framework",
"license": "MIT",
"scripts": {
@@ -12,15 +12,14 @@
"check:tsc-virtual": "tsc --noEmit -p src/virtual",
"test": "buildc --deps-only -- vitest",
"test:coverage": "bun run test run --coverage",
"sync-releases": "pnpx changelogen@latest gh release",
"prepack": "bun run build"
},
"dependencies": {
"@1natsu/wait-element": "^4.1.2",
"@aklinker1/rollup-plugin-visualizer": "5.12.0",
"@webext-core/fake-browser": "^1.3.4",
"@webext-core/isolated-element": "^1.1.3",
"@webext-core/match-patterns": "^1.0.3",
"@webext-core/fake-browser": "^2.0.1",
"@webext-core/isolated-element": "^1.1.3 || ^2 || ^3",
"@webext-core/match-patterns": "^2.0.0",
"@wxt-dev/browser": "workspace:^",
"@wxt-dev/storage": "workspace:^1.0.0",
"async-mutex": "^0.5.0",
@@ -30,8 +29,7 @@
"ci-info": "^4.4.0",
"consola": "^3.4.2",
"defu": "^6.1.4",
"dotenv-expand": "^12.0.3",
"esbuild": "^0.27.1",
"dotenv-expand": "^13.0.0",
"filesize": "^11.0.17",
"get-port-please": "^3.2.0",
"giget": "^1.2.3 || ^2.0.0 || ^3.0.0",
@@ -50,20 +48,27 @@
"open": "^11.0.0",
"picomatch": "^4.0.3",
"prompts": "^2.4.2",
"publish-browser-extension": "^2.3.0 || ^3.0.2 || ^4.0.5",
"publish-browser-extension": "^5.1.0",
"scule": "^1.3.0",
"tinyglobby": "^0.2.16",
"unimport": "^3.13.1 || ^4.0.0 || ^5.0.0 || ^6.0.0",
"vite": "^5.4.19 || ^6.3.4 || ^7.0.0 || ^8.0.0-0",
"vite-node": "^3.2.4 || ^5.0.0 || ^6.0.0",
"web-ext-run": "^0.2.4"
},
"peerDependencies": {
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0"
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
"vite": "^6.3.4 || ^7.0.0 || ^8.0.0-0",
"web-ext": ">=9.2.0",
"typescript": ">=5.4"
},
"peerDependenciesMeta": {
"eslint": {
"optional": true
},
"web-ext": {
"optional": true
},
"typescript": {
"optional": true
}
},
"devDependencies": {
@@ -83,8 +88,10 @@
"publint": "catalog:",
"tsdown": "catalog:",
"typescript": "catalog:",
"vite": "catalog:",
"vitest": "catalog:",
"vitest-plugin-random-seed": "catalog:"
"vitest-plugin-random-seed": "catalog:",
"web-ext": "^10.5.0"
},
"repository": {
"type": "git",
@@ -192,10 +199,6 @@
"types": "./dist/testing/wxt-vitest-plugin.d.mts",
"default": "./dist/testing/wxt-vitest-plugin.mjs"
},
"./testing": {
"types": "./dist/testing/index.d.mts",
"default": "./dist/testing/index.mjs"
},
"./vite-builder-env": {
"types": "./dist/vite-builder-env.d.ts"
},
@@ -205,7 +208,7 @@
}
},
"engines": {
"node": ">=20.12.0",
"node": ">=22",
"bun": ">=1.2.0"
}
}
+2 -2
View File
@@ -1,6 +1,6 @@
// Custom TS definitions for non-TS packages
declare module 'web-ext-run' {
declare module 'web-ext' {
export interface WebExtRunInstance {
reloadAllExtensions(): Promise<void>;
exit(): Promise<void>;
@@ -14,7 +14,7 @@ declare module 'web-ext-run' {
export default webExt;
}
declare module 'web-ext-run/util/logger' {
declare module 'web-ext/util/logger' {
// https://github.com/mozilla/web-ext/blob/e37e60a2738478f512f1255c537133321f301771/src/util/logger.js#L43
export interface IConsoleStream {
stopCapturing(): void;
+72 -55
View File
@@ -2,9 +2,6 @@ import { Hookable } from 'hookable';
import { mkdir, readdir, rename, rmdir, stat } from 'node:fs/promises';
import { dirname, extname, join, relative, resolve } from 'node:path';
import type * as vite from 'vite';
import { ViteNodeRunner } from 'vite-node/client';
import { ViteNodeServer } from 'vite-node/server';
import { installSourcemapsSupport } from 'vite-node/source-map';
import {
BuildStepOutput,
Entrypoint,
@@ -83,7 +80,6 @@ export async function createViteBuilder(
// TODO: Remove once https://github.com/wxt-dev/wxt/pull/1411 is merged
config.legacy ??= {};
// @ts-ignore: Untyped option:
config.legacy.skipWebSocketTokenCheck = true;
// Solves https://github.com/wxt-dev/wxt/issues/353
@@ -98,7 +94,6 @@ export async function createViteBuilder(
config.plugins ??= [];
config.plugins.push(
wxtPlugins.download(wxtConfig),
wxtPlugins.devHtmlPrerender(wxtConfig, server),
wxtPlugins.resolveVirtualModules(wxtConfig),
wxtPlugins.devServerGlobals(wxtConfig, server),
@@ -110,8 +105,9 @@ export async function createViteBuilder(
wxtPlugins.resolveAppConfig(wxtConfig),
);
if (
// TODO: Should this be migrated to use perEnvironmentState?
wxtConfig.analysis.enabled &&
// If included, vite-node entrypoint loader will increment the
// If included, entrypoint loader will increment the
// bundleAnalysis's internal build index tracker, which we don't want
!baseConfigOptions?.excludeAnalysisPlugin
) {
@@ -149,7 +145,7 @@ export async function createViteBuilder(
iifeReturnValueName = entrypoint.options.globalName(entrypoint);
}
if (entrypoint.options.globalName === false) {
if (!entrypoint.options.globalName) {
plugins.push(wxtPlugins.iifeAnonymous(iifeReturnValueName));
} else {
plugins.push(wxtPlugins.iifeFooter(iifeReturnValueName));
@@ -259,8 +255,7 @@ export async function createViteBuilder(
},
};
};
const createViteNodeImporter = async (paths: string[]) => {
const createImporterEnvironment = async (paths: string[]) => {
const baseConfig = await getBaseConfig({
excludeAnalysisPlugin: true,
});
@@ -273,30 +268,47 @@ export async function createViteBuilder(
wxtPlugins.removeEntrypointMainFunction(wxtConfig, path),
),
};
const config = vite.mergeConfig(baseConfig, envConfig);
const server = await vite.createServer(config);
await server.pluginContainer.buildStart({});
const node = new ViteNodeServer(server);
installSourcemapsSupport({
getSourceMap: (source) => node.getSourceMap(source),
});
const runner = new ViteNodeRunner({
root: server.config.root,
base: server.config.base,
// when having the server and runner in a different context,
// you will need to handle the communication between them
// and pass to this function
fetchModule(id) {
return node.fetchModule(id);
},
resolveId(id, importer) {
return node.resolveId(id, importer);
const importerConfig = vite.mergeConfig(baseConfig, envConfig);
const config = await vite.resolveConfig(
vite.mergeConfig(importerConfig || {}, {
configFile: false,
envDir: false,
cacheDir: process.cwd(),
environments: {
inline: {
consumer: 'server',
dev: {
moduleRunnerTransform: true,
},
resolve: {
external: true,
mainFields: [],
conditions: ['node'],
},
},
},
} satisfies vite.InlineConfig),
'serve',
);
const environment = vite.createRunnableDevEnvironment('inline', config, {
runnerOptions: {
hmr: {
logger: false,
},
},
hot: false,
});
return { runner, server };
await environment.init();
return environment;
};
const requireDefaultExport = (path: string, mod: any) => {
function requireDefaultExport(
path: string,
mod: any,
): asserts mod is { default: unknown } {
const relativePath = relative(wxtConfig.root, path);
if (mod?.default == null) {
const defineFn = relativePath.includes('.content')
@@ -309,36 +321,37 @@ export async function createViteBuilder(
`${relativePath}: Default export not found, did you forget to call "export default ${defineFn}(...)"?`,
);
}
};
}
return {
name: 'Vite',
version: vite.version,
async importEntrypoint(path) {
const env = createExtensionEnvironment();
const { runner, server } = await createViteNodeImporter([path]);
const res = await env.run(() => runner.executeFile(path));
await server.close();
requireDefaultExport(path, res);
return res.default;
const [module] = await this.importEntrypoints([path]);
return module as any;
},
async importEntrypoints(paths) {
const env = createExtensionEnvironment();
const { runner, server } = await createViteNodeImporter(paths);
const res = await env.run(() =>
Promise.all(
paths.map(async (path) => {
const mod = await runner.executeFile(path);
requireDefaultExport(path, mod);
return mod.default;
}),
),
);
await server.close();
return res;
const context = createExtensionEnvironment();
const environment = await createImporterEnvironment(paths);
try {
return await context.run(
async () =>
await Promise.all(
paths.map(async (path) => {
const module = await environment.runner.import(path);
requireDefaultExport(path, module);
return module.default as any;
}),
),
);
} finally {
await environment.close();
}
},
async build(group) {
let entryConfig;
let entryConfig: vite.InlineConfig;
if (Array.isArray(group)) entryConfig = getMultiPageConfig(group);
else if (
group.type === 'content-script-style' ||
@@ -347,12 +360,16 @@ export async function createViteBuilder(
entryConfig = getCssConfig(group);
else entryConfig = getLibModeConfig(group);
const buildConfig = vite.mergeConfig(await getBaseConfig(), entryConfig);
const buildConfig: vite.InlineConfig = vite.mergeConfig(
await getBaseConfig(),
entryConfig,
);
await hooks.callHook(
'vite:build:extendConfig',
toArray(group),
buildConfig,
);
const result = await vite.build(buildConfig);
const chunks = getBuildOutputChunks(result);
return {
@@ -410,16 +427,16 @@ export function getRunnerProfileWatchIgnores(
): string[] {
const root = normalizePath(wxtConfig.root);
const chromiumArgProfiles = extractPathArgs(
wxtConfig.runnerConfig.config?.chromiumArgs,
wxtConfig.webExt.config?.chromiumArgs,
'--user-data-dir',
);
const firefoxArgProfiles = extractPathArgs(
wxtConfig.runnerConfig.config?.firefoxArgs,
wxtConfig.webExt.config?.firefoxArgs,
'-profile',
);
const profiles = [
wxtConfig.runnerConfig.config?.chromiumProfile,
wxtConfig.runnerConfig.config?.firefoxProfile,
wxtConfig.webExt.config?.chromiumProfile,
wxtConfig.webExt.config?.firefoxProfile,
...chromiumArgProfiles,
...firefoxArgProfiles,
].filter((profile): profile is string => typeof profile === 'string');
@@ -1,36 +0,0 @@
import type { Plugin } from 'vite';
import type { ResolvedConfig } from '../../../../types';
import { fetchCached } from '../../../utils/network';
/**
* Downloads any URL imports, like Google Analytics, into virtual modules so
* they are bundled with the extension instead of depending on remote code at
* runtime.
*
* @example
* import 'url:https://google-tagmanager.com/gtag?id=XYZ';
*/
export function download(config: ResolvedConfig): Plugin {
return {
name: 'wxt:download',
enforce: 'pre',
resolveId: {
filter: {
id: /^url:/,
},
handler(id) {
return `\0${id}`;
},
},
load: {
filter: {
//eslint-disable-next-line no-control-regex
id: /^\x00url:/,
},
handler(id) {
const url = id.replace('\0url:', '');
return fetchCached(url, config);
},
},
};
}
@@ -1,6 +1,5 @@
export * from './devHtmlPrerender';
export * from './devServerGlobals';
export * from './download';
export * from './resolveVirtualModules';
export * from './tsconfigPaths';
export * from './noopBackground';
@@ -22,7 +22,7 @@ export function removeEntrypointMainFunction(
},
handler(code) {
const newCode = removeMainFunctionCode(code);
config.logger.debug('vite-node transformed entrypoint', path);
config.logger.debug('transformed entrypoint', path);
config.logger.debug(`Original:\n---\n${code}\n---`);
config.logger.debug(`Transformed:\n---\n${newCode.code}\n---`);
return newCode;
+1 -18
View File
@@ -13,24 +13,7 @@ import { styleText } from 'node:util';
*
* @param config Optional config that will override your `<root>/wxt.config.ts`.
*/
export async function clean(config?: InlineConfig): Promise<void>;
/**
* Remove generated/temp files from the directory.
*
* @deprecated
* @example
* await clean();
*
* @param root The directory to look for generated/temp files in. Defaults to
* `process.cwd()`. Can be relative to `process.cwd()` or absolute.
*/
export async function clean(root?: string): Promise<void>;
export async function clean(config?: string | InlineConfig) {
if (typeof config === 'string') {
config = { root: config };
}
export async function clean(config?: InlineConfig): Promise<void> {
await registerWxt('build', config);
wxt.logger.info('Cleaning Project');
+7 -13
View File
@@ -1,7 +1,6 @@
import chokidar from 'chokidar';
import { InlineConfig, ServerInfo, WxtDevServer } from '../types';
import { internalBuild } from './utils/building';
import { createExtensionRunner } from './runners';
import { deinitWxtModules, initWxtModules, registerWxt, wxt } from './wxt';
import { unnormalizePath } from './utils/paths';
import { createKeyboardShortcuts } from './keyboard-shortcuts';
@@ -37,10 +36,7 @@ async function createServerInternal(): Promise<WxtDevServer> {
return { host, port, origin };
};
let [runner, builderServer] = await Promise.all([
createExtensionRunner(),
wxt.builder.createServer(getServerInfo()),
]);
let builderServer = await wxt.builder.createServer(getServerInfo());
// Used to track if modules need to be re-initialized
let wasStopped = false;
@@ -67,7 +63,6 @@ async function createServerInternal(): Promise<WxtDevServer> {
async start() {
if (wasStopped) {
await wxt.reloadConfig();
runner = await createExtensionRunner();
builderServer = await wxt.builder.createServer(getServerInfo());
await initWxtModules();
}
@@ -99,7 +94,7 @@ async function createServerInternal(): Promise<WxtDevServer> {
async stop() {
wasStopped = true;
keyboardShortcuts.stop();
await runner.closeBrowser?.();
await wxt.config.runner.closeBrowser?.();
await builderServer.close();
await wxt.hooks.callHook('server:closed', wxt, server);
@@ -123,15 +118,14 @@ async function createServerInternal(): Promise<WxtDevServer> {
server.ws.send('wxt:reload-extension');
},
async restartBrowser() {
await runner.closeBrowser?.();
await wxt.config.runner.closeBrowser?.();
keyboardShortcuts.stop();
await wxt.reloadConfig();
runner = await createExtensionRunner();
await runner.openBrowser();
await wxt.config.runner.openBrowser();
keyboardShortcuts.start();
keyboardShortcuts.printHelp({
canReopenBrowser:
!wxt.config.runnerConfig.config.disabled && !!runner.canOpen?.(),
!wxt.config.webExt.config.disabled && !!wxt.config.runner.canOpen?.(),
});
},
};
@@ -170,11 +164,11 @@ async function createServerInternal(): Promise<WxtDevServer> {
}
// Open browser after everything is ready to go.
await runner.openBrowser();
await wxt.config.runner.openBrowser();
keyboardShortcuts.start();
keyboardShortcuts.printHelp({
canReopenBrowser:
!wxt.config.runnerConfig.config.disabled && !!runner.canOpen?.(),
!wxt.config.webExt.config.disabled && !!wxt.config.runner.canOpen?.(),
});
};
@@ -1,14 +1,5 @@
import consola from 'consola';
import { WebExtConfig } from '../types';
/** @deprecated Use `defineWebExtConfig` instead. Same function, different name. */
export function defineRunnerConfig(config: WebExtConfig): WebExtConfig {
consola.warn(
'`defineRunnerConfig` is deprecated, use `defineWebExtConfig` instead. See https://wxt.dev/guide/resources/upgrading.html#v0-19-0-rarr-v0-20-0',
);
return defineWebExtConfig(config);
}
/**
* Configure how [`web-ext`](https://github.com/mozilla/web-ext) starts the
* browser during development.
+12 -4
View File
@@ -297,15 +297,23 @@ async function getTsConfigEntry(): Promise<WxtDirFileEntry> {
const tsconfig = {
compilerOptions: {
// Environment setup & latest features
lib: ['ESNext', 'DOM', 'DOM.Iterable'],
target: 'ESNext',
module: 'ESNext',
module: 'Preserve',
moduleDetection: 'force',
// Bundler mode
moduleResolution: 'Bundler',
allowImportingTsExtensions: true,
verbatimModuleSyntax: true,
noEmit: true,
esModuleInterop: true,
forceConsistentCasingInFileNames: true,
resolveJsonModule: true,
// Best practices
strict: true,
skipLibCheck: true,
noFallthroughCasesInSwitch: true,
noUncheckedIndexedAccess: true,
noImplicitOverride: true,
// Project settings
paths,
},
include: [`${getTsconfigPath(wxt.config.root)}/**/*`, './wxt.d.ts'],
+77 -48
View File
@@ -1,19 +1,20 @@
import { loadConfig } from 'c12';
import { resolve as esmResolve } from 'import-meta-resolve';
import {
InlineConfig,
ResolvedConfig,
UserConfig,
ConfigEnv,
UserManifestFn,
UserManifest,
WebExtConfig,
WxtResolvedUnimportOptions,
InlineConfig,
Logger,
ResolvedConfig,
ResolvedEslintrc,
UserConfig,
UserManifest,
UserManifestFn,
WebExtConfig,
WxtCommand,
WxtModule,
WxtModuleWithMetadata,
ResolvedEslintrc,
WxtResolvedUnimportOptions,
ExtensionRunner,
} from '../types';
import path from 'node:path';
import { createFsCache } from './utils/cache';
@@ -29,6 +30,10 @@ import { safeStringToNumber } from './utils/number';
import { loadEnv } from './utils/env';
import { getPort } from 'get-port-please';
import { fileURLToPath, pathToFileURL } from 'node:url';
import { createSafariRunner } from './runners/safari';
import isWsl from 'is-wsl';
import { createWslRunner } from './runners/wsl';
import { createManualRunner } from './runners/manual';
/**
* Given an inline config, discover the config file if necessary, merge the
@@ -119,19 +124,13 @@ export async function resolveConfig(
const outDir = path.resolve(outBaseDir, outDirTemplate);
const reloadCommand = mergedConfig.dev?.reloadCommand ?? 'Alt+R';
if (inlineConfig.runner != null || userConfig.runner != null) {
logger.warn(
'`InlineConfig#runner` is deprecated, use `InlineConfig#webExt` instead. See https://wxt.dev/guide/resources/upgrading.html#v0-19-0-rarr-v0-20-0',
);
}
const runnerConfig = await loadConfig<WebExtConfig>({
const webExt = await loadConfig<WebExtConfig>({
name: 'web-ext',
cwd: root,
globalRc: true,
rcFile: '.webextrc',
overrides: inlineConfig.webExt ?? inlineConfig.runner,
defaults: userConfig.webExt ?? userConfig.runner,
overrides: inlineConfig.webExt,
defaults: userConfig.webExt,
});
// Make sure alias are absolute
const alias = Object.fromEntries(
@@ -146,20 +145,9 @@ export async function resolveConfig(
let devServerConfig: ResolvedConfig['dev']['server'];
if (command === 'serve') {
if (mergedConfig.dev?.server?.hostname)
logger.warn(
`The 'hostname' option is deprecated, please use 'host' or 'origin' depending on your circumstances.`,
);
const host =
mergedConfig.dev?.server?.host ??
mergedConfig.dev?.server?.hostname ??
'localhost';
const host = mergedConfig.dev?.server?.host ?? 'localhost';
let port = mergedConfig.dev?.server?.port;
const origin =
mergedConfig.dev?.server?.origin ??
mergedConfig.dev?.server?.hostname ??
'localhost';
const origin = mergedConfig.dev?.server?.origin ?? 'localhost';
const strictPort = mergedConfig.dev?.server?.strictPort ?? false;
if (port == null || !isFinite(port)) {
port = await getPort({
@@ -225,7 +213,11 @@ export async function resolveConfig(
publicDir,
wxtModuleDir,
root,
runnerConfig,
webExt,
runner:
command === 'serve'
? await resolveRunner(browser, logger, mergedConfig)
: createManualRunner(),
srcDir,
typesDir,
wxtDir,
@@ -308,10 +300,11 @@ function resolveZipConfig(
const downloadedPackagesDir = path.resolve(root, '.wxt/local_modules');
return {
name: undefined,
sourcesTemplate: '{{name}}-{{version}}-sources.zip',
artifactTemplate: '{{name}}-{{version}}-{{browser}}.zip',
sourcesTemplate: '{{name}}-{{packageVersion}}-sources{{modeSuffix}}.zip',
artifactTemplate:
'{{name}}-{{packageVersion}}-{{browser}}{{modeSuffix}}.zip',
sourcesRoot: root,
includeSources: [],
includeSources: mergedConfig.zip?.includeSources ?? ['**/*'],
compressionLevel: 9,
...mergedConfig.zip,
zipSources:
@@ -321,8 +314,6 @@ function resolveZipConfig(
'**/node_modules',
// WXT files
'**/web-ext.config.ts',
// Hidden files
'**/.*',
// Tests
'**/__tests__/**',
'**/*.+(test|spec).?(c|m)+(j|t)s?(x)',
@@ -331,6 +322,7 @@ function resolveZipConfig(
// From user
...(mergedConfig.zip?.excludeSources ?? []),
],
dotSources: mergedConfig.zip?.dotSources ?? false,
downloadPackages: mergedConfig.zip?.downloadPackages ?? [],
downloadedPackagesDir,
};
@@ -365,7 +357,11 @@ async function getUnimportOptions(
config: InlineConfig,
): Promise<WxtResolvedUnimportOptions> {
const disabled = config.imports === false;
const eslintrc = await getUnimportEslintOptions(wxtDir, config.imports);
const eslintrc = await getUnimportEslintOptions(
logger,
wxtDir,
config.imports,
);
// mlly sometimes picks up things as exports that aren't. That's what this array contains.
const invalidExports = ['options'];
@@ -375,7 +371,7 @@ async function getUnimportOptions(
];
const defaultOptions: WxtResolvedUnimportOptions = {
imports: [{ name: 'fakeBrowser', from: 'wxt/testing' }],
imports: [{ name: 'fakeBrowser', from: 'wxt/testing/fake-browser' }],
presets: [
{
from: 'wxt/browser',
@@ -505,25 +501,34 @@ async function getUnimportOptions(
}
async function getUnimportEslintOptions(
logger: Logger,
wxtDir: string,
options: InlineConfig['imports'],
): Promise<ResolvedEslintrc> {
const inlineEnabled =
options === false ? false : (options?.eslintrc?.enabled ?? 'auto');
const version = await getEslintVersion();
const major = parseInt(version[0]);
let enabled: ResolvedEslintrc['enabled'];
switch (inlineEnabled) {
case 'auto':
const version = await getEslintVersion();
let major = parseInt(version[0]);
if (isNaN(major)) enabled = false;
if (major <= 8) enabled = 8;
else if (major >= 9) enabled = 9;
// NaN
else enabled = false;
break;
case true:
enabled = 8;
if (isNaN(major)) {
if (inlineEnabled === true) {
logger.warn(
'Could not determine installed ESLint version, `eslint-auto-imports.mjs` not generated',
);
}
enabled = false;
} else if (major <= 8) {
enabled = 8;
} else if (major >= 9) {
enabled = 9;
} else {
enabled = false;
}
break;
default:
enabled = inlineEnabled;
@@ -533,7 +538,7 @@ async function getUnimportEslintOptions(
enabled,
filePath: path.resolve(
wxtDir,
enabled === 9 ? 'eslint-auto-imports.mjs' : 'eslintrc-auto-import.json',
enabled === 8 ? 'eslintrc-auto-import.json' : 'eslint-auto-imports.mjs',
),
globalsPropValue: true,
};
@@ -651,3 +656,27 @@ export async function resolveWxtUserModules(
);
return [...npmModules, ...localModules];
}
async function resolveRunner(
browser: string,
logger: Logger,
mergedConfig: InlineConfig,
): Promise<ExtensionRunner> {
if (browser === 'safari') return createSafariRunner();
if (isWsl) return createWslRunner();
try {
// This module imports `web-ext`, so if it fails, we know `web-ext` isn't installed
const { createWebExtRunner } = await import('./runners/web-ext');
return mergedConfig.webExt?.disabled
? createManualRunner()
: createWebExtRunner();
} catch (err: any) {
if (err?.code !== 'ERR_MODULE_NOT_FOUND') throw err;
logger.debug('Error loading the web-ext runner', err);
}
return createManualRunner();
}
@@ -1,87 +0,0 @@
import { describe, expect, it, vi } from 'vitest';
import { createExtensionRunner } from '..';
import { setFakeWxt } from '../../utils/testing/fake-objects';
import { mock } from 'vitest-mock-extended';
import { createSafariRunner } from '../safari';
import { createWslRunner } from '../wsl';
import { createManualRunner } from '../manual';
import { isWsl } from '../../utils/wsl';
import { createWebExtRunner } from '../web-ext';
import { ExtensionRunner } from '../../../types';
vi.mock('../../utils/wsl');
const isWslMock = vi.mocked(isWsl);
vi.mock('../safari');
const createSafariRunnerMock = vi.mocked(createSafariRunner);
vi.mock('../wsl');
const createWslRunnerMock = vi.mocked(createWslRunner);
vi.mock('../manual');
const createManualRunnerMock = vi.mocked(createManualRunner);
vi.mock('../web-ext');
const createWebExtRunnerMock = vi.mocked(createWebExtRunner);
describe('createExtensionRunner', () => {
it('should return a Safari runner when browser is "safari"', async () => {
setFakeWxt({
config: {
browser: 'safari',
},
});
const safariRunner = mock<ExtensionRunner>();
createSafariRunnerMock.mockReturnValue(safariRunner);
await expect(createExtensionRunner()).resolves.toBe(safariRunner);
});
it('should return a WSL runner when `is-wsl` is true', async () => {
isWslMock.mockReturnValueOnce(true);
setFakeWxt({
config: {
browser: 'chrome',
},
});
const wslRunner = mock<ExtensionRunner>();
createWslRunnerMock.mockReturnValue(wslRunner);
await expect(createExtensionRunner()).resolves.toBe(wslRunner);
});
it('should return a manual runner when `runner.disabled` is true', async () => {
isWslMock.mockReturnValueOnce(false);
setFakeWxt({
config: {
browser: 'chrome',
runnerConfig: {
config: {
disabled: true,
},
},
},
});
const manualRunner = mock<ExtensionRunner>();
createManualRunnerMock.mockReturnValue(manualRunner);
await expect(createExtensionRunner()).resolves.toBe(manualRunner);
});
it('should return a web-ext runner otherwise', async () => {
setFakeWxt({
config: {
browser: 'chrome',
runnerConfig: {
config: {
disabled: undefined,
},
},
},
});
const manualRunner = mock<ExtensionRunner>();
createWebExtRunnerMock.mockReturnValue(manualRunner);
await expect(createExtensionRunner()).resolves.toBe(manualRunner);
});
});
-16
View File
@@ -1,16 +0,0 @@
import type { ExtensionRunner } from '../../types';
import { isWsl } from '../utils/wsl';
import { wxt } from '../wxt';
import { createManualRunner } from './manual';
import { createSafariRunner } from './safari';
import { createWebExtRunner } from './web-ext';
import { createWslRunner } from './wsl';
export async function createExtensionRunner(): Promise<ExtensionRunner> {
if (wxt.config.browser === 'safari') return createSafariRunner();
if (isWsl()) return createWslRunner();
if (wxt.config.runnerConfig.config?.disabled) return createManualRunner();
return createWebExtRunner();
}
+6 -6
View File
@@ -1,8 +1,10 @@
import type { WebExtRunInstance } from 'web-ext-run';
import type { WebExtRunInstance } from 'web-ext';
import { ExtensionRunner } from '../../types';
import { formatDuration } from '../utils/time';
import defu from 'defu';
import { wxt } from '../wxt';
import webExt from 'web-ext';
import { consoleStream } from 'web-ext/util/logger';
/** Create an `ExtensionRunner` backed by `web-ext`. */
export function createWebExtRunner(): ExtensionRunner {
@@ -16,13 +18,12 @@ export function createWebExtRunner(): ExtensionRunner {
const startTime = Date.now();
// Use WXT's logger instead of web-ext's built-in one.
const webExtLogger = await import('web-ext-run/util/logger');
webExtLogger.consoleStream.write = ({ level, msg, name }) => {
consoleStream.write = ({ level, msg, name }) => {
if (level >= ERROR_LOG_LEVEL) wxt.logger.error(name, msg);
if (level >= WARN_LOG_LEVEL) wxt.logger.warn(msg);
};
const wxtUserConfig = wxt.config.runnerConfig.config;
const wxtUserConfig = wxt.config.webExt.config;
const userConfig = {
browserConsole: wxtUserConfig?.openConsole,
devtools: wxtUserConfig?.openDevtools,
@@ -69,8 +70,7 @@ export function createWebExtRunner(): ExtensionRunner {
wxt.logger.debug('web-ext config:', finalConfig);
wxt.logger.debug('web-ext options:', options);
const webExt = await import('web-ext-run');
runner = await webExt.default.cmd.run(finalConfig, options);
runner = await webExt.cmd.run(finalConfig, options);
const duration = Date.now() - startTime;
wxt.logger.success(`Opened browser in ${formatDuration(duration)}`);
@@ -1,71 +0,0 @@
import { describe, it, expect } from 'vitest';
import { picomatchMultiple } from '../picomatch-multiple';
describe('picomatchMultiple', () => {
it('should return false if the pattern array is undefined', () => {
const patterns = undefined;
const search = 'test.json';
expect(picomatchMultiple(search, patterns)).toBe(false);
});
it('should return false if the pattern array is empty', () => {
const patterns: string[] = [];
const search = 'test.json';
expect(picomatchMultiple(search, patterns)).toBe(false);
});
it('should return true if the pattern array contains a match', () => {
const patterns = ['test.yml', 'test.json'];
const search = 'test.json';
expect(picomatchMultiple(search, patterns)).toBe(true);
});
it('should return false if the pattern array does not contain a match', () => {
const patterns = ['test.yml', 'test.json'];
const search = 'test.txt';
expect(picomatchMultiple(search, patterns)).toBe(false);
});
it('should return false if the pattern matches a negative pattern', () => {
const patterns = ['test.*', '!test.json'];
const search = 'test.json';
expect(picomatchMultiple(search, patterns)).toBe(false);
});
it('should return false if the pattern matches a negative pattern, regardless of order', () => {
const patterns = ['!test.json', 'test.*'];
const search = 'test.json';
expect(picomatchMultiple(search, patterns)).toBe(false);
});
it('should support extglob-like extension matching', () => {
const patterns = ['content.[jt]s?(x)'];
expect(picomatchMultiple('content.ts', patterns)).toBe(true);
expect(picomatchMultiple('content.jsx', patterns)).toBe(true);
expect(picomatchMultiple('content.css', patterns)).toBe(false);
});
it('should support nested paths', () => {
const patterns = ['foo/**/*.ts'];
expect(picomatchMultiple('foo/bar/baz.ts', patterns)).toBe(true);
expect(picomatchMultiple('foo/bar/baz.js', patterns)).toBe(false);
});
it('should preserve include/exclude interaction used by zip filtering', () => {
const include = ['special.txt'];
const exclude = ['**/*.txt'];
const search = 'special.txt';
const shouldInclude =
picomatchMultiple(search, include) || !picomatchMultiple(search, exclude);
expect(shouldInclude).toBe(true);
});
});
@@ -103,7 +103,7 @@ describe('Detect Dev Changes', () => {
const runnerFile = '/root/web-ext.config.ts';
setFakeWxt({
config: {
runnerConfig: {
webExt: {
configFile: runnerFile,
},
},
@@ -63,7 +63,7 @@ export function detectDevChanges(
const isRunnerChange = some(
relevantChangedFiles,
(file) => file === wxt.config.runnerConfig.configFile,
(file) => file === wxt.config.webExt.configFile,
);
if (isRunnerChange) return { type: 'browser-restart' };
@@ -146,7 +146,7 @@ export function getRelevantDevChangedFiles(
return Array.from(new Set(changedFiles)).filter((changedFile) => {
if (changedFile === wxt.config.userConfigMetadata.configFile) return true;
if (changedFile.startsWith(wxt.config.modulesDir)) return true;
if (changedFile === wxt.config.runnerConfig.configFile) return true;
if (changedFile === wxt.config.webExt.configFile) return true;
if (changedFile.startsWith(wxt.config.publicDir)) return true;
return findEffectedSteps(changedFile, currentOutput).length > 0;
});
@@ -1,38 +0,0 @@
import picomatch, { PicomatchOptions } from 'picomatch';
/**
* Run [`picomatch`](https://npmjs.com/package/picomatch) against multiple
* patterns.
*
* Supports negated patterns, the order does not matter. If your `search` string
* matches any of the negative patterns, it will return `false`.
*
* @example
* picomatchMultiple('a.json', ['*.json', '!b.json']); // => true
* picomatchMultiple('b.json', ['*.json', '!b.json']); // => false
*/
export function picomatchMultiple(
search: string,
patterns: string[] | undefined,
options?: PicomatchOptions,
): boolean {
if (patterns == null) return false;
const negatePatterns: string[] = [];
const positivePatterns: string[] = [];
for (const pattern of patterns) {
if (pattern[0] === '!') negatePatterns.push(pattern.slice(1));
else positivePatterns.push(pattern);
}
if (
negatePatterns.some((negatePattern) =>
picomatch(negatePattern, options)(search),
)
)
return false;
return positivePatterns.some((positivePattern) =>
picomatch(positivePattern, options)(search),
);
}
@@ -264,9 +264,10 @@ export const fakeResolvedConfig = fakeObjectCreator<ResolvedConfig>(() => {
publicDir: fakeDir(),
root: fakeDir(),
wxtModuleDir: fakeDir(),
runnerConfig: {
webExt: {
config: {},
},
runner: mock(),
debug: faker.datatype.boolean(),
srcDir: fakeDir(),
typesDir: fakeDir(),
@@ -284,6 +285,7 @@ export const fakeResolvedConfig = fakeObjectCreator<ResolvedConfig>(() => {
artifactTemplate: '{{name}}-{{version}}.zip',
includeSources: [],
excludeSources: [],
dotSources: false,
exclude: [],
sourcesRoot: fakeDir(),
sourcesTemplate: '{{name}}-sources.zip',
+1 -1
View File
@@ -22,7 +22,7 @@ export function withTimeout<T>(
}
/**
* @deprecated Don't use in production, just for testing and slowing things
* @internal Don't use in production, just for testing and slowing things
* down.
*/
export function sleep(ms: number): Promise<void> {
+30 -19
View File
@@ -11,7 +11,6 @@ import { registerWxt, wxt } from './wxt';
import JSZip from 'jszip';
import { glob } from 'tinyglobby';
import { normalizePath } from './utils';
import { picomatchMultiple } from './utils/picomatch-multiple';
/**
* Build and zip the extension for distribution.
@@ -32,15 +31,22 @@ export async function zip(config?: InlineConfig): Promise<string[]> {
const projectName =
wxt.config.zip.name ??
safeFilename(packageJson?.name || path.basename(process.cwd()));
const modeSuffixes: Record<string, string | undefined> = {
production: '',
development: '-dev',
};
const modeSuffix = modeSuffixes[wxt.config.mode] ?? `-${wxt.config.mode}`;
const applyTemplate = (template: string): string =>
template
.replaceAll('{{name}}', projectName)
.replaceAll('{{browser}}', wxt.config.browser)
.replaceAll('{{version}}', output.manifest.version)
.replaceAll(
'{{version}}',
'{{versionName}}',
output.manifest.version_name ?? output.manifest.version,
)
.replaceAll('{{packageVersion}}', packageJson?.version)
.replaceAll('{{modeSuffix}}', modeSuffix)
.replaceAll('{{mode}}', wxt.config.mode)
.replaceAll('{{manifestVersion}}', `mv${wxt.config.manifestVersion}`);
@@ -64,7 +70,7 @@ export async function zip(config?: InlineConfig): Promise<string[]> {
...skippedEntrypoints.map((entry) =>
path.relative(wxt.config.zip.sourcesRoot, entry.inputPath),
),
].map((paths) => paths.replaceAll('\\', '/'));
].map((paths) => paths.replaceAll('\\', '/')); // TODO: Use normalizePath?
await wxt.hooks.callHook('zip:sources:start', wxt);
const { overrides, files: downloadedPackages } =
await downloadPrivatePackages();
@@ -73,7 +79,7 @@ export async function zip(config?: InlineConfig): Promise<string[]> {
wxt.config.outBaseDir,
sourcesZipFilename,
);
await zipDir(wxt.config.zip.sourcesRoot, sourcesZipPath, {
const files = await zipDir(wxt.config.zip.sourcesRoot, sourcesZipPath, {
include: wxt.config.zip.includeSources,
exclude: excludeSources,
transform(absolutePath, zipPath, content) {
@@ -82,9 +88,17 @@ export async function zip(config?: InlineConfig): Promise<string[]> {
}
},
additionalFiles: downloadedPackages,
dot: wxt.config.zip.dotSources,
});
zipFiles.push(sourcesZipPath);
await wxt.hooks.callHook('zip:sources:done', wxt, sourcesZipPath);
await printFileList(
wxt.logger.info,
`Sources included in \`${sourcesZipFilename}\``,
wxt.config.zip.sourcesRoot,
files,
);
}
await printFileList(
@@ -112,29 +126,24 @@ async function zipDir(
) => Promise<string | undefined | void> | string | undefined | void;
additionalWork?: (archive: JSZip) => Promise<void> | void;
additionalFiles?: string[];
dot?: boolean;
},
): Promise<void> {
): Promise<string[]> {
const archive = new JSZip();
const files = (
await glob(['**/*', ...(options?.include || [])], {
cwd: directory,
// Ignore node_modules, otherwise this glob step takes forever
ignore: ['**/node_modules'],
onlyFiles: true,
expandDirectories: false,
})
).filter((relativePath) => {
return (
picomatchMultiple(relativePath, options?.include) ||
!picomatchMultiple(relativePath, options?.exclude)
);
// includeSources patterns are used directly (defaults to ['**/*'] from config)
// excludeSources patterns are passed to glob's ignore option for efficient filtering
const files = await glob(options?.include ?? ['**/*'], {
cwd: directory,
ignore: options?.exclude ?? [],
onlyFiles: true,
dot: options?.dot,
});
const filesToZip = [
...files,
...(options?.additionalFiles ?? []).map((file) =>
path.relative(directory, file),
),
];
].sort();
for (const file of filesToZip) {
const absolutePath = path.resolve(directory, file);
if (file.endsWith('.json')) {
@@ -165,6 +174,8 @@ async function zipDir(
.on('error', reject)
.on('close', resolve),
);
return filesToZip;
}
async function downloadPrivatePackages() {
-9
View File
@@ -1,9 +0,0 @@
/**
* Utilities for unit testing WXT extensions.
*
* @module wxt/testing
* @deprecated Use `wxt/testing/*` instead to prevent issues with JSDOM or
* HappyDOM environments. Will be removed in the next major version of WXT.
*/
export * from './fake-browser';
export * from './wxt-vitest-plugin';
@@ -2,12 +2,11 @@
* Contains a Vitest plugin that configures your test environment to work with
* WXT projects.
*
* @module wxt/testing/vitest
* @module wxt/testing/vitest-plugin
*/
import type * as vite from 'vite';
import {
download,
tsconfigPaths,
globals,
extensionApiMock,
@@ -41,7 +40,6 @@ export async function WxtVitest(
const plugins: vite.PluginOption[] = [
globals(wxt.config),
download(wxt.config),
tsconfigPaths(wxt.config),
resolveAppConfig(wxt.config),
extensionApiMock(wxt.config),
+71 -41
View File
@@ -1,5 +1,5 @@
import type * as vite from 'vite';
import { UnimportOptions, Import } from 'unimport';
import { Import, UnimportOptions } from 'unimport';
import { LogLevel } from 'consola';
import type { ContentScriptContext } from './utils/content-script-context';
import type { PluginVisualizerOptions } from '@aklinker1/rollup-plugin-visualizer';
@@ -184,8 +184,6 @@ export interface InlineConfig {
* `web-ext.config.ts` file.
*/
webExt?: WebExtConfig;
/** @deprecated Use `webExt` instead. Same option, just renamed. */
runner?: WebExtConfig;
zip?: {
/**
* Configure the filename output when zipping files.
@@ -194,16 +192,20 @@ export interface InlineConfig {
*
* - <span v-pre>`{{name}}`</span> - The project's name converted to
* kebab-case
* - <span v-pre>`{{version}}`</span> - The version_name or version from the
* manifest
* - <span v-pre>`{{version}}`</span> - The version from the manifest
* - <span v-pre>`{{versionName}}`</span> - The `version_name` from the
* manifest or, if not set (i.e. if built for Firefox), the `version` from
* the manifest
* - <span v-pre>`{{packageVersion}}`</span> - The version from the
* package.json
* - <span v-pre>`{{browser}}`</span> - The target browser from the
* `--browser` CLI flag
* - <span v-pre>`{{mode}}`</span> - The current mode
* - <span v-pre>`{{modeSuffix}}`</span>: A suffix based on the mode ('-dev'
* for development, '' for production)
* - <span v-pre>`{{manifestVersion}}`</span> - Either "2" or "3"
*
* @default '{{name}}-{{version}}-{{browser}}.zip'
* @default '{{name}}-{{packageVersion}}-{{browser}}{{modeSuffix}}.zip'
*/
artifactTemplate?: string;
/**
@@ -223,16 +225,20 @@ export interface InlineConfig {
*
* - <span v-pre>`{{name}}`</span> - The project's name converted to
* kebab-case
* - <span v-pre>`{{version}}`</span> - The version_name or version from the
* manifest
* - <span v-pre>`{{version}}`</span> - The version from the manifest
* - <span v-pre>`{{versionName}}`</span> - The `version_name` from the
* manifest or, if not set (i.e. if built for Firefox), the `version` from
* the manifest
* - <span v-pre>`{{packageVersion}}`</span> - The version from the
* package.json
* - <span v-pre>`{{browser}}`</span> - The target browser from the
* `--browser` CLI flag
* - <span v-pre>`{{mode}}`</span> - The current mode
* - <span v-pre>`{{modeSuffix}}`</span>: A suffix based on the mode ('-dev'
* for development, '' for production)
* - <span v-pre>`{{manifestVersion}}`</span> - Either "2" or "3"
*
* @default '{{name}}-{{version}}-sources.zip'
* @default '{{name}}-{{packageVersion}}-sources{{modeSuffix}}.zip'
*/
sourcesTemplate?: string;
/**
@@ -248,25 +254,39 @@ export interface InlineConfig {
*/
sourcesRoot?: string;
/**
* [Picomatch](https://www.npmjs.com/package/picomatch) patterns of files to
* include when creating a ZIP of all your source code for Firefox. Patterns
* are relative to your `config.zip.sourcesRoot`.
* [Tinyglobby](https://npmjs.org/tinyglobby) patterns of files to include
* when creating a ZIP of all your source code for Firefox. Patterns are
* relative to your `config.zip.sourcesRoot`.
*
* This setting overrides `excludeSources`. So if a file matches both lists,
* it is included in the ZIP.
* Sources ZIP files are created using standard allowlist/blocklist
* behavior:
*
* - You specify a pattern to "include" (via `includeSources`), then a pattern
* to "exclude" from the included files (via `excludeSources`).
*
* By default, this option includes all files except for hidden files and
* directories (files/directories starting with a `.`).
*
* If you want to include hidden files/directories in your sources ZIP, see
* `InlineConfig.zip.dotSources`.
*
* @example
* [
* 'coverage', // Include the coverage directory in the `sourcesRoot`
* ];
* ['entrypoints/**', 'wxt.config.ts', 'package.json', 'tsconfig.json'];
*/
includeSources?: string[];
/**
* [Picomatch](https://www.npmjs.com/package/picomatch) patterns of files to
* exclude when creating a ZIP of all your source code for Firefox. Patterns
* are relative to your `config.zip.sourcesRoot`.
* [Tinyglobby](https://npmjs.org/tinyglobby) patterns of files to exclude
* when creating a ZIP of all your source code for Firefox. Patterns are
* relative to your `config.zip.sourcesRoot`.
*
* Hidden files, node_modules, and tests are ignored by default.
* By default, WXT excludes some files:
*
* - `node_modules`
* - Tests files and directories
* - Output directory
*
* Any values specified in this option will be merged with the ones above -
* you cannot replace the default values, only add to them.
*
* @example
* [
@@ -275,13 +295,31 @@ export interface InlineConfig {
*/
excludeSources?: string[];
/**
* [Picomatch](https://www.npmjs.com/package/picomatch) patterns of files to
* exclude when zipping the extension.
* Include hidden files/directories in your sources ZIP.
*
* [Tinyglobby](https://npmjs.org/tinyglobby) does not match against files
* and directory that start with a `.` by default. For example, if you need
* to include a `.env` file, you need to set this to `true`, then exclude
* other hidden files/directories in `excludeSources`.
*
* **Be very careful when this is enabled - WXT may include files with
* secrets in your ZIP you did not intend to share with Mozilla or upload to
* other places**. Make sure all hidden files you don't want to include are
* added to `excludeSources`.
*
* @default false
*/
dotSources?: boolean;
/**
* [Tinyglobby](https://npmjs.org/tinyglobby) patterns of files to exclude
* when zipping the extension.
*
* @example
* [
* '**\/*.map', // Exclude all sourcemaps
* ];
*
* @default [ ]
*/
exclude?: string[];
/**
@@ -412,13 +450,6 @@ export interface InlineConfig {
* @default false
*/
strictPort?: boolean;
/**
* Hostname to run the dev server on.
*
* @deprecated Use `host` to specify the interface to bind to, or use
* `origin` to specify the dev server hostname.
*/
hostname?: string;
};
/**
* Controls whether a custom keyboard shortcut command, `Alt+R`, is added
@@ -644,12 +675,12 @@ export interface BaseScriptEntrypointOptions extends BaseEntrypointOptions {
* name
* - `false`: Output the IIFE without a variable name, making it anonymous. This
* is the safest option to avoid conflicts with existing variables on the
* page. This will become the default in a future version of WXT.
* page.
* - `string`: Use the provided string as the global variable name.
* - `function`: A function that receives the entrypoint and returns a string to
* use as the variable name.
*
* @default true
* @default false
*/
globalName?: string | boolean | ((entrypoint: Entrypoint) => string);
}
@@ -1138,9 +1169,6 @@ export interface ConfigEnv {
export type WxtCommand = 'build' | 'serve';
/** @deprecated Use `WebExtConfig` instead. */
export type ExtensionRunnerConfig = WebExtConfig;
/**
* Options for how [`web-ext`](https://github.com/mozilla/web-ext) starts the
* browser.
@@ -1223,7 +1251,7 @@ export interface WxtBuilder {
* Import a JS entrypoint file, returning the default export containing the
* options.
*/
importEntrypoint<T>(path: string): Promise<T>;
importEntrypoint<T>(this: WxtBuilder, path: string): Promise<T>;
/** Import a list of JS entrypoint files, returning their options. */
importEntrypoints(paths: string[]): Promise<Record<string, unknown>[]>;
/**
@@ -1533,13 +1561,15 @@ export interface ResolvedConfig {
imports: WxtResolvedUnimportOptions;
manifest: UserManifest;
fsCache: FsCache;
runnerConfig: C12ResolvedConfig<WebExtConfig>;
webExt: C12ResolvedConfig<WebExtConfig>;
runner: ExtensionRunner;
zip: {
name?: string;
artifactTemplate: string;
sourcesTemplate: string;
includeSources: string[];
excludeSources: string[];
dotSources: boolean;
sourcesRoot: string;
downloadedPackagesDir: string;
downloadPackages: string[];
@@ -1639,16 +1669,16 @@ export interface Eslintrc {
* When true, generates a file that can be used by ESLint to know which
* variables are valid globals.
*
* - `false`: Don't generate the file.
* - `'auto'`: Check if eslint is installed, and if it is, generate a compatible
* config file.
* - `true`: Same as `8`.
* - `true`: Same as `'auto'`.
* - `false`: Don't generate the file.
* - `8`: Generate a config file compatible with ESLint 8.
* - `9`: Generate a config file compatible with ESLint 9.
*
* @default 'auto'
*/
enabled?: false | true | 'auto' | 8 | 9;
enabled?: 'auto' | boolean | 8 | 9;
/**
* File path to save the generated eslint config.
*
@@ -1697,7 +1727,7 @@ export type WxtResolvedUnimportOptions = Partial<UnimportOptions> & {
/**
* Package management utils built on top of
* [`nypm`](https://www.npmjs.com/package/nypm)
* [`nypm`](https://npmjs.org/package/nypm)
*/
export interface WxtPackageManager extends Nypm.PackageManager {
addDependency: typeof Nypm.addDependency;
+8
View File
@@ -15,8 +15,16 @@ export function getAppConfig(): WxtAppConfig {
/**
* Alias for {@link getAppConfig}.
*
* @deprecated Use {@link getAppConfig} instead. Same function, different name.
* @see https://wxt.dev/guide/essentials/config/runtime.html
*/
export function useAppConfig(): WxtAppConfig {
// After v1.0 this function will be removed, and migrate to use only `getAppConfig` instead.
if (import.meta.env.DEV) {
console.warn(
'[wxt] `useAppConfig` is deprecated. Please use `getAppConfig` instead.',
);
}
return getAppConfig();
}
@@ -55,7 +55,7 @@ export async function createShadowRootUi<TMounted>(
const mount = () => {
// Add shadow root element to DOM
mountUi(shadowHost, options);
applyPosition(shadowHost, shadow.querySelector('html'), options);
applyPosition(shadowHost, uiContainer, options);
// Add document CSS
if (
+1 -1
View File
@@ -1,4 +1,4 @@
import { fakeBrowser } from 'wxt/testing';
import { fakeBrowser } from 'wxt/testing/fake-browser';
export const browser = fakeBrowser;
export default fakeBrowser;
+4 -1
View File
@@ -22,7 +22,10 @@ export default defineConfig({
plugins: [RandomSeed({ define: 'import.meta.env.TEST_SEED' })],
resolve: {
alias: {
'wxt/testing': path.resolve('src/testing'),
'wxt/testing/fake-browser': path.resolve('src/testing/fake-browser.ts'),
'wxt/testing/vitest-plugin': path.resolve(
'src/testing/wxt-vitest-plugin.ts',
),
},
},
});
-119
View File
@@ -1,119 +0,0 @@
import {
determineSemverChange,
generateMarkDown,
loadChangelogConfig,
parseChangelogMarkdown,
parseCommits,
} from 'changelogen';
import { consola } from 'consola';
import { readdir } from 'node:fs/promises';
import { join } from 'node:path';
import { getPkgTag, grabPackageDetails, listCommitsInDir } from './git';
const pkg = process.argv[2];
if (!pkg) {
throw Error(
'Package name missing. Usage: bun run scripts/bump-package-version.ts <package-name>',
);
}
const { pkgDir, pkgName, currentVersion, prevTag, changelogPath, pkgJsonPath } =
await grabPackageDetails(pkg);
consola.info('Bumping:', { pkg, pkgDir, pkgName, currentVersion });
// Get commits
const config = await loadChangelogConfig(process.cwd());
consola.info('Config:', config);
const additionalDirs = pkg === 'wxt' ? ['docs'] : [];
const rawCommits = await listCommitsInDir(pkgDir, prevTag, additionalDirs);
const commits = parseCommits(rawCommits, config);
// Bump version
const originalBumpType = determineSemverChange(commits, config) ?? 'patch';
let bumpType = originalBumpType;
if (currentVersion.startsWith('0.')) {
if (bumpType === 'major') {
bumpType = 'minor';
} else if (bumpType === 'minor') {
bumpType = 'patch';
}
}
await Bun.$`bun pm version ${bumpType}`.cwd(pkgDir);
const updatedPkgJson = await Bun.file(pkgJsonPath).json();
const newVersion: string = updatedPkgJson.version;
const newTag = getPkgTag(pkg, newVersion);
consola.info('Bump:', { currentVersion, bumpType, newVersion });
// Generate changelog
const versionChangelog = await generateMarkDown(commits, {
...config,
from: prevTag,
to: newTag,
});
let versionChangelogBody = versionChangelog
.split('\n')
.slice(1)
.join('\n')
.trim();
if (originalBumpType === 'major') {
versionChangelogBody = versionChangelogBody.replace(
'[compare changes]',
`[⚠️ breaking changes](https://wxt.dev/guide/resources/upgrading.html) &bull; [compare changes]`,
);
}
const { releases: prevReleases } = await Bun.file(changelogPath)
.text()
.then(parseChangelogMarkdown)
.catch(() => ({ releases: [] }));
const allReleases = [
{
version: newVersion,
body: versionChangelogBody,
},
...prevReleases,
];
const newChangelog =
'# Changelog\n\n' +
allReleases
.map((release) => [`## v${release.version}`, release.body].join('\n\n'))
.join('\n\n');
await Bun.write(changelogPath, newChangelog);
consola.success('Updated changelog');
// Update WXT version in templates when releasing wxt package
const templatePkgJsonPaths: string[] = [];
if (pkg === 'wxt') {
const templatesDir = 'templates';
const templateDirs = await readdir(templatesDir);
for (const templateDir of templateDirs) {
const templatePkgJsonPath = join(templatesDir, templateDir, 'package.json');
const templatePkgJsonFile = Bun.file(templatePkgJsonPath);
if (await templatePkgJsonFile.exists()) {
const templatePkgJson = await templatePkgJsonFile.json();
if (templatePkgJson.devDependencies?.wxt) {
templatePkgJson.devDependencies.wxt = `^${newVersion}`;
await templatePkgJsonFile.write(
JSON.stringify(templatePkgJson, null, 2),
);
templatePkgJsonPaths.push(templatePkgJsonPath);
consola.success(`Updated wxt version in ${templatePkgJsonPath}`);
}
} else {
console.warn(`No package.json found in ${templatePkgJsonPath}`, {
cwd: process.cwd(),
});
}
}
}
// Run a bun install to update the lockfile after the version change
await Bun.$`bun install --ignore-scripts`;
// Commit changes
await Bun.$`git add "${pkgJsonPath}" "${changelogPath}" bun.lock`;
for (const packageJsonPath of templatePkgJsonPaths) {
await Bun.$`git add "${packageJsonPath}"`;
}
await Bun.$`git commit -m "chore(release): ${pkgName} v${newVersion}"`;
await Bun.$`git tag ${newTag}`;
consola.success('Committed version and changelog');
-34
View File
@@ -1,34 +0,0 @@
import {
createGithubRelease,
GithubRelease,
loadChangelogConfig,
parseChangelogMarkdown,
} from 'changelogen';
import { grabPackageDetails } from './git';
import consola from 'consola';
const pkg = process.argv[2];
if (!pkg) {
throw Error(
'Package name missing. Usage: bun run scripts/create-github-release.ts <package-name>',
);
}
const { pkgName, prevTag, currentVersion, changelogPath } =
await grabPackageDetails(pkg);
consola.info('Creating release for:', { pkg, pkgName, prevTag });
const { releases } = await Bun.file(changelogPath)
.text()
.then(parseChangelogMarkdown)
.catch(() => ({ releases: [] }));
const config = await loadChangelogConfig(process.cwd());
config.tokens.github = process.env.GITHUB_TOKEN;
await createGithubRelease(config, {
tag_name: prevTag,
name: `${pkgName} v${currentVersion}`,
body: releases[0].body,
make_latest: String(pkg === 'wxt'),
} as GithubRelease & { make_latest: string });
consola.success('Created release');
-42
View File
@@ -1,42 +0,0 @@
import { RawGitCommit, getGitDiff } from 'changelogen';
import { consola } from 'consola';
export async function grabPackageDetails(pkg: string) {
const pkgDir = `packages/${pkg}`;
const pkgJsonPath = `${pkgDir}/package.json`;
const pkgJson = await Bun.file(pkgJsonPath).json();
const currentVersion: string = pkgJson.version;
return {
pkgDir,
pkgJsonPath,
changelogPath: `${pkgDir}/CHANGELOG.md`,
pkgJson,
pkgName: pkgJson.name,
currentVersion,
prevTag: getPkgTag(pkg, currentVersion),
};
}
export function getPkgTag(pkg: string, version: string | undefined) {
return `${pkg}-v${version}`;
}
export async function listCommitsInDir(
dir: string,
lastTag: string,
additionalDirs: string[] = [],
): Promise<RawGitCommit[]> {
const allDirs = [dir, ...additionalDirs];
consola.info('Listing commits:', { lastTag, dirs: allDirs });
const commits = await getGitDiff(lastTag);
consola.info('All commits:', commits.length);
consola.debug(commits);
// commit.body contains all the files that were modified/added. So just check to make sure "\t" + "packages/storage" + "/" is in the body to include
// '"\n\nM\tpackages/wxt/vitest.config.ts\n"'
const filtered = commits.filter((commit) =>
allDirs.some((dir) => commit.body.includes(`\t${dir}/`)),
);
consola.info('Filtered:', filtered.length);
consola.debug(filtered);
return filtered;
}
-43
View File
@@ -1,43 +0,0 @@
import {
getGithubReleaseByTag,
loadChangelogConfig,
parseChangelogMarkdown,
updateGithubRelease,
} from 'changelogen';
import { getPkgTag, grabPackageDetails } from './git';
import consola from 'consola';
const pkg = process.argv[2];
if (!pkg) {
throw Error(
'Package name missing. Usage: bun run scripts/sync-releases.ts <package-name>',
);
}
// Update
const { changelogPath, pkgName } = await grabPackageDetails(pkg);
const { releases } = await Bun.file(changelogPath)
.text()
.then(parseChangelogMarkdown)
.catch(() => ({ releases: [] }));
const config = await loadChangelogConfig(process.cwd());
config.tokens.github = process.env.GITHUB_TOKEN;
// Update releases
for (const release of releases) {
const tag = getPkgTag(pkg, release.version);
try {
const existing = await getGithubReleaseByTag(config, tag);
if (existing.body !== release.body) {
await updateGithubRelease(config, existing.id!, {
tag_name: tag,
name: `${pkgName} v${release.version}`,
body: release.body,
});
}
consola.success(`Synced \`${tag}\``);
} catch (err) {
consola.fail(`\`${tag}\``, err);
}
}
consola.success('Done');
+1
View File
@@ -23,6 +23,7 @@
"@types/react-dom": "^19.2.3",
"@wxt-dev/module-react": "^1.1.5",
"typescript": "^5.9.3",
"web-ext": "^10.5.0",
"wxt": "^0.20.27"
}
}
+2
View File
@@ -20,6 +20,8 @@
"devDependencies": {
"@wxt-dev/module-solid": "^1.1.4",
"typescript": "^5.9.3",
"vite": "^8.1.5",
"web-ext": "^10.5.0",
"wxt": "^0.20.27"
}
}
+2
View File
@@ -21,6 +21,8 @@
"svelte-check": "^4.4.4",
"tslib": "^2.8.1",
"typescript": "^5.9.3",
"vite": "^8.1.5",
"web-ext": "^10.5.0",
"wxt": "^0.20.27"
}
}
+2
View File
@@ -16,6 +16,8 @@
},
"devDependencies": {
"typescript": "^5.9.3",
"vite": "^8.1.5",
"web-ext": "^10.5.0",
"wxt": "^0.20.27"
}
}
+2
View File
@@ -20,7 +20,9 @@
"devDependencies": {
"@wxt-dev/module-vue": "^1.0.3",
"typescript": "^5.9.3",
"vite": "^8.1.5",
"vue-tsc": "^3.2.5",
"web-ext": "^10.5.0",
"wxt": "^0.20.27"
}
}