onedollarstats 0.0.1 → 0.0.4

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
@@ -7,10 +7,10 @@ A lightweight, zero-dependency analytics tracker for client apps. OneDollarStats
7
7
 
8
8
  ## Features
9
9
 
10
- -Automatic pageview tracking (supports client/server side navigation and hash routing)
11
- -Automatic UTM parameter collection
12
- -Automatic event tracking on clicks of elements with data-s-event attributes
13
- -Zero dependencies, easy to integrate
10
+ - Automatic pageview tracking (supports client/server side navigation and hash routing)
11
+ - Automatic UTM parameter collection
12
+ - Automatic event tracking on clicks of elements with data-s-event attributes
13
+ - Zero dependencies, easy to integrate
14
14
 
15
15
  ## Installation
16
16
 
@@ -36,7 +36,11 @@ configure({
36
36
  });
37
37
  ```
38
38
 
39
- #### Track Pageviews Manually
39
+ ### Manual Tracking
40
+
41
+ > **Note:** Any path or properties you pass to `view` or `event` take **priority** over values found on the page (like `data-s-path`, `data-s:view-props`, or meta tags).
42
+
43
+ **Track Pageviews**
40
44
 
41
45
  By default, pageviews are tracked automatically. If you want to track them manually (for example, with autocollect: false), you can use the `view` function:
42
46
 
@@ -50,7 +54,7 @@ view("/homepage");
50
54
  view("/checkout", { step: 2, plan: "pro" });
51
55
  ```
52
56
 
53
- #### Track Custom Events Manually
57
+ **Track Custom Events**
54
58
 
55
59
  The `event` function can accept different types of arguments depending on your needs:
56
60
 
package/dist/index.js CHANGED
@@ -43,6 +43,21 @@ var parseProps = (propsString) => {
43
43
  return Object.keys(propsObj).length === 0 ? void 0 : propsObj;
44
44
  };
45
45
 
46
+ // src/utils/resolve-path.ts
47
+ var resolvePath = (pathOrProps) => {
48
+ if (pathOrProps) return pathOrProps;
49
+ const sources = [
50
+ { value: document.body?.getAttribute("data-s-path"), name: "data-s-path" },
51
+ { value: document.body?.getAttribute("data-s:path"), name: "data-s:path" },
52
+ { value: document.querySelector('meta[name="stonks-path"]')?.getAttribute("content"), name: "meta[name='stonks-path']" }
53
+ ];
54
+ const existing = sources.filter(({ value }) => value);
55
+ if (existing.length > 1) {
56
+ console.warn("[onedollarstats] Multiple path sources found. Using priority order:", existing.map(({ name }) => name).join(" > "));
57
+ }
58
+ return existing[0]?.value ?? location.pathname;
59
+ };
60
+
46
61
  // src/utils/should-track.ts
47
62
  var matchesPattern = (path, pattern) => {
48
63
  const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
@@ -131,22 +146,30 @@ var _AnalyticsTracker = class _AnalyticsTracker {
131
146
  const tryImageBeacon = payloadBase64.length <= safeGetThreshold;
132
147
  if (tryImageBeacon) {
133
148
  const img = new Image(1, 1);
134
- img.onerror = () => {
135
- this.sendWithBeaconOrFetch(stringifiedBody).catch((err) => console.error("[onedollarstats] fallback failed:", err?.message || err));
136
- };
149
+ img.onerror = () => this.sendWithBeaconOrFetch(stringifiedBody);
137
150
  img.src = `${this.config.collectorUrl}?data=${payloadBase64}`;
138
- }
139
- await this.sendWithBeaconOrFetch(stringifiedBody);
151
+ } else await this.sendWithBeaconOrFetch(stringifiedBody);
140
152
  }
141
153
  // Prevents duplicate pageviews and respects include/exclude page rules. Automatically parses UTM parameters from URL.
