Compare commits
65 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2faba91ddb | |||
| fe8e2ed23b | |||
| 95369ff2c9 | |||
| 829525f824 | |||
| 9ad04d325b | |||
| f218c30825 | |||
| fdee7c615c | |||
| b34754b363 | |||
| be74af40f9 | |||
| baebe28a3e | |||
| 3b9f395a7d | |||
| 95367203bf | |||
| 6fb1463a32 | |||
| b727453509 | |||
| 446fd90bea | |||
| 78f97f32a2 | |||
| 459662a6c1 | |||
| b150a52471 | |||
| 028c601515 | |||
| af382ef065 | |||
| 91ef7f2ab5 | |||
| 0bf7279c8f | |||
| 62525d33c6 | |||
| 88ff40e301 | |||
| 1a72a0cdc6 | |||
| 2b07b4bc12 | |||
| 06c09e7c87 | |||
| 30b96ac87c | |||
| 2e9b5cffe8 | |||
| 3e1641a6ec | |||
| d64ca52bb0 | |||
| 8c645fa1ce | |||
| 79c9c89923 | |||
| 11d93fe724 | |||
| 039c561a80 | |||
| 90c2b7f9bf | |||
| c431dafe08 | |||
| 3786c7b6d1 | |||
| 0416ff7ec2 | |||
| 26cbef5a42 | |||
| e98f29fddb | |||
| 93e6dd6db7 | |||
| 7879fabbad | |||
| a861dc1736 | |||
| f75c5ca1aa | |||
| e8e00e4e04 | |||
| 15adc77d23 | |||
| c73a4b6a96 | |||
| d96840b2f5 | |||
| e4886af90a | |||
| c69e99db3f | |||
| 55113d654d | |||
| 50d2170844 | |||
| ee53bb0a5e | |||
| 5216d75209 | |||
| d0623fe173 | |||
| e0d0618325 | |||
| 563bd4e108 | |||
| 107803bd8f | |||
| 06fd7e4eac | |||
| eba8788a76 | |||
| 8ace11f3cb | |||
| 328acbbfe7 | |||
| f99c1aa7b5 | |||
| 5217279070 |
@@ -7,6 +7,7 @@ on:
|
||||
default: wxt
|
||||
type: choice
|
||||
options:
|
||||
- analytics
|
||||
- auto-icons
|
||||
- i18n
|
||||
- module-react
|
||||
|
||||
@@ -7,6 +7,7 @@ on:
|
||||
default: wxt
|
||||
type: choice
|
||||
options:
|
||||
- analytics
|
||||
- auto-icons
|
||||
- i18n
|
||||
- module-react
|
||||
|
||||
@@ -145,3 +145,24 @@ pnpm dlx taze -r
|
||||
```
|
||||
|
||||
Configuration is in [`taze.config.ts`](./taze.config.ts).
|
||||
|
||||
## Install Unreleased Versions
|
||||
|
||||
This repo uses https://pkg.pr.new to publish versions of all it's packages for almost every commit. You can install them via:
|
||||
|
||||
```sh
|
||||
npm i https://pkg.pr.new/[package-name]@[ref]
|
||||
```
|
||||
|
||||
Or use one of the shorthands:
|
||||
|
||||
```sh
|
||||
# Install the latest build of `wxt` from a PR:
|
||||
npm i https://pkg.pr.new/wxt@1283
|
||||
|
||||
# Install the latest build of `@wxt-dev/module-react` on the `main` branch
|
||||
npm i https://pkg.pr.new/@wxt-dev/module-react@main
|
||||
|
||||
# Install `@wxt-dev/storage` from a specific commit:
|
||||
npm i https://pkg.pr.new/@wxt-dev/module-react@426f907
|
||||
```
|
||||
|
||||
@@ -59,6 +59,9 @@ const chromeExtensionIds = [
|
||||
'npgghjedpchajflknnbngajkjkdhncdo', // aesthetic Notion, styled
|
||||
'hmdcmlfkchdmnmnmheododdhjedfccka', // Eye Dropper
|
||||
'eihpmapodnppeemkhkbhikmggfojdkjd', // Cursorful - Screen Recorder with Auto Zoom
|
||||
'hjjkgbibknbahijglkffklflidncplkn', // Show IP – Live View of Website IPs for Developers
|
||||
'ilbikcehnpkmldojkcmlldkoelofnbde', // Strong Password Generator
|
||||
'ocllfkhcdopiafndigclebelbecaiocp', // ZenGram: Mindful Instagram, Your Way
|
||||
];
|
||||
|
||||
const { data, err, isLoading } = useListExtensionDetails(chromeExtensionIds);
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
--wxt-c-green-1: #0b8a00;
|
||||
--wxt-c-green-2: #096600;
|
||||
--wxt-c-green-3: #096600;
|
||||
--wxt-c-green-soft: rgba(#0b8a00 / 0.14);
|
||||
--wxt-c-green-soft: rgba(11, 138, 0, 0.14);
|
||||
}
|
||||
|
||||
.dark {
|
||||
--wxt-c-green-1: #67d45e;
|
||||
--wxt-c-green-2: #329929;
|
||||
--wxt-c-green-3: #21651b;
|
||||
--wxt-c-green-soft: rgba(#67d45e / 0.14);
|
||||
--wxt-c-green-soft: rgba(103, 212, 94, 0.14);
|
||||
}
|
||||
|
||||
/* https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css */
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 132 KiB After Width: | Height: | Size: 131 KiB |
@@ -156,6 +156,11 @@ Alternatively, you can use [`@wxt-dev/auto-icons`](https://www.npmjs.com/package
|
||||
|
||||
> [Chrome docs](https://developer.chrome.com/docs/extensions/reference/permissions/)
|
||||
|
||||
Most of the time, you need to manually add permissions to your manifest. Only in a few specific situations are permissions added automatically:
|
||||
|
||||
- During development: the `tabs` and `scripting` permissions will be added to enable hot reloading.
|
||||
- When a `sidepanel` entrypoint is present: The `sidepanel` permission is added.
|
||||
|
||||
```ts
|
||||
export default defineConfig({
|
||||
manifest: {
|
||||
|
||||
@@ -306,9 +306,12 @@ Follow the [Devtools Example](https://github.com/wxt-dev/examples/tree/main/exam
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Options Title</title>
|
||||
|
||||
<!-- Customize the manifest options -->
|
||||
<meta name="manifest.open_in_tab" content="true|false" />
|
||||
<meta name="manifest.chrome_style" content="true|false" />
|
||||
<meta name="manifest.browser_style" content="true|false" />
|
||||
|
||||
<!-- Set include/exclude if the page should be removed from some builds -->
|
||||
<meta name="manifest.include" content="['chrome', ...]" />
|
||||
<meta name="manifest.exclude" content="['chrome', ...]" />
|
||||
@@ -336,7 +339,11 @@ Follow the [Devtools Example](https://github.com/wxt-dev/examples/tree/main/exam
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
|
||||
<!-- Set the `action.default_title` in the manifest -->
|
||||
<title>Default Popup Title</title>
|
||||
|
||||
<!-- Customize the manifest options -->
|
||||
<meta
|
||||
name="manifest.default_icon"
|
||||
content="{
|
||||
@@ -347,6 +354,7 @@ Follow the [Devtools Example](https://github.com/wxt-dev/examples/tree/main/exam
|
||||
/>
|
||||
<meta name="manifest.type" content="page_action|browser_action" />
|
||||
<meta name="manifest.browser_style" content="true|false" />
|
||||
|
||||
<!-- Set include/exclude if the page should be removed from some builds -->
|
||||
<meta name="manifest.include" content="['chrome', ...]" />
|
||||
<meta name="manifest.exclude" content="['chrome', ...]" />
|
||||
@@ -381,6 +389,7 @@ Firefox does not support sandboxed pages.
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Title</title>
|
||||
|
||||
<!-- Set include/exclude if the page should be removed from some builds -->
|
||||
<meta name="manifest.include" content="['chrome', ...]" />
|
||||
<meta name="manifest.exclude" content="['chrome', ...]" />
|
||||
@@ -413,6 +422,8 @@ In Chrome, side panels use the `side_panel` API, while Firefox uses the `sidebar
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Default Side Panel Title</title>
|
||||
|
||||
<!-- Customize the manifest options -->
|
||||
<meta
|
||||
name="manifest.default_icon"
|
||||
content="{
|
||||
@@ -423,6 +434,7 @@ In Chrome, side panels use the `side_panel` API, while Firefox uses the `sidebar
|
||||
/>
|
||||
<meta name="manifest.open_at_install" content="true|false" />
|
||||
<meta name="manifest.browser_style" content="true|false" />
|
||||
|
||||
<!-- Set include/exclude if the page should be removed from some builds -->
|
||||
<meta name="manifest.include" content="['chrome', ...]" />
|
||||
<meta name="manifest.exclude" content="['chrome', ...]" />
|
||||
@@ -472,6 +484,7 @@ body {
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Title</title>
|
||||
|
||||
<!-- Set include/exclude if the page should be removed from some builds -->
|
||||
<meta name="manifest.include" content="['chrome', ...]" />
|
||||
<meta name="manifest.exclude" content="['chrome', ...]" />
|
||||
|
||||
@@ -167,6 +167,31 @@ This file could then be loaded at runtime:
|
||||
const res = await fetch(browser.runtime.getURL('/some-text.txt'));
|
||||
```
|
||||
|
||||
#### Add custom entrypoints
|
||||
|
||||
Once the existing files under the `entrypoints/` directory have been discovered, the `entrypoints:found` hook can be used to add custom entrypoints.
|
||||
|
||||
:::info
|
||||
The `entrypoints:found` hook is triggered before validation is carried out on the list of entrypoints. Thus, any custom entrypoints will still be checked for duplicate names and logged during debugging.
|
||||
:::
|
||||
|
||||
```ts
|
||||
import { defineWxtModule } from 'wxt/modules';
|
||||
|
||||
export default defineWxtModule({
|
||||
setup(wxt) {
|
||||
wxt.hook('entrypoints:found', (_, entrypointInfos) => {
|
||||
// Add your new entrypoint
|
||||
entrypointInfos.push({
|
||||
name: 'my-custom-script',
|
||||
inputPath: 'path/to/custom-script.js',
|
||||
type: 'content-script',
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
#### Generate runtime module
|
||||
|
||||
Create a file in `.wxt`, add an alias to import it, and add auto-imports for exported variables.
|
||||
|
||||
@@ -28,7 +28,7 @@ See https://wxt.dev/guide/essentials/config/browser-startup.html#persist-data
|
||||
|
||||
## My component library doesn't work in content scripts!
|
||||
|
||||
Component libraries place their CSS in the document's `<head>` by default. When using `createShadowRoot`, your UI is isolated from the document's styles because it's inside a ShadowRoot.
|
||||
Component libraries place their CSS in the document's `<head>` by default. When using `createShadowRootUi`, your UI is isolated from the document's styles because it's inside a ShadowRoot.
|
||||
|
||||
To fix this, you need to tell your component library to insert it's CSS inside the shadow root. Here's the docs for a couple of popular libraries:
|
||||
|
||||
@@ -38,7 +38,7 @@ To fix this, you need to tell your component library to insert it's CSS inside t
|
||||
|
||||
> If your library isn't listed above, try searching it's docs/issues for "shadow root", "shadow dom", or "css container".
|
||||
|
||||
`createShadowRoot` provides it's own `<head>` element inside the shadow root, so that were you should tell the library to add the CSS. Here's an example with Ant Design:
|
||||
`createShadowRootUi` provides it's own `<head>` element inside the shadow root, so that were you should tell the library to add the CSS. Here's an example with Ant Design:
|
||||
|
||||
```tsx
|
||||
import { StyleProvider } from '@ant-design/cssinjs'; // [!code ++]
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
# WXT Analytics
|
||||
|
||||
Report analytics events from your web extension extension.
|
||||
|
||||
## Supported Analytics Providers
|
||||
|
||||
- [Google Analytics 4 (Measurement Protocol)](#google-analytics-4-measurement-protocol)
|
||||
- [Umami](#umami)
|
||||
|
||||
## Install With WXT
|
||||
|
||||
1. Install the NPM package:
|
||||
```bash
|
||||
pnpm i @wxt-dev/analytics
|
||||
```
|
||||
2. In your `wxt.config.ts`, add the WXT module:
|
||||
```ts
|
||||
export default defineConfig({
|
||||
modules: ['@wxt-dev/analytics/module'],
|
||||
});
|
||||
```
|
||||
3. In your `<srcDir>/app.config.ts`, add a provider:
|
||||
|
||||
```ts
|
||||
// <srcDir>/app.config.ts
|
||||
import { umami } from '@wxt-dev/analytics/providers/umami';
|
||||
|
||||
export default defineAppConfig({
|
||||
analytics: {
|
||||
debug: true,
|
||||
providers: [
|
||||
// ...
|
||||
],
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
4. Then use the `#analytics` module to report events:
|
||||
|
||||
```ts
|
||||
import { analytics } from '#analytics';
|
||||
|
||||
await analytics.track('some-event');
|
||||
await analytics.page();
|
||||
await analytics.identify('some-user-id');
|
||||
analytics.autoTrack(document.body);
|
||||
```
|
||||
|
||||
## Install Without WXT
|
||||
|
||||
1. Install the NPM package:
|
||||
```bash
|
||||
pnpm i @wxt-dev/analytics
|
||||
```
|
||||
2. Create an `analytics` instance:
|
||||
|
||||
```ts
|
||||
// utils/analytics.ts
|
||||
import { createAnalytics } from '@wxt-dev/analytics';
|
||||
|
||||
export const analytics = createAnalytics({
|
||||
providers: [
|
||||
// ...
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
3. Import your analytics module in the background to initialize the message listener:
|
||||
```ts
|
||||
// background.ts
|
||||
import './utils/analytics';
|
||||
```
|
||||
4. Then use your `analytics` instance to report events:
|
||||
|
||||
```ts
|
||||
import { analytics } from './utils/analytics';
|
||||
|
||||
await analytics.track('some-event');
|
||||
await analytics.page();
|
||||
await analytics.identify('some-user-id');
|
||||
analytics.autoTrack(document.body);
|
||||
```
|
||||
|
||||
## Providers
|
||||
|
||||
### Google Analytics 4 (Measurement Protocol)
|
||||
|
||||
The [Measurement Protocol](https://developers.google.com/analytics/devguides/collection/protocol/ga4) is an alternative to GTag for reporting events to Google Analytics for MV3 extensions.
|
||||
|
||||
> [Why use the Measurement Protocol instead of GTag?](https://developer.chrome.com/docs/extensions/how-to/integrate/google-analytics-4#measurement-protocol)
|
||||
|
||||
Follow [Google's documentation](https://developer.chrome.com/docs/extensions/how-to/integrate/google-analytics-4#setup-credentials) to obtain your credentials and put them in your `.env` file:
|
||||
|
||||
```dotenv
|
||||
WXT_GA_API_SECRET='...'
|
||||
```
|
||||
|
||||
Then add the `googleAnalytics4` provider to your `<srcDir>/app.config.ts` file:
|
||||
|
||||
```ts
|
||||
import { googleAnalytics4 } from '@wxt-dev/analytics/providers/google-analytics-4';
|
||||
|
||||
export default defineAppConfig({
|
||||
analytics: {
|
||||
providers: [
|
||||
googleAnalytics4({
|
||||
apiSecret: import.meta.env.WXT_GA_API_SECRET,
|
||||
measurementId: '...',
|
||||
}),
|
||||
],
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Umami
|
||||
|
||||
[Umami](https://umami.is/) is a privacy-first, open source analytics platform.
|
||||
|
||||
In Umami's dashboard, create a new website. The website's name and domain can be anything. Obviously, an extension doesn't have a domain, so make one up if you don't have one.
|
||||
|
||||
After the website has been created, save the website ID and domain to your `.env` file:
|
||||
|
||||
```dotenv
|
||||
WXT_UMAMI_WEBSITE_ID='...'
|
||||
WXT_UMAMI_DOMAIN='...'
|
||||
```
|
||||
|
||||
Then add the `umami` provider to your `<srcDir>/app.config.ts` file:
|
||||
|
||||
```ts
|
||||
import { umami } from '@wxt-dev/analytics/providers/umami';
|
||||
|
||||
export default defineAppConfig({
|
||||
analytics: {
|
||||
providers: [
|
||||
umami({
|
||||
apiUrl: 'https://<your-umami-instance>/api',
|
||||
websiteId: import.meta.env.WXT_UMAMI_WEBSITE_ID,
|
||||
domain: import.meta.env.WXT_UMAMI_DOMAIN,
|
||||
}),
|
||||
],
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Custom Provider
|
||||
|
||||
If your analytics platform is not supported, you can provide an implementation of the `AnalyticsProvider` type in your `app.config.ts` instead:
|
||||
|
||||
```ts
|
||||
import { defineAnalyticsProvider } from '@wxt-dev/analytics/client';
|
||||
|
||||
interface CustomAnalyticsOptions {
|
||||
// ...
|
||||
}
|
||||
|
||||
const customAnalytics = defineAnalyticsProvider<CustomAnalyticsOptions>(
|
||||
(analytics, analyticsConfig, providerOptions) => {
|
||||
// ...
|
||||
},
|
||||
);
|
||||
|
||||
export default defineAppConfig({
|
||||
analytics: {
|
||||
providers: [
|
||||
customAnalytics({
|
||||
// ...
|
||||
}),
|
||||
],
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Example `AnalyticsProvider` implementations can be found at [`./modules/analytics/providers`](https://github.com/wxt-dev/wxt/tree/main/packages/analytics/modules/analytics/providers).
|
||||
@@ -0,0 +1,20 @@
|
||||
import { defineAppConfig } from 'wxt/sandbox';
|
||||
import { googleAnalytics4 } from './modules/analytics/providers/google-analytics-4';
|
||||
import { umami } from './modules/analytics/providers/umami';
|
||||
|
||||
export default defineAppConfig({
|
||||
analytics: {
|
||||
debug: true,
|
||||
providers: [
|
||||
googleAnalytics4({
|
||||
apiSecret: '...',
|
||||
measurementId: '...',
|
||||
}),
|
||||
umami({
|
||||
apiUrl: 'https://umami.aklinker1.io/api',
|
||||
domain: 'analytics.wxt.dev',
|
||||
websiteId: '8f1c2aa4-fad3-406e-a5b2-33e8d4501716',
|
||||
}),
|
||||
],
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,21 @@
|
||||
import { defineBuildConfig } from 'unbuild';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
// Build module and plugins
|
||||
export default defineBuildConfig({
|
||||
rootDir: 'modules/analytics',
|
||||
outDir: resolve(__dirname, 'dist'),
|
||||
entries: [
|
||||
{ input: 'index.ts', name: 'module' },
|
||||
{ input: 'client.ts', name: 'index' },
|
||||
'background-plugin.ts',
|
||||
'types.ts',
|
||||
'providers/google-analytics-4.ts',
|
||||
'providers/umami.ts',
|
||||
],
|
||||
externals: ['#analytics'],
|
||||
replace: {
|
||||
'import.meta.env.NPM': 'true',
|
||||
},
|
||||
declaration: true,
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Popup</title>
|
||||
</head>
|
||||
<body>
|
||||
<label>
|
||||
<input id="enabledCheckbox" type="checkbox" />
|
||||
 Analytics enabled
|
||||
</label>
|
||||
<button id="button1">Button 1</button>
|
||||
<button class="cool-button">Button 2</button>
|
||||
<script type="module" src="./main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,9 @@
|
||||
import { analytics } from '#analytics';
|
||||
|
||||
declare const enabledCheckbox: HTMLInputElement;
|
||||
|
||||
analytics.autoTrack(document);
|
||||
|
||||
enabledCheckbox.oninput = () => {
|
||||
void analytics.setEnabled(enabledCheckbox.checked);
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
import '#analytics';
|
||||
|
||||
export default () => {};
|
||||
@@ -0,0 +1,288 @@
|
||||
import { UAParser } from 'ua-parser-js';
|
||||
import type {
|
||||
Analytics,
|
||||
AnalyticsConfig,
|
||||
AnalyticsPageViewEvent,
|
||||
AnalyticsStorageItem,
|
||||
AnalyticsTrackEvent,
|
||||
BaseAnalyticsEvent,
|
||||
AnalyticsEventMetadata,
|
||||
AnalyticsProvider,
|
||||
} from './types';
|
||||
|
||||
const ANALYTICS_PORT = '@wxt-dev/analytics';
|
||||
|
||||
export function createAnalytics(config?: AnalyticsConfig): Analytics {
|
||||
if (typeof chrome === 'undefined' || !chrome?.runtime?.id)
|
||||
throw Error(
|
||||
'Cannot use WXT analytics in contexts without access to the browser.runtime APIs',
|
||||
);
|
||||
if (config == null) {
|
||||
console.warn(
|
||||
"[@wxt-dev/analytics] Config not provided to createAnalytics. If you're using WXT, add the 'analytics' property to '<srcDir>/app.config.ts'.",
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: This only works for standard WXT extensions, add a more generic
|
||||
// background script detector that works with non-WXT projects.
|
||||
if (location.pathname === '/background.js')
|
||||
return createBackgroundAnalytics(config);
|
||||
|
||||
return createFrontendAnalytics();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an analytics client in the background responsible for uploading events to the server to avoid CORS errors.
|
||||
*/
|
||||
function createBackgroundAnalytics(
|
||||
config: AnalyticsConfig | undefined,
|
||||
): Analytics {
|
||||
// User properties storage
|
||||
const userIdStorage =
|
||||
config?.userId ?? defineStorageItem<string>('wxt-analytics:user-id');
|
||||
const userPropertiesStorage =
|
||||
config?.userProperties ??
|
||||
defineStorageItem<Record<string, string>>(
|
||||
'wxt-analytics:user-properties',
|
||||
{},
|
||||
);
|
||||
const enabled =
|
||||
config?.enabled ??
|
||||
defineStorageItem<boolean>('local:wxt-analytics:enabled', false);
|
||||
|
||||
// Cached values
|
||||
const platformInfo = chrome.runtime.getPlatformInfo();
|
||||
const userAgent = UAParser();
|
||||
let userId = Promise.resolve(userIdStorage.getValue()).then(
|
||||
(id) => id ?? globalThis.crypto.randomUUID(),
|
||||
);
|
||||
let userProperties = userPropertiesStorage.getValue();
|
||||
const manifest = chrome.runtime.getManifest();
|
||||
|
||||
const getBackgroundMeta = () => ({
|
||||
timestamp: Date.now(),
|
||||
// Don't track sessions for the background, it can be running
|
||||
// indefinitely, and will inflate session duration stats.
|
||||
sessionId: undefined,
|
||||
language: navigator.language,
|
||||
referrer: undefined,
|
||||
screen: undefined,
|
||||
url: location.href,
|
||||
title: undefined,
|
||||
});
|
||||
|
||||
const getBaseEvent = async (
|
||||
meta: AnalyticsEventMetadata,
|
||||
): Promise<BaseAnalyticsEvent> => {
|
||||
const platform = await platformInfo;
|
||||
return {
|
||||
meta,
|
||||
user: {
|
||||
id: await userId,
|
||||
properties: {
|
||||
version: config?.version ?? manifest.version_name ?? manifest.version,
|
||||
wxtMode: import.meta.env.MODE,
|
||||
wxtBrowser: import.meta.env.BROWSER,
|
||||
arch: platform.arch,
|
||||
os: platform.os,
|
||||
browser: userAgent.browser.name,
|
||||
browserVersion: userAgent.browser.version,
|
||||
...(await userProperties),
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const analytics = {
|
||||
identify: async (
|
||||
newUserId: string,
|
||||
newUserProperties: Record<string, string> = {},
|
||||
meta: AnalyticsEventMetadata = getBackgroundMeta(),
|
||||
) => {
|
||||
// Update in-memory cache for all providers
|
||||
userId = Promise.resolve(newUserId);
|
||||
userProperties = Promise.resolve(newUserProperties);
|
||||
// Persist user info to storage
|
||||
await Promise.all([
|
||||
userIdStorage.setValue?.(newUserId),
|
||||
userPropertiesStorage.setValue?.(newUserProperties),
|
||||
]);
|
||||
// Notify providers
|
||||
const event = await getBaseEvent(meta);
|
||||
if (config?.debug) console.debug('[@wxt-dev/analytics] identify', event);
|
||||
if (await enabled.getValue()) {
|
||||
await Promise.allSettled(
|
||||
providers.map((provider) => provider.identify(event)),
|
||||
);
|
||||
} else if (config?.debug) {
|
||||
console.debug(
|
||||
'[@wxt-dev/analytics] Analytics disabled, identify() not uploaded',
|
||||
);
|
||||
}
|
||||
},
|
||||
page: async (
|
||||
location: string,
|
||||
meta: AnalyticsEventMetadata = getBackgroundMeta(),
|
||||
) => {
|
||||
const baseEvent = await getBaseEvent(meta);
|
||||
const event: AnalyticsPageViewEvent = {
|
||||
...baseEvent,
|
||||
page: {
|
||||
url: meta?.url ?? globalThis.location?.href,
|
||||
location,
|
||||
title: meta?.title ?? globalThis.document?.title,
|
||||
},
|
||||
};
|
||||
if (config?.debug) console.debug('[@wxt-dev/analytics] page', event);
|
||||
if (await enabled.getValue()) {
|
||||
await Promise.allSettled(
|
||||
providers.map((provider) => provider.page(event)),
|
||||
);
|
||||
} else if (config?.debug) {
|
||||
console.debug(
|
||||
'[@wxt-dev/analytics] Analytics disabled, page() not uploaded',
|
||||
);
|
||||
}
|
||||
},
|
||||
track: async (
|
||||
eventName: string,
|
||||
eventProperties?: Record<string, string>,
|
||||
meta: AnalyticsEventMetadata = getBackgroundMeta(),
|
||||
) => {
|
||||
const baseEvent = await getBaseEvent(meta);
|
||||
const event: AnalyticsTrackEvent = {
|
||||
...baseEvent,
|
||||
event: { name: eventName, properties: eventProperties },
|
||||
};
|
||||
if (config?.debug) console.debug('[@wxt-dev/analytics] track', event);
|
||||
if (await enabled.getValue()) {
|
||||
await Promise.allSettled(
|
||||
providers.map((provider) => provider.track(event)),
|
||||
);
|
||||
} else if (config?.debug) {
|
||||
console.debug(
|
||||
'[@wxt-dev/analytics] Analytics disabled, track() not uploaded',
|
||||
);
|
||||
}
|
||||
},
|
||||
setEnabled: async (newEnabled) => {
|
||||
await enabled.setValue?.(newEnabled);
|
||||
},
|
||||
autoTrack: () => {
|
||||
// Noop, background doesn't have a UI
|
||||
return () => {};
|
||||
},
|
||||
} satisfies Analytics;
|
||||
|
||||
const providers =
|
||||
config?.providers?.map((provider) => provider(analytics, config)) ?? [];
|
||||
|
||||
// Listen for messages from the rest of the extension
|
||||
chrome.runtime.onConnect.addListener((port) => {
|
||||
if (port.name === ANALYTICS_PORT) {
|
||||
port.onMessage.addListener(({ fn, args }) => {
|
||||
// @ts-expect-error: Untyped fn key
|
||||
void analytics[fn]?.(...args);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return analytics;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an analytics client for non-background contexts.
|
||||
*/
|
||||
function createFrontendAnalytics(): Analytics {
|
||||
const port = chrome.runtime.connect({ name: ANALYTICS_PORT });
|
||||
const sessionId = Date.now();
|
||||
const getFrontendMetadata = (): AnalyticsEventMetadata => ({
|
||||
sessionId,
|
||||
timestamp: Date.now(),
|
||||
language: navigator.language,
|
||||
referrer: globalThis.document?.referrer || undefined,
|
||||
screen: globalThis.window
|
||||
? `${globalThis.window.screen.width}x${globalThis.window.screen.height}`
|
||||
: undefined,
|
||||
url: location.href,
|
||||
title: document.title || undefined,
|
||||
});
|
||||
|
||||
const methodForwarder =
|
||||
(fn: string) =>
|
||||
(...args: any[]) => {
|
||||
port.postMessage({ fn, args: [...args, getFrontendMetadata()] });
|
||||
};
|
||||
|
||||
const analytics: Analytics = {
|
||||
identify: methodForwarder('identify'),
|
||||
page: methodForwarder('page'),
|
||||
track: methodForwarder('track'),
|
||||
setEnabled: methodForwarder('setEnabled'),
|
||||
autoTrack: (root) => {
|
||||
const onClick = (event: Event) => {
|
||||
const element = event.target as any;
|
||||
if (
|
||||
!element ||
|
||||
(!INTERACTIVE_TAGS.has(element.tagName) &&
|
||||
!INTERACTIVE_ROLES.has(element.getAttribute('role')))
|
||||
)
|
||||
return;
|
||||
|
||||
void analytics.track('click', {
|
||||
tagName: element.tagName?.toLowerCase(),
|
||||
id: element.id || undefined,
|
||||
className: element.className || undefined,
|
||||
textContent: element.textContent?.substring(0, 50) || undefined, // Limit text content length
|
||||
href: element.href,
|
||||
});
|
||||
};
|
||||
root.addEventListener('click', onClick, { capture: true, passive: true });
|
||||
return () => {
|
||||
root.removeEventListener('click', onClick);
|
||||
};
|
||||
},
|
||||
};
|
||||
return analytics;
|
||||
}
|
||||
|
||||
function defineStorageItem<T>(
|
||||
key: string,
|
||||
defaultValue?: NonNullable<T>,
|
||||
): AnalyticsStorageItem<T> {
|
||||
return {
|
||||
getValue: async () =>
|
||||
(await chrome.storage.local.get(key))[key] ?? defaultValue,
|
||||
setValue: (newValue) => chrome.storage.local.set({ [key]: newValue }),
|
||||
};
|
||||
}
|
||||
|
||||
const INTERACTIVE_TAGS = new Set([
|
||||
'A',
|
||||
'BUTTON',
|
||||
'INPUT',
|
||||
'SELECT',
|
||||
'TEXTAREA',
|
||||
]);
|
||||
const INTERACTIVE_ROLES = new Set([
|
||||
'button',
|
||||
'link',
|
||||
'checkbox',
|
||||
'menuitem',
|
||||
'tab',
|
||||
'radio',
|
||||
]);
|
||||
|
||||
export function defineAnalyticsProvider<T = never>(
|
||||
definition: (
|
||||
/** The analytics object. */
|
||||
analytics: Analytics,
|
||||
/** Config passed into the analytics module from `app.config.ts`. */
|
||||
config: AnalyticsConfig,
|
||||
/** Provider options */
|
||||
options: T,
|
||||
) => ReturnType<AnalyticsProvider>,
|
||||
): (options: T) => AnalyticsProvider {
|
||||
return (options) => (analytics, config) =>
|
||||
definition(analytics, config, options);
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
import 'wxt';
|
||||
import 'wxt/sandbox';
|
||||
import { addAlias, addWxtPlugin, defineWxtModule } from 'wxt/modules';
|
||||
import { relative, resolve } from 'node:path';
|
||||
import type { AnalyticsConfig } from './types';
|
||||
|
||||
declare module 'wxt/sandbox' {
|
||||
export interface WxtAppConfig {
|
||||
analytics: AnalyticsConfig;
|
||||
}
|
||||
}
|
||||
|
||||
export default defineWxtModule({
|
||||
name: 'analytics',
|
||||
imports: [{ name: 'analytics', from: '#analytics' }],
|
||||
setup(wxt) {
|
||||
// Paths
|
||||
const wxtAnalyticsFolder = resolve(wxt.config.wxtDir, 'analytics');
|
||||
const wxtAnalyticsIndex = resolve(wxtAnalyticsFolder, 'index.ts');
|
||||
const clientModuleId = import.meta.env.NPM
|
||||
? '@wxt-dev/analytics'
|
||||
: resolve(wxt.config.modulesDir, 'analytics/client');
|
||||
const pluginModuleId = import.meta.env.NPM
|
||||
? '@wxt-dev/analytics/background-plugin'
|
||||
: resolve(wxt.config.modulesDir, 'analytics/background-plugin');
|
||||
|
||||
// Add required permissions
|
||||
wxt.hook('build:manifestGenerated', (_, manifest) => {
|
||||
manifest.permissions ??= [];
|
||||
if (!manifest.permissions.includes('storage')) {
|
||||
manifest.permissions.push('storage');
|
||||
}
|
||||
});
|
||||
|
||||
// Generate #analytics module
|
||||
const wxtAnalyticsCode = [
|
||||
`import { createAnalytics } from '${
|
||||
import.meta.env.NPM
|
||||
? clientModuleId
|
||||
: relative(wxtAnalyticsFolder, clientModuleId)
|
||||
}';`,
|
||||
`import { useAppConfig } from 'wxt/client';`,
|
||||
``,
|
||||
`export const analytics = createAnalytics(useAppConfig().analytics);`,
|
||||
``,
|
||||
].join('\n');
|
||||
addAlias(wxt, '#analytics', wxtAnalyticsIndex);
|
||||
wxt.hook('prepare:types', async (_, entries) => {
|
||||
entries.push({
|
||||
path: wxtAnalyticsIndex,
|
||||
text: wxtAnalyticsCode,
|
||||
});
|
||||
});
|
||||
|
||||
// Ensure there is a background entrypoint
|
||||
wxt.hook('entrypoints:resolved', (_, entrypoints) => {
|
||||
const hasBackground = entrypoints.find(
|
||||
(entry) => entry.type === 'background',
|
||||
);
|
||||
if (!hasBackground) {
|
||||
entrypoints.push({
|
||||
type: 'background',
|
||||
inputPath: 'virtual:user-background',
|
||||
name: 'background',
|
||||
options: {},
|
||||
outputDir: wxt.config.outDir,
|
||||
skipped: false,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Ensure analytics is initialized in every context, mainly the background.
|
||||
// TODO: Once there's a way to filter which entrypoints a plugin is applied to, only apply this to the background
|
||||
addWxtPlugin(wxt, pluginModuleId);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,73 @@
|
||||
import { defineAnalyticsProvider } from '../client';
|
||||
import type { BaseAnalyticsEvent } from '../types';
|
||||
|
||||
const DEFAULT_ENGAGEMENT_TIME_IN_MSEC = 100;
|
||||
|
||||
export interface GoogleAnalytics4ProviderOptions {
|
||||
apiSecret: string;
|
||||
measurementId: string;
|
||||
}
|
||||
|
||||
export const googleAnalytics4 =
|
||||
defineAnalyticsProvider<GoogleAnalytics4ProviderOptions>(
|
||||
(_, config, options) => {
|
||||
const send = async (
|
||||
data: BaseAnalyticsEvent,
|
||||
eventName: string,
|
||||
eventProperties: Record<string, string | undefined> | undefined,
|
||||
): Promise<void> => {
|
||||
const url = new URL(
|
||||
config?.debug ? '/debug/mp/collect' : '/mp/collect',
|
||||
'https://www.google-analytics.com',
|
||||
);
|
||||
if (options.apiSecret)
|
||||
url.searchParams.set('api_secret', options.apiSecret);
|
||||
if (options.measurementId)
|
||||
url.searchParams.set('measurement_id', options.measurementId);
|
||||
|
||||
const userProperties = {
|
||||
language: data.meta.language,
|
||||
screen: data.meta.screen,
|
||||
...data.user.properties,
|
||||
};
|
||||
const mappedUserProperties = Object.fromEntries(
|
||||
Object.entries(userProperties).map(([name, value]) => [
|
||||
name,
|
||||
value == null ? undefined : { value },
|
||||
]),
|
||||
);
|
||||
|
||||
await fetch(url.href, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
client_id: data.user.id,
|
||||
consent: {
|
||||
ad_user_data: 'DENIED',
|
||||
ad_personalization: 'DENIED',
|
||||
},
|
||||
user_properties: mappedUserProperties,
|
||||
events: [
|
||||
{
|
||||
name: eventName,
|
||||
params: {
|
||||
session_id: data.meta.sessionId,
|
||||
engagement_time_msec: DEFAULT_ENGAGEMENT_TIME_IN_MSEC,
|
||||
...eventProperties,
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
identify: () => Promise.resolve(), // No-op, user data uploaded in page/track
|
||||
page: (event) =>
|
||||
send(event, 'page_view', {
|
||||
page_title: event.page.title,
|
||||
page_location: event.page.location,
|
||||
}),
|
||||
track: (event) => send(event, event.event.name, event.event.properties),
|
||||
};
|
||||
},
|
||||
);
|
||||
@@ -0,0 +1,70 @@
|
||||
import { defineAnalyticsProvider } from '../client';
|
||||
|
||||
export interface UmamiProviderOptions {
|
||||
apiUrl: string;
|
||||
websiteId: string;
|
||||
domain: string;
|
||||
}
|
||||
|
||||
export const umami = defineAnalyticsProvider<UmamiProviderOptions>(
|
||||
(_, config, options) => {
|
||||
const send = (payload: UmamiPayload) => {
|
||||
if (config.debug) {
|
||||
console.debug('[@wxt-dev/analytics] Sending event to Umami:', payload);
|
||||
}
|
||||
return fetch(`${options.apiUrl}/send`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ type: 'event', payload }),
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
identify: () => Promise.resolve(), // No-op, user data uploaded in page/track
|
||||
page: async (event) => {
|
||||
await send({
|
||||
name: 'page_view',
|
||||
website: options.websiteId,
|
||||
url: event.page.url,
|
||||
hostname: options.domain,
|
||||
language: event.meta.language ?? '',
|
||||
referrer: event.meta.referrer ?? '',
|
||||
screen: event.meta.screen ?? '',
|
||||
title: event.page.title ?? '<blank>',
|
||||
data: event.user.properties,
|
||||
});
|
||||
},
|
||||
track: async (event) => {
|
||||
await send({
|
||||
name: event.event.name,
|
||||
website: options.websiteId,
|
||||
url: event.meta.url ?? '/',
|
||||
title: '<blank>',
|
||||
hostname: options.domain,
|
||||
language: event.meta.language ?? '',
|
||||
referrer: event.meta.referrer ?? '',
|
||||
screen: event.meta.screen ?? '',
|
||||
data: {
|
||||
...event.event.properties,
|
||||
...event.user.properties,
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
/** @see https://umami.is/docs/api/sending-stats#post-/api/send */
|
||||
interface UmamiPayload {
|
||||
hostname?: string;
|
||||
language?: string;
|
||||
referrer?: string;
|
||||
screen?: string;
|
||||
title?: string;
|
||||
url?: string;
|
||||
website: string;
|
||||
name: string;
|
||||
data?: Record<string, string | undefined>;
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
export interface Analytics {
|
||||
/** Report a page change */
|
||||
page: (url: string) => void;
|
||||
/** Report a custom event */
|
||||
track: (eventName: string, eventProperties?: Record<string, string>) => void;
|
||||
/** Save information about the user */
|
||||
identify: (userId: string, userProperties?: Record<string, string>) => void;
|
||||
/** Automatically setup and track user interactions, returning a function to remove any listeners that were setup. */
|
||||
autoTrack: (root: Document | ShadowRoot | Element) => () => void;
|
||||
/** Calls `config.enabled.setValue` */
|
||||
setEnabled: (enabled: boolean) => void;
|
||||
}
|
||||
|
||||
export interface AnalyticsConfig {
|
||||
/**
|
||||
* Array of providers to send analytics to.
|
||||
*/
|
||||
providers: AnalyticsProvider[];
|
||||
/**
|
||||
* Enable debug logs and other provider-specific debugging features.
|
||||
*/
|
||||
debug?: boolean;
|
||||
/**
|
||||
* Extension version, defaults to `browser.runtime.getManifest().version`.
|
||||
*/
|
||||
version?: string;
|
||||
/**
|
||||
* Configure how the enabled flag is persisted. Defaults to using `""` in local extension storage.
|
||||
*/
|
||||
enabled?: AnalyticsStorageItem<boolean>;
|
||||
/**
|
||||
* Configure how the user Id is persisted
|
||||
*/
|
||||
userId?: AnalyticsStorageItem<string>;
|
||||
/**
|
||||
* Configure how user properties are persisted
|
||||
*/
|
||||
userProperties?: AnalyticsStorageItem<Record<string, string>>;
|
||||
}
|
||||
|
||||
export interface AnalyticsStorageItem<T> {
|
||||
getValue: () => T | Promise<T>;
|
||||
setValue?: (newValue: T) => void | Promise<void>;
|
||||
}
|
||||
|
||||
export type AnalyticsProvider = (
|
||||
analytics: Analytics,
|
||||
config: AnalyticsConfig,
|
||||
) => {
|
||||
/** Upload a page view event */
|
||||
page: (event: AnalyticsPageViewEvent) => Promise<void>;
|
||||
/** Upload a custom event */
|
||||
track: (event: AnalyticsTrackEvent) => Promise<void>;
|
||||
/** Upload information about the user */
|
||||
identify: (event: BaseAnalyticsEvent) => Promise<void>;
|
||||
};
|
||||
|
||||
export interface BaseAnalyticsEvent {
|
||||
meta: AnalyticsEventMetadata;
|
||||
user: {
|
||||
id: string;
|
||||
properties: Record<string, string | undefined>;
|
||||
};
|
||||
}
|
||||
|
||||
export interface AnalyticsEventMetadata {
|
||||
/** Identifier of the session the event was fired from */
|
||||
sessionId: number | undefined;
|
||||
/** `Date.now()` of when the event was reported */
|
||||
timestamp: number;
|
||||
/** `"1920x1080"` */
|
||||
screen: string | undefined;
|
||||
/** `document.referrer` */
|
||||
referrer: string | undefined;
|
||||
/** `navigator.language` */
|
||||
language: string | undefined;
|
||||
/** `location.href` */
|
||||
url: string | undefined;
|
||||
/** `document.title` */
|
||||
title: string | undefined;
|
||||
}
|
||||
|
||||
export interface AnalyticsPageInfo {
|
||||
url: string;
|
||||
title: string | undefined;
|
||||
location: string | undefined;
|
||||
}
|
||||
|
||||
export interface AnalyticsPageViewEvent extends BaseAnalyticsEvent {
|
||||
page: AnalyticsPageInfo;
|
||||
}
|
||||
|
||||
export interface AnalyticsTrackEvent extends BaseAnalyticsEvent {
|
||||
event: {
|
||||
name: string;
|
||||
properties?: Record<string, string>;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
{
|
||||
"name": "@wxt-dev/analytics",
|
||||
"version": "0.4.0",
|
||||
"description": "Add analytics to your web extension",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/wxt-dev/wxt.git",
|
||||
"directory": "packages/analytics"
|
||||
},
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.mts",
|
||||
"default": "./dist/index.mjs"
|
||||
},
|
||||
"./module": {
|
||||
"types": "./dist/module.d.mts",
|
||||
"default": "./dist/module.mjs"
|
||||
},
|
||||
"./background-plugin": {
|
||||
"types": "./dist/background-plugin.d.mts",
|
||||
"default": "./dist/background-plugin.mjs"
|
||||
},
|
||||
"./types": {
|
||||
"types": "./dist/types.d.mts"
|
||||
},
|
||||
"./providers/google-analytics-4": {
|
||||
"types": "./dist/providers/google-analytics-4.d.mts",
|
||||
"default": "./dist/providers/google-analytics-4.mjs"
|
||||
},
|
||||
"./providers/umami": {
|
||||
"types": "./dist/providers/umami.d.mts",
|
||||
"default": "./dist/providers/umami.mjs"
|
||||
}
|
||||
},
|
||||
"module": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"dev": "buildc --deps-only -- wxt",
|
||||
"dev:build": "buildc --deps-only -- wxt build",
|
||||
"check": "pnpm build && check",
|
||||
"build": "buildc -- unbuild",
|
||||
"prepack": "pnpm -s build",
|
||||
"prepare": "buildc --deps-only -- wxt prepare"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"wxt": ">=0.19.23"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@aklinker1/check": "^1.3.1",
|
||||
"@types/chrome": "^0.0.268",
|
||||
"@types/ua-parser-js": "^0.7.39",
|
||||
"prettier": "^3.3.2",
|
||||
"publint": "^0.2.8",
|
||||
"typescript": "^5.5.2",
|
||||
"unbuild": "^2.0.0",
|
||||
"wxt": "workspace:*"
|
||||
},
|
||||
"dependencies": {
|
||||
"ua-parser-js": "^1.0.38"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": ["../../tsconfig.base.json", "./.wxt/tsconfig.json"],
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"#analytics": ["./.wxt/analytics/index.ts"]
|
||||
},
|
||||
"types": ["chrome"]
|
||||
},
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { defineConfig } from 'wxt';
|
||||
|
||||
export default defineConfig({
|
||||
// Unimport doesn't look for imports in node_modules, so when developing a
|
||||
// WXT module, we need to disable this to simplify the build process
|
||||
imports: false,
|
||||
|
||||
manifest: {
|
||||
name: 'Analytics Demo',
|
||||
},
|
||||
});
|
||||
@@ -1,5 +1,17 @@
|
||||
# Changelog
|
||||
|
||||
## v1.1.3
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/module-react-v1.1.2...module-react-v1.1.3)
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Use react 19 in `@wxt-dev/module-react` and `templates/react` ([#1285](https://github.com/wxt-dev/wxt/pull/1285))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Aaron ([@aklinker1](http://github.com/aklinker1))
|
||||
|
||||
## v1.1.2
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/module-react-v1.1.1...module-react-v1.1.2)
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"email": "aaronklinker1+wxt@gmail.com"
|
||||
},
|
||||
"license": "MIT",
|
||||
"version": "1.1.2",
|
||||
"version": "1.1.3",
|
||||
"type": "module",
|
||||
"main": "./dist/index.cjs",
|
||||
"module": "./dist/index.mjs",
|
||||
@@ -47,15 +47,15 @@
|
||||
"wxt": ">=0.19.16"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vitejs/plugin-react": "^4.3.3"
|
||||
"@vitejs/plugin-react": "^4.3.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@aklinker1/check": "^1.4.5",
|
||||
"@types/react": "^18.3.12",
|
||||
"@types/react-dom": "^18.3.1",
|
||||
"@types/react": "^19.0.1",
|
||||
"@types/react-dom": "^19.0.2",
|
||||
"publint": "^0.2.12",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"typescript": "^5.6.3",
|
||||
"unbuild": "^2.0.0",
|
||||
"wxt": "workspace:*"
|
||||
|
||||
@@ -18,13 +18,13 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@wxt-dev/i18n": "workspace:*",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1"
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chrome": "^0.0.280",
|
||||
"@types/react": "^18.3.12",
|
||||
"@types/react-dom": "^18.3.1",
|
||||
"@types/react": "^19.0.1",
|
||||
"@types/react-dom": "^19.0.2",
|
||||
"@wxt-dev/auto-icons": "workspace:*",
|
||||
"@wxt-dev/unocss": "workspace:*",
|
||||
"sass": "^1.80.7",
|
||||
|
||||
@@ -1,5 +1,31 @@
|
||||
# Changelog
|
||||
|
||||
## v0.19.23
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.19.22...wxt-v0.19.23)
|
||||
|
||||
### 🚀 Enhancements
|
||||
|
||||
- **hooks:** Move `entrypoints:resolved` before debug logs and add `entrypoints:found` ([#1292](https://github.com/wxt-dev/wxt/pull/1292))
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Allow runtime registered content scripts to not have `matches` ([#1306](https://github.com/wxt-dev/wxt/pull/1306))
|
||||
- Properly close readline instance on close ([#1278](https://github.com/wxt-dev/wxt/pull/1278))
|
||||
|
||||
### 📖 Documentation
|
||||
|
||||
- Sync READMEs ([27298b7](https://github.com/wxt-dev/wxt/commit/27298b7))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- Simplify keyboard shortcuts ([#1284](https://github.com/wxt-dev/wxt/pull/1284))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Aaron ([@aklinker1](http://github.com/aklinker1))
|
||||
- Abhigyan Trips ([@abhigyantrips](http://github.com/abhigyantrips))
|
||||
|
||||
## v0.19.22
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.19.21...wxt-v0.19.22)
|
||||
@@ -2749,4 +2775,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))
|
||||
|
||||
@@ -11,6 +11,7 @@ const hooks: WxtHooks = {
|
||||
'build:done': vi.fn(),
|
||||
'build:manifestGenerated': vi.fn(),
|
||||
'build:publicAssets': vi.fn(),
|
||||
'entrypoints:found': vi.fn(),
|
||||
'entrypoints:resolved': vi.fn(),
|
||||
'entrypoints:grouped': vi.fn(),
|
||||
'vite:build:extendConfig': vi.fn(),
|
||||
@@ -60,6 +61,7 @@ describe('Hooks', () => {
|
||||
'build:done': false,
|
||||
'build:publicAssets': false,
|
||||
'build:manifestGenerated': false,
|
||||
'entrypoints:found': true,
|
||||
'entrypoints:grouped': false,
|
||||
'entrypoints:resolved': true,
|
||||
'vite:build:extendConfig': false,
|
||||
@@ -91,6 +93,7 @@ describe('Hooks', () => {
|
||||
'build:done': true,
|
||||
'build:publicAssets': true,
|
||||
'build:manifestGenerated': true,
|
||||
'entrypoints:found': true,
|
||||
'entrypoints:grouped': true,
|
||||
'entrypoints:resolved': true,
|
||||
'vite:build:extendConfig': 1,
|
||||
@@ -122,6 +125,7 @@ describe('Hooks', () => {
|
||||
'build:done': true,
|
||||
'build:publicAssets': true,
|
||||
'build:manifestGenerated': true,
|
||||
'entrypoints:found': true,
|
||||
'entrypoints:grouped': true,
|
||||
'entrypoints:resolved': true,
|
||||
'vite:build:extendConfig': 1,
|
||||
@@ -153,6 +157,7 @@ describe('Hooks', () => {
|
||||
'build:done': true,
|
||||
'build:publicAssets': true,
|
||||
'build:manifestGenerated': true,
|
||||
'entrypoints:found': 2,
|
||||
'entrypoints:grouped': true,
|
||||
'entrypoints:resolved': 2,
|
||||
'vite:build:extendConfig': 1,
|
||||
@@ -191,6 +196,7 @@ describe('Hooks', () => {
|
||||
'build:done': true,
|
||||
'build:publicAssets': true,
|
||||
'build:manifestGenerated': true,
|
||||
'entrypoints:found': true,
|
||||
'entrypoints:grouped': true,
|
||||
'entrypoints:resolved': true,
|
||||
'vite:build:extendConfig': 2,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "wxt",
|
||||
"type": "module",
|
||||
"version": "0.19.22",
|
||||
"version": "0.19.23",
|
||||
"description": "Next gen framework for developing web extensions",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -372,6 +372,9 @@ export async function createViteBuilder(
|
||||
},
|
||||
},
|
||||
watcher: viteServer.watcher,
|
||||
on(event, cb) {
|
||||
viteServer.httpServer?.on(event, cb);
|
||||
},
|
||||
};
|
||||
|
||||
return server;
|
||||
|
||||
@@ -171,6 +171,8 @@ async function createServerInternal(): Promise<WxtDevServer> {
|
||||
await runner.openBrowser();
|
||||
};
|
||||
|
||||
builderServer.on?.('close', () => keyboardShortcuts.stop());
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ export async function initialize(options: {
|
||||
template: string;
|
||||
packageManager: string;
|
||||
}) {
|
||||
consola.info('Initalizing new project');
|
||||
consola.info('Initializing new project');
|
||||
|
||||
const templates = await listTemplates();
|
||||
const defaultTemplate = templates.find(
|
||||
@@ -44,10 +44,7 @@ export async function initialize(options: {
|
||||
{ title: pc.red('npm'), value: 'npm' },
|
||||
{ title: pc.yellow('pnpm'), value: 'pnpm' },
|
||||
{ title: pc.cyan('yarn'), value: 'yarn' },
|
||||
{
|
||||
title: `${pc.magenta('bun')}${pc.gray(' (experimental)')}`,
|
||||
value: 'bun',
|
||||
},
|
||||
{ title: pc.magenta('bun'), value: 'bun' },
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -15,7 +15,6 @@ export interface KeyboardShortcutWatcher {
|
||||
export function createKeyboardShortcuts(
|
||||
server: WxtDevServer,
|
||||
): KeyboardShortcutWatcher {
|
||||
let isWatching = false;
|
||||
let rl: readline.Interface | undefined;
|
||||
|
||||
const handleInput = (line: string) => {
|
||||
@@ -27,7 +26,7 @@ export function createKeyboardShortcuts(
|
||||
|
||||
return {
|
||||
start() {
|
||||
if (isWatching) return;
|
||||
if (rl) return;
|
||||
|
||||
rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
@@ -35,18 +34,11 @@ export function createKeyboardShortcuts(
|
||||
});
|
||||
|
||||
rl.on('line', handleInput);
|
||||
isWatching = true;
|
||||
},
|
||||
|
||||
stop() {
|
||||
if (!isWatching) return;
|
||||
|
||||
if (rl) {
|
||||
rl.close();
|
||||
rl = undefined;
|
||||
}
|
||||
|
||||
isWatching = false;
|
||||
rl?.close();
|
||||
rl = undefined;
|
||||
},
|
||||
|
||||
printHelp(flags) {
|
||||
|
||||
@@ -35,7 +35,7 @@ export function createWebExtRunner(): ExtensionRunner {
|
||||
|
||||
const wxtUserConfig = wxt.config.runnerConfig.config;
|
||||
const userConfig = {
|
||||
console: wxtUserConfig?.openConsole,
|
||||
browserConsole: wxtUserConfig?.openConsole,
|
||||
devtools: wxtUserConfig?.openDevtools,
|
||||
startUrl: wxtUserConfig?.startUrls,
|
||||
keepProfileChanges: wxtUserConfig?.keepProfileChanges,
|
||||
|
||||
@@ -72,9 +72,10 @@ describe('Validation Utils', () => {
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
|
||||
it("should return an error when content scripts don't have a matches", () => {
|
||||
it('should return an error when "registration: manifest" content scripts don\'t have matches', () => {
|
||||
const entrypoint = fakeContentScriptEntrypoint({
|
||||
options: {
|
||||
registration: 'manifest',
|
||||
// @ts-expect-error
|
||||
matches: null,
|
||||
},
|
||||
@@ -83,7 +84,8 @@ describe('Validation Utils', () => {
|
||||
errors: [
|
||||
{
|
||||
type: 'error',
|
||||
message: '`matches` is required',
|
||||
message:
|
||||
'`matches` is required for manifest registered content scripts',
|
||||
value: null,
|
||||
entrypoint,
|
||||
},
|
||||
@@ -96,5 +98,24 @@ describe('Validation Utils', () => {
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should allow "registration: runtime" content scripts to not have matches', () => {
|
||||
const entrypoint = fakeContentScriptEntrypoint({
|
||||
options: {
|
||||
registration: 'runtime',
|
||||
// @ts-expect-error
|
||||
matches: null,
|
||||
},
|
||||
});
|
||||
const expected = {
|
||||
errors: [],
|
||||
errorCount: 0,
|
||||
warningCount: 0,
|
||||
};
|
||||
|
||||
const actual = validateEntrypoints([entrypoint]);
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
BackgroundEntrypoint,
|
||||
ContentScriptEntrypoint,
|
||||
Entrypoint,
|
||||
EntrypointInfo,
|
||||
GenericEntrypoint,
|
||||
OptionsEntrypoint,
|
||||
PopupEntrypoint,
|
||||
@@ -67,6 +68,8 @@ export async function findEntrypoints(): Promise<Entrypoint[]> {
|
||||
return results;
|
||||
}, []);
|
||||
|
||||
await wxt.hooks.callHook('entrypoints:found', wxt, entrypointInfos);
|
||||
|
||||
// Validation
|
||||
preventNoEntrypoints(entrypointInfos);
|
||||
preventDuplicateEntrypointNames(entrypointInfos);
|
||||
@@ -137,6 +140,8 @@ export async function findEntrypoints(): Promise<Entrypoint[]> {
|
||||
skipped: isEntrypointSkipped(entry),
|
||||
}));
|
||||
|
||||
await wxt.hooks.callHook('entrypoints:resolved', wxt, entrypoints);
|
||||
|
||||
wxt.logger.debug('All entrypoints:', entrypoints);
|
||||
const skippedEntrypointNames = entrypoints
|
||||
.filter((item) => item.skipped)
|
||||
@@ -151,17 +156,10 @@ export async function findEntrypoints(): Promise<Entrypoint[]> {
|
||||
].join('\n'),
|
||||
);
|
||||
}
|
||||
await wxt.hooks.callHook('entrypoints:resolved', wxt, entrypoints);
|
||||
|
||||
return entrypoints;
|
||||
}
|
||||
|
||||
interface EntrypointInfo {
|
||||
name: string;
|
||||
inputPath: string;
|
||||
type: Entrypoint['type'];
|
||||
}
|
||||
|
||||
/** Returns a map of input paths to the file's options. */
|
||||
async function importEntrypoints(infos: EntrypointInfo[]) {
|
||||
const resMap: Record<string, Record<string, any> | undefined> = {};
|
||||
|
||||
@@ -30,10 +30,13 @@ function validateContentScriptEntrypoint(
|
||||
definition: ContentScriptEntrypoint,
|
||||
): ValidationResult[] {
|
||||
const errors = validateBaseEntrypoint(definition);
|
||||
if (definition.options.matches == null) {
|
||||
if (
|
||||
definition.options.registration !== 'runtime' &&
|
||||
definition.options.matches == null
|
||||
) {
|
||||
errors.push({
|
||||
type: 'error',
|
||||
message: '`matches` is required',
|
||||
message: '`matches` is required for manifest registered content scripts',
|
||||
value: definition.options.matches,
|
||||
entrypoint: definition,
|
||||
});
|
||||
|
||||
@@ -789,6 +789,13 @@ export type Entrypoint =
|
||||
| OptionsEntrypoint
|
||||
| SidepanelEntrypoint;
|
||||
|
||||
export interface EntrypointInfo {
|
||||
name: string;
|
||||
/** Absolute path to the entrypoint file. */
|
||||
inputPath: string;
|
||||
type: Entrypoint['type'];
|
||||
}
|
||||
|
||||
export type EntrypointGroup = Entrypoint | Entrypoint[];
|
||||
|
||||
export type OnContentScriptStopped = (cb: () => void) => void;
|
||||
@@ -1091,6 +1098,7 @@ export interface WxtBuilderServer {
|
||||
* Chokidar file watcher instance.
|
||||
*/
|
||||
watcher: FSWatcher;
|
||||
on?(event: string, callback: () => void): void;
|
||||
}
|
||||
|
||||
export interface ServerInfo {
|
||||
@@ -1182,6 +1190,12 @@ export interface WxtHooks {
|
||||
wxt: Wxt,
|
||||
manifest: Manifest.WebExtensionManifest,
|
||||
) => HookResult;
|
||||
/**
|
||||
* Called once the names and paths of all entrypoints have been resolved.
|
||||
* @param wxt The configured WXT object
|
||||
* @param infos List of entrypoints found in the project's `entrypoints` directory
|
||||
*/
|
||||
'entrypoints:found': (wxt: Wxt, infos: EntrypointInfo[]) => HookResult;
|
||||
/**
|
||||
* Called once all entrypoints have been loaded from the `entrypointsDir`.
|
||||
* Use `wxt.builder.importEntrypoint` to load entrypoint options from the
|
||||
|
||||
Generated
+246
-96
@@ -83,6 +83,37 @@ importers:
|
||||
specifier: workspace:*
|
||||
version: link:packages/wxt
|
||||
|
||||
packages/analytics:
|
||||
dependencies:
|
||||
ua-parser-js:
|
||||
specifier: ^1.0.38
|
||||
version: 1.0.40
|
||||
devDependencies:
|
||||
'@aklinker1/check':
|
||||
specifier: ^1.3.1
|
||||
version: 1.4.5(typescript@5.6.3)
|
||||
'@types/chrome':
|
||||
specifier: ^0.0.268
|
||||
version: 0.0.268
|
||||
'@types/ua-parser-js':
|
||||
specifier: ^0.7.39
|
||||
version: 0.7.39
|
||||
prettier:
|
||||
specifier: ^3.3.2
|
||||
version: 3.3.3
|
||||
publint:
|
||||
specifier: ^0.2.8
|
||||
version: 0.2.12
|
||||
typescript:
|
||||
specifier: ^5.5.2
|
||||
version: 5.6.3
|
||||
unbuild:
|
||||
specifier: ^2.0.0
|
||||
version: 2.0.0(sass@1.80.7)(typescript@5.6.3)
|
||||
wxt:
|
||||
specifier: workspace:*
|
||||
version: link:../wxt
|
||||
|
||||
packages/auto-icons:
|
||||
dependencies:
|
||||
defu:
|
||||
@@ -160,27 +191,27 @@ importers:
|
||||
packages/module-react:
|
||||
dependencies:
|
||||
'@vitejs/plugin-react':
|
||||
specifier: ^4.3.3
|
||||
version: 4.3.3(vite@5.4.11(@types/node@20.17.6)(sass@1.80.7))
|
||||
specifier: ^4.3.4
|
||||
version: 4.3.4(vite@5.4.11(@types/node@20.17.6)(sass@1.80.7))
|
||||
devDependencies:
|
||||
'@aklinker1/check':
|
||||
specifier: ^1.4.5
|
||||
version: 1.4.5(typescript@5.6.3)
|
||||
'@types/react':
|
||||
specifier: ^18.3.12
|
||||
version: 18.3.12
|
||||
specifier: ^19.0.1
|
||||
version: 19.0.1
|
||||
'@types/react-dom':
|
||||
specifier: ^18.3.1
|
||||
version: 18.3.1
|
||||
specifier: ^19.0.2
|
||||
version: 19.0.2(@types/react@19.0.1)
|
||||
publint:
|
||||
specifier: ^0.2.12
|
||||
version: 0.2.12
|
||||
react:
|
||||
specifier: ^18.3.1
|
||||
version: 18.3.1
|
||||
specifier: ^19.0.0
|
||||
version: 19.0.0
|
||||
react-dom:
|
||||
specifier: ^18.3.1
|
||||
version: 18.3.1(react@18.3.1)
|
||||
specifier: ^19.0.0
|
||||
version: 19.0.0(react@19.0.0)
|
||||
typescript:
|
||||
specifier: ^5.6.3
|
||||
version: 5.6.3
|
||||
@@ -527,21 +558,21 @@ importers:
|
||||
specifier: workspace:*
|
||||
version: link:../i18n
|
||||
react:
|
||||
specifier: ^18.3.1
|
||||
version: 18.3.1
|
||||
specifier: ^19.0.0
|
||||
version: 19.0.0
|
||||
react-dom:
|
||||
specifier: ^18.3.1
|
||||
version: 18.3.1(react@18.3.1)
|
||||
specifier: ^19.0.0
|
||||
version: 19.0.0(react@19.0.0)
|
||||
devDependencies:
|
||||
'@types/chrome':
|
||||
specifier: ^0.0.280
|
||||
version: 0.0.280
|
||||
'@types/react':
|
||||
specifier: ^18.3.12
|
||||
version: 18.3.12
|
||||
specifier: ^19.0.1
|
||||
version: 19.0.1
|
||||
'@types/react-dom':
|
||||
specifier: ^18.3.1
|
||||
version: 18.3.1
|
||||
specifier: ^19.0.2
|
||||
version: 19.0.2(@types/react@19.0.1)
|
||||
'@wxt-dev/auto-icons':
|
||||
specifier: workspace:*
|
||||
version: link:../auto-icons
|
||||
@@ -675,20 +706,24 @@ packages:
|
||||
resolution: {integrity: sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/code-frame@7.26.2':
|
||||
resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/compat-data@7.24.7':
|
||||
resolution: {integrity: sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/compat-data@7.25.7':
|
||||
resolution: {integrity: sha512-9ickoLz+hcXCeh7jrcin+/SLWm+GkxE2kTvoYyp38p4WkdFXfQJxDFGWp/YHjiKLPx06z2A7W8XKuqbReXDzsw==}
|
||||
'@babel/compat-data@7.26.3':
|
||||
resolution: {integrity: sha512-nHIxvKPniQXpmQLb0vhY3VaFb3S0YrTAwpOWJZh1wn3oJPjJk9Asva204PsBdmAE8vpzfHudT8DB0scYvy9q0g==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/core@7.24.7':
|
||||
resolution: {integrity: sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/core@7.25.7':
|
||||
resolution: {integrity: sha512-yJ474Zv3cwiSOO9nXJuqzvwEeM+chDuQ8GJirw+pZ91sCGCyOZ3dJkVE09fTV0VEVzXyLWhh3G/AolYTPX7Mow==}
|
||||
'@babel/core@7.26.0':
|
||||
resolution: {integrity: sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/generator@7.24.7':
|
||||
@@ -699,12 +734,16 @@ packages:
|
||||
resolution: {integrity: sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/generator@7.26.3':
|
||||
resolution: {integrity: sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helper-compilation-targets@7.24.7':
|
||||
resolution: {integrity: sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helper-compilation-targets@7.25.7':
|
||||
resolution: {integrity: sha512-DniTEax0sv6isaw6qSQSfV4gVRNtw2rte8HHM45t9ZR0xILaufBRNkpMifCRiAPyvL4ACD6v0gfCwCmtOQaV4A==}
|
||||
'@babel/helper-compilation-targets@7.25.9':
|
||||
resolution: {integrity: sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helper-environment-visitor@7.24.7':
|
||||
@@ -727,8 +766,8 @@ packages:
|
||||
resolution: {integrity: sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helper-module-imports@7.25.7':
|
||||
resolution: {integrity: sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw==}
|
||||
'@babel/helper-module-imports@7.25.9':
|
||||
resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helper-module-transforms@7.24.7':
|
||||
@@ -737,8 +776,8 @@ packages:
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0
|
||||
|
||||
'@babel/helper-module-transforms@7.25.7':
|
||||
resolution: {integrity: sha512-k/6f8dKG3yDz/qCwSM+RKovjMix563SLxQFo0UhRNo239SP6n9u5/eLtKD6EAjwta2JHJ49CsD8pms2HdNiMMQ==}
|
||||
'@babel/helper-module-transforms@7.26.0':
|
||||
resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0
|
||||
@@ -747,12 +786,12 @@ packages:
|
||||
resolution: {integrity: sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helper-simple-access@7.24.7':
|
||||
resolution: {integrity: sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==}
|
||||
'@babel/helper-plugin-utils@7.25.9':
|
||||
resolution: {integrity: sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helper-simple-access@7.25.7':
|
||||
resolution: {integrity: sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ==}
|
||||
'@babel/helper-simple-access@7.24.7':
|
||||
resolution: {integrity: sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helper-split-export-declaration@7.24.7':
|
||||
@@ -771,6 +810,10 @@ packages:
|
||||
resolution: {integrity: sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helper-string-parser@7.25.9':
|
||||
resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helper-validator-identifier@7.24.7':
|
||||
resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
@@ -779,20 +822,24 @@ packages:
|
||||
resolution: {integrity: sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helper-validator-identifier@7.25.9':
|
||||
resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helper-validator-option@7.24.7':
|
||||
resolution: {integrity: sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helper-validator-option@7.25.7':
|
||||
resolution: {integrity: sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ==}
|
||||
'@babel/helper-validator-option@7.25.9':
|
||||
resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helpers@7.24.7':
|
||||
resolution: {integrity: sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helpers@7.25.7':
|
||||
resolution: {integrity: sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA==}
|
||||
'@babel/helpers@7.26.0':
|
||||
resolution: {integrity: sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/highlight@7.24.7':
|
||||
@@ -818,20 +865,25 @@ packages:
|
||||
engines: {node: '>=6.0.0'}
|
||||
hasBin: true
|
||||
|
||||
'@babel/parser@7.26.3':
|
||||
resolution: {integrity: sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
hasBin: true
|
||||
|
||||
'@babel/plugin-syntax-jsx@7.24.7':
|
||||
resolution: {integrity: sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-react-jsx-self@7.24.7':
|
||||
resolution: {integrity: sha512-fOPQYbGSgH0HUp4UJO4sMBFjY6DuWq+2i8rixyUMb3CdGixs/gccURvYOAhajBdKDoGajFr3mUq5rH3phtkGzw==}
|
||||
'@babel/plugin-transform-react-jsx-self@7.25.9':
|
||||
resolution: {integrity: sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/plugin-transform-react-jsx-source@7.24.7':
|
||||
resolution: {integrity: sha512-J2z+MWzZHVOemyLweMqngXrgGC42jQ//R0KdxqkIz/OrbVIIlhFI3WigZ5fO+nwFvBlncr4MGapd8vTyc7RPNQ==}
|
||||
'@babel/plugin-transform-react-jsx-source@7.25.9':
|
||||
resolution: {integrity: sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
@@ -852,6 +904,10 @@ packages:
|
||||
resolution: {integrity: sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/template@7.25.9':
|
||||
resolution: {integrity: sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/traverse@7.24.7':
|
||||
resolution: {integrity: sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
@@ -860,6 +916,10 @@ packages:
|
||||
resolution: {integrity: sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/traverse@7.26.4':
|
||||
resolution: {integrity: sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/types@7.24.7':
|
||||
resolution: {integrity: sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
@@ -872,6 +932,10 @@ packages:
|
||||
resolution: {integrity: sha512-vwIVdXG+j+FOpkwqHRcBgHLYNL7XMkufrlaFvL9o6Ai9sJn9+PdyIL5qa0XzTZw084c+u9LOls53eoZWP/W5WQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/types@7.26.3':
|
||||
resolution: {integrity: sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@bcoe/v8-coverage@0.2.3':
|
||||
resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
|
||||
|
||||
@@ -1952,15 +2016,23 @@ packages:
|
||||
'@types/prop-types@15.7.9':
|
||||
resolution: {integrity: sha512-n1yyPsugYNSmHgxDFjicaI2+gCNjsBck8UX9kuofAKlc0h1bL+20oSF72KeNaW2DUlesbEVCFgyV2dPGTiY42g==}
|
||||
|
||||
'@types/react-dom@18.3.1':
|
||||
resolution: {integrity: sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==}
|
||||
'@types/react-dom@19.0.2':
|
||||
resolution: {integrity: sha512-c1s+7TKFaDRRxr1TxccIX2u7sfCnc3RxkVyBIUA2lCpyqCF+QoAwQ/CBg7bsMdVwP120HEH143VQezKtef5nCg==}
|
||||
peerDependencies:
|
||||
'@types/react': ^19.0.0
|
||||
|
||||
'@types/react@18.3.12':
|
||||
resolution: {integrity: sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==}
|
||||
|
||||
'@types/react@19.0.1':
|
||||
resolution: {integrity: sha512-YW6614BDhqbpR5KtUYzTA+zlA7nayzJRA9ljz9CQoxthR0sDisYZLuvSMsil36t4EH/uAt8T52Xb4sVw17G+SQ==}
|
||||
|
||||
'@types/resolve@1.20.2':
|
||||
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
|
||||
|
||||
'@types/ua-parser-js@0.7.39':
|
||||
resolution: {integrity: sha512-P/oDfpofrdtF5xw433SPALpdSchtJmY7nsJItf8h3KXqOslkbySh8zq4dSWXH2oTjRvJ5PczVEoCZPow6GicLg==}
|
||||
|
||||
'@types/unist@3.0.2':
|
||||
resolution: {integrity: sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==}
|
||||
|
||||
@@ -2056,11 +2128,11 @@ packages:
|
||||
peerDependencies:
|
||||
vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0 || ^5.0.0-0
|
||||
|
||||
'@vitejs/plugin-react@4.3.3':
|
||||
resolution: {integrity: sha512-NooDe9GpHGqNns1i8XDERg0Vsg5SSYRhRxxyTGogUdkdNt47jal+fbuYi+Yfq6pzRCKXyoPcWisfxE6RIM3GKA==}
|
||||
'@vitejs/plugin-react@4.3.4':
|
||||
resolution: {integrity: sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug==}
|
||||
engines: {node: ^14.18.0 || >=16.0.0}
|
||||
peerDependencies:
|
||||
vite: ^4.2.0 || ^5.0.0
|
||||
vite: ^4.2.0 || ^5.0.0 || ^6.0.0
|
||||
|
||||
'@vitejs/plugin-vue@5.2.0':
|
||||
resolution: {integrity: sha512-7n7KdUEtx/7Yl7I/WVAMZ1bEb0eVvXF3ummWTeLcs/9gvo9pJhuLdouSXGjdZ/MKD1acf1I272+X0RMua4/R3g==}
|
||||
@@ -4222,6 +4294,11 @@ packages:
|
||||
peerDependencies:
|
||||
react: ^18.3.1
|
||||
|
||||
react-dom@19.0.0:
|
||||
resolution: {integrity: sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==}
|
||||
peerDependencies:
|
||||
react: ^19.0.0
|
||||
|
||||
react-refresh@0.14.2:
|
||||
resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -4230,6 +4307,10 @@ packages:
|
||||
resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
react@19.0.0:
|
||||
resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
readable-stream@2.3.8:
|
||||
resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==}
|
||||
|
||||
@@ -4350,6 +4431,9 @@ packages:
|
||||
scheduler@0.23.2:
|
||||
resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==}
|
||||
|
||||
scheduler@0.25.0:
|
||||
resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==}
|
||||
|
||||
scule@1.3.0:
|
||||
resolution: {integrity: sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==}
|
||||
|
||||
@@ -4721,6 +4805,10 @@ packages:
|
||||
engines: {node: '>=14.17'}
|
||||
hasBin: true
|
||||
|
||||
ua-parser-js@1.0.40:
|
||||
resolution: {integrity: sha512-z6PJ8Lml+v3ichVojCiB8toQJBuwR42ySM4ezjXIqXK3M0HczmKQ3LF4rhU55PfD99KEEXQG6yb7iOMyvYuHew==}
|
||||
hasBin: true
|
||||
|
||||
ufo@1.5.3:
|
||||
resolution: {integrity: sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==}
|
||||
|
||||
@@ -5269,9 +5357,15 @@ snapshots:
|
||||
'@babel/highlight': 7.25.7
|
||||
picocolors: 1.1.1
|
||||
|
||||
'@babel/code-frame@7.26.2':
|
||||
dependencies:
|
||||
'@babel/helper-validator-identifier': 7.25.9
|
||||
js-tokens: 4.0.0
|
||||
picocolors: 1.1.1
|
||||
|
||||
'@babel/compat-data@7.24.7': {}
|
||||
|
||||
'@babel/compat-data@7.25.7': {}
|
||||
'@babel/compat-data@7.26.3': {}
|
||||
|
||||
'@babel/core@7.24.7':
|
||||
dependencies:
|
||||
@@ -5293,18 +5387,18 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/core@7.25.7':
|
||||
'@babel/core@7.26.0':
|
||||
dependencies:
|
||||
'@ampproject/remapping': 2.3.0
|
||||
'@babel/code-frame': 7.25.7
|
||||
'@babel/generator': 7.25.7
|
||||
'@babel/helper-compilation-targets': 7.25.7
|
||||
'@babel/helper-module-transforms': 7.25.7(@babel/core@7.25.7)
|
||||
'@babel/helpers': 7.25.7
|
||||
'@babel/parser': 7.25.7
|
||||
'@babel/template': 7.25.7
|
||||
'@babel/traverse': 7.25.7
|
||||
'@babel/types': 7.25.7
|
||||
'@babel/code-frame': 7.26.2
|
||||
'@babel/generator': 7.26.3
|
||||
'@babel/helper-compilation-targets': 7.25.9
|
||||
'@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0)
|
||||
'@babel/helpers': 7.26.0
|
||||
'@babel/parser': 7.26.3
|
||||
'@babel/template': 7.25.9
|
||||
'@babel/traverse': 7.26.4
|
||||
'@babel/types': 7.26.3
|
||||
convert-source-map: 2.0.0
|
||||
debug: 4.3.7
|
||||
gensync: 1.0.0-beta.2
|
||||
@@ -5327,6 +5421,14 @@ snapshots:
|
||||
'@jridgewell/trace-mapping': 0.3.25
|
||||
jsesc: 3.0.2
|
||||
|
||||
'@babel/generator@7.26.3':
|
||||
dependencies:
|
||||
'@babel/parser': 7.26.3
|
||||
'@babel/types': 7.26.3
|
||||
'@jridgewell/gen-mapping': 0.3.5
|
||||
'@jridgewell/trace-mapping': 0.3.25
|
||||
jsesc: 3.0.2
|
||||
|
||||
'@babel/helper-compilation-targets@7.24.7':
|
||||
dependencies:
|
||||
'@babel/compat-data': 7.24.7
|
||||
@@ -5335,17 +5437,17 @@ snapshots:
|
||||
lru-cache: 5.1.1
|
||||
semver: 6.3.1
|
||||
|
||||
'@babel/helper-compilation-targets@7.25.7':
|
||||
'@babel/helper-compilation-targets@7.25.9':
|
||||
dependencies:
|
||||
'@babel/compat-data': 7.25.7
|
||||
'@babel/helper-validator-option': 7.25.7
|
||||
'@babel/compat-data': 7.26.3
|
||||
'@babel/helper-validator-option': 7.25.9
|
||||
browserslist: 4.24.0
|
||||
lru-cache: 5.1.1
|
||||
semver: 6.3.1
|
||||
|
||||
'@babel/helper-environment-visitor@7.24.7':
|
||||
dependencies:
|
||||
'@babel/types': 7.25.6
|
||||
'@babel/types': 7.25.7
|
||||
|
||||
'@babel/helper-function-name@7.24.7':
|
||||
dependencies:
|
||||
@@ -5367,10 +5469,10 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/helper-module-imports@7.25.7':
|
||||
'@babel/helper-module-imports@7.25.9':
|
||||
dependencies:
|
||||
'@babel/traverse': 7.25.7
|
||||
'@babel/types': 7.25.7
|
||||
'@babel/traverse': 7.26.4
|
||||
'@babel/types': 7.26.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -5385,26 +5487,20 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/helper-module-transforms@7.25.7(@babel/core@7.25.7)':
|
||||
'@babel/helper-module-transforms@7.26.0(@babel/core@7.26.0)':
|
||||
dependencies:
|
||||
'@babel/core': 7.25.7
|
||||
'@babel/helper-module-imports': 7.25.7
|
||||
'@babel/helper-simple-access': 7.25.7
|
||||
'@babel/helper-validator-identifier': 7.25.7
|
||||
'@babel/traverse': 7.25.7
|
||||
'@babel/core': 7.26.0
|
||||
'@babel/helper-module-imports': 7.25.9
|
||||
'@babel/helper-validator-identifier': 7.25.9
|
||||
'@babel/traverse': 7.26.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/helper-plugin-utils@7.24.7': {}
|
||||
|
||||
'@babel/helper-simple-access@7.24.7':
|
||||
dependencies:
|
||||
'@babel/traverse': 7.24.7
|
||||
'@babel/types': 7.25.6
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
'@babel/helper-plugin-utils@7.25.9': {}
|
||||
|
||||
'@babel/helper-simple-access@7.25.7':
|
||||
'@babel/helper-simple-access@7.24.7':
|
||||
dependencies:
|
||||
'@babel/traverse': 7.25.7
|
||||
'@babel/types': 7.25.7
|
||||
@@ -5413,7 +5509,7 @@ snapshots:
|
||||
|
||||
'@babel/helper-split-export-declaration@7.24.7':
|
||||
dependencies:
|
||||
'@babel/types': 7.25.6
|
||||
'@babel/types': 7.25.7
|
||||
|
||||
'@babel/helper-string-parser@7.24.7': {}
|
||||
|
||||
@@ -5421,23 +5517,27 @@ snapshots:
|
||||
|
||||
'@babel/helper-string-parser@7.25.7': {}
|
||||
|
||||
'@babel/helper-string-parser@7.25.9': {}
|
||||
|
||||
'@babel/helper-validator-identifier@7.24.7': {}
|
||||
|
||||
'@babel/helper-validator-identifier@7.25.7': {}
|
||||
|
||||
'@babel/helper-validator-identifier@7.25.9': {}
|
||||
|
||||
'@babel/helper-validator-option@7.24.7': {}
|
||||
|
||||
'@babel/helper-validator-option@7.25.7': {}
|
||||
'@babel/helper-validator-option@7.25.9': {}
|
||||
|
||||
'@babel/helpers@7.24.7':
|
||||
dependencies:
|
||||
'@babel/template': 7.24.7
|
||||
'@babel/types': 7.25.6
|
||||
|
||||
'@babel/helpers@7.25.7':
|
||||
'@babel/helpers@7.26.0':
|
||||
dependencies:
|
||||
'@babel/template': 7.25.7
|
||||
'@babel/types': 7.25.7
|
||||
'@babel/template': 7.25.9
|
||||
'@babel/types': 7.26.3
|
||||
|
||||
'@babel/highlight@7.24.7':
|
||||
dependencies:
|
||||
@@ -5465,20 +5565,24 @@ snapshots:
|
||||
dependencies:
|
||||
'@babel/types': 7.25.7
|
||||
|
||||
'@babel/parser@7.26.3':
|
||||
dependencies:
|
||||
'@babel/types': 7.26.3
|
||||
|
||||
'@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.24.7)':
|
||||
dependencies:
|
||||
'@babel/core': 7.24.7
|
||||
'@babel/helper-plugin-utils': 7.24.7
|
||||
|
||||
'@babel/plugin-transform-react-jsx-self@7.24.7(@babel/core@7.25.7)':
|
||||
'@babel/plugin-transform-react-jsx-self@7.25.9(@babel/core@7.26.0)':
|
||||
dependencies:
|
||||
'@babel/core': 7.25.7
|
||||
'@babel/helper-plugin-utils': 7.24.7
|
||||
'@babel/core': 7.26.0
|
||||
'@babel/helper-plugin-utils': 7.25.9
|
||||
|
||||
'@babel/plugin-transform-react-jsx-source@7.24.7(@babel/core@7.25.7)':
|
||||
'@babel/plugin-transform-react-jsx-source@7.25.9(@babel/core@7.26.0)':
|
||||
dependencies:
|
||||
'@babel/core': 7.25.7
|
||||
'@babel/helper-plugin-utils': 7.24.7
|
||||
'@babel/core': 7.26.0
|
||||
'@babel/helper-plugin-utils': 7.25.9
|
||||
|
||||
'@babel/runtime@7.24.7':
|
||||
dependencies:
|
||||
@@ -5498,6 +5602,12 @@ snapshots:
|
||||
'@babel/parser': 7.25.7
|
||||
'@babel/types': 7.25.7
|
||||
|
||||
'@babel/template@7.25.9':
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.26.2
|
||||
'@babel/parser': 7.26.3
|
||||
'@babel/types': 7.26.3
|
||||
|
||||
'@babel/traverse@7.24.7':
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.24.7
|
||||
@@ -5525,6 +5635,18 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/traverse@7.26.4':
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.26.2
|
||||
'@babel/generator': 7.26.3
|
||||
'@babel/parser': 7.26.3
|
||||
'@babel/template': 7.25.9
|
||||
'@babel/types': 7.26.3
|
||||
debug: 4.3.7
|
||||
globals: 11.12.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/types@7.24.7':
|
||||
dependencies:
|
||||
'@babel/helper-string-parser': 7.24.7
|
||||
@@ -5543,6 +5665,11 @@ snapshots:
|
||||
'@babel/helper-validator-identifier': 7.25.7
|
||||
to-fast-properties: 2.0.0
|
||||
|
||||
'@babel/types@7.26.3':
|
||||
dependencies:
|
||||
'@babel/helper-string-parser': 7.25.9
|
||||
'@babel/helper-validator-identifier': 7.25.9
|
||||
|
||||
'@bcoe/v8-coverage@0.2.3': {}
|
||||
|
||||
'@devicefarmer/adbkit-logcat@2.1.3': {}
|
||||
@@ -6334,19 +6461,27 @@ snapshots:
|
||||
'@types/node': 20.17.6
|
||||
kleur: 3.0.3
|
||||
|
||||
'@types/prop-types@15.7.9': {}
|
||||
'@types/prop-types@15.7.9':
|
||||
optional: true
|
||||
|
||||
'@types/react-dom@18.3.1':
|
||||
'@types/react-dom@19.0.2(@types/react@19.0.1)':
|
||||
dependencies:
|
||||
'@types/react': 18.3.12
|
||||
'@types/react': 19.0.1
|
||||
|
||||
'@types/react@18.3.12':
|
||||
dependencies:
|
||||
'@types/prop-types': 15.7.9
|
||||
csstype: 3.1.3
|
||||
optional: true
|
||||
|
||||
'@types/react@19.0.1':
|
||||
dependencies:
|
||||
csstype: 3.1.3
|
||||
|
||||
'@types/resolve@1.20.2': {}
|
||||
|
||||
'@types/ua-parser-js@0.7.39': {}
|
||||
|
||||
'@types/unist@3.0.2': {}
|
||||
|
||||
'@types/web-bluetooth@0.0.20': {}
|
||||
@@ -6511,11 +6646,11 @@ snapshots:
|
||||
- supports-color
|
||||
- vue
|
||||
|
||||
'@vitejs/plugin-react@4.3.3(vite@5.4.11(@types/node@20.17.6)(sass@1.80.7))':
|
||||
'@vitejs/plugin-react@4.3.4(vite@5.4.11(@types/node@20.17.6)(sass@1.80.7))':
|
||||
dependencies:
|
||||
'@babel/core': 7.25.7
|
||||
'@babel/plugin-transform-react-jsx-self': 7.24.7(@babel/core@7.25.7)
|
||||
'@babel/plugin-transform-react-jsx-source': 7.24.7(@babel/core@7.25.7)
|
||||
'@babel/core': 7.26.0
|
||||
'@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.0)
|
||||
'@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.0)
|
||||
'@types/babel__core': 7.20.5
|
||||
react-refresh: 0.14.2
|
||||
vite: 5.4.11(@types/node@20.17.6)(sass@1.80.7)
|
||||
@@ -6927,7 +7062,7 @@ snapshots:
|
||||
|
||||
caniuse-api@3.0.0:
|
||||
dependencies:
|
||||
browserslist: 4.23.1
|
||||
browserslist: 4.24.0
|
||||
caniuse-lite: 1.0.30001633
|
||||
lodash.memoize: 4.1.2
|
||||
lodash.uniq: 4.5.0
|
||||
@@ -8100,6 +8235,7 @@ snapshots:
|
||||
loose-envify@1.4.0:
|
||||
dependencies:
|
||||
js-tokens: 4.0.0
|
||||
optional: true
|
||||
|
||||
loupe@3.1.1:
|
||||
dependencies:
|
||||
@@ -8826,12 +8962,21 @@ snapshots:
|
||||
loose-envify: 1.4.0
|
||||
react: 18.3.1
|
||||
scheduler: 0.23.2
|
||||
optional: true
|
||||
|
||||
react-dom@19.0.0(react@19.0.0):
|
||||
dependencies:
|
||||
react: 19.0.0
|
||||
scheduler: 0.25.0
|
||||
|
||||
react-refresh@0.14.2: {}
|
||||
|
||||
react@18.3.1:
|
||||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
optional: true
|
||||
|
||||
react@19.0.0: {}
|
||||
|
||||
readable-stream@2.3.8:
|
||||
dependencies:
|
||||
@@ -8970,6 +9115,9 @@ snapshots:
|
||||
scheduler@0.23.2:
|
||||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
optional: true
|
||||
|
||||
scheduler@0.25.0: {}
|
||||
|
||||
scule@1.3.0: {}
|
||||
|
||||
@@ -9186,7 +9334,7 @@ snapshots:
|
||||
|
||||
stylehacks@7.0.2(postcss@8.4.39):
|
||||
dependencies:
|
||||
browserslist: 4.23.1
|
||||
browserslist: 4.24.0
|
||||
postcss: 8.4.39
|
||||
postcss-selector-parser: 6.1.0
|
||||
|
||||
@@ -9341,6 +9489,8 @@ snapshots:
|
||||
|
||||
typescript@5.6.3: {}
|
||||
|
||||
ua-parser-js@1.0.40: {}
|
||||
|
||||
ufo@1.5.3: {}
|
||||
|
||||
ufo@1.5.4: {}
|
||||
|
||||
@@ -15,14 +15,14 @@
|
||||
"postinstall": "wxt prepare"
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1"
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chrome": "^0.0.280",
|
||||
"@types/react": "^18.3.12",
|
||||
"@types/react-dom": "^18.3.1",
|
||||
"@wxt-dev/module-react": "^1.1.1",
|
||||
"@types/react": "^19.0.1",
|
||||
"@types/react-dom": "^19.0.2",
|
||||
"@wxt-dev/module-react": "^1.1.2",
|
||||
"typescript": "^5.6.3",
|
||||
"wxt": "^0.19.13"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user