@wxt-dev/analytics 0.5.1 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,6 @@
1
- declare const _default: () => void;
1
+ import "#analytics";
2
2
 
3
- export { _default as default };
3
+ //#region modules/analytics/background-plugin.d.ts
4
+ declare const _default: () => void;
5
+ //#endregion
6
+ export { _default as default };
@@ -1,6 +1,7 @@
1
- import '#analytics';
1
+ import "#analytics";
2
2
 
3
- const backgroundPlugin = () => {
4
- };
3
+ //#region modules/analytics/background-plugin.ts
4
+ var background_plugin_default = () => {};
5
5
 
6
- export { backgroundPlugin as default };
6
+ //#endregion
7
+ export { background_plugin_default as default };
package/dist/index.d.mts CHANGED
@@ -1,12 +1,13 @@
1
- import { AnalyticsConfig, Analytics, AnalyticsProvider } from './types.mjs';
1
+ import { Analytics, AnalyticsConfig, AnalyticsProvider } from "./types.mjs";
2
2
 
3
+ //#region modules/analytics/client.d.ts
3
4
  declare function createAnalytics(config?: AnalyticsConfig): Analytics;
4
- declare function defineAnalyticsProvider<T = never>(definition: (
5
- /** The analytics object. */
6
- analytics: Analytics,
7
- /** Config passed into the analytics module from `app.config.ts`. */
8
- config: AnalyticsConfig,
9
- /** Provider options */
10
- options: T) => ReturnType<AnalyticsProvider>): (options: T) => AnalyticsProvider;
5
+ declare function defineAnalyticsProvider<T = never>(definition: (/** The analytics object. */
6
+
7
+ analytics: Analytics, /** Config passed into the analytics module from `app.config.ts`. */
11
8
 
12
- export { createAnalytics, defineAnalyticsProvider };
9
+ config: AnalyticsConfig, /** Provider options */
10
+
11
+ options: T) => ReturnType<AnalyticsProvider>): (options: T) => AnalyticsProvider;
12
+ //#endregion
13
+ export { createAnalytics, defineAnalyticsProvider };
package/dist/index.mjs CHANGED
@@ -1,206 +1,177 @@
1
- import { UAParser } from 'ua-parser-js';
2
- import { browser } from '@wxt-dev/browser';
1
+ import { UAParser } from "ua-parser-js";
2
+ import { browser } from "@wxt-dev/browser";
3
3
 
4
+ //#region modules/analytics/client.ts
4
5
  const ANALYTICS_PORT = "@wxt-dev/analytics";
6
+ const INTERACTIVE_TAGS = new Set([
7
+ "A",
8
+ "BUTTON",
9
+ "INPUT",
10
+ "SELECT",
11
+ "TEXTAREA"
12
+ ]);
13
+ const INTERACTIVE_ROLES = new Set([
14
+ "button",
15
+ "link",
16
+ "checkbox",
17
+ "menuitem",
18
+ "tab",
19
+ "radio"
20
+ ]);
5
21
  function createAnalytics(config) {
6
- if (!browser?.runtime?.id)
7
- throw Error(
8
- "Cannot use WXT analytics in contexts without access to the browser.runtime APIs"
9
- );
10
- if (config == null) {
11
- console.warn(
12
- "[@wxt-dev/analytics] Config not provided to createAnalytics. If you're using WXT, add the 'analytics' property to '<srcDir>/app.config.ts'."
13
- );
14
- }
15
- if (location.pathname === "/background.js")
16
- return createBackgroundAnalytics(config);
17
- return createFrontendAnalytics();
22
+ if (!browser?.runtime?.id) throw Error("Cannot use WXT analytics in contexts without access to the browser.runtime APIs");
23
+ 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'.");
24
+ if (location.pathname === "/background.js") return createBackgroundAnalytics(config);
25
+ return createFrontendAnalytics();
18
26
  }