142
154
  trackPageView({ path, props }, checkBlock = false) {
143
155
  if (!isClient()) return;
144
- const cleanPath = path || location.pathname;
145
- if (!this.config.hashRouting && this.lastPage === cleanPath) return;
146
- if (checkBlock && !shouldTrackPath(cleanPath, this.config)) return;
147
- this.lastPage = cleanPath;
156
+ const viewPath = resolvePath(path);
157
+ const viewProps = props || (() => {
158
+ const newProps = {};
159
+ const elements = document.querySelectorAll("[data-s\\:view-props], [data-s-view-props]");
160
+ for (const el of Array.from(elements)) {
161
+ const propsString = el.getAttribute("data-s-view-props") || el.getAttribute("data-s:view-props");
162
+ if (!propsString) continue;
163
+ const parsedProps = parseProps(propsString);
164
+ Object.assign(newProps, parsedProps);
165
+ }
166
+ return Object.keys(newProps).length ? newProps : void 0;
167
+ })();
168
+ if (!this.config.hashRouting && this.lastPage === viewPath) return;
169
+ if (checkBlock && !shouldTrackPath(viewPath, this.config)) return;
170
+ this.lastPage = viewPath;
148
171
  const utm = parseUtmParams(new URLSearchParams(location.search));
149
- this.send({ type: "PageView", path: cleanPath, props, utm });
172
+ this.send({ type: "PageView", path: viewPath, props: viewProps, utm });
150
173
  }
