@wxt-dev/analytics 0.1.6 → 0.2.1

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.
package/README.md CHANGED
@@ -4,8 +4,8 @@ Add analytics, like google analytics, to your WXT extension.
4
4
 
5
5
  ## Supported Analytics Providers
6
6
 
7
- - Google Analytics (Measurement Protocol)
8
- - Umami
7
+ - [Google Analytics 4 (Measurement Protocol)](#google-analytics-4-measurement-protocol)
8
+ - [Umami](#umami)
9
9
 
10
10
  ## Installation
11
11
 
@@ -49,7 +49,7 @@ await analytics.identify('some-user-id');
49
49
 
50
50
  ## Providers
51
51
 
52
- ### Google Analytics (Measurement Protocol)
52
+ ### Google Analytics 4 (Measurement Protocol)
53
53
 
54
54
  Follow [Google's documentation](https://developer.chrome.com/docs/extensions/how-to/integrate/google-analytics-4#setup-credentials) to obtain your credentials:
55
55
 
package/dist/client.d.mts CHANGED
@@ -1,6 +1,5 @@
1
- import { a as Analytics } from './shared/analytics.c704a57b.mjs';
1
+ import { A as AnalyticsConfig, a as Analytics } from './shared/analytics.5d517cf0.mjs';
2
2
 
3
- declare let analytics: Analytics;
4
- declare const _default: any;
3
+ declare function createAnalytics(config?: AnalyticsConfig): Analytics;
5
4
 
6
- export { analytics, _default as default };
5
+ export { createAnalytics };
package/dist/client.d.ts CHANGED
@@ -1,6 +1,5 @@
1
- import { a as Analytics } from './shared/analytics.c704a57b.js';
1
+ import { A as AnalyticsConfig, a as Analytics } from './shared/analytics.5d517cf0.js';
2
2
 
3
- declare let analytics: Analytics;
4
- declare const _default: any;
3
+ declare function createAnalytics(config?: AnalyticsConfig): Analytics;
5
4
 
6
- export { analytics, _default as default };
5
+ export { createAnalytics };
package/dist/client.mjs CHANGED
@@ -1,67 +1,21 @@
1
- import { defineWxtPlugin } from 'wxt/sandbox';
2
- import { useAppConfig } from 'wxt/client';
3
- import uaParser from 'ua-parser-js';
1
+ import { UAParser } from 'ua-parser-js';
4
2
 
5
- const defineStorageItem = (key, defaultValue) => ({
6
- getValue: async () => (await chrome.storage.local.get(key))[key] ?? defaultValue,
7
- setValue: (newValue) => chrome.storage.local.set({ [key]: newValue })
8
- });
9
- let analytics;
10
- const ANALYTICS_PORT = "wxt-analytics";
11
- const interactiveTags = /* @__PURE__ */ new Set(["A", "BUTTON", "INPUT", "SELECT", "TEXTAREA"]);
12
- const interactiveRoles = /* @__PURE__ */ new Set([
13
- "button",
14
- "link",
15
- "checkbox",
16
- "menuitem",
17
- "tab",
18
- "radio"
19
- ]);
20
- const client = defineWxtPlugin(() => {
21
- const isBackground = globalThis.window == null;
22
- analytics = isBackground ? createBackgroundAnalytics() : createAnalyticsForwarder();
23
- });
24
- function createAnalyticsForwarder() {
25
- const port = chrome.runtime.connect({ name: ANALYTICS_PORT });
26
- const sessionId = Date.now();
27
- const getMetadata = () => ({
28
- sessionId,
29
- timestamp: Date.now(),
30
- language: navigator.language,
31
- referrer: globalThis.document?.referrer || void 0,
32
- screen: globalThis.window ? `${globalThis.window.screen.width}x${globalThis.window.screen.height}` : void 0,
33
- url: location.href
34
- });
35
- const methodForwarder = (fn) => (...args) => port.postMessage({ fn, args: [...args, getMetadata()] });
36
- const analytics2 = {
37
- identify: methodForwarder("identify"),
38
- page: methodForwarder("page"),
39
- track: methodForwarder("track"),
40
- setEnabled: methodForwarder("setEnabled"),
41
- autoTrack: (root) => {
42
- const onClick = (event) => {
43
- const element = event.target;
44
- if (!element || !interactiveTags.has(element.tagName) && !interactiveRoles.has(element.getAttribute("role")))
45
- return;
46
- void analytics2.track("click", {
47
- tagName: element.tagName?.toLowerCase(),
48
- id: element.id || void 0,
49
- className: element.className || void 0,
50
- textContent: element.textContent?.substring(0, 50) || void 0,
51
- // Limit text content length
52
- href: element.href
53
- });
54
- };
55
- root.addEventListener("click", onClick, { capture: true, passive: true });
56
- return () => {
57
- root.removeEventListener("click", onClick);
58
- };
59
- }
60
- };
61
- return analytics2;
3
+ const ANALYTICS_PORT = "@wxt-dev/analytics";
4
+ function createAnalytics(config) {
5
+ if (typeof chrome === "undefined" || !chrome?.runtime?.id)
6
+ throw Error(
7
+ "Cannot use WXT analytics in contexts without access to the browser.runtime APIs"
8
+ );
9
+ if (config == null) {
10
+ console.warn(
11
+ "[@wxt-dev/analytics] Config not provided to createAnalytics. If you're using WXT, add the 'analytics' property to '<srcDir>/app.config.ts'."
12
+ );
13
+ }
14
+ if (location.pathname === "/background.js")
15
+ return createBackgroundAnalytics(config);
16
+ return createFrontendAnalytics();
62
17
  }
63
- function createBackgroundAnalytics() {
64
- const config = useAppConfig().analytics;
18
+ function createBackgroundAnalytics(config) {
65
19
  const userIdStorage = config?.userId ?? defineStorageItem("local:wxt-analytics:user-id");
66
20
  const userPropertiesStorage = config?.userProperties ?? defineStorageItem(
67
21
  "local:wxt-analytics:user-properties",
@@ -69,7 +23,7 @@ function createBackgroundAnalytics() {
69
23
  );
70
24
  const enabled = config?.enabled ?? defineStorageItem("local:wxt-analytics:enabled", false);
71
25
  const platformInfo = chrome.runtime.getPlatformInfo();
72
- const userAgent = uaParser();
26
+ const userAgent = UAParser();
73
27
  let userId = Promise.resolve(userIdStorage.getValue()).then(
74
28
  (id) => id ?? globalThis.crypto.randomUUID()
75
29
  );
@@ -92,7 +46,8 @@ function createBackgroundAnalytics() {
92
46
  timestamp: meta.timestamp,
93
47
  screen: meta.screen,
94
48
  referrer: meta.referrer,
95
- language: meta.language
49
+ language: meta.language,
50
+ url: meta.url
96
51
  },
97
52
  user: {
98
53
  id: await userId,
@@ -109,7 +64,7 @@ function createBackgroundAnalytics() {
109
64
  }
110
65
  };
111
66
  };
112
- const analytics2 = {
67
+ const analytics = {
113
68
  identify: async (newUserId, newUserProperties = {}, forwardMeta) => {
114
69
  userId = Promise.resolve(newUserId);
115
70
  userProperties = Promise.resolve(newUserProperties);
@@ -132,7 +87,11 @@ function createBackgroundAnalytics() {
132
87
  const baseEvent = await getBaseEvent(forwardMeta);
133
88
  const event = {
134
89
  ...baseEvent,
135
- page: { url }
90
+ page: {
91
+ url,
92
+ location: globalThis.location?.href,
93
+ title: globalThis.document?.title
94
+ }
136
95
  };
137
96
  if (config?.debug)
138
97
  console.debug("[analytics] page", event);
@@ -168,15 +127,75 @@ function createBackgroundAnalytics() {
168
127
  };
169
128
  }
170
129
  };
171
- const providers = config?.providers?.map((provider) => provider(analytics2, config)) ?? [];
130
+ const providers = config?.providers?.map((provider) => provider(analytics, config)) ?? [];
172
131
  chrome.runtime.onConnect.addListener((port) => {
173
132
  if (port.name === ANALYTICS_PORT) {
174
133
  port.onMessage.addListener(({ fn, args }) => {
175
- void analytics2[fn]?.(...args);
134
+ void analytics[fn]?.(...args);
176
135
  });
177
136
  }
178
137
  });
179
- return analytics2;
138
+ return analytics;
180
139
  }
140
+ function createFrontendAnalytics() {
141
+ const port = chrome.runtime.connect({ name: ANALYTICS_PORT });
142
+ const sessionId = Date.now();
143
+ const getMetadata = () => ({
144
+ sessionId,
145
+ timestamp: Date.now(),
146
+ language: navigator.language,
147
+ referrer: globalThis.document?.referrer || void 0,
148
+ screen: globalThis.window ? `${globalThis.window.screen.width}x${globalThis.window.screen.height}` : void 0,
149
+ url: location.href
150
+ });
151
+ const methodForwarder = (fn) => (...args) => port.postMessage({ fn, args: [...args, getMetadata()] });
152
+ const analytics = {
153
+ identify: methodForwarder("identify"),
154
+ page: methodForwarder("page"),
155
+ track: methodForwarder("track"),
156
+ setEnabled: methodForwarder("setEnabled"),
157
+ autoTrack: (root) => {
158
+ const onClick = (event) => {
159
+ const element = event.target;
160
+ if (!element || !INTERACTIVE_TAGS.has(element.tagName) && !INTERACTIVE_ROLES.has(element.getAttribute("role")))
161
+ return;
162
+ void analytics.track("click", {
163
+ tagName: element.tagName?.toLowerCase(),
164
+ id: element.id || void 0,
165
+ className: element.className || void 0,
166
+ textContent: element.textContent?.substring(0, 50) || void 0,
167
+ // Limit text content length
168
+ href: element.href
169
+ });
170
+ };
171
+ root.addEventListener("click", onClick, { capture: true, passive: true });
172
+ return () => {
173
+ root.removeEventListener("click", onClick);
174
+ };
175
+ }
176
+ };
177
+ return analytics;
178
+ }
179
+ function defineStorageItem(key, defaultValue) {
180
+ return {
181
+ getValue: async () => (await chrome.storage.local.get(key))[key] ?? defaultValue,
182
+ setValue: (newValue) => chrome.storage.local.set({ [key]: newValue })
183
+ };
184
+ }
185
+ const INTERACTIVE_TAGS = /* @__PURE__ */ new Set([
186
+ "A",
187
+ "BUTTON",
188
+ "INPUT",
189
+ "SELECT",
190
+ "TEXTAREA"
191
+ ]);
192
+ const INTERACTIVE_ROLES = /* @__PURE__ */ new Set([
193
+ "button",
194
+ "link",
195
+ "checkbox",
196
+ "menuitem",
197
+ "tab",
198
+ "radio"
199
+ ]);
181
200
 
182
- export { analytics, client as default };
201
+ export { createAnalytics };
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as wxt from 'wxt';
2
- import { A as AnalyticsConfig } from './shared/analytics.c704a57b.mjs';
2
+ import { A as AnalyticsConfig } from './shared/analytics.5d517cf0.mjs';
3
3
 
4
4
  declare module 'wxt/sandbox' {
5
5
  interface WxtAppConfig {
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as wxt from 'wxt';
2
- import { A as AnalyticsConfig } from './shared/analytics.c704a57b.js';
2
+ import { A as AnalyticsConfig } from './shared/analytics.5d517cf0.js';
3
3
 
4
4
  declare module 'wxt/sandbox' {
5
5
  interface WxtAppConfig {
package/dist/index.mjs CHANGED
@@ -1,25 +1,34 @@
1
1
  import 'wxt';
2
2
  import 'wxt/sandbox';
3
- import { defineWxtModule, addWxtPlugin } from 'wxt/modules';
4
- import { dirname, resolve } from 'node:path';
5
- import { fileURLToPath } from 'url';
3
+ import { defineWxtModule, addAlias } from 'wxt/modules';
4
+ import { resolve } from 'node:path';
6
5
 
7
- const _dirname = dirname(fileURLToPath(import.meta.url));
8
- const pluginId = "@wxt-dev/analytics/client" ;
9
6
  const index = defineWxtModule({
10
7
  name: "analytics",
11
- imports: [{ name: "analytics", from: pluginId }],
8
+ imports: [{ name: "analytics", from: "#analytics" }],
12
9
  setup(wxt) {
13
- addWxtPlugin(
14
- wxt,
15
- resolve(_dirname, "client.mjs" )
16
- );
17
- wxt.hooks.hook("build:manifestGenerated", (_, manifest) => {
10
+ wxt.hook("build:manifestGenerated", (_, manifest) => {
18
11
  manifest.permissions ?? (manifest.permissions = []);
19
12
  if (!manifest.permissions.includes("storage")) {
20
13
  manifest.permissions.push("storage");
21
14
  }
22
15
  });
16
+ const analyticsModulePath = resolve(
17
+ wxt.config.wxtDir,
18
+ "analytics/index.ts"
19
+ );
20
+ const analyticsModuleCode = `
21
+ import { createAnalytics } from '@wxt-dev/analytics/client';
22
+
23
+ export const analytics = createAnalytics(useAppConfig().analytics);
24
+ `;
25
+ addAlias(wxt, "#analytics", analyticsModulePath);
26
+ wxt.hook("prepare:types", async (_, entries) => {
27
+ entries.push({
28
+ path: analyticsModulePath,
29
+ text: analyticsModuleCode
30
+ });
31
+ });
23
32
  }
24
33
  });
25
34
 
@@ -1,4 +1,4 @@
1
- import { b as AnalyticsProvider } from '../shared/analytics.c704a57b.mjs';
1
+ import { b as AnalyticsProvider } from '../shared/analytics.5d517cf0.mjs';
2
2
 
3
3
  interface GoogleAnalyticsProviderOptions {
4
4
  apiSecret: string;
@@ -1,4 +1,4 @@
1
- import { b as AnalyticsProvider } from '../shared/analytics.c704a57b.js';
1
+ import { b as AnalyticsProvider } from '../shared/analytics.5d517cf0.js';
2
2
 
3
3
  interface GoogleAnalyticsProviderOptions {
4
4
  apiSecret: string;
@@ -1,4 +1,4 @@
1
- import { b as AnalyticsProvider } from '../shared/analytics.c704a57b.mjs';
1
+ import { b as AnalyticsProvider } from '../shared/analytics.5d517cf0.mjs';
2
2
 
3
3
  interface UmamiProviderOptions {
4
4
  baseUrl: string;
@@ -1,4 +1,4 @@
1
- import { b as AnalyticsProvider } from '../shared/analytics.c704a57b.js';
1
+ import { b as AnalyticsProvider } from '../shared/analytics.5d517cf0.js';
2
2
 
3
3
  interface UmamiProviderOptions {
4
4
  baseUrl: string;
@@ -26,17 +26,17 @@ interface AnalyticsConfig {
26
26
  /**
27
27
  * Configure how the enabled flag is persisted
28
28
  */
29
- enabled?: AnalyticsStorageItemConfig<boolean>;
29
+ enabled?: AnalyticsStorageItem<boolean>;
30
30
  /**
31
31
  * Configure how the user Id is persisted
32
32
  */
33
- userId?: AnalyticsStorageItemConfig<string>;
33
+ userId?: AnalyticsStorageItem<string>;
34
34
  /**
35
35
  * Configure how user properties are persisted
36
36
  */
37
- userProperties?: AnalyticsStorageItemConfig<Record<string, string>>;
37
+ userProperties?: AnalyticsStorageItem<Record<string, string>>;
38
38
  }
39
- interface AnalyticsStorageItemConfig<T> {
39
+ interface AnalyticsStorageItem<T> {
40
40
  getValue: () => T | Promise<T>;
41
41
  setValue?: (newValue: T) => void | Promise<void>;
42
42
  }
@@ -55,13 +55,13 @@ interface BaseAnalyticsEvent {
55
55
  /** `Date.now()` of when the event was reported */
56
56
  timestamp: number;
57
57
  /** `"1920x1080"` */
58
- screen?: string;
58
+ screen: string | undefined;
59
59
  /** `document.referrer` */
60
- referrer?: string;
60
+ referrer: string | undefined;
61
61
  /** `navigator.language` */
62
- language?: string;
62
+ language: string | undefined;
63
63
  /** `location.href` */
64
- url?: string;
64
+ url: string | undefined;
65
65
  };
66
66
  user: {
67
67
  id: string;
@@ -70,8 +70,8 @@ interface BaseAnalyticsEvent {
70
70
  }
71
71
  interface AnalyticsPageInfo {
72
72
  url: string;
73
- title?: string;
74
- location?: string;
73
+ title: string | undefined;
74
+ location: string | undefined;
75
75
  }
76
76
  interface AnalyticsPageViewEvent extends BaseAnalyticsEvent {
77
77
  page: AnalyticsPageInfo;
@@ -26,17 +26,17 @@ interface AnalyticsConfig {
26
26
  /**
27
27
  * Configure how the enabled flag is persisted
28
28
  */
29
- enabled?: AnalyticsStorageItemConfig<boolean>;
29
+ enabled?: AnalyticsStorageItem<boolean>;
30
30
  /**
31
31
  * Configure how the user Id is persisted
32
32
  */
33
- userId?: AnalyticsStorageItemConfig<string>;
33
+ userId?: AnalyticsStorageItem<string>;
34
34
  /**
35
35
  * Configure how user properties are persisted
36
36
  */
37
- userProperties?: AnalyticsStorageItemConfig<Record<string, string>>;
37
+ userProperties?: AnalyticsStorageItem<Record<string, string>>;
38
38
  }
39
- interface AnalyticsStorageItemConfig<T> {
39
+ interface AnalyticsStorageItem<T> {
40
40
  getValue: () => T | Promise<T>;
41
41
  setValue?: (newValue: T) => void | Promise<void>;
42
42
  }
@@ -55,13 +55,13 @@ interface BaseAnalyticsEvent {
55
55
  /** `Date.now()` of when the event was reported */
56
56
  timestamp: number;
57
57
  /** `"1920x1080"` */
58
- screen?: string;
58
+ screen: string | undefined;
59
59
  /** `document.referrer` */
60
- referrer?: string;
60
+ referrer: string | undefined;
61
61
  /** `navigator.language` */
62
- language?: string;
62
+ language: string | undefined;
63
63
  /** `location.href` */
64
- url?: string;
64
+ url: string | undefined;
65
65
  };
66
66
  user: {
67
67
  id: string;
@@ -70,8 +70,8 @@ interface BaseAnalyticsEvent {
70
70
  }
71
71
  interface AnalyticsPageInfo {
72
72
  url: string;
73
- title?: string;
74
- location?: string;
73
+ title: string | undefined;
74
+ location: string | undefined;
75
75
  }
76
76
  interface AnalyticsPageViewEvent extends BaseAnalyticsEvent {
77
77
  page: AnalyticsPageInfo;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wxt-dev/analytics",
3
- "version": "0.1.6",
3
+ "version": "0.2.1",
4
4
  "description": "Add analytics to your web extension",
5
5
  "repository": {
6
6
  "type": "git",
@@ -43,7 +43,7 @@
43
43
  "publint": "^0.2.8",
44
44
  "typescript": "^5.5.2",
45
45
  "unbuild": "^2.0.0",
46
- "wxt": "0.18.13"
46
+ "wxt": "0.19.13"
47
47
  },
48
48
  "dependencies": {
49
49
  "ua-parser-js": "^1.0.38"