27
+ /**
28
+ * Creates an analytics client in the background responsible for uploading events to the server to avoid CORS errors.
29
+ */
19
30
  function createBackgroundAnalytics(config) {
20
- const userIdStorage = config?.userId ?? defineStorageItem("wxt-analytics:user-id");
21
- const userPropertiesStorage = config?.userProperties ?? defineStorageItem(
22
- "wxt-analytics:user-properties",
23
- {}
24
- );
25
- const enabled = config?.enabled ?? defineStorageItem("local:wxt-analytics:enabled", false);
26
- const platformInfo = browser.runtime.getPlatformInfo();
27
- const userAgent = UAParser();
28
- let userId = Promise.resolve(userIdStorage.getValue()).then(
29
- (id) => id ?? globalThis.crypto.randomUUID()
30
- );
31
- let userProperties = userPropertiesStorage.getValue();
32
- const manifest = browser.runtime.getManifest();
33
- const getBackgroundMeta = () => ({
34
- timestamp: Date.now(),
35
- // Don't track sessions for the background, it can be running
36
- // indefinitely, and will inflate session duration stats.
37
- sessionId: void 0,
38
- language: navigator.language,
39
- referrer: void 0,
40
- screen: void 0,
41
- url: location.href,
42
- title: void 0
43
- });
44
- const getBaseEvent = async (meta) => {
45
- const platform = await platformInfo;
46
- return {
47
- meta,
48
- user: {
49
- id: await userId,
50
- properties: {
51
- version: config?.version ?? manifest.version_name ?? manifest.version,
52
- wxtMode: import.meta.env.MODE,
53
- wxtBrowser: import.meta.env.BROWSER,
54
- arch: platform.arch,
55
- os: platform.os,
56
- browser: userAgent.browser.name,
57
- browserVersion: userAgent.browser.version,
58
- ...await userProperties
59
- }
60
- }
61
- };
62
- };
63
- const analytics = {
64
- identify: async (newUserId, newUserProperties = {}, meta = getBackgroundMeta()) => {
65
- userId = Promise.resolve(newUserId);
66
- userProperties = Promise.resolve(newUserProperties);
67
- await Promise.all([
68
- userIdStorage.setValue?.(newUserId),
69
- userPropertiesStorage.setValue?.(newUserProperties)
70
- ]);
71
- const event = await getBaseEvent(meta);
72
- if (config?.debug) console.debug("[@wxt-dev/analytics] identify", event);
73
- if (await enabled.getValue()) {
74
- await Promise.allSettled(
75
- providers.map((provider) => provider.identify(event))
76
- );
77
- } else if (config?.debug) {
78
- console.debug(
79
- "[@wxt-dev/analytics] Analytics disabled, identify() not uploaded"
80
- );
81
- }
82
- },
83
- page: async (location2, meta = getBackgroundMeta()) => {
84
- const baseEvent = await getBaseEvent(meta);
85
- const event = {
86
- ...baseEvent,
87
- page: {
88
- url: meta?.url ?? globalThis.location?.href,
89
- location: location2,
90
- title: meta?.title ?? globalThis.document?.title
91
- }
92
- };
93
- if (config?.debug) console.debug("[@wxt-dev/analytics] page", event);
94
- if (await enabled.getValue()) {
95
- await Promise.allSettled(
96
- providers.map((provider) => provider.page(event))
97
- );
98
- } else if (config?.debug) {
99
- console.debug(
100
- "[@wxt-dev/analytics] Analytics disabled, page() not uploaded"
101
- );
102
- }
103
- },
104
- track: async (eventName, eventProperties, meta = getBackgroundMeta()) => {
105
- const baseEvent = await getBaseEvent(meta);
106
- const event = {
107
- ...baseEvent,
108
- event: { name: eventName, properties: eventProperties }
109
- };
110
- if (config?.debug) console.debug("[@wxt-dev/analytics] track", event);
111
- if (await enabled.getValue()) {
112
- await Promise.allSettled(
113
- providers.map((provider) => provider.track(event))
114
- );
115
- } else if (config?.debug) {
116
- console.debug(
117
- "[@wxt-dev/analytics] Analytics disabled, track() not uploaded"
118
- );
119
- }
120
- },
121
- setEnabled: async (newEnabled) => {
122
- await enabled.setValue?.(newEnabled);
123
- },
124
- autoTrack: () => {
125
- return () => {
126
- };
127
- }
128
- };
129
- const providers = config?.providers?.map((provider) => provider(analytics, config)) ?? [];
130
- browser.runtime.onConnect.addListener((port) => {
131
- if (port.name === ANALYTICS_PORT) {
132
- port.onMessage.addListener(({ fn, args }) => {
133
- void analytics[fn]?.(...args);
134
- });
135
- }
136
- });
137
- return analytics;
31
+ const userIdStorage = config?.userId ?? defineStorageItem("wxt-analytics:user-id");
32
+ const userPropertiesStorage = config?.userProperties ?? defineStorageItem("wxt-analytics:user-properties", {});
33
+ const enabled = config?.enabled ?? defineStorageItem("local:wxt-analytics:enabled", false);
34
+ const platformInfo = browser.runtime.getPlatformInfo();
35
+ const userAgent = UAParser();
36
+ let userId = Promise.resolve(userIdStorage.getValue()).then((id) => id ?? globalThis.crypto.randomUUID());
37
+ let userProperties = userPropertiesStorage.getValue();
38
+ const manifest = browser.runtime.getManifest();
39
+ const getBackgroundMeta = () => ({
40
+ timestamp: Date.now(),
41
+ sessionId: void 0,
42
+ language: navigator.language,
43
+ referrer: void 0,
44
+ screen: void 0,
45
+ url: location.href,
46
+ title: void 0
47
+ });
48
+ const getBaseEvent = async (meta) => {
49
+ const { arch, os } = await platformInfo;
50
+ return {
51
+ meta,
52
+ user: {
53
+ id: await userId,
54
+ properties: {
55
+ version: config?.version ?? manifest.version_name ?? manifest.version,
56
+ wxtMode: import.meta.env.MODE,
57
+ wxtBrowser: import.meta.env.BROWSER,
58
+ arch,
59
+ os,
60
+ browser: userAgent.browser.name,
61
+ browserVersion: userAgent.browser.version,
62
+ ...await userProperties
63
+ }
64
+ }
65
+ };
66
+ };
67
+ const analytics = {
68
+ identify: async (newUserId, newUserProperties = {}, meta = getBackgroundMeta()) => {
69
+ userId = Promise.resolve(newUserId);
70
+ userProperties = Promise.resolve(newUserProperties);
71
+ await Promise.all([userIdStorage.setValue?.(newUserId), userPropertiesStorage.setValue?.(newUserProperties)]);
72
+ const event = await getBaseEvent(meta);
73
+ if (config?.debug) console.debug("[@wxt-dev/analytics] identify", event);
74
+ if (await enabled.getValue()) await Promise.allSettled(providers.map((provider) => provider.identify(event)));
75
+ else if (config?.debug) console.debug("[@wxt-dev/analytics] Analytics disabled, identify() not uploaded");
76
+ },
77
+ page: async (location, meta = getBackgroundMeta()) => {
78
+ const event = {
79
+ ...await getBaseEvent(meta),
80
+ page: {
81
+ url: meta?.url ?? globalThis.location?.href,
82
+ location,
83
+ title: meta?.title ?? globalThis.document?.title
84
+ }
85
+ };
86
+ if (config?.debug) console.debug("[@wxt-dev/analytics] page", event);
87
+ if (await enabled.getValue()) await Promise.allSettled(providers.map((provider) => provider.page(event)));
88
+ else if (config?.debug) console.debug("[@wxt-dev/analytics] Analytics disabled, page() not uploaded");
89
+ },
90
+ track: async (eventName, eventProperties, meta = getBackgroundMeta()) => {
91
+ const event = {
92
+ ...await getBaseEvent(meta),
93
+ event: {
94
+ name: eventName,
95
+ properties: eventProperties
96
+ }
97
+ };
98
+ if (config?.debug) console.debug("[@wxt-dev/analytics] track", event);
99
+ if (await enabled.getValue()) await Promise.allSettled(providers.map((provider) => provider.track(event)));
100
+ else if (config?.debug) console.debug("[@wxt-dev/analytics] Analytics disabled, track() not uploaded");
101
+ },
102
+ setEnabled: async (newEnabled) => {
103
+ await enabled.setValue?.(newEnabled);
104
+ },
105
+ autoTrack: () => {
106
+ return () => {};
107
+ }
108
+ };
109
+ const providers = config?.providers?.map((provider) => provider(analytics, config)) ?? [];
110
+ browser.runtime.onConnect.addListener((port) => {
111
+ if (port.name === ANALYTICS_PORT) port.onMessage.addListener(({ fn, args }) => {
112
+ analytics[fn]?.(...args);
113
+ });
114
+ });
115
+ return analytics;
138
116
  }