151
174
  /**
152
175
  * Tracks a custom event.
@@ -162,7 +185,7 @@ var _AnalyticsTracker = class _AnalyticsTracker {
162
185
  if (isLocalhost && !this.config.trackLocalhostAs || isHeadlessBrowser) return;
163
186
  const args = {};
164
187
  if (typeof pathOrProps === "string") {
165
- args.path = pathOrProps;
188
+ args.path = resolvePath(pathOrProps);
166
189
  args.props = props;
167
190
  } else if (typeof pathOrProps === "object") args.props = pathOrProps;
168
191
  this.send({ type: eventName, ...args });
@@ -197,7 +220,7 @@ var _AnalyticsTracker = class _AnalyticsTracker {
197
220
  setupAutocollect() {
198
221
  if (!isClient() || this.autocollectSetupDone) return;
199
222
  this.autocollectSetupDone = true;
200
- const handlePageView = () => this.trackPageView({ path: location.pathname }, true);
223
+ const handlePageView = () => this.trackPageView({}, true);
201
224
  const onVisibility = () => {
202
225
  if (document.visibilityState === "visible") handlePageView();
203
226
  };
@@ -220,11 +243,11 @@ var _AnalyticsTracker = class _AnalyticsTracker {
220
243
  let el = target;
221
244
  let depth = 0;
222
245
  while (el) {
223
- const eventName = el.getAttribute("data-s:event") ?? el.getAttribute("data-s-event");
246
+ const eventName = el.getAttribute("data-s-event") || el.getAttribute("data-s:event");
224
247
  if (eventName) {
225
- const propsAttr = el.getAttribute("data-s:event-props") ?? el.getAttribute("data-s-event-props");
248
+ const propsAttr = el.getAttribute("data-s-event-props") || el.getAttribute("data-s:event-props");
226
249
  const props = propsAttr ? parseProps(propsAttr) : void 0;
227
- const path = el.getAttribute("data-s:event-path") || el.getAttribute("data-s-event-path") || void 0;
250
+ const path = el.getAttribute("data-s-event-path") || el.getAttribute("data-s:event-path") || void 0;
228
251
  if (path && !shouldTrackPath(path, this.config) || !shouldTrackPath(location.pathname, this.config)) {
229
252
  return;
230
253
  }
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/utils/environment.ts", "../src/utils/parse-utm-params.ts", "../src/utils/props-parser.ts", "../src/utils/should-track.ts", "../src/index.ts"],
4
- "sourcesContent": ["export const getEnvironment = (): {\n isLocalhost: boolean;\n isHeadlessBrowser: boolean;\n} => ({\n isLocalhost: /^localhost$|^127(\\.[0-9]+){0,2}\\.[0-9]+$|^\\[::1?\\]$/.test(location.hostname) || location.protocol === \"file:\",\n isHeadlessBrowser: Boolean(\n window.navigator.webdriver ||\n (\"_phantom\" in window && window._phantom) ||\n (\"__nightmare\" in window && window.__nightmare) ||\n (\"Cypress\" in window && window.Cypress)\n )\n});\nexport const isClient = (): boolean => {\n try {\n // Basic checks for window and document\n if (typeof window === \"undefined\" || typeof document === \"undefined\") return false;\n\n // Check for navigator safely\n const ua = typeof navigator !== \"undefined\" ? navigator.userAgent : \"\";\n if (/node|jsdom/i.test(ua)) return false;\n return true;\n } catch {\n return false;\n }\n};\n", "export const parseUtmParams = (urlSearchParams: URLSearchParams) => {\n const utm: Record<string, string | string[]> = {};\n\n [\"utm_campaign\", \"utm_source\", \"utm_medium\", \"utm_term\", \"utm_content\"].forEach((key) => {\n const values = urlSearchParams.getAll(key);\n if (values.length === 1) {\n utm[key] = values[0];\n } else if (values.length > 1) {\n utm[key] = values; // store array if multiple values\n }\n });\n\n return utm;\n};\n", "export const parseProps = (propsString: string): Record<string, string> | undefined => {\n if (!propsString) return undefined;\n // \"key1=value1;key2=value2\"\n\n const splittedProps = propsString.split(\";\");\n const propsObj: Record<string, string> = {};\n\n for (const keyValueString of splittedProps) {\n const keyValuePair = keyValueString.split(\"=\").map((el) => el.trim());\n if (keyValuePair.length !== 2 || keyValuePair[0] === \"\" || keyValuePair[1] === \"\") continue;\n // @ts-ignore\n propsObj[keyValuePair[0]] = keyValuePair[1];\n }\n\n return Object.keys(propsObj).length === 0 ? undefined : propsObj;\n};\n", "import type { AnalyticsConfig } from \"../types\";\n\nconst matchesPattern = (path: string, pattern: string): boolean => {\n // Escape special regex characters except '*' which becomes '.*'\n const escaped = pattern.replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\").replace(/\\*/g, \".*\");\n return new RegExp(`^${escaped}$`).test(path);\n};\n\nexport const shouldTrackPath = (path: string, config: Required<AnalyticsConfig>): boolean => {\n // Exclude pages first\n if (config.excludePages.some((pattern) => matchesPattern(path, pattern))) return false;\n // If includePages is defined, only allow matching paths\n if (config.includePages.length && !config.includePages.some((pattern) => matchesPattern(path, pattern))) return false;\n return true;\n};\n", "import type { AnalyticsConfig, BaseProps, BodyToSend, Event, ViewArguments } from \"./types\";\nimport { getEnvironment, isClient } from \"./utils/environment\";\nimport { parseUtmParams } from \"./utils/parse-utm-params\";\nimport { parseProps } from \"./utils/props-parser\";\nimport { shouldTrackPath } from \"./utils/should-track\";\n\nconst defaultConfig: Required<AnalyticsConfig> = {\n trackLocalhostAs: null,\n collectorUrl: \"https://collector.onedollarstats.com/events\",\n hashRouting: false,\n autocollect: true,\n excludePages: [],\n includePages: []\n};\n\nclass AnalyticsTracker {\n private static instance: AnalyticsTracker | null = null;\n\n private autocollectSetupDone = false;\n private config: Required<AnalyticsConfig>;\n private lastPage: string | null = null;\n\n public static getInstance(userConfig: AnalyticsConfig = {}): AnalyticsTracker {\n if (!isClient()) {\n console.warn(\"[onedollarstats] Running in non-browser environment. Returning no-op instance.\");\n return new AnalyticsTracker(userConfig); // Fresh no-op instance for SSR\n }\n\n if (!AnalyticsTracker.instance) {\n AnalyticsTracker.instance = new AnalyticsTracker(userConfig);\n }\n return AnalyticsTracker.instance;\n }\n\n private constructor(userConfig: AnalyticsConfig = {}) {\n this.config = { ...defaultConfig, ...userConfig };\n\n // Skip setup in non-client environments\n if (!isClient()) return;\n\n // Auto-start autocollect\n if (this.config.autocollect) this.setupAutocollect();\n }\n\n private async sendWithBeaconOrFetch(stringifiedBody: string): Promise<void> {\n // First fallback: try sendBeacon\n if (navigator.sendBeacon?.(this.config.collectorUrl, stringifiedBody)) return;\n\n // Second fallback: use fetch() with keepalive\n fetch(this.config.collectorUrl, {\n method: \"POST\",\n body: stringifiedBody,\n headers: { \"Content-Type\": \"application/json\" },\n keepalive: true\n }).catch((err: Error) => console.error(\"[onedollarstats] fetch() failed:\", err.message));\n }\n\n // Handles localhost replacement, referrer, UTM parameters, and debug mode.\n // Uses img beacon then `navigator.sendBeacon` if available, otherwise falls back to `fetch`.\n private async send(data: Event): Promise<void> {\n const { isLocalhost, isHeadlessBrowser } = getEnvironment();\n if ((isLocalhost && !this.config.trackLocalhostAs) || isHeadlessBrowser) return;\n\n const urlToSend = new URL(location.href);\n\n // Determine debug mode and handle localhost replacement\n let isDebug: boolean = false;\n if (isLocalhost && this.config.trackLocalhostAs && urlToSend.hostname !== this.config.trackLocalhostAs) {\n isDebug = true;\n urlToSend.hostname = this.config.trackLocalhostAs;\n }\n\n // Clean query string unless UTM is explicitly provided\n urlToSend.search = \"\";\n if (data.path) urlToSend.pathname = data.path;\n\n const cleanUrl = urlToSend.href.replace(/\\/$/, \"\");\n\n // Determine referrer\n let referrer: string | undefined = data.referrer;\n try {\n if (!referrer && document.referrer && document.referrer !== \"null\") {\n const referrerURL = new URL(document.referrer);\n if (referrerURL.hostname !== urlToSend.hostname) referrer = referrerURL.href;\n }\n } catch {} // ignore malformed referrer\n\n // Build request body\n const body: BodyToSend = {\n u: cleanUrl,\n e: [\n {\n t: data.type,\n h: this.config.hashRouting,\n r: referrer,\n p: data.props\n }\n ]\n };\n\n if (data.utm && Object.keys(data.utm).length > 0) body.qs = data.utm;\n if (isDebug) body.debug = true;\n\n // Prepare the event payload\n const stringifiedBody = JSON.stringify(body);\n // Encode for safe inclusion in query string using Base64\n const payloadBase64 = btoa(stringifiedBody);\n\n const safeGetThreshold = 1500; // limit for query-string-containing URLs\n const tryImageBeacon = payloadBase64.length <= safeGetThreshold;\n\n if (tryImageBeacon) {\n // Send via image beacon\n const img = new Image(1, 1);\n\n // If loading image fails (server unavailable, blocked, etc.)\n img.onerror = () => {\n this.sendWithBeaconOrFetch(stringifiedBody).catch((err) => console.error(\"[onedollarstats] fallback failed:\", err?.message || err));\n };\n\n // Primary attempt: send data via image beacon (GET request with query string)\n img.src = `${this.config.collectorUrl}?data=${payloadBase64}`;\n }\n\n await this.sendWithBeaconOrFetch(stringifiedBody);\n }\n\n // Prevents duplicate pageviews and respects include/exclude page rules. Automatically parses UTM parameters from URL.\n private trackPageView({ path, props }: ViewArguments, checkBlock: boolean = false) {\n if (!isClient()) return;\n\n const cleanPath = path || location.pathname;\n\n // Skip duplicate pageviews or excluded pages\n if (!this.config.hashRouting && this.lastPage === cleanPath) return;\n\n // Skip page if checkBlock is true and the path should be excluded\n if (checkBlock && !shouldTrackPath(cleanPath, this.config)) return;\n\n this.lastPage = cleanPath;\n\n const utm = parseUtmParams(new URLSearchParams(location.search));\n this.send({ type: \"PageView\", path: cleanPath, props, utm });\n }\n\n /**\n * Tracks a custom event.\n * Can accept path string or a props object.\n *\n * @param eventName Name of the event to track.\n * @param pathOrProps Optional path string or props object.\n * @param props Optional props object if path string is provided.\n */\n public async event(eventName: string, pathOrProps?: string | BaseProps, props?: BaseProps) {\n if (!isClient()) return;\n\n const { isLocalhost, isHeadlessBrowser } = getEnvironment();\n if ((isLocalhost && !this.config.trackLocalhostAs) || isHeadlessBrowser) return;\n\n const args: ViewArguments = {};\n if (typeof pathOrProps === \"string\") {\n args.path = pathOrProps;\n args.props = props;\n } else if (typeof pathOrProps === \"object\") args.props = pathOrProps;\n\n this.send({ type: eventName, ...args });\n }\n\n /**\n * Records a page view.\n * Can accept path string or a props object.\n *\n * @param pathOrProps Optional path string or props object.\n * @param props Optional props when first arg is a path string.\n */\n public async view(pathOrProps?: string | BaseProps, props?: BaseProps) {\n if (!isClient()) return;\n\n const args: ViewArguments = {};\n\n if (typeof pathOrProps === \"string\") {\n args.path = pathOrProps;\n args.props = props;\n } else if (typeof pathOrProps === \"object\") {\n args.props = pathOrProps;\n }\n\n this.trackPageView(args);\n }\n\n /**\n * Installs global DOM/window listeners exactly once for:\n * - visibilitychange\n * - history.pushState\n * - popstate\n * - hashchange\n * - click autocapture for elements annotated with `data-s:event` & `data-s-event`\n *\n */\n private setupAutocollect() {\n if (!isClient() || this.autocollectSetupDone) return;\n this.autocollectSetupDone = true;\n\n const handlePageView = () => this.trackPageView({ path: location.pathname }, true);\n\n // visibilitychange\n const onVisibility = () => {\n if (document.visibilityState === \"visible\") handlePageView();\n };\n document.addEventListener(\"visibilitychange\", onVisibility);\n\n // pushState\n const origPush = history.pushState.bind(history);\n history.pushState = (...args) => {\n origPush(...args);\n requestAnimationFrame(() => {\n handlePageView();\n });\n };\n\n // popstate\n window.addEventListener(\"popstate\", handlePageView);\n\n // hashchange\n window.addEventListener(\"hashchange\", handlePageView);\n\n // click autocapture\n const onClick: EventListener = (ev: Event) => {\n const clickEvent = ev as MouseEvent;\n if (clickEvent.type === \"auxclick\" && clickEvent.button !== 1) return;\n\n const target = clickEvent.target as Element | null;\n if (!target) return;\n\n // Check if inside <a> or <button>\n const insideInteractive = !!target.closest(\"a, button\");\n\n let el: Element | null = target;\n let depth = 0;\n\n while (el) {\n const eventName = el.getAttribute(\"data-s:event\") ?? el.getAttribute(\"data-s-event\");\n if (eventName) {\n const propsAttr = el.getAttribute(\"data-s:event-props\") ?? el.getAttribute(\"data-s-event-props\");\n const props = propsAttr ? parseProps(propsAttr) : undefined;\n const path = el.getAttribute(\"data-s:event-path\") || el.getAttribute(\"data-s-event-path\") || undefined;\n\n if ((path && !shouldTrackPath(path, this.config)) || !shouldTrackPath(location.pathname, this.config)) {\n return;\n }\n\n this.event(eventName, path ?? props, props);\n return;\n }\n\n el = el.parentElement;\n depth++;\n\n // If not in <a>/<button>, stop after 3 levels\n if (!insideInteractive && depth >= 3) break;\n }\n };\n\n document.addEventListener(\"click\", onClick);\n\n // Fire initial pageview if already visible\n if (document.visibilityState === \"visible\") handlePageView();\n }\n}\n\nexport const configure = (userConfig: AnalyticsConfig = {}) => {\n AnalyticsTracker.getInstance(userConfig);\n};\n\nexport const event = async (eventName: string, pathOrProps?: string | BaseProps, props?: BaseProps) => {\n const instance = AnalyticsTracker.getInstance();\n await instance.event(eventName, pathOrProps, props);\n};\n\nexport const view = async (pathOrProps?: string | BaseProps, props?: BaseProps) => {\n const instance = AnalyticsTracker.getInstance();\n await instance.view(pathOrProps, props);\n};\n"],
5
- "mappings": "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",
3
+ "sources": ["../src/utils/environment.ts", "../src/utils/parse-utm-params.ts", "../src/utils/props-parser.ts", "../src/utils/resolve-path.ts", "../src/utils/should-track.ts", "../src/index.ts"],
4
+ "sourcesContent": ["export const getEnvironment = (): {\n isLocalhost: boolean;\n isHeadlessBrowser: boolean;\n} => ({\n isLocalhost: /^localhost$|^127(\\.[0-9]+){0,2}\\.[0-9]+$|^\\[::1?\\]$/.test(location.hostname) || location.protocol === \"file:\",\n isHeadlessBrowser: Boolean(\n window.navigator.webdriver ||\n (\"_phantom\" in window && window._phantom) ||\n (\"__nightmare\" in window && window.__nightmare) ||\n (\"Cypress\" in window && window.Cypress)\n )\n});\nexport const isClient = (): boolean => {\n try {\n // Basic checks for window and document\n if (typeof window === \"undefined\" || typeof document === \"undefined\") return false;\n\n // Check for navigator safely\n const ua = typeof navigator !== \"undefined\" ? navigator.userAgent : \"\";\n if (/node|jsdom/i.test(ua)) return false;\n return true;\n } catch {\n return false;\n }\n};\n", "export const parseUtmParams = (urlSearchParams: URLSearchParams) => {\n const utm: Record<string, string | string[]> = {};\n\n [\"utm_campaign\", \"utm_source\", \"utm_medium\", \"utm_term\", \"utm_content\"].forEach((key) => {\n const values = urlSearchParams.getAll(key);\n if (values.length === 1) {\n utm[key] = values[0];\n } else if (values.length > 1) {\n utm[key] = values; // store array if multiple values\n }\n });\n\n return utm;\n};\n", "export const parseProps = (propsString: string): Record<string, string> | undefined => {\n if (!propsString) return undefined;\n // \"key1=value1;key2=value2\"\n\n const splittedProps = propsString.split(\";\");\n const propsObj: Record<string, string> = {};\n\n for (const keyValueString of splittedProps) {\n const keyValuePair = keyValueString.split(\"=\").map((el) => el.trim());\n if (keyValuePair.length !== 2 || keyValuePair[0] === \"\" || keyValuePair[1] === \"\") continue;\n // @ts-ignore\n propsObj[keyValuePair[0]] = keyValuePair[1];\n }\n\n return Object.keys(propsObj).length === 0 ? undefined : propsObj;\n};\n", "export const resolvePath = (pathOrProps?: string): string => {\n if (pathOrProps) return pathOrProps;\n\n const sources = [\n { value: document.body?.getAttribute(\"data-s-path\"), name: \"data-s-path\" },\n { value: document.body?.getAttribute(\"data-s:path\"), name: \"data-s:path\" },\n { value: document.querySelector('meta[name=\"stonks-path\"]')?.getAttribute(\"content\"), name: \"meta[name='stonks-path']\" }\n ];\n\n // Only keep sources that actually exist\n const existing = sources.filter(({ value }) => value);\n\n if (existing.length > 1) {\n console.warn(\"[onedollarstats] Multiple path sources found. Using priority order:\", existing.map(({ name }) => name).join(\" > \"));\n }\n\n // Return first available value, fallback to location.pathname\n return existing[0]?.value ?? location.pathname;\n};\n", "import type { AnalyticsConfig } from \"../types\";\n\nconst matchesPattern = (path: string, pattern: string): boolean => {\n // Escape special regex characters except '*' which becomes '.*'\n const escaped = pattern.replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\").replace(/\\*/g, \".*\");\n return new RegExp(`^${escaped}$`).test(path);\n};\n\nexport const shouldTrackPath = (path: string, config: Required<AnalyticsConfig>): boolean => {\n // Exclude pages first\n if (config.excludePages.some((pattern) => matchesPattern(path, pattern))) return false;\n // If includePages is defined, only allow matching paths\n if (config.includePages.length && !config.includePages.some((pattern) => matchesPattern(path, pattern))) return false;\n return true;\n};\n", "import type { AnalyticsConfig, BaseProps, BodyToSend, Event, ViewArguments } from \"./types\";\nimport { getEnvironment, isClient } from \"./utils/environment\";\nimport { parseUtmParams } from \"./utils/parse-utm-params\";\nimport { parseProps } from \"./utils/props-parser\";\nimport { resolvePath } from \"./utils/resolve-path\";\nimport { shouldTrackPath } from \"./utils/should-track\";\n\nconst defaultConfig: Required<AnalyticsConfig> = {\n trackLocalhostAs: null,\n collectorUrl: \"https://collector.onedollarstats.com/events\",\n hashRouting: false,\n autocollect: true,\n excludePages: [],\n includePages: []\n};\n\nclass AnalyticsTracker {\n private static instance: AnalyticsTracker | null = null;\n\n private autocollectSetupDone = false;\n private config: Required<AnalyticsConfig>;\n private lastPage: string | null = null;\n\n public static getInstance(userConfig: AnalyticsConfig = {}): AnalyticsTracker {\n if (!isClient()) {\n console.warn(\"[onedollarstats] Running in non-browser environment. Returning no-op instance.\");\n return new AnalyticsTracker(userConfig); // Fresh no-op instance for SSR\n }\n\n if (!AnalyticsTracker.instance) {\n AnalyticsTracker.instance = new AnalyticsTracker(userConfig);\n }\n return AnalyticsTracker.instance;\n }\n\n private constructor(userConfig: AnalyticsConfig = {}) {\n this.config = { ...defaultConfig, ...userConfig };\n\n // Skip setup in non-client environments\n if (!isClient()) return;\n\n // Auto-start autocollect\n if (this.config.autocollect) this.setupAutocollect();\n }\n\n private async sendWithBeaconOrFetch(stringifiedBody: string): Promise<void> {\n // First fallback: try sendBeacon\n if (navigator.sendBeacon?.(this.config.collectorUrl, stringifiedBody)) return;\n\n // Second fallback: use fetch() with keepalive\n fetch(this.config.collectorUrl, {\n method: \"POST\",\n body: stringifiedBody,\n headers: { \"Content-Type\": \"application/json\" },\n keepalive: true\n }).catch((err: Error) => console.error(\"[onedollarstats] fetch() failed:\", err.message));\n }\n\n // Handles localhost replacement, referrer, UTM parameters, and debug mode.\n // Uses img beacon then `navigator.sendBeacon` if available, otherwise falls back to `fetch`.\n private async send(data: Event): Promise<void> {\n const { isLocalhost, isHeadlessBrowser } = getEnvironment();\n if ((isLocalhost && !this.config.trackLocalhostAs) || isHeadlessBrowser) return;\n\n const urlToSend = new URL(location.href);\n\n // Determine debug mode and handle localhost replacement\n let isDebug: boolean = false;\n if (isLocalhost && this.config.trackLocalhostAs && urlToSend.hostname !== this.config.trackLocalhostAs) {\n isDebug = true;\n urlToSend.hostname = this.config.trackLocalhostAs;\n }\n\n // Clean query string unless UTM is explicitly provided\n urlToSend.search = \"\";\n if (data.path) urlToSend.pathname = data.path;\n\n const cleanUrl = urlToSend.href.replace(/\\/$/, \"\");\n\n // Determine referrer\n let referrer: string | undefined = data.referrer;\n try {\n if (!referrer && document.referrer && document.referrer !== \"null\") {\n const referrerURL = new URL(document.referrer);\n if (referrerURL.hostname !== urlToSend.hostname) referrer = referrerURL.href;\n }\n } catch {} // ignore malformed referrer\n\n // Build request body\n const body: BodyToSend = {\n u: cleanUrl,\n e: [\n {\n t: data.type,\n h: this.config.hashRouting,\n r: referrer,\n p: data.props\n }\n ]\n };\n\n if (data.utm && Object.keys(data.utm).length > 0) body.qs = data.utm;\n if (isDebug) body.debug = true;\n\n // Prepare the event payload\n const stringifiedBody = JSON.stringify(body);\n // Encode for safe inclusion in query string using Base64\n const payloadBase64 = btoa(stringifiedBody);\n\n const safeGetThreshold = 1500; // limit for query-string-containing URLs\n const tryImageBeacon = payloadBase64.length <= safeGetThreshold;\n\n if (tryImageBeacon) {\n // Send via image beacon\n const img = new Image(1, 1);\n\n // If loading image fails (server unavailable, blocked, etc.)\n img.onerror = () => this.sendWithBeaconOrFetch(stringifiedBody);\n\n // Primary attempt: send data via image beacon (GET request with query string)\n img.src = `${this.config.collectorUrl}?data=${payloadBase64}`;\n } else await this.sendWithBeaconOrFetch(stringifiedBody);\n }\n\n // Prevents duplicate pageviews and respects include/exclude page rules. Automatically parses UTM parameters from URL.\n private trackPageView({ path, props }: ViewArguments, checkBlock: boolean = false) {\n if (!isClient()) return;\n\n const viewPath = resolvePath(path);\n\n const viewProps =\n props ||\n (() => {\n const newProps = {};\n const elements = document.querySelectorAll(\"[data-s\\\\:view-props], [data-s-view-props]\");\n\n for (const el of Array.from(elements)) {\n const propsString = el.getAttribute(\"data-s-view-props\") || el.getAttribute(\"data-s:view-props\");\n if (!propsString) continue;\n const parsedProps = parseProps(propsString);\n Object.assign(newProps, parsedProps);\n }\n\n return Object.keys(newProps).length ? newProps : undefined;\n })();\n\n // Skip duplicate pageviews or excluded pages\n if (!this.config.hashRouting && this.lastPage === viewPath) return;\n\n // Skip page if checkBlock is true and the path should be excluded\n if (checkBlock && !shouldTrackPath(viewPath, this.config)) return;\n\n this.lastPage = viewPath;\n\n const utm = parseUtmParams(new URLSearchParams(location.search));\n this.send({ type: \"PageView\", path: viewPath, props: viewProps, utm });\n }\n\n /**\n * Tracks a custom event.\n * Can accept path string or a props object.\n *\n * @param eventName Name of the event to track.\n * @param pathOrProps Optional path string or props object.\n * @param props Optional props object if path string is provided.\n */\n public async event(eventName: string, pathOrProps?: string | BaseProps, props?: BaseProps) {\n if (!isClient()) return;\n\n const { isLocalhost, isHeadlessBrowser } = getEnvironment();\n if ((isLocalhost && !this.config.trackLocalhostAs) || isHeadlessBrowser) return;\n\n const args: ViewArguments = {};\n if (typeof pathOrProps === \"string\") {\n args.path = resolvePath(pathOrProps);\n\n args.props = props;\n } else if (typeof pathOrProps === \"object\") args.props = pathOrProps;\n\n this.send({ type: eventName, ...args });\n }\n\n /**\n * Records a page view.\n * Can accept path string or a props object.\n *\n * @param pathOrProps Optional path string or props object.\n * @param props Optional props when first arg is a path string.\n */\n public async view(pathOrProps?: string | BaseProps, props?: BaseProps) {\n if (!isClient()) return;\n\n const args: ViewArguments = {};\n\n if (typeof pathOrProps === \"string\") {\n args.path = pathOrProps;\n args.props = props;\n } else if (typeof pathOrProps === \"object\") {\n args.props = pathOrProps;\n }\n\n this.trackPageView(args);\n }\n\n /**\n * Installs global DOM/window listeners exactly once for:\n * - visibilitychange\n * - history.pushState\n * - popstate\n * - hashchange\n * - click autocapture for elements annotated with `data-s:event` & `data-s-event`\n *\n */\n private setupAutocollect() {\n if (!isClient() || this.autocollectSetupDone) return;\n this.autocollectSetupDone = true;\n\n const handlePageView = () => this.trackPageView({}, true);\n\n // visibilitychange\n const onVisibility = () => {\n if (document.visibilityState === \"visible\") handlePageView();\n };\n document.addEventListener(\"visibilitychange\", onVisibility);\n\n // pushState\n const origPush = history.pushState.bind(history);\n history.pushState = (...args) => {\n origPush(...args);\n requestAnimationFrame(() => {\n handlePageView();\n });\n };\n\n // popstate\n window.addEventListener(\"popstate\", handlePageView);\n\n // hashchange\n window.addEventListener(\"hashchange\", handlePageView);\n\n // click autocapture\n const onClick: EventListener = (ev: Event) => {\n const clickEvent = ev as MouseEvent;\n if (clickEvent.type === \"auxclick\" && clickEvent.button !== 1) return;\n\n const target = clickEvent.target as Element | null;\n if (!target) return;\n\n // Check if inside <a> or <button>\n const insideInteractive = !!target.closest(\"a, button\");\n\n let el: Element | null = target;\n let depth = 0;\n\n while (el) {\n const eventName = el.getAttribute(\"data-s-event\") || el.getAttribute(\"data-s:event\");\n if (eventName) {\n const propsAttr = el.getAttribute(\"data-s-event-props\") || el.getAttribute(\"data-s:event-props\");\n const props = propsAttr ? parseProps(propsAttr) : undefined;\n const path = el.getAttribute(\"data-s-event-path\") || el.getAttribute(\"data-s:event-path\") || undefined;\n\n if ((path && !shouldTrackPath(path, this.config)) || !shouldTrackPath(location.pathname, this.config)) {\n return;\n }\n\n this.event(eventName, path ?? props, props);\n return;\n }\n\n el = el.parentElement;\n depth++;\n\n // If not in <a>/<button>, stop after 3 levels\n if (!insideInteractive && depth >= 3) break;\n }\n };\n\n document.addEventListener(\"click\", onClick);\n\n // Fire initial pageview if already visible\n if (document.visibilityState === \"visible\") handlePageView();\n }\n}\n\nexport const configure = (userConfig: AnalyticsConfig = {}) => {\n AnalyticsTracker.getInstance(userConfig);\n};\n\nexport const event = async (eventName: string, pathOrProps?: string | BaseProps, props?: BaseProps) => {\n const instance = AnalyticsTracker.getInstance();\n await instance.event(eventName, pathOrProps, props);\n};\n\nexport const view = async (pathOrProps?: string | BaseProps, props?: BaseProps) => {\n const instance = AnalyticsTracker.getInstance();\n await instance.view(pathOrProps, props);\n};\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -0,0 +1 @@
1
+ export declare const resolvePath: (pathOrProps?: string) => string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "onedollarstats",
3
- "version": "0.0.1",
3
+ "version": "0.0.4",
4
4
  "description": "A lightweight, zero-dependency analytics tracker for frontend apps",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",