@snovasys/usage-analytics-sdk 1.0.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.
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // clarity.ts
21
+ var clarity_exports = {};
22
+ __export(clarity_exports, {
23
+ createClarityListener: () => createClarityListener
24
+ });
25
+ module.exports = __toCommonJS(clarity_exports);
26
+
27
+ // src/listeners/clarity.ts
28
+ var CLARITY_SCRIPT_BASE = "https://www.clarity.ms/tag/";
29
+ function isBrowser() {
30
+ return typeof window !== "undefined";
31
+ }
32
+ function loadClarityScript(projectId) {
33
+ return new Promise((resolve) => {
34
+ if (!isBrowser()) {
35
+ resolve();
36
+ return;
37
+ }
38
+ if (typeof window.clarity === "function") {
39
+ resolve();
40
+ return;
41
+ }
42
+ const script = document.createElement("script");
43
+ script.async = true;
44
+ script.src = `${CLARITY_SCRIPT_BASE}${encodeURIComponent(projectId)}`;
45
+ script.onload = () => resolve();
46
+ script.onerror = () => resolve();
47
+ document.head.appendChild(script);
48
+ });
49
+ }
50
+ function createClarityListener(config) {
51
+ const projectId = config.projectId;
52
+ let ready = false;
53
+ return {
54
+ async init(cfg) {
55
+ try {
56
+ const c = cfg ?? config;
57
+ const id = c.projectId;
58
+ if (!id || !isBrowser()) return;
59
+ await loadClarityScript(id);
60
+ ready = true;
61
+ } catch {
62
+ }
63
+ },
64
+ track(envelope) {
65
+ try {
66
+ if (!isBrowser() || !ready || typeof window.clarity !== "function") return;
67
+ window.clarity("event", envelope.name);
68
+ if (envelope.properties && typeof window.clarity === "function") {
69
+ for (const [key, value] of Object.entries(envelope.properties)) {
70
+ if (typeof value === "string" || Array.isArray(value)) {
71
+ window.clarity("set", key, value);
72
+ }
73
+ }
74
+ }
75
+ } catch {
76
+ }
77
+ },
78
+ identify(userId, _traits) {
79
+ try {
80
+ if (!isBrowser() || !ready || typeof window.clarity !== "function") return;
81
+ window.clarity("identify", userId, void 0, void 0, void 0);
82
+ } catch {
83
+ }
84
+ }
85
+ };
86
+ }
87
+ // Annotate the CommonJS export names for ESM import in node:
88
+ 0 && (module.exports = {
89
+ createClarityListener
90
+ });
91
+ //# sourceMappingURL=clarity.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../clarity.ts","../src/listeners/clarity.ts"],"sourcesContent":["/**\n * Entry point: @snovasys/usage-analytics-sdk/clarity\n * Export Clarity listener factory for manual wiring or use via built-in registry (id: clarity).\n */\nexport { createClarityListener } from './src/listeners/clarity.js';\nexport type { ClarityListenerConfig } from './src/listeners/clarity.js';\nexport type { AnalyticsListener, EventEnvelope } from './src/types/index.js';\n","import type { AnalyticsListener } from '../types/listener.js';\nimport type { EventEnvelope } from '../types/envelope.js';\n\nexport interface ClarityListenerConfig {\n projectId: string;\n}\n\nconst CLARITY_SCRIPT_BASE = 'https://www.clarity.ms/tag/';\n\ndeclare global {\n interface Window {\n clarity?: (cmd: string, ...args: unknown[]) => void;\n }\n}\n\nfunction isBrowser(): boolean {\n return typeof window !== 'undefined';\n}\n\nfunction loadClarityScript(projectId: string): Promise<void> {\n return new Promise((resolve) => {\n if (!isBrowser()) {\n resolve();\n return;\n }\n if (typeof window.clarity === 'function') {\n resolve();\n return;\n }\n const script = document.createElement('script');\n script.async = true;\n script.src = `${CLARITY_SCRIPT_BASE}${encodeURIComponent(projectId)}`;\n script.onload = () => resolve();\n script.onerror = () => resolve();\n document.head.appendChild(script);\n });\n}\n\n/**\n * Listener that sends events to Microsoft Clarity via script injection.\n * Loads Clarity script with projectId; track → clarity(\"event\", name); identify → clarity(\"identify\", userId, ...).\n * No-op when typeof window === 'undefined' (SSR).\n */\nexport function createClarityListener(config: ClarityListenerConfig): AnalyticsListener {\n const projectId = config.projectId;\n let ready = false;\n\n return {\n async init(cfg: unknown): Promise<void> {\n try {\n const c = (cfg ?? config) as ClarityListenerConfig;\n const id = c.projectId;\n if (!id || !isBrowser()) return;\n await loadClarityScript(id);\n ready = true;\n } catch {\n // swallow\n }\n },\n track(envelope: EventEnvelope): void {\n try {\n if (!isBrowser() || !ready || typeof window.clarity !== 'function') return;\n window.clarity('event', envelope.name);\n if (envelope.properties && typeof window.clarity === 'function') {\n for (const [key, value] of Object.entries(envelope.properties)) {\n if (typeof value === 'string' || Array.isArray(value)) {\n window.clarity('set', key, value);\n }\n }\n }\n } catch {\n // swallow\n }\n },\n identify(userId: string, _traits?: Record<string, unknown>): void {\n try {\n if (!isBrowser() || !ready || typeof window.clarity !== 'function') return;\n window.clarity('identify', userId, undefined, undefined, undefined);\n } catch {\n // swallow\n }\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACOA,IAAM,sBAAsB;AAQ5B,SAAS,YAAqB;AAC5B,SAAO,OAAO,WAAW;AAC3B;AAEA,SAAS,kBAAkB,WAAkC;AAC3D,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,QAAI,CAAC,UAAU,GAAG;AAChB,cAAQ;AACR;AAAA,IACF;AACA,QAAI,OAAO,OAAO,YAAY,YAAY;AACxC,cAAQ;AACR;AAAA,IACF;AACA,UAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,WAAO,QAAQ;AACf,WAAO,MAAM,GAAG,mBAAmB,GAAG,mBAAmB,SAAS,CAAC;AACnE,WAAO,SAAS,MAAM,QAAQ;AAC9B,WAAO,UAAU,MAAM,QAAQ;AAC/B,aAAS,KAAK,YAAY,MAAM;AAAA,EAClC,CAAC;AACH;AAOO,SAAS,sBAAsB,QAAkD;AACtF,QAAM,YAAY,OAAO;AACzB,MAAI,QAAQ;AAEZ,SAAO;AAAA,IACL,MAAM,KAAK,KAA6B;AACtC,UAAI;AACF,cAAM,IAAK,OAAO;AAClB,cAAM,KAAK,EAAE;AACb,YAAI,CAAC,MAAM,CAAC,UAAU,EAAG;AACzB,cAAM,kBAAkB,EAAE;AAC1B,gBAAQ;AAAA,MACV,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,IACA,MAAM,UAA+B;AACnC,UAAI;AACF,YAAI,CAAC,UAAU,KAAK,CAAC,SAAS,OAAO,OAAO,YAAY,WAAY;AACpE,eAAO,QAAQ,SAAS,SAAS,IAAI;AACrC,YAAI,SAAS,cAAc,OAAO,OAAO,YAAY,YAAY;AAC/D,qBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,SAAS,UAAU,GAAG;AAC9D,gBAAI,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAG;AACrD,qBAAO,QAAQ,OAAO,KAAK,KAAK;AAAA,YAClC;AAAA,UACF;AAAA,QACF;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,IACA,SAAS,QAAgB,SAAyC;AAChE,UAAI;AACF,YAAI,CAAC,UAAU,KAAK,CAAC,SAAS,OAAO,OAAO,YAAY,WAAY;AACpE,eAAO,QAAQ,YAAY,QAAQ,QAAW,QAAW,MAAS;AAAA,MACpE,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,19 @@
1
+ import { A as AnalyticsListener } from './listener-CrNaKh1a.cjs';
2
+ export { E as EventEnvelope } from './listener-CrNaKh1a.cjs';
3
+
4
+ interface ClarityListenerConfig {
5
+ projectId: string;
6
+ }
7
+ declare global {
8
+ interface Window {
9
+ clarity?: (cmd: string, ...args: unknown[]) => void;
10
+ }
11
+ }
12
+ /**
13
+ * Listener that sends events to Microsoft Clarity via script injection.
14
+ * Loads Clarity script with projectId; track → clarity("event", name); identify → clarity("identify", userId, ...).
15
+ * No-op when typeof window === 'undefined' (SSR).
16
+ */
17
+ declare function createClarityListener(config: ClarityListenerConfig): AnalyticsListener;
18
+
19
+ export { AnalyticsListener, type ClarityListenerConfig, createClarityListener };
@@ -0,0 +1,19 @@
1
+ import { A as AnalyticsListener } from './listener-CrNaKh1a.js';
2
+ export { E as EventEnvelope } from './listener-CrNaKh1a.js';
3
+
4
+ interface ClarityListenerConfig {
5
+ projectId: string;
6
+ }
7
+ declare global {
8
+ interface Window {
9
+ clarity?: (cmd: string, ...args: unknown[]) => void;
10
+ }
11
+ }
12
+ /**
13
+ * Listener that sends events to Microsoft Clarity via script injection.
14
+ * Loads Clarity script with projectId; track → clarity("event", name); identify → clarity("identify", userId, ...).
15
+ * No-op when typeof window === 'undefined' (SSR).
16
+ */
17
+ declare function createClarityListener(config: ClarityListenerConfig): AnalyticsListener;
18
+
19
+ export { AnalyticsListener, type ClarityListenerConfig, createClarityListener };
@@ -0,0 +1,64 @@
1
+ // src/listeners/clarity.ts
2
+ var CLARITY_SCRIPT_BASE = "https://www.clarity.ms/tag/";
3
+ function isBrowser() {
4
+ return typeof window !== "undefined";
5
+ }
6
+ function loadClarityScript(projectId) {
7
+ return new Promise((resolve) => {
8
+ if (!isBrowser()) {
9
+ resolve();
10
+ return;
11
+ }
12
+ if (typeof window.clarity === "function") {
13
+ resolve();
14
+ return;
15
+ }
16
+ const script = document.createElement("script");
17
+ script.async = true;
18
+ script.src = `${CLARITY_SCRIPT_BASE}${encodeURIComponent(projectId)}`;
19
+ script.onload = () => resolve();
20
+ script.onerror = () => resolve();
21
+ document.head.appendChild(script);
22
+ });
23
+ }
24
+ function createClarityListener(config) {
25
+ const projectId = config.projectId;
26
+ let ready = false;
27
+ return {
28
+ async init(cfg) {
29
+ try {
30
+ const c = cfg ?? config;
31
+ const id = c.projectId;
32
+ if (!id || !isBrowser()) return;
33
+ await loadClarityScript(id);
34
+ ready = true;
35
+ } catch {
36
+ }
37
+ },
38
+ track(envelope) {
39
+ try {
40
+ if (!isBrowser() || !ready || typeof window.clarity !== "function") return;
41
+ window.clarity("event", envelope.name);
42
+ if (envelope.properties && typeof window.clarity === "function") {
43
+ for (const [key, value] of Object.entries(envelope.properties)) {
44
+ if (typeof value === "string" || Array.isArray(value)) {
45
+ window.clarity("set", key, value);
46
+ }
47
+ }
48
+ }
49
+ } catch {
50
+ }
51
+ },
52
+ identify(userId, _traits) {
53
+ try {
54
+ if (!isBrowser() || !ready || typeof window.clarity !== "function") return;
55
+ window.clarity("identify", userId, void 0, void 0, void 0);
56
+ } catch {
57
+ }
58
+ }
59
+ };
60
+ }
61
+ export {
62
+ createClarityListener
63
+ };
64
+ //# sourceMappingURL=clarity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/listeners/clarity.ts"],"sourcesContent":["import type { AnalyticsListener } from '../types/listener.js';\nimport type { EventEnvelope } from '../types/envelope.js';\n\nexport interface ClarityListenerConfig {\n projectId: string;\n}\n\nconst CLARITY_SCRIPT_BASE = 'https://www.clarity.ms/tag/';\n\ndeclare global {\n interface Window {\n clarity?: (cmd: string, ...args: unknown[]) => void;\n }\n}\n\nfunction isBrowser(): boolean {\n return typeof window !== 'undefined';\n}\n\nfunction loadClarityScript(projectId: string): Promise<void> {\n return new Promise((resolve) => {\n if (!isBrowser()) {\n resolve();\n return;\n }\n if (typeof window.clarity === 'function') {\n resolve();\n return;\n }\n const script = document.createElement('script');\n script.async = true;\n script.src = `${CLARITY_SCRIPT_BASE}${encodeURIComponent(projectId)}`;\n script.onload = () => resolve();\n script.onerror = () => resolve();\n document.head.appendChild(script);\n });\n}\n\n/**\n * Listener that sends events to Microsoft Clarity via script injection.\n * Loads Clarity script with projectId; track → clarity(\"event\", name); identify → clarity(\"identify\", userId, ...).\n * No-op when typeof window === 'undefined' (SSR).\n */\nexport function createClarityListener(config: ClarityListenerConfig): AnalyticsListener {\n const projectId = config.projectId;\n let ready = false;\n\n return {\n async init(cfg: unknown): Promise<void> {\n try {\n const c = (cfg ?? config) as ClarityListenerConfig;\n const id = c.projectId;\n if (!id || !isBrowser()) return;\n await loadClarityScript(id);\n ready = true;\n } catch {\n // swallow\n }\n },\n track(envelope: EventEnvelope): void {\n try {\n if (!isBrowser() || !ready || typeof window.clarity !== 'function') return;\n window.clarity('event', envelope.name);\n if (envelope.properties && typeof window.clarity === 'function') {\n for (const [key, value] of Object.entries(envelope.properties)) {\n if (typeof value === 'string' || Array.isArray(value)) {\n window.clarity('set', key, value);\n }\n }\n }\n } catch {\n // swallow\n }\n },\n identify(userId: string, _traits?: Record<string, unknown>): void {\n try {\n if (!isBrowser() || !ready || typeof window.clarity !== 'function') return;\n window.clarity('identify', userId, undefined, undefined, undefined);\n } catch {\n // swallow\n }\n },\n };\n}\n"],"mappings":";AAOA,IAAM,sBAAsB;AAQ5B,SAAS,YAAqB;AAC5B,SAAO,OAAO,WAAW;AAC3B;AAEA,SAAS,kBAAkB,WAAkC;AAC3D,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,QAAI,CAAC,UAAU,GAAG;AAChB,cAAQ;AACR;AAAA,IACF;AACA,QAAI,OAAO,OAAO,YAAY,YAAY;AACxC,cAAQ;AACR;AAAA,IACF;AACA,UAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,WAAO,QAAQ;AACf,WAAO,MAAM,GAAG,mBAAmB,GAAG,mBAAmB,SAAS,CAAC;AACnE,WAAO,SAAS,MAAM,QAAQ;AAC9B,WAAO,UAAU,MAAM,QAAQ;AAC/B,aAAS,KAAK,YAAY,MAAM;AAAA,EAClC,CAAC;AACH;AAOO,SAAS,sBAAsB,QAAkD;AACtF,QAAM,YAAY,OAAO;AACzB,MAAI,QAAQ;AAEZ,SAAO;AAAA,IACL,MAAM,KAAK,KAA6B;AACtC,UAAI;AACF,cAAM,IAAK,OAAO;AAClB,cAAM,KAAK,EAAE;AACb,YAAI,CAAC,MAAM,CAAC,UAAU,EAAG;AACzB,cAAM,kBAAkB,EAAE;AAC1B,gBAAQ;AAAA,MACV,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,IACA,MAAM,UAA+B;AACnC,UAAI;AACF,YAAI,CAAC,UAAU,KAAK,CAAC,SAAS,OAAO,OAAO,YAAY,WAAY;AACpE,eAAO,QAAQ,SAAS,SAAS,IAAI;AACrC,YAAI,SAAS,cAAc,OAAO,OAAO,YAAY,YAAY;AAC/D,qBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,SAAS,UAAU,GAAG;AAC9D,gBAAI,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAG;AACrD,qBAAO,QAAQ,OAAO,KAAK,KAAK;AAAA,YAClC;AAAA,UACF;AAAA,QACF;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,IACA,SAAS,QAAgB,SAAyC;AAChE,UAAI;AACF,YAAI,CAAC,UAAU,KAAK,CAAC,SAAS,OAAO,OAAO,YAAY,WAAY;AACpE,eAAO,QAAQ,YAAY,QAAQ,QAAW,QAAW,MAAS;AAAA,MACpE,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // custom-api.ts
21
+ var custom_api_exports = {};
22
+ __export(custom_api_exports, {
23
+ createCustomApiListener: () => createCustomApiListener
24
+ });
25
+ module.exports = __toCommonJS(custom_api_exports);
26
+
27
+ // src/listeners/custom-api.ts
28
+ var DEFAULT_BATCH_SIZE = 1;
29
+ var DEFAULT_FLUSH_INTERVAL_MS = 5e3;
30
+ function createCustomApiListener(config) {
31
+ const endpoint = config.endpoint;
32
+ const apiKey = config.apiKey;
33
+ const batchSize = config.batchSize ?? DEFAULT_BATCH_SIZE;
34
+ const flushIntervalMs = config.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS;
35
+ let batch = [];
36
+ let flushTimer = null;
37
+ function scheduleFlush() {
38
+ if (flushTimer != null) return;
39
+ flushTimer = setTimeout(() => {
40
+ flushTimer = null;
41
+ sendBatch();
42
+ }, flushIntervalMs);
43
+ }
44
+ function sendBatch() {
45
+ if (batch.length === 0) return;
46
+ const toSend = [...batch];
47
+ batch = [];
48
+ const body = JSON.stringify(toSend.length === 1 ? toSend[0] : { events: toSend });
49
+ const headers = {
50
+ "Content-Type": "application/json"
51
+ };
52
+ if (apiKey) headers["Authorization"] = `Bearer ${apiKey}`;
53
+ if (typeof fetch !== "undefined") {
54
+ fetch(endpoint, {
55
+ method: "POST",
56
+ headers,
57
+ body,
58
+ keepalive: true
59
+ }).catch(() => {
60
+ });
61
+ }
62
+ }
63
+ return {
64
+ init(_config) {
65
+ },
66
+ track(envelope) {
67
+ try {
68
+ batch.push(envelope);
69
+ if (batch.length >= batchSize) {
70
+ sendBatch();
71
+ } else if (flushIntervalMs > 0) {
72
+ scheduleFlush();
73
+ }
74
+ } catch {
75
+ }
76
+ },
77
+ flush() {
78
+ if (flushTimer != null) {
79
+ clearTimeout(flushTimer);
80
+ flushTimer = null;
81
+ }
82
+ sendBatch();
83
+ return Promise.resolve();
84
+ },
85
+ teardown() {
86
+ if (flushTimer != null) {
87
+ clearTimeout(flushTimer);
88
+ flushTimer = null;
89
+ }
90
+ batch.length = 0;
91
+ }
92
+ };
93
+ }
94
+ // Annotate the CommonJS export names for ESM import in node:
95
+ 0 && (module.exports = {
96
+ createCustomApiListener
97
+ });
98
+ //# sourceMappingURL=custom-api.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../custom-api.ts","../src/listeners/custom-api.ts"],"sourcesContent":["/**\n * Entry point: @snovasys/usage-analytics-sdk/custom-api\n * Export custom API listener factory for apps that send events to their backend.\n */\nexport { createCustomApiListener } from './src/listeners/custom-api.js';\nexport type { CustomApiListenerConfig } from './src/listeners/custom-api.js';\nexport type { AnalyticsListener, EventEnvelope } from './src/types/index.js';\n","import type { AnalyticsListener } from '../types/listener.js';\nimport type { EventEnvelope } from '../types/envelope.js';\n\nexport interface CustomApiListenerConfig {\n /** Endpoint URL for POST (e.g. https://api.example.com/analytics/events). */\n endpoint: string;\n /** Optional API key or bearer token. */\n apiKey?: string;\n /** Optional: batch size before sending. Default 1 (no batching). */\n batchSize?: number;\n /** Optional: max ms to wait before sending a partial batch. Default 5000. */\n flushIntervalMs?: number;\n}\n\nconst DEFAULT_BATCH_SIZE = 1;\nconst DEFAULT_FLUSH_INTERVAL_MS = 5000;\n\n/**\n * Listener that POSTs events to a configurable endpoint.\n * Optional batching: accumulates events and sends when batchSize or flushIntervalMs is reached.\n */\nexport function createCustomApiListener(config: CustomApiListenerConfig): AnalyticsListener {\n const endpoint = config.endpoint;\n const apiKey = config.apiKey;\n const batchSize = config.batchSize ?? DEFAULT_BATCH_SIZE;\n const flushIntervalMs = config.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS;\n\n let batch: EventEnvelope[] = [];\n let flushTimer: ReturnType<typeof setTimeout> | null = null;\n\n function scheduleFlush(): void {\n if (flushTimer != null) return;\n flushTimer = setTimeout(() => {\n flushTimer = null;\n sendBatch();\n }, flushIntervalMs);\n }\n\n function sendBatch(): void {\n if (batch.length === 0) return;\n const toSend = [...batch];\n batch = [];\n const body = JSON.stringify(toSend.length === 1 ? toSend[0] : { events: toSend });\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n if (apiKey) headers['Authorization'] = `Bearer ${apiKey}`;\n if (typeof fetch !== 'undefined') {\n fetch(endpoint, {\n method: 'POST',\n headers,\n body,\n keepalive: true,\n }).catch(() => {});\n }\n }\n\n return {\n init(_config: unknown): void {\n // config was passed at createCustomApiListener\n },\n track(envelope: EventEnvelope): void {\n try {\n batch.push(envelope);\n if (batch.length >= batchSize) {\n sendBatch();\n } else if (flushIntervalMs > 0) {\n scheduleFlush();\n }\n } catch {\n // swallow\n }\n },\n flush(): Promise<void> {\n if (flushTimer != null) {\n clearTimeout(flushTimer);\n flushTimer = null;\n }\n sendBatch();\n return Promise.resolve();\n },\n teardown(): void {\n if (flushTimer != null) {\n clearTimeout(flushTimer);\n flushTimer = null;\n }\n batch.length = 0;\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACcA,IAAM,qBAAqB;AAC3B,IAAM,4BAA4B;AAM3B,SAAS,wBAAwB,QAAoD;AAC1F,QAAM,WAAW,OAAO;AACxB,QAAM,SAAS,OAAO;AACtB,QAAM,YAAY,OAAO,aAAa;AACtC,QAAM,kBAAkB,OAAO,mBAAmB;AAElD,MAAI,QAAyB,CAAC;AAC9B,MAAI,aAAmD;AAEvD,WAAS,gBAAsB;AAC7B,QAAI,cAAc,KAAM;AACxB,iBAAa,WAAW,MAAM;AAC5B,mBAAa;AACb,gBAAU;AAAA,IACZ,GAAG,eAAe;AAAA,EACpB;AAEA,WAAS,YAAkB;AACzB,QAAI,MAAM,WAAW,EAAG;AACxB,UAAM,SAAS,CAAC,GAAG,KAAK;AACxB,YAAQ,CAAC;AACT,UAAM,OAAO,KAAK,UAAU,OAAO,WAAW,IAAI,OAAO,CAAC,IAAI,EAAE,QAAQ,OAAO,CAAC;AAChF,UAAM,UAAkC;AAAA,MACtC,gBAAgB;AAAA,IAClB;AACA,QAAI,OAAQ,SAAQ,eAAe,IAAI,UAAU,MAAM;AACvD,QAAI,OAAO,UAAU,aAAa;AAChC,YAAM,UAAU;AAAA,QACd,QAAQ;AAAA,QACR;AAAA,QACA;AAAA,QACA,WAAW;AAAA,MACb,CAAC,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AAAA,IACnB;AAAA,EACF;AAEA,SAAO;AAAA,IACL,KAAK,SAAwB;AAAA,IAE7B;AAAA,IACA,MAAM,UAA+B;AACnC,UAAI;AACF,cAAM,KAAK,QAAQ;AACnB,YAAI,MAAM,UAAU,WAAW;AAC7B,oBAAU;AAAA,QACZ,WAAW,kBAAkB,GAAG;AAC9B,wBAAc;AAAA,QAChB;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,IACA,QAAuB;AACrB,UAAI,cAAc,MAAM;AACtB,qBAAa,UAAU;AACvB,qBAAa;AAAA,MACf;AACA,gBAAU;AACV,aAAO,QAAQ,QAAQ;AAAA,IACzB;AAAA,IACA,WAAiB;AACf,UAAI,cAAc,MAAM;AACtB,qBAAa,UAAU;AACvB,qBAAa;AAAA,MACf;AACA,YAAM,SAAS;AAAA,IACjB;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,20 @@
1
+ import { A as AnalyticsListener } from './listener-CrNaKh1a.cjs';
2
+ export { E as EventEnvelope } from './listener-CrNaKh1a.cjs';
3
+
4
+ interface CustomApiListenerConfig {
5
+ /** Endpoint URL for POST (e.g. https://api.example.com/analytics/events). */
6
+ endpoint: string;
7
+ /** Optional API key or bearer token. */
8
+ apiKey?: string;
9
+ /** Optional: batch size before sending. Default 1 (no batching). */
10
+ batchSize?: number;
11
+ /** Optional: max ms to wait before sending a partial batch. Default 5000. */
12
+ flushIntervalMs?: number;
13
+ }
14
+ /**
15
+ * Listener that POSTs events to a configurable endpoint.
16
+ * Optional batching: accumulates events and sends when batchSize or flushIntervalMs is reached.
17
+ */
18
+ declare function createCustomApiListener(config: CustomApiListenerConfig): AnalyticsListener;
19
+
20
+ export { AnalyticsListener, type CustomApiListenerConfig, createCustomApiListener };
@@ -0,0 +1,20 @@
1
+ import { A as AnalyticsListener } from './listener-CrNaKh1a.js';
2
+ export { E as EventEnvelope } from './listener-CrNaKh1a.js';
3
+
4
+ interface CustomApiListenerConfig {
5
+ /** Endpoint URL for POST (e.g. https://api.example.com/analytics/events). */
6
+ endpoint: string;
7
+ /** Optional API key or bearer token. */
8
+ apiKey?: string;
9
+ /** Optional: batch size before sending. Default 1 (no batching). */
10
+ batchSize?: number;
11
+ /** Optional: max ms to wait before sending a partial batch. Default 5000. */
12
+ flushIntervalMs?: number;
13
+ }
14
+ /**
15
+ * Listener that POSTs events to a configurable endpoint.
16
+ * Optional batching: accumulates events and sends when batchSize or flushIntervalMs is reached.
17
+ */
18
+ declare function createCustomApiListener(config: CustomApiListenerConfig): AnalyticsListener;
19
+
20
+ export { AnalyticsListener, type CustomApiListenerConfig, createCustomApiListener };
@@ -0,0 +1,71 @@
1
+ // src/listeners/custom-api.ts
2
+ var DEFAULT_BATCH_SIZE = 1;
3
+ var DEFAULT_FLUSH_INTERVAL_MS = 5e3;
4
+ function createCustomApiListener(config) {
5
+ const endpoint = config.endpoint;
6
+ const apiKey = config.apiKey;
7
+ const batchSize = config.batchSize ?? DEFAULT_BATCH_SIZE;
8
+ const flushIntervalMs = config.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS;
9
+ let batch = [];
10
+ let flushTimer = null;
11
+ function scheduleFlush() {
12
+ if (flushTimer != null) return;
13
+ flushTimer = setTimeout(() => {
14
+ flushTimer = null;
15
+ sendBatch();
16
+ }, flushIntervalMs);
17
+ }
18
+ function sendBatch() {
19
+ if (batch.length === 0) return;
20
+ const toSend = [...batch];
21
+ batch = [];
22
+ const body = JSON.stringify(toSend.length === 1 ? toSend[0] : { events: toSend });
23
+ const headers = {
24
+ "Content-Type": "application/json"
25
+ };
26
+ if (apiKey) headers["Authorization"] = `Bearer ${apiKey}`;
27
+ if (typeof fetch !== "undefined") {
28
+ fetch(endpoint, {
29
+ method: "POST",
30
+ headers,
31
+ body,
32
+ keepalive: true
33
+ }).catch(() => {
34
+ });
35
+ }
36
+ }
37
+ return {
38
+ init(_config) {
39
+ },
40
+ track(envelope) {
41
+ try {
42
+ batch.push(envelope);
43
+ if (batch.length >= batchSize) {
44
+ sendBatch();
45
+ } else if (flushIntervalMs > 0) {
46
+ scheduleFlush();
47
+ }
48
+ } catch {
49
+ }
50
+ },
51
+ flush() {
52
+ if (flushTimer != null) {
53
+ clearTimeout(flushTimer);
54
+ flushTimer = null;
55
+ }
56
+ sendBatch();
57
+ return Promise.resolve();
58
+ },
59
+ teardown() {
60
+ if (flushTimer != null) {
61
+ clearTimeout(flushTimer);
62
+ flushTimer = null;
63
+ }
64
+ batch.length = 0;
65
+ }
66
+ };
67
+ }
68
+ export {
69
+ createCustomApiListener
70
+ };
71
+ //# sourceMappingURL=custom-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/listeners/custom-api.ts"],"sourcesContent":["import type { AnalyticsListener } from '../types/listener.js';\nimport type { EventEnvelope } from '../types/envelope.js';\n\nexport interface CustomApiListenerConfig {\n /** Endpoint URL for POST (e.g. https://api.example.com/analytics/events). */\n endpoint: string;\n /** Optional API key or bearer token. */\n apiKey?: string;\n /** Optional: batch size before sending. Default 1 (no batching). */\n batchSize?: number;\n /** Optional: max ms to wait before sending a partial batch. Default 5000. */\n flushIntervalMs?: number;\n}\n\nconst DEFAULT_BATCH_SIZE = 1;\nconst DEFAULT_FLUSH_INTERVAL_MS = 5000;\n\n/**\n * Listener that POSTs events to a configurable endpoint.\n * Optional batching: accumulates events and sends when batchSize or flushIntervalMs is reached.\n */\nexport function createCustomApiListener(config: CustomApiListenerConfig): AnalyticsListener {\n const endpoint = config.endpoint;\n const apiKey = config.apiKey;\n const batchSize = config.batchSize ?? DEFAULT_BATCH_SIZE;\n const flushIntervalMs = config.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS;\n\n let batch: EventEnvelope[] = [];\n let flushTimer: ReturnType<typeof setTimeout> | null = null;\n\n function scheduleFlush(): void {\n if (flushTimer != null) return;\n flushTimer = setTimeout(() => {\n flushTimer = null;\n sendBatch();\n }, flushIntervalMs);\n }\n\n function sendBatch(): void {\n if (batch.length === 0) return;\n const toSend = [...batch];\n batch = [];\n const body = JSON.stringify(toSend.length === 1 ? toSend[0] : { events: toSend });\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n if (apiKey) headers['Authorization'] = `Bearer ${apiKey}`;\n if (typeof fetch !== 'undefined') {\n fetch(endpoint, {\n method: 'POST',\n headers,\n body,\n keepalive: true,\n }).catch(() => {});\n }\n }\n\n return {\n init(_config: unknown): void {\n // config was passed at createCustomApiListener\n },\n track(envelope: EventEnvelope): void {\n try {\n batch.push(envelope);\n if (batch.length >= batchSize) {\n sendBatch();\n } else if (flushIntervalMs > 0) {\n scheduleFlush();\n }\n } catch {\n // swallow\n }\n },\n flush(): Promise<void> {\n if (flushTimer != null) {\n clearTimeout(flushTimer);\n flushTimer = null;\n }\n sendBatch();\n return Promise.resolve();\n },\n teardown(): void {\n if (flushTimer != null) {\n clearTimeout(flushTimer);\n flushTimer = null;\n }\n batch.length = 0;\n },\n };\n}\n"],"mappings":";AAcA,IAAM,qBAAqB;AAC3B,IAAM,4BAA4B;AAM3B,SAAS,wBAAwB,QAAoD;AAC1F,QAAM,WAAW,OAAO;AACxB,QAAM,SAAS,OAAO;AACtB,QAAM,YAAY,OAAO,aAAa;AACtC,QAAM,kBAAkB,OAAO,mBAAmB;AAElD,MAAI,QAAyB,CAAC;AAC9B,MAAI,aAAmD;AAEvD,WAAS,gBAAsB;AAC7B,QAAI,cAAc,KAAM;AACxB,iBAAa,WAAW,MAAM;AAC5B,mBAAa;AACb,gBAAU;AAAA,IACZ,GAAG,eAAe;AAAA,EACpB;AAEA,WAAS,YAAkB;AACzB,QAAI,MAAM,WAAW,EAAG;AACxB,UAAM,SAAS,CAAC,GAAG,KAAK;AACxB,YAAQ,CAAC;AACT,UAAM,OAAO,KAAK,UAAU,OAAO,WAAW,IAAI,OAAO,CAAC,IAAI,EAAE,QAAQ,OAAO,CAAC;AAChF,UAAM,UAAkC;AAAA,MACtC,gBAAgB;AAAA,IAClB;AACA,QAAI,OAAQ,SAAQ,eAAe,IAAI,UAAU,MAAM;AACvD,QAAI,OAAO,UAAU,aAAa;AAChC,YAAM,UAAU;AAAA,QACd,QAAQ;AAAA,QACR;AAAA,QACA;AAAA,QACA,WAAW;AAAA,MACb,CAAC,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AAAA,IACnB;AAAA,EACF;AAEA,SAAO;AAAA,IACL,KAAK,SAAwB;AAAA,IAE7B;AAAA,IACA,MAAM,UAA+B;AACnC,UAAI;AACF,cAAM,KAAK,QAAQ;AACnB,YAAI,MAAM,UAAU,WAAW;AAC7B,oBAAU;AAAA,QACZ,WAAW,kBAAkB,GAAG;AAC9B,wBAAc;AAAA,QAChB;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,IACA,QAAuB;AACrB,UAAI,cAAc,MAAM;AACtB,qBAAa,UAAU;AACvB,qBAAa;AAAA,MACf;AACA,gBAAU;AACV,aAAO,QAAQ,QAAQ;AAAA,IACzB;AAAA,IACA,WAAiB;AACf,UAAI,cAAc,MAAM;AACtB,qBAAa,UAAU;AACvB,qBAAa;AAAA,MACf;AACA,YAAM,SAAS;AAAA,IACjB;AAAA,EACF;AACF;","names":[]}
package/dist/ga.cjs ADDED
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // ga.ts
21
+ var ga_exports = {};
22
+ __export(ga_exports, {
23
+ createGAListener: () => createGAListener
24
+ });
25
+ module.exports = __toCommonJS(ga_exports);
26
+
27
+ // src/listeners/ga.ts
28
+ var GTAG_SCRIPT_URL = "https://www.googletagmanager.com/gtag/js";
29
+ function isBrowser() {
30
+ return typeof window !== "undefined";
31
+ }
32
+ function loadGtagScript(measurementId) {
33
+ return new Promise((resolve) => {
34
+ if (!isBrowser()) {
35
+ resolve();
36
+ return;
37
+ }
38
+ if (window.gtag) {
39
+ window.gtag("config", measurementId);
40
+ resolve();
41
+ return;
42
+ }
43
+ window.dataLayer = window.dataLayer ?? [];
44
+ const gtag = (...args) => {
45
+ window.dataLayer.push(args);
46
+ };
47
+ window.gtag = gtag;
48
+ gtag("js", /* @__PURE__ */ new Date());
49
+ const script = document.createElement("script");
50
+ script.async = true;
51
+ script.src = `${GTAG_SCRIPT_URL}?id=${encodeURIComponent(measurementId)}`;
52
+ script.onload = () => {
53
+ gtag("config", measurementId);
54
+ resolve();
55
+ };
56
+ script.onerror = () => resolve();
57
+ document.head.appendChild(script);
58
+ });
59
+ }
60
+ function createGAListener(config) {
61
+ const measurementId = config.measurementId;
62
+ let ready = false;
63
+ return {
64
+ async init(cfg) {
65
+ try {
66
+ const c = cfg ?? config;
67
+ const id = c.measurementId;
68
+ if (!id || !isBrowser()) return;
69
+ await loadGtagScript(id);
70
+ ready = true;
71
+ } catch {
72
+ }
73
+ },
74
+ track(envelope) {
75
+ try {
76
+ if (!isBrowser() || !ready || typeof window.gtag !== "function") return;
77
+ const params = envelope.properties ?? {};
78
+ if (envelope.userId) params["user_id"] = envelope.userId;
79
+ window.gtag("event", envelope.name, params);
80
+ } catch {
81
+ }
82
+ },
83
+ identify(userId, traits) {
84
+ try {
85
+ if (!isBrowser() || typeof window.gtag !== "function") return;
86
+ window.gtag("set", "user_properties", { user_id: userId, ...traits });
87
+ } catch {
88
+ }
89
+ }
90
+ };
91
+ }
92
+ // Annotate the CommonJS export names for ESM import in node:
93
+ 0 && (module.exports = {
94
+ createGAListener
95
+ });
96
+ //# sourceMappingURL=ga.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../ga.ts","../src/listeners/ga.ts"],"sourcesContent":["/**\n * Entry point: @snovasys/usage-analytics-sdk/ga\n * Export GA listener factory for manual wiring or use via built-in registry (id: ga).\n */\nexport { createGAListener } from './src/listeners/ga.js';\nexport type { GAListenerConfig } from './src/listeners/ga.js';\nexport type { AnalyticsListener, EventEnvelope } from './src/types/index.js';\n","import type { AnalyticsListener } from '../types/listener.js';\nimport type { EventEnvelope } from '../types/envelope.js';\n\nexport interface GAListenerConfig {\n measurementId: string;\n}\n\nconst GTAG_SCRIPT_URL = 'https://www.googletagmanager.com/gtag/js';\n\ndeclare global {\n interface Window {\n dataLayer?: unknown[];\n gtag?: (...args: unknown[]) => void;\n }\n}\n\nfunction isBrowser(): boolean {\n return typeof window !== 'undefined';\n}\n\nfunction loadGtagScript(measurementId: string): Promise<void> {\n return new Promise((resolve) => {\n if (!isBrowser()) {\n resolve();\n return;\n }\n if (window.gtag) {\n window.gtag('config', measurementId);\n resolve();\n return;\n }\n window.dataLayer = window.dataLayer ?? [];\n const gtag = (...args: unknown[]) => {\n window.dataLayer!.push(args);\n };\n window.gtag = gtag;\n gtag('js', new Date());\n const script = document.createElement('script');\n script.async = true;\n script.src = `${GTAG_SCRIPT_URL}?id=${encodeURIComponent(measurementId)}`;\n script.onload = () => {\n gtag('config', measurementId);\n resolve();\n };\n script.onerror = () => resolve();\n document.head.appendChild(script);\n });\n}\n\n/**\n * Listener that sends events to Google Analytics 4 via gtag.\n * Loads gtag script with measurementId; track → gtag('event', name, properties).\n * No-op when typeof window === 'undefined' (SSR).\n */\nexport function createGAListener(config: GAListenerConfig): AnalyticsListener {\n const measurementId = config.measurementId;\n let ready = false;\n\n return {\n async init(cfg: unknown): Promise<void> {\n try {\n const c = (cfg ?? config) as GAListenerConfig;\n const id = c.measurementId;\n if (!id || !isBrowser()) return;\n await loadGtagScript(id);\n ready = true;\n } catch {\n // swallow\n }\n },\n track(envelope: EventEnvelope): void {\n try {\n if (!isBrowser() || !ready || typeof window.gtag !== 'function') return;\n const params = envelope.properties ?? {};\n if (envelope.userId) (params as Record<string, unknown>)['user_id'] = envelope.userId;\n window.gtag('event', envelope.name, params);\n } catch {\n // swallow\n }\n },\n identify(userId: string, traits?: Record<string, unknown>): void {\n try {\n if (!isBrowser() || typeof window.gtag !== 'function') return;\n window.gtag('set', 'user_properties', { user_id: userId, ...traits });\n } catch {\n // swallow\n }\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACOA,IAAM,kBAAkB;AASxB,SAAS,YAAqB;AAC5B,SAAO,OAAO,WAAW;AAC3B;AAEA,SAAS,eAAe,eAAsC;AAC5D,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,QAAI,CAAC,UAAU,GAAG;AAChB,cAAQ;AACR;AAAA,IACF;AACA,QAAI,OAAO,MAAM;AACf,aAAO,KAAK,UAAU,aAAa;AACnC,cAAQ;AACR;AAAA,IACF;AACA,WAAO,YAAY,OAAO,aAAa,CAAC;AACxC,UAAM,OAAO,IAAI,SAAoB;AACnC,aAAO,UAAW,KAAK,IAAI;AAAA,IAC7B;AACA,WAAO,OAAO;AACd,SAAK,MAAM,oBAAI,KAAK,CAAC;AACrB,UAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,WAAO,QAAQ;AACf,WAAO,MAAM,GAAG,eAAe,OAAO,mBAAmB,aAAa,CAAC;AACvE,WAAO,SAAS,MAAM;AACpB,WAAK,UAAU,aAAa;AAC5B,cAAQ;AAAA,IACV;AACA,WAAO,UAAU,MAAM,QAAQ;AAC/B,aAAS,KAAK,YAAY,MAAM;AAAA,EAClC,CAAC;AACH;AAOO,SAAS,iBAAiB,QAA6C;AAC5E,QAAM,gBAAgB,OAAO;AAC7B,MAAI,QAAQ;AAEZ,SAAO;AAAA,IACL,MAAM,KAAK,KAA6B;AACtC,UAAI;AACF,cAAM,IAAK,OAAO;AAClB,cAAM,KAAK,EAAE;AACb,YAAI,CAAC,MAAM,CAAC,UAAU,EAAG;AACzB,cAAM,eAAe,EAAE;AACvB,gBAAQ;AAAA,MACV,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,IACA,MAAM,UAA+B;AACnC,UAAI;AACF,YAAI,CAAC,UAAU,KAAK,CAAC,SAAS,OAAO,OAAO,SAAS,WAAY;AACjE,cAAM,SAAS,SAAS,cAAc,CAAC;AACvC,YAAI,SAAS,OAAQ,CAAC,OAAmC,SAAS,IAAI,SAAS;AAC/E,eAAO,KAAK,SAAS,SAAS,MAAM,MAAM;AAAA,MAC5C,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,IACA,SAAS,QAAgB,QAAwC;AAC/D,UAAI;AACF,YAAI,CAAC,UAAU,KAAK,OAAO,OAAO,SAAS,WAAY;AACvD,eAAO,KAAK,OAAO,mBAAmB,EAAE,SAAS,QAAQ,GAAG,OAAO,CAAC;AAAA,MACtE,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
package/dist/ga.d.cts ADDED
@@ -0,0 +1,20 @@
1
+ import { A as AnalyticsListener } from './listener-CrNaKh1a.cjs';
2
+ export { E as EventEnvelope } from './listener-CrNaKh1a.cjs';
3
+
4
+ interface GAListenerConfig {
5
+ measurementId: string;
6
+ }
7
+ declare global {
8
+ interface Window {
9
+ dataLayer?: unknown[];
10
+ gtag?: (...args: unknown[]) => void;
11
+ }
12
+ }
13
+ /**
14
+ * Listener that sends events to Google Analytics 4 via gtag.
15
+ * Loads gtag script with measurementId; track → gtag('event', name, properties).
16
+ * No-op when typeof window === 'undefined' (SSR).
17
+ */
18
+ declare function createGAListener(config: GAListenerConfig): AnalyticsListener;
19
+
20
+ export { AnalyticsListener, type GAListenerConfig, createGAListener };
package/dist/ga.d.ts ADDED
@@ -0,0 +1,20 @@
1
+ import { A as AnalyticsListener } from './listener-CrNaKh1a.js';
2
+ export { E as EventEnvelope } from './listener-CrNaKh1a.js';
3
+
4
+ interface GAListenerConfig {
5
+ measurementId: string;
6
+ }
7
+ declare global {
8
+ interface Window {
9
+ dataLayer?: unknown[];
10
+ gtag?: (...args: unknown[]) => void;
11
+ }
12
+ }
13
+ /**
14
+ * Listener that sends events to Google Analytics 4 via gtag.
15
+ * Loads gtag script with measurementId; track → gtag('event', name, properties).
16
+ * No-op when typeof window === 'undefined' (SSR).
17
+ */
18
+ declare function createGAListener(config: GAListenerConfig): AnalyticsListener;
19
+
20
+ export { AnalyticsListener, type GAListenerConfig, createGAListener };