117
+ /**
118
+ * Creates an analytics client for non-background contexts.
119
+ */
139
120
  function createFrontendAnalytics() {
140
- const port = browser.runtime.connect({ name: ANALYTICS_PORT });
141
- const sessionId = Date.now();
142
- const getFrontendMetadata = () => ({
143
- sessionId,
144
- timestamp: Date.now(),
145
- language: navigator.language,
146
- referrer: globalThis.document?.referrer || void 0,
147
- screen: globalThis.window ? `${globalThis.window.screen.width}x${globalThis.window.screen.height}` : void 0,
148
- url: location.href,
149
- title: document.title || void 0
150
- });
151
- const methodForwarder = (fn) => (...args) => {
152
- port.postMessage({ fn, args: [...args, getFrontendMetadata()] });
153
- };
154
- const analytics = {
155
- identify: methodForwarder("identify"),
156
- page: methodForwarder("page"),
157
- track: methodForwarder("track"),
158
- setEnabled: methodForwarder("setEnabled"),
159
- autoTrack: (root) => {
160
- const onClick = (event) => {
161
- const element = event.target;
162
- if (!element || !INTERACTIVE_TAGS.has(element.tagName) && !INTERACTIVE_ROLES.has(element.getAttribute("role")))
163
- return;
164
- void analytics.track("click", {
165
- tagName: element.tagName?.toLowerCase(),
166
- id: element.id || void 0,
167
- className: element.className || void 0,
168
- textContent: element.textContent?.substring(0, 50) || void 0,
169
- // Limit text content length
170
- href: element.href
171
- });
172
- };
173
- root.addEventListener("click", onClick, { capture: true, passive: true });
174
- return () => {
175
- root.removeEventListener("click", onClick);
176
- };
177
- }
178
- };
179
- return analytics;
121
+ const port = browser.runtime.connect({ name: ANALYTICS_PORT });
122
+ const sessionId = Date.now();
123
+ const getFrontendMetadata = () => ({
124
+ sessionId,
125
+ timestamp: Date.now(),
126
+ language: navigator.language,
127
+ referrer: globalThis.document?.referrer || void 0,
128
+ screen: globalThis.window ? `${globalThis.window.screen.width}x${globalThis.window.screen.height}` : void 0,
129
+ url: location.href,
130
+ title: document.title || void 0
131
+ });
132
+ const methodForwarder = (fn) => (...args) => {
133
+ port.postMessage({
134
+ fn,
135
+ args: [...args, getFrontendMetadata()]
136
+ });
137
+ };
138
+ const analytics = {
139
+ identify: methodForwarder("identify"),
140
+ page: methodForwarder("page"),
141
+ track: methodForwarder("track"),
142
+ setEnabled: methodForwarder("setEnabled"),
143
+ autoTrack: (root) => {
144
+ const onClick = (event) => {
145
+ const element = event.target;
146
+ if (!element || !INTERACTIVE_TAGS.has(element.tagName) && !INTERACTIVE_ROLES.has(element.getAttribute("role"))) return;
147
+ analytics.track("click", {
148
+ tagName: element.tagName?.toLowerCase(),
149
+ id: element.id || void 0,
150
+ className: element.className || void 0,
151
+ textContent: element.textContent?.substring(0, 50) || void 0,
152
+ href: element.href
153
+ });
154
+ };
155
+ root.addEventListener("click", onClick, {
156
+ capture: true,
157
+ passive: true
158
+ });
159
+ return () => {
160
+ root.removeEventListener("click", onClick);
161
+ };
162
+ }
163
+ };
164
+ return analytics;
180
165
  }
181
166
  function defineStorageItem(key, defaultValue) {
182
- return {
183
- getValue: async () => (await browser.storage.local.get(key))[key] ?? defaultValue,
184
- setValue: (newValue) => browser.storage.local.set({ [key]: newValue })
185
- };
167
+ return {
168
+ getValue: async () => (await browser.storage.local.get(key))[key] ?? defaultValue,
169
+ setValue: (newValue) => browser.storage.local.set({ [key]: newValue })
170
+ };
186
171
  }
187
- const INTERACTIVE_TAGS = /* @__PURE__ */ new Set([
188
- "A",
189
- "BUTTON",
190
- "INPUT",
191
- "SELECT",
192
- "TEXTAREA"
193
- ]);
194
- const INTERACTIVE_ROLES = /* @__PURE__ */ new Set([
195
- "button",
196
- "link",
197
- "checkbox",
198
- "menuitem",
199
- "tab",
200
- "radio"
201
- ]);
202
172
  function defineAnalyticsProvider(definition) {
203
- return (options) => (analytics, config) => definition(analytics, config, options);
173
+ return (options) => (analytics, config) => definition(analytics, config, options);
204
174
  }
205
175
 
206
- export { createAnalytics, defineAnalyticsProvider };
176
+ //#endregion
177
+ export { createAnalytics, defineAnalyticsProvider };
package/dist/module.d.mts CHANGED
@@ -1,11 +1,13 @@
1
- import * as wxt from 'wxt';
2
- import { AnalyticsConfig } from './types.mjs';
1
+ import { AnalyticsConfig } from "./types.mjs";
2
+ import * as wxt from "wxt";
3
+ import "wxt/utils/define-app-config";
3
4
 
