@wxt-dev/analytics 0.1.5 → 0.2.0

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,80 +1,29 @@
1
- import { defineWxtPlugin } from 'wxt/sandbox';
2
- import { storage } from 'wxt/storage';
3
- import { useAppConfig } from 'wxt/client';
4
- import { browser } from 'wxt/browser';
5
- import uaParser from 'ua-parser-js';
1
+ import { UAParser } from 'ua-parser-js';
6
2
 
7
- let analytics;
8
- const ANALYTICS_PORT = "wxt-analytics";
9
- const interactiveTags = /* @__PURE__ */ new Set(["A", "BUTTON", "INPUT", "SELECT", "TEXTAREA"]);
10
- const interactiveRoles = /* @__PURE__ */ new Set([
11
- "button",
12
- "link",
13
- "checkbox",
14
- "menuitem",
15
- "tab",
16
- "radio"
17
- ]);
18
- const client = defineWxtPlugin(() => {
19
- const isBackground = globalThis.window == null;
20
- analytics = isBackground ? createBackgroundAnalytics() : createAnalyticsForwarder();
21
- });
22
- function createAnalyticsForwarder() {
23
- const port = browser.runtime.connect({ name: ANALYTICS_PORT });
24
- const sessionId = Date.now();
25
- const getMetadata = () => ({
26
- sessionId,
27
- timestamp: Date.now(),
28
- language: navigator.language,
29
- referrer: globalThis.document?.referrer || void 0,
30
- screen: globalThis.window ? `${globalThis.window.screen.width}x${globalThis.window.screen.height}` : void 0,
31
- url: location.href
32
- });
33
- const methodForwarder = (fn) => (...args) => port.postMessage({ fn, args: [...args, getMetadata()] });
34
- const analytics2 = {
35
- identify: methodForwarder("identify"),
36
- page: methodForwarder("page"),
37
- track: methodForwarder("track"),
38
- setEnabled: methodForwarder("setEnabled"),
39
- autoTrack: (root) => {
40
- const onClick = (event) => {
41
- const element = event.target;
42
- if (!element || !interactiveTags.has(element.tagName) && !interactiveRoles.has(element.getAttribute("role")))
43
- return;
44
- void analytics2.track("click", {
45
- tagName: element.tagName?.toLowerCase(),
46
- id: element.id || void 0,
47
- className: element.className || void 0,
48
- textContent: element.textContent?.substring(0, 50) || void 0,
49
- // Limit text content length
50
- href: element.href
51
- });
52
- };
53
- root.addEventListener("click", onClick, { capture: true, passive: true });
54
- return () => {
55
- root.removeEventListener("click", onClick);
56
- };
57
- }
58
- };
59
- return analytics2;
3
+ const ANALYTICS_PORT = "@wxt-dev/analytics";
4
+ function createAnalytics(config) {
5
+ if (globalThis.chrome?.runtime?.id)
6
+ throw Error(
7
+ "Cannot use WXT analytics in contexts without access to the browser.runtime APIs"
8
+ );
9
+ if (location.pathname === "/background.js")
10
+ return createBackgroundAnalytics(config);
11
+ return createFrontendAnalytics();
60
12
  }
61
- function createBackgroundAnalytics() {
62
- const config = useAppConfig().analytics;
63
- const userIdStorage = config?.userId ?? storage.defineItem("local:wxt-analytics:user-id");
64
- const userPropertiesStorage = config?.userProperties ?? storage.defineItem(
13
+ function createBackgroundAnalytics(config) {
14
+ const userIdStorage = config?.userId ?? defineStorageItem("local:wxt-analytics:user-id");
15
+ const userPropertiesStorage = config?.userProperties ?? defineStorageItem(
65
16
  "local:wxt-analytics:user-properties",
66
- { defaultValue: {} }
17
+ {}
67
18
  );
68
- const enabled = config?.enabled ?? storage.defineItem("local:wxt-analytics:enabled", {
69
- defaultValue: false
70
- });
71
- const platformInfo = browser.runtime.getPlatformInfo();
72
- const userAgent = uaParser();
19
+ const enabled = config?.enabled ?? defineStorageItem("local:wxt-analytics:enabled", false);
20
+ const platformInfo = chrome.runtime.getPlatformInfo();
21
+ const userAgent = UAParser();
73
22
  let userId = Promise.resolve(userIdStorage.getValue()).then(
74
23
  (id) => id ?? globalThis.crypto.randomUUID()
75
24
  );
76
25
  let userProperties = userPropertiesStorage.getValue();
77
- const manifest = browser.runtime.getManifest();
26
+ const manifest = chrome.runtime.getManifest();
78
27
  const getBaseEvent = async (meta = {
79
28
  timestamp: Date.now(),
80
29
  // Don't track sessions for the background, it can be running
@@ -92,7 +41,8 @@ function createBackgroundAnalytics() {
92
41
  timestamp: meta.timestamp,
93
42
  screen: meta.screen,
94
43
  referrer: meta.referrer,
95
- language: meta.language
44
+ language: meta.language,
45
+ url: meta.url
96
46
  },
97
47
  user: {
98
48
  id: await userId,
@@ -109,7 +59,7 @@ function createBackgroundAnalytics() {
109
59
  }
110
60
  };
111
61
  };
112
- const analytics2 = {
62
+ const analytics = {
113
63
  identify: async (newUserId, newUserProperties = {}, forwardMeta) => {
114
64
  userId = Promise.resolve(newUserId);
115
65
  userProperties = Promise.resolve(newUserProperties);
@@ -132,7 +82,11 @@ function createBackgroundAnalytics() {
132
82
  const baseEvent = await getBaseEvent(forwardMeta);
133
83
  const event = {
134
84
  ...baseEvent,
135
- page: { url }
85
+ page: {
86
+ url,
87
+ location: globalThis.location?.href,
88
+ title: globalThis.document?.title
89
+ }
136
90
  };
137
91
  if (config?.debug)
138
92
  console.debug("[analytics] page", event);
@@ -168,15 +122,75 @@ function createBackgroundAnalytics() {
168
122
  };
169
123
  }
170
124
  };
171
- const providers = config?.providers?.map((provider) => provider(analytics2, config)) ?? [];
125
+ const providers = config?.providers?.map((provider) => provider(analytics, config)) ?? [];
172
126
  chrome.runtime.onConnect.addListener((port) => {
173
127
  if (port.name === ANALYTICS_PORT) {
174
128
  port.onMessage.addListener(({ fn, args }) => {
175
- void analytics2[fn]?.(...args);
129
+ void analytics[fn]?.(...args);
176
130
  });
177
131
  }
178
132
  });
179
- return analytics2;
133
+ return analytics;
134
+ }
135
+ function createFrontendAnalytics() {
136
+ const port = chrome.runtime.connect({ name: ANALYTICS_PORT });
137
+ const sessionId = Date.now();
138
+ const getMetadata = () => ({
139
+ sessionId,
140
+ timestamp: Date.now(),
141
+ language: navigator.language,
142
+ referrer: globalThis.document?.referrer || void 0,
143
+ screen: globalThis.window ? `${globalThis.window.screen.width}x${globalThis.window.screen.height}` : void 0,
144
+ url: location.href
145
+ });
146
+ const methodForwarder = (fn) => (...args) => port.postMessage({ fn, args: [...args, getMetadata()] });
147
+ const analytics = {
148
+ identify: methodForwarder("identify"),
149
+ page: methodForwarder("page"),
150
+ track: methodForwarder("track"),
151
+ setEnabled: methodForwarder("setEnabled"),
152
+ autoTrack: (root) => {
153
+ const onClick = (event) => {
154
+ const element = event.target;
155
+ if (!element || !INTERACTIVE_TAGS.has(element.tagName) && !INTERACTIVE_ROLES.has(element.getAttribute("role")))
156
+ return;
157
+ void analytics.track("click", {
158
+ tagName: element.tagName?.toLowerCase(),
159
+ id: element.id || void 0,
160
+ className: element.className || void 0,
161
+ textContent: element.textContent?.substring(0, 50) || void 0,
162
+ // Limit text content length
163
+ href: element.href
164
+ });
165
+ };
166
+ root.addEventListener("click", onClick, { capture: true, passive: true });
167
+ return () => {
168
+ root.removeEventListener("click", onClick);
169
+ };
170
+ }
171
+ };
172
+ return analytics;
180
173
  }
174
+ function defineStorageItem(key, defaultValue) {
175
+ return {
176
+ getValue: async () => (await chrome.storage.local.get(key))[key] ?? defaultValue,
177
+ setValue: (newValue) => chrome.storage.local.set({ [key]: newValue })
178
+ };
179
+ }
180
+ const INTERACTIVE_TAGS = /* @__PURE__ */ new Set([
181
+ "A",
182
+ "BUTTON",
183
+ "INPUT",
184
+ "SELECT",
185
+ "TEXTAREA"
186
+ ]);
187
+ const INTERACTIVE_ROLES = /* @__PURE__ */ new Set([
188
+ "button",
189
+ "link",
190
+ "checkbox",
191
+ "menuitem",
192
+ "tab",
193
+ "radio"
194
+ ]);
181
195
 
182
- export { analytics, client as default };
196
+ 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.5",
3
+ "version": "0.2.0",
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"