5
+ //#region modules/analytics/index.d.ts
4
6
  declare module 'wxt/utils/define-app-config' {
5
- interface WxtAppConfig {
6
- analytics: AnalyticsConfig;
7
- }
7
+ interface WxtAppConfig {
8
+ analytics: AnalyticsConfig;
9
+ }
8
10
  }
9
11
  declare const _default: wxt.WxtModule<wxt.WxtModuleOptions>;
10
-
11
- export { _default as default };
12
+ //#endregion
13
+ export { _default as default };
package/dist/module.mjs CHANGED
@@ -1,61 +1,52 @@
1
- import 'wxt';
2
- import 'wxt/utils/define-app-config';
3
- import { defineWxtModule, addAlias, addWxtPlugin, addViteConfig } from 'wxt/modules';
4
- import { resolve } from 'node:path';
1
+ import "wxt";
2
+ import "wxt/utils/define-app-config";
3
+ import { addAlias, addViteConfig, addWxtPlugin, defineWxtModule } from "wxt/modules";
4
+ import { resolve } from "node:path";
5
5
 
6
- const index = defineWxtModule({
7
- name: "analytics",
8
- imports: [{ name: "analytics", from: "#analytics" }],
9
- setup(wxt) {
10
- const wxtAnalyticsFolder = resolve(wxt.config.wxtDir, "analytics");
11
- const wxtAnalyticsIndex = resolve(wxtAnalyticsFolder, "index.ts");
12
- const clientModuleId = "@wxt-dev/analytics" ;
13
- const pluginModuleId = "@wxt-dev/analytics/background-plugin" ;
14
- wxt.hook("build:manifestGenerated", (_, manifest) => {
15
- manifest.permissions ??= [];
16
- if (!manifest.permissions.includes("storage")) {
17
- manifest.permissions.push("storage");
18
- }
19
- });
20
- const wxtAnalyticsCode = [
21
- `import { createAnalytics } from '${clientModuleId }';`,
22
- `import { useAppConfig } from '#imports';`,
23
- ``,
24
- `export const analytics = createAnalytics(useAppConfig().analytics);`,
25
- ``
26
- ].join("\n");
27
- addAlias(wxt, "#analytics", wxtAnalyticsIndex);
28
- wxt.hook("prepare:types", async (_, entries) => {
29
- entries.push({
30
- path: wxtAnalyticsIndex,
31
- text: wxtAnalyticsCode
32
- });
33
- });
34
- wxt.hook("entrypoints:resolved", (_, entrypoints) => {
35
- const hasBackground = entrypoints.find(
36
- (entry) => entry.type === "background"
37
- );
38
- if (!hasBackground) {
39
- entrypoints.push({
40
- type: "background",
41
- inputPath: "virtual:user-background",
42
- name: "background",
43
- options: {},
44
- outputDir: wxt.config.outDir,
45
- skipped: false
46
- });
47
- }
48
- });
49
- addWxtPlugin(wxt, pluginModuleId);
50
- addViteConfig(wxt, () => ({
51
- optimizeDeps: {
52
- // Ensure the "#analytics" import is processed by vite in the background plugin
53
- exclude: ["@wxt-dev/analytics"],
54
- // Ensure the CJS subdependency is preprocessed into ESM
55
- include: ["@wxt-dev/analytics > ua-parser-js"]
56
- }
57
- }));
58
- }
6
+ //#region modules/analytics/index.ts
7
+ var analytics_default = defineWxtModule({
8
+ name: "analytics",
9
+ imports: [{
10
+ name: "analytics",
11
+ from: "#analytics"
12
+ }],
13
+ setup(wxt) {
14
+ const wxtAnalyticsIndex = resolve(resolve(wxt.config.wxtDir, "analytics"), "index.ts");
15
+ const clientModuleId = "@wxt-dev/analytics";
16
+ const pluginModuleId = "@wxt-dev/analytics/background-plugin";
17
+ wxt.hook("build:manifestGenerated", (_, manifest) => {
18
+ manifest.permissions ??= [];
19
+ if (!manifest.permissions.includes("storage")) manifest.permissions.push("storage");
20
+ });
21
+ const wxtAnalyticsCode = `import { createAnalytics } from '${clientModuleId}';
22
+ import { useAppConfig } from '#imports';
23
+
24
+ export const analytics = createAnalytics(useAppConfig().analytics);
25
+ `;
26
+ addAlias(wxt, "#analytics", wxtAnalyticsIndex);
27
+ wxt.hook("prepare:types", async (_, entries) => {
28
+ entries.push({
29
+ path: wxtAnalyticsIndex,
30
+ text: wxtAnalyticsCode
31
+ });
32
+ });
33
+ wxt.hook("entrypoints:resolved", (_, entrypoints) => {
34
+ if (!entrypoints.find((entry) => entry.type === "background")) entrypoints.push({
35
+ type: "background",
36
+ inputPath: "virtual:user-background",
37
+ name: "background",
38
+ options: {},
39
+ outputDir: wxt.config.outDir,
40
+ skipped: false
41
+ });
42
+ });
43
+ addWxtPlugin(wxt, pluginModuleId);
44
+ addViteConfig(wxt, () => ({ optimizeDeps: {
45
+ exclude: ["@wxt-dev/analytics"],
46
+ include: ["@wxt-dev/analytics > ua-parser-js"]
47
+ } }));
48
+ }
59
49
  });
60
50
 
61
- export { index as default };
51
+ //#endregion
52
+ export { analytics_default as default };
@@ -1,10 +1,11 @@
1
- import { AnalyticsProvider } from '../types.mjs';
1
+ import { AnalyticsProvider } from "../types.mjs";
2
2
 
3
+ //#region modules/analytics/providers/google-analytics-4.d.ts
3
4
  interface GoogleAnalytics4ProviderOptions {
4
- apiSecret: string;
5
- measurementId: string;
5
+ apiUrl?: string;
6
+ apiSecret: string;
7
+ measurementId: string;
6
8
  }
7
9
  declare const googleAnalytics4: (options: GoogleAnalytics4ProviderOptions) => AnalyticsProvider;
8
-
9
- export { googleAnalytics4 };
10
- export type { GoogleAnalytics4ProviderOptions };
10
+ //#endregion
11
+ export { GoogleAnalytics4ProviderOptions, googleAnalytics4 };
@@ -1,63 +1,48 @@
1
- import { defineAnalyticsProvider } from '../index.mjs';
2
- import 'ua-parser-js';
3
- import '@wxt-dev/browser';
1
+ import { defineAnalyticsProvider } from "../index.mjs";
4
2
 
3
+ //#region modules/analytics/providers/google-analytics-4.ts
5
4
  const DEFAULT_ENGAGEMENT_TIME_IN_MSEC = 100;
6
- const googleAnalytics4 = defineAnalyticsProvider(
7
- (_, config, options) => {
8
- const send = async (data, eventName, eventProperties) => {
9
- const url = new URL(
10
- config?.debug ? "/debug/mp/collect" : "/mp/collect",
11
- "https://www.google-analytics.com"
12
- );
13
- if (options.apiSecret)
14
- url.searchParams.set("api_secret", options.apiSecret);
15
- if (options.measurementId)
16
- url.searchParams.set("measurement_id", options.measurementId);
17
- const userProperties = {
18
- language: data.meta.language,
19
- screen: data.meta.screen,
20
- ...data.user.properties
21
- };
22
- const mappedUserProperties = Object.fromEntries(
23
- Object.entries(userProperties).map(([name, value]) => [
24
- name,
25
- value == null ? void 0 : { value }
26
- ])
27
- );
28
- await fetch(url.href, {
29
- method: "POST",
30
- body: JSON.stringify({
31
- client_id: data.user.id,
32
- consent: {
33
- ad_user_data: "DENIED",
34
- ad_personalization: "DENIED"
35
- },
36
- user_properties: mappedUserProperties,
37
- user_agent: navigator.userAgent,
38
- events: [
39
- {
40
- name: eventName,
41
- params: {
42
- session_id: data.meta.sessionId,
43
- engagement_time_msec: DEFAULT_ENGAGEMENT_TIME_IN_MSEC,
44
- ...eventProperties
45
- }
46
- }
47
- ]
48
- })
49
- });
50
- };
51
- return {
52
- identify: () => Promise.resolve(),
53
- // No-op, user data uploaded in page/track
54
- page: (event) => send(event, "page_view", {
55
- page_title: event.page.title,
56
- page_location: event.page.location
57
- }),
58
- track: (event) => send(event, event.event.name, event.event.properties)
59
- };
60
- }
61
- );
5
+ const googleAnalytics4 = defineAnalyticsProvider((_, config, options) => {
6
+ const send = async (data, eventName, eventProperties) => {
7
+ const url = new URL(config?.debug ? "/debug/mp/collect" : "/mp/collect", options.apiUrl ?? "https://www.google-analytics.com");
8
+ if (options.apiSecret) url.searchParams.set("api_secret", options.apiSecret);
9
+ if (options.measurementId) url.searchParams.set("measurement_id", options.measurementId);
10
+ const userProperties = {
11
+ language: data.meta.language,
12
+ screen: data.meta.screen,
13
+ ...data.user.properties
14
+ };
15
+ const mappedUserProperties = Object.fromEntries(Object.entries(userProperties).map(([name, value]) => [name, value == null ? void 0 : { value }]));
16
+ await fetch(url.href, {
17
+ method: "POST",
18
+ body: JSON.stringify({
19
+ client_id: data.user.id,
20
+ consent: {
21
+ ad_user_data: "DENIED",
22
+ ad_personalization: "DENIED"
23
+ },
24
+ user_properties: mappedUserProperties,
25
+ user_agent: navigator.userAgent,
26
+ events: [{
27
+ name: eventName,
28
+ params: {
29
+ session_id: data.meta.sessionId,
30
+ engagement_time_msec: DEFAULT_ENGAGEMENT_TIME_IN_MSEC,
31
+ ...eventProperties
32
+ }
33
+ }]
34
+ })
35
+ });
36
+ };
37
+ return {
38
+ identify: () => Promise.resolve(),
39
+ page: (event) => send(event, "page_view", {
40
+ page_title: event.page.title,
41
+ page_location: event.page.location
42
+ }),
43
+ track: (event) => send(event, event.event.name, event.event.properties)
44
+ };
45
+ });
62
46
 
63
- export { googleAnalytics4 };
47
+ //#endregion
48
+ export { googleAnalytics4 };
@@ -1,11 +1,11 @@
1
- import { AnalyticsProvider } from '../types.mjs';
1
+ import { AnalyticsProvider } from "../types.mjs";
2
2
 
3
+ //#region modules/analytics/providers/umami.d.ts
3
4
  interface UmamiProviderOptions {
4
- apiUrl: string;
5
- websiteId: string;
6
- domain: string;
5
+ apiUrl: string;
6
+ websiteId: string;
7
+ domain: string;
7
8
  }
8
9
  declare const umami: (options: UmamiProviderOptions) => AnalyticsProvider;
9
-
10
- export { umami };
11
- export type { UmamiProviderOptions };
10
+ //#endregion
11
+ export { UmamiProviderOptions, umami };
@@ -1,55 +1,51 @@
1
- import { defineAnalyticsProvider } from '../index.mjs';
2
- import 'ua-parser-js';
3
- import '@wxt-dev/browser';
1
+ import { defineAnalyticsProvider } from "../index.mjs";
4
2
 
5
- const umami = defineAnalyticsProvider(
6
- (_, config, options) => {
7
- const send = (payload) => {
8
- if (config.debug) {
9
- console.debug("[@wxt-dev/analytics] Sending event to Umami:", payload);
10
- }
11
- return fetch(`${options.apiUrl}/send`, {
12
- method: "POST",
13
- headers: {
14
- "Content-Type": "application/json"
15
- },
16
- body: JSON.stringify({ type: "event", payload })
17
- });
18
- };
19
- return {
20
- identify: () => Promise.resolve(),
21
- // No-op, user data uploaded in page/track
22
- page: async (event) => {
23
- await send({
24
- name: "page_view",
25
- website: options.websiteId,
26
- url: event.page.url,
27
- hostname: options.domain,
28
- language: event.meta.language ?? "",
29
- referrer: event.meta.referrer ?? "",
30
- screen: event.meta.screen ?? "",
31
- title: event.page.title ?? "<blank>",
32
- data: event.user.properties
33
- });
34
- },
35
- track: async (event) => {
36
- await send({
37
- name: event.event.name,
38
- website: options.websiteId,
39
- url: event.meta.url ?? "/",
40
- title: "<blank>",
41
- hostname: options.domain,
42
- language: event.meta.language ?? "",
43
- referrer: event.meta.referrer ?? "",
44
- screen: event.meta.screen ?? "",
45
- data: {
46
- ...event.event.properties,
47
- ...event.user.properties
48
- }
49
- });
50
- }
51
- };
52
- }
53
- );
3
+ //#region modules/analytics/providers/umami.ts
4
+ const umami = defineAnalyticsProvider((_, config, options) => {
5
+ const send = (payload) => {
6
+ if (config.debug) console.debug("[@wxt-dev/analytics] Sending event to Umami:", payload);
7
+ return fetch(`${options.apiUrl}/send`, {
8
+ method: "POST",
9
+ headers: { "Content-Type": "application/json" },
10
+ body: JSON.stringify({
11
+ type: "event",
12
+ payload
13
+ })
14
+ });
15
+ };
16
+ return {
17
+ identify: () => Promise.resolve(),
18
+ page: async (event) => {
19
+ await send({
20
+ name: "page_view",
21
+ website: options.websiteId,
22
+ url: event.page.url,
23
+ hostname: options.domain,
24
+ language: event.meta.language ?? "",
25
+ referrer: event.meta.referrer ?? "",
26
+ screen: event.meta.screen ?? "",
27
+ title: event.page.title ?? "<blank>",
28
+ data: event.user.properties
29
+ });
30
+ },
31
+ track: async (event) => {
32
+ await send({
33
+ name: event.event.name,
34
+ website: options.websiteId,
35
+ url: event.meta.url ?? "/",
36
+ title: "<blank>",
37
+ hostname: options.domain,
38
+ language: event.meta.language ?? "",
39
+ referrer: event.meta.referrer ?? "",
40
+ screen: event.meta.screen ?? "",
41
+ data: {
42
+ ...event.event.properties,
43
+ ...event.user.properties
44
+ }
45
+ });
46
+ }
47
+ };
48
+ });
54
49
 
55
- export { umami };
50
+ //#endregion
51
+ export { umami };
package/dist/types.d.mts CHANGED
@@ -1,90 +1,88 @@
1
+ //#region modules/analytics/types.d.ts
1
2
  interface Analytics {
2
- /** Report a page change. */
3
- page: (url: string) => void;
4
- /** Report a custom event. */
5
- track: (eventName: string, eventProperties?: Record<string, string>) => void;
6
- /** Save information about the user. */
7
- identify: (userId: string, userProperties?: Record<string, string>) => void;
8
- /** Automatically setup and track user interactions, returning a function to remove any listeners that were setup. */
9
- autoTrack: (root: Document | ShadowRoot | Element) => () => void;
10
- /** Calls `config.enabled.setValue`. */
11
- setEnabled: (enabled: boolean) => void;
3
+ /** Report a page change. */
4
+ page: (url: string) => void;
5
+ /** Report a custom event. */
6
+ track: (eventName: string, eventProperties?: Record<string, string>) => void;
7
+ /** Save information about the user. */
8
+ identify: (userId: string, userProperties?: Record<string, string>) => void;
9
+ /** Automatically setup and track user interactions, returning a function to remove any listeners that were setup. */
10
+ autoTrack: (root: Document | ShadowRoot | Element) => () => void;
11
+ /** Calls `config.enabled.setValue`. */
12
+ setEnabled: (enabled: boolean) => void;
12
13
  }
13
14
  interface AnalyticsConfig {
14
- /**
15
- * Array of providers to send analytics to.
16
- */
17
- providers: AnalyticsProvider[];
18
- /**
19
- * Enable debug logs and other provider-specific debugging features.
20
- */
21
- debug?: boolean;
22
- /**
23
- * Your extension's version, reported alongside events.
24
- * @default browser.runtime.getManifest().version`.
25
- */
26
- version?: string;
27
- /**
28
- * Configure how the enabled flag is persisted. Defaults to using `browser.storage.local`.
29
- */
30
- enabled?: AnalyticsStorageItem<boolean>;
31
- /**
32
- * Configure how the user Id is persisted. Defaults to using `browser.storage.local`.
33
- */
34
- userId?: AnalyticsStorageItem<string>;
35
- /**
36
- * Configure how user properties are persisted. Defaults to using `browser.storage.local`.
37
- */
38
- userProperties?: AnalyticsStorageItem<Record<string, string>>;
15
+ /**
16
+ * Array of providers to send analytics to.
17
+ */
18
+ providers: AnalyticsProvider[];
19
+ /**
20
+ * Enable debug logs and other provider-specific debugging features.
21
+ */
22
+ debug?: boolean;
23
+ /**
24
+ * Your extension's version, reported alongside events.
25
+ * @default browser.runtime.getManifest().version`.
26
+ */
27
+ version?: string;
28
+ /**
29
+ * Configure how the enabled flag is persisted. Defaults to using `browser.storage.local`.
30
+ */
31
+ enabled?: AnalyticsStorageItem<boolean>;
32
+ /**
33
+ * Configure how the user Id is persisted. Defaults to using `browser.storage.local`.
34
+ */
35
+ userId?: AnalyticsStorageItem<string>;
36
+ /**
37
+ * Configure how user properties are persisted. Defaults to using `browser.storage.local`.
38
+ */
39
+ userProperties?: AnalyticsStorageItem<Record<string, string>>;
39
40
  }
40
41
  interface AnalyticsStorageItem<T> {
41
- getValue: () => T | Promise<T>;
42
- setValue?: (newValue: T) => void | Promise<void>;
42
+ getValue: () => T | Promise<T>;
43
+ setValue?: (newValue: T) => void | Promise<void>;
43
44
  }
44
45
  type AnalyticsProvider = (analytics: Analytics, config: AnalyticsConfig) => {
45
- /** Upload a page view event. */
46
- page: (event: AnalyticsPageViewEvent) => Promise<void>;
47
- /** Upload a custom event. */
48
- track: (event: AnalyticsTrackEvent) => Promise<void>;
49
- /** Upload information about the user. */
50
- identify: (event: BaseAnalyticsEvent) => Promise<void>;
46
+ /** Upload a page view event. */page: (event: AnalyticsPageViewEvent) => Promise<void>; /** Upload a custom event. */
47
+ track: (event: AnalyticsTrackEvent) => Promise<void>; /** Upload information about the user. */
48
+ identify: (event: BaseAnalyticsEvent) => Promise<void>;
51
49
  };
52
50
  interface BaseAnalyticsEvent {
53
- meta: AnalyticsEventMetadata;
54
- user: {
55
- id: string;
56
- properties: Record<string, string | undefined>;
57
- };
51
+ meta: AnalyticsEventMetadata;
52
+ user: {
53
+ id: string;
54
+ properties: Record<string, string | undefined>;
55
+ };
58
56
  }
59
57
  interface AnalyticsEventMetadata {
60
- /** Identifier of the session the event was fired from. */
61
- sessionId: number | undefined;
62
- /** `Date.now()` of when the event was reported. */
63
- timestamp: number;
64
- /** Ex: `"1920x1080"`. */
65
- screen: string | undefined;
66
- /** `document.referrer` */
67
- referrer: string | undefined;
68
- /** `navigator.language` */
69
- language: string | undefined;
70
- /** `location.href` */
71
- url: string | undefined;
72
- /** `document.title` */
73
- title: string | undefined;
58
+ /** Identifier of the session the event was fired from. */
59
+ sessionId: number | undefined;
60
+ /** `Date.now()` of when the event was reported. */
61
+ timestamp: number;
62
+ /** Ex: `"1920x1080"`. */
63
+ screen: string | undefined;
64
+ /** `document.referrer` */
65
+ referrer: string | undefined;
66
+ /** `navigator.language` */
67
+ language: string | undefined;
68
+ /** `location.href` */
69
+ url: string | undefined;
70
+ /** `document.title` */
71
+ title: string | undefined;
74
72
  }
75
73
  interface AnalyticsPageInfo {
76
- url: string;
77
- title: string | undefined;
78
- location: string | undefined;
74
+ url: string;
75
+ title: string | undefined;
76
+ location: string | undefined;
79
77
  }
80
78
  interface AnalyticsPageViewEvent extends BaseAnalyticsEvent {
81
- page: AnalyticsPageInfo;
79
+ page: AnalyticsPageInfo;
82
80
  }
83
81
  interface AnalyticsTrackEvent extends BaseAnalyticsEvent {
84
- event: {
85
- name: string;
86
- properties?: Record<string, string>;
87
- };
82
+ event: {
83
+ name: string;
84
+ properties?: Record<string, string>;
85
+ };
88
86
  }
89
-
90
- export type { Analytics, AnalyticsConfig, AnalyticsEventMetadata, AnalyticsPageInfo, AnalyticsPageViewEvent, AnalyticsProvider, AnalyticsStorageItem, AnalyticsTrackEvent, BaseAnalyticsEvent };
87
+ //#endregion
88
+ export { Analytics, AnalyticsConfig, AnalyticsEventMetadata, AnalyticsPageInfo, AnalyticsPageViewEvent, AnalyticsProvider, AnalyticsStorageItem, AnalyticsTrackEvent, BaseAnalyticsEvent };
package/dist/types.mjs CHANGED
@@ -1 +1 @@
1
-
1
+ export { };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wxt-dev/analytics",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "description": "Add analytics to your web extension",
5
5
  "repository": {
6
6
  "type": "git",
@@ -35,7 +35,7 @@
35
35
  }
36
36
  },
37
37
  "module": "./dist/index.mjs",
38
- "types": "./dist/index.d.ts",
38
+ "types": "./dist/index.d.mts",
39
39
  "files": [
40
40
  "dist"
41
41
  ],
@@ -43,21 +43,19 @@
43
43
  "wxt": ">=0.20.0"
44
44
  },
45
45
  "devDependencies": {
46
- "@aklinker1/check": "^2.1.0",
47
46
  "@types/ua-parser-js": "^0.7.39",
48
- "publint": "^0.3.12",
49
- "typescript": "^5.9.2",
50
- "unbuild": "^3.6.1",
51
- "wxt": "0.20.8"
47
+ "publint": "^0.3.17",
48
+ "typescript": "^5.9.3",
49
+ "wxt": "0.20.16"
52
50
  },
53
51
  "dependencies": {
54
52
  "ua-parser-js": "^1.0.40",
55
- "@wxt-dev/browser": "^0.1.4"
53
+ "@wxt-dev/browser": "^0.1.36"
56
54
  },
57
55
  "scripts": {
58
56
  "dev": "buildc --deps-only -- wxt",
59
57
  "dev:build": "buildc --deps-only -- wxt build",
60
58
  "check": "pnpm build && check",
61
- "build": "buildc -- unbuild"
59
+ "build": "buildc -- tsdown"
62
60
  }
63
61
  }
@@ -1,3 +0,0 @@
1
- declare const _default: () => void;
2
-
3
- export { _default as default };
package/dist/index.d.ts DELETED
@@ -1,12 +0,0 @@
1
- import { AnalyticsConfig, Analytics, AnalyticsProvider } from './types.js';
2
-
3
- declare function createAnalytics(config?: AnalyticsConfig): Analytics;
4
- declare function defineAnalyticsProvider<T = never>(definition: (
5
- /** The analytics object. */
6
- analytics: Analytics,
7
- /** Config passed into the analytics module from `app.config.ts`. */
8
- config: AnalyticsConfig,
9
- /** Provider options */
10
- options: T) => ReturnType<AnalyticsProvider>): (options: T) => AnalyticsProvider;
11
-
12
- export { createAnalytics, defineAnalyticsProvider };
package/dist/module.d.ts DELETED
@@ -1,11 +0,0 @@
1
- import * as wxt from 'wxt';
2
- import { AnalyticsConfig } from './types.js';
3
-
4
- declare module 'wxt/utils/define-app-config' {
5
- interface WxtAppConfig {
6
- analytics: AnalyticsConfig;
7
- }
8
- }
9
- declare const _default: wxt.WxtModule<wxt.WxtModuleOptions>;
10
-
11
- export { _default as default };
@@ -1,10 +0,0 @@
1
- import { AnalyticsProvider } from '../types.js';
2
-
3
- interface GoogleAnalytics4ProviderOptions {
4
- apiSecret: string;
5
- measurementId: string;
6
- }
7
- declare const googleAnalytics4: (options: GoogleAnalytics4ProviderOptions) => AnalyticsProvider;
8
-
9
- export { googleAnalytics4 };
10
- export type { GoogleAnalytics4ProviderOptions };
@@ -1,11 +0,0 @@
1
- import { AnalyticsProvider } from '../types.js';
2
-
3
- interface UmamiProviderOptions {
4
- apiUrl: string;
5
- websiteId: string;
6
- domain: string;
7
- }
8
- declare const umami: (options: UmamiProviderOptions) => AnalyticsProvider;
9
-
10
- export { umami };
11
- export type { UmamiProviderOptions };
package/dist/types.d.ts DELETED
@@ -1,90 +0,0 @@
1
- interface Analytics {
2
- /** Report a page change. */
3
- page: (url: string) => void;
4
- /** Report a custom event. */
5
- track: (eventName: string, eventProperties?: Record<string, string>) => void;
6
- /** Save information about the user. */
7
- identify: (userId: string, userProperties?: Record<string, string>) => void;
8
- /** Automatically setup and track user interactions, returning a function to remove any listeners that were setup. */
9
- autoTrack: (root: Document | ShadowRoot | Element) => () => void;
10
- /** Calls `config.enabled.setValue`. */
11
- setEnabled: (enabled: boolean) => void;
12
- }
13
- interface AnalyticsConfig {
14
- /**
15
- * Array of providers to send analytics to.
16
- */
17
- providers: AnalyticsProvider[];
18
- /**
19
- * Enable debug logs and other provider-specific debugging features.
20
- */
21
- debug?: boolean;
22
- /**
23
- * Your extension's version, reported alongside events.
24
- * @default browser.runtime.getManifest().version`.
25
- */
26
- version?: string;
27
- /**
28
- * Configure how the enabled flag is persisted. Defaults to using `browser.storage.local`.
29
- */
30
- enabled?: AnalyticsStorageItem<boolean>;
31
- /**
32
- * Configure how the user Id is persisted. Defaults to using `browser.storage.local`.
33
- */
34
- userId?: AnalyticsStorageItem<string>;
35
- /**
36
- * Configure how user properties are persisted. Defaults to using `browser.storage.local`.
37
- */
38
- userProperties?: AnalyticsStorageItem<Record<string, string>>;
39
- }
40
- interface AnalyticsStorageItem<T> {
41
- getValue: () => T | Promise<T>;
42
- setValue?: (newValue: T) => void | Promise<void>;
43
- }
44
- type AnalyticsProvider = (analytics: Analytics, config: AnalyticsConfig) => {
45
- /** Upload a page view event. */
46
- page: (event: AnalyticsPageViewEvent) => Promise<void>;
47
- /** Upload a custom event. */
48
- track: (event: AnalyticsTrackEvent) => Promise<void>;
49
- /** Upload information about the user. */
50
- identify: (event: BaseAnalyticsEvent) => Promise<void>;
51
- };
52
- interface BaseAnalyticsEvent {
53
- meta: AnalyticsEventMetadata;
54
- user: {
55
- id: string;
56
- properties: Record<string, string | undefined>;
57
- };
58
- }
59
- interface AnalyticsEventMetadata {
60
- /** Identifier of the session the event was fired from. */
61
- sessionId: number | undefined;
62
- /** `Date.now()` of when the event was reported. */
63
- timestamp: number;
64
- /** Ex: `"1920x1080"`. */
65
- screen: string | undefined;
66
- /** `document.referrer` */
67
- referrer: string | undefined;
68
- /** `navigator.language` */
69
- language: string | undefined;
70
- /** `location.href` */
71
- url: string | undefined;
72
- /** `document.title` */
73
- title: string | undefined;
74
- }
75
- interface AnalyticsPageInfo {
76
- url: string;
77
- title: string | undefined;
78
- location: string | undefined;
79
- }
80
- interface AnalyticsPageViewEvent extends BaseAnalyticsEvent {
81
- page: AnalyticsPageInfo;
82
- }
83
- interface AnalyticsTrackEvent extends BaseAnalyticsEvent {
84
- event: {
85
- name: string;
86
- properties?: Record<string, string>;
87
- };
88
- }
89
-
90
- export type { Analytics, AnalyticsConfig, AnalyticsEventMetadata, AnalyticsPageInfo, AnalyticsPageViewEvent, AnalyticsProvider, AnalyticsStorageItem, AnalyticsTrackEvent, BaseAnalyticsEvent };